From b9f1ff3c7748c6a2665e76d17e86c3b7228f44fe Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Mon, 19 Sep 2022 19:49:10 +0200 Subject: [PATCH] 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 --- .../Instructions/InstEmitSimdHelper.cs | 156 +++++-- ARMeilleure/Instructions/InstEmitSimdShift.cs | 386 +++++++++++------- ARMeilleure/Instructions/SoftFallback.cs | 330 --------------- ARMeilleure/Translation/Delegates.cs | 4 - ARMeilleure/Translation/PTC/Ptc.cs | 2 +- 5 files changed, 351 insertions(+), 527 deletions(-) diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs index 27b5c1302..80dfc6889 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs @@ -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); diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs index 1a95200db..146aeafa7 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; + } + } } } diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs index 829dd37a3..d5e1ab65d 100644 --- a/ARMeilleure/Instructions/SoftFallback.cs +++ b/ARMeilleure/Instructions/SoftFallback.cs @@ -5,287 +5,6 @@ namespace ARMeilleure.Instructions { 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" public static long SignedShrImm64(long value, long roundConst, int shift) { @@ -508,55 +227,6 @@ namespace ARMeilleure.Instructions } #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" public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). { diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs index b36472b83..0da69ebc3 100644 --- a/ARMeilleure/Translation/Delegates.cs +++ b/ARMeilleure/Translation/Delegates.cs @@ -179,8 +179,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1))); 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.Tbl1))); 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.Tbx3))); 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(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert))); diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 71f69ef7c..01f089882 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\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 BackupDir = "1";