aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instructions/InstEmitAlu.cs
diff options
context:
space:
mode:
authorAlex Barney <thealexbarney@gmail.com>2018-10-30 19:43:02 -0600
committergdkchan <gab.dark.100@gmail.com>2018-10-30 22:43:02 -0300
commit9cb57fb4bb3bbae0ae052a5af4a96a49fc5d864d (patch)
tree0c97425aeb311c142bc92a6fcc503cb2c07d4376 /ChocolArm64/Instructions/InstEmitAlu.cs
parent5a87e58183578f5b84ca8d01cbb76aed11820f78 (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.cs402
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);
+ }
+ }
+}