aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Instructions/InstEmitSimdShift32.cs
diff options
context:
space:
mode:
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);