Update AInstEmitSimdHelper.cs
This commit is contained in:
parent
8ba723262b
commit
1a328a1159
1 changed files with 633 additions and 63 deletions
|
@ -336,17 +336,21 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rd))
|
||||
bool Rd = (Opers & OperFlags.Rd) != 0;
|
||||
bool Rn = (Opers & OperFlags.Rn) != 0;
|
||||
bool Rm = (Opers & OperFlags.Rm) != 0;
|
||||
|
||||
if (Rd)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed);
|
||||
}
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rn))
|
||||
if (Rn)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed);
|
||||
}
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rm))
|
||||
if (Rm)
|
||||
{
|
||||
EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed);
|
||||
}
|
||||
|
@ -377,17 +381,21 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Ra))
|
||||
bool Ra = (Opers & OperFlags.Ra) != 0;
|
||||
bool Rn = (Opers & OperFlags.Rn) != 0;
|
||||
bool Rm = (Opers & OperFlags.Rm) != 0;
|
||||
|
||||
if (Ra)
|
||||
{
|
||||
EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF);
|
||||
}
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rn))
|
||||
if (Rn)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
}
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rm))
|
||||
if (Rm)
|
||||
{
|
||||
EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF);
|
||||
}
|
||||
|
@ -769,7 +777,7 @@ namespace ChocolArm64.Instruction
|
|||
Emit();
|
||||
|
||||
EmitVectorInsertTmp(Context, Pairs + Index, Op.Size);
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
|
@ -781,56 +789,238 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SaturatingFlags
|
||||
{
|
||||
Scalar = 1 << 0,
|
||||
Signed = 1 << 1,
|
||||
|
||||
Add = 1 << 2,
|
||||
Sub = 1 << 3,
|
||||
|
||||
Accumulate = 1 << 4,
|
||||
|
||||
ScalarSx = Scalar | Signed,
|
||||
ScalarZx = Scalar,
|
||||
|
||||
VectorSx = Signed,
|
||||
VectorZx = 0,
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingUnaryOpSx(Context, Emit, SaturatingFlags.ScalarSx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingUnaryOpSx(Context, Emit, SaturatingFlags.VectorSx);
|
||||
}
|
||||
|
||||
public static void EmitSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit, SaturatingFlags Flags)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
bool Scalar = (Flags & SaturatingFlags.Scalar) != 0;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = !Scalar ? Bytes >> Op.Size : 1;
|
||||
|
||||
Context.EmitLdc_I8(0L);
|
||||
Context.EmitSttmp(); // Saturated = 0
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitUnarySignedSatQAbsOrNeg(Context, Op.Size);
|
||||
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitUpdateFpsrQCFlag(Context);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
|
||||
{
|
||||
EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarSx | Flags);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
|
||||
{
|
||||
EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarZx | Flags);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
|
||||
{
|
||||
EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorSx | Flags);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
|
||||
{
|
||||
EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorZx | Flags);
|
||||
}
|
||||
|
||||
public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, SaturatingFlags Flags)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
bool Scalar = (Flags & SaturatingFlags.Scalar) != 0;
|
||||
bool Signed = (Flags & SaturatingFlags.Signed) != 0;
|
||||
|
||||
bool Add = (Flags & SaturatingFlags.Add) != 0;
|
||||
bool Sub = (Flags & SaturatingFlags.Sub) != 0;
|
||||
|
||||
bool Accumulate = (Flags & SaturatingFlags.Accumulate) != 0;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = !Scalar ? Bytes >> Op.Size : 1;
|
||||
|
||||
Context.EmitLdc_I8(0L);
|
||||
Context.EmitSttmp(); // Saturated = 0
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
if (Add || Sub)
|
||||
{
|
||||
if (Op.Size <= 2)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
|
||||
|
||||
Context.Emit(Add ? OpCodes.Add : OpCodes.Sub);
|
||||
|
||||
EmitSatQ(Context, Op.Size, true, Signed);
|
||||
}
|
||||
else /* if (Op.Size == 3) */
|
||||
{
|
||||
if (Add)
|
||||
{
|
||||
EmitBinarySatQAdd(Context, Index, Signed);
|
||||
}
|
||||
else /* if (Sub) */
|
||||
{
|
||||
EmitBinarySatQSub(Context, Index, Signed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Accumulate)
|
||||
{
|
||||
if (Op.Size <= 2)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, !Signed);
|
||||
EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
EmitSatQ(Context, Op.Size, true, Signed);
|
||||
}
|
||||
else /* if (Op.Size == 3) */
|
||||
{
|
||||
EmitBinarySatQAccumulate(Context, Index, Signed);
|
||||
}
|
||||
}
|
||||
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitUpdateFpsrQCFlag(Context);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SaturatingNarrowFlags
|
||||
{
|
||||
Scalar = 1 << 0,
|
||||
SignedSrc = 1 << 1,
|
||||
SignedDst = 1 << 2,
|
||||
|
||||
ScalarSxSx = Scalar | SignedSrc | SignedDst,
|
||||
ScalarSxZx = Scalar | SignedSrc,
|
||||
ScalarZxZx = Scalar,
|
||||
|
||||
VectorSxSx = SignedSrc | SignedDst,
|
||||
VectorSxZx = SignedSrc,
|
||||
VectorZxZx = 0
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, true, true, true);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, true, false, true);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, false, false, true);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, true, true, false);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, true, false, false);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, false, false, false);
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
|
||||
public static void EmitSaturatingNarrowOp(
|
||||
AILEmitterCtx Context,
|
||||
Action Emit,
|
||||
bool SignedSrc,
|
||||
bool SignedDst,
|
||||
bool Scalar)
|
||||
public static void EmitSaturatingNarrowOp(AILEmitterCtx Context, Action Emit, SaturatingNarrowFlags Flags)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Elems = !Scalar ? 8 >> Op.Size : 1;
|
||||
bool Scalar = (Flags & SaturatingNarrowFlags.Scalar) != 0;
|
||||
bool SignedSrc = (Flags & SaturatingNarrowFlags.SignedSrc) != 0;
|
||||
bool SignedDst = (Flags & SaturatingNarrowFlags.SignedDst) != 0;
|
||||
|
||||
int ESize = 8 << Op.Size;
|
||||
int Elems = !Scalar ? 8 >> Op.Size : 1;
|
||||
|
||||
int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0;
|
||||
|
||||
long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize));
|
||||
long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0;
|
||||
|
||||
Context.EmitLdc_I8(0L);
|
||||
Context.EmitSttmp();
|
||||
Context.EmitSttmp(); // Saturated = 0
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
|
||||
if (Part != 0)
|
||||
{
|
||||
|
@ -840,47 +1030,11 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
AILLabel LblLe = new AILLabel();
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);
|
||||
|
||||
Emit();
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
Context.EmitLdc_I8(0x8000000L);
|
||||
Context.EmitSttmp();
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblGeEnd);
|
||||
|
||||
Context.MarkLabel(LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
Context.EmitLdc_I8(0x8000000L);
|
||||
Context.EmitSttmp();
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
|
||||
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
}
|
||||
|
@ -893,12 +1047,428 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitUpdateFpsrQCFlag(Context);
|
||||
}
|
||||
|
||||
// TSrc (from 8bit to 64bit) > TDst (from 8bit to 32bit), signed or unsigned.
|
||||
public static void EmitSatQ(
|
||||
AILEmitterCtx Context,
|
||||
int SizeDst,
|
||||
bool SignedSrc,
|
||||
bool SignedDst)
|
||||
{
|
||||
if (SizeDst > 2)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
int ESize = 8 << SizeDst;
|
||||
|
||||
long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L;
|
||||
long TMinValue = SignedDst ? -(1 << (ESize - 1)) : 0L;
|
||||
|
||||
AILLabel LblLe = new AILLabel();
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblGeEnd);
|
||||
|
||||
Context.MarkLabel(LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
}
|
||||
|
||||
// TSrc (from 8bit to 64bit) == TDst (from 8bit to 64bit), signed.
|
||||
public static void EmitUnarySignedSatQAbsOrNeg(
|
||||
AILEmitterCtx Context,
|
||||
int Size)
|
||||
{
|
||||
int ESize = 8 << Size;
|
||||
|
||||
long TMaxValue = (1L << (ESize - 1)) - 1;
|
||||
long TMinValue = -(1L << (ESize - 1));
|
||||
|
||||
AILLabel LblFalse = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
Context.Emit(OpCodes.Neg);
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
Context.Emit(OpCodes.Brfalse_S, LblFalse);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.MarkLabel(LblFalse);
|
||||
}
|
||||
|
||||
// TSrcs (64bit) == TDst (64bit), signed or unsigned.
|
||||
public static void EmitBinarySatQAdd(
|
||||
AILEmitterCtx Context,
|
||||
int Index,
|
||||
bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
if (Op.Size < 3)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, 3, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Index, 3, Signed);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
long TMaxValue = long.MaxValue;
|
||||
long TMinValue = long.MinValue;
|
||||
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
AILLabel LblGe = new AILLabel();
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractSx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.Not);
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractSx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Bge_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Bge_S, LblGe);
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblGeEnd);
|
||||
|
||||
Context.MarkLabel(LblGe);
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
long TMaxValue = ~0L;
|
||||
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Bge_Un_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Bge_Un_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
// TSrcs (64bit) == TDst (64bit), signed or unsigned.
|
||||
public static void EmitBinarySatQSub(
|
||||
AILEmitterCtx Context,
|
||||
int Index,
|
||||
bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
if (Op.Size < 3)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, 3, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Index, 3, Signed);
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
long TMaxValue = long.MaxValue;
|
||||
long TMinValue = long.MinValue;
|
||||
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
AILLabel LblGe = new AILLabel();
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractSx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractSx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Sub);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Bge_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Bge_S, LblGe);
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblGeEnd);
|
||||
|
||||
Context.MarkLabel(LblGe);
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
long TMinValue = 0L;
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, 3);
|
||||
Context.Emit(OpCodes.Bge_Un_S, LblTrue);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
}
|
||||
}
|
||||
|
||||
// TSrcs (64bit) == TDst (64bit), signed or unsigned.
|
||||
public static void EmitBinarySatQAccumulate(
|
||||
AILEmitterCtx Context,
|
||||
int Index,
|
||||
bool Signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
if (Op.Size < 3)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
long TMaxValue = long.MaxValue;
|
||||
|
||||
AILLabel LblGt = new AILLabel();
|
||||
AILLabel LblLt = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
Context.Emit(OpCodes.Bgt_Un_S, LblGt);
|
||||
|
||||
// op1 from ulong.MinValue to (ulong)long.MaxValue
|
||||
// op2 from long.MinValue to long.MaxValue
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractSx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractSx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Bge_S, LblEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblGt);
|
||||
|
||||
// op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
|
||||
// op2 from (long)ulong.MinValue to long.MaxValue
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Blt_S, LblLt);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblLt);
|
||||
|
||||
// op1 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
|
||||
// op2 from long.MinValue to (long)ulong.MinValue - 1L
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractSx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
Context.Emit(OpCodes.Ble_Un_S, LblEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
long TMaxValue = ~0L;
|
||||
long TMinValue = 0L;
|
||||
|
||||
AILLabel LblLt = new AILLabel();
|
||||
AILLabel LblLe = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.Emit(OpCodes.Blt_S, LblLt);
|
||||
|
||||
// op1 from (long)ulong.MinValue to long.MaxValue
|
||||
// op2 from ulong.MinValue to ulong.MaxValue
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
Context.Emit(OpCodes.Bge_Un_S, LblEnd);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Bge_Un_S, LblEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMaxValue);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblLt);
|
||||
|
||||
// op1 from long.MinValue to (long)ulong.MinValue - 1L
|
||||
// op2 from (ulong)long.MaxValue + 1UL to ulong.MaxValue
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, 3);
|
||||
Context.EmitLdc_I8(long.MaxValue); // TODO: Spostare a variabile?
|
||||
Context.Emit(OpCodes.Ble_Un_S, LblLe);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblLe);
|
||||
|
||||
// op1 from long.MinValue to (long)ulong.MinValue - 1L
|
||||
// op2 from ulong.MinValue to (ulong)long.MaxValue
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, 3);
|
||||
EmitVectorExtractSx(Context, Op.Rd, Index, 3);
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
Context.Emit(OpCodes.Bge_S, LblEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I8(1L);
|
||||
Context.EmitSttmp(); // Saturated = 1
|
||||
|
||||
Context.EmitLdc_I8(TMinValue);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitUpdateFpsrQCFlag(AILEmitterCtx Context)
|
||||
{
|
||||
const int QCFlag = 27;
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
|
||||
Context.EmitLdtmp();
|
||||
|
||||
Context.EmitLdtmp(); // Saturated == 0 || Saturated == 1
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
Context.EmitLsl(QCFlag);
|
||||
|
||||
Context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue