Просмотр исходного кода

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

gdkchan 8 лет назад
Родитель
Сommit
161193e113

+ 6 - 6
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));

+ 2 - 0
Ryujinx/Cpu/Decoder/AOpCodeSimdMemMs.cs

@@ -37,6 +37,8 @@ namespace ChocolArm64.Decoder
                 return;
             }
 
+            Extend64 = false;
+
             RegisterSize = Q
                 ? ARegisterSize.SIMD128
                 : ARegisterSize.SIMD64;

+ 2 - 0
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

+ 1 - 1
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);
         }
 

+ 73 - 32
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);
+        }
     }
 }

+ 0 - 745
Ryujinx/Cpu/Instruction/AInstEmitScalar.cs

@@ -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();
-            }
-        }
-    }
-}

+ 0 - 1370
Ryujinx/Cpu/Instruction/AInstEmitSimd.cs

@@ -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);
-        }
-    }
-}

+ 354 - 0
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));
+        }
+    }
+}

+ 236 - 0
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);
+            }
+        }
+    }
+}

+ 399 - 0
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);
+            }
+        }
+    }
+}

+ 508 - 0
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);
+        }
+    }
+}

+ 69 - 0
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));
+        }
+    }
+}

+ 155 - 0
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);
+        }
+    }
+}

+ 275 - 0
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);
+            }
+        }
+    }
+}

+ 306 - 0
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);
+        }
+    }
+}

+ 26 - 171
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));
-        }
     }
 }

+ 72 - 0
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

+ 0 - 113
Ryujinx/Cpu/Translation/AILConv.cs

@@ -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 };
-    }
-}

+ 0 - 3
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));
             }
         }

+ 6 - 102
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)

+ 26 - 31
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);
+            }
         }
     }
 }

+ 29 - 34
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));
         }

+ 2 - 0
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);

+ 2 - 0
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);