tests.cpp 38 KB

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