| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- using ChocolArm64.Decoder;
- using ChocolArm64.State;
- using ChocolArm64.Translation;
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- namespace ChocolArm64.Instruction
- {
- static partial class AInstEmit
- {
- public static void Addp_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvec(Op.Rn);
- Context.EmitLdc_I4(Op.Size);
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Addp_S));
- Context.EmitStvec(Op.Rd);
- }
- public static void Dup_S(AILEmitterCtx Context)
- {
- AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
- Context.EmitLdvec(Op.Rn);
- Context.EmitLdc_I4(Op.DstIndex);
- Context.EmitLdc_I4(Op.Size);
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Dup_S));
- Context.EmitStvec(Op.Rd);
- }
- public static void Fabs_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- MethodInfo MthdInfo;
- if (Op.Size == 0)
- {
- MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) });
- }
- else if (Op.Size == 1)
- {
- MthdInfo = typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) });
- }
- else
- {
- throw new InvalidOperationException();
- }
- Context.EmitCall(MthdInfo);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fadd_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Add);
- public static void Fccmp_S(AILEmitterCtx Context)
- {
- AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
- AILLabel LblTrue = new AILLabel();
- AILLabel LblEnd = new AILLabel();
- Context.EmitCondBranch(LblTrue, Op.Cond);
- //TODO: Share this logic with Ccmp.
- Context.EmitLdc_I4((Op.NZCV >> 0) & 1);
- Context.EmitStflg((int)APState.VBit);
- Context.EmitLdc_I4((Op.NZCV >> 1) & 1);
- Context.EmitStflg((int)APState.CBit);
- Context.EmitLdc_I4((Op.NZCV >> 2) & 1);
- Context.EmitStflg((int)APState.ZBit);
- Context.EmitLdc_I4((Op.NZCV >> 3) & 1);
- Context.EmitStflg((int)APState.NBit);
- Context.Emit(OpCodes.Br_S, LblEnd);
- Context.MarkLabel(LblTrue);
- Fcmp_S(Context);
- Context.MarkLabel(LblEnd);
- }
- public static void Fcmp_S(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
- //todo
- //Context.TryMarkCondWithoutCmp();
- void EmitLoadOpers()
- {
- Context.EmitLdvecsf(Op.Rn);
- if (CmpWithZero)
- {
- EmitLdcImmF(Context, 0, Op.Size);
- }
- else
- {
- Context.EmitLdvecsf(Op.Rm);
- }
- }
- //Z = Rn == Rm
- EmitLoadOpers();
-
- Context.Emit(OpCodes.Ceq);
- Context.Emit(OpCodes.Dup);
- Context.EmitStflg((int)APState.ZBit);
- //C = Rn >= Rm
- EmitLoadOpers();
- Context.Emit(OpCodes.Cgt);
- Context.Emit(OpCodes.Or);
- Context.EmitStflg((int)APState.CBit);
- //N = Rn < Rm
- EmitLoadOpers();
- Context.Emit(OpCodes.Clt);
- Context.EmitStflg((int)APState.NBit);
- //Handle NaN case. If any number is NaN, then NZCV = 0011.
- AILLabel LblNotNaN = new AILLabel();
- if (CmpWithZero)
- {
- EmitNaNCheck(Context, Op.Rn);
- }
- else
- {
- EmitNaNCheck(Context, Op.Rn);
- EmitNaNCheck(Context, Op.Rm);
- Context.Emit(OpCodes.Or);
- }
- Context.Emit(OpCodes.Brfalse_S, LblNotNaN);
- Context.EmitLdc_I4(1);
- Context.EmitLdc_I4(1);
- Context.EmitStflg((int)APState.CBit);
- Context.EmitStflg((int)APState.VBit);
- Context.MarkLabel(LblNotNaN);
- }
- public static void Fcmpe_S(AILEmitterCtx Context)
- {
- //TODO: Raise exception if value is NaN, how to handle exceptions?
- Fcmp_S(Context);
- }
- public static void Fcsel_S(AILEmitterCtx Context)
- {
- AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
- AILLabel LblTrue = new AILLabel();
- AILLabel LblEnd = new AILLabel();
- Context.EmitCondBranch(LblTrue, Op.Cond);
- Context.EmitLdvecsf(Op.Rm);
- Context.EmitStvecsf(Op.Rd);
- Context.Emit(OpCodes.Br_S, LblEnd);
- Context.MarkLabel(LblTrue);
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitStvecsf(Op.Rd);
- Context.MarkLabel(LblEnd);
- }
- public static void Fcvt_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- EmitFloatCast(Context, Op.Opc);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fcvtms_S(AILEmitterCtx Context) => EmitMathOpCvtToInt(Context, nameof(Math.Floor));
- public static void Fcvtps_S(AILEmitterCtx Context) => EmitMathOpCvtToInt(Context, nameof(Math.Ceiling));
- public static void Fcvtzs_S(AILEmitterCtx Context) => EmitFcvtz_(Context, true);
- public static void Fcvtzu_S(AILEmitterCtx Context) => EmitFcvtz_(Context, false);
- private static void EmitFcvtz_(AILEmitterCtx Context, bool Signed)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- if (Signed)
- {
- EmitCvtToInt(Context, Op.Size);
- }
- else
- {
- EmitCvtToUInt(Context, Op.Size);
- }
- Context.EmitStintzr(Op.Rd);
- }
- public static void Fcvtzs_Fix(AILEmitterCtx Context) => EmitFcvtz__Fix(Context, true);
- public static void Fcvtzu_Fix(AILEmitterCtx Context) => EmitFcvtz__Fix(Context, false);
- private static void EmitFcvtz__Fix(AILEmitterCtx Context, bool Signed)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- EmitLdcImmF(Context, 1L << Op.FBits, Op.Size);
- Context.Emit(OpCodes.Mul);
- if (Signed)
- {
- EmitCvtToInt(Context, Op.Size);
- }
- else
- {
- EmitCvtToUInt(Context, Op.Size);
- }
- Context.EmitStintzr(Op.Rd);
- }
- public static void Fdiv_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Div);
- public static void Fmadd_S(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsf(Op.Ra);
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitLdvecsf(Op.Rm);
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Add);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fmax_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Max));
- public static void Fmin_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Min));
- public static void Fmaxnm_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Max));
- public static void Fminnm_S(AILEmitterCtx Context) => EmitMathOp3(Context, nameof(Math.Min));
- public static void Fmov_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fmov_Si(AILEmitterCtx Context)
- {
- AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp;
- Context.EmitLdc_I8(Op.Imm);
- Context.EmitLdc_I4(0);
- Context.EmitLdc_I4(Op.Size + 2);
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Fmov_S));
- Context.EmitStvec(Op.Rd);
- }
- public static void Fmov_Ftoi(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdvecsi(Op.Rn);
- Context.EmitStintzr(Op.Rd);
- }
- public static void Fmov_Itof(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdintzr(Op.Rn);
- Context.EmitStvecsi(Op.Rd);
- }
- public static void Fmov_Ftoi1(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdvec(Op.Rn);
- Context.EmitLdc_I4(1);
- Context.EmitLdc_I4(3);
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
- Context.EmitStintzr(Op.Rd);
- }
- public static void Fmov_Itof1(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdintzr(Op.Rn);
- Context.EmitLdc_I4(1);
- Context.EmitLdc_I4(3);
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Fmov_S));
- Context.EmitStvec(Op.Rd);
- }
- public static void Fmsub_S(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsf(Op.Ra);
- Context.EmitLdvecsf(Op.Rn);
- Context.Emit(OpCodes.Neg);
- Context.EmitLdvecsf(Op.Rm);
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Sub);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fmul_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Mul);
- public static void Fneg_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Neg);
- public static void Fnmul_S(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitLdvecsf(Op.Rm);
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Neg);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Frinta_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero);
- MethodInfo MthdInfo;
- if (Op.Size == 0)
- {
- Type[] Types = new Type[] { typeof(float), typeof(MidpointRounding) };
- MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types);
- }
- else if (Op.Size == 1)
- {
- Type[] Types = new Type[] { typeof(double), typeof(MidpointRounding) };
- MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types);
- }
- else
- {
- throw new InvalidOperationException();
- }
- Context.EmitCall(MthdInfo);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Frintm_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- MethodInfo MthdInfo;
- if (Op.Size == 0)
- {
- MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) });
- }
- else if (Op.Size == 1)
- {
- MthdInfo = typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) });
- }
- else
- {
- throw new InvalidOperationException();
- }
- Context.EmitCall(MthdInfo);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Fsqrt_S(AILEmitterCtx Context) => EmitMathOp2(Context, nameof(Math.Sqrt));
- public static void Fsub_S(AILEmitterCtx Context) => EmitScalarOp(Context, OpCodes.Sub);
- public static void Scvtf_Gp(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdintzr(Op.Rn);
- EmitFloatCast(Context, Op.Size);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Scvtf_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsi(Op.Rn);
- EmitFloatCast(Context, Op.Size);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void Shl_S(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
- Context.EmitLdvecsi(Op.Rn);
- Context.EmitLdc_I4(Op.Imm - (8 << Op.Size));
- Context.Emit(OpCodes.Shl);
- Context.EmitStvecsi(Op.Rd);
- }
- public static void Sshr_S(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
- Context.EmitLdvecsi(Op.Rn);
- Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
- Context.Emit(OpCodes.Shr);
- Context.EmitStvecsi(Op.Rd);
- }
- public static void Sub_S(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsi(Op.Rn);
- Context.EmitLdvecsi(Op.Rm);
- Context.Emit(OpCodes.Sub);
- Context.EmitStvecsi(Op.Rd);
- }
- public static void Ucvtf_Gp(AILEmitterCtx Context)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdintzr(Op.Rn);
- Context.Emit(OpCodes.Conv_R_Un);
- EmitFloatCast(Context, Op.Size);
- Context.EmitStvecsf(Op.Rd);
- }
- private static void EmitScalarOp(AILEmitterCtx Context, OpCode ILOp)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- //Negate and Not are the only unary operations supported on IL.
- //"Not" doesn't work with floats, so we don't need to compare it.
- if (ILOp != OpCodes.Neg)
- {
- Context.EmitLdvecsf(Op.Rm);
- }
- Context.Emit(ILOp);
- Context.EmitStvecsf(Op.Rd);
- }
- private static void EmitMathOp2(AILEmitterCtx Context, string Name)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- EmitMathOpCall(Context, Name);
- Context.EmitStvecsf(Op.Rd);
- }
- private static void EmitMathOp3(AILEmitterCtx Context, string Name)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- Context.EmitLdvecsf(Op.Rm);
- MethodInfo MthdInfo;
- if (Op.Size == 0)
- {
- MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) });
- }
- else if (Op.Size == 1)
- {
- MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) });
- }
- else
- {
- throw new InvalidOperationException();
- }
- Context.EmitCall(MthdInfo);
- Context.EmitStvecsf(Op.Rd);
- }
- public static void EmitMathOpCvtToInt(AILEmitterCtx Context, string Name)
- {
- AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
- Context.EmitLdvecsf(Op.Rn);
- EmitMathOpCall(Context, Name);
- EmitCvtToInt(Context, Op.Size);
- Context.EmitStintzr(Op.Rd);
- }
- private static void EmitMathOpCall(AILEmitterCtx Context, string Name)
- {
- IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
- MethodInfo MthdInfo;
- if (Op.Size == 0)
- {
- MthdInfo = typeof(MathF).GetMethod(Name);
- }
- else if (Op.Size == 1)
- {
- MthdInfo = typeof(Math).GetMethod(Name);
- }
- else
- {
- throw new InvalidOperationException();
- }
- Context.EmitCall(MthdInfo);
- }
- private static void EmitCvtToInt(AILEmitterCtx Context, int Size)
- {
- if (Size < 0 || Size > 1)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
- Context.EmitLdc_I4(0);
- if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
- {
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToInt32));
- }
- else /* if (Size == 1) */
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToInt32));
- }
- }
- else
- {
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToInt64));
- }
- else /* if (Size == 1) */
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToInt64));
- }
- }
- }
- private static void EmitCvtToUInt(AILEmitterCtx Context, int Size)
- {
- if (Size < 0 || Size > 1)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
- Context.EmitLdc_I4(0);
- if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
- {
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToUInt32));
- }
- else /* if (Size == 1) */
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToUInt32));
- }
- }
- else
- {
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatSingleToUInt64));
- }
- else /* if (Size == 1) */
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatDoubleToUInt64));
- }
- }
- }
- private static void EmitFloatCast(AILEmitterCtx Context, int Size)
- {
- if (Size == 0)
- {
- Context.Emit(OpCodes.Conv_R4);
- }
- else if (Size == 1)
- {
- Context.Emit(OpCodes.Conv_R8);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
- }
- private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size)
- {
- if (Size == 0)
- {
- Context.EmitLdc_R4((float)ImmF);
- }
- else if (Size == 1)
- {
- Context.EmitLdc_R8(ImmF);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
- }
- private static void EmitNaNCheck(AILEmitterCtx Context, int Index)
- {
- IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
- Context.EmitLdvecsf(Index);
- if (Op.Size == 0)
- {
- Context.EmitCall(typeof(float), nameof(float.IsNaN));
- }
- else if (Op.Size == 1)
- {
- Context.EmitCall(typeof(double), nameof(double.IsNaN));
- }
- else
- {
- throw new InvalidOperationException();
- }
- }
- }
- }
|