InterpretedVirtualMachine.cpp 24 KB

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