TestAluFpu.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. //RandomX ALU + FPU test
  2. //https://github.com/tevador/RandomX
  3. //License: GPL v3
  4. #include <iostream>
  5. #include <iomanip>
  6. #include <limits>
  7. #include "Instructions.h"
  8. using namespace RandomX;
  9. typedef void(*VmOperation)(convertible_t&, convertible_t&, convertible_t&);
  10. double rxRound(uint32_t mode, int64_t x, int64_t y, VmOperation op) {
  11. convertible_t a, b, c;
  12. a.u64 = mode;
  13. FROUND(a, b, c);
  14. a.i64 = x;
  15. b.i64 = y;
  16. op(a, b, c);
  17. return c.f64;
  18. }
  19. #define CATCH_CONFIG_MAIN
  20. #include "catch.hpp"
  21. #define RX_EXECUTE_U64(va, vb, INST) do { \
  22. a.u64 = va; \
  23. b.u64 = vb; \
  24. INST(a, b, c); \
  25. } while(false)
  26. #define RX_EXECUTE_I64(va, vb, INST) do { \
  27. a.i64 = va; \
  28. b.i64 = vb; \
  29. INST(a, b, c); \
  30. } while(false)
  31. TEST_CASE("Integer addition (64-bit)", "[ADD_64]") {
  32. convertible_t a, b, c;
  33. RX_EXECUTE_U64(0xFFFFFFFF, 0x1, ADD_64);
  34. REQUIRE(c.u64 == 0x100000000);
  35. RX_EXECUTE_U64(0x8000000000000000, 0x8000000000000000, ADD_64);
  36. REQUIRE(c.u64 == 0x0);
  37. }
  38. TEST_CASE("Integer addition (32-bit)", "[ADD_32]") {
  39. convertible_t a, b, c;
  40. RX_EXECUTE_U64(0xFFFFFFFF, 0x1, ADD_32);
  41. REQUIRE(c.u64 == 0);
  42. RX_EXECUTE_U64(0xFF00000000000001, 0x0000000100000001, ADD_32);
  43. REQUIRE(c.u64 == 2);
  44. }
  45. TEST_CASE("Integer subtraction (64-bit)", "[SUB_64]") {
  46. convertible_t a, b, c;
  47. RX_EXECUTE_U64(1, 0xFFFFFFFF, SUB_64);
  48. REQUIRE(c.u64 == 0xFFFFFFFF00000002);
  49. }
  50. TEST_CASE("Integer subtraction (32-bit)", "[SUB_32]") {
  51. convertible_t a, b, c;
  52. RX_EXECUTE_U64(1, 0xFFFFFFFF, SUB_32);
  53. REQUIRE(c.u64 == 2);
  54. }
  55. TEST_CASE("Unsigned multiplication (64-bit, low half)", "[MUL_64]") {
  56. convertible_t a, b, c;
  57. RX_EXECUTE_U64(0xBC550E96BA88A72B, 0xF5391FA9F18D6273, MUL_64);
  58. REQUIRE(c.u64 == 0x28723424A9108E51);
  59. }
  60. TEST_CASE("Unsigned multiplication (64-bit, high half)", "[MULH_64]") {
  61. convertible_t a, b, c;
  62. RX_EXECUTE_U64(0xBC550E96BA88A72B, 0xF5391FA9F18D6273, MULH_64);
  63. REQUIRE(c.u64 == 0xB4676D31D2B34883);
  64. }
  65. TEST_CASE("Unsigned multiplication (32-bit x 32-bit -> 64-bit)", "[MUL_32]") {
  66. convertible_t a, b, c;
  67. RX_EXECUTE_U64(0xBC550E96BA88A72B, 0xF5391FA9F18D6273, MUL_32);
  68. REQUIRE(c.u64 == 0xB001AA5FA9108E51);
  69. }
  70. TEST_CASE("Signed multiplication (32-bit x 32-bit -> 64-bit)", "[IMUL_32]") {
  71. convertible_t a, b, c;
  72. RX_EXECUTE_U64(0xBC550E96BA88A72B, 0xF5391FA9F18D6273, IMUL_32);
  73. REQUIRE(c.u64 == 0x03EBA0C1A9108E51);
  74. }
  75. TEST_CASE("Signed multiplication (64-bit, high half)", "[IMULH_64]") {
  76. convertible_t a, b, c;
  77. RX_EXECUTE_U64(0xBC550E96BA88A72B, 0xF5391FA9F18D6273, IMULH_64);
  78. REQUIRE(c.u64 == 0x02D93EF1269D3EE5);
  79. }
  80. TEST_CASE("Unsigned division (64-bit / 32-bit -> 32-bit)", "[DIV_64]") {
  81. convertible_t a, b, c;
  82. RX_EXECUTE_U64(8774217225983458895, 3014068202, DIV_64);
  83. REQUIRE(c.u64 == 2911087818);
  84. RX_EXECUTE_U64(8774217225983458895, 0, DIV_64);
  85. REQUIRE(c.u64 == 8774217225983458895);
  86. RX_EXECUTE_U64(3014068202, 8774217225983458895, DIV_64);
  87. REQUIRE(c.u64 == 2);
  88. }
  89. TEST_CASE("Signed division (64-bit / 32-bit -> 32-bit)", "[IDIV_64]") {
  90. convertible_t a, b, c;
  91. RX_EXECUTE_U64(8774217225983458895, 3014068202, IDIV_64);
  92. REQUIRE(c.u64 == 0xFFFFFFFE67B4994E);
  93. RX_EXECUTE_U64(8774217225983458895, 0, IDIV_64);
  94. REQUIRE(c.u64 == 8774217225983458895);
  95. RX_EXECUTE_U64(0x8000000000000000, 0xFFFFFFFFFFFFFFFF, IDIV_64);
  96. REQUIRE(c.u64 == 0x8000000000000000);
  97. RX_EXECUTE_U64(0xFFFFFFFFB3A707EA, 8774217225983458895, IDIV_64);
  98. REQUIRE(c.u64 == 0xFFFFFFFFFFFFFFFF);
  99. }
  100. TEST_CASE("Bitwise AND (64-bit)", "[AND_64]") {
  101. convertible_t a, b, c;
  102. RX_EXECUTE_U64(0xCCCCCCCCCCCCCCCC, 0xAAAAAAAAAAAAAAAA, AND_64);
  103. REQUIRE(c.u64 == 0x8888888888888888);
  104. }
  105. TEST_CASE("Bitwise AND (32-bit)", "[AND_32]") {
  106. convertible_t a, b, c;
  107. RX_EXECUTE_U64(0xCCCCCCCCCCCCCCCC, 0xAAAAAAAAAAAAAAAA, AND_32);
  108. REQUIRE(c.u64 == 0x88888888);
  109. }
  110. TEST_CASE("Bitwise OR (64-bit)", "[OR_64]") {
  111. convertible_t a, b, c;
  112. RX_EXECUTE_U64(0x4444444444444444, 0xAAAAAAAAAAAAAAAA, OR_64);
  113. REQUIRE(c.u64 == 0xEEEEEEEEEEEEEEEE);
  114. }
  115. TEST_CASE("Bitwise OR (32-bit)", "[OR_32]") {
  116. convertible_t a, b, c;
  117. RX_EXECUTE_U64(0x4444444444444444, 0xAAAAAAAAAAAAAAAA, OR_32);
  118. REQUIRE(c.u64 == 0xEEEEEEEE);
  119. }
  120. TEST_CASE("Bitwise XOR (64-bit)", "[XOR_64]") {
  121. convertible_t a, b, c;
  122. RX_EXECUTE_U64(0x8888888888888888, 0xAAAAAAAAAAAAAAAA, XOR_64);
  123. REQUIRE(c.u64 == 0x2222222222222222);
  124. }
  125. TEST_CASE("Bitwise XOR (32-bit)", "[XOR_32]") {
  126. convertible_t a, b, c;
  127. RX_EXECUTE_U64(0x8888888888888888, 0xAAAAAAAAAAAAAAAA, XOR_32);
  128. REQUIRE(c.u64 == 0x22222222);
  129. }
  130. TEST_CASE("Logical left shift (64-bit)", "[SHL_64]") {
  131. convertible_t a, b, c;
  132. RX_EXECUTE_U64(0x3, 52, SHL_64);
  133. REQUIRE(c.u64 == 0x30000000000000);
  134. RX_EXECUTE_U64(953360005391419562, 4569451684712230561, SHL_64);
  135. REQUIRE(c.u64 == 6978065200108797952);
  136. RX_EXECUTE_U64(0x8000000000000000, 1, SHL_64);
  137. REQUIRE(c.u64 == 0);
  138. }
  139. TEST_CASE("Logical right shift (64-bit)", "[SHR_64]") {
  140. convertible_t a, b, c;
  141. RX_EXECUTE_U64(0x3, 52, SHR_64);
  142. REQUIRE(c.u64 == 0);
  143. RX_EXECUTE_U64(953360005391419562, 4569451684712230561, SHR_64);
  144. REQUIRE(c.u64 == 110985711);
  145. RX_EXECUTE_U64(0x8000000000000000, 1, SHR_64);
  146. REQUIRE(c.u64 == 0x4000000000000000);
  147. }
  148. TEST_CASE("Arithmetic right shift (64-bit)", "[SAR_64]") {
  149. convertible_t a, b, c;
  150. RX_EXECUTE_I64(-9, 2, SAR_64);
  151. REQUIRE(c.i64 == -3);
  152. RX_EXECUTE_I64(INT64_MIN, 63, SAR_64);
  153. REQUIRE(c.i64 == -1);
  154. RX_EXECUTE_I64(INT64_MAX, 163768499474606398, SAR_64);
  155. REQUIRE(c.i64 == 1);
  156. }
  157. TEST_CASE("Circular left shift (64-bit)", "[ROL_64]") {
  158. convertible_t a, b, c;
  159. RX_EXECUTE_U64(0x3, 52, ROL_64);
  160. REQUIRE(c.u64 == 0x30000000000000);
  161. RX_EXECUTE_U64(953360005391419562, 4569451684712230561, ROL_64);
  162. REQUIRE(c.u64 == 6978065200552740799);
  163. RX_EXECUTE_U64(0x8000000000000000, 1, ROL_64);
  164. REQUIRE(c.u64 == 1);
  165. }
  166. TEST_CASE("Circular right shift (64-bit)", "[ROR_64]") {
  167. convertible_t a, b, c;
  168. RX_EXECUTE_U64(0x3, 52, ROR_64);
  169. REQUIRE(c.u64 == 12288);
  170. RX_EXECUTE_U64(953360005391419562, 4569451684712230561, ROR_64);
  171. REQUIRE(c.u64 == 0xD835C455069D81EF);
  172. RX_EXECUTE_U64(0x8000000000000000, 1, ROR_64);
  173. REQUIRE(c.u64 == 0x4000000000000000);
  174. }
  175. TEST_CASE("Denormal numbers are flushed to zero", "[FTZ]") {
  176. FPINIT();
  177. convertible_t a, c;
  178. a.i64 = 1;
  179. FDIV_64(a, std::numeric_limits<double>::max(), c);
  180. REQUIRE(c.f64 == 0.0);
  181. }
  182. TEST_CASE("IEEE-754 compliance", "[FPU]") {
  183. FPINIT();
  184. convertible_t a, c;
  185. a.i64 = 1;
  186. FDIV_64(a, 0, c);
  187. REQUIRE(c.f64 == std::numeric_limits<double>::infinity());
  188. a.i64 = -1;
  189. FDIV_64(a, 0, c);
  190. REQUIRE(c.f64 == -std::numeric_limits<double>::infinity());
  191. REQUIRE(rxRound(RoundToNearest, 33073499373184121, -37713516328519941, &FADD) == -4640016955335824.0);
  192. REQUIRE(rxRound(RoundDown, 33073499373184121, -37713516328519941, &FADD) == -4640016955335824.0);
  193. REQUIRE(rxRound(RoundUp, 33073499373184121, -37713516328519941, &FADD) == -4640016955335812.0);
  194. REQUIRE(rxRound(RoundToZero, 33073499373184121, -37713516328519941, &FADD) == -4640016955335816.0);
  195. REQUIRE(rxRound(RoundToNearest, -8570200862721897289, -1111111111111111119, &FSUB) == -7.4590897516107858e+18);
  196. REQUIRE(rxRound(RoundDown, -8570200862721897289, -1111111111111111119, &FSUB) == -7.4590897516107868e+18);
  197. REQUIRE(rxRound(RoundUp, -8570200862721897289, -1111111111111111119, &FSUB) == -7.4590897516107848e+18);
  198. REQUIRE(rxRound(RoundToZero, -8570200862721897289, -1111111111111111119, &FSUB) == -7.4590897516107848e+18);
  199. REQUIRE(rxRound(RoundToNearest, 1, -10, &FDIV) == -0.10000000000000001);
  200. REQUIRE(rxRound(RoundDown, 1, -10, &FDIV) == -0.10000000000000001);
  201. REQUIRE(rxRound(RoundUp, 1, -10, &FDIV) == -0.099999999999999992);
  202. REQUIRE(rxRound(RoundToZero, 1, -10, &FDIV) == -0.099999999999999992);
  203. REQUIRE(rxRound(RoundToNearest, -2, 0, &FABSQRT) == 1.4142135623730951);
  204. REQUIRE(rxRound(RoundDown, -2, 0, &FABSQRT) == 1.4142135623730949);
  205. REQUIRE(rxRound(RoundUp, -2, 0, &FABSQRT) == 1.4142135623730951);
  206. REQUIRE(rxRound(RoundToZero, -2, 0, &FABSQRT) == 1.4142135623730949);
  207. }