| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- using ChocolArm64.Decoders;
- using ChocolArm64.IntermediateRepresentation;
- using ChocolArm64.State;
- using ChocolArm64.Translation;
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Runtime.Intrinsics.X86;
- using static ChocolArm64.Instructions.InstEmitAluHelper;
- namespace ChocolArm64.Instructions
- {
- static partial class InstEmit
- {
- public static void Adc(ILEmitterCtx context) => EmitAdc(context, false);
- public static void Adcs(ILEmitterCtx context) => EmitAdc(context, true);
- private static void EmitAdc(ILEmitterCtx context, bool setFlags)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Add);
- context.EmitLdflg((int)PState.CBit);
- Type[] mthdTypes = new Type[] { typeof(bool) };
- MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
- context.EmitCall(mthdInfo);
- if (context.CurrOp.RegisterSize != RegisterSize.Int32)
- {
- context.Emit(OpCodes.Conv_U8);
- }
- context.Emit(OpCodes.Add);
- if (setFlags)
- {
- context.EmitZnFlagCheck();
- EmitAdcsCCheck(context);
- EmitAddsVCheck(context);
- }
- EmitAluStore(context);
- }
- public static void Add(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Add);
- public static void Adds(ILEmitterCtx context)
- {
- context.TryOptMarkCondWithoutCmp();
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Add);
- context.EmitZnFlagCheck();
- EmitAddsCCheck(context);
- EmitAddsVCheck(context);
- EmitAluStoreS(context);
- }
- public static void And(ILEmitterCtx context) => EmitAluOp(context, OpCodes.And);
- public static void Ands(ILEmitterCtx context)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.And);
- EmitZeroCvFlags(context);
- context.EmitZnFlagCheck();
- EmitAluStoreS(context);
- }
- public static void Asrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr);
- public static void Bic(ILEmitterCtx context) => EmitBic(context, false);
- public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
- private static void EmitBic(ILEmitterCtx context, bool setFlags)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Not);
- context.Emit(OpCodes.And);
- if (setFlags)
- {
- EmitZeroCvFlags(context);
- context.EmitZnFlagCheck();
- }
- EmitAluStore(context, setFlags);
- }
- public static void Cls(ILEmitterCtx context)
- {
- OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
- context.EmitLdintzr(op.Rn);
- context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64);
- SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingSigns));
- context.EmitStintzr(op.Rd);
- }
- public static void Clz(ILEmitterCtx context)
- {
- OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
- context.EmitLdintzr(op.Rn);
- if (Lzcnt.IsSupported)
- {
- Type tValue = op.RegisterSize == RegisterSize.Int32 ? typeof(uint) : typeof(ulong);
- context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { tValue }));
- }
- else
- {
- context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64);
- SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingZeros));
- }
- context.EmitStintzr(op.Rd);
- }
- public static void Eon(ILEmitterCtx context)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Not);
- context.Emit(OpCodes.Xor);
- EmitAluStore(context);
- }
- public static void Eor(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Xor);
- public static void Extr(ILEmitterCtx context)
- {
- // TODO: Ensure that the Shift is valid for the Is64Bits.
- OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;
- context.EmitLdintzr(op.Rm);
- if (op.Shift > 0)
- {
- context.EmitLdc_I4(op.Shift);
- context.Emit(OpCodes.Shr_Un);
- context.EmitLdintzr(op.Rn);
- context.EmitLdc_I4(op.GetBitsCount() - op.Shift);
- context.Emit(OpCodes.Shl);
- context.Emit(OpCodes.Or);
- }
- EmitAluStore(context);
- }
- public static void Lslv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shl);
- public static void Lsrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr_Un);
- public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
- public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
- private static void EmitSbc(ILEmitterCtx context, bool setFlags)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Sub);
- context.EmitLdflg((int)PState.CBit);
- Type[] mthdTypes = new Type[] { typeof(bool) };
- MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
- context.EmitCall(mthdInfo);
- context.EmitLdc_I4(1);
- context.Emit(OpCodes.Xor);
- if (context.CurrOp.RegisterSize != RegisterSize.Int32)
- {
- context.Emit(OpCodes.Conv_U8);
- }
- context.Emit(OpCodes.Sub);
- if (setFlags)
- {
- context.EmitZnFlagCheck();
- EmitSbcsCCheck(context);
- EmitSubsVCheck(context);
- }
- EmitAluStore(context);
- }
- public static void Sub(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Sub);
- public static void Subs(ILEmitterCtx context)
- {
- context.TryOptMarkCondWithoutCmp();
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Sub);
- context.EmitZnFlagCheck();
- EmitSubsCCheck(context);
- EmitSubsVCheck(context);
- EmitAluStoreS(context);
- }
- public static void Orn(ILEmitterCtx context)
- {
- EmitAluLoadOpers(context);
- context.Emit(OpCodes.Not);
- context.Emit(OpCodes.Or);
- EmitAluStore(context);
- }
- public static void Orr(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Or);
- public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context,
- nameof(SoftFallback.ReverseBits32),
- nameof(SoftFallback.ReverseBits64));
- public static void Rev16(ILEmitterCtx context) => EmitFallback32_64(context,
- nameof(SoftFallback.ReverseBytes16_32),
- nameof(SoftFallback.ReverseBytes16_64));
- public static void Rev32(ILEmitterCtx context) => EmitFallback32_64(context,
- nameof(SoftFallback.ReverseBytes32_32),
- nameof(SoftFallback.ReverseBytes32_64));
- private static void EmitFallback32_64(ILEmitterCtx context, string name32, string name64)
- {
- OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
- context.EmitLdintzr(op.Rn);
- if (op.RegisterSize == RegisterSize.Int32)
- {
- SoftFallback.EmitCall(context, name32);
- }
- else
- {
- SoftFallback.EmitCall(context, name64);
- }
- context.EmitStintzr(op.Rd);
- }
- public static void Rev64(ILEmitterCtx context)
- {
- OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
- context.EmitLdintzr(op.Rn);
- SoftFallback.EmitCall(context, nameof(SoftFallback.ReverseBytes64));
- context.EmitStintzr(op.Rd);
- }
- public static void Rorv(ILEmitterCtx context)
- {
- EmitAluLoadRn(context);
- EmitAluLoadShift(context);
- context.Emit(OpCodes.Shr_Un);
- EmitAluLoadRn(context);
- context.EmitLdc_I4(context.CurrOp.GetBitsCount());
- EmitAluLoadShift(context);
- context.Emit(OpCodes.Sub);
- context.Emit(OpCodes.Shl);
- context.Emit(OpCodes.Or);
- EmitAluStore(context);
- }
- public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div);
- public static void Udiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div_Un);
- private static void EmitDiv(ILEmitterCtx context, OpCode ilOp)
- {
- // If Rm == 0, Rd = 0 (division by zero).
- context.EmitLdc_I(0);
- EmitAluLoadRm(context);
- context.EmitLdc_I(0);
- ILLabel badDiv = new ILLabel();
- context.Emit(OpCodes.Beq_S, badDiv);
- context.Emit(OpCodes.Pop);
- if (ilOp == OpCodes.Div)
- {
- // If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
- long intMin = 1L << (context.CurrOp.GetBitsCount() - 1);
- context.EmitLdc_I(intMin);
- EmitAluLoadRn(context);
- context.EmitLdc_I(intMin);
- context.Emit(OpCodes.Ceq);
- EmitAluLoadRm(context);
- context.EmitLdc_I(-1);
- context.Emit(OpCodes.Ceq);
- context.Emit(OpCodes.And);
- context.Emit(OpCodes.Brtrue_S, badDiv);
- context.Emit(OpCodes.Pop);
- }
- EmitAluLoadRn(context);
- EmitAluLoadRm(context);
- context.Emit(ilOp);
- context.MarkLabel(badDiv);
- EmitAluStore(context);
- }
- private static void EmitAluOp(ILEmitterCtx context, OpCode ilOp)
- {
- EmitAluLoadOpers(context);
- context.Emit(ilOp);
- EmitAluStore(context);
- }
- private static void EmitAluOpShift(ILEmitterCtx context, OpCode ilOp)
- {
- EmitAluLoadRn(context);
- EmitAluLoadShift(context);
- context.Emit(ilOp);
- EmitAluStore(context);
- }
- private static void EmitAluLoadShift(ILEmitterCtx context)
- {
- EmitAluLoadRm(context);
- context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
- context.Emit(OpCodes.And);
- // Note: Only 32-bits shift values are valid, so when the value is 64-bits
- // we need to cast it to a 32-bits integer. This is fine because we
- // AND the value and only keep the lower 5 or 6 bits anyway -- it
- // could very well fit on a byte.
- if (context.CurrOp.RegisterSize != RegisterSize.Int32)
- {
- context.Emit(OpCodes.Conv_I4);
- }
- }
- private static void EmitZeroCvFlags(ILEmitterCtx context)
- {
- context.EmitLdc_I4(0);
- context.EmitStflg((int)PState.VBit);
- context.EmitLdc_I4(0);
- context.EmitStflg((int)PState.CBit);
- }
- public static void EmitAluStore(ILEmitterCtx context) => EmitAluStore(context, false);
- public static void EmitAluStoreS(ILEmitterCtx context) => EmitAluStore(context, true);
- public static void EmitAluStore(ILEmitterCtx context, bool setFlags)
- {
- IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
- if (setFlags || op is IOpCodeAluRs64)
- {
- context.EmitStintzr(op.Rd);
- }
- else
- {
- context.EmitStint(op.Rd);
- }
- }
- }
- }
|