InterpretedVirtualMachine.cpp 22 KB

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