Update AInstEmitSimdHelper.cs

This commit is contained in:
LDj3SNuD 2018-07-30 02:28:26 +02:00 committed by GitHub
parent 8ba723262b
commit 1a328a1159
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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));
}