aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instruction
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2018-08-10 19:27:15 +0200
committergdkchan <gab.dark.100@gmail.com>2018-08-10 14:27:15 -0300
commit02a6fdcd1369cea926a1ad549ef69dbff60f034a (patch)
tree39f569023d300b2dd2b5a1132221658d7590648d /ChocolArm64/Instruction
parent267af1f0f775d11b36dab0d1276188f907604584 (diff)
Add Sqdmulh_S, Sqdmulh_V, Sqrdmulh_S, Sqrdmulh_V instructions; add 6 Tests. Now all saturating methods are on ASoftFallback. (#334)
* Update Instructions.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update AOpCodeTable.cs * Update AInstEmitSimdArithmetic.cs * Update AInstEmitSimdHelper.cs * Update ASoftFallback.cs * Update CpuTestAlu.cs * Update CpuTestAluImm.cs * Update CpuTestAluRs.cs * Update CpuTestAluRx.cs * Update CpuTestBfm.cs * Update CpuTestCcmpImm.cs * Update CpuTestCcmpReg.cs * Update CpuTestCsel.cs * Update CpuTestMov.cs * Update CpuTestMul.cs * Update Ryujinx.Tests.csproj * Update Ryujinx.csproj * Update Luea.csproj * Update Ryujinx.ShaderTools.csproj * Address PR feedback (further tested). * Address PR feedback.
Diffstat (limited to 'ChocolArm64/Instruction')
-rw-r--r--ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs56
-rw-r--r--ChocolArm64/Instruction/AInstEmitSimdHelper.cs79
-rw-r--r--ChocolArm64/Instruction/ASoftFallback.cs196
3 files changed, 202 insertions, 129 deletions
diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs
index 559811d9..02e903f6 100644
--- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs
+++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs
@@ -158,6 +158,42 @@ namespace ChocolArm64.Instruction
Context.MarkLabel(LblTrue);
}
+ private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx Context, bool Round)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ int ESize = 8 << Op.Size;
+
+ Context.Emit(OpCodes.Mul);
+
+ if (!Round)
+ {
+ Context.EmitAsr(ESize - 1);
+ }
+ else
+ {
+ long RoundConst = 1L << (ESize - 1);
+
+ AILLabel LblTrue = new AILLabel();
+
+ Context.EmitLsl(1);
+
+ Context.EmitLdc_I8(RoundConst);
+
+ Context.Emit(OpCodes.Add);
+
+ Context.EmitAsr(ESize);
+
+ Context.Emit(OpCodes.Dup);
+ Context.EmitLdc_I8((long)int.MinValue);
+ Context.Emit(OpCodes.Bne_Un_S, LblTrue);
+
+ Context.Emit(OpCodes.Neg);
+
+ Context.MarkLabel(LblTrue);
+ }
+ }
+
private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
@@ -1040,6 +1076,16 @@ namespace ChocolArm64.Instruction
EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Add);
}
+ public static void Sqdmulh_S(AILEmitterCtx Context)
+ {
+ EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.ScalarSx);
+ }
+
+ public static void Sqdmulh_V(AILEmitterCtx Context)
+ {
+ EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.VectorSx);
+ }
+
public static void Sqneg_S(AILEmitterCtx Context)
{
EmitScalarSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
@@ -1050,6 +1096,16 @@ namespace ChocolArm64.Instruction
EmitVectorSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
}
+ public static void Sqrdmulh_S(AILEmitterCtx Context)
+ {
+ EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.ScalarSx);
+ }
+
+ public static void Sqrdmulh_V(AILEmitterCtx Context)
+ {
+ EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.VectorSx);
+ }
+
public static void Sqsub_S(AILEmitterCtx Context)
{
EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Sub);
diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
index 161c44ea..a9af3902 100644
--- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
+++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs
@@ -804,7 +804,7 @@ namespace ChocolArm64.Instruction
ScalarZx = Scalar,
VectorSx = Signed,
- VectorZx = 0,
+ VectorZx = 0
}
public static void EmitScalarSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit)
@@ -837,7 +837,14 @@ namespace ChocolArm64.Instruction
Emit();
- EmitUnarySignedSatQAbsOrNeg(Context, Op.Size);
+ if (Op.Size <= 2)
+ {
+ EmitSatQ(Context, Op.Size, true, true);
+ }
+ else /* if (Op.Size == 3) */
+ {
+ EmitUnarySignedSatQAbsOrNeg(Context);
+ }
EmitVectorInsertTmp(Context, Index, Op.Size);
}
@@ -853,25 +860,25 @@ namespace ChocolArm64.Instruction
public static void EmitScalarSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
{
- EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarSx | Flags);
+ EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.ScalarSx | Flags);
}
public static void EmitScalarSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
{
- EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarZx | Flags);
+ EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.ScalarZx | Flags);
}
public static void EmitVectorSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags)
{
- EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorSx | Flags);
+ EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.VectorSx | Flags);
}
public static void EmitVectorSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags)
{
- EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorZx | Flags);
+ EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.VectorZx | Flags);
}
- public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, SaturatingFlags Flags)
+ public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, Action Emit, SaturatingFlags Flags)
{
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
@@ -940,6 +947,20 @@ namespace ChocolArm64.Instruction
EmitVectorInsertTmp(Context, Index, Op.Size);
}
}
+ else
+ {
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
+ EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
+
+ Emit();
+
+ EmitSatQ(Context, Op.Size, true, Signed);
+
+ EmitVectorInsertTmp(Context, Index, Op.Size);
+ }
+ }
Context.EmitLdvectmp();
Context.EmitStvec(Op.Rd);
@@ -1080,29 +1101,17 @@ namespace ChocolArm64.Instruction
}
}
- // TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed.
- public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size)
+ // TSrc (64bit) == TDst (64bit); signed.
+ public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context)
{
- int ESize = 8 << Size;
-
- long TMaxValue = (1L << (ESize - 1)) - 1L;
- 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);
-
- EmitSetFpsrQCFlag(Context);
+ if (((AOpCodeSimd)Context.CurrOp).Size < 3)
+ {
+ throw new InvalidOperationException();
+ }
- Context.EmitLdc_I8(TMaxValue);
+ Context.EmitLdarg(ATranslatedSub.StateArgIdx);
- Context.MarkLabel(LblFalse);
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UnarySignedSatQAbsOrNeg));
}
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
@@ -1150,22 +1159,6 @@ namespace ChocolArm64.Instruction
: 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.EmitLdc_I4(1 << QCFlagBit);
-
- Context.Emit(OpCodes.Or);
-
- Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
- }
-
public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size)
{
EmitVectorZeroAll(Context, Reg);
diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs
index a4d12dd6..40898578 100644
--- a/ChocolArm64/Instruction/ASoftFallback.cs
+++ b/ChocolArm64/Instruction/ASoftFallback.cs
@@ -11,6 +11,107 @@ namespace ChocolArm64.Instruction
Context.EmitCall(typeof(ASoftFallback), MthdName);
}
+#region "Saturating"
+ public static long SignedSrcSignedDstSatQ(long op, int Size, AThreadState State)
+ {
+ int ESize = 8 << Size;
+
+ long TMaxValue = (1L << (ESize - 1)) - 1L;
+ long TMinValue = -(1L << (ESize - 1));
+
+ if (op > TMaxValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMaxValue;
+ }
+ else if (op < TMinValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMinValue;
+ }
+ else
+ {
+ return op;
+ }
+ }
+
+ public static ulong SignedSrcUnsignedDstSatQ(long op, int Size, AThreadState State)
+ {
+ int ESize = 8 << Size;
+
+ ulong TMaxValue = (1UL << ESize) - 1UL;
+ ulong TMinValue = 0UL;
+
+ if (op > (long)TMaxValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMaxValue;
+ }
+ else if (op < (long)TMinValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMinValue;
+ }
+ else
+ {
+ return (ulong)op;
+ }
+ }
+
+ public static long UnsignedSrcSignedDstSatQ(ulong op, int Size, AThreadState State)
+ {
+ int ESize = 8 << Size;
+
+ long TMaxValue = (1L << (ESize - 1)) - 1L;
+
+ if (op > (ulong)TMaxValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMaxValue;
+ }
+ else
+ {
+ return (long)op;
+ }
+ }
+
+ public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int Size, AThreadState State)
+ {
+ int ESize = 8 << Size;
+
+ ulong TMaxValue = (1UL << ESize) - 1UL;
+
+ if (op > TMaxValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return TMaxValue;
+ }
+ else
+ {
+ return op;
+ }
+ }
+
+ public static long UnarySignedSatQAbsOrNeg(long op, AThreadState State)
+ {
+ if (op == long.MinValue)
+ {
+ SetFpsrQCFlag(State);
+
+ return long.MaxValue;
+ }
+ else
+ {
+ return op;
+ }
+ }
+
public static long BinarySignedSatQAdd(long op1, long op2, AThreadState State)
{
long Add = op1 + op2;
@@ -185,99 +286,15 @@ namespace ChocolArm64.Instruction
}
}
- public static long SignedSrcSignedDstSatQ(long op, int Size, AThreadState State)
- {
- int ESize = 8 << Size;
-
- long TMaxValue = (1L << (ESize - 1)) - 1L;
- long TMinValue = -(1L << (ESize - 1));
-
- if (op > TMaxValue)
- {
- SetFpsrQCFlag(State);
-
- return TMaxValue;
- }
- else if (op < TMinValue)
- {
- SetFpsrQCFlag(State);
-
- return TMinValue;
- }
- else
- {
- return op;
- }
- }
-
- public static ulong SignedSrcUnsignedDstSatQ(long op, int Size, AThreadState State)
- {
- int ESize = 8 << Size;
-
- ulong TMaxValue = (1UL << ESize) - 1UL;
- ulong TMinValue = 0UL;
-
- if (op > (long)TMaxValue)
- {
- SetFpsrQCFlag(State);
-
- return TMaxValue;
- }
- else if (op < (long)TMinValue)
- {
- SetFpsrQCFlag(State);
-
- return TMinValue;
- }
- else
- {
- return (ulong)op;
- }
- }
-
- public static long UnsignedSrcSignedDstSatQ(ulong op, int Size, AThreadState State)
- {
- int ESize = 8 << Size;
-
- long TMaxValue = (1L << (ESize - 1)) - 1L;
-
- if (op > (ulong)TMaxValue)
- {
- SetFpsrQCFlag(State);
-
- return TMaxValue;
- }
- else
- {
- return (long)op;
- }
- }
-
- public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int Size, AThreadState State)
- {
- int ESize = 8 << Size;
-
- ulong TMaxValue = (1UL << ESize) - 1UL;
-
- if (op > TMaxValue)
- {
- SetFpsrQCFlag(State);
-
- return TMaxValue;
- }
- else
- {
- return op;
- }
- }
-
private static void SetFpsrQCFlag(AThreadState State)
{
const int QCFlagBit = 27;
State.Fpsr |= 1 << QCFlagBit;
}
+#endregion
+#region "Count"
public static ulong CountLeadingSigns(ulong Value, int Size)
{
Value ^= Value >> 1;
@@ -325,7 +342,9 @@ namespace ChocolArm64.Instruction
return (Value >> 4) + (Value & 0x0f);
}
+#endregion
+#region "Crc32"
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
@@ -384,7 +403,9 @@ namespace ChocolArm64.Instruction
return Crc;
}
+#endregion
+#region "Reverse"
public static uint ReverseBits8(uint Value)
{
Value = ((Value & 0xaa) >> 1) | ((Value & 0x55) << 1);
@@ -453,7 +474,9 @@ namespace ChocolArm64.Instruction
throw new ArgumentException(nameof(Size));
}
+#endregion
+#region "MultiplyHigh"
public static long SMulHi128(long LHS, long RHS)
{
long Result = (long)UMulHi128((ulong)LHS, (ulong)RHS);
@@ -479,5 +502,6 @@ namespace ChocolArm64.Instruction
return LHigh * RHigh + Z0 + (Z1 >> 32);
}
+#endregion
}
}