aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitSimdShift.cs
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2022-09-19 19:49:10 +0200
committerGitHub <noreply@github.com>2022-09-19 14:49:10 -0300
commitb9f1ff3c7748c6a2665e76d17e86c3b7228f44fe (patch)
tree318f3a5c124f6a980c643b027bb73f3891953c46 /ARMeilleure/Instructions/InstEmitSimdShift.cs
parenta77af4c5e9e74ada62bfdb7ef5672eeebb00c3ab (diff)
Implemented in IR the managed methods of the ShlReg region of the SoftFallback class. (#3700)1.1.273
* Implemented in IR the managed methods of the Saturating region ... ... of the SoftFallback class (the SatQ ones). The need to natively manage the Fpcr and Fpsr system registers is still a fact. Contributes to https://github.com/Ryujinx/Ryujinx/issues/2917 ; I will open another PR to implement in Intrinsics-branchless the methods of the Saturation region as well (the SatXXXToXXX ones). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Ptc.InternalVersion = 3665 * Addressed PR feedback. * Implemented in IR the managed methods of the ShlReg region of the SoftFallback class. It also includes the last two SatQ ones (following up on https://github.com/Ryujinx/Ryujinx/pull/3665). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Update InstEmitSimdHelper.cs
Diffstat (limited to 'ARMeilleure/Instructions/InstEmitSimdShift.cs')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdShift.cs386
1 files changed, 239 insertions, 147 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs
index 1a95200d..146aeafa 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift.cs
@@ -188,23 +188,7 @@ namespace ARMeilleure.Instructions
public static void Sqrshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
}
public static void Sqrshrn_S(ArmEmitterContext context)
@@ -229,23 +213,7 @@ namespace ARMeilleure.Instructions
public static void Sqshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
}
public static void Sqshrn_S(ArmEmitterContext context)
@@ -280,23 +248,7 @@ namespace ARMeilleure.Instructions
public static void Srshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
}
public static void Srshr_S(ArmEmitterContext context)
@@ -393,12 +345,12 @@ namespace ARMeilleure.Instructions
public static void Sshl_S(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: true, scalar: true);
+ EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed);
}
public static void Sshl_V(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: true, scalar: false);
+ EmitShlRegOp(context, ShlRegFlags.Signed);
}
public static void Sshll_V(ArmEmitterContext context)
@@ -506,23 +458,7 @@ namespace ARMeilleure.Instructions
public static void Uqrshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
}
public static void Uqrshrn_S(ArmEmitterContext context)
@@ -537,23 +473,7 @@ namespace ARMeilleure.Instructions
public static void Uqshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Saturating);
}
public static void Uqshrn_S(ArmEmitterContext context)
@@ -568,23 +488,7 @@ namespace ARMeilleure.Instructions
public static void Urshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Round);
}
public static void Urshr_S(ArmEmitterContext context)
@@ -677,12 +581,12 @@ namespace ARMeilleure.Instructions
public static void Ushl_S(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: false, scalar: true);
+ EmitShlRegOp(context, ShlRegFlags.Scalar);
}
public static void Ushl_V(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: false, scalar: false);
+ EmitShlRegOp(context, ShlRegFlags.None);
}
public static void Ushll_V(ArmEmitterContext context)
@@ -872,43 +776,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool signed)
- {
- Debug.Assert(op.Type == OperandType.I64);
- Debug.Assert(shiftLsB.Type == OperandType.I32);
- Debug.Assert((uint)size < 4u);
-
- Operand negShiftLsB = context.Negate(shiftLsB);
-
- Operand isInRange = context.BitwiseAnd(
- context.ICompareLess(shiftLsB, Const(8 << size)),
- context.ICompareLess(negShiftLsB, Const(8 << size)));
-
- Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
-
- Operand shl = context.ShiftLeft(op, shiftLsB);
-
- Operand sarOrShr = signed
- ? context.ShiftRightSI(op, negShiftLsB)
- : context.ShiftRightUI(op, negShiftLsB);
-
- Operand res = context.ConditionalSelect(isPositive, shl, sarOrShr);
-
- if (signed)
- {
- Operand isPositive2 = context.ICompareGreaterOrEqual(op, Const(0L));
-
- Operand res2 = context.ConditionalSelect(isPositive2, Const(0L), Const(-1L));
- res2 = context.ConditionalSelect(isPositive, Const(0L), res2);
-
- return context.ConditionalSelect(isInRange, res, res2);
- }
- else
- {
- return context.ConditionalSelect(isInRange, res, Const(0UL));
- }
- }
-
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
{
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
@@ -1168,8 +1035,23 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitSshlOrUshl(ArmEmitterContext context, bool signed, bool scalar)
+ [Flags]
+ private enum ShlRegFlags
+ {
+ None = 0,
+ Scalar = 1 << 0,
+ Signed = 1 << 1,
+ Round = 1 << 2,
+ Saturating = 1 << 3
+ }
+
+ private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
{
+ bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
+ bool signed = flags.HasFlag(ShlRegFlags.Signed);
+ bool round = flags.HasFlag(ShlRegFlags.Round);
+ bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
+
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand res = context.VectorZero();
@@ -1178,15 +1060,225 @@ namespace ARMeilleure.Instructions
for (int index = 0; index < elems; index++)
{
- Operand ne = EmitVectorExtract (context, op.Rn, index, op.Size, signed);
- Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0);
+ Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
+ Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, size: 0);
- Operand e = EmitShlRegOp(context, ne, context.ConvertI64ToI32(me), op.Size, signed);
+ Operand e = !saturating
+ ? EmitShlReg(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed)
+ : EmitShlRegSatQ(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed);
res = EmitVectorInsert(context, res, e, index, op.Size);
}
context.Copy(GetVec(op.Rd), res);
}
+
+ // long SignedShlReg(long op, int shiftLsB, bool round, int size);
+ // ulong UnsignedShlReg(ulong op, int shiftLsB, bool round, int size);
+ private static Operand EmitShlReg(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
+ {
+ int eSize = 8 << size;
+
+ Debug.Assert(op.Type == OperandType.I64);
+ Debug.Assert(shiftLsB.Type == OperandType.I32);
+ Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
+
+ Operand lbl1 = Label();
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zero = Const(0);
+ Operand zeroL = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, signed
+ ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
+ : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
+ Operand shl = context.ShiftLeft(op, shiftLsB);
+ Operand isGreaterOrEqual = context.ICompareGreaterOrEqual(shiftLsB, eSizeOp);
+ context.Copy(res, context.ConditionalSelect(isGreaterOrEqual, zeroL, shl));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // long SignedShlRegSatQ(long op, int shiftLsB, bool round, int size);
+ // ulong UnsignedShlRegSatQ(ulong op, int shiftLsB, bool round, int size);
+ private static Operand EmitShlRegSatQ(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
+ {
+ int eSize = 8 << size;
+
+ Debug.Assert(op.Type == OperandType.I64);
+ Debug.Assert(shiftLsB.Type == OperandType.I32);
+ Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
+
+ Operand lbl1 = Label();
+ Operand lbl2 = Label();
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zero = Const(0);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, signed
+ ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
+ : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
+ context.BranchIf(lbl2, shiftLsB, eSizeOp, Comparison.Less);
+ context.Copy(res, signed
+ ? EmitSignedSignSatQ(context, op, size)
+ : EmitUnsignedSignSatQ(context, op, size));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl2);
+ Operand shl = context.ShiftLeft(op, shiftLsB);
+ if (eSize == 64)
+ {
+ Operand sarOrShr = signed
+ ? context.ShiftRightSI(shl, shiftLsB)
+ : context.ShiftRightUI(shl, shiftLsB);
+ context.Copy(res, shl);
+ context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
+ context.Copy(res, signed
+ ? EmitSignedSignSatQ(context, op, size)
+ : EmitUnsignedSignSatQ(context, op, size));
+ }
+ else
+ {
+ context.Copy(res, signed
+ ? EmitSignedSrcSatQ(context, shl, size, signedDst: true)
+ : EmitUnsignedSrcSatQ(context, shl, size, signedDst: false));
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // shift := [1, 128]; eSize := {8, 16, 32, 64}.
+ // long SignedShrReg(long op, int shift, bool round, int eSize);
+ private static Operand EmitSignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
+ {
+ if (round)
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroL = Const(0L);
+ Operand one = Const(1);
+ Operand oneL = Const(1L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.GreaterOrEqual);
+ Operand roundConst = context.ShiftLeft(oneL, context.Subtract(shift, one));
+ Operand add = context.Add(op, roundConst);
+ Operand sar = context.ShiftRightSI(add, shift);
+ if (eSize == 64)
+ {
+ Operand shr = context.ShiftRightUI(add, shift);
+ Operand left = context.BitwiseAnd(context.Negate(op), context.BitwiseExclusiveOr(op, add));
+ Operand isLess = context.ICompareLess(left, zeroL);
+ context.Copy(res, context.ConditionalSelect(isLess, shr, sar));
+ }
+ else
+ {
+ context.Copy(res, sar);
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ else
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroL = Const(0L);
+ Operand negOneL = Const(-1L);
+
+ Operand sar = context.ShiftRightSI(op, shift);
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sar);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
+ Operand isLess = context.ICompareLess(op, zeroL);
+ context.Copy(res, context.ConditionalSelect(isLess, negOneL, zeroL));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ }
+
+ // shift := [1, 128]; eSize := {8, 16, 32, 64}.
+ // ulong UnsignedShrReg(ulong op, int shift, bool round, int eSize);
+ private static Operand EmitUnsignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
+ {
+ if (round)
+ {
+ Operand lblEnd = Label();
+
+ Operand zeroUL = Const(0UL);
+ Operand one = Const(1);
+ Operand oneUL = Const(1UL);
+ Operand eSizeMaxOp = Const(64);
+ Operand oneShl63UL = Const(1UL << 63);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL);
+
+ context.BranchIf(lblEnd, shift, eSizeMaxOp, Comparison.Greater);
+ Operand roundConst = context.ShiftLeft(oneUL, context.Subtract(shift, one));
+ Operand add = context.Add(op, roundConst);
+ Operand shr = context.ShiftRightUI(add, shift);
+ Operand isEqual = context.ICompareEqual(shift, eSizeMaxOp);
+ context.Copy(res, context.ConditionalSelect(isEqual, zeroUL, shr));
+ if (eSize == 64)
+ {
+ context.BranchIf(lblEnd, add, op, Comparison.GreaterOrEqualUI);
+ Operand right = context.BitwiseOr(shr, context.ShiftRightUI(oneShl63UL, context.Subtract(shift, one)));
+ context.Copy(res, context.ConditionalSelect(isEqual, oneUL, right));
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ else
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroUL = Const(0UL);
+
+ Operand shr = context.ShiftRightUI(op, shift);
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), shr);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
+ context.Copy(res, zeroUL);
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ }
}
}