aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Instructions')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdHelper.cs148
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdShift.cs386
-rw-r--r--ARMeilleure/Instructions/SoftFallback.cs330
3 files changed, 346 insertions, 518 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
index 27b5c130..80dfc688 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
@@ -1533,29 +1533,88 @@ namespace ARMeilleure.Instructions
context.Copy(d, res);
}
+ // long SignedSignSatQ(long op, int size);
+ public static Operand EmitSignedSignSatQ(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 lbl1 = Label();
+ Operand lblEnd = Label();
+
+ Operand zeroL = Const(0L);
+ Operand maxT = Const((1L << (eSize - 1)) - 1L);
+ Operand minT = Const(-(1L << (eSize - 1)));
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
+
+ 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, 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)
{
- 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 lbl1 = Label();
Operand lblEnd = Label();
- 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);
+ 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, res, maxT, Comparison.LessOrEqual);
+ 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, res, minT, Comparison.GreaterOrEqual);
+ 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;
- Operand lblEnd = Label();
+ Debug.Assert(op.Type == OperandType.I64);
+ Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32);
- int eSize = 8 << sizeDst;
+ Operand lblEnd = Label();
- 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 1a95200d..146aeafa 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift.cs
@@ -188,23 +188,7 @@ namespace ARMeilleure.Instructions
public static void Sqrshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating);
}
public static void Sqrshrn_S(ArmEmitterContext context)
@@ -229,23 +213,7 @@ namespace ARMeilleure.Instructions
public static void Sqshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating);
}
public static void Sqshrn_S(ArmEmitterContext context)
@@ -280,23 +248,7 @@ namespace ARMeilleure.Instructions
public static void Srshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round);
}
public static void Srshr_S(ArmEmitterContext context)
@@ -393,12 +345,12 @@ namespace ARMeilleure.Instructions
public static void Sshl_S(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: true, scalar: true);
+ EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed);
}
public static void Sshl_V(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: true, scalar: false);
+ EmitShlRegOp(context, ShlRegFlags.Signed);
}
public static void Sshll_V(ArmEmitterContext context)
@@ -506,23 +458,7 @@ namespace ARMeilleure.Instructions
public static void Uqrshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating);
}
public static void Uqrshrn_S(ArmEmitterContext context)
@@ -537,23 +473,7 @@ namespace ARMeilleure.Instructions
public static void Uqshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Saturating);
}
public static void Uqshrn_S(ArmEmitterContext context)
@@ -568,23 +488,7 @@ namespace ARMeilleure.Instructions
public static void Urshl_V(ArmEmitterContext context)
{
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
-
- Operand res = context.VectorZero();
-
- int elems = op.GetBytesCount() >> op.Size;
-
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
-
- Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)), ne, me, Const(1), Const(op.Size));
-
- res = EmitVectorInsert(context, res, e, index, op.Size);
- }
-
- context.Copy(GetVec(op.Rd), res);
+ EmitShlRegOp(context, ShlRegFlags.Round);
}
public static void Urshr_S(ArmEmitterContext context)
@@ -677,12 +581,12 @@ namespace ARMeilleure.Instructions
public static void Ushl_S(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: false, scalar: true);
+ EmitShlRegOp(context, ShlRegFlags.Scalar);
}
public static void Ushl_V(ArmEmitterContext context)
{
- EmitSshlOrUshl(context, signed: false, scalar: false);
+ EmitShlRegOp(context, ShlRegFlags.None);
}
public static void Ushll_V(ArmEmitterContext context)
@@ -872,43 +776,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool signed)
- {
- Debug.Assert(op.Type == OperandType.I64);
- Debug.Assert(shiftLsB.Type == OperandType.I32);
- Debug.Assert((uint)size < 4u);
-
- Operand negShiftLsB = context.Negate(shiftLsB);
-
- Operand isInRange = context.BitwiseAnd(
- context.ICompareLess(shiftLsB, Const(8 << size)),
- context.ICompareLess(negShiftLsB, Const(8 << size)));
-
- Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
-
- Operand shl = context.ShiftLeft(op, shiftLsB);
-
- Operand sarOrShr = signed
- ? context.ShiftRightSI(op, negShiftLsB)
- : context.ShiftRightUI(op, negShiftLsB);
-
- Operand res = context.ConditionalSelect(isPositive, shl, sarOrShr);
-
- if (signed)
- {
- Operand isPositive2 = context.ICompareGreaterOrEqual(op, Const(0L));
-
- Operand res2 = context.ConditionalSelect(isPositive2, Const(0L), Const(-1L));
- res2 = context.ConditionalSelect(isPositive, Const(0L), res2);
-
- return context.ConditionalSelect(isInRange, res, res2);
- }
- else
- {
- return context.ConditionalSelect(isInRange, res, Const(0UL));
- }
- }
-
private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round)
{
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
@@ -1168,8 +1035,23 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitSshlOrUshl(ArmEmitterContext context, bool signed, bool scalar)
+ [Flags]
+ private enum ShlRegFlags
+ {
+ None = 0,
+ Scalar = 1 << 0,
+ Signed = 1 << 1,
+ Round = 1 << 2,
+ Saturating = 1 << 3
+ }
+
+ private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
{
+ bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
+ bool signed = flags.HasFlag(ShlRegFlags.Signed);
+ bool round = flags.HasFlag(ShlRegFlags.Round);
+ bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
+
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand res = context.VectorZero();
@@ -1178,15 +1060,225 @@ namespace ARMeilleure.Instructions
for (int index = 0; index < elems; index++)
{
- Operand ne = EmitVectorExtract (context, op.Rn, index, op.Size, signed);
- Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0);
+ Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
+ Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, size: 0);
- Operand e = EmitShlRegOp(context, ne, context.ConvertI64ToI32(me), op.Size, signed);
+ Operand e = !saturating
+ ? EmitShlReg(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed)
+ : EmitShlRegSatQ(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed);
res = EmitVectorInsert(context, res, e, index, op.Size);
}
context.Copy(GetVec(op.Rd), res);
}
+
+ // long SignedShlReg(long op, int shiftLsB, bool round, int size);
+ // ulong UnsignedShlReg(ulong op, int shiftLsB, bool round, int size);
+ private static Operand EmitShlReg(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
+ {
+ int eSize = 8 << size;
+
+ Debug.Assert(op.Type == OperandType.I64);
+ Debug.Assert(shiftLsB.Type == OperandType.I32);
+ Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
+
+ Operand lbl1 = Label();
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zero = Const(0);
+ Operand zeroL = Const(0L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, signed
+ ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
+ : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
+ Operand shl = context.ShiftLeft(op, shiftLsB);
+ Operand isGreaterOrEqual = context.ICompareGreaterOrEqual(shiftLsB, eSizeOp);
+ context.Copy(res, context.ConditionalSelect(isGreaterOrEqual, zeroL, shl));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // long SignedShlRegSatQ(long op, int shiftLsB, bool round, int size);
+ // ulong UnsignedShlRegSatQ(ulong op, int shiftLsB, bool round, int size);
+ private static Operand EmitShlRegSatQ(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed)
+ {
+ int eSize = 8 << size;
+
+ Debug.Assert(op.Type == OperandType.I64);
+ Debug.Assert(shiftLsB.Type == OperandType.I32);
+ Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
+
+ Operand lbl1 = Label();
+ Operand lbl2 = Label();
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zero = Const(0);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
+
+ context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual);
+ context.Copy(res, signed
+ ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)
+ : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual);
+ context.BranchIf(lbl2, shiftLsB, eSizeOp, Comparison.Less);
+ context.Copy(res, signed
+ ? EmitSignedSignSatQ(context, op, size)
+ : EmitUnsignedSignSatQ(context, op, size));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl2);
+ Operand shl = context.ShiftLeft(op, shiftLsB);
+ if (eSize == 64)
+ {
+ Operand sarOrShr = signed
+ ? context.ShiftRightSI(shl, shiftLsB)
+ : context.ShiftRightUI(shl, shiftLsB);
+ context.Copy(res, shl);
+ context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
+ context.Copy(res, signed
+ ? EmitSignedSignSatQ(context, op, size)
+ : EmitUnsignedSignSatQ(context, op, size));
+ }
+ else
+ {
+ context.Copy(res, signed
+ ? EmitSignedSrcSatQ(context, shl, size, signedDst: true)
+ : EmitUnsignedSrcSatQ(context, shl, size, signedDst: false));
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
+ // shift := [1, 128]; eSize := {8, 16, 32, 64}.
+ // long SignedShrReg(long op, int shift, bool round, int eSize);
+ private static Operand EmitSignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
+ {
+ if (round)
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroL = Const(0L);
+ Operand one = Const(1);
+ Operand oneL = Const(1L);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.GreaterOrEqual);
+ Operand roundConst = context.ShiftLeft(oneL, context.Subtract(shift, one));
+ Operand add = context.Add(op, roundConst);
+ Operand sar = context.ShiftRightSI(add, shift);
+ if (eSize == 64)
+ {
+ Operand shr = context.ShiftRightUI(add, shift);
+ Operand left = context.BitwiseAnd(context.Negate(op), context.BitwiseExclusiveOr(op, add));
+ Operand isLess = context.ICompareLess(left, zeroL);
+ context.Copy(res, context.ConditionalSelect(isLess, shr, sar));
+ }
+ else
+ {
+ context.Copy(res, sar);
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ else
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroL = Const(0L);
+ Operand negOneL = Const(-1L);
+
+ Operand sar = context.ShiftRightSI(op, shift);
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sar);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
+ Operand isLess = context.ICompareLess(op, zeroL);
+ context.Copy(res, context.ConditionalSelect(isLess, negOneL, zeroL));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ }
+
+ // shift := [1, 128]; eSize := {8, 16, 32, 64}.
+ // ulong UnsignedShrReg(ulong op, int shift, bool round, int eSize);
+ private static Operand EmitUnsignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize)
+ {
+ if (round)
+ {
+ Operand lblEnd = Label();
+
+ Operand zeroUL = Const(0UL);
+ Operand one = Const(1);
+ Operand oneUL = Const(1UL);
+ Operand eSizeMaxOp = Const(64);
+ Operand oneShl63UL = Const(1UL << 63);
+
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL);
+
+ context.BranchIf(lblEnd, shift, eSizeMaxOp, Comparison.Greater);
+ Operand roundConst = context.ShiftLeft(oneUL, context.Subtract(shift, one));
+ Operand add = context.Add(op, roundConst);
+ Operand shr = context.ShiftRightUI(add, shift);
+ Operand isEqual = context.ICompareEqual(shift, eSizeMaxOp);
+ context.Copy(res, context.ConditionalSelect(isEqual, zeroUL, shr));
+ if (eSize == 64)
+ {
+ context.BranchIf(lblEnd, add, op, Comparison.GreaterOrEqualUI);
+ Operand right = context.BitwiseOr(shr, context.ShiftRightUI(oneShl63UL, context.Subtract(shift, one)));
+ context.Copy(res, context.ConditionalSelect(isEqual, oneUL, right));
+ }
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ else
+ {
+ Operand lblEnd = Label();
+
+ Operand eSizeOp = Const(eSize);
+ Operand zeroUL = Const(0UL);
+
+ Operand shr = context.ShiftRightUI(op, shift);
+ Operand res = context.Copy(context.AllocateLocal(OperandType.I64), shr);
+
+ context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less);
+ context.Copy(res, zeroUL);
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+ }
}
}
diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs
index 829dd37a..d5e1ab65 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.).
{