| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- using ARMeilleure.Decoders;
- using ARMeilleure.IntermediateRepresentation;
- using ARMeilleure.State;
- using ARMeilleure.Translation;
- using System;
- using static ARMeilleure.Instructions.InstEmitHelper;
- using static ARMeilleure.Instructions.InstEmitSimdHelper;
- using static ARMeilleure.IntermediateRepresentation.OperandHelper;
- namespace ARMeilleure.Instructions
- {
- using Func2I = Func<Operand, Operand, Operand>;
- static partial class InstEmit
- {
- public static void Cmeq_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: true);
- }
- public static void Cmeq_V(ArmEmitterContext context)
- {
- if (Optimizations.UseSse41)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Operand m;
- if (op is OpCodeSimdReg binOp)
- {
- m = GetVec(binOp.Rm);
- }
- else
- {
- m = context.VectorZero();
- }
- Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
- Operand res = context.AddIntrinsic(cmpInst, n, m);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: false);
- }
- }
- public static void Cmge_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: true);
- }
- public static void Cmge_V(ArmEmitterContext context)
- {
- if (Optimizations.UseSse42)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Operand m;
- if (op is OpCodeSimdReg binOp)
- {
- m = GetVec(binOp.Rm);
- }
- else
- {
- m = context.VectorZero();
- }
- Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
- Operand res = context.AddIntrinsic(cmpInst, m, n);
- Operand mask = X86GetAllElements(context, -1L);
- res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: false);
- }
- }
- public static void Cmgt_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: true);
- }
- public static void Cmgt_V(ArmEmitterContext context)
- {
- if (Optimizations.UseSse42)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Operand m;
- if (op is OpCodeSimdReg binOp)
- {
- m = GetVec(binOp.Rm);
- }
- else
- {
- m = context.VectorZero();
- }
- Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
- Operand res = context.AddIntrinsic(cmpInst, n, m);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: false);
- }
- }
- public static void Cmhi_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: true);
- }
- public static void Cmhi_V(ArmEmitterContext context)
- {
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
- if (Optimizations.UseSse41 && op.Size < 3)
- {
- Operand n = GetVec(op.Rn);
- Operand m = GetVec(op.Rm);
- Intrinsic maxInst = X86PmaxuInstruction[op.Size];
- Operand res = context.AddIntrinsic(maxInst, m, n);
- Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
- res = context.AddIntrinsic(cmpInst, res, m);
- Operand mask = X86GetAllElements(context, -1L);
- res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: false);
- }
- }
- public static void Cmhs_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: true);
- }
- public static void Cmhs_V(ArmEmitterContext context)
- {
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
- if (Optimizations.UseSse41 && op.Size < 3)
- {
- Operand n = GetVec(op.Rn);
- Operand m = GetVec(op.Rm);
- Intrinsic maxInst = X86PmaxuInstruction[op.Size];
- Operand res = context.AddIntrinsic(maxInst, n, m);
- Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
- res = context.AddIntrinsic(cmpInst, res, n);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: false);
- }
- }
- public static void Cmle_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: true);
- }
- public static void Cmle_V(ArmEmitterContext context)
- {
- if (Optimizations.UseSse42)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
- Operand res = context.AddIntrinsic(cmpInst, n, context.VectorZero());
- Operand mask = X86GetAllElements(context, -1L);
- res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: false);
- }
- }
- public static void Cmlt_S(ArmEmitterContext context)
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: true);
- }
- public static void Cmlt_V(ArmEmitterContext context)
- {
- if (Optimizations.UseSse42)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
- Operand res = context.AddIntrinsic(cmpInst, context.VectorZero(), n);
- if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else
- {
- EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: false);
- }
- }
- public static void Cmtst_S(ArmEmitterContext context)
- {
- EmitCmtstOp(context, scalar: true);
- }
- public static void Cmtst_V(ArmEmitterContext context)
- {
- EmitCmtstOp(context, scalar: false);
- }
- public static void Fccmp_S(ArmEmitterContext context)
- {
- EmitFccmpOrFccmpe(context, signalNaNs: false);
- }
- public static void Fccmpe_S(ArmEmitterContext context)
- {
- EmitFccmpOrFccmpe(context, signalNaNs: true);
- }
- public static void Fcmeq_S(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: true);
- }
- }
- public static void Fcmeq_V(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: false);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: false);
- }
- }
- public static void Fcmge_S(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: true);
- }
- }
- public static void Fcmge_V(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: false);
- }
- }
- public static void Fcmgt_S(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: true);
- }
- }
- public static void Fcmgt_V(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: false);
- }
- }
- public static void Fcmle_S(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, isLeOrLt: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: true);
- }
- }
- public static void Fcmle_V(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, isLeOrLt: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: false);
- }
- }
- public static void Fcmlt_S(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true, isLeOrLt: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: true);
- }
- }
- public static void Fcmlt_V(ArmEmitterContext context)
- {
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false, isLeOrLt: true);
- }
- else
- {
- EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: false);
- }
- }
- public static void Fcmp_S(ArmEmitterContext context)
- {
- EmitFcmpOrFcmpe(context, signalNaNs: false);
- }
- public static void Fcmpe_S(ArmEmitterContext context)
- {
- EmitFcmpOrFcmpe(context, signalNaNs: true);
- }
- public static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs)
- {
- OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp;
- Operand lblTrue = Label();
- Operand lblEnd = Label();
- context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond));
- EmitSetNzcv(context, Const(op.Nzcv));
- context.Branch(lblEnd);
- context.MarkLabel(lblTrue);
- EmitFcmpOrFcmpe(context, signalNaNs);
- context.MarkLabel(lblEnd);
- }
- private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs)
- {
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
- const int cmpOrdered = 7;
- bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
- if (Optimizations.FastFP && Optimizations.UseSse2)
- {
- Operand n = GetVec(op.Rn);
- Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm);
- Operand lblNaN = Label();
- Operand lblEnd = Label();
- if (op.Size == 0)
- {
- Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const(cmpOrdered));
- Operand isOrdered = context.VectorExtract16(ordMask, 0);
- context.BranchIfFalse(lblNaN, isOrdered);
- Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m);
- Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m);
- Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m);
- SetFlag(context, PState.VFlag, Const(0));
- SetFlag(context, PState.CFlag, cf);
- SetFlag(context, PState.ZFlag, zf);
- SetFlag(context, PState.NFlag, nf);
- }
- else /* if (op.Size == 1) */
- {
- Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const(cmpOrdered));
- Operand isOrdered = context.VectorExtract16(ordMask, 0);
- context.BranchIfFalse(lblNaN, isOrdered);
- Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m);
- Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m);
- Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m);
- SetFlag(context, PState.VFlag, Const(0));
- SetFlag(context, PState.CFlag, cf);
- SetFlag(context, PState.ZFlag, zf);
- SetFlag(context, PState.NFlag, nf);
- }
- context.Branch(lblEnd);
- context.MarkLabel(lblNaN);
- SetFlag(context, PState.VFlag, Const(1));
- SetFlag(context, PState.CFlag, Const(1));
- SetFlag(context, PState.ZFlag, Const(0));
- SetFlag(context, PState.NFlag, Const(0));
- context.MarkLabel(lblEnd);
- }
- else
- {
- OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32;
- Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
- Operand me;
- if (cmpWithZero)
- {
- me = op.Size == 0 ? ConstF(0f) : ConstF(0d);
- }
- else
- {
- me = context.VectorExtract(type, GetVec(op.Rm), 0);
- }
- Delegate dlg = op.Size != 0
- ? (Delegate)new _S32_F64_F64_Bool(SoftFloat64.FPCompare)
- : (Delegate)new _S32_F32_F32_Bool(SoftFloat32.FPCompare);
- Operand nzcv = context.Call(dlg, ne, me, Const(signalNaNs));
- EmitSetNzcv(context, nzcv);
- }
- }
- private static void EmitSetNzcv(ArmEmitterContext context, Operand nzcv)
- {
- Operand Extract(Operand value, int bit)
- {
- if (bit != 0)
- {
- value = context.ShiftRightUI(value, Const(bit));
- }
- value = context.BitwiseAnd(value, Const(1));
- return value;
- }
- SetFlag(context, PState.VFlag, Extract(nzcv, 0));
- SetFlag(context, PState.CFlag, Extract(nzcv, 1));
- SetFlag(context, PState.ZFlag, Extract(nzcv, 2));
- SetFlag(context, PState.NFlag, Extract(nzcv, 3));
- }
- private static void EmitCmpOp(ArmEmitterContext context, Func2I emitCmp, bool scalar)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand res = context.VectorZero();
- int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
- ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
- for (int index = 0; index < elems; index++)
- {
- Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
- Operand me;
- if (op is OpCodeSimdReg binOp)
- {
- me = EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
- }
- else
- {
- me = Const(0L);
- }
- Operand isTrue = emitCmp(ne, me);
- Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
- res = EmitVectorInsert(context, res, mask, index, op.Size);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- private static void EmitCmtstOp(ArmEmitterContext context, bool scalar)
- {
- OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
- Operand res = context.VectorZero();
- int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
- ulong szMask = ulong.MaxValue >> (64 - (8 << 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 test = context.BitwiseAnd(ne, me);
- Operand isTrue = context.ICompareNotEqual(test, Const(0L));
- Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
- res = EmitVectorInsert(context, res, mask, index, op.Size);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- private static void EmitCmpOpF(
- ArmEmitterContext context,
- _F32_F32_F32 f32,
- _F64_F64_F64 f64,
- bool scalar)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand res = context.VectorZero();
- int sizeF = op.Size & 1;
- OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
- int elems = !scalar ? op.GetBytesCount() >> sizeF + 2 : 1;
- for (int index = 0; index < elems; index++)
- {
- Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
- Operand me;
- if (op is OpCodeSimdReg binOp)
- {
- me = context.VectorExtract(type, GetVec(binOp.Rm), index);
- }
- else
- {
- me = sizeF == 0 ? ConstF(0f) : ConstF(0d);
- }
- Operand e = EmitSoftFloatCall(context, f32, f64, ne, me);
- res = context.VectorInsert(res, e, index);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- private enum CmpCondition
- {
- Equal = 0,
- GreaterThanOrEqual = 5,
- GreaterThan = 6
- }
- private static void EmitCmpSseOrSse2OpF(
- ArmEmitterContext context,
- CmpCondition cond,
- bool scalar,
- bool isLeOrLt = false)
- {
- OpCodeSimd op = (OpCodeSimd)context.CurrOp;
- Operand n = GetVec(op.Rn);
- Operand m = op is OpCodeSimdReg binOp ? GetVec(binOp.Rm) : context.VectorZero();
- int sizeF = op.Size & 1;
- if (sizeF == 0)
- {
- Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps;
- Operand res = isLeOrLt
- ? context.AddIntrinsic(inst, m, n, Const((int)cond))
- : context.AddIntrinsic(inst, n, m, Const((int)cond));
- if (scalar)
- {
- res = context.VectorZeroUpper96(res);
- }
- else if (op.RegisterSize == RegisterSize.Simd64)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- else /* if (sizeF == 1) */
- {
- Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd;
- Operand res = isLeOrLt
- ? context.AddIntrinsic(inst, m, n, Const((int)cond))
- : context.AddIntrinsic(inst, n, m, Const((int)cond));
- if (scalar)
- {
- res = context.VectorZeroUpper64(res);
- }
- context.Copy(GetVec(op.Rd), res);
- }
- }
- }
- }
|