Просмотр исходного кода

Implement a custom value generator for the Tests of the CLS and CLZ instructions (Base: 32, 64 bits. Simd: 8, 16, 32 bits). (#696)

* Update CpuTestAlu.cs

* Update CpuTestSimd.cs

* Update CpuTestMov.cs
LDj3SNuD 6 лет назад
Родитель
Сommit
d87c5375f1
3 измененных файлов с 292 добавлено и 40 удалено
  1. 87 8
      Ryujinx.Tests/Cpu/CpuTestAlu.cs
  2. 3 2
      Ryujinx.Tests/Cpu/CpuTestMov.cs
  3. 202 30
      Ryujinx.Tests/Cpu/CpuTestSimd.cs

+ 87 - 8
Ryujinx.Tests/Cpu/CpuTestAlu.cs

@@ -2,19 +2,101 @@
 
 using NUnit.Framework;
 
+using System.Collections.Generic;
+
 namespace Ryujinx.Tests.Cpu
 {
     [Category("Alu")]
     public sealed class CpuTestAlu : CpuTest
     {
 #if Alu
+
+#region "Helper methods"
+        private static uint GenLeadingSignsMinus32(int cnt) // 0 <= cnt <= 31
+        {
+            return ~GenLeadingZeros32(cnt + 1);
+        }
+
+        private static ulong GenLeadingSignsMinus64(int cnt) // 0 <= cnt <= 63
+        {
+            return ~GenLeadingZeros64(cnt + 1);
+        }
+
+        private static uint GenLeadingSignsPlus32(int cnt) // 0 <= cnt <= 31
+        {
+            return GenLeadingZeros32(cnt + 1);
+        }
+
+        private static ulong GenLeadingSignsPlus64(int cnt) // 0 <= cnt <= 63
+        {
+            return GenLeadingZeros64(cnt + 1);
+        }
+
+        private static uint GenLeadingZeros32(int cnt) // 0 <= cnt <= 32
+        {
+            if (cnt == 32) return 0u;
+            if (cnt == 31) return 1u;
+
+            uint rnd  = TestContext.CurrentContext.Random.NextUInt();
+            int  mask = int.MinValue;
+
+            return (rnd >> (cnt + 1)) | ((uint)mask >> cnt);
+        }
+
+        private static ulong GenLeadingZeros64(int cnt) // 0 <= cnt <= 64
+        {
+            if (cnt == 64) return 0ul;
+            if (cnt == 63) return 1ul;
+
+            ulong rnd  = TestContext.CurrentContext.Random.NextULong();
+            long  mask = long.MinValue;
+
+            return (rnd >> (cnt + 1)) | ((ulong)mask >> cnt);
+        }
+#endregion
+
+#region "ValueSource (Types)"
+        private static IEnumerable<ulong> _GenLeadingSignsX_()
+        {
+            for (int cnt = 0; cnt <= 63; cnt++)
+            {
+                yield return GenLeadingSignsMinus64(cnt);
+                yield return GenLeadingSignsPlus64(cnt);
+            }
+        }
+
+        private static IEnumerable<uint> _GenLeadingSignsW_()
+        {
+            for (int cnt = 0; cnt <= 31; cnt++)
+            {
+                yield return GenLeadingSignsMinus32(cnt);
+                yield return GenLeadingSignsPlus32(cnt);
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingZerosX_()
+        {
+            for (int cnt = 0; cnt <= 64; cnt++)
+            {
+                yield return GenLeadingZeros64(cnt);
+            }
+        }
+
+        private static IEnumerable<uint> _GenLeadingZerosW_()
+        {
+            for (int cnt = 0; cnt <= 32; cnt++)
+            {
+                yield return GenLeadingZeros32(cnt);
+            }
+        }
+#endregion
+
         private const int RndCnt = 2;
 
         [Test, Pairwise, Description("CLS <Xd>, <Xn>")]
         public void Cls_64bit([Values(0u, 31u)] uint rd,
                               [Values(1u, 31u)] uint rn,
-                              [Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
-                                      0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
+                              [ValueSource("_GenLeadingSignsX_")] [Random(RndCnt)] ulong xn)
         {
             uint opcode = 0xDAC01400; // CLS X0, X0
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
@@ -29,8 +111,7 @@ namespace Ryujinx.Tests.Cpu
         [Test, Pairwise, Description("CLS <Wd>, <Wn>")]
         public void Cls_32bit([Values(0u, 31u)] uint rd,
                               [Values(1u, 31u)] uint rn,
-                              [Values(0x00000000u, 0x7FFFFFFFu,
-                                      0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
+                              [ValueSource("_GenLeadingSignsW_")] [Random(RndCnt)] uint wn)
         {
             uint opcode = 0x5AC01400; // CLS W0, W0
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
@@ -45,8 +126,7 @@ namespace Ryujinx.Tests.Cpu
         [Test, Pairwise, Description("CLZ <Xd>, <Xn>")]
         public void Clz_64bit([Values(0u, 31u)] uint rd,
                               [Values(1u, 31u)] uint rn,
-                              [Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
-                                      0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn)
+                              [ValueSource("_GenLeadingZerosX_")] [Random(RndCnt)] ulong xn)
         {
             uint opcode = 0xDAC01000; // CLZ X0, X0
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
@@ -61,8 +141,7 @@ namespace Ryujinx.Tests.Cpu
         [Test, Pairwise, Description("CLZ <Wd>, <Wn>")]
         public void Clz_32bit([Values(0u, 31u)] uint rd,
                               [Values(1u, 31u)] uint rn,
-                              [Values(0x00000000u, 0x7FFFFFFFu,
-                                      0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn)
+                              [ValueSource("_GenLeadingZerosW_")] [Random(RndCnt)] uint wn)
         {
             uint opcode = 0x5AC01000; // CLZ W0, W0
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);

+ 3 - 2
Ryujinx.Tests/Cpu/CpuTestMov.cs

@@ -8,11 +8,12 @@ namespace Ryujinx.Tests.Cpu
     public sealed class CpuTestMov : CpuTest
     {
 #if Mov
+        private const int RndCnt    = 2;
         private const int RndCntImm = 2;
 
         [Test, Pairwise, Description("MOVK <Xd>, #<imm>{, LSL #<shift>}")]
         public void Movk_64bit([Values(0u, 31u)] uint rd,
-                               [Random(RndCntImm)] ulong xd,
+                               [Random(RndCnt)] ulong xd,
                                [Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
                                [Values(0u, 16u, 32u, 48u)] uint shift)
         {
@@ -29,7 +30,7 @@ namespace Ryujinx.Tests.Cpu
 
         [Test, Pairwise, Description("MOVK <Wd>, #<imm>{, LSL #<shift>}")]
         public void Movk_32bit([Values(0u, 31u)] uint rd,
-                               [Random(RndCntImm)] uint wd,
+                               [Random(RndCnt)] uint wd,
                                [Values(0u, 65535u)] [Random(0u, 65535u, RndCntImm)] uint imm,
                                [Values(0u, 16u)] uint shift)
         {

+ 202 - 30
Ryujinx.Tests/Cpu/CpuTestSimd.cs

@@ -13,6 +13,71 @@ namespace Ryujinx.Tests.Cpu
     {
 #if Simd
 
+#region "Helper methods"
+        private static byte GenLeadingSignsMinus8(int cnt) // 0 <= cnt <= 7
+        {
+            return (byte)(~(uint)GenLeadingZeros8(cnt + 1));
+        }
+
+        private static ushort GenLeadingSignsMinus16(int cnt) // 0 <= cnt <= 15
+        {
+            return (ushort)(~(uint)GenLeadingZeros16(cnt + 1));
+        }
+
+        private static uint GenLeadingSignsMinus32(int cnt) // 0 <= cnt <= 31
+        {
+            return ~GenLeadingZeros32(cnt + 1);
+        }
+
+        private static byte GenLeadingSignsPlus8(int cnt) // 0 <= cnt <= 7
+        {
+            return GenLeadingZeros8(cnt + 1);
+        }
+
+        private static ushort GenLeadingSignsPlus16(int cnt) // 0 <= cnt <= 15
+        {
+            return GenLeadingZeros16(cnt + 1);
+        }
+
+        private static uint GenLeadingSignsPlus32(int cnt) // 0 <= cnt <= 31
+        {
+            return GenLeadingZeros32(cnt + 1);
+        }
+
+        private static byte GenLeadingZeros8(int cnt) // 0 <= cnt <= 8
+        {
+            if (cnt == 8) return (byte)0;
+            if (cnt == 7) return (byte)1;
+
+            byte  rnd  = TestContext.CurrentContext.Random.NextByte();
+            sbyte mask = sbyte.MinValue;
+
+            return (byte)(((uint)rnd >> (cnt + 1)) | ((uint)((byte)mask) >> cnt));
+        }
+
+        private static ushort GenLeadingZeros16(int cnt) // 0 <= cnt <= 16
+        {
+            if (cnt == 16) return (ushort)0;
+            if (cnt == 15) return (ushort)1;
+
+            ushort rnd  = TestContext.CurrentContext.Random.NextUShort();
+            short  mask = short.MinValue;
+
+            return (ushort)(((uint)rnd >> (cnt + 1)) | ((uint)((ushort)mask) >> cnt));
+        }
+
+        private static uint GenLeadingZeros32(int cnt) // 0 <= cnt <= 32
+        {
+            if (cnt == 32) return 0u;
+            if (cnt == 31) return 1u;
+
+            uint rnd  = TestContext.CurrentContext.Random.NextUInt();
+            int  mask = int.MinValue;
+
+            return (rnd >> (cnt + 1)) | ((uint)mask >> cnt);
+        }
+#endregion
+
 #region "ValueSource (Types)"
         private static ulong[] _1B1H1S1D_()
         {
@@ -90,6 +155,75 @@ namespace Ryujinx.Tests.Cpu
                                  0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
         }
 
+        private static IEnumerable<ulong> _GenLeadingSigns8B_()
+        {
+            for (int cnt = 0; cnt <= 7; cnt++)
+            {
+                ulong rnd1 = GenLeadingSignsMinus8(cnt);
+                ulong rnd2 = GenLeadingSignsPlus8(cnt);
+
+                yield return (rnd1 << 56) | (rnd1 << 48) | (rnd1 << 40) | (rnd1 << 32) |
+                             (rnd1 << 24) | (rnd1 << 16) | (rnd1 << 08) | rnd1;
+                yield return (rnd2 << 56) | (rnd2 << 48) | (rnd2 << 40) | (rnd2 << 32) |
+                             (rnd2 << 24) | (rnd2 << 16) | (rnd2 << 08) | rnd2;
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingSigns4H_()
+        {
+            for (int cnt = 0; cnt <= 15; cnt++)
+            {
+                ulong rnd1 = GenLeadingSignsMinus16(cnt);
+                ulong rnd2 = GenLeadingSignsPlus16(cnt);
+
+                yield return (rnd1 << 48) | (rnd1 << 32) | (rnd1 << 16) | rnd1;
+                yield return (rnd2 << 48) | (rnd2 << 32) | (rnd2 << 16) | rnd2;
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingSigns2S_()
+        {
+            for (int cnt = 0; cnt <= 31; cnt++)
+            {
+                ulong rnd1 = GenLeadingSignsMinus32(cnt);
+                ulong rnd2 = GenLeadingSignsPlus32(cnt);
+
+                yield return (rnd1 << 32) | rnd1;
+                yield return (rnd2 << 32) | rnd2;
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingZeros8B_()
+        {
+            for (int cnt = 0; cnt <= 8; cnt++)
+            {
+                ulong rnd = GenLeadingZeros8(cnt);
+
+                yield return (rnd << 56) | (rnd << 48) | (rnd << 40) | (rnd << 32) |
+                             (rnd << 24) | (rnd << 16) | (rnd << 08) | rnd;
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingZeros4H_()
+        {
+            for (int cnt = 0; cnt <= 16; cnt++)
+            {
+                ulong rnd = GenLeadingZeros16(cnt);
+
+                yield return (rnd << 48) | (rnd << 32) | (rnd << 16) | rnd;
+            }
+        }
+
+        private static IEnumerable<ulong> _GenLeadingZeros2S_()
+        {
+            for (int cnt = 0; cnt <= 32; cnt++)
+            {
+                ulong rnd = GenLeadingZeros32(cnt);
+
+                yield return (rnd << 32) | rnd;
+            }
+        }
+
         private static IEnumerable<ulong> _1H_F_()
         {
             yield return 0x000000000000FBFFul; // -Max Normal
@@ -1034,18 +1168,18 @@ namespace Ryujinx.Tests.Cpu
         }
 
         [Test, Pairwise, Description("CLS <Vd>.<T>, <Vn>.<T>")]
-        public void Cls_V_8B_4H_2S([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) // <8B, 4H, 2S>
+        public void Cls_V_8B_16B([Values(0u)]     uint rd,
+                                 [Values(1u, 0u)] uint rn,
+                                 [ValueSource("_GenLeadingSigns8B_")] [Random(RndCnt)] ulong z,
+                                 [ValueSource("_GenLeadingSigns8B_")] [Random(RndCnt)] ulong a,
+                                 [Values(0b0u, 0b1u)] uint q) // <8B, 16B>
         {
             uint opcode = 0x0E204800; // CLS V0.8B, V0.8B
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcode |= ((q & 1) << 30);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
-            Vector128<float> v1 = MakeVectorE0(a);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
 
             SingleOpcode(opcode, v0: v0, v1: v1);
 
@@ -1053,18 +1187,37 @@ namespace Ryujinx.Tests.Cpu
         }
 
         [Test, Pairwise, Description("CLS <Vd>.<T>, <Vn>.<T>")]
-        public void Cls_V_16B_8H_4S([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) // <16B, 8H, 4S>
+        public void Cls_V_4H_8H([Values(0u)]     uint rd,
+                                [Values(1u, 0u)] uint rn,
+                                [ValueSource("_GenLeadingSigns4H_")] [Random(RndCnt)] ulong z,
+                                [ValueSource("_GenLeadingSigns4H_")] [Random(RndCnt)] ulong a,
+                                [Values(0b0u, 0b1u)] uint q) // <4H, 8H>
         {
-            uint opcode = 0x4E204800; // CLS V0.16B, V0.16B
+            uint opcode = 0x0E604800; // CLS V0.4H, V0.4H
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcode |= ((q & 1) << 30);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
-            Vector128<float> v1 = MakeVectorE0E1(a, a);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
+
+            SingleOpcode(opcode, v0: v0, v1: v1);
+
+            CompareAgainstUnicorn();
+        }
+
+        [Test, Pairwise, Description("CLS <Vd>.<T>, <Vn>.<T>")]
+        public void Cls_V_2S_4S([Values(0u)]     uint rd,
+                                [Values(1u, 0u)] uint rn,
+                                [ValueSource("_GenLeadingSigns2S_")] [Random(RndCnt)] ulong z,
+                                [ValueSource("_GenLeadingSigns2S_")] [Random(RndCnt)] ulong a,
+                                [Values(0b0u, 0b1u)] uint q) // <2S, 4S>
+        {
+            uint opcode = 0x0EA04800; // CLS V0.2S, V0.2S
+            opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
+            opcode |= ((q & 1) << 30);
+
+            Vector128<float> v0 = MakeVectorE0E1(z, z);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
 
             SingleOpcode(opcode, v0: v0, v1: v1);
 
@@ -1072,18 +1225,18 @@ namespace Ryujinx.Tests.Cpu
         }
 
         [Test, Pairwise, Description("CLZ <Vd>.<T>, <Vn>.<T>")]
-        public void Clz_V_8B_4H_2S([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) // <8B, 4H, 2S>
+        public void Clz_V_8B_16B([Values(0u)]     uint rd,
+                                 [Values(1u, 0u)] uint rn,
+                                 [ValueSource("_GenLeadingZeros8B_")] [Random(RndCnt)] ulong z,
+                                 [ValueSource("_GenLeadingZeros8B_")] [Random(RndCnt)] ulong a,
+                                 [Values(0b0u, 0b1u)] uint q) // <8B, 16B>
         {
             uint opcode = 0x2E204800; // CLZ V0.8B, V0.8B
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcode |= ((q & 1) << 30);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
-            Vector128<float> v1 = MakeVectorE0(a);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
 
             SingleOpcode(opcode, v0: v0, v1: v1);
 
@@ -1091,18 +1244,37 @@ namespace Ryujinx.Tests.Cpu
         }
 
         [Test, Pairwise, Description("CLZ <Vd>.<T>, <Vn>.<T>")]
-        public void Clz_V_16B_8H_4S([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) // <16B, 8H, 4S>
+        public void Clz_V_4H_8H([Values(0u)]     uint rd,
+                                [Values(1u, 0u)] uint rn,
+                                [ValueSource("_GenLeadingZeros4H_")] [Random(RndCnt)] ulong z,
+                                [ValueSource("_GenLeadingZeros4H_")] [Random(RndCnt)] ulong a,
+                                [Values(0b0u, 0b1u)] uint q) // <4H, 8H>
         {
-            uint opcode = 0x6E204800; // CLZ V0.16B, V0.16B
+            uint opcode = 0x2E604800; // CLZ V0.4H, V0.4H
             opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
-            opcode |= ((size & 3) << 22);
+            opcode |= ((q & 1) << 30);
 
             Vector128<float> v0 = MakeVectorE0E1(z, z);
-            Vector128<float> v1 = MakeVectorE0E1(a, a);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
+
+            SingleOpcode(opcode, v0: v0, v1: v1);
+
+            CompareAgainstUnicorn();
+        }
+
+        [Test, Pairwise, Description("CLZ <Vd>.<T>, <Vn>.<T>")]
+        public void Clz_V_2S_4S([Values(0u)]     uint rd,
+                                [Values(1u, 0u)] uint rn,
+                                [ValueSource("_GenLeadingZeros2S_")] [Random(RndCnt)] ulong z,
+                                [ValueSource("_GenLeadingZeros2S_")] [Random(RndCnt)] ulong a,
+                                [Values(0b0u, 0b1u)] uint q) // <2S, 4S>
+        {
+            uint opcode = 0x2EA04800; // CLZ V0.2S, V0.2S
+            opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
+            opcode |= ((q & 1) << 30);
+
+            Vector128<float> v0 = MakeVectorE0E1(z, z);
+            Vector128<float> v1 = MakeVectorE0E1(a, a * q);
 
             SingleOpcode(opcode, v0: v0, v1: v1);