Implemented in IR the managed methods of the ShlReg region of the SoftFallback class. (#3700)

* 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
This commit is contained in:
LDj3SNuD 2022-09-19 19:49:10 +02:00 committed by GitHub
parent a77af4c5e9
commit b9f1ff3c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 351 additions and 527 deletions

View file

@ -1533,29 +1533,88 @@ namespace ARMeilleure.Instructions
context.Copy(d, res);
}
// 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)
// long SignedSignSatQ(long op, int size);
public static Operand EmitSignedSignSatQ(ArmEmitterContext context, Operand op, int size)
{
Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
int eSize = 8 << size;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
Operand lbl1 = Label();
Operand lblEnd = Label();
int eSize = 8 << sizeDst;
Operand zeroL = Const(0L);
Operand maxT = Const((1L << (eSize - 1)) - 1L);
Operand minT = Const(-(1L << (eSize - 1)));
Operand maxT = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
Operand minT = signedDst ? Const(-(1L << (eSize - 1))) : Const(0UL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
context.BranchIf(lbl1, res, maxT, Comparison.LessOrEqual);
context.BranchIf(lbl1, op, zeroL, 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.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, minT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
return res;
}
// private static ulong UnsignedSignSatQ(ulong op, int size);
public static Operand EmitUnsignedSignSatQ(ArmEmitterContext context, Operand op, int size)
{
int eSize = 8 << size;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
Operand lblEnd = Label();
Operand zeroUL = Const(0UL);
Operand maxT = Const(ulong.MaxValue >> (64 - eSize));
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL);
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
return res;
}
// 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)
{
int eSizeDst = 8 << sizeDst;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
Operand lbl1 = Label();
Operand lblEnd = Label();
Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL);
Operand minT = signedDst ? Const(-(1L << (eSizeDst - 1))) : Const(0UL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
context.Copy(res, minT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1569,18 +1628,19 @@ namespace ARMeilleure.Instructions
// 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(op.Type == OperandType.I64 && (uint)sizeDst <= 2u);
int eSizeDst = 8 << sizeDst;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
Operand lblEnd = Label();
int eSize = 8 << sizeDst;
Operand maxL = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI);
context.Copy(res, maxL);
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1601,7 +1661,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
context.BranchIf(lblEnd, res, minL, Comparison.NotEqual);
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1620,15 +1680,16 @@ namespace ARMeilleure.Instructions
Operand minL = Const(long.MinValue);
Operand maxL = Const(long.MaxValue);
Operand zero = Const(0L);
Operand zeroL = Const(0L);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
Operand add = context.Add(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2));
Operand right = context.BitwiseExclusiveOr(op1, res);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
Operand right = context.BitwiseExclusiveOr(op1, add);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual);
Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1647,9 +1708,10 @@ namespace ARMeilleure.Instructions
Operand maxUL = Const(ulong.MaxValue);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
Operand add = context.Add(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
context.Copy(res, maxUL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1668,15 +1730,16 @@ namespace ARMeilleure.Instructions
Operand minL = Const(long.MinValue);
Operand maxL = Const(long.MaxValue);
Operand zero = Const(0L);
Operand zeroL = Const(0L);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
Operand sub = context.Subtract(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub);
Operand left = context.BitwiseExclusiveOr(op1, op2);
Operand right = context.BitwiseExclusiveOr(op1, res);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual);
Operand right = context.BitwiseExclusiveOr(op1, sub);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual);
Operand isPositive = context.ICompareGreaterOrEqual(op1, zero);
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1693,12 +1756,13 @@ namespace ARMeilleure.Instructions
Operand lblEnd = Label();
Operand zero = Const(0L);
Operand zeroL = Const(0L);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2));
Operand sub = context.Subtract(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub);
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
context.Copy(res, zero);
context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1717,25 +1781,26 @@ namespace ARMeilleure.Instructions
Operand lblEnd = Label();
Operand maxL = Const(long.MaxValue);
Operand zero = Const(0L);
Operand zeroL = Const(0L);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
Operand add = context.Add(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI);
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), res);
context.BranchIf(lblEnd, notOp2AndRes, zero, Comparison.GreaterOrEqual);
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
context.BranchIf(lblEnd, notOp2AndRes, zeroL, 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.BranchIf(lbl2, op2, zeroL, 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.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);
@ -1755,20 +1820,21 @@ namespace ARMeilleure.Instructions
Operand maxUL = Const(ulong.MaxValue);
Operand maxL = Const(long.MaxValue);
Operand zero = Const(0L);
Operand zeroL = Const(0L);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2));
Operand add = context.Add(op1, op2);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add);
context.BranchIf(lbl1, op1, zero, Comparison.Less);
context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI);
context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
context.BranchIf(lblEnd, add, 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.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd);