diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
index 9a632fd63..a35e28a15 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
@@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
});
}
}
@@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
});
}
}
@@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
});
}
}
@@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
});
}
}
@@ -1633,37 +1633,17 @@ namespace ARMeilleure.Instructions
public static void Frinti_S(ArmEmitterContext context)
{
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
-
EmitScalarUnaryOpF(context, (op1) =>
{
- if (op.Size == 0)
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
- }
- else /* if (op.Size == 1) */
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
- }
+ return EmitRoundByRMode(context, op1);
});
}
public static void Frinti_V(ArmEmitterContext context)
{
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
-
- int sizeF = op.Size & 1;
-
EmitVectorUnaryOpF(context, (op1) =>
{
- if (sizeF == 0)
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
- }
- else /* if (sizeF == 1) */
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
- }
+ return EmitRoundByRMode(context, op1);
});
}
@@ -1759,37 +1739,17 @@ namespace ARMeilleure.Instructions
public static void Frintx_S(ArmEmitterContext context)
{
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
-
EmitScalarUnaryOpF(context, (op1) =>
{
- if (op.Size == 0)
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
- }
- else /* if (op.Size == 1) */
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
- }
+ return EmitRoundByRMode(context, op1);
});
}
public static void Frintx_V(ArmEmitterContext context)
{
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
-
- int sizeF = op.Size & 1;
-
EmitVectorUnaryOpF(context, (op1) =>
{
- if (sizeF == 0)
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
- }
- else /* if (sizeF == 1) */
- {
- return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
- }
+ return EmitRoundByRMode(context, op1);
});
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
index 1acc74657..339d32939 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
-using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions
private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
{
- Operand one = Const(1);
if (zero)
{
EmitVectorUnaryOpF32(context, (m) =>
{
- OperandType type = m.Type;
+ Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f);
- if (type == OperandType.FP64)
- {
- return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one);
- }
- else
- {
- return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one);
- }
+ return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp);
});
}
else
{
EmitVectorBinaryOpF32(context, (n, m) =>
{
- OperandType type = n.Type;
-
- if (type == OperandType.FP64)
- {
- return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one);
- }
- else
- {
- return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one);
- }
+ return EmitSoftFloatCallDefaultFpscr(context, name, n, m);
});
}
}
@@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions
me = ExtractScalar(context, type, op.Vm);
}
- MethodInfo info = sizeF != 0
- ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
- : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));
-
- Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));
+ Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
EmitSetFpscrNzcv(context, nzcv);
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
index 6994643ed..c8c427b79 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
@@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
+ context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
+ context.LoadFromContext();
res = context.ZeroExtend16(OperandType.I64, res);
@@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
+ context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
+ context.LoadFromContext();
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
}
@@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
+ context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
+ context.LoadFromContext();
res = context.ZeroExtend16(OperandType.I64, res);
@@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
+ context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
+ context.LoadFromContext();
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
}
@@ -224,7 +232,9 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
+ context.StoreToContext();
Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
+ context.LoadFromContext();
res = context.VectorInsert(res, e, index);
}
@@ -333,7 +343,9 @@ namespace ARMeilleure.Instructions
if (sizeF == 0)
{
+ context.StoreToContext();
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
+ context.LoadFromContext();
e = context.ZeroExtend16(OperandType.I64, e);
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
index b06ddd5e7..69ba42747 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
@@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions
{
Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
- Operand asInteger;
-
// TODO: Fast Path.
if (roundWithFpscr)
{
- MethodInfo info;
-
- if (floatSize == OperandType.FP64)
- {
- info = unsigned
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
- }
- else
- {
- info = unsigned
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
- }
-
- asInteger = context.Call(info, toConvert);
- }
- else
- {
- // Round towards zero.
- asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
+ toConvert = EmitRoundByRMode(context, toConvert);
}
+ // Round towards zero.
+ Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
+
InsertScalar(context, op.Vd, asInteger);
}
}
@@ -271,9 +252,7 @@ namespace ARMeilleure.Instructions
break;
}
- Operand asInteger;
-
- asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
+ Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
InsertScalar(context, op.Vd, asInteger);
}
@@ -399,15 +378,9 @@ namespace ARMeilleure.Instructions
// VRINTX (floating-point).
public static void Vrintx_S(ArmEmitterContext context)
{
- OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
-
- bool doubleSize = (op.Size & 1) == 1;
- string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF);
-
EmitScalarUnaryOpF32(context, (op1) =>
{
- MethodInfo info = typeof(SoftFallback).GetMethod(methodName);
- return context.Call(info, op1);
+ return EmitRoundByRMode(context, op1);
});
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
index 27b5c1302..49c9e6879 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
@@ -361,6 +361,54 @@ namespace ARMeilleure.Instructions
return context.Call(info, n, Const((int)roundMode));
}
+ public static Operand EmitGetRoundingMode(ArmEmitterContext context)
+ {
+ Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1));
+ rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag));
+
+ return rMode;
+ }
+
+ public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
+ {
+ Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64);
+
+ Operand lbl1 = Label();
+ Operand lbl2 = Label();
+ Operand lbl3 = Label();
+ Operand lblEnd = Label();
+
+ Operand rN = Const((int)FPRoundingMode.ToNearest);
+ Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity);
+ Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity);
+
+ Operand res = context.AllocateLocal(op.Type);
+
+ Operand rMode = EmitGetRoundingMode(context);
+
+ context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual);
+ context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
+ context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl2);
+ context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
+ context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl3);
+ context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lblEnd);
+
+ return res;
+ }
+
public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
@@ -369,7 +417,11 @@ namespace ARMeilleure.Instructions
? typeof(SoftFloat32).GetMethod(name)
: typeof(SoftFloat64).GetMethod(name);
- return context.Call(info, callArgs);
+ context.StoreToContext();
+ Operand res = context.Call(info, callArgs);
+ context.LoadFromContext();
+
+ return res;
}
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
@@ -1269,7 +1321,7 @@ namespace ARMeilleure.Instructions
public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue)
{
- isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
+ isTrue = GetFpFlag(FPState.FzFlag);
Operand lblTrue = Label();
context.BranchIfFalse(lblTrue, isTrue);
@@ -1281,9 +1333,7 @@ namespace ARMeilleure.Instructions
public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
{
- isTrue = isTrue == default
- ? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)))
- : isTrue;
+ isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue;
Operand lblTrue = Label();
context.BranchIfFalse(lblTrue, isTrue);
@@ -1533,31 +1583,90 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
+ 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);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
+ 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);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
+ context.Branch(lblEnd);
+
+ context.MarkLabel(lbl1);
+ context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
+ context.Copy(res, minT);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1569,19 +1678,20 @@ 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.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
+ context.Copy(res, maxT);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1601,9 +1711,9 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1620,17 +1730,18 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1647,11 +1758,12 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1668,17 +1780,18 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1693,13 +1806,14 @@ 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.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.Copy(res, zeroL);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1717,27 +1831,28 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
@@ -1755,21 +1870,22 @@ 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)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
- context.BranchIf(lblEnd, res, zero, Comparison.GreaterOrEqual);
- context.Copy(res, zero);
- context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
+ context.Copy(res, zeroL);
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
index c530985fa..0620ea332 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
@@ -1181,7 +1181,11 @@ namespace ARMeilleure.Instructions
Array.Resize(ref callArgs, callArgs.Length + 1);
callArgs[callArgs.Length - 1] = Const(1);
- return context.Call(info, callArgs);
+ context.StoreToContext();
+ Operand res = context.Call(info, callArgs);
+ context.LoadFromContext();
+
+ return res;
}
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
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/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
index e0968b7b1..9ac680884 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
@@ -1,5 +1,6 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
+using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
@@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions
context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
- context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
+ SetFpFlag(context, FPState.QcFlag, Const(1));
context.MarkLabel(lblNoSat);
diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs
index cdfaa26ec..cc32228c3 100644
--- a/ARMeilleure/Instructions/InstEmitSystem.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem.cs
@@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
- case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
- case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
+ case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
+ case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
@@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions
switch (GetPackedId(op))
{
- case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
- case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break;
- case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break;
+ case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
+ case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
+ case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
@@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
- Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
- Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
- Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
- Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
+ Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
+ nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
+ nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
+ nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
- Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
+ SetIntOrZR(context, op.Rt, nzcv);
+ }
- SetIntOrZR(context, op.Rt, nzcvSh);
+ private static void EmitGetFpcr(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
+
+ Operand fpcr = Const(0);
+
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
+ {
+ fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
+ }
+ }
+
+ SetIntOrZR(context, op.Rt, fpcr);
+ }
+
+ private static void EmitGetFpsr(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
+
+ Operand fpsr = Const(0);
+
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
+ {
+ fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
+ }
+ }
+
+ SetIntOrZR(context, op.Rt, fpsr);
}
private static void EmitSetNzcv(ArmEmitterContext context)
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
- Operand t = GetIntOrZR(context, op.Rt);
- t = context.ConvertI64ToI32(t);
+ Operand nzcv = GetIntOrZR(context, op.Rt);
+ nzcv = context.ConvertI64ToI32(nzcv);
- Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
- v = context.BitwiseAnd (v, Const(1));
+ SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
+ SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
+ SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
+ SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
+ }
- Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
- c = context.BitwiseAnd (c, Const(1));
+ private static void EmitSetFpcr(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
- Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
- z = context.BitwiseAnd (z, Const(1));
+ Operand fpcr = GetIntOrZR(context, op.Rt);
+ fpcr = context.ConvertI64ToI32(fpcr);
- Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
- n = context.BitwiseAnd (n, Const(1));
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
+ {
+ SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
+ }
+ }
+ }
- SetFlag(context, PState.VFlag, v);
- SetFlag(context, PState.CFlag, c);
- SetFlag(context, PState.ZFlag, z);
- SetFlag(context, PState.NFlag, n);
+ private static void EmitSetFpsr(ArmEmitterContext context)
+ {
+ OpCodeSystem op = (OpCodeSystem)context.CurrOp;
+
+ Operand fpsr = GetIntOrZR(context, op.Rt);
+ fpsr = context.ConvertI64ToI32(fpsr);
+
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
+ {
+ SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
+ }
+ }
}
}
}
diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs
index acd17045f..e07db4121 100644
--- a/ARMeilleure/Instructions/InstEmitSystem32.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem32.cs
@@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions
}
else
{
- Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
- Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
- Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
- Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
- Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag));
-
- Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
- spsr = context.BitwiseOr(spsr, qSh);
+ Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
+ spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
+ spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
+ spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
+ spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)));
// TODO: Remaining flags.
@@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions
EmitSetNzcv(context, value);
- Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag));
- q = context.BitwiseAnd(q, Const(1));
+ Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1));
SetFlag(context, PState.QFlag, q);
}
@@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
{
- Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
- v = context.BitwiseAnd(v, Const(1));
-
- Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
- c = context.BitwiseAnd(c, Const(1));
-
- Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
- z = context.BitwiseAnd(z, Const(1));
-
- Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
- n = context.BitwiseAnd(n, Const(1));
+ Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1));
+ Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1));
+ Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1));
+ Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1));
SetFlag(context, PState.VFlag, v);
SetFlag(context, PState.CFlag, c);
@@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
- Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag));
- Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag));
- Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag));
- Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag));
+ Operand fpscr = Const(0);
- Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
+ {
+ fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
+ }
+ }
- Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr)));
-
- SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr));
+ SetIntA32(context, op.Rt, fpscr);
}
private static void EmitSetFpscr(ArmEmitterContext context)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
- Operand t = GetIntA32(context, op.Rt);
+ Operand fpscr = GetIntA32(context, op.Rt);
- Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag));
- v = context.BitwiseAnd(v, Const(1));
-
- Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag));
- c = context.BitwiseAnd(c, Const(1));
-
- Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag));
- z = context.BitwiseAnd(z, Const(1));
-
- Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag));
- n = context.BitwiseAnd(n, Const(1));
-
- SetFpFlag(context, FPState.VFlag, v);
- SetFpFlag(context, FPState.CFlag, c);
- SetFpFlag(context, FPState.ZFlag, z);
- SetFpFlag(context, FPState.NFlag, n);
-
- context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t);
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
+ {
+ SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1)));
+ }
+ }
}
}
}
diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs
index ca4133ada..2ac748a9a 100644
--- a/ARMeilleure/Instructions/NativeInterface.cs
+++ b/ARMeilleure/Instructions/NativeInterface.cs
@@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions
return (ulong)GetContext().DczidEl0;
}
- public static ulong GetFpcr()
- {
- return (ulong)GetContext().Fpcr;
- }
-
- public static bool GetFpcrFz()
- {
- return (GetContext().Fpcr & FPCR.Fz) != 0;
- }
-
- public static ulong GetFpsr()
- {
- return (ulong)GetContext().Fpsr;
- }
-
- public static uint GetFpscr()
- {
- ExecutionContext context = GetContext();
-
- return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) |
- (uint)(context.Fpcr & FPCR.A32Mask);
- }
-
public static ulong GetTpidrEl0()
{
return (ulong)GetContext().TpidrEl0;
@@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions
return GetContext().CntvctEl0;
}
- public static void SetFpcr(ulong value)
- {
- GetContext().Fpcr = (FPCR)value;
- }
-
- public static void SetFpsr(ulong value)
- {
- GetContext().Fpsr = (FPSR)value;
- }
-
- public static void SetFpsrQc()
- {
- GetContext().Fpsr |= FPSR.Qc;
- }
-
- public static void SetFpscr(uint fpscr)
- {
- ExecutionContext context = GetContext();
-
- context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
- context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
- }
-
public static void SetTpidrEl0(ulong value)
{
GetContext().TpidrEl0 = (long)value;
diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs
index 829dd37a3..06d76a67c 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)
{
@@ -372,76 +91,6 @@ namespace ARMeilleure.Instructions
}
#endregion
-#region "Rounding"
- public static double Round(double value)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
-
- if (roundMode == FPRoundingMode.ToNearest)
- {
- return Math.Round(value); // even
- }
- else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
- {
- return Math.Ceiling(value);
- }
- else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
- {
- return Math.Floor(value);
- }
- else /* if (roundMode == FPRoundingMode.TowardsZero) */
- {
- return Math.Truncate(value);
- }
- }
-
- public static float RoundF(float value)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
-
- if (roundMode == FPRoundingMode.ToNearest)
- {
- return MathF.Round(value); // even
- }
- else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
- {
- return MathF.Ceiling(value);
- }
- else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
- {
- return MathF.Floor(value);
- }
- else /* if (roundMode == FPRoundingMode.TowardsZero) */
- {
- return MathF.Truncate(value);
- }
- }
-
- public static int FloatToInt32(float value)
- {
- return SatF32ToS32(RoundF(value));
- }
-
- public static int DoubleToInt32(double value)
- {
- return SatF64ToS32(Round(value));
- }
-
- public static uint FloatToUInt32(float value)
- {
- return SatF32ToU32(RoundF(value));
- }
-
- public static uint DoubleToUInt32(double value)
- {
- return SatF64ToU32(Round(value));
- }
-#endregion
-
#region "Saturation"
public static int SatF32ToS32(float value)
{
@@ -508,55 +157,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/Instructions/SoftFloat.cs b/ARMeilleure/Instructions/SoftFloat.cs
index a138f5df2..9e3db68d9 100644
--- a/ARMeilleure/Instructions/SoftFloat.cs
+++ b/ARMeilleure/Instructions/SoftFloat.cs
@@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
}
- internal static readonly byte[] RecipEstimateTable;
- internal static readonly byte[] RecipSqrtEstimateTable;
+ public static readonly byte[] RecipEstimateTable;
+ public static readonly byte[] RecipSqrtEstimateTable;
private static byte[] BuildRecipEstimateTable()
{
@@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions
context.Fpsr |= (FPSR)(1 << (int)exc);
}
}
+
+ public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
+ {
+ const int RModeShift = 22;
+
+ return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
+ }
}
static class SoftFloat16
diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs
index c73ca197d..5d18e6ed8 100644
--- a/ARMeilleure/State/ExecutionContext.cs
+++ b/ARMeilleure/State/ExecutionContext.cs
@@ -36,10 +36,25 @@ namespace ARMeilleure.State
set => _nativeContext.SetPstate(value);
}
- public FPCR Fpcr { get; set; }
- public FPSR Fpsr { get; set; }
+ public FPSR Fpsr
+ {
+ get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask);
+ set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask);
+ }
+
+ public FPCR Fpcr
+ {
+ get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask);
+ set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask);
+ }
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
+ public FPSCR Fpscr
+ {
+ get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask);
+ set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask);
+ }
+
public bool IsAarch32 { get; set; }
internal ExecutionMode ExecutionMode
diff --git a/ARMeilleure/State/FPCR.cs b/ARMeilleure/State/FPCR.cs
index 40d560455..6f707de7d 100644
--- a/ARMeilleure/State/FPCR.cs
+++ b/ARMeilleure/State/FPCR.cs
@@ -5,21 +5,18 @@ namespace ARMeilleure.State
[Flags]
public enum FPCR : uint
{
+ Ioe = 1u << 8,
+ Dze = 1u << 9,
+ Ofe = 1u << 10,
Ufe = 1u << 11,
+ Ixe = 1u << 12,
+ Ide = 1u << 15,
+ RMode0 = 1u << 22,
+ RMode1 = 1u << 23,
Fz = 1u << 24,
Dn = 1u << 25,
Ahp = 1u << 26,
- A32Mask = 0x07FF9F00u
- }
-
- public static class FPCRExtensions
- {
- private const int RModeShift = 22;
-
- public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
- {
- return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3);
- }
+ Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u
}
}
diff --git a/ARMeilleure/State/FPSCR.cs b/ARMeilleure/State/FPSCR.cs
new file mode 100644
index 000000000..d6d2fc26a
--- /dev/null
+++ b/ARMeilleure/State/FPSCR.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace ARMeilleure.State
+{
+ [Flags]
+ public enum FPSCR : uint
+ {
+ V = 1u << 28,
+ C = 1u << 29,
+ Z = 1u << 30,
+ N = 1u << 31,
+
+ Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu
+ }
+}
diff --git a/ARMeilleure/State/FPSR.cs b/ARMeilleure/State/FPSR.cs
index 800dcd10c..5e66d5ce1 100644
--- a/ARMeilleure/State/FPSR.cs
+++ b/ARMeilleure/State/FPSR.cs
@@ -5,11 +5,14 @@ namespace ARMeilleure.State
[Flags]
public enum FPSR : uint
{
+ Ioc = 1u << 0,
+ Dzc = 1u << 1,
+ Ofc = 1u << 2,
Ufc = 1u << 3,
- Qc = 1u << 27,
+ Ixc = 1u << 4,
+ Idc = 1u << 7,
+ Qc = 1u << 27,
- Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28),
-
- A32Mask = 0xF800009Fu
+ Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu
}
}
diff --git a/ARMeilleure/State/FPState.cs b/ARMeilleure/State/FPState.cs
index 60c7126c3..fa6ab9d46 100644
--- a/ARMeilleure/State/FPState.cs
+++ b/ARMeilleure/State/FPState.cs
@@ -2,9 +2,30 @@
{
public enum FPState
{
+ // FPSR Flags.
+ IocFlag = 0,
+ DzcFlag = 1,
+ OfcFlag = 2,
+ UfcFlag = 3,
+ IxcFlag = 4,
+ IdcFlag = 7,
+ QcFlag = 27,
VFlag = 28,
CFlag = 29,
ZFlag = 30,
- NFlag = 31
+ NFlag = 31,
+
+ // FPCR Flags.
+ IoeFlag = 8,
+ DzeFlag = 9,
+ OfeFlag = 10,
+ UfeFlag = 11,
+ IxeFlag = 12,
+ IdeFlag = 15,
+ RMode0Flag = 22,
+ RMode1Flag = 23,
+ FzFlag = 24,
+ DnFlag = 25,
+ AhpFlag = 26
}
}
diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs
index 11ab5ca3a..89e875d12 100644
--- a/ARMeilleure/State/NativeContext.cs
+++ b/ARMeilleure/State/NativeContext.cs
@@ -140,6 +140,34 @@ namespace ARMeilleure.State
GetStorage().FpFlags[(int)flag] = value ? 1u : 0u;
}
+ public unsafe uint GetFPState(uint mask = uint.MaxValue)
+ {
+ uint value = 0;
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ uint bit = 1u << flag;
+
+ if ((mask & bit) == bit)
+ {
+ value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u;
+ }
+ }
+ return value;
+ }
+
+ public unsafe void SetFPState(uint value, uint mask = uint.MaxValue)
+ {
+ for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
+ {
+ uint bit = 1u << flag;
+
+ if ((mask & bit) == bit)
+ {
+ GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u;
+ }
+ }
+ }
+
public int GetCounter() => GetStorage().Counter;
public void SetCounter(int value) => GetStorage().Counter = value;
diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs
index b36472b83..fef1f4ef7 100644
--- a/ARMeilleure/Translation/Delegates.cs
+++ b/ARMeilleure/Translation/Delegates.cs
@@ -109,10 +109,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
@@ -124,10 +120,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
@@ -151,12 +143,8 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
@@ -165,8 +153,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
@@ -179,8 +165,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 +174,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..f4ae411b7 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 = 3703; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
diff --git a/README.md b/README.md
index 83f56f66a..9a8581e06 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
-
+