vm_interpreted.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. /*
  2. Copyright (c) 2018 tevador
  3. This file is part of RandomX.
  4. RandomX is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. RandomX is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with RandomX. If not, see<http://www.gnu.org/licenses/>.
  14. */
  15. //#define TRACE
  16. //#define FPUCHECK
  17. #define RANDOMX_JUMP
  18. #include <iostream>
  19. #include <iomanip>
  20. #include <stdexcept>
  21. #include <sstream>
  22. #include <cmath>
  23. #include <cfloat>
  24. #include <climits>
  25. #include "vm_interpreted.hpp"
  26. #include "dataset.hpp"
  27. #include "intrin_portable.h"
  28. #include "reciprocal.h"
  29. #ifdef FPUCHECK
  30. constexpr bool fpuCheck = true;
  31. #else
  32. constexpr bool fpuCheck = false;
  33. #endif
  34. namespace randomx {
  35. static int_reg_t Zero = 0;
  36. template<class Allocator, bool softAes>
  37. void InterpretedVm<Allocator, softAes>::setDataset(randomx_dataset* dataset) {
  38. mem.memory = dataset->memory;
  39. }
  40. template<class Allocator, bool softAes>
  41. void InterpretedVm<Allocator, softAes>::run(void* seed) {
  42. VmBase<Allocator, softAes>::generateProgram(seed);
  43. randomx_vm::initialize();
  44. for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
  45. program(i).src %= RegistersCount;
  46. program(i).dst %= RegistersCount;
  47. }
  48. execute();
  49. }
  50. template<class Allocator, bool softAes>
  51. void InterpretedVm<Allocator, softAes>::executeBytecode(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
  52. for (int ic = 0; ic < RANDOMX_PROGRAM_SIZE; ++ic) {
  53. executeBytecode(ic, r, f, e, a);
  54. }
  55. }
  56. static void print(int_reg_t r) {
  57. std::cout << std::hex << std::setw(16) << std::setfill('0') << r << std::endl;
  58. }
  59. static void print(__m128d f) {
  60. uint64_t lo = *(((uint64_t*)&f) + 0);
  61. uint64_t hi = *(((uint64_t*)&f) + 1);
  62. std::cout << std::hex << std::setw(16) << std::setfill('0') << hi << '-' << std::hex << std::setw(16) << std::setfill('0') << lo << std::endl;
  63. }
  64. static void printState(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
  65. for (int i = 0; i < 8; ++i) {
  66. std::cout << "r" << i << " = "; print(r[i]);
  67. }
  68. for (int i = 0; i < 4; ++i) {
  69. std::cout << "f" << i << " = "; print(f[i]);
  70. }
  71. for (int i = 0; i < 4; ++i) {
  72. std::cout << "e" << i << " = "; print(e[i]);
  73. }
  74. for (int i = 0; i < 4; ++i) {
  75. std::cout << "a" << i << " = "; print(a[i]);
  76. }
  77. }
  78. static bool isDenormal(double x) {
  79. return std::fpclassify(x) == FP_SUBNORMAL;
  80. }
  81. template<class Allocator, bool softAes>
  82. FORCE_INLINE void* InterpretedVm<Allocator, softAes>::getScratchpadAddress(InstructionByteCode& ibc) {
  83. uint32_t addr = (*ibc.isrc + ibc.imm) & ibc.memMask;
  84. return scratchpad + addr;
  85. }
  86. template<class Allocator, bool softAes>
  87. FORCE_INLINE __m128d InterpretedVm<Allocator, softAes>::maskRegisterExponentMantissa(__m128d x) {
  88. constexpr uint64_t mantissaMask64 = (1ULL << 52) - 1;
  89. const __m128d mantissaMask = _mm_castsi128_pd(_mm_set_epi64x(mantissaMask64, mantissaMask64));
  90. const __m128d exponentMask = _mm_load_pd((const double*)&config.eMask);
  91. x = _mm_and_pd(x, mantissaMask);
  92. x = _mm_or_pd(x, exponentMask);
  93. return x;
  94. }
  95. template<class Allocator, bool softAes>
  96. void InterpretedVm<Allocator, softAes>::executeBytecode(int& ic, int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
  97. auto& ibc = byteCode[ic];
  98. if (trace) std::cout << std::dec << std::setw(3) << ic << " " << program(ic);
  99. switch (ibc.type)
  100. {
  101. case InstructionType::IADD_RS: {
  102. *ibc.idst += (*ibc.isrc << ibc.shift) + ibc.imm;
  103. } break;
  104. case InstructionType::IADD_M: {
  105. *ibc.idst += load64(getScratchpadAddress(ibc));
  106. } break;
  107. case InstructionType::IADD_RC: {
  108. *ibc.idst += *ibc.isrc + ibc.imm;
  109. } break;
  110. case InstructionType::ISUB_R: {
  111. *ibc.idst -= *ibc.isrc;
  112. } break;
  113. case InstructionType::ISUB_M: {
  114. *ibc.idst -= load64(getScratchpadAddress(ibc));
  115. } break;
  116. case InstructionType::IMUL_9C: {
  117. *ibc.idst += 8 * *ibc.idst + ibc.imm;
  118. } break;
  119. case InstructionType::IMUL_R: { //also handles IMUL_RCP
  120. *ibc.idst *= *ibc.isrc;
  121. } break;
  122. case InstructionType::IMUL_M: {
  123. *ibc.idst *= load64(getScratchpadAddress(ibc));
  124. } break;
  125. case InstructionType::IMULH_R: {
  126. *ibc.idst = mulh(*ibc.idst, *ibc.isrc);
  127. } break;
  128. case InstructionType::IMULH_M: {
  129. *ibc.idst = mulh(*ibc.idst, load64(getScratchpadAddress(ibc)));
  130. } break;
  131. case InstructionType::ISMULH_R: {
  132. *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(*ibc.isrc));
  133. } break;
  134. case InstructionType::ISMULH_M: {
  135. *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(load64(getScratchpadAddress(ibc))));
  136. } break;
  137. case InstructionType::INEG_R: {
  138. *ibc.idst = ~(*ibc.idst) + 1; //two's complement negative
  139. } break;
  140. case InstructionType::IXOR_R: {
  141. *ibc.idst ^= *ibc.isrc;
  142. } break;
  143. case InstructionType::IXOR_M: {
  144. *ibc.idst ^= load64(getScratchpadAddress(ibc));
  145. } break;
  146. case InstructionType::IROR_R: {
  147. *ibc.idst = rotr(*ibc.idst, *ibc.isrc & 63);
  148. } break;
  149. case InstructionType::IROL_R: {
  150. *ibc.idst = rotl(*ibc.idst, *ibc.isrc & 63);
  151. } break;
  152. case InstructionType::ISWAP_R: {
  153. int_reg_t temp = *ibc.isrc;
  154. *ibc.isrc = *ibc.idst;
  155. *ibc.idst = temp;
  156. } break;
  157. case InstructionType::FSWAP_R: {
  158. *ibc.fdst = _mm_shuffle_pd(*ibc.fdst, *ibc.fdst, 1);
  159. } break;
  160. case InstructionType::FADD_R: {
  161. *ibc.fdst = _mm_add_pd(*ibc.fdst, *ibc.fsrc);
  162. } break;
  163. case InstructionType::FADD_M: {
  164. __m128d fsrc = load_cvt_i32x2(getScratchpadAddress(ibc));
  165. *ibc.fdst = _mm_add_pd(*ibc.fdst, fsrc);
  166. } break;
  167. case InstructionType::FSUB_R: {
  168. *ibc.fdst = _mm_sub_pd(*ibc.fdst, *ibc.fsrc);
  169. } break;
  170. case InstructionType::FSUB_M: {
  171. __m128d fsrc = load_cvt_i32x2(getScratchpadAddress(ibc));
  172. *ibc.fdst = _mm_sub_pd(*ibc.fdst, fsrc);
  173. } break;
  174. case InstructionType::FSCAL_R: {
  175. const __m128d mask = _mm_castsi128_pd(_mm_set1_epi64x(0x81F0000000000000));
  176. *ibc.fdst = _mm_xor_pd(*ibc.fdst, mask);
  177. } break;
  178. case InstructionType::FMUL_R: {
  179. *ibc.fdst = _mm_mul_pd(*ibc.fdst, *ibc.fsrc);
  180. } break;
  181. case InstructionType::FDIV_M: {
  182. __m128d fsrc = maskRegisterExponentMantissa(load_cvt_i32x2(getScratchpadAddress(ibc)));
  183. *ibc.fdst = _mm_div_pd(*ibc.fdst, fsrc);
  184. } break;
  185. case InstructionType::FSQRT_R: {
  186. *ibc.fdst = _mm_sqrt_pd(*ibc.fdst);
  187. } break;
  188. case InstructionType::COND_R: {
  189. #ifdef RANDOMX_JUMP
  190. *ibc.creg += (1 << ibc.shift);
  191. const uint64_t conditionMask = ((1ULL << RANDOMX_CONDITION_BITS) - 1) << ibc.shift;
  192. if ((*ibc.creg & conditionMask) == 0) {
  193. ic = ibc.target;
  194. break;
  195. }
  196. #endif
  197. *ibc.idst += condition(ibc.condition, *ibc.isrc, ibc.imm) ? 1 : 0;
  198. } break;
  199. case InstructionType::COND_M: {
  200. #ifdef RANDOMX_JUMP
  201. *ibc.creg += (1uLL << ibc.shift);
  202. const uint64_t conditionMask = ((1ULL << RANDOMX_CONDITION_BITS) - 1) << ibc.shift;
  203. if ((*ibc.creg & conditionMask) == 0) {
  204. ic = ibc.target;
  205. break;
  206. }
  207. #endif
  208. *ibc.idst += condition(ibc.condition, load64(getScratchpadAddress(ibc)), ibc.imm) ? 1 : 0;
  209. } break;
  210. case InstructionType::CFROUND: {
  211. setRoundMode(rotr(*ibc.isrc, ibc.imm) % 4);
  212. } break;
  213. case InstructionType::ISTORE: {
  214. store64(scratchpad + ((*ibc.idst + ibc.imm) & ibc.memMask), *ibc.isrc);
  215. } break;
  216. case InstructionType::NOP: {
  217. //nothing
  218. } break;
  219. default:
  220. UNREACHABLE;
  221. }
  222. if (trace) {
  223. if(ibc.type < 20 || ibc.type == 31 || ibc.type == 32)
  224. print(*ibc.idst);
  225. else //if(ibc.type >= 20 && ibc.type <= 30)
  226. print(0);
  227. }
  228. #ifdef FPUCHECK
  229. if (ibc.type >= 26 && ibc.type <= 30) {
  230. double lo = *(((double*)ibc.fdst) + 0);
  231. double hi = *(((double*)ibc.fdst) + 1);
  232. if (lo <= 0 || hi <= 0) {
  233. std::stringstream ss;
  234. ss << "Underflow in operation " << ibc.type;
  235. printState(r, f, e, a);
  236. throw std::runtime_error(ss.str());
  237. }
  238. }
  239. #endif
  240. }
  241. template<class Allocator, bool softAes>
  242. void InterpretedVm<Allocator, softAes>::execute() {
  243. int_reg_t r[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  244. __m128d f[4];
  245. __m128d e[4];
  246. __m128d a[4];
  247. a[0] = _mm_load_pd(&reg.a[0].lo);
  248. a[1] = _mm_load_pd(&reg.a[1].lo);
  249. a[2] = _mm_load_pd(&reg.a[2].lo);
  250. a[3] = _mm_load_pd(&reg.a[3].lo);
  251. precompileProgram(r, f, e, a);
  252. uint32_t spAddr0 = mem.mx;
  253. uint32_t spAddr1 = mem.ma;
  254. if (trace) {
  255. std::cout << "execute (reg: r" << config.readReg0 << ", r" << config.readReg1 << ", r" << config.readReg2 << ", r" << config.readReg3 << ")" << std::endl;
  256. std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl;
  257. std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl;
  258. printState(r, f, e, a);
  259. }
  260. for(unsigned ic = 0; ic < RANDOMX_PROGRAM_ITERATIONS; ++ic) {
  261. uint64_t spMix = r[config.readReg0] ^ r[config.readReg1];
  262. spAddr0 ^= spMix;
  263. spAddr0 &= ScratchpadL3Mask64;
  264. spAddr1 ^= spMix >> 32;
  265. spAddr1 &= ScratchpadL3Mask64;
  266. r[0] ^= load64(scratchpad + spAddr0 + 0);
  267. r[1] ^= load64(scratchpad + spAddr0 + 8);
  268. r[2] ^= load64(scratchpad + spAddr0 + 16);
  269. r[3] ^= load64(scratchpad + spAddr0 + 24);
  270. r[4] ^= load64(scratchpad + spAddr0 + 32);
  271. r[5] ^= load64(scratchpad + spAddr0 + 40);
  272. r[6] ^= load64(scratchpad + spAddr0 + 48);
  273. r[7] ^= load64(scratchpad + spAddr0 + 56);
  274. f[0] = load_cvt_i32x2(scratchpad + spAddr1 + 0);
  275. f[1] = load_cvt_i32x2(scratchpad + spAddr1 + 8);
  276. f[2] = load_cvt_i32x2(scratchpad + spAddr1 + 16);
  277. f[3] = load_cvt_i32x2(scratchpad + spAddr1 + 24);
  278. e[0] = maskRegisterExponentMantissa(load_cvt_i32x2(scratchpad + spAddr1 + 32));
  279. e[1] = maskRegisterExponentMantissa(load_cvt_i32x2(scratchpad + spAddr1 + 40));
  280. e[2] = maskRegisterExponentMantissa(load_cvt_i32x2(scratchpad + spAddr1 + 48));
  281. e[3] = maskRegisterExponentMantissa(load_cvt_i32x2(scratchpad + spAddr1 + 56));
  282. if (trace) {
  283. std::cout << "iteration " << std::dec << ic << std::endl;
  284. std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl;
  285. std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl;
  286. printState(r, f, e, a);
  287. std::cout << "-----------------------------------" << std::endl;
  288. }
  289. executeBytecode(r, f, e, a);
  290. mem.mx ^= r[config.readReg2] ^ r[config.readReg3];
  291. mem.mx &= CacheLineAlignMask;
  292. datasetRead(mem.ma, r);
  293. std::swap(mem.mx, mem.ma);
  294. if (trace) {
  295. std::cout << "iteration " << std::dec << ic << std::endl;
  296. std::cout << "spAddr " << std::hex << std::setw(8) << std::setfill('0') << spAddr1 << " / " << std::setw(8) << std::setfill('0') << spAddr0 << std::endl;
  297. std::cout << "ma/mx " << std::hex << std::setw(8) << std::setfill('0') << mem.ma << std::setw(8) << std::setfill('0') << mem.mx << std::endl;
  298. printState(r, f, e, a);
  299. std::cout << "===================================" << std::endl;
  300. }
  301. store64(scratchpad + spAddr1 + 0, r[0]);
  302. store64(scratchpad + spAddr1 + 8, r[1]);
  303. store64(scratchpad + spAddr1 + 16, r[2]);
  304. store64(scratchpad + spAddr1 + 24, r[3]);
  305. store64(scratchpad + spAddr1 + 32, r[4]);
  306. store64(scratchpad + spAddr1 + 40, r[5]);
  307. store64(scratchpad + spAddr1 + 48, r[6]);
  308. store64(scratchpad + spAddr1 + 56, r[7]);
  309. f[0] = _mm_xor_pd(f[0], e[0]);
  310. f[1] = _mm_xor_pd(f[1], e[1]);
  311. f[2] = _mm_xor_pd(f[2], e[2]);
  312. f[3] = _mm_xor_pd(f[3], e[3]);
  313. #ifdef FPUCHECK
  314. for(int i = 0; i < 4; ++i) {
  315. double lo = *(((double*)&f[i]) + 0);
  316. double hi = *(((double*)&f[i]) + 1);
  317. if (isDenormal(lo) || isDenormal(hi)) {
  318. std::stringstream ss;
  319. ss << "Denormal f" << i;
  320. throw std::runtime_error(ss.str());
  321. }
  322. }
  323. #endif
  324. _mm_store_pd((double*)(scratchpad + spAddr0 + 0), f[0]);
  325. _mm_store_pd((double*)(scratchpad + spAddr0 + 16), f[1]);
  326. _mm_store_pd((double*)(scratchpad + spAddr0 + 32), f[2]);
  327. _mm_store_pd((double*)(scratchpad + spAddr0 + 48), f[3]);
  328. spAddr0 = 0;
  329. spAddr1 = 0;
  330. }
  331. store64(&reg.r[0], r[0]);
  332. store64(&reg.r[1], r[1]);
  333. store64(&reg.r[2], r[2]);
  334. store64(&reg.r[3], r[3]);
  335. store64(&reg.r[4], r[4]);
  336. store64(&reg.r[5], r[5]);
  337. store64(&reg.r[6], r[6]);
  338. store64(&reg.r[7], r[7]);
  339. _mm_store_pd(&reg.f[0].lo, f[0]);
  340. _mm_store_pd(&reg.f[1].lo, f[1]);
  341. _mm_store_pd(&reg.f[2].lo, f[2]);
  342. _mm_store_pd(&reg.f[3].lo, f[3]);
  343. _mm_store_pd(&reg.e[0].lo, e[0]);
  344. _mm_store_pd(&reg.e[1].lo, e[1]);
  345. _mm_store_pd(&reg.e[2].lo, e[2]);
  346. _mm_store_pd(&reg.e[3].lo, e[3]);
  347. }
  348. static int getConditionRegister(int(&registerUsage)[8]) {
  349. int min = INT_MAX;
  350. int minIndex;
  351. for (unsigned i = 0; i < 8; ++i) {
  352. if (registerUsage[i] < min) {
  353. min = registerUsage[i];
  354. minIndex = i;
  355. }
  356. }
  357. return minIndex;
  358. }
  359. template<class Allocator, bool softAes>
  360. void InterpretedVm<Allocator, softAes>::datasetRead(uint32_t address, int_reg_t(&r)[8]) {
  361. uint64_t* datasetLine = (uint64_t*)(mem.memory + address);
  362. for (int i = 0; i < RegistersCount; ++i)
  363. r[i] ^= datasetLine[i];
  364. }
  365. #include "instruction_weights.hpp"
  366. template<class Allocator, bool softAes>
  367. void InterpretedVm<Allocator, softAes>::precompileProgram(int_reg_t(&r)[8], __m128d (&f)[4], __m128d (&e)[4], __m128d (&a)[4]) {
  368. int registerUsage[8];
  369. for (unsigned i = 0; i < 8; ++i) {
  370. registerUsage[i] = -1;
  371. }
  372. for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
  373. auto& instr = program(i);
  374. auto& ibc = byteCode[i];
  375. switch (instr.opcode) {
  376. CASE_REP(IADD_RS) {
  377. auto dst = instr.dst % RegistersCount;
  378. auto src = instr.src % RegistersCount;
  379. ibc.type = InstructionType::IADD_RS;
  380. ibc.idst = &r[dst];
  381. if (dst != RegisterNeedsDisplacement) {
  382. ibc.isrc = &r[src];
  383. ibc.shift = instr.getModShift2();
  384. ibc.imm = 0;
  385. }
  386. else {
  387. ibc.isrc = &r[src];
  388. ibc.shift = instr.getModShift2();
  389. ibc.imm = signExtend2sCompl(instr.getImm32());
  390. }
  391. registerUsage[instr.dst] = i;
  392. } break;
  393. CASE_REP(IADD_M) {
  394. auto dst = instr.dst % RegistersCount;
  395. auto src = instr.src % RegistersCount;
  396. ibc.type = InstructionType::IADD_M;
  397. ibc.idst = &r[dst];
  398. ibc.imm = signExtend2sCompl(instr.getImm32());
  399. if (instr.src != instr.dst) {
  400. ibc.isrc = &r[src];
  401. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  402. }
  403. else {
  404. ibc.isrc = &Zero;
  405. ibc.memMask = ScratchpadL3Mask;
  406. }
  407. registerUsage[instr.dst] = i;
  408. } break;
  409. CASE_REP(IADD_RC) {
  410. auto dst = instr.dst % RegistersCount;
  411. auto src = instr.src % RegistersCount;
  412. ibc.type = InstructionType::IADD_RC;
  413. ibc.idst = &r[dst];
  414. ibc.isrc = &r[src];
  415. ibc.imm = signExtend2sCompl(instr.getImm32());
  416. registerUsage[instr.dst] = i;
  417. } break;
  418. CASE_REP(ISUB_R) {
  419. auto dst = instr.dst % RegistersCount;
  420. auto src = instr.src % RegistersCount;
  421. ibc.type = InstructionType::ISUB_R;
  422. ibc.idst = &r[dst];
  423. if (src != dst) {
  424. ibc.isrc = &r[src];
  425. }
  426. else {
  427. ibc.imm = signExtend2sCompl(instr.getImm32());
  428. ibc.isrc = &ibc.imm;
  429. }
  430. registerUsage[instr.dst] = i;
  431. } break;
  432. CASE_REP(ISUB_M) {
  433. auto dst = instr.dst % RegistersCount;
  434. auto src = instr.src % RegistersCount;
  435. ibc.type = InstructionType::ISUB_M;
  436. ibc.idst = &r[dst];
  437. ibc.imm = signExtend2sCompl(instr.getImm32());
  438. if (instr.src != instr.dst) {
  439. ibc.isrc = &r[src];
  440. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  441. }
  442. else {
  443. ibc.isrc = &Zero;
  444. ibc.memMask = ScratchpadL3Mask;
  445. }
  446. registerUsage[instr.dst] = i;
  447. } break;
  448. CASE_REP(IMUL_9C) {
  449. auto dst = instr.dst % RegistersCount;
  450. ibc.type = InstructionType::IMUL_9C;
  451. ibc.idst = &r[dst];
  452. ibc.imm = signExtend2sCompl(instr.getImm32());
  453. registerUsage[instr.dst] = i;
  454. } break;
  455. CASE_REP(IMUL_R) {
  456. auto dst = instr.dst % RegistersCount;
  457. auto src = instr.src % RegistersCount;
  458. ibc.type = InstructionType::IMUL_R;
  459. ibc.idst = &r[dst];
  460. if (src != dst) {
  461. ibc.isrc = &r[src];
  462. }
  463. else {
  464. ibc.imm = signExtend2sCompl(instr.getImm32());
  465. ibc.isrc = &ibc.imm;
  466. }
  467. registerUsage[instr.dst] = i;
  468. } break;
  469. CASE_REP(IMUL_M) {
  470. auto dst = instr.dst % RegistersCount;
  471. auto src = instr.src % RegistersCount;
  472. ibc.type = InstructionType::IMUL_M;
  473. ibc.idst = &r[dst];
  474. ibc.imm = signExtend2sCompl(instr.getImm32());
  475. if (instr.src != instr.dst) {
  476. ibc.isrc = &r[src];
  477. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  478. }
  479. else {
  480. ibc.isrc = &Zero;
  481. ibc.memMask = ScratchpadL3Mask;
  482. }
  483. registerUsage[instr.dst] = i;
  484. } break;
  485. CASE_REP(IMULH_R) {
  486. auto dst = instr.dst % RegistersCount;
  487. auto src = instr.src % RegistersCount;
  488. ibc.type = InstructionType::IMULH_R;
  489. ibc.idst = &r[dst];
  490. ibc.isrc = &r[src];
  491. registerUsage[instr.dst] = i;
  492. } break;
  493. CASE_REP(IMULH_M) {
  494. auto dst = instr.dst % RegistersCount;
  495. auto src = instr.src % RegistersCount;
  496. ibc.type = InstructionType::IMULH_M;
  497. ibc.idst = &r[dst];
  498. ibc.imm = signExtend2sCompl(instr.getImm32());
  499. if (instr.src != instr.dst) {
  500. ibc.isrc = &r[src];
  501. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  502. }
  503. else {
  504. ibc.isrc = &Zero;
  505. ibc.memMask = ScratchpadL3Mask;
  506. }
  507. registerUsage[instr.dst] = i;
  508. } break;
  509. CASE_REP(ISMULH_R) {
  510. auto dst = instr.dst % RegistersCount;
  511. auto src = instr.src % RegistersCount;
  512. ibc.type = InstructionType::ISMULH_R;
  513. ibc.idst = &r[dst];
  514. ibc.isrc = &r[src];
  515. registerUsage[instr.dst] = i;
  516. } break;
  517. CASE_REP(ISMULH_M) {
  518. auto dst = instr.dst % RegistersCount;
  519. auto src = instr.src % RegistersCount;
  520. ibc.type = InstructionType::ISMULH_M;
  521. ibc.idst = &r[dst];
  522. ibc.imm = signExtend2sCompl(instr.getImm32());
  523. if (instr.src != instr.dst) {
  524. ibc.isrc = &r[src];
  525. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  526. }
  527. else {
  528. ibc.isrc = &Zero;
  529. ibc.memMask = ScratchpadL3Mask;
  530. }
  531. registerUsage[instr.dst] = i;
  532. } break;
  533. CASE_REP(IMUL_RCP) {
  534. uint32_t divisor = instr.getImm32();
  535. if (divisor != 0) {
  536. auto dst = instr.dst % RegistersCount;
  537. ibc.type = InstructionType::IMUL_R;
  538. ibc.idst = &r[dst];
  539. ibc.imm = randomx_reciprocal(divisor);
  540. ibc.isrc = &ibc.imm;
  541. registerUsage[instr.dst] = i;
  542. }
  543. else {
  544. ibc.type = InstructionType::NOP;
  545. }
  546. } break;
  547. CASE_REP(INEG_R) {
  548. auto dst = instr.dst % RegistersCount;
  549. ibc.type = InstructionType::INEG_R;
  550. ibc.idst = &r[dst];
  551. registerUsage[instr.dst] = i;
  552. } break;
  553. CASE_REP(IXOR_R) {
  554. auto dst = instr.dst % RegistersCount;
  555. auto src = instr.src % RegistersCount;
  556. ibc.type = InstructionType::IXOR_R;
  557. ibc.idst = &r[dst];
  558. if (src != dst) {
  559. ibc.isrc = &r[src];
  560. }
  561. else {
  562. ibc.imm = signExtend2sCompl(instr.getImm32());
  563. ibc.isrc = &ibc.imm;
  564. }
  565. registerUsage[instr.dst] = i;
  566. } break;
  567. CASE_REP(IXOR_M) {
  568. auto dst = instr.dst % RegistersCount;
  569. auto src = instr.src % RegistersCount;
  570. ibc.type = InstructionType::IXOR_M;
  571. ibc.idst = &r[dst];
  572. ibc.imm = signExtend2sCompl(instr.getImm32());
  573. if (instr.src != instr.dst) {
  574. ibc.isrc = &r[src];
  575. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  576. }
  577. else {
  578. ibc.isrc = &Zero;
  579. ibc.memMask = ScratchpadL3Mask;
  580. }
  581. registerUsage[instr.dst] = i;
  582. } break;
  583. CASE_REP(IROR_R) {
  584. auto dst = instr.dst % RegistersCount;
  585. auto src = instr.src % RegistersCount;
  586. ibc.type = InstructionType::IROR_R;
  587. ibc.idst = &r[dst];
  588. if (src != dst) {
  589. ibc.isrc = &r[src];
  590. }
  591. else {
  592. ibc.imm = instr.getImm32();
  593. ibc.isrc = &ibc.imm;
  594. }
  595. registerUsage[instr.dst] = i;
  596. } break;
  597. CASE_REP(IROL_R) {
  598. auto dst = instr.dst % RegistersCount;
  599. auto src = instr.src % RegistersCount;
  600. ibc.type = InstructionType::IROL_R;
  601. ibc.idst = &r[dst];
  602. if (src != dst) {
  603. ibc.isrc = &r[src];
  604. }
  605. else {
  606. ibc.imm = instr.getImm32();
  607. ibc.isrc = &ibc.imm;
  608. }
  609. registerUsage[instr.dst] = i;
  610. } break;
  611. CASE_REP(ISWAP_R) {
  612. auto dst = instr.dst % RegistersCount;
  613. auto src = instr.src % RegistersCount;
  614. if (src != dst) {
  615. ibc.idst = &r[dst];
  616. ibc.isrc = &r[src];
  617. ibc.type = InstructionType::ISWAP_R;
  618. registerUsage[instr.dst] = i;
  619. registerUsage[instr.src] = i;
  620. }
  621. else {
  622. ibc.type = InstructionType::NOP;
  623. }
  624. } break;
  625. CASE_REP(FSWAP_R) {
  626. auto dst = instr.dst % RegistersCount;
  627. ibc.type = InstructionType::FSWAP_R;
  628. if (dst < 4)
  629. ibc.fdst = &f[dst];
  630. else
  631. ibc.fdst = &e[dst - 4];
  632. } break;
  633. CASE_REP(FADD_R) {
  634. auto dst = instr.dst % 4;
  635. auto src = instr.src % 4;
  636. ibc.type = InstructionType::FADD_R;
  637. ibc.fdst = &f[dst];
  638. ibc.fsrc = &a[src];
  639. } break;
  640. CASE_REP(FADD_M) {
  641. auto dst = instr.dst % 4;
  642. auto src = instr.src % 8;
  643. ibc.type = InstructionType::FADD_M;
  644. ibc.fdst = &f[dst];
  645. ibc.isrc = &r[src];
  646. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  647. ibc.imm = signExtend2sCompl(instr.getImm32());
  648. } break;
  649. CASE_REP(FSUB_R) {
  650. auto dst = instr.dst % 4;
  651. auto src = instr.src % 4;
  652. ibc.type = InstructionType::FSUB_R;
  653. ibc.fdst = &f[dst];
  654. ibc.fsrc = &a[src];
  655. } break;
  656. CASE_REP(FSUB_M) {
  657. auto dst = instr.dst % 4;
  658. auto src = instr.src % 8;
  659. ibc.type = InstructionType::FSUB_M;
  660. ibc.fdst = &f[dst];
  661. ibc.isrc = &r[src];
  662. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  663. ibc.imm = signExtend2sCompl(instr.getImm32());
  664. } break;
  665. CASE_REP(FSCAL_R) {
  666. auto dst = instr.dst % 4;
  667. ibc.fdst = &f[dst];
  668. ibc.type = InstructionType::FSCAL_R;
  669. } break;
  670. CASE_REP(FMUL_R) {
  671. auto dst = instr.dst % 4;
  672. auto src = instr.src % 4;
  673. ibc.type = InstructionType::FMUL_R;
  674. ibc.fdst = &e[dst];
  675. ibc.fsrc = &a[src];
  676. } break;
  677. CASE_REP(FDIV_M) {
  678. auto dst = instr.dst % 4;
  679. auto src = instr.src % 8;
  680. ibc.type = InstructionType::FDIV_M;
  681. ibc.fdst = &e[dst];
  682. ibc.isrc = &r[src];
  683. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  684. ibc.imm = signExtend2sCompl(instr.getImm32());
  685. } break;
  686. CASE_REP(FSQRT_R) {
  687. auto dst = instr.dst % 4;
  688. ibc.type = InstructionType::FSQRT_R;
  689. ibc.fdst = &e[dst];
  690. } break;
  691. CASE_REP(COND_R) {
  692. auto dst = instr.dst % RegistersCount;
  693. auto src = instr.src % RegistersCount;
  694. ibc.type = InstructionType::COND_R;
  695. ibc.idst = &r[dst];
  696. ibc.isrc = &r[src];
  697. ibc.condition = instr.getModCond();
  698. ibc.imm = instr.getImm32();
  699. //jump condition
  700. int reg = getConditionRegister(registerUsage);
  701. ibc.target = registerUsage[reg];
  702. ibc.shift = instr.getModShift3();
  703. ibc.creg = &r[reg];
  704. for (unsigned j = 0; j < 8; ++j) { //mark all registers as used
  705. registerUsage[j] = i;
  706. }
  707. } break;
  708. CASE_REP(COND_M) {
  709. auto dst = instr.dst % RegistersCount;
  710. auto src = instr.src % RegistersCount;
  711. ibc.type = InstructionType::COND_M;
  712. ibc.idst = &r[dst];
  713. ibc.isrc = &r[src];
  714. ibc.condition = instr.getModCond();
  715. ibc.imm = instr.getImm32();
  716. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  717. //jump condition
  718. int reg = getConditionRegister(registerUsage);
  719. ibc.target = registerUsage[reg];
  720. ibc.shift = instr.getModShift3();
  721. ibc.creg = &r[reg];
  722. for (unsigned j = 0; j < 8; ++j) { //mark all registers as used
  723. registerUsage[j] = i;
  724. }
  725. } break;
  726. CASE_REP(CFROUND) {
  727. auto src = instr.src % 8;
  728. ibc.isrc = &r[src];
  729. ibc.type = InstructionType::CFROUND;
  730. ibc.imm = instr.getImm32() & 63;
  731. } break;
  732. CASE_REP(ISTORE) {
  733. auto dst = instr.dst % RegistersCount;
  734. auto src = instr.src % RegistersCount;
  735. ibc.type = InstructionType::ISTORE;
  736. ibc.idst = &r[dst];
  737. ibc.isrc = &r[src];
  738. ibc.imm = signExtend2sCompl(instr.getImm32());
  739. if (instr.getModCond())
  740. ibc.memMask = (instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
  741. else
  742. ibc.memMask = ScratchpadL3Mask;
  743. } break;
  744. CASE_REP(NOP) {
  745. ibc.type = InstructionType::NOP;
  746. } break;
  747. default:
  748. UNREACHABLE;
  749. }
  750. }
  751. }
  752. template class InterpretedVm<AlignedAllocator<CacheLineSize>, false>;
  753. template class InterpretedVm<AlignedAllocator<CacheLineSize>, true>;
  754. template class InterpretedVm<LargePageAllocator, false>;
  755. template class InterpretedVm<LargePageAllocator, true>;
  756. }