diff options
| author | Alex Barney <thealexbarney@gmail.com> | 2018-10-30 19:43:02 -0600 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-10-30 22:43:02 -0300 |
| commit | 9cb57fb4bb3bbae0ae052a5af4a96a49fc5d864d (patch) | |
| tree | 0c97425aeb311c142bc92a6fcc503cb2c07d4376 /ChocolArm64/Instructions/InstEmitAlu.cs | |
| parent | 5a87e58183578f5b84ca8d01cbb76aed11820f78 (diff) | |
Adjust naming conventions for Ryujinx and ChocolArm64 projects (#484)
* Change naming convention for Ryujinx project
* Change naming convention for ChocolArm64 project
* Fix NaN
* Remove unneeded this. from Ryujinx project
* Adjust naming from new PRs
* Name changes based on feedback
* How did this get removed?
* Rebasing fix
* Change FP enum case
* Remove prefix from ChocolArm64 classes - Part 1
* Remove prefix from ChocolArm64 classes - Part 2
* Fix alignment from last commit's renaming
* Rename namespaces
* Rename stragglers
* Fix alignment
* Rename OpCode class
* Missed a few
* Adjust alignment
Diffstat (limited to 'ChocolArm64/Instructions/InstEmitAlu.cs')
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitAlu.cs | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/ChocolArm64/Instructions/InstEmitAlu.cs b/ChocolArm64/Instructions/InstEmitAlu.cs new file mode 100644 index 00000000..c0258ed2 --- /dev/null +++ b/ChocolArm64/Instructions/InstEmitAlu.cs @@ -0,0 +1,402 @@ +using ChocolArm64.Decoders; +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) + { + EmitDataLoadOpers(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); + } + + EmitDataStore(context); + } + + public static void Add(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Add); + + public static void Adds(ILEmitterCtx context) + { + EmitDataLoadOpers(context); + + context.Emit(OpCodes.Add); + + context.EmitZnFlagCheck(); + + EmitAddsCCheck(context); + EmitAddsVCheck(context); + EmitDataStoreS(context); + } + + public static void And(ILEmitterCtx context) => EmitDataOp(context, OpCodes.And); + + public static void Ands(ILEmitterCtx context) + { + EmitDataLoadOpers(context); + + context.Emit(OpCodes.And); + + EmitZeroCvFlags(context); + + context.EmitZnFlagCheck(); + + EmitDataStoreS(context); + } + + public static void Asrv(ILEmitterCtx context) => EmitDataOpShift(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) + { + EmitDataLoadOpers(context); + + context.Emit(OpCodes.Not); + context.Emit(OpCodes.And); + + if (setFlags) + { + EmitZeroCvFlags(context); + + context.EmitZnFlagCheck(); + } + + EmitDataStore(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) + { + EmitDataLoadOpers(context); + + context.Emit(OpCodes.Not); + context.Emit(OpCodes.Xor); + + EmitDataStore(context); + } + + public static void Eor(ILEmitterCtx context) => EmitDataOp(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); + } + + EmitDataStore(context); + } + + public static void Lslv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shl); + public static void Lsrv(ILEmitterCtx context) => EmitDataOpShift(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) + { + EmitDataLoadOpers(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); + } + + EmitDataStore(context); + } + + public static void Sub(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Sub); + + public static void Subs(ILEmitterCtx context) + { + context.TryOptMarkCondWithoutCmp(); + + EmitDataLoadOpers(context); + + context.Emit(OpCodes.Sub); + + context.EmitZnFlagCheck(); + + EmitSubsCCheck(context); + EmitSubsVCheck(context); + EmitDataStoreS(context); + } + + public static void Orn(ILEmitterCtx context) + { + EmitDataLoadOpers(context); + + context.Emit(OpCodes.Not); + context.Emit(OpCodes.Or); + + EmitDataStore(context); + } + + public static void Orr(ILEmitterCtx context) => EmitDataOp(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) + { + EmitDataLoadRn(context); + EmitDataLoadShift(context); + + context.Emit(OpCodes.Shr_Un); + + EmitDataLoadRn(context); + + context.EmitLdc_I4(context.CurrOp.GetBitsCount()); + + EmitDataLoadShift(context); + + context.Emit(OpCodes.Sub); + context.Emit(OpCodes.Shl); + context.Emit(OpCodes.Or); + + EmitDataStore(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); + + EmitDataLoadRm(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); + + EmitDataLoadRn(context); + + context.EmitLdc_I(intMin); + + context.Emit(OpCodes.Ceq); + + EmitDataLoadRm(context); + + context.EmitLdc_I(-1); + + context.Emit(OpCodes.Ceq); + context.Emit(OpCodes.And); + context.Emit(OpCodes.Brtrue_S, badDiv); + context.Emit(OpCodes.Pop); + } + + EmitDataLoadRn(context); + EmitDataLoadRm(context); + + context.Emit(ilOp); + + context.MarkLabel(badDiv); + + EmitDataStore(context); + } + + private static void EmitDataOp(ILEmitterCtx context, OpCode ilOp) + { + EmitDataLoadOpers(context); + + context.Emit(ilOp); + + EmitDataStore(context); + } + + private static void EmitDataOpShift(ILEmitterCtx context, OpCode ilOp) + { + EmitDataLoadRn(context); + EmitDataLoadShift(context); + + context.Emit(ilOp); + + EmitDataStore(context); + } + + private static void EmitDataLoadShift(ILEmitterCtx context) + { + EmitDataLoadRm(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); + } + } +} |
