aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-02-17 18:06:11 -0300
committergdkchan <gab.dark.100@gmail.com>2018-02-17 18:06:11 -0300
commit161193e113d4f3a481203573a1fe8772a6b16235 (patch)
treeadd92e11b6a6b83ba78f2bca666cbfaa14cad0fd
parentb3e47b571241d8795d6f81c1ddcdc6268fc60f9e (diff)
CPU refactoring - move SIMD (scalar and vector) instructions to separate files by category, remove AILConv and use only the methods inside SIMD helper to extract/insert vector elements
-rw-r--r--Ryujinx/Cpu/AOpCodeTable.cs12
-rw-r--r--Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs2
-rw-r--r--Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs2
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitMemory.cs2
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs105
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitScalar.cs745
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimd.cs1370
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs354
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs236
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs399
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs508
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs69
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs155
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs275
-rw-r--r--Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs306
-rw-r--r--Ryujinx/Cpu/Instruction/ASoftFallback.cs197
-rw-r--r--Ryujinx/Cpu/Memory/AMemory.cs72
-rw-r--r--Ryujinx/Cpu/Translation/AILConv.cs113
-rw-r--r--Ryujinx/Cpu/Translation/AILEmitter.cs3
-rw-r--r--Ryujinx/Cpu/Translation/AILEmitterCtx.cs108
-rw-r--r--Ryujinx/Cpu/Translation/AILOpCodeLoad.cs57
-rw-r--r--Ryujinx/Cpu/Translation/AILOpCodeStore.cs63
-rw-r--r--Ryujinx/OsHle/Horizon.cs2
-rw-r--r--Ryujinx/OsHle/Process.cs2
24 files changed, 2549 insertions, 2608 deletions
diff --git a/Ryujinx/Cpu/AOpCodeTable.cs b/Ryujinx/Cpu/AOpCodeTable.cs
index ffdf30a9..c9678fb5 100644
--- a/Ryujinx/Cpu/AOpCodeTable.cs
+++ b/Ryujinx/Cpu/AOpCodeTable.cs
@@ -151,14 +151,14 @@ namespace ChocolArm64
Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd));
- Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_S, typeof(AOpCodeSimdCvt));
- Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_S, typeof(AOpCodeSimdCvt));
- Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_S, typeof(AOpCodeSimdCvt));
- Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Fix, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt));
Set("0x0011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd));
Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm));
- Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_S, typeof(AOpCodeSimdCvt));
- Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Fix, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
+ Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
Set("0x1011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
index 7c285b28..9ea979ba 100644
--- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
+++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs
@@ -37,6 +37,8 @@ namespace ChocolArm64.Decoder
return;
}
+ Extend64 = false;
+
RegisterSize = Q
? ARegisterSize.SIMD128
: ARegisterSize.SIMD64;
diff --git a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs
index 5782d54b..52b8e470 100644
--- a/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs
+++ b/Ryujinx/Cpu/Decoder/AOpCodeSimdMemSs.cs
@@ -87,6 +87,8 @@ namespace ChocolArm64.Decoder
this.SElems = SElems;
this.Size = Scale;
+ Extend64 = false;
+
WBack = ((OpCode >> 23) & 0x1) != 0;
RegisterSize = Q != 0
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs
index ca0c82a3..af7de3ba 100644
--- a/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs
+++ b/Ryujinx/Cpu/Instruction/AInstEmitMemory.cs
@@ -20,7 +20,7 @@ namespace ChocolArm64.Instruction
{
AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp;
- Context.EmitLdc_I((Op.Position & ~0xfff) + (Op.Imm << 12));
+ Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12));
Context.EmitStintzr(Op.Rd);
}
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs
index e05153d9..d5a0051b 100644
--- a/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs
+++ b/Ryujinx/Cpu/Instruction/AInstEmitMemoryHelper.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Decoder;
using ChocolArm64.Memory;
using ChocolArm64.Translation;
using System;
@@ -31,67 +32,107 @@ namespace ChocolArm64.Instruction
private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size)
{
- if (Size < 0 || Size > 4)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
+ bool IsSimd = GetIsSimd(Context);
string Name = null;
- switch (Size)
+ if (Size < 0 || Size > (IsSimd ? 4 : 3))
{
- case 0: Name = nameof(AMemory.ReadByte); break;
- case 1: Name = nameof(AMemory.ReadUInt16); break;
- case 2: Name = nameof(AMemory.ReadUInt32); break;
- case 3: Name = nameof(AMemory.ReadUInt64); break;
- case 4: Name = nameof(AMemory.ReadVector128); break;
+ throw new ArgumentOutOfRangeException(nameof(Size));
}
- Context.EmitCall(typeof(AMemory), Name);
-
- if (Ext == Extension.Sx32 ||
- Ext == Extension.Sx64)
+ if (IsSimd)
+ {
+ switch (Size)
+ {
+ case 0: Name = nameof(AMemory.ReadVector8); break;
+ case 1: Name = nameof(AMemory.ReadVector16); break;
+ case 2: Name = nameof(AMemory.ReadVector32); break;
+ case 3: Name = nameof(AMemory.ReadVector64); break;
+ case 4: Name = nameof(AMemory.ReadVector128); break;
+ }
+ }
+ else
{
switch (Size)
{
- case 0: Context.Emit(OpCodes.Conv_I1); break;
- case 1: Context.Emit(OpCodes.Conv_I2); break;
- case 2: Context.Emit(OpCodes.Conv_I4); break;
+ case 0: Name = nameof(AMemory.ReadByte); break;
+ case 1: Name = nameof(AMemory.ReadUInt16); break;
+ case 2: Name = nameof(AMemory.ReadUInt32); break;
+ case 3: Name = nameof(AMemory.ReadUInt64); break;
}
}
- if (Size < 3)
+ Context.EmitCall(typeof(AMemory), Name);
+
+ if (!IsSimd)
{
- Context.Emit(Ext == Extension.Sx64
- ? OpCodes.Conv_I8
- : OpCodes.Conv_U8);
+ if (Ext == Extension.Sx32 ||
+ Ext == Extension.Sx64)
+ {
+ switch (Size)
+ {
+ case 0: Context.Emit(OpCodes.Conv_I1); break;
+ case 1: Context.Emit(OpCodes.Conv_I2); break;
+ case 2: Context.Emit(OpCodes.Conv_I4); break;
+ }
+ }
+
+ if (Size < 3)
+ {
+ Context.Emit(Ext == Extension.Sx64
+ ? OpCodes.Conv_I8
+ : OpCodes.Conv_U8);
+ }
}
}
public static void EmitWriteCall(AILEmitterCtx Context, int Size)
{
- if (Size < 0 || Size > 4)
+ bool IsSimd = GetIsSimd(Context);
+
+ string Name = null;
+
+ if (Size < 0 || Size > (IsSimd ? 4 : 3))
{
throw new ArgumentOutOfRangeException(nameof(Size));
- }
+ }
- if (Size < 3)
+ if (Size < 3 && !IsSimd)
{
Context.Emit(OpCodes.Conv_I4);
}
- string Name = null;
-
- switch (Size)
+ if (IsSimd)
{
- case 0: Name = nameof(AMemory.WriteByte); break;
- case 1: Name = nameof(AMemory.WriteUInt16); break;
- case 2: Name = nameof(AMemory.WriteUInt32); break;
- case 3: Name = nameof(AMemory.WriteUInt64); break;
- case 4: Name = nameof(AMemory.WriteVector128); break;
+ switch (Size)
+ {
+ case 0: Name = nameof(AMemory.WriteVector8); break;
+ case 1: Name = nameof(AMemory.WriteVector16); break;
+ case 2: Name = nameof(AMemory.WriteVector32); break;
+ case 3: Name = nameof(AMemory.WriteVector64); break;
+ case 4: Name = nameof(AMemory.WriteVector128); break;
+ }
+ }
+ else
+ {
+ switch (Size)
+ {
+ case 0: Name = nameof(AMemory.WriteByte); break;
+ case 1: Name = nameof(AMemory.WriteUInt16); break;
+ case 2: Name = nameof(AMemory.WriteUInt32); break;
+ case 3: Name = nameof(AMemory.WriteUInt64); break;
+ }
}
Context.EmitCall(typeof(AMemory), Name);
}
+
+ private static bool GetIsSimd(AILEmitterCtx Context)
+ {
+ return Context.CurrOp is IAOpCodeSimd &&
+ !(Context.CurrOp is AOpCodeSimdMemMs ||
+ Context.CurrOp is AOpCodeSimdMemSs);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs b/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs
deleted file mode 100644
index cb97d40f..00000000
--- a/Ryujinx/Cpu/Instruction/AInstEmitScalar.cs
+++ /dev/null
@@ -1,745 +0,0 @@
-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);
- }
-
- public static void Ucvtf_S(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- Context.EmitLdvecsi(Op.Rn);
-
- Context.Emit(OpCodes.Conv_R_Un);
-
- EmitFloatCast(Context, Op.Size);
-
- Context.EmitStvecsf(Op.Rd);
- }
-
- public static void Umov_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.ExtractVec));
-
- Context.EmitStintzr(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();
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs
deleted file mode 100644
index f4f9aa1a..00000000
--- a/Ryujinx/Cpu/Instruction/AInstEmitSimd.cs
+++ /dev/null
@@ -1,1370 +0,0 @@
-using ChocolArm64.Decoder;
-using ChocolArm64.State;
-using ChocolArm64.Translation;
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-
-using static ChocolArm64.Instruction.AInstEmitMemoryHelper;
-
-namespace ChocolArm64.Instruction
-{
- static partial class AInstEmit
- {
- public static void Add_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Add));
- }
-
- public static void Addp_V(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- int Elems = Bytes >> Op.Size;
- int Half = Elems >> 1;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- int Elem = (Index & (Half - 1)) << 1;
-
- EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size);
- EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size);
-
- Context.Emit(OpCodes.Add);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- public static void Addv_V(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- int Results = 0;
-
- for (int Size = Op.Size; Size < 4; Size++)
- {
- for (int Index = 0; Index < (Bytes >> Size); Index += 2)
- {
- EmitVectorExtractZx(Context, Op.Rn, Index + 0, Size);
- EmitVectorExtractZx(Context, Op.Rn, Index + 1, Size);
-
- Context.Emit(OpCodes.Add);
-
- Results++;
- }
- }
-
- while (--Results > 0)
- {
- Context.Emit(OpCodes.Add);
- }
-
- EmitVectorZeroLower(Context, Op.Rd);
- EmitVectorZeroUpper(Context, Op.Rd);
-
- EmitVectorInsert(Context, Op.Rd, 0, Op.Size);
- }
-
- public static void And_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.And));
- }
-
- public static void Bic_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () =>
- {
- Context.Emit(OpCodes.Not);
- Context.Emit(OpCodes.And);
- });
- }
-
- public static void Bic_Vi(AILEmitterCtx Context)
- {
- EmitVectorImmBinary(Context, () =>
- {
- Context.Emit(OpCodes.Not);
- Context.Emit(OpCodes.And);
- });
- }
-
- public static void Bsl_V(AILEmitterCtx Context)
- {
- EmitVectorTernaryZx(Context, () =>
- {
- Context.EmitSttmp();
- Context.EmitLdtmp();
-
- Context.Emit(OpCodes.Xor);
- Context.Emit(OpCodes.And);
-
- Context.EmitLdtmp();
-
- Context.Emit(OpCodes.Xor);
- });
- }
-
- public static void Cmeq_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Beq_S);
- }
-
- public static void Cmge_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Bge_S);
- }
-
- public static void Cmgt_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Bgt_S);
- }
-
- public static void Cmhi_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Bgt_Un_S);
- }
-
- public static void Cmhs_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Bge_Un_S);
- }
-
- public static void Cmle_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Ble_S);
- }
-
- public static void Cmlt_V(AILEmitterCtx Context)
- {
- EmitVectorCmp(Context, OpCodes.Blt_S);
- }
-
- public static void Cnt_V(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- EmitVectorExtractZx(Context, Op.Rn, Index, 0);
-
- Context.Emit(OpCodes.Conv_U1);
-
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8));
-
- Context.Emit(OpCodes.Conv_U8);
-
- EmitVectorInsert(Context, Op.Rd, Index, 0);
- }
- }
-
- public static void Dup_Gp(AILEmitterCtx Context)
- {
- AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- Context.EmitLdintzr(Op.Rn);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- public static void Dup_V(AILEmitterCtx Context)
- {
- AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- public static void Eor_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Xor));
- }
-
- public static void Fadd_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Add));
- }
-
- public static void Fcvtzs_V(AILEmitterCtx Context)
- {
- EmitVectorFcvt(Context, Signed: true);
- }
-
- public static void Fcvtzu_V(AILEmitterCtx Context)
- {
- EmitVectorFcvt(Context, Signed: false);
- }
-
- public static void Fmla_V(AILEmitterCtx Context)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
-
- EmitVectorTernaryF(Context, () =>
- {
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Add);
- });
- }
-
- public static void Fmla_Ve(AILEmitterCtx Context)
- {
- EmitVectorTernaryByElemF(Context, () =>
- {
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Add);
- });
- }
-
- public static void Fmov_V(AILEmitterCtx Context)
- {
- AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
-
- Context.EmitLdc_I8(Op.Imm);
- Context.EmitLdc_I4(Op.Size + 2);
-
- ASoftFallback.EmitCall(Context,
- nameof(ASoftFallback.Dup_Gp64),
- nameof(ASoftFallback.Dup_Gp128));
-
- Context.EmitStvec(Op.Rd);
- }
-
- public static void Fmul_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Mul));
- }
-
- public static void Fmul_Ve(AILEmitterCtx Context)
- {
- EmitVectorBinaryByElemF(Context, () => Context.Emit(OpCodes.Mul));
- }
-
- public static void Fsub_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryF(Context, () => Context.Emit(OpCodes.Sub));
- }
-
- public static void Ins_Gp(AILEmitterCtx Context)
- {
- AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
-
- Context.EmitLdintzr(Op.Rn);
-
- EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size);
- }
-
- public static void Ins_V(AILEmitterCtx Context)
- {
- AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
-
- EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size);
-
- EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size);
- }
-
- public static void Ld__Vms(AILEmitterCtx Context)
- {
- EmitSimdMemMs(Context, IsLoad: true);
- }
-
- public static void Ld__Vss(AILEmitterCtx Context)
- {
- EmitSimdMemSs(Context, IsLoad: true);
- }
-
- public static void Mla_V(AILEmitterCtx Context)
- {
- EmitVectorTernaryZx(Context, () =>
- {
- Context.Emit(OpCodes.Mul);
- Context.Emit(OpCodes.Add);
- });
- }
-
- public static void Movi_V(AILEmitterCtx Context)
- {
- EmitVectorImmUnary(Context, () => { });
- }
-
- public static void Mul_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Mul));
- }
-
- public static void Mvni_V(AILEmitterCtx Context)
- {
- EmitVectorImmUnary(Context, () => Context.Emit(OpCodes.Not));
- }
-
- public static void Neg_V(AILEmitterCtx Context)
- {
- EmitVectorUnarySx(Context, () => Context.Emit(OpCodes.Neg));
- }
-
- public static void Not_V(AILEmitterCtx Context)
- {
- EmitVectorUnaryZx(Context, () => Context.Emit(OpCodes.Not));
- }
-
- public static void Orr_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Or));
- }
-
- public static void Orr_Vi(AILEmitterCtx Context)
- {
- EmitVectorImmBinary(Context, () => Context.Emit(OpCodes.Or));
- }
-
- public static void Saddw_V(AILEmitterCtx Context)
- {
- EmitVectorWidenBinarySx(Context, () => Context.Emit(OpCodes.Add));
- }
-
- public static void Scvtf_V(AILEmitterCtx Context)
- {
- EmitVectorCvtf(Context, Signed: true);
- }
-
- public static void Shl_V(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = Op.Imm - (8 << Op.Size);
-
- EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
- }
-
- public static void Shrn_V(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = (8 << (Op.Size + 1)) - Op.Imm;
-
- EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift);
- }
-
- public static void Smax_V(AILEmitterCtx Context)
- {
- Type[] Types = new Type[] { typeof(long), typeof(long) };
-
- MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
-
- EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
- }
-
- public static void Smin_V(AILEmitterCtx Context)
- {
- Type[] Types = new Type[] { typeof(long), typeof(long) };
-
- MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
-
- EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
- }
-
- public static void Sshl_V(AILEmitterCtx Context)
- {
- EmitVectorShl(Context, Signed: true);
- }
-
- public static void Sshll_V(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = Op.Imm - (8 << Op.Size);
-
- EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift);
- }
-
- public static void Sshr_V(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = (8 << (Op.Size + 1)) - Op.Imm;
-
- EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift);
- }
-
- public static void St__Vms(AILEmitterCtx Context)
- {
- EmitSimdMemMs(Context, IsLoad: false);
- }
-
- public static void St__Vss(AILEmitterCtx Context)
- {
- EmitSimdMemSs(Context, IsLoad: false);
- }
-
- public static void Sub_V(AILEmitterCtx Context)
- {
- EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.Sub));
- }
-
- public static void Tbl_V(AILEmitterCtx Context)
- {
- AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp;
-
- Context.EmitLdvec(Op.Rm);
-
- for (int Index = 0; Index < Op.Size; Index++)
- {
- Context.EmitLdvec((Op.Rn + Index) & 0x1f);
- }
-
- switch (Op.Size)
- {
- case 1: ASoftFallback.EmitCall(Context,
- nameof(ASoftFallback.Tbl1_V64),
- nameof(ASoftFallback.Tbl1_V128)); break;
-
- case 2: ASoftFallback.EmitCall(Context,
- nameof(ASoftFallback.Tbl2_V64),
- nameof(ASoftFallback.Tbl2_V128)); break;
-
- case 3: ASoftFallback.EmitCall(Context,
- nameof(ASoftFallback.Tbl3_V64),
- nameof(ASoftFallback.Tbl3_V128)); break;
-
- case 4: ASoftFallback.EmitCall(Context,
- nameof(ASoftFallback.Tbl4_V64),
- nameof(ASoftFallback.Tbl4_V128)); break;
-
- default: throw new InvalidOperationException();
- }
-
- Context.EmitStvec(Op.Rd);
- }
-
- public static void Uaddlv_V(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
-
- for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
- {
- EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
-
- Context.Emit(OpCodes.Add);
- }
-
- EmitVectorZeroLower(Context, Op.Rd);
- EmitVectorZeroUpper(Context, Op.Rd);
-
- EmitVectorInsert(Context, Op.Rd, 0, Op.Size);
- }
-
- public static void Uaddw_V(AILEmitterCtx Context)
- {
- EmitVectorWidenBinaryZx(Context, () => Context.Emit(OpCodes.Add));
- }
-
- public static void Ucvtf_V(AILEmitterCtx Context)
- {
- EmitVectorCvtf(Context, Signed: false);
- }
-
- public static void Ushl_V(AILEmitterCtx Context)
- {
- EmitVectorShl(Context, Signed: false);
- }
-
- public static void Ushll_V(AILEmitterCtx Context)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = Op.Imm - (8 << Op.Size);
-
- EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
- }
-
- public static void Ushr_V(AILEmitterCtx Context)
- {
- EmitVectorShr(Context, ShrFlags.None);
- }
-
- public static void Usra_V(AILEmitterCtx Context)
- {
- EmitVectorShr(Context, ShrFlags.Accumulate);
- }
-
- [Flags]
- private enum ShrFlags
- {
- None = 0,
- Signed = 1 << 0,
- Rounding = 1 << 1,
- Accumulate = 1 << 2
- }
-
- private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Shift = (8 << (Op.Size + 1)) - Op.Imm;
-
- if (Flags.HasFlag(ShrFlags.Accumulate))
- {
- Action Emit = () =>
- {
- Context.EmitLdc_I4(Shift);
-
- Context.Emit(OpCodes.Shr_Un);
- Context.Emit(OpCodes.Add);
- };
-
- EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
- }
- else
- {
- EmitVectorUnaryZx(Context, () =>
- {
- Context.EmitLdc_I4(Shift);
-
- Context.Emit(OpCodes.Shr_Un);
- });
- }
- }
-
- public static void Uzp1_V(AILEmitterCtx Context)
- {
- EmitVectorUnzip(Context, Part: 0);
- }
-
- public static void Uzp2_V(AILEmitterCtx Context)
- {
- EmitVectorUnzip(Context, Part: 1);
- }
-
- private static void EmitVectorUnzip(AILEmitterCtx Context, int Part)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- int Elems = Bytes >> Op.Size;
- int Half = Elems >> 1;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- int Elem = Part + ((Index & (Half - 1)) << 1);
-
- EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- public static void Xtn_V(AILEmitterCtx Context)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Elems = 8 >> Op.Size;
-
- int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
-
- EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
- }
-
- if (Part == 0)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
- {
- AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
-
- int Offset = 0;
-
- for (int Rep = 0; Rep < Op.Reps; Rep++)
- for (int Elem = 0; Elem < Op.Elems; Elem++)
- for (int SElem = 0; SElem < Op.SElems; SElem++)
- {
- int Rtt = (Op.Rt + Rep + SElem) & 0x1f;
-
- if (IsLoad)
- {
- Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
- Context.EmitLdint(Op.Rn);
- Context.EmitLdc_I8(Offset);
-
- Context.Emit(OpCodes.Add);
-
- EmitReadZxCall(Context, Op.Size);
-
- EmitVectorInsert(Context, Rtt, Elem, Op.Size);
-
- if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1)
- {
- EmitVectorZeroUpper(Context, Rtt);
- }
- }
- else
- {
- Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
- Context.EmitLdint(Op.Rn);
- Context.EmitLdc_I8(Offset);
-
- Context.Emit(OpCodes.Add);
-
- EmitVectorExtractZx(Context, Rtt, Elem, Op.Size);
-
- EmitWriteCall(Context, Op.Size);
- }
-
- Offset += 1 << Op.Size;
- }
-
- if (Op.WBack)
- {
- EmitSimdMemWBack(Context, Offset);
- }
- }
-
- private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
- {
- AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
-
- //TODO: Replicate mode.
-
- int Offset = 0;
-
- for (int SElem = 0; SElem < Op.SElems; SElem++)
- {
- int Rt = (Op.Rt + SElem) & 0x1f;
-
- if (IsLoad)
- {
- Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
- Context.EmitLdint(Op.Rn);
- Context.EmitLdc_I8(Offset);
-
- Context.Emit(OpCodes.Add);
-
- EmitReadZxCall(Context, Op.Size);
-
- EmitVectorInsert(Context, Rt, Op.Index, Op.Size);
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Rt);
- }
- }
- else
- {
- Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
- Context.EmitLdint(Op.Rn);
- Context.EmitLdc_I8(Offset);
-
- Context.Emit(OpCodes.Add);
-
- EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size);
-
- EmitWriteCall(Context, Op.Size);
- }
-
- Offset += 1 << Op.Size;
- }
-
- if (Op.WBack)
- {
- EmitSimdMemWBack(Context, Offset);
- }
- }
-
- private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset)
- {
- AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp;
-
- Context.EmitLdint(Op.Rn);
-
- if (Op.Rm != ARegisters.ZRIndex)
- {
- Context.EmitLdint(Op.Rm);
- }
- else
- {
- Context.EmitLdc_I8(Offset);
- }
-
- Context.Emit(OpCodes.Add);
-
- Context.EmitStint(Op.Rn);
- }
-
- private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
-
- if (Op is AOpCodeSimdReg BinOp)
- {
- EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size);
- }
- else
- {
- Context.EmitLdc_I8(0);
- }
-
- AILLabel LblTrue = new AILLabel();
- AILLabel LblEnd = new AILLabel();
-
- Context.Emit(ILOp, LblTrue);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
-
- Context.Emit(OpCodes.Br_S, LblEnd);
-
- Context.MarkLabel(LblTrue);
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
-
- Context.MarkLabel(LblEnd);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
- {
- //This instruction shifts the value on vector A by the number of bits
- //specified on the signed, lower 8 bits of vector B. If the shift value
- //is greater or equal to the data size of each lane, then the result is zero.
- //Additionally, negative shifts produces right shifts by the negated shift value.
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int MaxShift = 8 << Op.Size;
-
- Action Emit = () =>
- {
- AILLabel LblShl = new AILLabel();
- AILLabel LblZero = new AILLabel();
- AILLabel LblEnd = new AILLabel();
-
- void EmitShift(OpCode ILOp)
- {
- Context.Emit(OpCodes.Dup);
-
- Context.EmitLdc_I4(MaxShift);
-
- Context.Emit(OpCodes.Bge_S, LblZero);
- Context.Emit(ILOp);
- Context.Emit(OpCodes.Br_S, LblEnd);
- }
-
- Context.Emit(OpCodes.Conv_I1);
- Context.Emit(OpCodes.Dup);
-
- Context.EmitLdc_I4(0);
-
- Context.Emit(OpCodes.Bge_S, LblShl);
- Context.Emit(OpCodes.Neg);
-
- EmitShift(Signed
- ? OpCodes.Shr
- : OpCodes.Shr_Un);
-
- Context.MarkLabel(LblShl);
-
- EmitShift(OpCodes.Shl);
-
- Context.MarkLabel(LblZero);
-
- Context.Emit(OpCodes.Pop);
- Context.Emit(OpCodes.Pop);
-
- Context.EmitLdc_I8(0);
-
- Context.MarkLabel(LblEnd);
- };
-
- if (Signed)
- {
- EmitVectorBinarySx(Context, Emit);
- }
- else
- {
- EmitVectorBinaryZx(Context, Emit);
- }
- }
-
- private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int SizeF = Op.Size & 1;
- int SizeI = SizeF + 2;
-
- int FBits = GetFBits(Context);
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> SizeI); Index++)
- {
- EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
-
- Context.EmitLdc_I4(FBits);
-
- if (SizeF == 0)
- {
- ASoftFallback.EmitCall(Context, Signed
- ? nameof(ASoftFallback.SatSingleToInt32)
- : nameof(ASoftFallback.SatSingleToUInt32));
- }
- else if (SizeF == 1)
- {
- ASoftFallback.EmitCall(Context, Signed
- ? nameof(ASoftFallback.SatDoubleToInt64)
- : nameof(ASoftFallback.SatDoubleToUInt64));
- }
-
- EmitVectorInsert(Context, Op.Rd, Index, SizeI);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int SizeF = Op.Size & 1;
- int SizeI = SizeF + 2;
-
- int FBits = GetFBits(Context);
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> SizeI); Index++)
- {
- EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed);
-
- Context.EmitLdc_I4(FBits);
-
- if (SizeF == 0)
- {
- Context.Emit(OpCodes.Conv_I4);
-
- ASoftFallback.EmitCall(Context, Signed
- ? nameof(ASoftFallback.Int32ToSingle)
- : nameof(ASoftFallback.UInt32ToSingle));
- }
- else if (SizeF == 1)
- {
- ASoftFallback.EmitCall(Context, Signed
- ? nameof(ASoftFallback.Int64ToDouble)
- : nameof(ASoftFallback.UInt64ToDouble));
- }
-
- EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static int GetFBits(AILEmitterCtx Context)
- {
- if (Context.CurrOp is AOpCodeSimdShImm Op)
- {
- return (8 << (Op.Size + 1)) - Op.Imm;
- }
-
- return 0;
- }
-
- [Flags]
- private enum OperFlags
- {
- Rd = 1 << 0,
- Rn = 1 << 1,
- Rm = 1 << 2,
-
- RnRm = Rn | Rm,
- RdRn = Rd | Rn,
- RdRnRm = Rd | Rn | Rm
- }
-
- private static void EmitVectorBinaryF(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorFOp(Context, Emit, OperFlags.RnRm);
- }
-
- private static void EmitVectorTernaryF(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorFOp(Context, Emit, OperFlags.RdRnRm);
- }
-
- private static void EmitVectorBinaryByElemF(AILEmitterCtx Context, Action Emit)
- {
- AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
-
- EmitVectorFOp(Context, Emit, OperFlags.RnRm, Op.Index);
- }
-
- private static void EmitVectorTernaryByElemF(AILEmitterCtx Context, Action Emit)
- {
- AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
-
- EmitVectorFOp(Context, Emit, OperFlags.RdRnRm, Op.Index);
- }
-
- private static void EmitVectorFOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, int Elem = -1)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
-
- int SizeF = Op.Size & 1;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++)
- {
- if (Opers.HasFlag(OperFlags.Rd))
- {
- EmitVectorExtractF(Context, Op.Rd, Index, SizeF);
- }
-
- if (Opers.HasFlag(OperFlags.Rn))
- {
- EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
- }
-
- if (Opers.HasFlag(OperFlags.Rm))
- {
- if (Elem != -1)
- {
- EmitVectorExtractF(Context, Op.Rm, Elem, SizeF);
- }
- else
- {
- EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
- }
- }
-
- Emit();
-
- EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorUnarySx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorOp(Context, Emit, OperFlags.Rn, true);
- }
-
- private static void EmitVectorBinarySx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorOp(Context, Emit, OperFlags.RnRm, true);
- }
-
- private static void EmitVectorUnaryZx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorOp(Context, Emit, OperFlags.Rn, false);
- }
-
- private static void EmitVectorBinaryZx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorOp(Context, Emit, OperFlags.RnRm, false);
- }
-
- private static void EmitVectorTernaryZx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false);
- }
-
- private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
- {
- AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- if (Opers.HasFlag(OperFlags.Rd))
- {
- EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
- }
-
- if (Opers.HasFlag(OperFlags.Rn))
- {
- EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
- }
-
- if (Opers.HasFlag(OperFlags.Rm))
- {
- EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
- }
-
- Emit();
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorImmUnary(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorImmOp(Context, Emit, false);
- }
-
- private static void EmitVectorImmBinary(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorImmOp(Context, Emit, true);
- }
-
- private static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary)
- {
- AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- if (Binary)
- {
- EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
- }
-
- Context.EmitLdc_I8(Op.Imm);
-
- Emit();
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmBinaryOp(Context, Emit, Imm, true);
- }
-
- private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmBinaryOp(Context, Emit, Imm, false);
- }
-
- private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Bytes = Context.CurrOp.GetBitsCount() >> 3;
-
- for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
- {
- EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
-
- Context.EmitLdc_I4(Imm);
-
- Emit();
-
- EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
- }
-
- if (Op.RegisterSize == ARegisterSize.SIMD64)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true);
- }
-
- private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false);
- }
-
- private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Elems = 8 >> Op.Size;
-
- int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
-
- Context.EmitLdc_I4(Imm);
-
- Emit();
-
- EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
- }
-
- if (Part == 0)
- {
- EmitVectorZeroUpper(Context, Op.Rd);
- }
- }
-
- private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true);
- }
-
- private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
- {
- EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false);
- }
-
- private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
- {
- AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
-
- int Elems = 8 >> Op.Size;
-
- int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
-
- Context.EmitLdc_I4(Imm);
-
- Emit();
-
- EmitVectorInsertTmp(Context, Index, Op.Size + 1);
- }
-
- Context.EmitLdvectmp();
- Context.EmitStvec(Op.Rd);
- }
-
- private static void EmitVectorWidenBinarySx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorWidenBinary(Context, Emit, true);
- }
-
- private static void EmitVectorWidenBinaryZx(AILEmitterCtx Context, Action Emit)
- {
- EmitVectorWidenBinary(Context, Emit, false);
- }
-
- private static void EmitVectorWidenBinary(AILEmitterCtx Context, Action Emit, bool Signed)
- {
- AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
-
- int Elems = 8 >> Op.Size;
-
- int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
-
- for (int Index = 0; Index < Elems; Index++)
- {
- EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
- EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed);
-
- Emit();
-
- EmitVectorInsertTmp(Context, Index, Op.Size + 1);
- }
-
- Context.EmitLdvectmp();
- Context.EmitStvec(Op.Rd);
- }
-
- private static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size)
- {
- Context.EmitLdvec(Reg);
- Context.EmitLdc_I4(Index);
-
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle));
- }
- else if (Size == 1)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble));
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
- }
-
- private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size)
- {
- EmitVectorExtract(Context, Reg, Index, Size, true);
- }
-
- private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size)
- {
- EmitVectorExtract(Context, Reg, Index, Size, false);
- }
-
- private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed)
- {
- if (Size < 0 || Size > 3)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
-
- Context.EmitLdvec(Reg);
- Context.EmitLdc_I4(Index);
- Context.EmitLdc_I4(Size);
-
- ASoftFallback.EmitCall(Context, Signed
- ? nameof(ASoftFallback.ExtractSVec)
- : nameof(ASoftFallback.ExtractVec));
- }
-
- private static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd)
- {
- EmitVectorInsert(Context, Rd, 0, 3, 0);
- }
-
- private static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd)
- {
- EmitVectorInsert(Context, Rd, 1, 3, 0);
- }
-
- private static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size)
- {
- Context.EmitLdvec(Reg);
- Context.EmitLdc_I4(Index);
-
- if (Size == 0)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle));
- }
- else if (Size == 1)
- {
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble));
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- Context.EmitStvec(Reg);
- }
-
- private static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size)
- {
- if (Size < 0 || Size > 3)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- Context.EmitLdvectmp();
- Context.EmitLdc_I4(Index);
- Context.EmitLdc_I4(Size);
-
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
-
- Context.EmitStvectmp();
- }
-
- private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size)
- {
- if (Size < 0 || Size > 3)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- Context.EmitLdvec(Reg);
- Context.EmitLdc_I4(Index);
- Context.EmitLdc_I4(Size);
-
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
-
- Context.EmitStvec(Reg);
- }
-
- private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value)
- {
- if (Size < 0 || Size > 3)
- {
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- Context.EmitLdvec(Reg);
- Context.EmitLdc_I4(Index);
- Context.EmitLdc_I4(Size);
- Context.EmitLdc_I8(Value);
-
- ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
-
- Context.EmitStvec(Reg);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs
new file mode 100644
index 00000000..854ba85d
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdArithmetic.cs
@@ -0,0 +1,354 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void Add_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
+ }
+
+ public static void Addp_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
+ EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Addp_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ int Elems = Bytes >> Op.Size;
+ int Half = Elems >> 1;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ int Elem = (Index & (Half - 1)) << 1;
+
+ EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size);
+ EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitVectorInsertTmp(Context, Index, Op.Size);
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitStvec(Op.Rd);
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void Addv_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
+
+ for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
+ {
+ EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
+
+ Context.Emit(OpCodes.Add);
+ }
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Cnt_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtractZx(Context, Op.Rn, Index, 0);
+
+ Context.Emit(OpCodes.Conv_U1);
+
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8));
+
+ Context.Emit(OpCodes.Conv_U8);
+
+ EmitVectorInsert(Context, Op.Rd, Index, 0);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void Fabs_S(AILEmitterCtx Context)
+ {
+ EmitScalarUnaryOpF(Context, () =>
+ {
+ EmitUnaryMathCall(Context, nameof(Math.Abs));
+ });
+ }
+
+ public static void Fadd_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
+ }
+
+ public static void Fadd_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
+ }
+
+ public static void Fdiv_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
+ }
+
+ public static void Fmadd_S(AILEmitterCtx Context)
+ {
+ EmitScalarTernaryRaOpF(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Add);
+ });
+ }
+
+ public static void Fmax_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () =>
+ {
+ EmitBinaryMathCall(Context, nameof(Math.Max));
+ });
+ }
+
+ public static void Fmin_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () =>
+ {
+ EmitBinaryMathCall(Context, nameof(Math.Min));
+ });
+ }
+
+ public static void Fmaxnm_S(AILEmitterCtx Context)
+ {
+ Fmax_S(Context);
+ }
+
+ public static void Fminnm_S(AILEmitterCtx Context)
+ {
+ Fmin_S(Context);
+ }
+
+ public static void Fmla_V(AILEmitterCtx Context)
+ {
+ EmitVectorTernaryOpF(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Add);
+ });
+ }
+
+ public static void Fmla_Ve(AILEmitterCtx Context)
+ {
+ EmitVectorTernaryOpByElemF(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Add);
+ });
+ }
+
+ public static void Fmsub_S(AILEmitterCtx Context)
+ {
+ EmitScalarTernaryRaOpF(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Neg);
+ Context.Emit(OpCodes.Add);
+ });
+ }
+
+ public static void Fmul_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
+ }
+
+ public static void Fmul_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
+ }
+
+ public static void Fmul_Ve(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
+ }
+
+ public static void Fneg_S(AILEmitterCtx Context)
+ {
+ EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
+ }
+
+ public static void Fnmul_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Neg);
+ });
+ }
+
+ public static void Frinta_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero);
+
+ MethodInfo MthdInfo;
+
+ Type[] Types = new Type[] { null, typeof(MidpointRounding) };
+
+ Types[0] = Op.Size == 0
+ ? typeof(float)
+ : typeof(double);
+
+ if (Op.Size == 0)
+ {
+ MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types);
+ }
+ else if (Op.Size == 1)
+ {
+ MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+
+ Context.EmitCall(MthdInfo);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Frintm_S(AILEmitterCtx Context)
+ {
+ EmitScalarUnaryOpF(Context, () =>
+ {
+ EmitUnaryMathCall(Context, nameof(Math.Floor));
+ });
+ }
+
+ public static void Fsqrt_S(AILEmitterCtx Context)
+ {
+ EmitScalarUnaryOpF(Context, () =>
+ {
+ EmitUnaryMathCall(Context, nameof(Math.Sqrt));
+ });
+ }
+
+ public static void Fsub_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
+ }
+
+ public static void Fsub_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
+ }
+
+ public static void Mla_V(AILEmitterCtx Context)
+ {
+ EmitVectorTernaryOpZx(Context, () =>
+ {
+ Context.Emit(OpCodes.Mul);
+ Context.Emit(OpCodes.Add);
+ });
+ }
+
+ public static void Mul_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
+ }
+
+ public static void Neg_V(AILEmitterCtx Context)
+ {
+ EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
+ }
+
+ public static void Saddw_V(AILEmitterCtx Context)
+ {
+ EmitVectorWidenBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
+ }
+
+ public static void Smax_V(AILEmitterCtx Context)
+ {
+ Type[] Types = new Type[] { typeof(long), typeof(long) };
+
+ MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
+
+ EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
+ }
+
+ public static void Smin_V(AILEmitterCtx Context)
+ {
+ Type[] Types = new Type[] { typeof(long), typeof(long) };
+
+ MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
+
+ EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
+ }
+
+ public static void Sub_S(AILEmitterCtx Context)
+ {
+ EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
+ }
+
+ public static void Sub_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
+ }
+
+ public static void Uaddlv_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
+
+ for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
+ {
+ EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
+
+ Context.Emit(OpCodes.Add);
+ }
+
+ EmitScalarSet(Context, Op.Rd, Op.Size + 1);
+ }
+
+ public static void Uaddw_V(AILEmitterCtx Context)
+ {
+ EmitVectorWidenBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs
new file mode 100644
index 00000000..92361fbd
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCmp.cs
@@ -0,0 +1,236 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void Cmeq_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Beq_S);
+ }
+
+ public static void Cmge_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Bge_S);
+ }
+
+ public static void Cmgt_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Bgt_S);
+ }
+
+ public static void Cmhi_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Bgt_Un_S);
+ }
+
+ public static void Cmhs_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Bge_Un_S);
+ }
+
+ public static void Cmle_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Ble_S);
+ }
+
+ public static void Cmlt_V(AILEmitterCtx Context)
+ {
+ EmitVectorCmp(Context, OpCodes.Blt_S);
+ }
+
+ 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;
+
+ void EmitLoadOpers()
+ {
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ if (CmpWithZero)
+ {
+ EmitLdcImmF(Context, 0, Op.Size);
+ }
+ else
+ {
+ EmitVectorExtractF(Context, Op.Rm, 0, Op.Size);
+ }
+ }
+
+ //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)
+ {
+ Fcmp_S(Context);
+ }
+
+ 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 Reg)
+ {
+ IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Reg, 0, Op.Size);
+
+ 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();
+ }
+ }
+
+ private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
+
+ if (Op is AOpCodeSimdReg BinOp)
+ {
+ EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size);
+ }
+ else
+ {
+ Context.EmitLdc_I8(0);
+ }
+
+ AILLabel LblTrue = new AILLabel();
+ AILLabel LblEnd = new AILLabel();
+
+ Context.Emit(ILOp, LblTrue);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
+
+ Context.Emit(OpCodes.Br_S, LblEnd);
+
+ Context.MarkLabel(LblTrue);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
+
+ Context.MarkLabel(LblEnd);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs
new file mode 100644
index 00000000..b7a47411
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdCvt.cs
@@ -0,0 +1,399 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void Fcvt_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ EmitFloatCast(Context, Op.Opc);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Opc);
+ }
+
+ public static void Fcvtms_Gp(AILEmitterCtx Context)
+ {
+ EmitFcvt_s_Gp(Context, nameof(Math.Floor));
+ }
+
+ public static void Fcvtps_Gp(AILEmitterCtx Context)
+ {
+ EmitFcvt_s_Gp(Context, nameof(Math.Ceiling));
+ }
+
+ public static void Fcvtzs_Gp(AILEmitterCtx Context)
+ {
+ EmitFcvtz__Gp(Context, Signed: true);
+ }
+
+ public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context)
+ {
+ EmitFcvtz__Gp_Fix(Context, Signed: true);
+ }
+
+ public static void Fcvtzs_V(AILEmitterCtx Context)
+ {
+ EmitVectorFcvt(Context, Signed: true);
+ }
+
+ public static void Fcvtzu_Gp(AILEmitterCtx Context)
+ {
+ EmitFcvtz__Gp(Context, Signed: false);
+ }
+
+ public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context)
+ {
+ EmitFcvtz__Gp_Fix(Context, Signed: false);
+ }
+
+ public static void Fcvtzu_V(AILEmitterCtx Context)
+ {
+ EmitVectorFcvt(Context, Signed: false);
+ }
+
+ public static void Scvtf_Gp(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ Context.EmitLdintzr(Op.Rn);
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Emit(OpCodes.Conv_U4);
+ }
+
+ EmitFloatCast(Context, Op.Size);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Scvtf_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractSx(Context, Op.Rd, 0, Op.Size + 2);
+
+ EmitFloatCast(Context, Op.Size);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Scvtf_V(AILEmitterCtx Context)
+ {
+ EmitVectorCvtf(Context, Signed: true);
+ }
+
+ public static void Ucvtf_Gp(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ Context.EmitLdintzr(Op.Rn);
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Emit(OpCodes.Conv_U4);
+ }
+
+ Context.Emit(OpCodes.Conv_R_Un);
+
+ EmitFloatCast(Context, Op.Size);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Ucvtf_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size + 2);
+
+ Context.Emit(OpCodes.Conv_R_Un);
+
+ EmitFloatCast(Context, Op.Size);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Ucvtf_V(AILEmitterCtx Context)
+ {
+ EmitVectorCvtf(Context, Signed: false);
+ }
+
+ private static int GetFBits(AILEmitterCtx Context)
+ {
+ if (Context.CurrOp is AOpCodeSimdShImm Op)
+ {
+ return GetImmShr(Op);
+ }
+
+ return 0;
+ }
+
+ 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 EmitFcvt_s_Gp(AILEmitterCtx Context, string Name)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ EmitUnaryMathCall(Context, Name);
+
+ EmitScalarFcvts(Context, Op.Size, 0);
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Emit(OpCodes.Conv_U8);
+ }
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ if (Signed)
+ {
+ EmitScalarFcvts(Context, Op.Size, 0);
+ }
+ else
+ {
+ EmitScalarFcvtu(Context, Op.Size, 0);
+ }
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Emit(OpCodes.Conv_U8);
+ }
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ if (Signed)
+ {
+ EmitScalarFcvts(Context, Op.Size, Op.FBits);
+ }
+ else
+ {
+ EmitScalarFcvtu(Context, Op.Size, Op.FBits);
+ }
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int SizeF = Op.Size & 1;
+ int SizeI = SizeF + 2;
+
+ int FBits = GetFBits(Context);
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> SizeI); Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed);
+
+ if (!Signed)
+ {
+ Context.Emit(OpCodes.Conv_R_Un);
+ }
+
+ Context.Emit(SizeF == 0
+ ? OpCodes.Conv_R4
+ : OpCodes.Conv_R8);
+
+ EmitI2fFBitsMul(Context, SizeF, FBits);
+
+ EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int SizeF = Op.Size & 1;
+ int SizeI = SizeF + 2;
+
+ int FBits = GetFBits(Context);
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> SizeI); Index++)
+ {
+ EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
+
+ EmitF2iFBitsMul(Context, SizeF, FBits);
+
+ if (SizeF == 0)
+ {
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.SatF32ToS32)
+ : nameof(ASoftFallback.SatF32ToU32));
+ }
+ else /* if (SizeF == 1) */
+ {
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.SatF64ToS64)
+ : nameof(ASoftFallback.SatF64ToU64));
+ }
+
+ EmitVectorInsert(Context, Op.Rd, Index, SizeI);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ private static void EmitScalarFcvts(AILEmitterCtx Context, int Size, int FBits)
+ {
+ if (Size < 0 || Size > 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ EmitF2iFBitsMul(Context, Size, FBits);
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS32));
+ }
+ else /* if (Size == 1) */
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS32));
+ }
+ }
+ else
+ {
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToS64));
+ }
+ else /* if (Size == 1) */
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToS64));
+ }
+ }
+ }
+
+ private static void EmitScalarFcvtu(AILEmitterCtx Context, int Size, int FBits)
+ {
+ if (Size < 0 || Size > 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ EmitF2iFBitsMul(Context, Size, FBits);
+
+ if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
+ {
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU32));
+ }
+ else /* if (Size == 1) */
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU32));
+ }
+ }
+ else
+ {
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF32ToU64));
+ }
+ else /* if (Size == 1) */
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SatF64ToU64));
+ }
+ }
+ }
+
+ private static void EmitF2iFBitsMul(AILEmitterCtx Context, int Size, int FBits)
+ {
+ if (FBits != 0)
+ {
+ if (Size == 0)
+ {
+ Context.EmitLdc_R4(MathF.Pow(2, FBits));
+ }
+ else if (Size == 1)
+ {
+ Context.EmitLdc_R8(Math.Pow(2, FBits));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.Emit(OpCodes.Mul);
+ }
+ }
+
+ private static void EmitI2fFBitsMul(AILEmitterCtx Context, int Size, int FBits)
+ {
+ if (FBits != 0)
+ {
+ if (Size == 0)
+ {
+ Context.EmitLdc_R4(1f / MathF.Pow(2, FBits));
+ }
+ else if (Size == 1)
+ {
+ Context.EmitLdc_R8(1 / Math.Pow(2, FBits));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.Emit(OpCodes.Mul);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs
new file mode 100644
index 00000000..0149fd2e
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdHelper.cs
@@ -0,0 +1,508 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection;
+
+namespace ChocolArm64.Instruction
+{
+ static class AInstEmitSimdHelper
+ {
+ [Flags]
+ public enum OperFlags
+ {
+ Rd = 1 << 0,
+ Rn = 1 << 1,
+ Rm = 1 << 2,
+ Ra = 1 << 3,
+
+ RnRm = Rn | Rm,
+ RdRn = Rd | Rn,
+ RaRnRm = Ra | Rn | Rm,
+ RdRnRm = Rd | Rn | Rm
+ }
+
+ public static int GetImmShl(AOpCodeSimdShImm Op)
+ {
+ return Op.Imm - (8 << Op.Size);
+ }
+
+ public static int GetImmShr(AOpCodeSimdShImm Op)
+ {
+ return (8 << (Op.Size + 1)) - Op.Imm;
+ }
+
+ public static void EmitUnaryMathCall(AILEmitterCtx Context, string Name)
+ {
+ IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
+
+ MethodInfo MthdInfo;
+
+ if (Op.Size == 0)
+ {
+ MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) });
+ }
+ else if (Op.Size == 1)
+ {
+ MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) });
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+
+ Context.EmitCall(MthdInfo);
+ }
+
+ public static void EmitBinaryMathCall(AILEmitterCtx Context, string Name)
+ {
+ IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
+
+ 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);
+ }
+
+ public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOp(Context, Emit, OperFlags.Rn, true);
+ }
+
+ public static void EmitScalarBinaryOpSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOp(Context, Emit, OperFlags.RnRm, true);
+ }
+
+ public static void EmitScalarUnaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOp(Context, Emit, OperFlags.Rn, false);
+ }
+
+ public static void EmitScalarBinaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOp(Context, Emit, OperFlags.RnRm, false);
+ }
+
+ public static void EmitScalarTernaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOp(Context, Emit, OperFlags.RdRnRm, false);
+ }
+
+ public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ if (Opers.HasFlag(OperFlags.Rd))
+ {
+ EmitVectorExtract(Context, Op.Rd, 0, Op.Size, Signed);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rn))
+ {
+ EmitVectorExtract(Context, Op.Rn, 0, Op.Size, Signed);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rm))
+ {
+ EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed);
+ }
+
+ Emit();
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void EmitScalarUnaryOpF(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOpF(Context, Emit, OperFlags.Rn);
+ }
+
+ public static void EmitScalarBinaryOpF(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOpF(Context, Emit, OperFlags.RnRm);
+ }
+
+ public static void EmitScalarTernaryRaOpF(AILEmitterCtx Context, Action Emit)
+ {
+ EmitScalarOpF(Context, Emit, OperFlags.RaRnRm);
+ }
+
+ public static void EmitScalarOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int SizeF = Op.Size & 1;
+
+ if (Opers.HasFlag(OperFlags.Ra))
+ {
+ EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Ra, 0, SizeF);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rn))
+ {
+ EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rm))
+ {
+ EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, 0, SizeF);
+ }
+
+ Emit();
+
+ EmitScalarSetF(Context, Op.Rd, SizeF);
+ }
+
+ public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOpF(Context, Emit, OperFlags.RnRm);
+ }
+
+ public static void EmitVectorTernaryOpF(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOpF(Context, Emit, OperFlags.RdRnRm);
+ }
+
+ public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit)
+ {
+ AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
+
+ EmitVectorOpF(Context, Emit, OperFlags.RnRm, Op.Index);
+ }
+
+ public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit)
+ {
+ AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
+
+ EmitVectorOpF(Context, Emit, OperFlags.RdRnRm, Op.Index);
+ }
+
+ public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers, int Elem = -1)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ int SizeF = Op.Size & 1;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++)
+ {
+ if (Opers.HasFlag(OperFlags.Rd))
+ {
+ EmitVectorExtractF(Context, Op.Rd, Index, SizeF);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rn))
+ {
+ EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rm))
+ {
+ if (Elem != -1)
+ {
+ EmitVectorExtractF(Context, Op.Rm, Elem, SizeF);
+ }
+ else
+ {
+ EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
+ }
+ }
+
+ Emit();
+
+ EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void EmitVectorUnaryOpSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOp(Context, Emit, OperFlags.Rn, true);
+ }
+
+ public static void EmitVectorBinaryOpSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOp(Context, Emit, OperFlags.RnRm, true);
+ }
+
+ public static void EmitVectorUnaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOp(Context, Emit, OperFlags.Rn, false);
+ }
+
+ public static void EmitVectorBinaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOp(Context, Emit, OperFlags.RnRm, false);
+ }
+
+ public static void EmitVectorTernaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false);
+ }
+
+ public static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ if (Opers.HasFlag(OperFlags.Rd))
+ {
+ EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rn))
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
+ }
+
+ if (Opers.HasFlag(OperFlags.Rm))
+ {
+ EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
+ }
+
+ Emit();
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorImmOp(Context, Emit, false);
+ }
+
+ public static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorImmOp(Context, Emit, true);
+ }
+
+ public static void EmitVectorImmOp(AILEmitterCtx Context, Action Emit, bool Binary)
+ {
+ AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ if (Binary)
+ {
+ EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
+ }
+
+ Context.EmitLdc_I8(Op.Imm);
+
+ Emit();
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void EmitVectorWidenBinaryOpSx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorWidenBinaryOp(Context, Emit, true);
+ }
+
+ public static void EmitVectorWidenBinaryOpZx(AILEmitterCtx Context, Action Emit)
+ {
+ EmitVectorWidenBinaryOp(Context, Emit, false);
+ }
+
+ public static void EmitVectorWidenBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ int Elems = 8 >> Op.Size;
+
+ int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
+ EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed);
+
+ Emit();
+
+ EmitVectorInsertTmp(Context, Index, Op.Size + 1);
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitStvec(Op.Rd);
+ }
+
+ public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size)
+ {
+ EmitVectorZeroAll(Context, Reg);
+ EmitVectorInsert(Context, Reg, 0, Size);
+ }
+
+ public static void EmitScalarSetF(AILEmitterCtx Context, int Reg, int Size)
+ {
+ EmitVectorZeroAll(Context, Reg);
+ EmitVectorInsertF(Context, Reg, 0, Size);
+ }
+
+ public static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size)
+ {
+ EmitVectorExtract(Context, Reg, Index, Size, true);
+ }
+
+ public static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size)
+ {
+ EmitVectorExtract(Context, Reg, Index, Size, false);
+ }
+
+ public static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed)
+ {
+ if (Size < 0 || Size > 3)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
+
+ Context.EmitLdvec(Reg);
+ Context.EmitLdc_I4(Index);
+ Context.EmitLdc_I4(Size);
+
+ ASoftFallback.EmitCall(Context, Signed
+ ? nameof(ASoftFallback.VectorExtractIntSx)
+ : nameof(ASoftFallback.VectorExtractIntZx));
+ }
+
+ public static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size)
+ {
+ Context.EmitLdvec(Reg);
+ Context.EmitLdc_I4(Index);
+
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle));
+ }
+ else if (Size == 1)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+ }
+
+ public static void EmitVectorZeroAll(AILEmitterCtx Context, int Rd)
+ {
+ EmitVectorZeroLower(Context, Rd);
+ EmitVectorZeroUpper(Context, Rd);
+ }
+
+ public static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd)
+ {
+ EmitVectorInsert(Context, Rd, 0, 3, 0);
+ }
+
+ public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd)
+ {
+ EmitVectorInsert(Context, Rd, 1, 3, 0);
+ }
+
+ public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size)
+ {
+ if (Size < 0 || Size > 3)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.EmitLdvec(Reg);
+ Context.EmitLdc_I4(Index);
+ Context.EmitLdc_I4(Size);
+
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
+
+ Context.EmitStvec(Reg);
+ }
+
+ public static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size)
+ {
+ if (Size < 0 || Size > 3)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitLdc_I4(Index);
+ Context.EmitLdc_I4(Size);
+
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
+
+ Context.EmitStvectmp();
+ }
+
+ public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value)
+ {
+ if (Size < 0 || Size > 3)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.EmitLdc_I8(Value);
+ Context.EmitLdvec(Reg);
+ Context.EmitLdc_I4(Index);
+ Context.EmitLdc_I4(Size);
+
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
+
+ Context.EmitStvec(Reg);
+ }
+
+ public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size)
+ {
+ Context.EmitLdvec(Reg);
+ Context.EmitLdc_I4(Index);
+
+ if (Size == 0)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle));
+ }
+ else if (Size == 1)
+ {
+ ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble));
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(Size));
+ }
+
+ Context.EmitStvec(Reg);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs
new file mode 100644
index 00000000..ea4b17b3
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdLogical.cs
@@ -0,0 +1,69 @@
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void And_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.And));
+ }
+
+ public static void Bic_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () =>
+ {
+ Context.Emit(OpCodes.Not);
+ Context.Emit(OpCodes.And);
+ });
+ }
+
+ public static void Bic_Vi(AILEmitterCtx Context)
+ {
+ EmitVectorImmBinaryOp(Context, () =>
+ {
+ Context.Emit(OpCodes.Not);
+ Context.Emit(OpCodes.And);
+ });
+ }
+
+ public static void Bsl_V(AILEmitterCtx Context)
+ {
+ EmitVectorTernaryOpZx(Context, () =>
+ {
+ Context.EmitSttmp();
+ Context.EmitLdtmp();
+
+ Context.Emit(OpCodes.Xor);
+ Context.Emit(OpCodes.And);
+
+ Context.EmitLdtmp();
+
+ Context.Emit(OpCodes.Xor);
+ });
+ }
+
+ public static void Eor_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Xor));
+ }
+
+ public static void Not_V(AILEmitterCtx Context)
+ {
+ EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not));
+ }
+
+ public static void Orr_V(AILEmitterCtx Context)
+ {
+ EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Or));
+ }
+
+ public static void Orr_Vi(AILEmitterCtx Context)
+ {
+ EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs
new file mode 100644
index 00000000..d75db619
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdMemory.cs
@@ -0,0 +1,155 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitMemoryHelper;
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void Ld__Vms(AILEmitterCtx Context)
+ {
+ EmitSimdMemMs(Context, IsLoad: true);
+ }
+
+ public static void Ld__Vss(AILEmitterCtx Context)
+ {
+ EmitSimdMemSs(Context, IsLoad: true);
+ }
+
+ public static void St__Vms(AILEmitterCtx Context)
+ {
+ EmitSimdMemMs(Context, IsLoad: false);
+ }
+
+ public static void St__Vss(AILEmitterCtx Context)
+ {
+ EmitSimdMemSs(Context, IsLoad: false);
+ }
+
+ private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
+ {
+ AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
+
+ int Offset = 0;
+
+ for (int Rep = 0; Rep < Op.Reps; Rep++)
+ for (int Elem = 0; Elem < Op.Elems; Elem++)
+ for (int SElem = 0; SElem < Op.SElems; SElem++)
+ {
+ int Rtt = (Op.Rt + Rep + SElem) & 0x1f;
+
+ if (IsLoad)
+ {
+ Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+ Context.EmitLdint(Op.Rn);
+ Context.EmitLdc_I8(Offset);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitReadZxCall(Context, Op.Size);
+
+ EmitVectorInsert(Context, Rtt, Elem, Op.Size);
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1)
+ {
+ EmitVectorZeroUpper(Context, Rtt);
+ }
+ }
+ else
+ {
+ Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+ Context.EmitLdint(Op.Rn);
+ Context.EmitLdc_I8(Offset);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitVectorExtractZx(Context, Rtt, Elem, Op.Size);
+
+ EmitWriteCall(Context, Op.Size);
+ }
+
+ Offset += 1 << Op.Size;
+ }
+
+ if (Op.WBack)
+ {
+ EmitSimdMemWBack(Context, Offset);
+ }
+ }
+
+ private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
+ {
+ AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
+
+ //TODO: Replicate mode.
+
+ int Offset = 0;
+
+ for (int SElem = 0; SElem < Op.SElems; SElem++)
+ {
+ int Rt = (Op.Rt + SElem) & 0x1f;
+
+ if (IsLoad)
+ {
+ Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+ Context.EmitLdint(Op.Rn);
+ Context.EmitLdc_I8(Offset);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitReadZxCall(Context, Op.Size);
+
+ EmitVectorInsert(Context, Rt, Op.Index, Op.Size);
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Rt);
+ }
+ }
+ else
+ {
+ Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
+ Context.EmitLdint(Op.Rn);
+ Context.EmitLdc_I8(Offset);
+
+ Context.Emit(OpCodes.Add);
+
+ EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size);
+
+ EmitWriteCall(Context, Op.Size);
+ }
+
+ Offset += 1 << Op.Size;
+ }
+
+ if (Op.WBack)
+ {
+ EmitSimdMemWBack(Context, Offset);
+ }
+ }
+
+ private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset)
+ {
+ AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp;
+
+ Context.EmitLdint(Op.Rn);
+
+ if (Op.Rm != ARegisters.ZRIndex)
+ {
+ Context.EmitLdint(Op.Rm);
+ }
+ else
+ {
+ Context.EmitLdc_I8(Offset);
+ }
+
+ Context.Emit(OpCodes.Add);
+
+ Context.EmitStint(Op.Rn);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs
new file mode 100644
index 00000000..87d57e96
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdMove.cs
@@ -0,0 +1,275 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ public static void Dup_Gp(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ Context.EmitLdintzr(Op.Rn);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ public static void Dup_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size);
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Dup_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ 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);
+
+ EmitVectorExtractF(Context, Op.Rm, 0, Op.Size);
+
+ Context.Emit(OpCodes.Br_S, LblEnd);
+
+ Context.MarkLabel(LblTrue);
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ Context.MarkLabel(LblEnd);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Fmov_Ftoi(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, 3);
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ public static void Fmov_Ftoi1(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, 1, 3);
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ public static void Fmov_Itof(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ Context.EmitLdintzr(Op.Rn);
+
+ EmitScalarSet(Context, Op.Rd, 3);
+ }
+
+ public static void Fmov_Itof1(AILEmitterCtx Context)
+ {
+ AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
+
+ Context.EmitLdintzr(Op.Rn);
+
+ EmitVectorInsert(Context, Op.Rd, 1, 3);
+ }
+
+ public static void Fmov_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
+
+ EmitScalarSetF(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Fmov_Si(AILEmitterCtx Context)
+ {
+ AOpCodeSimdFmov Op = (AOpCodeSimdFmov)Context.CurrOp;
+
+ Context.EmitLdc_I8(Op.Imm);
+
+ EmitScalarSet(Context, Op.Rd, Op.Size + 2);
+ }
+
+ public static void Fmov_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
+
+ for (int Index = 0; Index < (4 >> Op.Size); Index++)
+ {
+ Context.EmitLdc_I8(Op.Imm);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size + 2);
+ }
+ }
+
+ public static void Ins_Gp(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ Context.EmitLdintzr(Op.Rn);
+
+ EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size);
+ }
+
+ public static void Ins_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, Op.SrcIndex, Op.Size);
+
+ EmitVectorInsert(Context, Op.Rd, Op.DstIndex, Op.Size);
+ }
+
+ public static void Movi_V(AILEmitterCtx Context)
+ {
+ EmitVectorImmUnaryOp(Context, () => { });
+ }
+
+ public static void Mvni_V(AILEmitterCtx Context)
+ {
+ EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not));
+ }
+
+ public static void Tbl_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp;
+
+ Context.EmitLdvec(Op.Rm);
+
+ for (int Index = 0; Index < Op.Size; Index++)
+ {
+ Context.EmitLdvec((Op.Rn + Index) & 0x1f);
+ }
+
+ switch (Op.Size)
+ {
+ case 1: ASoftFallback.EmitCall(Context,
+ nameof(ASoftFallback.Tbl1_V64),
+ nameof(ASoftFallback.Tbl1_V128)); break;
+
+ case 2: ASoftFallback.EmitCall(Context,
+ nameof(ASoftFallback.Tbl2_V64),
+ nameof(ASoftFallback.Tbl2_V128)); break;
+
+ case 3: ASoftFallback.EmitCall(Context,
+ nameof(ASoftFallback.Tbl3_V64),
+ nameof(ASoftFallback.Tbl3_V128)); break;
+
+ case 4: ASoftFallback.EmitCall(Context,
+ nameof(ASoftFallback.Tbl4_V64),
+ nameof(ASoftFallback.Tbl4_V128)); break;
+
+ default: throw new InvalidOperationException();
+ }
+
+ Context.EmitStvec(Op.Rd);
+ }
+
+ public static void Umov_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, Op.DstIndex, Op.Size);
+
+ Context.EmitStintzr(Op.Rd);
+ }
+
+ public static void Uzp1_V(AILEmitterCtx Context)
+ {
+ EmitVectorUnzip(Context, Part: 0);
+ }
+
+ public static void Uzp2_V(AILEmitterCtx Context)
+ {
+ EmitVectorUnzip(Context, Part: 1);
+ }
+
+ public static void Xtn_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int Elems = 8 >> Op.Size;
+
+ int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
+
+ EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
+ }
+
+ if (Part == 0)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ private static void EmitVectorUnzip(AILEmitterCtx Context, int Part)
+ {
+ AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ int Elems = Bytes >> Op.Size;
+ int Half = Elems >> 1;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ int Elem = Part + ((Index & (Half - 1)) << 1);
+
+ EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size);
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs
new file mode 100644
index 00000000..16564234
--- /dev/null
+++ b/Ryujinx/Cpu/Instruction/AInstEmitSimdShift.cs
@@ -0,0 +1,306 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instruction.AInstEmitSimdHelper;
+
+namespace ChocolArm64.Instruction
+{
+ static partial class AInstEmit
+ {
+ [Flags]
+ private enum ShrFlags
+ {
+ None = 0,
+ Signed = 1 << 0,
+ Rounding = 1 << 1,
+ Accumulate = 1 << 2
+ }
+
+ public static void Shl_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
+
+ Context.EmitLdc_I4(GetImmShl(Op));
+
+ Context.Emit(OpCodes.Shl);
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Shl_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = Op.Imm - (8 << Op.Size);
+
+ EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
+ }
+
+ public static void Shrn_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = (8 << (Op.Size + 1)) - Op.Imm;
+
+ EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift);
+ }
+
+ public static void Sshl_V(AILEmitterCtx Context)
+ {
+ EmitVectorShl(Context, Signed: true);
+ }
+
+ public static void Sshll_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = Op.Imm - (8 << Op.Size);
+
+ EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift);
+ }
+
+ public static void Sshr_S(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size);
+
+ Context.EmitLdc_I4(GetImmShr(Op));
+
+ Context.Emit(OpCodes.Shr);
+
+ EmitScalarSet(Context, Op.Rd, Op.Size);
+ }
+
+ public static void Sshr_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = (8 << (Op.Size + 1)) - Op.Imm;
+
+ EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift);
+ }
+
+ public static void Ushl_V(AILEmitterCtx Context)
+ {
+ EmitVectorShl(Context, Signed: false);
+ }
+
+ public static void Ushll_V(AILEmitterCtx Context)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = Op.Imm - (8 << Op.Size);
+
+ EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
+ }
+
+ public static void Ushr_V(AILEmitterCtx Context)
+ {
+ EmitVectorShr(Context, ShrFlags.None);
+ }
+
+ public static void Usra_V(AILEmitterCtx Context)
+ {
+ EmitVectorShr(Context, ShrFlags.Accumulate);
+ }
+
+ private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
+ {
+ //This instruction shifts the value on vector A by the number of bits
+ //specified on the signed, lower 8 bits of vector B. If the shift value
+ //is greater or equal to the data size of each lane, then the result is zero.
+ //Additionally, negative shifts produces right shifts by the negated shift value.
+ AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
+
+ int MaxShift = 8 << Op.Size;
+
+ Action Emit = () =>
+ {
+ AILLabel LblShl = new AILLabel();
+ AILLabel LblZero = new AILLabel();
+ AILLabel LblEnd = new AILLabel();
+
+ void EmitShift(OpCode ILOp)
+ {
+ Context.Emit(OpCodes.Dup);
+
+ Context.EmitLdc_I4(MaxShift);
+
+ Context.Emit(OpCodes.Bge_S, LblZero);
+ Context.Emit(ILOp);
+ Context.Emit(OpCodes.Br_S, LblEnd);
+ }
+
+ Context.Emit(OpCodes.Conv_I1);
+ Context.Emit(OpCodes.Dup);
+
+ Context.EmitLdc_I4(0);
+
+ Context.Emit(OpCodes.Bge_S, LblShl);
+ Context.Emit(OpCodes.Neg);
+
+ EmitShift(Signed
+ ? OpCodes.Shr
+ : OpCodes.Shr_Un);
+
+ Context.MarkLabel(LblShl);
+
+ EmitShift(OpCodes.Shl);
+
+ Context.MarkLabel(LblZero);
+
+ Context.Emit(OpCodes.Pop);
+ Context.Emit(OpCodes.Pop);
+
+ Context.EmitLdc_I8(0);
+
+ Context.MarkLabel(LblEnd);
+ };
+
+ if (Signed)
+ {
+ EmitVectorBinaryOpSx(Context, Emit);
+ }
+ else
+ {
+ EmitVectorBinaryOpZx(Context, Emit);
+ }
+ }
+
+ private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Shift = (8 << (Op.Size + 1)) - Op.Imm;
+
+ if (Flags.HasFlag(ShrFlags.Accumulate))
+ {
+ Action Emit = () =>
+ {
+ Context.EmitLdc_I4(Shift);
+
+ Context.Emit(OpCodes.Shr_Un);
+ Context.Emit(OpCodes.Add);
+ };
+
+ EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
+ }
+ else
+ {
+ EmitVectorUnaryOpZx(Context, () =>
+ {
+ Context.EmitLdc_I4(Shift);
+
+ Context.Emit(OpCodes.Shr_Un);
+ });
+ }
+ }
+
+ private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmBinaryOp(Context, Emit, Imm, true);
+ }
+
+ private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmBinaryOp(Context, Emit, Imm, false);
+ }
+
+ private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Bytes = Context.CurrOp.GetBitsCount() >> 3;
+
+ for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
+
+ Context.EmitLdc_I4(Imm);
+
+ Emit();
+
+ EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
+ }
+
+ if (Op.RegisterSize == ARegisterSize.SIMD64)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true);
+ }
+
+ private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false);
+ }
+
+ private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Elems = 8 >> Op.Size;
+
+ int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
+
+ Context.EmitLdc_I4(Imm);
+
+ Emit();
+
+ EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
+ }
+
+ if (Part == 0)
+ {
+ EmitVectorZeroUpper(Context, Op.Rd);
+ }
+ }
+
+ private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true);
+ }
+
+ private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
+ {
+ EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false);
+ }
+
+ private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
+ {
+ AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
+
+ int Elems = 8 >> Op.Size;
+
+ int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
+
+ for (int Index = 0; Index < Elems; Index++)
+ {
+ EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
+
+ Context.EmitLdc_I4(Imm);
+
+ Emit();
+
+ EmitVectorInsertTmp(Context, Index, Op.Size + 1);
+ }
+
+ Context.EmitLdvectmp();
+ Context.EmitStvec(Op.Rd);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Instruction/ASoftFallback.cs b/Ryujinx/Cpu/Instruction/ASoftFallback.cs
index a8df0107..b70d0b4f 100644
--- a/Ryujinx/Cpu/Instruction/ASoftFallback.cs
+++ b/Ryujinx/Cpu/Instruction/ASoftFallback.cs
@@ -1,6 +1,7 @@
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
+using System.Runtime.CompilerServices;
namespace ChocolArm64.Instruction
{
@@ -97,142 +98,62 @@ namespace ChocolArm64.Instruction
throw new ArgumentException(nameof(Size));
}
- public static int SatSingleToInt32(float Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SatF32ToS32(float Value)
{
- if (FBits != 0) Value *= MathF.Pow(2, FBits);
-
return Value > int.MaxValue ? int.MaxValue :
Value < int.MinValue ? int.MinValue : (int)Value;
}
- public static long SatSingleToInt64(float Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long SatF32ToS64(float Value)
{
- if (FBits != 0) Value *= MathF.Pow(2, FBits);
-
return Value > long.MaxValue ? long.MaxValue :
Value < long.MinValue ? long.MinValue : (long)Value;
}
- public static uint SatSingleToUInt32(float Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint SatF32ToU32(float Value)
{
- if (FBits != 0) Value *= MathF.Pow(2, FBits);
-
return Value > uint.MaxValue ? uint.MaxValue :
Value < uint.MinValue ? uint.MinValue : (uint)Value;
}
- public static ulong SatSingleToUInt64(float Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong SatF32ToU64(float Value)
{
- if (FBits != 0) Value *= MathF.Pow(2, FBits);
-
return Value > ulong.MaxValue ? ulong.MaxValue :
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
}
- public static int SatDoubleToInt32(double Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SatF64ToS32(double Value)
{
- if (FBits != 0) Value *= Math.Pow(2, FBits);
-
return Value > int.MaxValue ? int.MaxValue :
Value < int.MinValue ? int.MinValue : (int)Value;
}
- public static long SatDoubleToInt64(double Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static long SatF64ToS64(double Value)
{
- if (FBits != 0) Value *= Math.Pow(2, FBits);
-
return Value > long.MaxValue ? long.MaxValue :
Value < long.MinValue ? long.MinValue : (long)Value;
}
- public static uint SatDoubleToUInt32(double Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint SatF64ToU32(double Value)
{
- if (FBits != 0) Value *= Math.Pow(2, FBits);
-
return Value > uint.MaxValue ? uint.MaxValue :
Value < uint.MinValue ? uint.MinValue : (uint)Value;
}
- public static ulong SatDoubleToUInt64(double Value, int FBits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ulong SatF64ToU64(double Value)
{
- if (FBits != 0) Value *= Math.Pow(2, FBits);
-
return Value > ulong.MaxValue ? ulong.MaxValue :
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
}
- public static float Int32ToSingle(int Value, int FBits)
- {
- float ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static float Int64ToSingle(long Value, int FBits)
- {
- float ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static float UInt32ToSingle(uint Value, int FBits)
- {
- float ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static float UInt64ToSingle(ulong Value, int FBits)
- {
- float ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / MathF.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static double Int32ToDouble(int Value, int FBits)
- {
- double ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static double Int64ToDouble(long Value, int FBits)
- {
- double ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static double UInt32ToDouble(uint Value, int FBits)
- {
- double ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits);
-
- return ValueF;
- }
-
- public static double UInt64ToDouble(ulong Value, int FBits)
- {
- double ValueF = Value;
-
- if (FBits != 0) ValueF *= 1 / Math.Pow(2, FBits);
-
- return ValueF;
- }
-
public static ulong SMulHi128(ulong LHS, ulong RHS)
{
long LLo = (uint)(LHS >> 0);
@@ -269,14 +190,6 @@ namespace ChocolArm64.Instruction
ulong ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry;
return ResHi;
- }
-
- public static AVec Addp_S(AVec Vector, int Size)
- {
- ulong Low = ExtractVec(Vector, 0, Size);
- ulong High = ExtractVec(Vector, 1, Size);
-
- return InsertVec(new AVec(), 0, Size, Low + High);
}
public static int CountSetBits8(byte Value)
@@ -287,38 +200,6 @@ namespace ChocolArm64.Instruction
(Value >> 6) & 1 + (Value >> 7);
}
- public static AVec Dup_Gp64(ulong Value, int Size)
- {
- return Dup_Gp(Value, Size, 8);
- }
-
- public static AVec Dup_Gp128(ulong Value, int Size)
- {
- return Dup_Gp(Value, Size, 16);
- }
-
- private static AVec Dup_Gp(ulong Value, int Size, int Bytes)
- {
- AVec Res = new AVec();
-
- for (int Index = 0; Index < (Bytes >> Size); Index++)
- {
- Res = InsertVec(Res, Index, Size, Value);
- }
-
- return Res;
- }
-
- public static AVec Dup_S(AVec Vector, int Elem, int Size)
- {
- return InsertVec(new AVec(), 0, Size, ExtractVec(Vector, Elem, Size));
- }
-
- public static AVec Fmov_S(ulong Value, int Elem, int Size)
- {
- return InsertVec(new AVec(), Elem, Size, Value);
- }
-
public static AVec Tbl1_V64(AVec Vector, AVec Tb0)
{
return Tbl(Vector, 8, Tb0);
@@ -368,27 +249,27 @@ namespace ChocolArm64.Instruction
for (int Index = 0; Index < Tb.Length; Index++)
for (int Index2 = 0; Index2 < 16; Index2++)
{
- Table[Index * 16 + Index2] = (byte)ExtractVec(Tb[Index], Index2, 0);
+ Table[Index * 16 + Index2] = (byte)VectorExtractIntZx(Tb[Index], Index2, 0);
}
for (int Index = 0; Index < Bytes; Index++)
{
- byte TblIdx = (byte)ExtractVec(Vector, Index, 0);
+ byte TblIdx = (byte)VectorExtractIntZx(Vector, Index, 0);
if (TblIdx < Table.Length)
{
- Res = InsertVec(Res, Index, 0, Table[TblIdx]);
+ Res = VectorInsertInt(Table[TblIdx], Res, Index, 0);
}
}
return Res;
}
- public static ulong ExtractVec(AVec Vector, int Index, int Size)
+ public static ulong VectorExtractIntZx(AVec Vector, int Index, int Size)
{
switch (Size)
{
- case 0: return Vector.ExtractByte(Index);
+ case 0: return Vector.ExtractByte (Index);
case 1: return Vector.ExtractUInt16(Index);
case 2: return Vector.ExtractUInt32(Index);
case 3: return Vector.ExtractUInt64(Index);
@@ -397,14 +278,14 @@ namespace ChocolArm64.Instruction
throw new ArgumentOutOfRangeException(nameof(Size));
}
- public static long ExtractSVec(AVec Vector, int Index, int Size)
+ public static long VectorExtractIntSx(AVec Vector, int Index, int Size)
{
switch (Size)
{
- case 0: return (sbyte)Vector.ExtractByte(Index);
+ case 0: return (sbyte)Vector.ExtractByte (Index);
case 1: return (short)Vector.ExtractUInt16(Index);
- case 2: return (int)Vector.ExtractUInt32(Index);
- case 3: return (long)Vector.ExtractUInt64(Index);
+ case 2: return (int)Vector.ExtractUInt32(Index);
+ case 3: return (long)Vector.ExtractUInt64(Index);
}
throw new ArgumentOutOfRangeException(nameof(Size));
@@ -442,31 +323,5 @@ namespace ChocolArm64.Instruction
throw new ArgumentOutOfRangeException(nameof(Size));
}
-
- public static AVec InsertVec(AVec Vector, int Index, int Size, ulong Value)
- {
- switch (Size)
- {
- case 0: return AVec.InsertByte(Vector, Index, (byte)Value);
- case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value);
- case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value);
- case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value);
- }
-
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- public static AVec InsertSVec(AVec Vector, int Index, int Size, long Value)
- {
- switch (Size)
- {
- case 0: return AVec.InsertByte(Vector, Index, (byte)Value);
- case 1: return AVec.InsertUInt16(Vector, Index, (ushort)Value);
- case 2: return AVec.InsertUInt32(Vector, Index, (uint)Value);
- case 3: return AVec.InsertUInt64(Vector, Index, (ulong)Value);
- }
-
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
}
} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Memory/AMemory.cs b/Ryujinx/Cpu/Memory/AMemory.cs
index ead99f3f..52f76e2e 100644
--- a/Ryujinx/Cpu/Memory/AMemory.cs
+++ b/Ryujinx/Cpu/Memory/AMemory.cs
@@ -174,6 +174,42 @@ namespace ChocolArm64.Memory
return *((ulong*)(RamPtr + (uint)Position));
}
+ public AVec ReadVector8(long Position)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
+ return new AVec() { B0 = ReadByte(Position) };
+ }
+
+ public AVec ReadVector16(long Position)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
+ return new AVec() { H0 = ReadUInt16(Position) };
+ }
+
+ public AVec ReadVector32(long Position)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
+ return new AVec() { W0 = ReadUInt32(Position) };
+ }
+
+ public AVec ReadVector64(long Position)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Read);
+#endif
+
+ return new AVec() { X0 = ReadUInt64(Position) };
+ }
+
public AVec ReadVector128(long Position)
{
#if DEBUG
@@ -228,6 +264,42 @@ namespace ChocolArm64.Memory
*((ulong*)(RamPtr + (uint)Position)) = Value;
}
+ public void WriteVector8(long Position, AVec Value)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
+ WriteByte(Position, Value.B0);
+ }
+
+ public void WriteVector16(long Position, AVec Value)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
+ WriteUInt16(Position, Value.H0);
+ }
+
+ public void WriteVector32(long Position, AVec Value)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
+ WriteUInt32(Position, Value.W0);
+ }
+
+ public void WriteVector64(long Position, AVec Value)
+ {
+#if DEBUG
+ EnsureAccessIsValid(Position, AMemoryPerm.Write);
+#endif
+
+ WriteUInt64(Position, Value.X0);
+ }
+
public void WriteVector128(long Position, AVec Value)
{
#if DEBUG
diff --git a/Ryujinx/Cpu/Translation/AILConv.cs b/Ryujinx/Cpu/Translation/AILConv.cs
deleted file mode 100644
index 8969dc4e..00000000
--- a/Ryujinx/Cpu/Translation/AILConv.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using ChocolArm64.State;
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace ChocolArm64.Translation
-{
- static class AILConv
- {
- public static void EmitConv(AILEmitter Context, Type SrcType, Type TgtType)
- {
- if (SrcType == TgtType)
- {
- //If both types are equal we don't need to cast anything.
- return;
- }
-
- if (SrcType.IsPrimitive)
- {
- if (TgtType == typeof(byte))
- {
- Context.Generator.Emit(OpCodes.Conv_U1);
- }
- else if (TgtType == typeof(ushort))
- {
- Context.Generator.Emit(OpCodes.Conv_U2);
- }
- else if (TgtType == typeof(uint))
- {
- Context.Generator.Emit(OpCodes.Conv_U4);
- }
- else if (TgtType == typeof(ulong))
- {
- Context.Generator.Emit(OpCodes.Conv_U8);
- }
- else if (TgtType == typeof(float))
- {
- Context.Generator.Emit(OpCodes.Conv_R4);
- }
- else if (TgtType == typeof(double))
- {
- Context.Generator.Emit(OpCodes.Conv_R8);
- }
- else if (TgtType == typeof(AVec))
- {
- EmitMakeVec(Context, SrcType);
- }
- else
- {
- throw new ArgumentException(nameof(TgtType));
- }
- }
- else if (SrcType == typeof(AVec))
- {
- if (TgtType == typeof(float))
- {
- EmitScalarLdfld(Context, nameof(AVec.S0));
- }
- else if (TgtType == typeof(double))
- {
- EmitScalarLdfld(Context, nameof(AVec.D0));
- }
- else if (TgtType == typeof(byte))
- {
- EmitScalarLdfld(Context, nameof(AVec.B0));
- }
- else if (TgtType == typeof(ushort))
- {
- EmitScalarLdfld(Context, nameof(AVec.H0));
- }
- else if (TgtType == typeof(uint))
- {
- EmitScalarLdfld(Context, nameof(AVec.W0));
- }
- else if (TgtType == typeof(ulong))
- {
- EmitScalarLdfld(Context, nameof(AVec.X0));
- }
- else
- {
- throw new ArgumentException(nameof(TgtType));
- }
- }
- else
- {
- throw new ArgumentException(nameof(SrcType));
- }
- }
-
- private static void EmitScalarLdfld(AILEmitter Context,string FldName)
- {
- Context.Generator.Emit(OpCodes.Ldfld, typeof(AVec).GetField(FldName));
- }
-
- private static void EmitMakeVec(AILEmitter Context, Type SrcType)
- {
- string MthdName = nameof(MakeScalar);
-
- Type[] MthdTypes = new Type[] { SrcType };
-
- MethodInfo MthdInfo = typeof(AILConv).GetMethod(MthdName, MthdTypes);
-
- Context.Generator.Emit(OpCodes.Call, MthdInfo);
- }
-
- public static AVec MakeScalar(byte Value) => new AVec { B0 = Value };
- public static AVec MakeScalar(ushort Value) => new AVec { H0 = Value };
- public static AVec MakeScalar(uint Value) => new AVec { W0 = Value };
- public static AVec MakeScalar(float Value) => new AVec { S0 = Value };
- public static AVec MakeScalar(ulong Value) => new AVec { X0 = Value };
- public static AVec MakeScalar(double Value) => new AVec { D0 = Value };
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Translation/AILEmitter.cs b/Ryujinx/Cpu/Translation/AILEmitter.cs
index 0619149c..8f6e1210 100644
--- a/Ryujinx/Cpu/Translation/AILEmitter.cs
+++ b/Ryujinx/Cpu/Translation/AILEmitter.cs
@@ -86,9 +86,6 @@ namespace ChocolArm64.Translation
ARegister Reg = Subroutine.Params[Index];
Generator.EmitLdarg(Index + ParamsStart);
-
- AILConv.EmitConv(this, GetFieldType(Reg.Type), GetLocalType(Reg));
-
Generator.EmitStloc(GetLocalIndex(Reg));
}
}
diff --git a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
index 4c4841c5..619ad3ae 100644
--- a/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
+++ b/Ryujinx/Cpu/Translation/AILEmitterCtx.cs
@@ -150,8 +150,8 @@ namespace ChocolArm64.Translation
if (LastCmpOp != null && LastFlagOp == LastCmpOp && BranchOps.ContainsKey(Cond))
{
- Ldloc(Tmp3Index, AIoType.Int, GetIntType(LastCmpOp));
- Ldloc(Tmp4Index, AIoType.Int, GetIntType(LastCmpOp));
+ Ldloc(Tmp3Index, AIoType.Int, LastCmpOp.RegisterSize);
+ Ldloc(Tmp4Index, AIoType.Int, LastCmpOp.RegisterSize);
if (LastCmpOp.Emitter == AInstEmit.Adds)
{
@@ -353,12 +353,6 @@ namespace ChocolArm64.Translation
public void EmitLdvec(int Index) => Ldloc(Index, AIoType.Vector);
public void EmitStvec(int Index) => Stloc(Index, AIoType.Vector);
- public void EmitLdvecsi(int Index) => Ldloc(Index, AIoType.VectorI);
- public void EmitStvecsi(int Index) => Stloc(Index, AIoType.VectorI);
-
- public void EmitLdvecsf(int Index) => Ldloc(Index, AIoType.VectorF);
- public void EmitStvecsf(int Index) => Stloc(Index, AIoType.VectorF);
-
public void EmitLdflg(int Index) => Ldloc(Index, AIoType.Flag);
public void EmitStflg(int Index)
{
@@ -369,107 +363,17 @@ namespace ChocolArm64.Translation
private void Ldloc(int Index, AIoType IoType)
{
- ILBlock.Add(new AILOpCodeLoad(Index, IoType, GetOperType(IoType)));
+ ILBlock.Add(new AILOpCodeLoad(Index, IoType, CurrOp.RegisterSize));
}
- private void Ldloc(int Index, AIoType IoType, Type Type)
+ private void Ldloc(int Index, AIoType IoType, ARegisterSize RegisterSize)
{
- ILBlock.Add(new AILOpCodeLoad(Index, IoType, Type));
+ ILBlock.Add(new AILOpCodeLoad(Index, IoType, RegisterSize));
}
private void Stloc(int Index, AIoType IoType)
{
- ILBlock.Add(new AILOpCodeStore(Index, IoType, GetOutOperType(IoType)));
- }
-
- private Type GetOutOperType(AIoType IoType)
- {
- //This instruction is used to convert between floating point
- //types, so the input and output types are different.
- if (CurrOp.Emitter == AInstEmit.Fcvt_S)
- {
- return GetFloatType(((AOpCodeSimd)CurrOp).Opc);
- }
- else
- {
- return GetOperType(IoType);
- }
- }
-
- private Type GetOperType(AIoType IoType)
- {
- switch (IoType & AIoType.Mask)
- {
- case AIoType.Flag: return typeof(bool);
- case AIoType.Int: return GetIntType(CurrOp);
- case AIoType.Vector: return GetVecType(CurrOp, IoType);
- }
-
- throw new ArgumentException(nameof(IoType));
- }
-
- private Type GetIntType(AOpCode OpCode)
- {
- //Always default to 64-bits.
- return OpCode.RegisterSize == ARegisterSize.Int32
- ? typeof(uint)
- : typeof(ulong);
- }
-
- private Type GetVecType(AOpCode OpCode, AIoType IoType)
- {
- if (!(OpCode is IAOpCodeSimd Op))
- {
- return typeof(AVec);
- }
-
- int Size = Op.Size;
-
- if (Op.Emitter == AInstEmit.Fmov_Ftoi ||
- Op.Emitter == AInstEmit.Fmov_Itof)
- {
- Size |= 2;
- }
-
- if ((Op is AOpCodeMem || Op is IAOpCodeLit) &&
- !(Op is AOpCodeSimdMemMs || Op is AOpCodeSimdMemSs))
- {
- return Size < 4 ? typeof(ulong) : typeof(AVec);
- }
- else if (IoType == AIoType.VectorI)
- {
- return GetIntType(Size);
- }
- else if (IoType == AIoType.VectorF)
- {
- return GetFloatType(Size);
- }
-
- return typeof(AVec);
- }
-
- private static Type GetIntType(int Size)
- {
- switch (Size)
- {
- case 0: return typeof(byte);
- case 1: return typeof(ushort);
- case 2: return typeof(uint);
- case 3: return typeof(ulong);
- }
-
- throw new ArgumentOutOfRangeException(nameof(Size));
- }
-
- private static Type GetFloatType(int Size)
- {
- switch (Size)
- {
- case 0: return typeof(float);
- case 1: return typeof(double);
- }
-
- throw new ArgumentOutOfRangeException(nameof(Size));
+ ILBlock.Add(new AILOpCodeStore(Index, IoType, CurrOp.RegisterSize));
}
public void EmitCallPropGet(Type ObjType, string PropName)
diff --git a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs b/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs
index 2169cc77..23ea0d07 100644
--- a/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs
+++ b/Ryujinx/Cpu/Translation/AILOpCodeLoad.cs
@@ -1,5 +1,4 @@
using ChocolArm64.State;
-using System;
using System.Reflection.Emit;
namespace ChocolArm64.Translation
@@ -10,43 +9,40 @@ namespace ChocolArm64.Translation
public AIoType IoType { get; private set; }
- public Type OperType { get; private set; }
+ public ARegisterSize RegisterSize { get; private set; }
- public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, null) { }
+ public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { }
- public AILOpCodeLoad(int Index, AIoType IoType, Type OperType)
+ public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize)
{
- this.IoType = IoType;
- this.Index = Index;
- this.OperType = OperType;
+ this.IoType = IoType;
+ this.Index = Index;
+ this.RegisterSize = RegisterSize;
}
public void Emit(AILEmitter Context)
{
switch (IoType & AIoType.Mask)
{
- case AIoType.Arg: EmitLdarg(Context, Index); break;
- case AIoType.Fields: EmitLdfld(Context, Index); break;
+ case AIoType.Arg: Context.Generator.EmitLdarg(Index); break;
+
+ case AIoType.Fields:
+ {
+ long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index));
+ long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index));
+
+ LoadLocals(Context, IntInputs, ARegisterType.Int);
+ LoadLocals(Context, VecInputs, ARegisterType.Vector);
+
+ break;
+ }
+
case AIoType.Flag: EmitLdloc(Context, Index, ARegisterType.Flag); break;
case AIoType.Int: EmitLdloc(Context, Index, ARegisterType.Int); break;
case AIoType.Vector: EmitLdloc(Context, Index, ARegisterType.Vector); break;
}
}
- private void EmitLdarg(AILEmitter Context, int Index)
- {
- Context.Generator.EmitLdarg(Index);
- }
-
- private void EmitLdfld(AILEmitter Context, int Index)
- {
- long IntInputs = Context.LocalAlloc.GetIntInputs(Context.GetILBlock(Index));
- long VecInputs = Context.LocalAlloc.GetVecInputs(Context.GetILBlock(Index));
-
- LoadLocals(Context, IntInputs, ARegisterType.Int);
- LoadLocals(Context, VecInputs, ARegisterType.Vector);
- }
-
private void LoadLocals(AILEmitter Context, long Inputs, ARegisterType BaseType)
{
for (int Bit = 0; Bit < 64; Bit++)
@@ -60,23 +56,22 @@ namespace ChocolArm64.Translation
Context.Generator.EmitLdarg(ATranslatedSub.RegistersArgIdx);
Context.Generator.Emit(OpCodes.Ldfld, Reg.GetField());
- AILConv.EmitConv(
- Context,
- Context.GetFieldType(Reg.Type),
- Context.GetLocalType(Reg));
-
Context.Generator.EmitStloc(Context.GetLocalIndex(Reg));
}
}
}
- private void EmitLdloc(AILEmitter Context, int Index, ARegisterType Type)
+ private void EmitLdloc(AILEmitter Context, int Index, ARegisterType RegisterType)
{
- ARegister Reg = new ARegister(Index, Type);
+ ARegister Reg = new ARegister(Index, RegisterType);
Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg));
- AILConv.EmitConv(Context, Context.GetLocalType(Reg), OperType);
+ if (RegisterType == ARegisterType.Int &&
+ RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Generator.Emit(OpCodes.Conv_U4);
+ }
}
}
} \ No newline at end of file
diff --git a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs b/Ryujinx/Cpu/Translation/AILOpCodeStore.cs
index 012e24ae..87d3f85a 100644
--- a/Ryujinx/Cpu/Translation/AILOpCodeStore.cs
+++ b/Ryujinx/Cpu/Translation/AILOpCodeStore.cs
@@ -1,52 +1,48 @@
using ChocolArm64.State;
-using System;
using System.Reflection.Emit;
namespace ChocolArm64.Translation
{
struct AILOpCodeStore : IAILEmit
{
- public AIoType IoType { get; private set; }
-
- public Type OperType { get; private set; }
-
public int Index { get; private set; }
- public AILOpCodeStore(int Index, AIoType IoType) : this(Index, IoType, null) { }
+ public AIoType IoType { get; private set; }
+
+ public ARegisterSize RegisterSize { get; private set; }
+
+ public AILOpCodeStore(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { }
- public AILOpCodeStore(int Index, AIoType IoType, Type OperType)
+ public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize)
{
- this.IoType = IoType;
- this.Index = Index;
- this.OperType = OperType;
+ this.IoType = IoType;
+ this.Index = Index;
+ this.RegisterSize = RegisterSize;
}
public void Emit(AILEmitter Context)
{
switch (IoType & AIoType.Mask)
{
- case AIoType.Arg: EmitStarg(Context, Index); break;
- case AIoType.Fields: EmitStfld(Context, Index); break;
+ case AIoType.Arg: Context.Generator.EmitStarg(Index); break;
+
+ case AIoType.Fields:
+ {
+ long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index));
+ long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index));
+
+ StoreLocals(Context, IntOutputs, ARegisterType.Int);
+ StoreLocals(Context, VecOutputs, ARegisterType.Vector);
+
+ break;
+ }
+
case AIoType.Flag: EmitStloc(Context, Index, ARegisterType.Flag); break;
case AIoType.Int: EmitStloc(Context, Index, ARegisterType.Int); break;
case AIoType.Vector: EmitStloc(Context, Index, ARegisterType.Vector); break;
}
}
- private void EmitStarg(AILEmitter Context, int Index)
- {
- Context.Generator.EmitStarg(Index);
- }
-
- private void EmitStfld(AILEmitter Context, int Index)
- {
- long IntOutputs = Context.LocalAlloc.GetIntOutputs(Context.GetILBlock(Index));
- long VecOutputs = Context.LocalAlloc.GetVecOutputs(Context.GetILBlock(Index));
-
- StoreLocals(Context, IntOutputs, ARegisterType.Int);
- StoreLocals(Context, VecOutputs, ARegisterType.Vector);
- }
-
private void StoreLocals(AILEmitter Context, long Outputs, ARegisterType BaseType)
{
for (int Bit = 0; Bit < 64; Bit++)
@@ -60,21 +56,20 @@ namespace ChocolArm64.Translation
Context.Generator.EmitLdarg(ATranslatedSub.RegistersArgIdx);
Context.Generator.EmitLdloc(Context.GetLocalIndex(Reg));
- AILConv.EmitConv(
- Context,
- Context.GetLocalType(Reg),
- Context.GetFieldType(Reg.Type));
-
Context.Generator.Emit(OpCodes.Stfld, Reg.GetField());
}
}
}
- private void EmitStloc(AILEmitter Context, int Index, ARegisterType Type)
+ private void EmitStloc(AILEmitter Context, int Index, ARegisterType RegisterType)
{
- ARegister Reg = new ARegister(Index, Type);
+ ARegister Reg = new ARegister(Index, RegisterType);
- AILConv.EmitConv(Context, OperType, Context.GetLocalType(Reg));
+ if (RegisterType == ARegisterType.Int &&
+ RegisterSize == ARegisterSize.Int32)
+ {
+ Context.Generator.Emit(OpCodes.Conv_U8);
+ }
Context.Generator.EmitStloc(Context.GetLocalIndex(Reg));
}
diff --git a/Ryujinx/OsHle/Horizon.cs b/Ryujinx/OsHle/Horizon.cs
index f3108873..01380105 100644
--- a/Ryujinx/OsHle/Horizon.cs
+++ b/Ryujinx/OsHle/Horizon.cs
@@ -80,6 +80,8 @@ namespace Ryujinx.OsHle
continue;
}
+ Logging.Info($"Loding {Path.GetFileNameWithoutExtension(File)}...");
+
using (FileStream Input = new FileStream(File, FileMode.Open))
{
Nso Program = new Nso(Input);
diff --git a/Ryujinx/OsHle/Process.cs b/Ryujinx/OsHle/Process.cs
index 05f12c1a..d1f020b5 100644
--- a/Ryujinx/OsHle/Process.cs
+++ b/Ryujinx/OsHle/Process.cs
@@ -70,6 +70,8 @@ namespace Ryujinx.OsHle
public void LoadProgram(IExecutable Program)
{
+ Logging.Info($"Image base at 0x{ImageBase:x16}.");
+
Executable Executable = new Executable(Program, Memory, ImageBase);
Executables.Add(Executable);