CpuTestSimd32.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #define Simd32
  2. using ARMeilleure.State;
  3. using NUnit.Framework;
  4. using System.Collections.Generic;
  5. namespace Ryujinx.Tests.Cpu
  6. {
  7. [Category("Simd32")]
  8. public sealed class CpuTestSimd32 : CpuTest32
  9. {
  10. #if Simd32
  11. #region "ValueSource (Opcodes)"
  12. private static uint[] _Vabs_Vneg_Vpaddl_I_()
  13. {
  14. return new uint[]
  15. {
  16. 0xf3b10300u, // VABS.S8 D0, D0
  17. 0xf3b10380u, // VNEG.S8 D0, D0
  18. 0xf3b00200u // VPADDL.S8 D0, D0
  19. };
  20. }
  21. private static uint[] _Vabs_Vneg_F_()
  22. {
  23. return new uint[]
  24. {
  25. 0xf3b90700u, // VABS.F32 D0, D0
  26. 0xf3b90780u // VNEG.F32 D0, D0
  27. };
  28. }
  29. #endregion
  30. #region "ValueSource (Types)"
  31. private static ulong[] _8B4H2S_()
  32. {
  33. return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
  34. 0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
  35. 0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
  36. 0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
  37. }
  38. private static IEnumerable<ulong> _1S_F_()
  39. {
  40. yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
  41. yield return 0x0000000080800000ul; // -Min Normal
  42. yield return 0x00000000807FFFFFul; // -Max Subnormal
  43. yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
  44. yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
  45. yield return 0x0000000000800000ul; // +Min Normal
  46. yield return 0x00000000007FFFFFul; // +Max Subnormal
  47. yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
  48. if (!NoZeros)
  49. {
  50. yield return 0x0000000080000000ul; // -Zero
  51. yield return 0x0000000000000000ul; // +Zero
  52. }
  53. if (!NoInfs)
  54. {
  55. yield return 0x00000000FF800000ul; // -Infinity
  56. yield return 0x000000007F800000ul; // +Infinity
  57. }
  58. if (!NoNaNs)
  59. {
  60. yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  61. yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
  62. yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  63. yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
  64. }
  65. for (int cnt = 1; cnt <= RndCnt; cnt++)
  66. {
  67. ulong grbg = TestContext.CurrentContext.Random.NextUInt();
  68. ulong rnd1 = GenNormalS();
  69. ulong rnd2 = GenSubnormalS();
  70. yield return (grbg << 32) | rnd1;
  71. yield return (grbg << 32) | rnd2;
  72. }
  73. }
  74. private static IEnumerable<ulong> _2S_F_()
  75. {
  76. yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
  77. yield return 0x8080000080800000ul; // -Min Normal
  78. yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
  79. yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
  80. yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
  81. yield return 0x0080000000800000ul; // +Min Normal
  82. yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
  83. yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
  84. if (!NoZeros)
  85. {
  86. yield return 0x8000000080000000ul; // -Zero
  87. yield return 0x0000000000000000ul; // +Zero
  88. }
  89. if (!NoInfs)
  90. {
  91. yield return 0xFF800000FF800000ul; // -Infinity
  92. yield return 0x7F8000007F800000ul; // +Infinity
  93. }
  94. if (!NoNaNs)
  95. {
  96. yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  97. yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
  98. yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  99. yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
  100. }
  101. for (int cnt = 1; cnt <= RndCnt; cnt++)
  102. {
  103. ulong rnd1 = GenNormalS();
  104. ulong rnd2 = GenSubnormalS();
  105. yield return (rnd1 << 32) | rnd1;
  106. yield return (rnd2 << 32) | rnd2;
  107. }
  108. }
  109. private static IEnumerable<ulong> _1D_F_()
  110. {
  111. yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
  112. yield return 0x8010000000000000ul; // -Min Normal
  113. yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
  114. yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
  115. yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
  116. yield return 0x0010000000000000ul; // +Min Normal
  117. yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
  118. yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
  119. if (!NoZeros)
  120. {
  121. yield return 0x8000000000000000ul; // -Zero
  122. yield return 0x0000000000000000ul; // +Zero
  123. }
  124. if (!NoInfs)
  125. {
  126. yield return 0xFFF0000000000000ul; // -Infinity
  127. yield return 0x7FF0000000000000ul; // +Infinity
  128. }
  129. if (!NoNaNs)
  130. {
  131. yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
  132. yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
  133. yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
  134. yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
  135. }
  136. for (int cnt = 1; cnt <= RndCnt; cnt++)
  137. {
  138. ulong rnd1 = GenNormalD();
  139. ulong rnd2 = GenSubnormalD();
  140. yield return rnd1;
  141. yield return rnd2;
  142. }
  143. }
  144. private static IEnumerable<ulong> _GenPopCnt8B_()
  145. {
  146. for (ulong cnt = 0ul; cnt <= 255ul; cnt++)
  147. {
  148. yield return (cnt << 56) | (cnt << 48) | (cnt << 40) | (cnt << 32) |
  149. (cnt << 24) | (cnt << 16) | (cnt << 08) | cnt;
  150. }
  151. }
  152. #endregion
  153. private const int RndCnt = 2;
  154. private static readonly bool NoZeros = false;
  155. private static readonly bool NoInfs = false;
  156. private static readonly bool NoNaNs = false;
  157. [Test, Pairwise, Description("SHA256SU0.32 <Qd>, <Qm>")]
  158. public void Sha256su0_V([Values(0xF3BA03C0u)] uint opcode,
  159. [Values(0u)] uint rd,
  160. [Values(2u)] uint rm,
  161. [Values(0x9BCBBF7443FB4F91ul)] ulong z0,
  162. [Values(0x482C58A58CBCBD59ul)] ulong z1,
  163. [Values(0xA0099B803625F82Aul)] ulong a0,
  164. [Values(0x1AA3B0B4E1AB4C8Cul)] ulong a1,
  165. [Values(0x29A44D72598F15F3ul)] ulong resultL,
  166. [Values(0x74CED221E2793F07ul)] ulong resultH)
  167. {
  168. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  169. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  170. V128 v0 = MakeVectorE0E1(z0, z1);
  171. V128 v1 = MakeVectorE0E1(a0, a1);
  172. ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, runUnicorn: false);
  173. Assert.Multiple(() =>
  174. {
  175. Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
  176. Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
  177. });
  178. // Unicorn does not yet support hash instructions in A32.
  179. // CompareAgainstUnicorn();
  180. }
  181. [Test, Pairwise]
  182. public void Vabs_Vneg_Vpaddl_V_I([ValueSource("_Vabs_Vneg_Vpaddl_I_")] uint opcode,
  183. [Range(0u, 3u)] uint rd,
  184. [Range(0u, 3u)] uint rm,
  185. [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
  186. [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
  187. [Values(0u, 1u, 2u)] uint size, // <S8, S16, S32>
  188. [Values] bool q)
  189. {
  190. if (q)
  191. {
  192. opcode |= 1 << 6;
  193. rd >>= 1; rd <<= 1;
  194. rm >>= 1; rm <<= 1;
  195. }
  196. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  197. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  198. opcode |= (size & 0x3) << 18;
  199. V128 v0 = MakeVectorE0E1(z, ~z);
  200. V128 v1 = MakeVectorE0E1(b, ~b);
  201. SingleOpcode(opcode, v0: v0, v1: v1);
  202. CompareAgainstUnicorn();
  203. }
  204. [Test, Pairwise]
  205. public void Vabs_Vneg_V_F32([ValueSource("_Vabs_Vneg_F_")] uint opcode,
  206. [Range(0u, 3u)] uint rd,
  207. [Range(0u, 3u)] uint rm,
  208. [ValueSource("_2S_F_")] ulong z,
  209. [ValueSource("_2S_F_")] ulong b,
  210. [Values] bool q)
  211. {
  212. if (q)
  213. {
  214. opcode |= 1 << 6;
  215. rd >>= 1; rd <<= 1;
  216. rm >>= 1; rm <<= 1;
  217. }
  218. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  219. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  220. V128 v0 = MakeVectorE0E1(z, ~z);
  221. V128 v1 = MakeVectorE0E1(b, ~b);
  222. SingleOpcode(opcode, v0: v0, v1: v1);
  223. CompareAgainstUnicorn();
  224. }
  225. [Test, Pairwise, Description("VCNT.8 D0, D0 | VCNT.8 Q0, Q0")]
  226. public void Vcnt([Values(0u, 1u)] uint rd,
  227. [Values(0u, 1u)] uint rm,
  228. [ValueSource(nameof(_GenPopCnt8B_))] [Random(RndCnt)] ulong d0,
  229. [Values] bool q)
  230. {
  231. ulong d1 = ~d0; // It's expensive to have a second generator.
  232. uint opcode = 0xf3b00500u; // VCNT.8 D0, D0
  233. if (q)
  234. {
  235. opcode |= 1u << 6;
  236. rd &= ~1u;
  237. rm &= ~1u;
  238. }
  239. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  240. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  241. V128 v0 = MakeVectorE0E1(d0, d1);
  242. SingleOpcode(opcode, v0: v0);
  243. CompareAgainstUnicorn();
  244. }
  245. [Test, Pairwise]
  246. public void Vmovn_V([Range(0u, 3u)] uint rd,
  247. [Range(0u, 3u)] uint rm,
  248. [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z,
  249. [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b,
  250. [Values(0u, 1u, 2u, 3u)] uint op,
  251. [Values(0u, 1u, 2u)] uint size) // <S8, S16, S32>
  252. {
  253. rm >>= 1; rm <<= 1;
  254. uint opcode = 0xf3b20200u; // VMOVN.S16 D0, Q0
  255. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  256. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  257. opcode |= (op & 0x3) << 6;
  258. opcode |= (size & 0x3) << 18;
  259. V128 v0 = MakeVectorE0E1(z, ~z);
  260. V128 v1 = MakeVectorE0E1(b, ~b);
  261. SingleOpcode(opcode, v0: v0, v1: v1);
  262. CompareAgainstUnicorn();
  263. }
  264. #endif
  265. }
  266. }