diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs index 0e610bbb1..8cf5c2c5d 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 2bcda35f3..f343dba8d 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 fb8b19cd1..a1bbd4bc0 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 25e47778c..d6bb7318a 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 , .")] - 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 v0 = MakeVectorE0E1(z, z); Vector128 v1 = MakeVectorE0(a); - SingleOpcode(opcode, v0: v0, v1: v1); + SingleOpcode(opcodes, v0: v0, v1: v1); CompareAgainstUnicorn(); } - [Test, Pairwise, Description("ADDV , .")] - 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 v0 = MakeVectorE0E1(z, z); Vector128 v1 = MakeVectorE0E1(a, a); - SingleOpcode(opcode, v0: v0, v1: v1); + SingleOpcode(opcodes, v0: v0, v1: v1); CompareAgainstUnicorn(); }