CpuTestSimdReg32.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. #define SimdReg32
  2. using ARMeilleure.State;
  3. using NUnit.Framework;
  4. using System;
  5. using System.Collections.Generic;
  6. namespace Ryujinx.Tests.Cpu
  7. {
  8. [Category("SimdReg32")]
  9. public sealed class CpuTestSimdReg32 : CpuTest32
  10. {
  11. #if SimdReg32
  12. #region "ValueSource (Opcodes)"
  13. private static uint[] _V_Add_Sub_Wide_I_()
  14. {
  15. return new uint[]
  16. {
  17. 0xf2800100u, // VADDW.S8 Q0, Q0, D0
  18. 0xf2800300u // VSUBW.S8 Q0, Q0, D0
  19. };
  20. }
  21. private static uint[] _Vp_Add_Max_Min_F_()
  22. {
  23. return new uint[]
  24. {
  25. 0xf3000d00u, // VPADD.F32 D0, D0, D0
  26. 0xf3000f00u, // VPMAX.F32 D0, D0, D0
  27. 0xf3200f00u // VPMIN.F32 D0, D0, D0
  28. };
  29. }
  30. // VPADD does not have an unsigned flag, so we check the opcode before setting it.
  31. private static uint VpaddI8 = 0xf2000b10u; // VPADD.I8 D0, D0, D0
  32. private static uint[] _Vp_Add_Max_Min_I_()
  33. {
  34. return new uint[]
  35. {
  36. VpaddI8,
  37. 0xf2000a00u, // VPMAX.S8 D0, D0, D0
  38. 0xf2000a10u // VPMIN.S8 D0, D0, D0
  39. };
  40. }
  41. #endregion
  42. #region "ValueSource (Types)"
  43. private static ulong[] _8B4H2S1D_()
  44. {
  45. return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
  46. 0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
  47. 0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
  48. 0x8000000080000000ul, 0x7FFFFFFFFFFFFFFFul,
  49. 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
  50. }
  51. private static IEnumerable<ulong> _1S_F_()
  52. {
  53. yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
  54. yield return 0x0000000080800000ul; // -Min Normal
  55. yield return 0x00000000807FFFFFul; // -Max Subnormal
  56. yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
  57. yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
  58. yield return 0x0000000000800000ul; // +Min Normal
  59. yield return 0x00000000007FFFFFul; // +Max Subnormal
  60. yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
  61. if (!NoZeros)
  62. {
  63. yield return 0x0000000080000000ul; // -Zero
  64. yield return 0x0000000000000000ul; // +Zero
  65. }
  66. if (!NoInfs)
  67. {
  68. yield return 0x00000000FF800000ul; // -Infinity
  69. yield return 0x000000007F800000ul; // +Infinity
  70. }
  71. if (!NoNaNs)
  72. {
  73. yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  74. yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
  75. yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  76. yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
  77. }
  78. for (int cnt = 1; cnt <= RndCnt; cnt++)
  79. {
  80. ulong grbg = TestContext.CurrentContext.Random.NextUInt();
  81. ulong rnd1 = GenNormalS();
  82. ulong rnd2 = GenSubnormalS();
  83. yield return (grbg << 32) | rnd1;
  84. yield return (grbg << 32) | rnd2;
  85. }
  86. }
  87. private static IEnumerable<ulong> _2S_F_()
  88. {
  89. yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
  90. yield return 0x8080000080800000ul; // -Min Normal
  91. yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
  92. yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
  93. yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
  94. yield return 0x0080000000800000ul; // +Min Normal
  95. yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
  96. yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
  97. if (!NoZeros)
  98. {
  99. yield return 0x8000000080000000ul; // -Zero
  100. yield return 0x0000000000000000ul; // +Zero
  101. }
  102. if (!NoInfs)
  103. {
  104. yield return 0xFF800000FF800000ul; // -Infinity
  105. yield return 0x7F8000007F800000ul; // +Infinity
  106. }
  107. if (!NoNaNs)
  108. {
  109. yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  110. yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
  111. yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  112. yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
  113. }
  114. for (int cnt = 1; cnt <= RndCnt; cnt++)
  115. {
  116. ulong rnd1 = GenNormalS();
  117. ulong rnd2 = GenSubnormalS();
  118. yield return (rnd1 << 32) | rnd1;
  119. yield return (rnd2 << 32) | rnd2;
  120. }
  121. }
  122. private static IEnumerable<ulong> _1D_F_()
  123. {
  124. yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
  125. yield return 0x8010000000000000ul; // -Min Normal
  126. yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
  127. yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
  128. yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
  129. yield return 0x0010000000000000ul; // +Min Normal
  130. yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
  131. yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
  132. if (!NoZeros)
  133. {
  134. yield return 0x8000000000000000ul; // -Zero
  135. yield return 0x0000000000000000ul; // +Zero
  136. }
  137. if (!NoInfs)
  138. {
  139. yield return 0xFFF0000000000000ul; // -Infinity
  140. yield return 0x7FF0000000000000ul; // +Infinity
  141. }
  142. if (!NoNaNs)
  143. {
  144. yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
  145. yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
  146. yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
  147. yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
  148. }
  149. for (int cnt = 1; cnt <= RndCnt; cnt++)
  150. {
  151. ulong rnd1 = GenNormalD();
  152. ulong rnd2 = GenSubnormalD();
  153. yield return rnd1;
  154. yield return rnd2;
  155. }
  156. }
  157. #endregion
  158. private const int RndCnt = 2;
  159. private static readonly bool NoZeros = false;
  160. private static readonly bool NoInfs = false;
  161. private static readonly bool NoNaNs = false;
  162. [Explicit]
  163. [Test, Pairwise, Description("VADD.f32 V0, V0, V0")]
  164. public void Vadd_f32([Values(0u)] uint rd,
  165. [Values(0u, 1u)] uint rn,
  166. [Values(0u, 2u)] uint rm,
  167. [ValueSource("_2S_F_")] ulong z0,
  168. [ValueSource("_2S_F_")] ulong z1,
  169. [ValueSource("_2S_F_")] ulong a0,
  170. [ValueSource("_2S_F_")] ulong a1,
  171. [ValueSource("_2S_F_")] ulong b0,
  172. [ValueSource("_2S_F_")] ulong b1,
  173. [Values] bool q)
  174. {
  175. uint opcode = 0xf2000d00u; // VADD.F32 D0, D0, D0
  176. if (q)
  177. {
  178. opcode |= 1 << 6;
  179. rm <<= 1;
  180. rn <<= 1;
  181. rd <<= 1;
  182. }
  183. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  184. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  185. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  186. V128 v0 = MakeVectorE0E1(z0, z1);
  187. V128 v1 = MakeVectorE0E1(a0, a1);
  188. V128 v2 = MakeVectorE0E1(b0, b1);
  189. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  190. CompareAgainstUnicorn();
  191. }
  192. [Test, Pairwise]
  193. public void V_Add_Sub_Wide_I([ValueSource("_V_Add_Sub_Wide_I_")] uint opcode,
  194. [Range(0u, 5u)] uint rd,
  195. [Range(0u, 5u)] uint rn,
  196. [Range(0u, 5u)] uint rm,
  197. [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong z,
  198. [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong a,
  199. [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong b,
  200. [Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32>
  201. [Values] bool u) // <S, U>
  202. {
  203. if (u)
  204. {
  205. opcode |= 1 << 24;
  206. }
  207. rd >>= 1; rd <<= 1;
  208. rn >>= 1; rn <<= 1;
  209. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  210. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  211. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  212. opcode |= (size & 0x3) << 20;
  213. V128 v0 = MakeVectorE0E1(z, ~z);
  214. V128 v1 = MakeVectorE0E1(a, ~a);
  215. V128 v2 = MakeVectorE0E1(b, ~b);
  216. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  217. CompareAgainstUnicorn();
  218. }
  219. [Test, Pairwise, Description("VCMP.f<size> Vd, Vm")]
  220. public void Vcmp([Values(2u, 3u)] uint size,
  221. [ValueSource("_1S_F_")] ulong a,
  222. [ValueSource("_1S_F_")] ulong b,
  223. [Values] bool e)
  224. {
  225. uint opcode = 0xeeb40840u;
  226. uint rm = 1;
  227. uint rd = 2;
  228. if (size == 3)
  229. {
  230. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  231. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  232. }
  233. else
  234. {
  235. opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
  236. opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
  237. }
  238. opcode |= ((size & 3) << 8);
  239. if (e)
  240. {
  241. opcode |= 1 << 7;
  242. }
  243. V128 v1 = MakeVectorE0(a);
  244. V128 v2 = MakeVectorE0(b);
  245. int fpscr = (int)(TestContext.CurrentContext.Random.NextUInt(0xf) << 28);
  246. SingleOpcode(opcode, v1: v1, v2: v2, fpscr: fpscr);
  247. CompareAgainstUnicorn(fpsrMask: Fpsr.Nzcv);
  248. }
  249. [Test, Pairwise, Description("VMLSL.<type><size> <Vd>, <Vn>, <Vm>")]
  250. public void Vmlsl_I([Values(0u)] uint rd,
  251. [Values(1u, 0u)] uint rn,
  252. [Values(2u, 0u)] uint rm,
  253. [Values(0u, 1u, 2u)] uint size,
  254. [Random(RndCnt)] ulong z,
  255. [Random(RndCnt)] ulong a,
  256. [Random(RndCnt)] ulong b,
  257. [Values] bool u)
  258. {
  259. uint opcode = 0xf2800a00u; // VMLSL.S8 Q0, D0, D0
  260. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  261. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  262. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  263. opcode |= size << 20;
  264. if (u)
  265. {
  266. opcode |= 1 << 24;
  267. }
  268. V128 v0 = MakeVectorE0E1(z, z);
  269. V128 v1 = MakeVectorE0E1(a, z);
  270. V128 v2 = MakeVectorE0E1(b, z);
  271. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  272. CompareAgainstUnicorn();
  273. }
  274. [Test, Pairwise, Description("VMULL.<size> <Vd>, <Vn>, <Vm>")]
  275. public void Vmull_I([Values(0u)] uint rd,
  276. [Values(1u, 0u)] uint rn,
  277. [Values(2u, 0u)] uint rm,
  278. [Values(0u, 1u, 2u)] uint size,
  279. [Random(RndCnt)] ulong z,
  280. [Random(RndCnt)] ulong a,
  281. [Random(RndCnt)] ulong b,
  282. [Values] bool op,
  283. [Values] bool u)
  284. {
  285. uint opcode = 0xf2800c00u; // VMULL.S8 Q0, D0, D0
  286. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  287. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  288. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  289. if (op)
  290. {
  291. opcode |= 1 << 9;
  292. size = 0;
  293. u = false;
  294. }
  295. opcode |= size << 20;
  296. if (u)
  297. {
  298. opcode |= 1 << 24;
  299. }
  300. V128 v0 = MakeVectorE0E1(z, z);
  301. V128 v1 = MakeVectorE0E1(a, z);
  302. V128 v2 = MakeVectorE0E1(b, z);
  303. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  304. CompareAgainstUnicorn();
  305. }
  306. [Test, Pairwise, Description("VSHL.<size> {<Vd>}, <Vm>, <Vn>")]
  307. public void Vshl([Values(0u)] uint rd,
  308. [Values(1u, 0u)] uint rn,
  309. [Values(2u, 0u)] uint rm,
  310. [Values(0u, 1u, 2u, 3u)] uint size,
  311. [Random(RndCnt)] ulong z,
  312. [Random(RndCnt)] ulong a,
  313. [Random(RndCnt)] ulong b,
  314. [Values] bool q,
  315. [Values] bool u)
  316. {
  317. uint opcode = 0xf2000400u; // VSHL.S8 D0, D0, D0
  318. if (q)
  319. {
  320. opcode |= 1 << 6;
  321. rm <<= 1;
  322. rn <<= 1;
  323. rd <<= 1;
  324. }
  325. if (u)
  326. {
  327. opcode |= 1 << 24;
  328. }
  329. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  330. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  331. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  332. opcode |= size << 20;
  333. V128 v0 = MakeVectorE0E1(z, z);
  334. V128 v1 = MakeVectorE0E1(a, z);
  335. V128 v2 = MakeVectorE0E1(b, z);
  336. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  337. CompareAgainstUnicorn();
  338. }
  339. [Explicit]
  340. [Test, Pairwise]
  341. public void Vp_Add_Max_Min_F([ValueSource("_Vp_Add_Max_Min_F_")] uint opcode,
  342. [Values(0u)] uint rd,
  343. [Range(0u, 7u)] uint rn,
  344. [Range(0u, 7u)] uint rm,
  345. [ValueSource("_2S_F_")] ulong z0,
  346. [ValueSource("_2S_F_")] ulong z1,
  347. [ValueSource("_2S_F_")] ulong a0,
  348. [ValueSource("_2S_F_")] ulong a1,
  349. [ValueSource("_2S_F_")] ulong b0,
  350. [ValueSource("_2S_F_")] ulong b1)
  351. {
  352. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  353. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  354. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  355. var rnd = TestContext.CurrentContext.Random;
  356. V128 v0 = MakeVectorE0E1(z0, z1);
  357. V128 v1 = MakeVectorE0E1(a0, a1);
  358. V128 v2 = MakeVectorE0E1(b0, b1);
  359. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  360. CompareAgainstUnicorn();
  361. }
  362. [Test, Pairwise]
  363. public void Vp_Add_Max_Min_I([ValueSource("_Vp_Add_Max_Min_I_")] uint opcode,
  364. [Values(0u)] uint rd,
  365. [Range(0u, 5u)] uint rn,
  366. [Range(0u, 5u)] uint rm,
  367. [Values(0u, 1u, 2u)] uint size,
  368. [Random(RndCnt)] ulong z,
  369. [Random(RndCnt)] ulong a,
  370. [Random(RndCnt)] ulong b,
  371. [Values] bool u)
  372. {
  373. if (u && opcode != VpaddI8)
  374. {
  375. opcode |= 1 << 24;
  376. }
  377. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  378. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  379. opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
  380. opcode |= size << 20;
  381. V128 v0 = MakeVectorE0E1(z, z);
  382. V128 v1 = MakeVectorE0E1(a, z);
  383. V128 v2 = MakeVectorE0E1(b, z);
  384. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  385. CompareAgainstUnicorn();
  386. }
  387. #endif
  388. }
  389. }