forked from Mirror/Ryujinx
Cpu: Implement Vpadal and Vrintr instructions (#6185)
* Cpu: Implement Vpadal and Vrintr instructions This PR superseed last instructions left in #2242. Since I'm not a CPU guy I've just ported the code and nothing more. Please be precise during review if there are some changes to be done. It should fixes #1781 Co-Authored-By: Piyachet Kanda <piyachetk@gmail.com> * Addresses gdkchan's feedback * Addresses gdkchan's feedback 2 * Apply suggestions from code review Co-authored-by: gdkchan <gab.dark.100@gmail.com> * another fix * Update InstEmitSimdHelper32.cs * Correct fix * Addresses gdkchan's feedback * Update CpuTestSimdCvt32.cs --------- Co-authored-by: Piyachet Kanda <piyachetk@gmail.com> Co-authored-by: gdkchan <gab.dark.100@gmail.com>
This commit is contained in:
parent
2adf031830
commit
8bf102d2cd
7 changed files with 133 additions and 0 deletions
|
@ -875,6 +875,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
|
||||||
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
|
SetVfp("<<<<11101x110110xxxx101x01x0xxxx", InstName.Vrintr, InstEmit32.Vrintr_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
|
||||||
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
|
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
|
||||||
|
@ -995,6 +996,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetAsimd("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
SetAsimd("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
|
||||||
SetAsimd("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
SetAsimd("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetAsimd("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
SetAsimd("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
|
SetAsimd("111100111x11<<00xxxx0110xxx0xxxx", InstName.Vpadal, InstEmit32.Vpadal, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetAsimd("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
SetAsimd("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetAsimd("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
SetAsimd("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
SetAsimd("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
SetAsimd("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||||
|
|
|
@ -1115,6 +1115,13 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Vpadal(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||||
|
|
||||||
|
EmitVectorPairwiseTernaryLongOpI32(context, (op1, op2, op3) => context.Add(context.Add(op1, op2), op3), op.Opc != 1);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Vpaddl(ArmEmitterContext context)
|
public static void Vpaddl(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||||
|
|
|
@ -578,6 +578,22 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VRINTR (floating-point).
|
||||||
|
public static void Vrintr_S(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseAdvSimd)
|
||||||
|
{
|
||||||
|
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintiS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarUnaryOpF32(context, (op1) =>
|
||||||
|
{
|
||||||
|
return EmitRoundByRMode(context, op1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VRINTZ (floating-point).
|
// VRINTZ (floating-point).
|
||||||
public static void Vrint_Z(ArmEmitterContext context)
|
public static void Vrint_Z(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
|
|
|
@ -673,6 +673,35 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetVecA32(op.Qd), res);
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EmitVectorPairwiseTernaryLongOpI32(ArmEmitterContext context, Func3I emit, bool signed)
|
||||||
|
{
|
||||||
|
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||||
|
|
||||||
|
int elems = op.GetBytesCount() >> op.Size;
|
||||||
|
int pairs = elems >> 1;
|
||||||
|
|
||||||
|
Operand res = GetVecA32(op.Qd);
|
||||||
|
|
||||||
|
for (int index = 0; index < pairs; index++)
|
||||||
|
{
|
||||||
|
int pairIndex = index * 2;
|
||||||
|
Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed);
|
||||||
|
Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed);
|
||||||
|
|
||||||
|
if (op.Size == 2)
|
||||||
|
{
|
||||||
|
m1 = signed ? context.SignExtend32(OperandType.I64, m1) : context.ZeroExtend32(OperandType.I64, m1);
|
||||||
|
m2 = signed ? context.SignExtend32(OperandType.I64, m2) : context.ZeroExtend32(OperandType.I64, m2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand d1 = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size + 1, signed);
|
||||||
|
|
||||||
|
res = EmitVectorInsert(context, res, emit(m1, m2, d1), op.Id + index, op.Size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
|
}
|
||||||
|
|
||||||
// Narrow
|
// Narrow
|
||||||
|
|
||||||
public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false)
|
public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false)
|
||||||
|
|
|
@ -637,6 +637,7 @@ namespace ARMeilleure.Instructions
|
||||||
Vorn,
|
Vorn,
|
||||||
Vorr,
|
Vorr,
|
||||||
Vpadd,
|
Vpadd,
|
||||||
|
Vpadal,
|
||||||
Vpaddl,
|
Vpaddl,
|
||||||
Vpmax,
|
Vpmax,
|
||||||
Vpmin,
|
Vpmin,
|
||||||
|
@ -656,6 +657,7 @@ namespace ARMeilleure.Instructions
|
||||||
Vrintm,
|
Vrintm,
|
||||||
Vrintn,
|
Vrintn,
|
||||||
Vrintp,
|
Vrintp,
|
||||||
|
Vrintr,
|
||||||
Vrintx,
|
Vrintx,
|
||||||
Vrshr,
|
Vrshr,
|
||||||
Vrshrn,
|
Vrshrn,
|
||||||
|
|
|
@ -511,6 +511,45 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise, Description("VRINTR.F<size> <Sd>, <Sm>")]
|
||||||
|
[Platform(Exclude = "Linux,MacOsX")] // Instruction isn't testable due to Unicorn.
|
||||||
|
public void Vrintr([Values(0u, 1u)] uint rd,
|
||||||
|
[Values(0u, 1u)] uint rm,
|
||||||
|
[Values(2u, 3u)] uint size,
|
||||||
|
[ValueSource(nameof(_1D_F_))] ulong s0,
|
||||||
|
[ValueSource(nameof(_1D_F_))] ulong s1,
|
||||||
|
[ValueSource(nameof(_1D_F_))] ulong s2,
|
||||||
|
[Values(RMode.Rn, RMode.Rm, RMode.Rp)] RMode rMode)
|
||||||
|
{
|
||||||
|
uint opcode = 0xEEB60A40;
|
||||||
|
|
||||||
|
V128 v0, v1, v2;
|
||||||
|
|
||||||
|
if (size == 2)
|
||||||
|
{
|
||||||
|
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||||
|
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||||
|
v0 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s0), (uint)BitConverter.SingleToInt32Bits(s0));
|
||||||
|
v1 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s1), (uint)BitConverter.SingleToInt32Bits(s0));
|
||||||
|
v2 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s2), (uint)BitConverter.SingleToInt32Bits(s1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||||
|
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||||
|
v0 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s0), (uint)BitConverter.DoubleToInt64Bits(s0));
|
||||||
|
v1 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s1), (uint)BitConverter.DoubleToInt64Bits(s0));
|
||||||
|
v2 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s2), (uint)BitConverter.DoubleToInt64Bits(s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((size & 3) << 8);
|
||||||
|
|
||||||
|
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||||
|
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -908,6 +908,44 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void Vp_Add_Long_Accumulate([Values(0u, 2u, 4u, 8u)] uint rd,
|
||||||
|
[Values(0u, 2u, 4u, 8u)] uint rm,
|
||||||
|
[Values(0u, 1u, 2u)] uint size,
|
||||||
|
[Random(RndCnt)] ulong z,
|
||||||
|
[Random(RndCnt)] ulong a,
|
||||||
|
[Random(RndCnt)] ulong b,
|
||||||
|
[Values] bool q,
|
||||||
|
[Values] bool unsigned)
|
||||||
|
{
|
||||||
|
uint opcode = 0xF3B00600; // VPADAL.S8 D0, Q0
|
||||||
|
|
||||||
|
if (q)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 6;
|
||||||
|
rm <<= 1;
|
||||||
|
rd <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||||
|
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||||
|
|
||||||
|
opcode |= size << 18;
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0E1(a, z);
|
||||||
|
V128 v2 = MakeVectorE0E1(b, z);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue