aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2018-08-04 21:58:54 +0200
committergdkchan <gab.dark.100@gmail.com>2018-08-04 16:58:54 -0300
commit5f34353dce716bca2e3fc1c7e82be6276b95d61a (patch)
treeebd21bf7aa8a67b3b60321789e404c224c66c8f4 /ChocolArm64/Instruction/AInstEmitSimdHelper.cs
parentfa70629fabbab5074640f55cb70f9d7d82cf91cb (diff)
Add SQADD, UQADD, SQSUB, UQSUB, SUQADD, USQADD, SQABS, SQNEG (Scalar, Vector) instructions; add 24 Tests. Most saturation instructions now on ASoftFallback. (#314)
* Update AOpCodeTable.cs * Update AInstEmitSimdHelper.cs * Update AInstEmitSimdArithmetic.cs * Update Pseudocode.cs * Update Instructions.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update AInstEmitSimdHelper.cs * Update AInstEmitSimdHelper.cs * Update AInstEmitSimdHelper.cs * Update AInstEmitSimdHelper.cs * Update ASoftFallback.cs * Update AInstEmitSimdHelper.cs * Update ASoftFallback.cs * Update AInstEmitSimdHelper.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update ASoftFallback.cs * Update AInstEmitSimdHelper.cs * Opt. (retest).
Diffstat (limited to 'ChocolArm64/Instruction/AInstEmitSimdHelper.cs')
-rw-r--r--ChocolArm64/Instruction/AInstEmitSimdHelper.cs378
1 files changed, 321 insertions, 57 deletions
diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
index 0bd1a629..161c44ea 100644
--- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
+++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
@@ -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,241 @@ 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;
+
+ 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);
+ }
+ }
+
+ 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;
+
+ if (Scalar)
+ {
+ EmitVectorZeroLowerTmp(Context);
+ }
+
+ if (Add || Sub)
+ {
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
+ EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
+
+ if (Op.Size <= 2)
+ {
+ Context.Emit(Add ? OpCodes.Add : OpCodes.Sub);
+
+ EmitSatQ(Context, Op.Size, true, Signed);
+ }
+ else /* if (Op.Size == 3) */
+ {
+ if (Add)
+ {
+ EmitBinarySatQAdd(Context, Signed);
+ }
+ else /* if (Sub) */
+ {
+ EmitBinarySatQSub(Context, Signed);
+ }
+ }
+
+ EmitVectorInsertTmp(Context, Index, Op.Size);
+ }
+ }
+ else if (Accumulate)
+ {
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size, !Signed);
+ EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
+
+ if (Op.Size <= 2)
+ {
+ Context.Emit(OpCodes.Add);
+
+ EmitSatQ(Context, Op.Size, true, Signed);
+ }
+ else /* if (Op.Size == 3) */
+ {
+ EmitBinarySatQAccumulate(Context, Signed);
+ }
+
+ EmitVectorInsertTmp(Context, Index, Op.Size);
+ }
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitStvec(Op.Rd);
+
+ if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ [Flags]
+ public enum SaturatingNarrowFlags
+ {
+ Scalar = 1 << 0,
+ SignedSrc = 1 << 1,
+ SignedDst = 1 << 2,
+
+ ScalarSxSx = Scalar | SignedSrc | SignedDst,
+ ScalarSxZx = Scalar | SignedSrc,
+ ScalarZxSx = Scalar | SignedDst,
+ ScalarZxZx = Scalar,
+
+ VectorSxSx = SignedSrc | SignedDst,
+ VectorSxZx = SignedSrc,
+ VectorZxSx = SignedDst,
+ 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 EmitScalarSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxSx);
}
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 EmitVectorSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxSx);
}
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();
+ if (Scalar)
+ {
+ EmitVectorZeroLowerTmp(Context);
+ }
if (Part != 0)
{
@@ -840,65 +1033,136 @@ 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);
+ EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
+
+ EmitVectorInsertTmp(Context, Part + Index, Op.Size);
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitStvec(Op.Rd);
+
+ if (Part == 0)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
+ public static void EmitSatQ(
+ AILEmitterCtx Context,
+ int SizeDst,
+ bool SignedSrc,
+ bool SignedDst)
+ {
+ if (SizeDst > 2)
+ {
+ throw new ArgumentOutOfRangeException(nameof(SizeDst));
+ }
- Context.EmitLdc_I8(TMaxValue);
+ Context.EmitLdc_I4(SizeDst);
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
- Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);
+ if (SignedSrc)
+ {
+ ASoftFallback.EmitCall(Context, SignedDst
+ ? nameof(ASoftFallback.SignedSrcSignedDstSatQ)
+ : nameof(ASoftFallback.SignedSrcUnsignedDstSatQ));
+ }
+ else
+ {
+ ASoftFallback.EmitCall(Context, SignedDst
+ ? nameof(ASoftFallback.UnsignedSrcSignedDstSatQ)
+ : nameof(ASoftFallback.UnsignedSrcUnsignedDstSatQ));
+ }
+ }
- Context.Emit(OpCodes.Pop);
+ // TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed.
+ public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size)
+ {
+ int ESize = 8 << Size;
- Context.EmitLdc_I8(TMaxValue);
- Context.EmitLdc_I8(0x8000000L);
- Context.EmitSttmp();
+ long TMaxValue = (1L << (ESize - 1)) - 1L;
+ long TMinValue = -(1L << (ESize - 1));
- Context.Emit(OpCodes.Br_S, LblGeEnd);
+ AILLabel LblFalse = new AILLabel();
- Context.MarkLabel(LblLe);
+ 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.Dup);
+ Context.Emit(OpCodes.Pop);
- Context.EmitLdc_I8(TMinValue);
+ EmitSetFpsrQCFlag(Context);
- Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);
+ Context.EmitLdc_I8(TMaxValue);
- Context.Emit(OpCodes.Pop);
+ Context.MarkLabel(LblFalse);
+ }
- Context.EmitLdc_I8(TMinValue);
- Context.EmitLdc_I8(0x8000000L);
- Context.EmitSttmp();
+ // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+ public static void EmitBinarySatQAdd(AILEmitterCtx Context, bool Signed)
+ {
+ if (((AOpCodeSimdReg)Context.CurrOp).Size < 3)
+ {
+ throw new InvalidOperationException();
+ }
- Context.MarkLabel(LblGeEnd);
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
- if (Scalar)
- {
- EmitVectorZeroLowerTmp(Context);
- }
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.BinarySignedSatQAdd)
+ : nameof(ASoftFallback.BinaryUnsignedSatQAdd));
+ }
- EmitVectorInsertTmp(Context, Part + Index, Op.Size);
+ // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+ public static void EmitBinarySatQSub(AILEmitterCtx Context, bool Signed)
+ {
+ if (((AOpCodeSimdReg)Context.CurrOp).Size < 3)
+ {
+ throw new InvalidOperationException();
}
- Context.EmitLdvectmp();
- Context.EmitStvec(Op.Rd);
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
- if (Part == 0)
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.BinarySignedSatQSub)
+ : nameof(ASoftFallback.BinaryUnsignedSatQSub));
+ }
+
+ // TSrcs (64bit) == TDst (64bit); signed, unsigned.
+ public static void EmitBinarySatQAccumulate(AILEmitterCtx Context, bool Signed)
+ {
+ if (((AOpCodeSimd)Context.CurrOp).Size < 3)
{
- EmitVectorZeroUpper(Context, Op.Rd);
+ throw new InvalidOperationException();
}
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.BinarySignedSatQAcc)
+ : nameof(ASoftFallback.BinaryUnsignedSatQAcc));
+ }
+
+ public static void EmitSetFpsrQCFlag(AILEmitterCtx Context)
+ {
+ const int QCFlagBit = 27;
+
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
- Context.EmitLdtmp();
- Context.Emit(OpCodes.Conv_I4);
+
+ Context.EmitLdc_I4(1 << QCFlagBit);
+
Context.Emit(OpCodes.Or);
+
Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
}