From 301ced766ccf1924de57a3635bb1ad6d04bd2ab6 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Mon, 13 Jan 2020 17:47:22 +0000 Subject: [PATCH] Add tests and fix issues with VTRN, VZIP, VUZP --- ARMeilleure/Instructions/InstEmitSimdCmp32.cs | 2 +- .../Instructions/InstEmitSimdHelper32.cs | 2 + .../Instructions/InstEmitSimdMove32.cs | 20 ++++- Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs | 90 +++++++++++++++++++ 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs index 9abf31ac10..0da6f5943a 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs @@ -242,7 +242,7 @@ namespace ARMeilleure.Instructions me = ExtractScalar(context, type, op.Vm); } - Delegate dlg = op.Size != 0 + Delegate dlg = fSize != 0 ? (Delegate)new _S32_F64_F64_Bool(SoftFloat64.FPCompare) : (Delegate)new _S32_F32_F32_Bool(SoftFloat32.FPCompare); diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index 3edb8e5ceb..35f711e934 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -114,6 +114,8 @@ namespace ARMeilleure.Instructions OperandType type = (op.Size & 1) != 0 ? OperandType.I64 : OperandType.I32; + if (op.Size < 2) throw new Exception("Not supported right now"); + Operand n = ExtractScalar(context, type, op.Vn); Operand m = ExtractScalar(context, type, op.Vm); diff --git a/ARMeilleure/Instructions/InstEmitSimdMove32.cs b/ARMeilleure/Instructions/InstEmitSimdMove32.cs index 4f236c832f..eed4e97e12 100644 --- a/ARMeilleure/Instructions/InstEmitSimdMove32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdMove32.cs @@ -115,6 +115,8 @@ namespace ARMeilleure.Instructions (int vm, int em) = GetQuadwordAndSubindex(op.Vm, op.RegisterSize); (int vd, int ed) = GetQuadwordAndSubindex(op.Vd, op.RegisterSize); + bool overlap = vm == vd; + Operand resD = GetVecA32(vd); Operand resM = GetVecA32(vm); @@ -125,11 +127,13 @@ namespace ARMeilleure.Instructions Operand m1 = EmitVectorExtract32(context, vm, pairIndex + em * elems, op.Size, false); resD = EmitVectorInsert(context, resD, m1, pairIndex + 1 + ed * elems, op.Size); + if (overlap) resM = resD; resM = EmitVectorInsert(context, resM, d2, pairIndex + em * elems, op.Size); + if (overlap) resD = resM; } context.Copy(GetVecA32(vd), resD); - context.Copy(GetVecA32(vm), resM); + if (!overlap) context.Copy(GetVecA32(vm), resM); } public static void Vzip(ArmEmitterContext context) @@ -142,6 +146,8 @@ namespace ARMeilleure.Instructions (int vm, int em) = GetQuadwordAndSubindex(op.Vm, op.RegisterSize); (int vd, int ed) = GetQuadwordAndSubindex(op.Vd, op.RegisterSize); + bool overlap = vm == vd; + Operand resD = GetVecA32(vd); Operand resM = GetVecA32(vm); @@ -157,12 +163,16 @@ namespace ARMeilleure.Instructions resD = EmitVectorInsert(context, resD, dRowD, pairIndex + ed * elems, op.Size); resD = EmitVectorInsert(context, resD, mRowD, pairIndex + 1 + ed * elems, op.Size); + if (overlap) resM = resD; + resM = EmitVectorInsert(context, resM, dRowM, pairIndex + em * elems, op.Size); resM = EmitVectorInsert(context, resM, mRowM, pairIndex + 1 + em * elems, op.Size); + + if (overlap) resD = resM; } context.Copy(GetVecA32(vd), resD); - context.Copy(GetVecA32(vm), resM); + if (!overlap) context.Copy(GetVecA32(vm), resM); } public static void Vuzp(ArmEmitterContext context) @@ -175,6 +185,8 @@ namespace ARMeilleure.Instructions (int vm, int em) = GetQuadwordAndSubindex(op.Vm, op.RegisterSize); (int vd, int ed) = GetQuadwordAndSubindex(op.Vd, op.RegisterSize); + bool overlap = vm == vd; + Operand resD = GetVecA32(vd); Operand resM = GetVecA32(vm); @@ -194,11 +206,13 @@ namespace ARMeilleure.Instructions } resD = EmitVectorInsert(context, resD, dIns, index + ed * elems, op.Size); + if (overlap) resM = resD; resM = EmitVectorInsert(context, resM, mIns, index + em * elems, op.Size); + if (overlap) resD = resM; } context.Copy(GetVecA32(vd), resD); - context.Copy(GetVecA32(vm), resM); + if (!overlap) context.Copy(GetVecA32(vm), resM); } } } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs b/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs index c54d829d96..dd946facc0 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs @@ -103,6 +103,96 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Combinatorial, Description("VTRN. , ")] + public void Vtrn([Values(0u, 1u, 2u, 3u)] uint vm, + [Values(0u, 1u, 2u, 3u)] uint vd, + [Values(0u, 1u, 2u)] uint size, + [Values] bool q) + { + uint opcode = 0xf3b20080; + if (vm == vd) return; //undefined + + if (q) + { + opcode |= 1 << 6; + vd <<= 1; vm <<= 1; + } + opcode |= (vm & 0x10) << 1; + opcode |= (vm & 0xf); + opcode |= (vd & 0x10) << 18; + opcode |= (vd & 0xf) << 12; + opcode |= (size & 0x3) << 18; + + V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3); //correct + + CompareAgainstUnicorn(); + } + + [Test, Combinatorial, Description("VZIP. , ")] + public void Vzip([Values(0u, 1u, 2u, 3u)] uint vm, + [Values(0u, 1u, 2u, 3u)] uint vd, + [Values(0u, 1u, 2u)] uint size, + [Values] bool q) + { + uint opcode = 0xf3b20180; + if (vm == vd || (size == 2 && !q)) return; //undefined + + if (q) + { + opcode |= 1 << 6; + vd <<= 1; vm <<= 1; + } + opcode |= (vm & 0x10) << 1; + opcode |= (vm & 0xf); + opcode |= (vd & 0x10) << 18; + opcode |= (vd & 0xf) << 12; + opcode |= (size & 0x3) << 18; + + V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3); //correct + + CompareAgainstUnicorn(); + } + + [Test, Combinatorial, Description("VUZP. , ")] + public void Vuzp([Values(0u, 1u, 2u, 3u)] uint vm, + [Values(0u, 1u, 2u, 3u)] uint vd, + [Values(0u, 1u, 2u)] uint size, + [Values] bool q) + { + uint opcode = 0xf3b20100; + if (vm == vd || (size == 2 && !q)) return; //undefined + + if (q) + { + opcode |= 1 << 6; + vd <<= 1; vm <<= 1; + } + opcode |= (vm & 0x10) << 1; + opcode |= (vm & 0xf); + opcode |= (vd & 0x10) << 18; + opcode |= (vd & 0xf) << 12; + opcode |= (size & 0x3) << 18; + + V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3); //correct + + CompareAgainstUnicorn(); + } #endif } }