From 81aa50feb0899e73ee62e5113b786efe0ff6b7a9 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 26 Feb 2019 09:50:36 -0300
Subject: [PATCH] Optimize MOVI/MVNI instructions using intrinsics (#606)

---
 ChocolArm64/Instructions/InstEmitSimdMove.cs | 50 +++++++++++++++++++-
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs
index 7145263d38..20647ce09d 100644
--- a/ChocolArm64/Instructions/InstEmitSimdMove.cs
+++ b/ChocolArm64/Instructions/InstEmitSimdMove.cs
@@ -318,12 +318,26 @@ namespace ChocolArm64.Instructions
 
         public static void Movi_V(ILEmitterCtx context)
         {
-            EmitVectorImmUnaryOp(context, () => { });
+            if (Optimizations.UseSse2)
+            {
+                EmitMoviMvni(context, not: false);
+            }
+            else
+            {
+                EmitVectorImmUnaryOp(context, () => { });
+            }
         }
 
         public static void Mvni_V(ILEmitterCtx context)
         {
-            EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not));
+            if (Optimizations.UseSse2)
+            {
+                EmitMoviMvni(context, not: true);
+            }
+            else
+            {
+                EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not));
+            }
         }
 
         public static void Smov_S(ILEmitterCtx context)
@@ -480,6 +494,38 @@ namespace ChocolArm64.Instructions
             }
         }
 
+        private static void EmitMoviMvni(ILEmitterCtx context, bool not)
+        {
+            OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp;
+
+            Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] };
+
+            long imm = op.Imm;
+
+            if (not)
+            {
+                imm = ~imm;
+            }
+
+            if (op.Size < 3)
+            {
+                context.EmitLdc_I4((int)imm);
+            }
+            else
+            {
+                context.EmitLdc_I8(imm);
+            }
+
+            context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
+
+            context.EmitStvec(op.Rd);
+
+            if (op.RegisterSize == RegisterSize.Simd64)
+            {
+                EmitVectorZeroUpper(context, op.Rd);
+            }
+        }
+
         private static void EmitVectorTranspose(ILEmitterCtx context, int part)
         {
             OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;