aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitSimdHelper.cs
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2022-09-09 00:40:41 +0200
committerGitHub <noreply@github.com>2022-09-08 19:40:41 -0300
commit7baa08dcb4b38fe36bb19bf84b3fcd386d143463 (patch)
treebfbbd817e56b3d47a1ca9662bf0c69c0119ddd58 /ARMeilleure/Instructions/InstEmitSimdHelper.cs
parent408bd63b08cbde8ba55bb05a39868271a9e40ba4 (diff)
Implemented in IR the managed methods of the Saturating region ... (#3665)1.1.252
* 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.
Diffstat (limited to 'ARMeilleure/Instructions/InstEmitSimdHelper.cs')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdHelper.cs293
1 files changed, 236 insertions, 57 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
index 736d16a3..805656d2 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
@@ -1352,7 +1352,7 @@ namespace ARMeilleure.Instructions
if (op.Size <= 2)
{
- de = EmitSatQ(context, emit(ne), op.Size, signedSrc: true, signedDst: true);
+ de = EmitSignedSrcSatQ(context, emit(ne), op.Size, signedDst: true);
}
else /* if (op.Size == 3) */
{
@@ -1419,15 +1419,18 @@ namespace ARMeilleure.Instructions
{
Operand temp = add ? context.Add(ne, me) : context.Subtract(ne, me);
- de = EmitSatQ(context, temp, op.Size, signedSrc: true, signedDst: signed);
+ de = EmitSignedSrcSatQ(context, temp, op.Size, signedDst: signed);
}
- else if (add) /* if (op.Size == 3) */
- {
- de = EmitBinarySatQAdd(context, ne, me, signed);
- }
- else /* if (sub) */
+ else /* if (op.Size == 3) */
{
- de = EmitBinarySatQSub(context, ne, me, signed);
+ if (add)
+ {
+ de = signed ? EmitBinarySignedSatQAdd(context, ne, me) : EmitBinaryUnsignedSatQAdd(context, ne, me);
+ }
+ else /* if (sub) */
+ {
+ de = signed ? EmitBinarySignedSatQSub(context, ne, me) : EmitBinaryUnsignedSatQSub(context, ne, me);
+ }
}
res = EmitVectorInsert(context, res, de, index, op.Size);
@@ -1445,11 +1448,11 @@ namespace ARMeilleure.Instructions
{
Operand temp = context.Add(ne, me);
- de = EmitSatQ(context, temp, op.Size, signedSrc: true, signedDst: signed);
+ de = EmitSignedSrcSatQ(context, temp, op.Size, signedDst: signed);
}
else /* if (op.Size == 3) */
{
- de = EmitBinarySatQAccumulate(context, ne, me, signed);
+ de = signed ? EmitBinarySignedSatQAcc(context, ne, me) : EmitBinaryUnsignedSatQAcc(context, ne, me);
}
res = EmitVectorInsert(context, res, de, index, op.Size);
@@ -1475,7 +1478,7 @@ namespace ARMeilleure.Instructions
me = EmitVectorExtract(context, ((OpCodeSimdReg)op).Rm, index, op.Size, signed);
}
- Operand de = EmitSatQ(context, emit(ne, me), op.Size, true, signed);
+ Operand de = EmitSignedSrcSatQ(context, emit(ne, me), op.Size, signedDst: signed);
res = EmitVectorInsert(context, res, de, index, op.Size);
}
@@ -1520,7 +1523,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size + 1, signedSrc);
- Operand temp = EmitSatQ(context, ne, op.Size, signedSrc, signedDst);
+ Operand temp = signedSrc
+ ? EmitSignedSrcSatQ(context, ne, op.Size, signedDst)
+ : EmitUnsignedSrcSatQ(context, ne, op.Size, signedDst);
res = EmitVectorInsert(context, res, temp, part + index, op.Size);
}
@@ -1528,74 +1533,248 @@ namespace ARMeilleure.Instructions
context.Copy(d, res);
}
- // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
- public static Operand EmitSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedSrc, bool signedDst)
+ // TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned).
+ // long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size);
+ public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
{
- if ((uint)sizeDst > 2u)
- {
- throw new ArgumentOutOfRangeException(nameof(sizeDst));
- }
+ Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
- MethodInfo info;
+ Operand lbl1 = Label();
+ Operand lblEnd = Label();
- if (signedSrc)
- {
- info = signedDst
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcSignedDstSatQ))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcUnsignedDstSatQ));
- }
- else
- {
- info = signedDst
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcSignedDstSatQ))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ));
- }
+ int eSize = 8 << sizeDst;
+
+ Operand maxT = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
+ Operand minT = signedDst ? Const(-(1L << (eSize - 1))) : Const(0UL);
- return context.Call(info, op, Const(sizeDst));
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lbl1, res, maxT, Comparison.LessOrEqual);
+ context.Copy(res, maxT);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, res, minT, Comparison.GreaterOrEqual);
+ context.Copy(res, minT);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
}
- // TSrc (64bit) == TDst (64bit); signed.
- public static Operand EmitUnarySignedSatQAbsOrNeg(ArmEmitterContext context, Operand op)
+ // TSrc (16bit, 32bit, 64bit; unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
+ // long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size);
+ public static Operand EmitUnsignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
{
- Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
+ Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
+
+ Operand lblEnd = Label();
+
+ int eSize = 8 << sizeDst;
+
+ Operand maxL = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI);
+ context.Copy(res, maxL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnarySignedSatQAbsOrNeg)), op);
+ context.MarkLabel(lblEnd);
+
+ return res;
}
- // TSrcs (64bit) == TDst (64bit); signed, unsigned.
- public static Operand EmitBinarySatQAdd(ArmEmitterContext context, Operand op1, Operand op2, bool signed)
+ // long UnarySignedSatQAbsOrNeg(long op);
+ private static Operand EmitUnarySignedSatQAbsOrNeg(ArmEmitterContext context, Operand op)
{
- Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
+ Debug.Assert(op.Type == OperandType.I64);
+
+ Operand lblEnd = Label();
+
+ Operand minL = Const(long.MinValue);
+ Operand maxL = Const(long.MaxValue);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lblEnd, res, minL, Comparison.NotEqual);
+ context.Copy(res, maxL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
- MethodInfo info = signed
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAdd))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAdd));
+ context.MarkLabel(lblEnd);
- return context.Call(info, op1, op2);
+ return res;
}
- // TSrcs (64bit) == TDst (64bit); signed, unsigned.
- public static Operand EmitBinarySatQSub(ArmEmitterContext context, Operand op1, Operand op2, bool signed)
+ // long BinarySignedSatQAdd(long op1, long op2);
+ private static Operand EmitBinarySignedSatQAdd(ArmEmitterContext context, Operand op1, Operand op2)
{
- Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lblEnd = Label();
+
+ Operand minL = Const(long.MinValue);
+ Operand maxL = Const(long.MaxValue);
+ Operand zero = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
+
+ Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2));
+ Operand right = context.BitwiseExclusiveOr(op1, res);
+ context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
- MethodInfo info = signed
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQSub))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQSub));
+ Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
+ context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
- return context.Call(info, op1, op2);
+ context.MarkLabel(lblEnd);
+
+ return res;
}
- // TSrcs (64bit) == TDst (64bit); signed, unsigned.
- public static Operand EmitBinarySatQAccumulate(ArmEmitterContext context, Operand op1, Operand op2, bool signed)
+ // ulong BinaryUnsignedSatQAdd(ulong op1, ulong op2);
+ private static Operand EmitBinaryUnsignedSatQAdd(ArmEmitterContext context, Operand op1, Operand op2)
{
- Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lblEnd = Label();
+
+ Operand maxUL = Const(ulong.MaxValue);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
- MethodInfo info = signed
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAcc))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAcc));
+ context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
+ context.Copy(res, maxUL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
- return context.Call(info, op1, op2);
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // long BinarySignedSatQSub(long op1, long op2);
+ private static Operand EmitBinarySignedSatQSub(ArmEmitterContext context, Operand op1, Operand op2)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lblEnd = Label();
+
+ Operand minL = Const(long.MinValue);
+ Operand maxL = Const(long.MaxValue);
+ Operand zero = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
+
+ Operand left = context.BitwiseExclusiveOr(op1, op2);
+ Operand right = context.BitwiseExclusiveOr(op1, res);
+ context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
+
+ Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
+ context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // ulong BinaryUnsignedSatQSub(ulong op1, ulong op2);
+ private static Operand EmitBinaryUnsignedSatQSub(ArmEmitterContext context, Operand op1, Operand op2)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lblEnd = Label();
+
+ Operand zero = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
+
+ context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
+ context.Copy(res, zero);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // long BinarySignedSatQAcc(ulong op1, long op2);
+ private static Operand EmitBinarySignedSatQAcc(ArmEmitterContext context, Operand op1, Operand op2)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lbl1 = Label();
+ Operand lbl2 = Label();
+ Operand lblEnd = Label();
+
+ Operand maxL = Const(long.MaxValue);
+ Operand zero = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
+
+ context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI);
+ Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), res);
+ context.BranchIf(lblEnd, notOp2AndRes, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, maxL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lbl2, op2, zero, Comparison.Less);
+ context.Copy(res, maxL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl2);
+ context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI);
+ context.Copy(res, maxL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // ulong BinaryUnsignedSatQAcc(long op1, ulong op2);
+ private static Operand EmitBinaryUnsignedSatQAcc(ArmEmitterContext context, Operand op1, Operand op2)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand lbl1 = Label();
+ Operand lblEnd = Label();
+
+ Operand maxUL = Const(ulong.MaxValue);
+ Operand maxL = Const(long.MaxValue);
+ Operand zero = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
+
+ context.BranchIf(lbl1, op1, zero, Comparison.Less);
+ context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
+ context.Copy(res, maxUL);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
+ context.BranchIf(lblEnd, res, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, zero);
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
}
public static Operand EmitFloatAbs(ArmEmitterContext context, Operand value, bool single, bool vector)