aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitSimdShift32.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-09-09 21:47:38 -0300
committerGitHub <noreply@github.com>2022-09-09 21:47:38 -0300
commitdb45688aa8d0e63d3ffbe50351722ef32f8360f8 (patch)
tree3228986398039c37546510ddeecea1600a48b933 /ARMeilleure/Instructions/InstEmitSimdShift32.cs
parentc6d82209abeacd2336cde99e5a02b4596e70da83 (diff)
Implement VRSRA, VRSHRN, VQSHRUN, VQMOVN, VQMOVUN, VQADD, VQSUB, VRHADD, VPADDL, VSUBL, VQDMULH and VMLAL Arm32 NEON instructions (#3677)
* Implement VRSRA, VRSHRN, VQSHRUN, VQMOVN, VQMOVUN, VQADD, VQSUB, VRHADD, VPADDL, VSUBL, VQDMULH and VMLAL Arm32 NEON instructions * PPTC version * Fix VQADD/VQSUB * Improve MRC/MCR handling and exception messages In case data is being recompiled as code, we don't want to throw at emit stage, instead we should only throw if it actually tries to execute
Diffstat (limited to 'ARMeilleure/Instructions/InstEmitSimdShift32.cs')
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdShift32.cs168
1 files changed, 108 insertions, 60 deletions
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
index 6dcfe065..e0968b7b 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
@@ -33,64 +33,24 @@ namespace ARMeilleure.Instructions
EmitShrImmSaturatingNarrowOp(context, op.U ? ShrImmSaturatingNarrowFlags.VectorZxZx : ShrImmSaturatingNarrowFlags.VectorSxSx);
}
- public static void Vrshr(ArmEmitterContext context)
+ public static void Vqshrun(ArmEmitterContext context)
{
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- int shift = GetImmShr(op);
- long roundConst = 1L << (shift - 1);
-
- if (op.U)
- {
- if (op.Size < 2)
- {
- EmitVectorUnaryOpZx32(context, (op1) =>
- {
- op1 = context.Add(op1, Const(op1.Type, roundConst));
-
- return context.ShiftRightUI(op1, Const(shift));
- });
- }
- else if (op.Size == 2)
- {
- EmitVectorUnaryOpZx32(context, (op1) =>
- {
- op1 = context.ZeroExtend32(OperandType.I64, op1);
- op1 = context.Add(op1, Const(op1.Type, roundConst));
+ EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
+ }
- return context.ConvertI64ToI32(context.ShiftRightUI(op1, Const(shift)));
- });
- }
- else /* if (op.Size == 3) */
- {
- EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: false, roundConst, shift));
- }
- }
- else
- {
- if (op.Size < 2)
- {
- EmitVectorUnaryOpSx32(context, (op1) =>
- {
- op1 = context.Add(op1, Const(op1.Type, roundConst));
+ public static void Vrshr(ArmEmitterContext context)
+ {
+ EmitRoundShrImmOp(context, accumulate: false);
+ }
- return context.ShiftRightSI(op1, Const(shift));
- });
- }
- else if (op.Size == 2)
- {
- EmitVectorUnaryOpSx32(context, (op1) =>
- {
- op1 = context.SignExtend32(OperandType.I64, op1);
- op1 = context.Add(op1, Const(op1.Type, roundConst));
+ public static void Vrshrn(ArmEmitterContext context)
+ {
+ EmitRoundShrImmNarrowOp(context, signed: false);
+ }
- return context.ConvertI64ToI32(context.ShiftRightSI(op1, Const(shift)));
- });
- }
- else /* if (op.Size == 3) */
- {
- EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: true, roundConst, shift));
- }
- }
+ public static void Vrsra(ArmEmitterContext context)
+ {
+ EmitRoundShrImmOp(context, accumulate: true);
}
public static void Vshl(ArmEmitterContext context)
@@ -191,6 +151,89 @@ namespace ARMeilleure.Instructions
}
}
+ public static void EmitRoundShrImmOp(ArmEmitterContext context, bool accumulate)
+ {
+ OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
+ int shift = GetImmShr(op);
+ long roundConst = 1L << (shift - 1);
+
+ if (op.U)
+ {
+ if (op.Size < 2)
+ {
+ EmitVectorUnaryOpZx32(context, (op1) =>
+ {
+ op1 = context.Add(op1, Const(op1.Type, roundConst));
+
+ return context.ShiftRightUI(op1, Const(shift));
+ }, accumulate);
+ }
+ else if (op.Size == 2)
+ {
+ EmitVectorUnaryOpZx32(context, (op1) =>
+ {
+ op1 = context.ZeroExtend32(OperandType.I64, op1);
+ op1 = context.Add(op1, Const(op1.Type, roundConst));
+
+ return context.ConvertI64ToI32(context.ShiftRightUI(op1, Const(shift)));
+ }, accumulate);
+ }
+ else /* if (op.Size == 3) */
+ {
+ EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: false, roundConst, shift), accumulate);
+ }
+ }
+ else
+ {
+ if (op.Size < 2)
+ {
+ EmitVectorUnaryOpSx32(context, (op1) =>
+ {
+ op1 = context.Add(op1, Const(op1.Type, roundConst));
+
+ return context.ShiftRightSI(op1, Const(shift));
+ }, accumulate);
+ }
+ else if (op.Size == 2)
+ {
+ EmitVectorUnaryOpSx32(context, (op1) =>
+ {
+ op1 = context.SignExtend32(OperandType.I64, op1);
+ op1 = context.Add(op1, Const(op1.Type, roundConst));
+
+ return context.ConvertI64ToI32(context.ShiftRightSI(op1, Const(shift)));
+ }, accumulate);
+ }
+ else /* if (op.Size == 3) */
+ {
+ EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: true, roundConst, shift), accumulate);
+ }
+ }
+ }
+
+ private static void EmitRoundShrImmNarrowOp(ArmEmitterContext context, bool signed)
+ {
+ OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
+
+ int shift = GetImmShr(op);
+ long roundConst = 1L << (shift - 1);
+
+ EmitVectorUnaryNarrowOp32(context, (op1) =>
+ {
+ if (op.Size <= 1)
+ {
+ op1 = context.Add(op1, Const(op1.Type, roundConst));
+ op1 = signed ? context.ShiftRightSI(op1, Const(shift)) : context.ShiftRightUI(op1, Const(shift));
+ }
+ else /* if (op.Size == 2 && round) */
+ {
+ op1 = EmitShrImm64(context, op1, signed, roundConst, shift); // shift <= 32
+ }
+
+ return op1;
+ }, signed);
+ }
+
private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool unsigned)
{
if (shiftLsB.Type == OperandType.I64)
@@ -289,7 +332,7 @@ namespace ARMeilleure.Instructions
op1 = EmitShrImm64(context, op1, signedSrc, roundConst, shift); // shift <= 32
}
- return EmitSatQ(context, op1, 8 << op.Size, signedDst);
+ return EmitSatQ(context, op1, 8 << op.Size, signedSrc, signedDst);
}, signedSrc);
}
@@ -313,15 +356,20 @@ namespace ARMeilleure.Instructions
return context.Call(info, value, Const(roundConst), Const(shift));
}
- private static Operand EmitSatQ(ArmEmitterContext context, Operand value, int eSize, bool signed)
+ private static Operand EmitSatQ(ArmEmitterContext context, Operand value, int eSize, bool signedSrc, bool signedDst)
{
Debug.Assert(eSize <= 32);
- long intMin = signed ? -(1L << (eSize - 1)) : 0;
- long intMax = signed ? (1L << (eSize - 1)) - 1 : (1L << eSize) - 1;
+ long intMin = signedDst ? -(1L << (eSize - 1)) : 0;
+ long intMax = signedDst ? (1L << (eSize - 1)) - 1 : (1L << eSize) - 1;
+
+ Operand gt = signedSrc
+ ? context.ICompareGreater(value, Const(value.Type, intMax))
+ : context.ICompareGreaterUI(value, Const(value.Type, intMax));
- Operand gt = context.ICompareGreater(value, Const(value.Type, intMax));
- Operand lt = context.ICompareLess(value, Const(value.Type, intMin));
+ Operand lt = signedSrc
+ ? context.ICompareLess(value, Const(value.Type, intMin))
+ : context.ICompareLessUI(value, Const(value.Type, intMin));
value = context.ConditionalSelect(gt, Const(value.Type, intMax), value);
value = context.ConditionalSelect(lt, Const(value.Type, intMin), value);