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); context.Copy(d, res);
} }
// TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned). // long SignedSignSatQ(long op, int size);
// long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size); public static Operand EmitSignedSignSatQ(ArmEmitterContext context, Operand op, int size)
public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst)
{ {
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 lbl1 = Label();
Operand lblEnd = 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 res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
Operand minT = signedDst ? Const(-(1L << (eSize - 1))) : Const(0UL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
context.BranchIf(lbl1, res, maxT, Comparison.LessOrEqual);
context.Copy(res, maxT); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); 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.Copy(res, minT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1569,18 +1628,19 @@ namespace ARMeilleure.Instructions
// long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size); // long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size);
public static Operand EmitUnsignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst) 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(); Operand lblEnd = Label();
int eSize = 8 << sizeDst; Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL);
Operand maxL = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL);
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI); context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
context.Copy(res, maxL); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1601,7 +1661,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); 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.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1620,15 +1680,16 @@ namespace ARMeilleure.Instructions
Operand minL = Const(long.MinValue); Operand minL = Const(long.MinValue);
Operand maxL = Const(long.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);
Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2)); Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2));
Operand right = context.BitwiseExclusiveOr(op1, res); Operand right = context.BitwiseExclusiveOr(op1, add);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual); 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.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1647,9 +1708,10 @@ namespace ARMeilleure.Instructions
Operand maxUL = Const(ulong.MaxValue); 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.Copy(res, maxUL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1668,15 +1730,16 @@ namespace ARMeilleure.Instructions
Operand minL = Const(long.MinValue); Operand minL = Const(long.MinValue);
Operand maxL = Const(long.MaxValue); 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 left = context.BitwiseExclusiveOr(op1, op2);
Operand right = context.BitwiseExclusiveOr(op1, res); Operand right = context.BitwiseExclusiveOr(op1, sub);
context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual); 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.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1693,12 +1756,13 @@ namespace ARMeilleure.Instructions
Operand lblEnd = Label(); 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.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
context.Copy(res, zero); context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1717,25 +1781,26 @@ namespace ARMeilleure.Instructions
Operand lblEnd = Label(); Operand lblEnd = Label();
Operand maxL = Const(long.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, maxL, Comparison.GreaterUI); context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI);
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), res); Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
context.BranchIf(lblEnd, notOp2AndRes, zero, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lbl2, op2, zero, Comparison.Less); context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl2); context.MarkLabel(lbl2);
context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI); context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
@ -1755,20 +1820,21 @@ namespace ARMeilleure.Instructions
Operand maxUL = Const(ulong.MaxValue); Operand maxUL = Const(ulong.MaxValue);
Operand maxL = Const(long.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(lbl1, op1, zeroL, Comparison.Less);
context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI); context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
context.Copy(res, maxUL); context.Copy(res, maxUL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI); context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
context.BranchIf(lblEnd, res, zero, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, zero); context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
context.Branch(lblEnd); context.Branch(lblEnd);

View File

@ -188,23 +188,7 @@ namespace ARMeilleure.Instructions
public static void Sqrshl_V(ArmEmitterContext context) public static void Sqrshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
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);
} }
public static void Sqrshrn_S(ArmEmitterContext context) public static void Sqrshrn_S(ArmEmitterContext context)
@ -229,23 +213,7 @@ namespace ARMeilleure.Instructions
public static void Sqshl_V(ArmEmitterContext context) public static void Sqshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
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);
} }
public static void Sqshrn_S(ArmEmitterContext context) public static void Sqshrn_S(ArmEmitterContext context)
@ -280,23 +248,7 @@ namespace ARMeilleure.Instructions
public static void Srshl_V(ArmEmitterContext context) public static void Srshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
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);
} }
public static void Srshr_S(ArmEmitterContext context) public static void Srshr_S(ArmEmitterContext context)
@ -393,12 +345,12 @@ namespace ARMeilleure.Instructions
public static void Sshl_S(ArmEmitterContext context) 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) public static void Sshl_V(ArmEmitterContext context)
{ {
EmitSshlOrUshl(context, signed: true, scalar: false); EmitShlRegOp(context, ShlRegFlags.Signed);
} }
public static void Sshll_V(ArmEmitterContext context) public static void Sshll_V(ArmEmitterContext context)
@ -506,23 +458,7 @@ namespace ARMeilleure.Instructions
public static void Uqrshl_V(ArmEmitterContext context) public static void Uqrshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
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);
} }
public static void Uqrshrn_S(ArmEmitterContext context) public static void Uqrshrn_S(ArmEmitterContext context)
@ -537,23 +473,7 @@ namespace ARMeilleure.Instructions
public static void Uqshl_V(ArmEmitterContext context) public static void Uqshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Saturating);
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);
} }
public static void Uqshrn_S(ArmEmitterContext context) public static void Uqshrn_S(ArmEmitterContext context)
@ -568,23 +488,7 @@ namespace ARMeilleure.Instructions
public static void Urshl_V(ArmEmitterContext context) public static void Urshl_V(ArmEmitterContext context)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; EmitShlRegOp(context, ShlRegFlags.Round);
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);
} }
public static void Urshr_S(ArmEmitterContext context) public static void Urshr_S(ArmEmitterContext context)
@ -677,12 +581,12 @@ namespace ARMeilleure.Instructions
public static void Ushl_S(ArmEmitterContext context) public static void Ushl_S(ArmEmitterContext context)
{ {
EmitSshlOrUshl(context, signed: false, scalar: true); EmitShlRegOp(context, ShlRegFlags.Scalar);
} }
public static void Ushl_V(ArmEmitterContext context) public static void Ushl_V(ArmEmitterContext context)
{ {
EmitSshlOrUshl(context, signed: false, scalar: false); EmitShlRegOp(context, ShlRegFlags.None);
} }
public static void Ushll_V(ArmEmitterContext context) public static void Ushll_V(ArmEmitterContext context)
@ -872,43 +776,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res); 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) private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
{ {
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; 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; OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand res = context.VectorZero(); Operand res = context.VectorZero();
@ -1178,15 +1060,225 @@ namespace ARMeilleure.Instructions
for (int index = 0; index < elems; index++) for (int index = 0; index < elems; index++)
{ {
Operand ne = EmitVectorExtract (context, op.Rn, index, op.Size, signed); Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0); 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); res = EmitVectorInsert(context, res, e, index, op.Size);
} }
context.Copy(GetVec(op.Rd), res); 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;
}
}
} }
} }

View File

@ -5,287 +5,6 @@ namespace ARMeilleure.Instructions
{ {
static class SoftFallback static class SoftFallback
{ {
#region "ShlReg"
public static long SignedShlReg(long value, long shift, bool round, int size)
{
int eSize = 8 << size;
int shiftLsB = (sbyte)shift;
if (shiftLsB < 0)
{
return SignedShrReg(value, -shiftLsB, round, eSize);
}
else if (shiftLsB > 0)
{
if (shiftLsB >= eSize)
{
return 0L;
}
return value << shiftLsB;
}
else /* if (shiftLsB == 0) */
{
return value;
}
}
public static ulong UnsignedShlReg(ulong value, ulong shift, bool round, int size)
{
int eSize = 8 << size;
int shiftLsB = (sbyte)shift;
if (shiftLsB < 0)
{
return UnsignedShrReg(value, -shiftLsB, round, eSize);
}
else if (shiftLsB > 0)
{
if (shiftLsB >= eSize)
{
return 0UL;
}
return value << shiftLsB;
}
else /* if (shiftLsB == 0) */
{
return value;
}
}
public static long SignedShlRegSatQ(long value, long shift, bool round, int size)
{
ExecutionContext context = NativeInterface.GetContext();
int eSize = 8 << size;
int shiftLsB = (sbyte)shift;
if (shiftLsB < 0)
{
return SignedShrReg(value, -shiftLsB, round, eSize);
}
else if (shiftLsB > 0)
{
if (shiftLsB >= eSize)
{
return SignedSignSatQ(value, eSize, context);
}
if (eSize == 64)
{
long shl = value << shiftLsB;
long shr = shl >> shiftLsB;
if (shr != value)
{
return SignedSignSatQ(value, eSize, context);
}
else /* if (shr == value) */
{
return shl;
}
}
else /* if (eSize != 64) */
{
return SignedSrcSignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitSignedSrcSatQ(signedDst: true).
}
}
else /* if (shiftLsB == 0) */
{
return value;
}
}
public static ulong UnsignedShlRegSatQ(ulong value, ulong shift, bool round, int size)
{
ExecutionContext context = NativeInterface.GetContext();
int eSize = 8 << size;
int shiftLsB = (sbyte)shift;
if (shiftLsB < 0)
{
return UnsignedShrReg(value, -shiftLsB, round, eSize);
}
else if (shiftLsB > 0)
{
if (shiftLsB >= eSize)
{
return UnsignedSignSatQ(value, eSize, context);
}
if (eSize == 64)
{
ulong shl = value << shiftLsB;
ulong shr = shl >> shiftLsB;
if (shr != value)
{
return UnsignedSignSatQ(value, eSize, context);
}
else /* if (shr == value) */
{
return shl;
}
}
else /* if (eSize != 64) */
{
return UnsignedSrcUnsignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitUnsignedSrcSatQ(signedDst: false).
}
}
else /* if (shiftLsB == 0) */
{
return value;
}
}
private static long SignedShrReg(long value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}.
{
if (round)
{
if (shift >= eSize)
{
return 0L;
}
long roundConst = 1L << (shift - 1);
long add = value + roundConst;
if (eSize == 64)
{
if ((~value & (value ^ add)) < 0L)
{
return (long)((ulong)add >> shift);
}
else
{
return add >> shift;
}
}
else /* if (eSize != 64) */
{
return add >> shift;
}
}
else /* if (!round) */
{
if (shift >= eSize)
{
if (value < 0L)
{
return -1L;
}
else /* if (value >= 0L) */
{
return 0L;
}
}
return value >> shift;
}
}
private static ulong UnsignedShrReg(ulong value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}.
{
if (round)
{
if (shift > 64)
{
return 0UL;
}
ulong roundConst = 1UL << (shift - 1);
ulong add = value + roundConst;
if (eSize == 64)
{
if ((add < value) && (add < roundConst))
{
if (shift == 64)
{
return 1UL;
}
return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
}
else
{
if (shift == 64)
{
return 0UL;
}
return add >> shift;
}
}
else /* if (eSize != 64) */
{
if (shift == 64)
{
return 0UL;
}
return add >> shift;
}
}
else /* if (!round) */
{
if (shift >= eSize)
{
return 0UL;
}
return value >> shift;
}
}
private static long SignedSignSatQ(long op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}.
{
long tMaxValue = (1L << (eSize - 1)) - 1L;
long tMinValue = -(1L << (eSize - 1));
if (op > 0L)
{
context.Fpsr |= FPSR.Qc;
return tMaxValue;
}
else if (op < 0L)
{
context.Fpsr |= FPSR.Qc;
return tMinValue;
}
else
{
return 0L;
}
}
private static ulong UnsignedSignSatQ(ulong op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}.
{
ulong tMaxValue = ulong.MaxValue >> (64 - eSize);
if (op > 0UL)
{
context.Fpsr |= FPSR.Qc;
return tMaxValue;
}
else
{
return 0UL;
}
}
#endregion
#region "ShrImm64" #region "ShrImm64"
public static long SignedShrImm64(long value, long roundConst, int shift) public static long SignedShrImm64(long value, long roundConst, int shift)
{ {
@ -508,55 +227,6 @@ namespace ARMeilleure.Instructions
} }
#endregion #endregion
#region "Saturating"
private static long SignedSrcSignedDstSatQ(long op, int size)
{
ExecutionContext context = NativeInterface.GetContext();
int eSize = 8 << size;
long tMaxValue = (1L << (eSize - 1)) - 1L;
long tMinValue = -(1L << (eSize - 1));
if (op > tMaxValue)
{
context.Fpsr |= FPSR.Qc;
return tMaxValue;
}
else if (op < tMinValue)
{
context.Fpsr |= FPSR.Qc;
return tMinValue;
}
else
{
return op;
}
}
private static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size)
{
ExecutionContext context = NativeInterface.GetContext();
int eSize = 8 << size;
ulong tMaxValue = (1UL << eSize) - 1UL;
if (op > tMaxValue)
{
context.Fpsr |= FPSR.Qc;
return tMaxValue;
}
else
{
return op;
}
}
#endregion
#region "Count" #region "Count"
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{ {

View File

@ -179,8 +179,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
@ -190,8 +188,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert))); SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));

View File

@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 3695; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";