| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- using ARMeilleure.Decoders;
- using ARMeilleure.IntermediateRepresentation;
- using ARMeilleure.Translation;
- using System;
- using System.Diagnostics;
- using System.Reflection;
- using static ARMeilleure.Instructions.InstEmitHelper;
- using static ARMeilleure.Instructions.InstEmitSimdHelper;
- using static ARMeilleure.Instructions.InstEmitSimdHelper32;
- using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
- namespace ARMeilleure.Instructions
- {
- static partial class InstEmit32
- {
- public static void Vqrshrn(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- EmitRoundShrImmSaturatingNarrowOp(context, op.U ? ShrImmSaturatingNarrowFlags.VectorZxZx : ShrImmSaturatingNarrowFlags.VectorSxSx);
- }
- public static void Vqrshrun(ArmEmitterContext context)
- {
- EmitRoundShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.VectorSxZx);
- }
- public static void Vqshrn(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- EmitShrImmSaturatingNarrowOp(context, op.U ? ShrImmSaturatingNarrowFlags.VectorZxZx : ShrImmSaturatingNarrowFlags.VectorSxSx);
- }
- public static void Vrshr(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));
- 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));
- 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));
- 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 Vshl(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- EmitVectorUnaryOpZx32(context, (op1) => context.ShiftLeft(op1, Const(op.Shift)));
- }
- public static void Vshl_I(ArmEmitterContext context)
- {
- OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
- if (op.U)
- {
- EmitVectorBinaryOpZx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, true));
- }
- else
- {
- EmitVectorBinaryOpSx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, false));
- }
- }
- public static void Vshll(ArmEmitterContext context)
- {
- OpCode32SimdShImmLong op = (OpCode32SimdShImmLong)context.CurrOp;
- Operand res = context.VectorZero();
- int elems = op.GetBytesCount() >> op.Size;
- for (int index = 0; index < elems; index++)
- {
- Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U);
- if (op.Size == 2)
- {
- if (op.U)
- {
- me = context.ZeroExtend32(OperandType.I64, me);
- }
- else
- {
- me = context.SignExtend32(OperandType.I64, me);
- }
- }
- me = context.ShiftLeft(me, Const(op.Shift));
- res = EmitVectorInsert(context, res, me, index, op.Size + 1);
- }
- context.Copy(GetVecA32(op.Qd), res);
- }
- public static void Vshr(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- int shift = GetImmShr(op);
- int maxShift = (8 << op.Size) - 1;
- if (op.U)
- {
- EmitVectorUnaryOpZx32(context, (op1) => (shift > maxShift) ? Const(op1.Type, 0) : context.ShiftRightUI(op1, Const(shift)));
- }
- else
- {
- EmitVectorUnaryOpSx32(context, (op1) => context.ShiftRightSI(op1, Const(Math.Min(maxShift, shift))));
- }
- }
- public static void Vshrn(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- int shift = GetImmShr(op);
- EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift)));
- }
- public static void Vsra(ArmEmitterContext context)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- int shift = GetImmShr(op);
- int maxShift = (8 << op.Size) - 1;
- if (op.U)
- {
- EmitVectorImmBinaryQdQmOpZx32(context, (op1, op2) =>
- {
- Operand shiftRes = shift > maxShift ? Const(op2.Type, 0) : context.ShiftRightUI(op2, Const(shift));
- return context.Add(op1, shiftRes);
- });
- }
- else
- {
- EmitVectorImmBinaryQdQmOpSx32(context, (op1, op2) => context.Add(op1, context.ShiftRightSI(op2, Const(Math.Min(maxShift, shift)))));
- }
- }
- private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool unsigned)
- {
- if (shiftLsB.Type == OperandType.I64)
- {
- shiftLsB = context.ConvertI64ToI32(shiftLsB);
- }
- shiftLsB = context.SignExtend8(OperandType.I32, shiftLsB);
- Debug.Assert((uint)size < 4u);
- Operand negShiftLsB = context.Negate(shiftLsB);
- Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
- Operand shl = context.ShiftLeft(op, shiftLsB);
- Operand shr = unsigned ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB);
- Operand res = context.ConditionalSelect(isPositive, shl, shr);
- if (unsigned)
- {
- Operand isOutOfRange = context.BitwiseOr(
- context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)),
- context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size)));
- return context.ConditionalSelect(isOutOfRange, Const(op.Type, 0), res);
- }
- else
- {
- Operand isOutOfRange0 = context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size));
- Operand isOutOfRangeN = context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size));
- // Also zero if shift is too negative, but value was positive.
- isOutOfRange0 = context.BitwiseOr(isOutOfRange0, context.BitwiseAnd(isOutOfRangeN, context.ICompareGreaterOrEqual(op, Const(op.Type, 0))));
- Operand min = (op.Type == OperandType.I64) ? Const(-1L) : Const(-1);
- return context.ConditionalSelect(isOutOfRange0, Const(op.Type, 0), context.ConditionalSelect(isOutOfRangeN, min, res));
- }
- }
- [Flags]
- private enum ShrImmSaturatingNarrowFlags
- {
- Scalar = 1 << 0,
- SignedSrc = 1 << 1,
- SignedDst = 1 << 2,
- Round = 1 << 3,
- ScalarSxSx = Scalar | SignedSrc | SignedDst,
- ScalarSxZx = Scalar | SignedSrc,
- ScalarZxZx = Scalar,
- VectorSxSx = SignedSrc | SignedDst,
- VectorSxZx = SignedSrc,
- VectorZxZx = 0
- }
- private static void EmitRoundShrImmSaturatingNarrowOp(ArmEmitterContext context, ShrImmSaturatingNarrowFlags flags)
- {
- EmitShrImmSaturatingNarrowOp(context, ShrImmSaturatingNarrowFlags.Round | flags);
- }
- private static void EmitShrImmSaturatingNarrowOp(ArmEmitterContext context, ShrImmSaturatingNarrowFlags flags)
- {
- OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
- bool scalar = (flags & ShrImmSaturatingNarrowFlags.Scalar) != 0;
- bool signedSrc = (flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0;
- bool signedDst = (flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0;
- bool round = (flags & ShrImmSaturatingNarrowFlags.Round) != 0;
- if (scalar)
- {
- // TODO: Support scalar operation.
- throw new NotImplementedException();
- }
- int shift = GetImmShr(op);
- long roundConst = 1L << (shift - 1);
- EmitVectorUnaryNarrowOp32(context, (op1) =>
- {
- if (op.Size <= 1 || !round)
- {
- if (round)
- {
- op1 = context.Add(op1, Const(op1.Type, roundConst));
- }
- op1 = signedSrc ? context.ShiftRightSI(op1, Const(shift)) : context.ShiftRightUI(op1, Const(shift));
- }
- else /* if (op.Size == 2 && round) */
- {
- op1 = EmitShrImm64(context, op1, signedSrc, roundConst, shift); // shift <= 32
- }
- return EmitSatQ(context, op1, 8 << op.Size, signedDst);
- }, signedSrc);
- }
- private static int GetImmShr(OpCode32SimdShImm op)
- {
- return (8 << op.Size) - op.Shift; // Shr amount is flipped.
- }
- // dst64 = (Int(src64, signed) + roundConst) >> shift;
- private static Operand EmitShrImm64(
- ArmEmitterContext context,
- Operand value,
- bool signed,
- long roundConst,
- int shift)
- {
- MethodInfo info = signed
- ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))
- : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64));
- return context.Call(info, value, Const(roundConst), Const(shift));
- }
- private static Operand EmitSatQ(ArmEmitterContext context, Operand value, int eSize, bool signed)
- {
- Debug.Assert(eSize <= 32);
- long intMin = signed ? -(1L << (eSize - 1)) : 0;
- long intMax = signed ? (1L << (eSize - 1)) - 1 : (1L << eSize) - 1;
- Operand gt = context.ICompareGreater(value, Const(value.Type, intMax));
- Operand lt = context.ICompareLess(value, Const(value.Type, intMin));
- value = context.ConditionalSelect(gt, Const(value.Type, intMax), value);
- value = context.ConditionalSelect(lt, Const(value.Type, intMin), value);
- Operand lblNoSat = Label();
- context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
- context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
- context.MarkLabel(lblNoSat);
- return value;
- }
- }
- }
|