From db45688aa8d0e63d3ffbe50351722ef32f8360f8 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 9 Sep 2022 21:47:38 -0300 Subject: 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 --- ARMeilleure/Instructions/InstEmitSimdShift32.cs | 168 +++++++++++++++--------- 1 file changed, 108 insertions(+), 60 deletions(-) (limited to 'ARMeilleure/Instructions/InstEmitSimdShift32.cs') 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); -- cgit v1.2.3