InterpretedVirtualMachine.cpp 22 KB

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