From 51ea6fa583fd52eabc5374b414e4052efab4128a Mon Sep 17 00:00:00 2001
From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>
Date: Thu, 30 May 2019 02:29:24 +0200
Subject: [PATCH] Add Smaxv_V, Sminv_V, Umaxv_V, Uminv_V Inst.; add Tests.
 (#691)

* Update InstEmitSimdHelper.cs

* Update InstEmitSimdArithmetic.cs

* Update OpCodeTable.cs

* Update CpuTestSimd.cs
---
 .../Instructions/InstEmitSimdArithmetic.cs    | 52 ++++++++++-----
 .../Instructions/InstEmitSimdHelper.cs        | 29 +++++++++
 ChocolArm64/OpCodeTable.cs                    |  8 +++
 Ryujinx.Tests/Cpu/CpuTestSimd.cs              | 64 +++++++++++++------
 4 files changed, 118 insertions(+), 35 deletions(-)

diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs
index 0e610bbb..8cf5c2c5 100644
--- a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs
+++ b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs
@@ -68,21 +68,7 @@ namespace ChocolArm64.Instructions
 
         public static void Addv_V(ILEmitterCtx context)
         {
-            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
-
-            int bytes = op.GetBitsCount() >> 3;
-            int elems = bytes >> op.Size;
-
-            EmitVectorExtractZx(context, op.Rn, 0, op.Size);
-
-            for (int index = 1; index < elems; index++)
-            {
-                EmitVectorExtractZx(context, op.Rn, index, op.Size);
-
-                context.Emit(OpCodes.Add);
-            }
-
-            EmitScalarSet(context, op.Rd, op.Size);
+            EmitVectorAcrossVectorOpZx(context, () => context.Emit(OpCodes.Add));
         }
 
         public static void Cls_V(ILEmitterCtx context)
@@ -2388,6 +2374,15 @@ namespace ChocolArm64.Instructions
             EmitVectorPairwiseOpSx(context, () => context.EmitCall(mthdInfo));
         }
 
+        public static void Smaxv_V(ILEmitterCtx context)
+        {
+            Type[] types = new Type[] { typeof(long), typeof(long) };
+
+            MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types);
+
+            EmitVectorAcrossVectorOpSx(context, () => context.EmitCall(mthdInfo));
+        }
+
         public static void Smin_V(ILEmitterCtx context)
         {
             if (Optimizations.UseSse41)
@@ -2429,6 +2424,15 @@ namespace ChocolArm64.Instructions
             EmitVectorPairwiseOpSx(context, () => context.EmitCall(mthdInfo));
         }
 
+        public static void Sminv_V(ILEmitterCtx context)
+        {
+            Type[] types = new Type[] { typeof(long), typeof(long) };
+
+            MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types);
+
+            EmitVectorAcrossVectorOpSx(context, () => context.EmitCall(mthdInfo));
+        }
+
         public static void Smlal_V(ILEmitterCtx context)
         {
             OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
@@ -3208,6 +3212,15 @@ namespace ChocolArm64.Instructions
             EmitVectorPairwiseOpZx(context, () => context.EmitCall(mthdInfo));
         }
 
+        public static void Umaxv_V(ILEmitterCtx context)
+        {
+            Type[] types = new Type[] { typeof(ulong), typeof(ulong) };
+
+            MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Max), types);
+
+            EmitVectorAcrossVectorOpZx(context, () => context.EmitCall(mthdInfo));
+        }
+
         public static void Umin_V(ILEmitterCtx context)
         {
             if (Optimizations.UseSse41)
@@ -3249,6 +3262,15 @@ namespace ChocolArm64.Instructions
             EmitVectorPairwiseOpZx(context, () => context.EmitCall(mthdInfo));
         }
 
+        public static void Uminv_V(ILEmitterCtx context)
+        {
+            Type[] types = new Type[] { typeof(ulong), typeof(ulong) };
+
+            MethodInfo mthdInfo = typeof(Math).GetMethod(nameof(Math.Min), types);
+
+            EmitVectorAcrossVectorOpZx(context, () => context.EmitCall(mthdInfo));
+        }
+
         public static void Umlal_V(ILEmitterCtx context)
         {
             OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs
index 2bcda35f..f343dba8 100644
--- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs
+++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs
@@ -821,6 +821,35 @@ namespace ChocolArm64.Instructions
             }
         }
 
+        public static void EmitVectorAcrossVectorOpSx(ILEmitterCtx context, Action emit)
+        {
+            EmitVectorAcrossVectorOp(context, emit, true);
+        }
+
+        public static void EmitVectorAcrossVectorOpZx(ILEmitterCtx context, Action emit)
+        {
+            EmitVectorAcrossVectorOp(context, emit, false);
+        }
+
+        public static void EmitVectorAcrossVectorOp(ILEmitterCtx context, Action emit, bool signed)
+        {
+            OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
+
+            int bytes = op.GetBitsCount() >> 3;
+            int elems = bytes >> op.Size;
+
+            EmitVectorExtract(context, op.Rn, 0, op.Size, signed);
+
+            for (int index = 1; index < elems; index++)
+            {
+                EmitVectorExtract(context, op.Rn, index, op.Size, signed);
+
+                emit();
+            }
+
+            EmitScalarSet(context, op.Rd, op.Size);
+        }
+
         public static void EmitVectorPairwiseOpF(ILEmitterCtx context, Action emit)
         {
             OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs
index fb8b19cd..a1bbd4bc 100644
--- a/ChocolArm64/OpCodeTable.cs
+++ b/ChocolArm64/OpCodeTable.cs
@@ -461,8 +461,12 @@ namespace ChocolArm64
             SetA64("0x1011110>>>>xxx010101xxxxxxxxxx", InstEmit.Sli_V,           typeof(OpCodeSimdShImm64));
             SetA64("0x001110<<1xxxxx011001xxxxxxxxxx", InstEmit.Smax_V,          typeof(OpCodeSimdReg64));
             SetA64("0x001110<<1xxxxx101001xxxxxxxxxx", InstEmit.Smaxp_V,         typeof(OpCodeSimdReg64));
+            SetA64("000011100x110000101010xxxxxxxxxx", InstEmit.Smaxv_V,         typeof(OpCodeSimd64));
+            SetA64("01001110<<110000101010xxxxxxxxxx", InstEmit.Smaxv_V,         typeof(OpCodeSimd64));
             SetA64("0x001110<<1xxxxx011011xxxxxxxxxx", InstEmit.Smin_V,          typeof(OpCodeSimdReg64));
             SetA64("0x001110<<1xxxxx101011xxxxxxxxxx", InstEmit.Sminp_V,         typeof(OpCodeSimdReg64));
+            SetA64("000011100x110001101010xxxxxxxxxx", InstEmit.Sminv_V,         typeof(OpCodeSimd64));
+            SetA64("01001110<<110001101010xxxxxxxxxx", InstEmit.Sminv_V,         typeof(OpCodeSimd64));
             SetA64("0x001110<<1xxxxx100000xxxxxxxxxx", InstEmit.Smlal_V,         typeof(OpCodeSimdReg64));
             SetA64("0x001111xxxxxxxx0010x0xxxxxxxxxx", InstEmit.Smlal_Ve,        typeof(OpCodeSimdRegElem64));
             SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", InstEmit.Smlsl_V,         typeof(OpCodeSimdReg64));
@@ -556,8 +560,12 @@ namespace ChocolArm64
             SetA64("0x101110<<1xxxxx001001xxxxxxxxxx", InstEmit.Uhsub_V,         typeof(OpCodeSimdReg64));
             SetA64("0x101110<<1xxxxx011001xxxxxxxxxx", InstEmit.Umax_V,          typeof(OpCodeSimdReg64));
             SetA64("0x101110<<1xxxxx101001xxxxxxxxxx", InstEmit.Umaxp_V,         typeof(OpCodeSimdReg64));
+            SetA64("001011100x110000101010xxxxxxxxxx", InstEmit.Umaxv_V,         typeof(OpCodeSimd64));
+            SetA64("01101110<<110000101010xxxxxxxxxx", InstEmit.Umaxv_V,         typeof(OpCodeSimd64));
             SetA64("0x101110<<1xxxxx011011xxxxxxxxxx", InstEmit.Umin_V,          typeof(OpCodeSimdReg64));
             SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", InstEmit.Uminp_V,         typeof(OpCodeSimdReg64));
+            SetA64("001011100x110001101010xxxxxxxxxx", InstEmit.Uminv_V,         typeof(OpCodeSimd64));
+            SetA64("01101110<<110001101010xxxxxxxxxx", InstEmit.Uminv_V,         typeof(OpCodeSimd64));
             SetA64("0x101110<<1xxxxx100000xxxxxxxxxx", InstEmit.Umlal_V,         typeof(OpCodeSimdReg64));
             SetA64("0x101111xxxxxxxx0010x0xxxxxxxxxx", InstEmit.Umlal_Ve,        typeof(OpCodeSimdRegElem64));
             SetA64("0x101110<<1xxxxx101000xxxxxxxxxx", InstEmit.Umlsl_V,         typeof(OpCodeSimdReg64));
diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs
index 25e47778..d6bb7318 100644
--- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs
+++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs
@@ -445,6 +445,30 @@ namespace Ryujinx.Tests.Cpu
 #endregion
 
 #region "ValueSource (Opcodes)"
+        private static uint[] _SU_Add_Max_Min_V_V_8BB_4HH_()
+        {
+            return new uint[]
+            {
+                0x0E31B800u, // ADDV  B0, V0.8B
+                0x0E30A800u, // SMAXV B0, V0.8B
+                0x0E31A800u, // SMINV B0, V0.8B
+                0x2E30A800u, // UMAXV B0, V0.8B
+                0x2E31A800u  // UMINV B0, V0.8B
+            };
+        }
+
+        private static uint[] _SU_Add_Max_Min_V_V_16BB_8HH_4SS_()
+        {
+            return new uint[]
+            {
+                0x4E31B800u, // ADDV  B0, V0.16B
+                0x4E30A800u, // SMAXV B0, V0.16B
+                0x4E31A800u, // SMINV B0, V0.16B
+                0x6E30A800u, // UMAXV B0, V0.16B
+                0x6E31A800u  // UMINV B0, V0.16B
+            };
+        }
+
         private static uint[] _F_Abs_Neg_Recpx_Sqrt_S_S_()
         {
             return new uint[]
@@ -913,40 +937,40 @@ namespace Ryujinx.Tests.Cpu
             CompareAgainstUnicorn();
         }
 
-        [Test, Pairwise, Description("ADDV <V><d>, <Vn>.<T>")]
-        public void Addv_V_8BB_4HH([Values(0u)]     uint rd,
-                                   [Values(1u, 0u)] uint rn,
-                                   [ValueSource("_8B4H_")] [Random(RndCnt)] ulong z,
-                                   [ValueSource("_8B4H_")] [Random(RndCnt)] ulong a,
-                                   [Values(0b00u, 0b01u)] uint size) // <8BB, 4HH>
+        [Test, Pairwise]
+        public void SU_Add_Max_Min_V_V_8BB_4HH([ValueSource("_SU_Add_Max_Min_V_V_8BB_4HH_")] uint opcodes,
+                                               [Values(0u)]     uint rd,
+                                               [Values(1u, 0u)] uint rn,
+                                               [ValueSource("_8B4H_")] [Random(RndCnt)] ulong z,
+                                               [ValueSource("_8B4H_")] [Random(RndCnt)] ulong a,
+                                               [Values(0b00u, 0b01u)] uint size) // <8BB, 4HH>
         {
-            uint opcode = 0x0E31B800; // ADDV B0, V0.8B
-            opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
+            opcodes |= ((size & 3) << 22);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
             Vector128<float> v1 = MakeVectorE0(a);
 
-            SingleOpcode(opcode, v0: v0, v1: v1);
+            SingleOpcode(opcodes, v0: v0, v1: v1);
 
             CompareAgainstUnicorn();
         }
 
-        [Test, Pairwise, Description("ADDV <V><d>, <Vn>.<T>")]
-        public void Addv_V_16BB_8HH_4SS([Values(0u)]     uint rd,
-                                        [Values(1u, 0u)] uint rn,
-                                        [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
-                                        [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a,
-                                        [Values(0b00u, 0b01u, 0b10u)] uint size) // <16BB, 8HH, 4SS>
+        [Test, Pairwise]
+        public void SU_Add_Max_Min_V_V_16BB_8HH_4SS([ValueSource("_SU_Add_Max_Min_V_V_16BB_8HH_4SS_")] uint opcodes,
+                                                    [Values(0u)]     uint rd,
+                                                    [Values(1u, 0u)] uint rn,
+                                                    [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
+                                                    [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a,
+                                                    [Values(0b00u, 0b01u, 0b10u)] uint size) // <16BB, 8HH, 4SS>
         {
-            uint opcode = 0x4E31B800; // ADDV B0, V0.16B
-            opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
+            opcodes |= ((size & 3) << 22);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
             Vector128<float> v1 = MakeVectorE0E1(a, a);
 
-            SingleOpcode(opcode, v0: v0, v1: v1);
+            SingleOpcode(opcodes, v0: v0, v1: v1);
 
             CompareAgainstUnicorn();
         }