tests.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. #ifdef NDEBUG
  2. #undef NDEBUG
  3. #endif
  4. #include <cassert>
  5. #include <iomanip>
  6. #include "utility.hpp"
  7. #include "../bytecode_machine.hpp"
  8. #include "../dataset.hpp"
  9. #include "../blake2/endian.h"
  10. #include "../blake2/blake2.h"
  11. #include "../blake2_generator.hpp"
  12. #include "../superscalar.hpp"
  13. #include "../reciprocal.h"
  14. #include "../intrin_portable.h"
  15. #include "../jit_compiler.hpp"
  16. #include "../aes_hash.hpp"
  17. struct CacheKey {
  18. void* key;
  19. size_t size = 0;
  20. };
  21. randomx_cache* cache;
  22. randomx_vm* vm = nullptr;
  23. CacheKey currentKey;
  24. template<size_t N>
  25. void initCache(const char (&key)[N]) {
  26. assert(cache != nullptr);
  27. if (N - 1 == currentKey.size && memcmp(currentKey.key, key, N - 1) == 0)
  28. return;
  29. //std::cout << "randomx_init_cache with key ";
  30. //outputHex(std::cout, key, N - 1);
  31. //std::cout << std::endl;
  32. randomx_init_cache(cache, key, N - 1);
  33. currentKey.key = (void*)key;
  34. currentKey.size = N - 1;
  35. if (vm != nullptr)
  36. randomx_vm_set_cache(vm, cache);
  37. }
  38. template<size_t K, size_t H>
  39. void calcStringHash(const char(&key)[K], const char(&input)[H], void* output) {
  40. initCache(key);
  41. assert(vm != nullptr);
  42. randomx_calculate_hash(vm, input, H - 1, output);
  43. }
  44. template<size_t K, size_t H>
  45. void calcHexHash(const char(&key)[K], const char(&hex)[H], void* output) {
  46. initCache(key);
  47. assert(vm != nullptr);
  48. char input[H / 2];
  49. hex2bin((char*)hex, H - 1, input);
  50. randomx_calculate_hash(vm, input, sizeof(input), output);
  51. }
  52. int testNo = 0;
  53. int skipped = 0;
  54. template<typename FUNC>
  55. void runTest(const char* name, bool condition, FUNC f) {
  56. std::cout << "[";
  57. std::cout.width(2);
  58. std::cout << std::right << ++testNo << "] ";
  59. std::cout.width(40);
  60. std::cout << std::left << name << " ... ";
  61. std::cout.flush();
  62. if (condition) {
  63. f();
  64. std::cout << "PASSED" << std::endl;
  65. }
  66. else {
  67. std::cout << "SKIPPED" << std::endl;
  68. skipped++;
  69. }
  70. }
  71. int main() {
  72. char testHash[32];
  73. //std::cout << "Allocating randomx_cache..." << std::endl;
  74. cache = randomx_alloc_cache(RANDOMX_FLAG_DEFAULT);
  75. runTest("Cache initialization", RANDOMX_ARGON_ITERATIONS == 3 && RANDOMX_ARGON_LANES == 1 && RANDOMX_ARGON_MEMORY == 262144 && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), []() {
  76. initCache("test key 000");
  77. uint64_t* cacheMemory = (uint64_t*)cache->memory;
  78. assert(cacheMemory[0] == 0x191e0e1d23c02186);
  79. assert(cacheMemory[1568413] == 0xf1b62fe6210bf8b1);
  80. assert(cacheMemory[33554431] == 0x1f47f056d05cd99b);
  81. });
  82. runTest("SuperscalarHash generator", RANDOMX_SUPERSCALAR_LATENCY == 170, []() {
  83. char sprogHash[32];
  84. randomx::SuperscalarProgram sprog;
  85. const char key[] = "test key 000";
  86. constexpr size_t keySize = sizeof(key) - 1;
  87. randomx::Blake2Generator gen(key, keySize);
  88. const char superscalarReferences[10][65] = {
  89. "d3a4a6623738756f77e6104469102f082eff2a3e60be7ad696285ef7dfc72a61",
  90. "f5e7e0bbc7e93c609003d6359208688070afb4a77165a552ff7be63b38dfbc86",
  91. "85ed8b11734de5b3e9836641413a8f36e99e89694f419c8cd25c3f3f16c40c5a",
  92. "5dd956292cf5d5704ad99e362d70098b2777b2a1730520be52f772ca48cd3bc0",
  93. "6f14018ca7d519e9b48d91af094c0f2d7e12e93af0228782671a8640092af9e5",
  94. "134be097c92e2c45a92f23208cacd89e4ce51f1009a0b900dbe83b38de11d791",
  95. "268f9392c20c6e31371a5131f82bd7713d3910075f2f0468baafaa1abd2f3187",
  96. "c668a05fd909714ed4a91e8d96d67b17e44329e88bc71e0672b529a3fc16be47",
  97. "99739351315840963011e4c5d8e90ad0bfed3facdcb713fe8f7138fbf01c4c94",
  98. "14ab53d61880471f66e80183968d97effd5492b406876060e595fcf9682f9295",
  99. };
  100. for (int i = 0; i < 10; ++i) {
  101. randomx::generateSuperscalar(sprog, gen);
  102. blake2b(sprogHash, sizeof(sprogHash), &sprog.programBuffer, sizeof(randomx::Instruction) * sprog.getSize(), nullptr, 0);
  103. assert(equalsHex(sprogHash, superscalarReferences[i]));
  104. }
  105. });
  106. runTest("randomx_reciprocal", true, []() {
  107. assert(randomx_reciprocal(3) == 12297829382473034410U);
  108. assert(randomx_reciprocal(13) == 11351842506898185609U);
  109. assert(randomx_reciprocal(33) == 17887751829051686415U);
  110. assert(randomx_reciprocal(65537) == 18446462603027742720U);
  111. assert(randomx_reciprocal(15000001) == 10316166306300415204U);
  112. assert(randomx_reciprocal(3845182035) == 10302264209224146340U);
  113. assert(randomx_reciprocal(0xffffffff) == 9223372039002259456U);
  114. });
  115. runTest("randomx_reciprocal_fast", RANDOMX_HAVE_FAST_RECIPROCAL, []() {
  116. assert(randomx_reciprocal_fast(3) == 12297829382473034410U);
  117. assert(randomx_reciprocal_fast(13) == 11351842506898185609U);
  118. assert(randomx_reciprocal_fast(33) == 17887751829051686415U);
  119. assert(randomx_reciprocal_fast(65537) == 18446462603027742720U);
  120. assert(randomx_reciprocal_fast(15000001) == 10316166306300415204U);
  121. assert(randomx_reciprocal_fast(3845182035) == 10302264209224146340U);
  122. assert(randomx_reciprocal_fast(0xffffffff) == 9223372039002259456U);
  123. });
  124. runTest("Dataset initialization (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), []() {
  125. initCache("test key 000");
  126. uint64_t datasetItem[8];
  127. randomx::initDatasetItem(cache, (uint8_t*)&datasetItem, 0);
  128. assert(datasetItem[0] == 0x680588a85ae222db);
  129. randomx::initDatasetItem(cache, (uint8_t*)&datasetItem, 10000000);
  130. assert(datasetItem[0] == 0x7943a1f6186ffb72);
  131. randomx::initDatasetItem(cache, (uint8_t*)&datasetItem, 20000000);
  132. assert(datasetItem[0] == 0x9035244d718095e1);
  133. randomx::initDatasetItem(cache, (uint8_t*)&datasetItem, 30000000);
  134. assert(datasetItem[0] == 0x145a5091f7853099);
  135. });
  136. runTest("Dataset initialization (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), []() {
  137. initCache("test key 000");
  138. randomx::JitCompiler jit;
  139. jit.generateSuperscalarHash(cache->programs, cache->reciprocalCache);
  140. jit.generateDatasetInitCode();
  141. jit.enableAll();
  142. uint64_t datasetItem[8];
  143. jit.getDatasetInitFunc()(cache, (uint8_t*)&datasetItem, 0, 1);
  144. assert(datasetItem[0] == 0x680588a85ae222db);
  145. jit.getDatasetInitFunc()(cache, (uint8_t*)&datasetItem, 10000000, 10000001);
  146. assert(datasetItem[0] == 0x7943a1f6186ffb72);
  147. jit.getDatasetInitFunc()(cache, (uint8_t*)&datasetItem, 20000000, 20000001);
  148. assert(datasetItem[0] == 0x9035244d718095e1);
  149. jit.getDatasetInitFunc()(cache, (uint8_t*)&datasetItem, 30000000, 30000001);
  150. assert(datasetItem[0] == 0x145a5091f7853099);
  151. });
  152. runTest("AesGenerator1R", true, []() {
  153. char state[64] = { 0 };
  154. hex2bin("6c19536eb2de31b6c0065f7f116e86f960d8af0c57210a6584c3237b9d064dc7", 64, state);
  155. fillAes1Rx4<true>(state, sizeof(state), state);
  156. assert(equalsHex(state, "fa89397dd6ca422513aeadba3f124b5540324c4ad4b6db434394307a17c833ab"));
  157. });
  158. randomx::NativeRegisterFile reg;
  159. randomx::BytecodeMachine decoder;
  160. randomx::InstructionByteCode ibc;
  161. alignas(16) randomx::ProgramConfiguration config;
  162. constexpr int registerHigh = 192;
  163. constexpr int registerDst = 0;
  164. constexpr int registerSrc = 1;
  165. int pc = 0;
  166. constexpr uint32_t imm32 = 3234567890;
  167. constexpr uint64_t imm64 = signExtend2sCompl(imm32);
  168. decoder.beginCompilation(reg);
  169. runTest("IADD_RS (decode)", RANDOMX_FREQ_IADD_RS > 0, [&] {
  170. randomx::Instruction instr;
  171. instr.opcode = randomx::ceil_IADD_RS - 1;
  172. instr.dst = registerHigh | registerDst;
  173. instr.src = registerHigh | registerSrc;
  174. instr.mod = UINT8_MAX;
  175. instr.setImm32(imm32);
  176. decoder.compileInstruction(instr, pc, ibc);
  177. assert(ibc.type == randomx::InstructionType::IADD_RS);
  178. assert(ibc.idst == &reg.r[registerDst]);
  179. assert(ibc.isrc == &reg.r[registerSrc]);
  180. assert(ibc.shift == 3);
  181. assert(ibc.imm == 0);
  182. });
  183. runTest("IADD_RS (execute)", RANDOMX_FREQ_IADD_RS > 0, [&] {
  184. reg.r[registerDst] = 0x8000000000000000;
  185. reg.r[registerSrc] = 0x1000000000000000;
  186. decoder.executeInstruction(ibc, pc, nullptr, config);
  187. assert(reg.r[registerDst] == 0);
  188. });
  189. runTest("IADD_RS with immediate (decode)", RANDOMX_FREQ_IADD_RS > 0, [&] {
  190. randomx::Instruction instr;
  191. instr.opcode = randomx::ceil_IADD_RS - 1;
  192. instr.mod = 8;
  193. instr.dst = registerHigh | randomx::RegisterNeedsDisplacement;
  194. instr.src = registerHigh | registerSrc;
  195. instr.setImm32(imm32);
  196. decoder.compileInstruction(instr, pc, ibc);
  197. assert(ibc.type == randomx::InstructionType::IADD_RS);
  198. assert(ibc.idst == &reg.r[randomx::RegisterNeedsDisplacement]);
  199. assert(ibc.isrc == &reg.r[registerSrc]);
  200. assert(ibc.shift == 2);
  201. assert(ibc.imm == imm64);
  202. });
  203. runTest("IADD_RS with immediate (decode)", RANDOMX_FREQ_IADD_RS > 0, [&] {
  204. reg.r[randomx::RegisterNeedsDisplacement] = 0x8000000000000000;
  205. reg.r[registerSrc] = 0x2000000000000000;
  206. decoder.executeInstruction(ibc, pc, nullptr, config);
  207. assert(reg.r[randomx::RegisterNeedsDisplacement] == imm64);
  208. });
  209. runTest("IADD_M (decode)", RANDOMX_FREQ_IADD_M > 0, [&] {
  210. randomx::Instruction instr;
  211. instr.opcode = randomx::ceil_IADD_M - 1;
  212. instr.mod = 1;
  213. instr.dst = registerHigh | registerDst;
  214. instr.src = registerHigh | registerSrc;
  215. instr.setImm32(imm32);
  216. decoder.compileInstruction(instr, pc, ibc);
  217. assert(ibc.type == randomx::InstructionType::IADD_M);
  218. assert(ibc.idst == &reg.r[registerDst]);
  219. assert(ibc.isrc == &reg.r[registerSrc]);
  220. assert(ibc.imm == imm64);
  221. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  222. });
  223. runTest("ISUB_R (decode)", RANDOMX_FREQ_ISUB_R > 0, [&] {
  224. randomx::Instruction instr;
  225. instr.opcode = randomx::ceil_ISUB_R - 1;
  226. instr.dst = registerHigh | registerDst;
  227. instr.src = registerHigh | registerSrc;
  228. instr.setImm32(imm32);
  229. decoder.compileInstruction(instr, pc, ibc);
  230. assert(ibc.type == randomx::InstructionType::ISUB_R);
  231. assert(ibc.idst == &reg.r[registerDst]);
  232. assert(ibc.isrc == &reg.r[registerSrc]);
  233. });
  234. runTest("ISUB_R (execute)", RANDOMX_FREQ_ISUB_R > 0, [&] {
  235. reg.r[registerDst] = 1;
  236. reg.r[registerSrc] = 0xFFFFFFFF;
  237. decoder.executeInstruction(ibc, pc, nullptr, config);
  238. assert(reg.r[registerDst] == 0xFFFFFFFF00000002);
  239. });
  240. runTest("ISUB_R with immediate (decode)", RANDOMX_FREQ_ISUB_R > 0, [&] {
  241. randomx::Instruction instr;
  242. instr.opcode = randomx::ceil_ISUB_R - 1;
  243. instr.dst = registerHigh | registerDst;
  244. instr.src = registerHigh | registerDst;
  245. instr.setImm32(imm32);
  246. decoder.compileInstruction(instr, pc, ibc);
  247. assert(ibc.type == randomx::InstructionType::ISUB_R);
  248. assert(ibc.idst == &reg.r[registerDst]);
  249. assert(ibc.isrc == &ibc.imm);
  250. });
  251. runTest("ISUB_R with immediate (decode)", RANDOMX_FREQ_ISUB_R > 0, [&] {
  252. reg.r[registerDst] = 0;
  253. decoder.executeInstruction(ibc, pc, nullptr, config);
  254. assert(reg.r[registerDst] == (~imm64 + 1));
  255. });
  256. runTest("ISUB_M (decode)", RANDOMX_FREQ_ISUB_M > 0, [&] {
  257. randomx::Instruction instr;
  258. instr.opcode = randomx::ceil_ISUB_M - 1;
  259. instr.mod = 0;
  260. instr.dst = registerHigh | registerDst;
  261. instr.src = registerHigh | registerSrc;
  262. instr.setImm32(imm32);
  263. decoder.compileInstruction(instr, pc, ibc);
  264. assert(ibc.type == randomx::InstructionType::ISUB_M);
  265. assert(ibc.idst == &reg.r[registerDst]);
  266. assert(ibc.isrc == &reg.r[registerSrc]);
  267. assert(ibc.imm == imm64);
  268. assert(ibc.memMask == randomx::ScratchpadL2Mask);
  269. });
  270. runTest("IMUL_R (decode)", RANDOMX_FREQ_IMUL_R > 0, [&] {
  271. randomx::Instruction instr;
  272. instr.opcode = randomx::ceil_IMUL_R - 1;
  273. instr.dst = registerHigh | registerDst;
  274. instr.src = registerHigh | registerSrc;
  275. instr.setImm32(imm32);
  276. decoder.compileInstruction(instr, pc, ibc);
  277. assert(ibc.type == randomx::InstructionType::IMUL_R);
  278. assert(ibc.idst == &reg.r[registerDst]);
  279. assert(ibc.isrc == &reg.r[registerSrc]);
  280. });
  281. runTest("IMUL_R (execute)", RANDOMX_FREQ_IMUL_R > 0, [&] {
  282. reg.r[registerDst] = 0xBC550E96BA88A72B;
  283. reg.r[registerSrc] = 0xF5391FA9F18D6273;
  284. decoder.executeInstruction(ibc, pc, nullptr, config);
  285. assert(reg.r[registerDst] == 0x28723424A9108E51);
  286. });
  287. runTest("IMUL_R with immediate (decode)", RANDOMX_FREQ_IMUL_R > 0, [&] {
  288. randomx::Instruction instr;
  289. instr.opcode = randomx::ceil_IMUL_R - 1;
  290. instr.dst = registerHigh | registerDst;
  291. instr.src = registerHigh | registerDst;
  292. instr.setImm32(imm32);
  293. decoder.compileInstruction(instr, pc, ibc);
  294. assert(ibc.type == randomx::InstructionType::IMUL_R);
  295. assert(ibc.idst == &reg.r[registerDst]);
  296. assert(ibc.isrc == &ibc.imm);
  297. });
  298. runTest("IMUL_R with immediate (execute)", RANDOMX_FREQ_IMUL_R > 0, [&] {
  299. reg.r[registerDst] = 1;
  300. decoder.executeInstruction(ibc, pc, nullptr, config);
  301. assert(reg.r[registerDst] == imm64);
  302. });
  303. runTest("IMUL_M (decode)", RANDOMX_FREQ_IMUL_M > 0, [&] {
  304. randomx::Instruction instr;
  305. instr.opcode = randomx::ceil_IMUL_M - 1;
  306. instr.mod = 0;
  307. instr.dst = registerHigh | registerDst;
  308. instr.src = registerHigh | registerDst;
  309. instr.setImm32(imm32);
  310. decoder.compileInstruction(instr, pc, ibc);
  311. assert(ibc.type == randomx::InstructionType::IMUL_M);
  312. assert(ibc.idst == &reg.r[registerDst]);
  313. assert(*ibc.isrc == 0);
  314. assert(ibc.imm == imm64);
  315. assert(ibc.memMask == randomx::ScratchpadL3Mask);
  316. });
  317. runTest("IMULH_R (decode)", RANDOMX_FREQ_IMULH_R > 0, [&] {
  318. randomx::Instruction instr;
  319. instr.opcode = randomx::ceil_IMULH_R - 1;
  320. instr.dst = registerHigh | registerDst;
  321. instr.src = registerHigh | registerSrc;
  322. instr.setImm32(imm32);
  323. decoder.compileInstruction(instr, pc, ibc);
  324. assert(ibc.type == randomx::InstructionType::IMULH_R);
  325. assert(ibc.idst == &reg.r[registerDst]);
  326. assert(ibc.isrc == &reg.r[registerSrc]);
  327. });
  328. runTest("IMULH_R (execute)", RANDOMX_FREQ_IMULH_R > 0, [&] {
  329. reg.r[registerDst] = 0xBC550E96BA88A72B;
  330. reg.r[registerSrc] = 0xF5391FA9F18D6273;
  331. decoder.executeInstruction(ibc, pc, nullptr, config);
  332. assert(reg.r[registerDst] == 0xB4676D31D2B34883);
  333. });
  334. runTest("IMULH_R squared (decode)", RANDOMX_FREQ_IMULH_R > 0, [&] {
  335. randomx::Instruction instr;
  336. instr.opcode = randomx::ceil_IMULH_R - 1;
  337. instr.dst = registerHigh | registerDst;
  338. instr.src = registerHigh | registerDst;
  339. instr.setImm32(imm32);
  340. decoder.compileInstruction(instr, pc, ibc);
  341. assert(ibc.type == randomx::InstructionType::IMULH_R);
  342. assert(ibc.idst == &reg.r[registerDst]);
  343. assert(ibc.isrc == &reg.r[registerDst]);
  344. });
  345. runTest("IMULH_M (decode)", RANDOMX_FREQ_IMULH_M > 0, [&] {
  346. randomx::Instruction instr;
  347. instr.opcode = randomx::ceil_IMULH_M - 1;
  348. instr.mod = 0;
  349. instr.dst = registerHigh | registerDst;
  350. instr.src = registerHigh | registerSrc;
  351. instr.setImm32(imm32);
  352. decoder.compileInstruction(instr, pc, ibc);
  353. assert(ibc.type == randomx::InstructionType::IMULH_M);
  354. assert(ibc.idst == &reg.r[registerDst]);
  355. assert(ibc.isrc == &reg.r[registerSrc]);
  356. assert(ibc.imm == imm64);
  357. assert(ibc.memMask == randomx::ScratchpadL2Mask);
  358. });
  359. runTest("ISMULH_R (decode)", RANDOMX_FREQ_ISMULH_R > 0, [&] {
  360. randomx::Instruction instr;
  361. instr.opcode = randomx::ceil_ISMULH_R - 1;
  362. instr.dst = registerHigh | registerDst;
  363. instr.src = registerHigh | registerSrc;
  364. instr.setImm32(imm32);
  365. decoder.compileInstruction(instr, pc, ibc);
  366. assert(ibc.type == randomx::InstructionType::ISMULH_R);
  367. assert(ibc.idst == &reg.r[registerDst]);
  368. assert(ibc.isrc == &reg.r[registerSrc]);
  369. });
  370. runTest("ISMULH_R (execute)", RANDOMX_FREQ_ISMULH_R > 0, [&] {
  371. reg.r[registerDst] = 0xBC550E96BA88A72B;
  372. reg.r[registerSrc] = 0xF5391FA9F18D6273;
  373. decoder.executeInstruction(ibc, pc, nullptr, config);
  374. assert(reg.r[registerDst] == 0x02D93EF1269D3EE5);
  375. });
  376. runTest("ISMULH_R squared (decode)", RANDOMX_FREQ_ISMULH_R > 0, [&] {
  377. randomx::Instruction instr;
  378. instr.opcode = randomx::ceil_ISMULH_R - 1;
  379. instr.dst = registerHigh | registerDst;
  380. instr.src = registerHigh | registerDst;
  381. instr.setImm32(imm32);
  382. decoder.compileInstruction(instr, pc, ibc);
  383. assert(ibc.type == randomx::InstructionType::ISMULH_R);
  384. assert(ibc.idst == &reg.r[registerDst]);
  385. assert(ibc.isrc == &reg.r[registerDst]);
  386. });
  387. runTest("ISMULH_M (decode)", RANDOMX_FREQ_ISMULH_M > 0, [&] {
  388. randomx::Instruction instr;
  389. instr.opcode = randomx::ceil_ISMULH_M - 1;
  390. instr.mod = 3;
  391. instr.dst = registerHigh | registerDst;
  392. instr.src = registerHigh | registerSrc;
  393. instr.setImm32(imm32);
  394. decoder.compileInstruction(instr, pc, ibc);
  395. assert(ibc.type == randomx::InstructionType::ISMULH_M);
  396. assert(ibc.idst == &reg.r[registerDst]);
  397. assert(ibc.isrc == &reg.r[registerSrc]);
  398. assert(ibc.imm == imm64);
  399. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  400. });
  401. runTest("IMUL_RCP (decode)", RANDOMX_FREQ_IMUL_RCP > 0, [&] {
  402. randomx::Instruction instr;
  403. instr.opcode = randomx::ceil_IMUL_RCP - 1;
  404. instr.dst = registerHigh | registerDst;
  405. instr.setImm32(imm32);
  406. decoder.compileInstruction(instr, pc, ibc);
  407. assert(ibc.type == randomx::InstructionType::IMUL_R);
  408. assert(ibc.idst == &reg.r[registerDst]);
  409. assert(ibc.isrc == &ibc.imm);
  410. assert(ibc.imm == randomx_reciprocal(imm32));
  411. });
  412. runTest("IMUL_RCP zero imm32 (decode)", RANDOMX_FREQ_IMUL_RCP > 0, [&] {
  413. randomx::Instruction instr;
  414. instr.opcode = randomx::ceil_IMUL_RCP - 1;
  415. instr.setImm32(0);
  416. decoder.compileInstruction(instr, pc, ibc);
  417. assert(ibc.type == randomx::InstructionType::NOP);
  418. });
  419. runTest("INEG_R (decode)", RANDOMX_FREQ_INEG_R > 0, [&] {
  420. randomx::Instruction instr;
  421. instr.opcode = randomx::ceil_INEG_R - 1;
  422. instr.dst = registerHigh | registerDst;
  423. instr.setImm32(imm32);
  424. decoder.compileInstruction(instr, pc, ibc);
  425. assert(ibc.type == randomx::InstructionType::INEG_R);
  426. assert(ibc.idst == &reg.r[registerDst]);
  427. });
  428. runTest("INEG_R (execute)", RANDOMX_FREQ_INEG_R > 0, [&] {
  429. reg.r[registerDst] = 0xFFFFFFFFFFFFFFFF;
  430. decoder.executeInstruction(ibc, pc, nullptr, config);
  431. assert(reg.r[registerDst] == 1);
  432. });
  433. runTest("IXOR_R (decode)", RANDOMX_FREQ_IXOR_R > 0, [&] {
  434. randomx::Instruction instr;
  435. instr.opcode = randomx::ceil_IXOR_R - 1;
  436. instr.dst = registerHigh | registerDst;
  437. instr.src = registerHigh | registerSrc;
  438. instr.setImm32(imm32);
  439. decoder.compileInstruction(instr, pc, ibc);
  440. assert(ibc.type == randomx::InstructionType::IXOR_R);
  441. assert(ibc.idst == &reg.r[registerDst]);
  442. assert(ibc.isrc == &reg.r[registerSrc]);
  443. });
  444. runTest("IXOR_R (execute)", RANDOMX_FREQ_IMUL_R > 0, [&] {
  445. reg.r[registerDst] = 0x8888888888888888;
  446. reg.r[registerSrc] = 0xAAAAAAAAAAAAAAAA;
  447. decoder.executeInstruction(ibc, pc, nullptr, config);
  448. assert(reg.r[registerDst] == 0x2222222222222222);
  449. });
  450. runTest("IXOR_R with immediate (decode)", RANDOMX_FREQ_IXOR_R > 0, [&] {
  451. randomx::Instruction instr;
  452. instr.opcode = randomx::ceil_IXOR_R - 1;
  453. instr.dst = registerHigh | registerDst;
  454. instr.src = registerHigh | registerDst;
  455. instr.setImm32(imm32);
  456. decoder.compileInstruction(instr, pc, ibc);
  457. assert(ibc.type == randomx::InstructionType::IXOR_R);
  458. assert(ibc.idst == &reg.r[registerDst]);
  459. assert(ibc.isrc == &ibc.imm);
  460. });
  461. runTest("IXOR_R with immediate (execute)", RANDOMX_FREQ_IXOR_R > 0, [&] {
  462. reg.r[registerDst] = 0xFFFFFFFFFFFFFFFF;
  463. decoder.executeInstruction(ibc, pc, nullptr, config);
  464. assert(reg.r[registerDst] == ~imm64);
  465. });
  466. runTest("IXOR_M (decode)", RANDOMX_FREQ_IXOR_M > 0, [&] {
  467. randomx::Instruction instr;
  468. instr.opcode = randomx::ceil_IXOR_M - 1;
  469. instr.dst = registerHigh | registerDst;
  470. instr.src = registerHigh | registerDst;
  471. instr.setImm32(imm32);
  472. decoder.compileInstruction(instr, pc, ibc);
  473. assert(ibc.type == randomx::InstructionType::IXOR_M);
  474. assert(ibc.idst == &reg.r[registerDst]);
  475. assert(*ibc.isrc == 0);
  476. assert(ibc.imm == imm64);
  477. assert(ibc.memMask == randomx::ScratchpadL3Mask);
  478. });
  479. runTest("IROR_R (decode)", RANDOMX_FREQ_IROR_R > 0, [&] {
  480. randomx::Instruction instr;
  481. instr.opcode = randomx::ceil_IROR_R - 1;
  482. instr.dst = registerHigh | registerDst;
  483. instr.src = registerHigh | registerSrc;
  484. instr.setImm32(imm32);
  485. decoder.compileInstruction(instr, pc, ibc);
  486. assert(ibc.type == randomx::InstructionType::IROR_R);
  487. assert(ibc.idst == &reg.r[registerDst]);
  488. assert(ibc.isrc == &reg.r[registerSrc]);
  489. });
  490. runTest("IROR_R (execute)", RANDOMX_FREQ_IROR_R > 0, [&] {
  491. reg.r[registerDst] = 953360005391419562;
  492. reg.r[registerSrc] = 4569451684712230561;
  493. decoder.executeInstruction(ibc, pc, nullptr, config);
  494. assert(reg.r[registerDst] == 0xD835C455069D81EF);
  495. });
  496. runTest("IROL_R (decode)", RANDOMX_FREQ_IROL_R > 0, [&] {
  497. randomx::Instruction instr;
  498. instr.opcode = randomx::ceil_IROL_R - 1;
  499. instr.dst = registerHigh | registerDst;
  500. instr.src = registerHigh | registerSrc;
  501. instr.setImm32(imm32);
  502. decoder.compileInstruction(instr, pc, ibc);
  503. assert(ibc.type == randomx::InstructionType::IROL_R);
  504. assert(ibc.idst == &reg.r[registerDst]);
  505. assert(ibc.isrc == &reg.r[registerSrc]);
  506. });
  507. runTest("IROL_R (execute)", RANDOMX_FREQ_IROL_R > 0, [&] {
  508. reg.r[registerDst] = 953360005391419562;
  509. reg.r[registerSrc] = 4569451684712230561;
  510. decoder.executeInstruction(ibc, pc, nullptr, config);
  511. assert(reg.r[registerDst] == 6978065200552740799);
  512. });
  513. runTest("ISWAP_R (decode)", RANDOMX_FREQ_ISWAP_R > 0, [&] {
  514. randomx::Instruction instr;
  515. instr.opcode = randomx::ceil_ISWAP_R - 1;
  516. instr.dst = registerHigh | registerDst;
  517. instr.src = registerHigh | registerSrc;
  518. instr.setImm32(imm32);
  519. decoder.compileInstruction(instr, pc, ibc);
  520. assert(ibc.type == randomx::InstructionType::ISWAP_R);
  521. assert(ibc.idst == &reg.r[registerDst]);
  522. assert(ibc.isrc == &reg.r[registerSrc]);
  523. });
  524. runTest("ISWAP_R (execute)", RANDOMX_FREQ_ISWAP_R > 0, [&] {
  525. reg.r[registerDst] = 953360005391419562;
  526. reg.r[registerSrc] = 4569451684712230561;
  527. decoder.executeInstruction(ibc, pc, nullptr, config);
  528. assert(reg.r[registerDst] == 4569451684712230561);
  529. assert(reg.r[registerSrc] == 953360005391419562);
  530. });
  531. runTest("FSWAP_R (decode)", RANDOMX_FREQ_FSWAP_R > 0, [&] {
  532. randomx::Instruction instr;
  533. instr.opcode = randomx::ceil_FSWAP_R - 1;
  534. instr.dst = registerHigh | registerDst;
  535. decoder.compileInstruction(instr, pc, ibc);
  536. assert(ibc.type == randomx::InstructionType::FSWAP_R);
  537. assert(ibc.fdst == &reg.f[registerDst]);
  538. });
  539. runTest("FSWAP_R (execute)", RANDOMX_FREQ_FSWAP_R > 0, [&] {
  540. alignas(16) uint64_t vec[2];
  541. reg.f[registerDst] = rx_set_vec_f128(953360005391419562, 4569451684712230561);
  542. decoder.executeInstruction(ibc, pc, nullptr, config);
  543. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  544. assert(equalsHex((const char*)&vec, "aa886bb0df033b0da12e95e518f4693f"));
  545. });
  546. runTest("FADD_R (decode)", RANDOMX_FREQ_FADD_R > 0, [&] {
  547. randomx::Instruction instr;
  548. instr.opcode = randomx::ceil_FADD_R - 1;
  549. instr.dst = registerHigh | registerDst;
  550. instr.src = registerHigh | registerSrc;
  551. instr.setImm32(imm32);
  552. decoder.compileInstruction(instr, pc, ibc);
  553. assert(ibc.type == randomx::InstructionType::FADD_R);
  554. assert(ibc.fdst == &reg.f[registerDst]);
  555. assert(ibc.fsrc == &reg.a[registerSrc]);
  556. });
  557. runTest("FADD_R RoundToNearest (execute)", RANDOMX_FREQ_FADD_R > 0, [&] {
  558. alignas(16) uint64_t vec[2];
  559. reg.f[registerDst] = rx_set_vec_f128(0x3ffd2c97cc4ef015, 0xc1ce30b3c4223576);
  560. reg.a[registerSrc] = rx_set_vec_f128(0x402a26a86a60c8fb, 0x40b8f684057a59e1);
  561. rx_set_rounding_mode(RoundToNearest);
  562. decoder.executeInstruction(ibc, pc, nullptr, config);
  563. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  564. assert(equalsHex(&vec, "b932e048a730cec1fea6ea633bcc2d40"));
  565. });
  566. runTest("FADD_R RoundDown (execute)", RANDOMX_FREQ_FADD_R > 0, [&] {
  567. alignas(16) uint64_t vec[2];
  568. reg.f[registerDst] = rx_set_vec_f128(0x3ffd2c97cc4ef015, 0xc1ce30b3c4223576);
  569. reg.a[registerSrc] = rx_set_vec_f128(0x402a26a86a60c8fb, 0x40b8f684057a59e1);
  570. rx_set_rounding_mode(RoundDown);
  571. decoder.executeInstruction(ibc, pc, nullptr, config);
  572. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  573. assert(equalsHex(&vec, "b932e048a730cec1fda6ea633bcc2d40"));
  574. });
  575. runTest("FADD_R RoundUp (execute)", RANDOMX_FREQ_FADD_R > 0, [&] {
  576. alignas(16) uint64_t vec[2];
  577. reg.f[registerDst] = rx_set_vec_f128(0x3ffd2c97cc4ef015, 0xc1ce30b3c4223576);
  578. reg.a[registerSrc] = rx_set_vec_f128(0x402a26a86a60c8fb, 0x40b8f684057a59e1);
  579. rx_set_rounding_mode(RoundUp);
  580. decoder.executeInstruction(ibc, pc, nullptr, config);
  581. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  582. assert(equalsHex(&vec, "b832e048a730cec1fea6ea633bcc2d40"));
  583. });
  584. runTest("FADD_R RoundToZero (execute)", RANDOMX_FREQ_FADD_R > 0, [&] {
  585. alignas(16) uint64_t vec[2];
  586. reg.f[registerDst] = rx_set_vec_f128(0x3ffd2c97cc4ef015, 0xc1ce30b3c4223576);
  587. reg.a[registerSrc] = rx_set_vec_f128(0x402a26a86a60c8fb, 0x40b8f684057a59e1);
  588. rx_set_rounding_mode(RoundToZero);
  589. decoder.executeInstruction(ibc, pc, nullptr, config);
  590. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  591. assert(equalsHex(&vec, "b832e048a730cec1fda6ea633bcc2d40"));
  592. });
  593. runTest("FADD_M (decode)", RANDOMX_FREQ_FADD_M > 0, [&] {
  594. randomx::Instruction instr;
  595. instr.opcode = randomx::ceil_FADD_M - 1;
  596. instr.mod = 1;
  597. instr.dst = registerHigh | registerDst;
  598. instr.src = registerHigh | registerSrc;
  599. instr.setImm32(imm32);
  600. decoder.compileInstruction(instr, pc, ibc);
  601. assert(ibc.type == randomx::InstructionType::FADD_M);
  602. assert(ibc.fdst == &reg.f[registerDst]);
  603. assert(ibc.isrc == &reg.r[registerSrc]);
  604. assert(ibc.imm == imm64);
  605. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  606. });
  607. runTest("FADD_M (execute)", RANDOMX_FREQ_FADD_R > 0, [&] {
  608. uint64_t mockScratchpad;
  609. store64(&mockScratchpad, 0x1234567890abcdef);
  610. alignas(16) uint64_t vec[2];
  611. reg.f[registerDst] = rx_set_vec_f128(0, 0);
  612. reg.r[registerSrc] = 0xFFFFFFFFFFFFE930;
  613. rx_set_rounding_mode(RoundToNearest);
  614. decoder.executeInstruction(ibc, pc, (uint8_t*)&mockScratchpad, config);
  615. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  616. assert(equalsHex(&vec, "000040840cd5dbc1000000785634b241"));
  617. });
  618. runTest("FSUB_R (decode)", RANDOMX_FREQ_FSUB_R > 0, [&] {
  619. randomx::Instruction instr;
  620. instr.opcode = randomx::ceil_FSUB_R - 1;
  621. instr.dst = registerHigh | registerDst;
  622. instr.src = registerHigh | registerSrc;
  623. instr.setImm32(imm32);
  624. decoder.compileInstruction(instr, pc, ibc);
  625. assert(ibc.type == randomx::InstructionType::FSUB_R);
  626. assert(ibc.fdst == &reg.f[registerDst]);
  627. assert(ibc.fsrc == &reg.a[registerSrc]);
  628. });
  629. runTest("FSUB_M (decode)", RANDOMX_FREQ_FSUB_M > 0, [&] {
  630. randomx::Instruction instr;
  631. instr.opcode = randomx::ceil_FSUB_M - 1;
  632. instr.mod = 2;
  633. instr.dst = registerHigh | registerDst;
  634. instr.src = registerHigh | registerSrc;
  635. instr.setImm32(imm32);
  636. decoder.compileInstruction(instr, pc, ibc);
  637. assert(ibc.type == randomx::InstructionType::FSUB_M);
  638. assert(ibc.fdst == &reg.f[registerDst]);
  639. assert(ibc.isrc == &reg.r[registerSrc]);
  640. assert(ibc.imm == imm64);
  641. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  642. });
  643. runTest("FSCAL_R (decode)", RANDOMX_FREQ_FSCAL_R > 0, [&] {
  644. randomx::Instruction instr;
  645. instr.opcode = randomx::ceil_FSCAL_R - 1;
  646. instr.dst = registerHigh | registerDst;
  647. instr.setImm32(imm32);
  648. decoder.compileInstruction(instr, pc, ibc);
  649. assert(ibc.type == randomx::InstructionType::FSCAL_R);
  650. assert(ibc.fdst == &reg.f[registerDst]);
  651. });
  652. runTest("FSCAL_R (execute)", RANDOMX_FREQ_FSCAL_R > 0, [&] {
  653. alignas(16) uint64_t vec[2];
  654. reg.f[registerDst] = rx_set_vec_f128(0x41dbc35cef248783, 0x40fdfdabb6173d07);
  655. decoder.executeInstruction(ibc, pc, nullptr, config);
  656. rx_store_vec_f128((double*)&vec, reg.f[registerDst]);
  657. assert(equalsHex((const char*)&vec, "073d17b6abfd0dc0838724ef5cc32bc1"));
  658. });
  659. runTest("FMUL_R (decode)", RANDOMX_FREQ_FMUL_R > 0, [&] {
  660. randomx::Instruction instr;
  661. instr.opcode = randomx::ceil_FMUL_R - 1;
  662. instr.dst = registerHigh | registerDst;
  663. instr.src = registerHigh | registerSrc;
  664. instr.setImm32(imm32);
  665. decoder.compileInstruction(instr, pc, ibc);
  666. assert(ibc.type == randomx::InstructionType::FMUL_R);
  667. assert(ibc.fdst == &reg.e[registerDst]);
  668. assert(ibc.fsrc == &reg.a[registerSrc]);
  669. });
  670. runTest("FMUL_R RoundToNearest (execute)", RANDOMX_FREQ_FMUL_R > 0, [&] {
  671. alignas(16) uint64_t vec[2];
  672. reg.e[registerDst] = rx_set_vec_f128(0x41dbc35cef248783, 0x40fdfdabb6173d07);
  673. reg.a[registerSrc] = rx_set_vec_f128(0x40eba861aa31c7c0, 0x41c4561212ae2d50);
  674. rx_set_rounding_mode(RoundToNearest);
  675. decoder.executeInstruction(ibc, pc, nullptr, config);
  676. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  677. assert(equalsHex(&vec, "69697aff350fd3422f1589cdecfed742"));
  678. });
  679. runTest("FMUL_R RoundDown/RoundToZero (execute)", RANDOMX_FREQ_FMUL_R > 0, [&] {
  680. alignas(16) uint64_t vec[2];
  681. reg.e[registerDst] = rx_set_vec_f128(0x41dbc35cef248783, 0x40fdfdabb6173d07);
  682. reg.a[registerSrc] = rx_set_vec_f128(0x40eba861aa31c7c0, 0x41c4561212ae2d50);
  683. rx_set_rounding_mode(RoundDown);
  684. decoder.executeInstruction(ibc, pc, nullptr, config);
  685. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  686. assert(equalsHex(&vec, "69697aff350fd3422e1589cdecfed742"));
  687. });
  688. runTest("FMUL_R RoundUp (execute)", RANDOMX_FREQ_FMUL_R > 0, [&] {
  689. alignas(16) uint64_t vec[2];
  690. reg.e[registerDst] = rx_set_vec_f128(0x41dbc35cef248783, 0x40fdfdabb6173d07);
  691. reg.a[registerSrc] = rx_set_vec_f128(0x40eba861aa31c7c0, 0x41c4561212ae2d50);
  692. rx_set_rounding_mode(RoundUp);
  693. decoder.executeInstruction(ibc, pc, nullptr, config);
  694. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  695. assert(equalsHex(&vec, "6a697aff350fd3422f1589cdecfed742"));
  696. });
  697. runTest("FDIV_M (decode)", RANDOMX_FREQ_FDIV_M > 0, [&] {
  698. randomx::Instruction instr;
  699. instr.opcode = randomx::ceil_FDIV_M - 1;
  700. instr.mod = 3;
  701. instr.dst = registerHigh | registerDst;
  702. instr.src = registerHigh | registerSrc;
  703. instr.setImm32(imm32);
  704. decoder.compileInstruction(instr, pc, ibc);
  705. assert(ibc.type == randomx::InstructionType::FDIV_M);
  706. assert(ibc.fdst == &reg.e[registerDst]);
  707. assert(ibc.isrc == &reg.r[registerSrc]);
  708. assert(ibc.imm == imm64);
  709. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  710. });
  711. runTest("FDIV_M RoundToNearest (execute)", RANDOMX_FREQ_FDIV_M > 0, [&] {
  712. alignas(16) uint64_t vec[2];
  713. alignas(16) uint32_t mockScratchpad[2];
  714. store32(&mockScratchpad[0], 0xd350a1b6);
  715. store32(&mockScratchpad[1], 0x8b2460d9);
  716. store64(&config.eMask[0], 0x3a0000000005d11a);
  717. store64(&config.eMask[1], 0x39000000001ba31e);
  718. reg.e[registerDst] = rx_set_vec_f128(0x41937f76fede16ee, 0x411b414296ce93b6);
  719. reg.r[registerSrc] = 0xFFFFFFFFFFFFE930;
  720. rx_set_rounding_mode(RoundToNearest);
  721. decoder.executeInstruction(ibc, pc, (uint8_t*)&mockScratchpad, config);
  722. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  723. assert(equalsHex(&vec, "e7b269639484434632474a66635ba547"));
  724. });
  725. runTest("FDIV_M RoundDown/RoundToZero (execute)", RANDOMX_FREQ_FDIV_M > 0, [&] {
  726. alignas(16) uint64_t vec[2];
  727. alignas(16) uint32_t mockScratchpad[2];
  728. store32(&mockScratchpad[0], 0xd350a1b6);
  729. store32(&mockScratchpad[1], 0x8b2460d9);
  730. store64(&config.eMask[0], 0x3a0000000005d11a);
  731. store64(&config.eMask[1], 0x39000000001ba31e);
  732. reg.e[registerDst] = rx_set_vec_f128(0x41937f76fede16ee, 0x411b414296ce93b6);
  733. reg.r[registerSrc] = 0xFFFFFFFFFFFFE930;
  734. rx_set_rounding_mode(RoundDown);
  735. decoder.executeInstruction(ibc, pc, (uint8_t*)&mockScratchpad, config);
  736. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  737. assert(equalsHex(&vec, "e6b269639484434632474a66635ba547"));
  738. });
  739. runTest("FDIV_M RoundUp (execute)", RANDOMX_FREQ_FDIV_M > 0, [&] {
  740. alignas(16) uint64_t vec[2];
  741. alignas(16) uint32_t mockScratchpad[2];
  742. store32(&mockScratchpad[0], 0xd350a1b6);
  743. store32(&mockScratchpad[1], 0x8b2460d9);
  744. store64(&config.eMask[0], 0x3a0000000005d11a);
  745. store64(&config.eMask[1], 0x39000000001ba31e);
  746. reg.e[registerDst] = rx_set_vec_f128(0x41937f76fede16ee, 0x411b414296ce93b6);
  747. reg.r[registerSrc] = 0xFFFFFFFFFFFFE930;
  748. rx_set_rounding_mode(RoundUp);
  749. decoder.executeInstruction(ibc, pc, (uint8_t*)&mockScratchpad, config);
  750. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  751. assert(equalsHex(&vec, "e7b269639484434633474a66635ba547"));
  752. });
  753. runTest("FSQRT_R (decode)", RANDOMX_FREQ_FSQRT_R > 0, [&] {
  754. randomx::Instruction instr;
  755. instr.opcode = randomx::ceil_FSQRT_R - 1;
  756. instr.dst = registerHigh | registerDst;
  757. decoder.compileInstruction(instr, pc, ibc);
  758. assert(ibc.type == randomx::InstructionType::FSQRT_R);
  759. assert(ibc.fdst == &reg.e[registerDst]);
  760. });
  761. runTest("FSQRT_R RoundToNearest (execute)", RANDOMX_FREQ_FSQRT_R > 0, [&] {
  762. alignas(16) uint64_t vec[2];
  763. reg.e[registerDst] = rx_set_vec_f128(0x41b6b21c11affea7, 0x40526a7e778d9824);
  764. rx_set_rounding_mode(RoundToNearest);
  765. decoder.executeInstruction(ibc, pc, nullptr, config);
  766. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  767. assert(equalsHex(&vec, "e81f300b612a21408dbaa33f570ed340"));
  768. });
  769. runTest("FSQRT_R RoundDown/RoundToZero (execute)", RANDOMX_FREQ_FSQRT_R > 0, [&] {
  770. alignas(16) uint64_t vec[2];
  771. reg.e[registerDst] = rx_set_vec_f128(0x41b6b21c11affea7, 0x40526a7e778d9824);
  772. rx_set_rounding_mode(RoundDown);
  773. decoder.executeInstruction(ibc, pc, nullptr, config);
  774. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  775. assert(equalsHex(&vec, "e81f300b612a21408cbaa33f570ed340"));
  776. });
  777. runTest("FSQRT_R RoundUp (execute)", RANDOMX_FREQ_FSQRT_R > 0, [&] {
  778. alignas(16) uint64_t vec[2];
  779. reg.e[registerDst] = rx_set_vec_f128(0x41b6b21c11affea7, 0x40526a7e778d9824);
  780. rx_set_rounding_mode(RoundUp);
  781. decoder.executeInstruction(ibc, pc, nullptr, config);
  782. rx_store_vec_f128((double*)&vec, reg.e[registerDst]);
  783. assert(equalsHex(&vec, "e91f300b612a21408dbaa33f570ed340"));
  784. });
  785. runTest("CBRANCH (decode) 100", RANDOMX_FREQ_CBRANCH > 0, [&] {
  786. randomx::Instruction instr;
  787. instr.opcode = randomx::ceil_CBRANCH - 1;
  788. instr.dst = registerHigh | registerDst;
  789. instr.setImm32(imm32);
  790. instr.mod = 48;
  791. decoder.compileInstruction(instr, 100, ibc);
  792. assert(ibc.type == randomx::InstructionType::CBRANCH);
  793. assert(ibc.idst == &reg.r[registerDst]);
  794. assert(ibc.imm == 0xFFFFFFFFC0CB9AD2);
  795. assert(ibc.memMask == 0x7F800);
  796. assert(ibc.target == pc);
  797. });
  798. runTest("CBRANCH (decode) 200", RANDOMX_FREQ_CBRANCH > 0, [&] {
  799. randomx::Instruction instr;
  800. instr.opcode = randomx::ceil_CBRANCH - 1;
  801. instr.dst = registerHigh | registerDst;
  802. instr.setImm32(imm32);
  803. instr.mod = 48;
  804. decoder.compileInstruction(instr, pc = 200, ibc);
  805. assert(ibc.type == randomx::InstructionType::CBRANCH);
  806. assert(ibc.idst == &reg.r[registerDst]);
  807. assert(ibc.imm == 0xFFFFFFFFC0CB9AD2);
  808. assert(ibc.memMask == 0x7F800);
  809. assert(ibc.target == 100);
  810. });
  811. runTest("CBRANCH not taken (execute)", RANDOMX_FREQ_CBRANCH > 0, [&] {
  812. reg.r[registerDst] = 0;
  813. decoder.executeInstruction(ibc, pc, nullptr, config);
  814. assert(pc == 200);
  815. });
  816. runTest("CBRANCH taken (execute)", RANDOMX_FREQ_CBRANCH > 0, [&] {
  817. reg.r[registerDst] = 0xFFFFFFFFFFFC6800;
  818. decoder.executeInstruction(ibc, pc, nullptr, config);
  819. assert(pc == ibc.target);
  820. });
  821. runTest("CFROUND (decode)", RANDOMX_FREQ_CFROUND > 0, [&] {
  822. randomx::Instruction instr;
  823. instr.opcode = randomx::ceil_CFROUND - 1;
  824. instr.src = registerHigh | registerSrc;
  825. instr.setImm32(imm32);
  826. decoder.compileInstruction(instr, 100, ibc);
  827. assert(ibc.type == randomx::InstructionType::CFROUND);
  828. assert(ibc.isrc == &reg.r[registerSrc]);
  829. assert(ibc.imm == 18);
  830. });
  831. runTest("ISTORE L1 (decode)", RANDOMX_FREQ_ISTORE > 0, [&] {
  832. randomx::Instruction instr;
  833. instr.opcode = randomx::ceil_ISTORE - 1;
  834. instr.src = registerHigh | registerSrc;
  835. instr.dst = registerHigh | registerDst;
  836. instr.setImm32(imm32);
  837. instr.mod = 1;
  838. decoder.compileInstruction(instr, pc, ibc);
  839. assert(ibc.type == randomx::InstructionType::ISTORE);
  840. assert(ibc.idst == &reg.r[registerDst]);
  841. assert(ibc.isrc == &reg.r[registerSrc]);
  842. assert(ibc.imm == imm64);
  843. assert(ibc.memMask == randomx::ScratchpadL1Mask);
  844. });
  845. runTest("ISTORE L2 (decode)", RANDOMX_FREQ_ISTORE > 0, [&] {
  846. randomx::Instruction instr;
  847. instr.opcode = randomx::ceil_ISTORE - 1;
  848. instr.src = registerHigh | registerSrc;
  849. instr.dst = registerHigh | registerDst;
  850. instr.setImm32(imm32);
  851. instr.mod = 0;
  852. decoder.compileInstruction(instr, pc, ibc);
  853. assert(ibc.type == randomx::InstructionType::ISTORE);
  854. assert(ibc.idst == &reg.r[registerDst]);
  855. assert(ibc.isrc == &reg.r[registerSrc]);
  856. assert(ibc.imm == imm64);
  857. assert(ibc.memMask == randomx::ScratchpadL2Mask);
  858. });
  859. runTest("ISTORE L3 (decode)", RANDOMX_FREQ_ISTORE > 0, [&] {
  860. randomx::Instruction instr;
  861. instr.opcode = randomx::ceil_ISTORE - 1;
  862. instr.src = registerHigh | registerSrc;
  863. instr.dst = registerHigh | registerDst;
  864. instr.setImm32(imm32);
  865. instr.mod = 224;
  866. decoder.compileInstruction(instr, pc, ibc);
  867. assert(ibc.type == randomx::InstructionType::ISTORE);
  868. assert(ibc.idst == &reg.r[registerDst]);
  869. assert(ibc.isrc == &reg.r[registerSrc]);
  870. assert(ibc.imm == imm64);
  871. assert(ibc.memMask == randomx::ScratchpadL3Mask);
  872. });
  873. vm = randomx_create_vm(RANDOMX_FLAG_DEFAULT, cache, nullptr);
  874. auto test_a = [&] {
  875. char hash[RANDOMX_HASH_SIZE];
  876. calcStringHash("test key 000", "This is a test", &hash);
  877. assert(equalsHex(hash, "639183aae1bf4c9a35884cb46b09cad9175f04efd7684e7262a0ac1c2f0b4e3f"));
  878. };
  879. auto test_b = [&] {
  880. char hash[RANDOMX_HASH_SIZE];
  881. calcStringHash("test key 000", "Lorem ipsum dolor sit amet", &hash);
  882. assert(equalsHex(hash, "300a0adb47603dedb42228ccb2b211104f4da45af709cd7547cd049e9489c969"));
  883. };
  884. auto test_c = [&] {
  885. char hash[RANDOMX_HASH_SIZE];
  886. calcStringHash("test key 000", "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", &hash);
  887. assert(equalsHex(hash, "c36d4ed4191e617309867ed66a443be4075014e2b061bcdaf9ce7b721d2b77a8"));
  888. };
  889. auto test_d = [&] {
  890. char hash[RANDOMX_HASH_SIZE];
  891. calcStringHash("test key 001", "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", &hash);
  892. assert(equalsHex(hash, "e9ff4503201c0c2cca26d285c93ae883f9b1d30c9eb240b820756f2d5a7905fc"));
  893. };
  894. auto test_e = [&] {
  895. char hash[RANDOMX_HASH_SIZE];
  896. calcHexHash("test key 001", "0b0b98bea7e805e0010a2126d287a2a0cc833d312cb786385a7c2f9de69d25537f584a9bc9977b00000000666fd8753bf61a8631f12984e3fd44f4014eca629276817b56f32e9b68bd82f416", &hash);
  897. //std::cout << std::endl;
  898. //outputHex(std::cout, (const char*)hash, sizeof(hash));
  899. //std::cout << std::endl;
  900. assert(equalsHex(hash, "c56414121acda1713c2f2a819d8ae38aed7c80c35c2a769298d34f03833cd5f1"));
  901. };
  902. runTest("Hash test 1a (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_a);
  903. runTest("Hash test 1b (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_b);
  904. runTest("Hash test 1c (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_c);
  905. runTest("Hash test 1d (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_d);
  906. runTest("Hash test 1e (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_e);
  907. randomx_release_cache(cache);
  908. cache = randomx_alloc_cache(RANDOMX_FLAG_JIT);
  909. currentKey.size = 0;
  910. randomx_destroy_vm(vm);
  911. initCache("test key 000");
  912. vm = randomx_create_vm(RANDOMX_FLAG_JIT, cache, nullptr);
  913. runTest("Hash test 2a (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_a);
  914. runTest("Hash test 2b (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_b);
  915. runTest("Hash test 2c (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_c);
  916. runTest("Hash test 2d (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_d);
  917. runTest("Hash test 2e (compiler)", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_e);
  918. std::cout << std::endl << "All tests PASSED" << std::endl;
  919. if (skipped) {
  920. std::cout << skipped << " tests were SKIPPED due to incompatible configuration (see above)" << std::endl;
  921. }
  922. }