CpuTestSimd32.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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
  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
  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
  34. [
  35. 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
  36. 0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
  37. 0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
  38. 0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul
  39. ];
  40. }
  41. private static IEnumerable<ulong> _1S_F_()
  42. {
  43. yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
  44. yield return 0x0000000080800000ul; // -Min Normal
  45. yield return 0x00000000807FFFFFul; // -Max Subnormal
  46. yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
  47. yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
  48. yield return 0x0000000000800000ul; // +Min Normal
  49. yield return 0x00000000007FFFFFul; // +Max Subnormal
  50. yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
  51. if (!_noZeros)
  52. {
  53. yield return 0x0000000080000000ul; // -Zero
  54. yield return 0x0000000000000000ul; // +Zero
  55. }
  56. if (!_noInfs)
  57. {
  58. yield return 0x00000000FF800000ul; // -Infinity
  59. yield return 0x000000007F800000ul; // +Infinity
  60. }
  61. if (!_noNaNs)
  62. {
  63. yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  64. yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
  65. yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  66. yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
  67. }
  68. for (int cnt = 1; cnt <= RndCnt; cnt++)
  69. {
  70. ulong grbg = TestContext.CurrentContext.Random.NextUInt();
  71. ulong rnd1 = GenNormalS();
  72. ulong rnd2 = GenSubnormalS();
  73. yield return (grbg << 32) | rnd1;
  74. yield return (grbg << 32) | rnd2;
  75. }
  76. }
  77. private static IEnumerable<ulong> _2S_F_()
  78. {
  79. yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
  80. yield return 0x8080000080800000ul; // -Min Normal
  81. yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
  82. yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
  83. yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
  84. yield return 0x0080000000800000ul; // +Min Normal
  85. yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
  86. yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
  87. if (!_noZeros)
  88. {
  89. yield return 0x8000000080000000ul; // -Zero
  90. yield return 0x0000000000000000ul; // +Zero
  91. }
  92. if (!_noInfs)
  93. {
  94. yield return 0xFF800000FF800000ul; // -Infinity
  95. yield return 0x7F8000007F800000ul; // +Infinity
  96. }
  97. if (!_noNaNs)
  98. {
  99. yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
  100. yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
  101. yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
  102. yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
  103. }
  104. for (int cnt = 1; cnt <= RndCnt; cnt++)
  105. {
  106. ulong rnd1 = GenNormalS();
  107. ulong rnd2 = GenSubnormalS();
  108. yield return (rnd1 << 32) | rnd1;
  109. yield return (rnd2 << 32) | rnd2;
  110. }
  111. }
  112. private static IEnumerable<ulong> _1D_F_()
  113. {
  114. yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
  115. yield return 0x8010000000000000ul; // -Min Normal
  116. yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
  117. yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
  118. yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
  119. yield return 0x0010000000000000ul; // +Min Normal
  120. yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
  121. yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
  122. if (!_noZeros)
  123. {
  124. yield return 0x8000000000000000ul; // -Zero
  125. yield return 0x0000000000000000ul; // +Zero
  126. }
  127. if (!_noInfs)
  128. {
  129. yield return 0xFFF0000000000000ul; // -Infinity
  130. yield return 0x7FF0000000000000ul; // +Infinity
  131. }
  132. if (!_noNaNs)
  133. {
  134. yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
  135. yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
  136. yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
  137. yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
  138. }
  139. for (int cnt = 1; cnt <= RndCnt; cnt++)
  140. {
  141. ulong rnd1 = GenNormalD();
  142. ulong rnd2 = GenSubnormalD();
  143. yield return rnd1;
  144. yield return rnd2;
  145. }
  146. }
  147. private static IEnumerable<ulong> _GenPopCnt8B_()
  148. {
  149. for (ulong cnt = 0ul; cnt <= 255ul; cnt++)
  150. {
  151. yield return (cnt << 56) | (cnt << 48) | (cnt << 40) | (cnt << 32) |
  152. (cnt << 24) | (cnt << 16) | (cnt << 08) | cnt;
  153. }
  154. }
  155. #endregion
  156. private const int RndCnt = 2;
  157. private static readonly bool _noZeros = false;
  158. private static readonly bool _noInfs = false;
  159. private static readonly bool _noNaNs = false;
  160. [Test, Pairwise, Description("SHA256SU0.32 <Qd>, <Qm>")]
  161. public void Sha256su0_V([Values(0xF3BA03C0u)] uint opcode,
  162. [Values(0u)] uint rd,
  163. [Values(2u)] uint rm,
  164. [Values(0x9BCBBF7443FB4F91ul)] ulong z0,
  165. [Values(0x482C58A58CBCBD59ul)] ulong z1,
  166. [Values(0xA0099B803625F82Aul)] ulong a0,
  167. [Values(0x1AA3B0B4E1AB4C8Cul)] ulong a1,
  168. [Values(0x29A44D72598F15F3ul)] ulong resultL,
  169. [Values(0x74CED221E2793F07ul)] ulong resultH)
  170. {
  171. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  172. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  173. V128 v0 = MakeVectorE0E1(z0, z1);
  174. V128 v1 = MakeVectorE0E1(a0, a1);
  175. ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, runUnicorn: false);
  176. Assert.Multiple(() =>
  177. {
  178. Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
  179. Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
  180. });
  181. // Unicorn does not yet support hash instructions in A32.
  182. // CompareAgainstUnicorn();
  183. }
  184. [Test, Pairwise]
  185. public void Vabs_Vneg_Vpaddl_V_I([ValueSource(nameof(_Vabs_Vneg_Vpaddl_I_))] uint opcode,
  186. [Range(0u, 3u)] uint rd,
  187. [Range(0u, 3u)] uint rm,
  188. [ValueSource(nameof(_8B4H2S_))] ulong z,
  189. [ValueSource(nameof(_8B4H2S_))] ulong b,
  190. [Values(0u, 1u, 2u)] uint size, // <S8, S16, S32>
  191. [Values] bool q)
  192. {
  193. if (q)
  194. {
  195. opcode |= 1 << 6;
  196. rd >>= 1;
  197. rd <<= 1;
  198. rm >>= 1;
  199. rm <<= 1;
  200. }
  201. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  202. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  203. opcode |= (size & 0x3) << 18;
  204. V128 v0 = MakeVectorE0E1(z, ~z);
  205. V128 v1 = MakeVectorE0E1(b, ~b);
  206. SingleOpcode(opcode, v0: v0, v1: v1);
  207. CompareAgainstUnicorn();
  208. }
  209. [Test, Pairwise]
  210. public void Vabs_Vneg_V_F32([ValueSource(nameof(_Vabs_Vneg_F_))] uint opcode,
  211. [Range(0u, 3u)] uint rd,
  212. [Range(0u, 3u)] uint rm,
  213. [ValueSource(nameof(_2S_F_))] ulong z,
  214. [ValueSource(nameof(_2S_F_))] ulong b,
  215. [Values] bool q)
  216. {
  217. if (q)
  218. {
  219. opcode |= 1 << 6;
  220. rd >>= 1;
  221. rd <<= 1;
  222. rm >>= 1;
  223. rm <<= 1;
  224. }
  225. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  226. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  227. V128 v0 = MakeVectorE0E1(z, ~z);
  228. V128 v1 = MakeVectorE0E1(b, ~b);
  229. SingleOpcode(opcode, v0: v0, v1: v1);
  230. CompareAgainstUnicorn();
  231. }
  232. [Test, Pairwise, Description("VCNT.8 D0, D0 | VCNT.8 Q0, Q0")]
  233. public void Vcnt([Values(0u, 1u)] uint rd,
  234. [Values(0u, 1u)] uint rm,
  235. [ValueSource(nameof(_GenPopCnt8B_))] ulong d0,
  236. [Values] bool q)
  237. {
  238. ulong d1 = ~d0; // It's expensive to have a second generator.
  239. uint opcode = 0xf3b00500u; // VCNT.8 D0, D0
  240. if (q)
  241. {
  242. opcode |= 1u << 6;
  243. rd &= ~1u;
  244. rm &= ~1u;
  245. }
  246. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  247. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  248. V128 v0 = MakeVectorE0E1(d0, d1);
  249. SingleOpcode(opcode, v0: v0);
  250. CompareAgainstUnicorn();
  251. }
  252. [Test, Pairwise]
  253. public void Vmovn_V([Range(0u, 3u)] uint rd,
  254. [Range(0u, 3u)] uint rm,
  255. [ValueSource(nameof(_8B4H2S_))] ulong z,
  256. [ValueSource(nameof(_8B4H2S_))] ulong b,
  257. [Values(0u, 1u, 2u, 3u)] uint op,
  258. [Values(0u, 1u, 2u)] uint size) // <S8, S16, S32>
  259. {
  260. rm >>= 1;
  261. rm <<= 1;
  262. uint opcode = 0xf3b20200u; // VMOVN.S16 D0, Q0
  263. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  264. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  265. opcode |= (op & 0x3) << 6;
  266. opcode |= (size & 0x3) << 18;
  267. V128 v0 = MakeVectorE0E1(z, ~z);
  268. V128 v1 = MakeVectorE0E1(b, ~b);
  269. SingleOpcode(opcode, v0: v0, v1: v1);
  270. CompareAgainstUnicorn();
  271. }
  272. [Test, Pairwise, Description("VSHLL.<size> {<Vd>}, <Vm>, #<imm>")]
  273. public void Vshll([Values(0u, 2u)] uint rd,
  274. [Values(1u, 0u)] uint rm,
  275. [Values(0u, 1u, 2u)] uint size,
  276. [Random(RndCnt)] ulong z,
  277. [Random(RndCnt)] ulong a,
  278. [Random(RndCnt)] ulong b)
  279. {
  280. uint opcode = 0xf3b20300u; // VSHLL.I8 Q0, D0, #8
  281. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  282. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  283. opcode |= size << 18;
  284. V128 v0 = MakeVectorE0E1(z, z);
  285. V128 v1 = MakeVectorE0E1(a, z);
  286. V128 v2 = MakeVectorE0E1(b, z);
  287. SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
  288. CompareAgainstUnicorn();
  289. }
  290. [Test, Pairwise, Description("VSWP D0, D0")]
  291. public void Vswp([Values(0u, 1u)] uint rd,
  292. [Values(0u, 1u)] uint rm,
  293. [Values] bool q)
  294. {
  295. uint opcode = 0xf3b20000u; // VSWP D0, D0
  296. if (q)
  297. {
  298. opcode |= 1u << 6;
  299. rd &= ~1u;
  300. rm &= ~1u;
  301. }
  302. opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
  303. opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
  304. V128 v0 = new(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
  305. V128 v1 = new(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
  306. SingleOpcode(opcode, v0: v0, v1: v1);
  307. CompareAgainstUnicorn();
  308. }
  309. #endif
  310. }
  311. }