InterpretedVirtualMachine.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 "Pcg32.hpp"
  19. #include "instructions.hpp"
  20. #include <iostream>
  21. #include <iomanip>
  22. #include <stdexcept>
  23. #include <sstream>
  24. #include <cmath>
  25. #ifdef STATS
  26. #include <algorithm>
  27. #endif
  28. #ifdef FPUCHECK
  29. constexpr bool fpuCheck = true;
  30. #else
  31. constexpr bool fpuCheck = false;
  32. #endif
  33. namespace RandomX {
  34. void InterpretedVirtualMachine::initializeProgram(const void* seed) {
  35. Pcg32 gen(seed);
  36. for (unsigned i = 0; i < sizeof(reg) / sizeof(Pcg32::result_type); ++i) {
  37. *(((uint32_t*)&reg) + i) = gen();
  38. }
  39. FPINIT();
  40. for (int i = 0; i < RegistersCount; ++i) {
  41. reg.f[i].lo.f64 = (double)reg.f[i].lo.i64;
  42. reg.f[i].hi.f64 = (double)reg.f[i].hi.i64;
  43. }
  44. //std::cout << reg;
  45. p.initialize(gen);
  46. mem.ma = (gen() ^ *(((uint32_t*)seed) + 4)) & ~7;
  47. mem.mx = *(((uint32_t*)seed) + 5);
  48. pc = 0;
  49. ic = InstructionCount;
  50. stack.clear();
  51. }
  52. void InterpretedVirtualMachine::execute() {
  53. while (ic > 0) {
  54. #ifdef STATS
  55. count_instructions[pc]++;
  56. #endif
  57. auto& inst = p(pc);
  58. if(trace) std::cout << inst.getName() << " (" << std::dec << pc << ")" << std::endl;
  59. pc = (pc + 1) % ProgramLength;
  60. auto handler = engine[inst.opcode];
  61. (this->*handler)(inst);
  62. ic--;
  63. }
  64. #ifdef STATS
  65. count_endstack += stack.size();
  66. #endif
  67. }
  68. convertible_t InterpretedVirtualMachine::loada(Instruction& inst) {
  69. convertible_t& rega = reg.r[inst.rega % RegistersCount];
  70. rega.i64 ^= inst.addra; //sign-extend addra
  71. addr_t addr = rega.u32;
  72. switch (inst.loca & 7)
  73. {
  74. case 0:
  75. case 1:
  76. case 2:
  77. case 3:
  78. return readDataset(addr, mem);
  79. case 4:
  80. return scratchpad[addr % ScratchpadL2];
  81. case 5:
  82. case 6:
  83. case 7:
  84. return scratchpad[addr % ScratchpadL1];
  85. }
  86. }
  87. convertible_t InterpretedVirtualMachine::loadbr1(Instruction& inst) {
  88. switch (inst.locb & 7)
  89. {
  90. case 0:
  91. case 1:
  92. case 2:
  93. case 3:
  94. case 4:
  95. case 5:
  96. return reg.r[inst.regb % RegistersCount];
  97. case 6:
  98. case 7:
  99. convertible_t temp;
  100. temp.i64 = inst.imm32; //sign-extend imm32
  101. return temp;
  102. }
  103. }
  104. convertible_t InterpretedVirtualMachine::loadbr0(Instruction& inst) {
  105. switch (inst.locb & 7)
  106. {
  107. case 0:
  108. case 1:
  109. case 2:
  110. case 3:
  111. return reg.r[inst.regb % RegistersCount];
  112. case 4:
  113. case 5:
  114. case 6:
  115. case 7:
  116. convertible_t temp;
  117. temp.u64 = inst.imm8;
  118. return temp;
  119. }
  120. }
  121. convertible_t& InterpretedVirtualMachine::getcr(Instruction& inst) {
  122. addr_t addr;
  123. switch (inst.locc & 7)
  124. {
  125. case 0:
  126. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  127. return scratchpad[addr % ScratchpadL2];
  128. case 1:
  129. case 2:
  130. case 3:
  131. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  132. return scratchpad[addr % ScratchpadL1];
  133. case 4:
  134. case 5:
  135. case 6:
  136. case 7:
  137. return reg.r[inst.regc % RegistersCount];
  138. }
  139. }
  140. void InterpretedVirtualMachine::writecf(Instruction& inst, fpu_reg_t& regc) {
  141. addr_t addr;
  142. switch (inst.locc & 7)
  143. {
  144. case 4:
  145. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  146. scratchpad[addr % ScratchpadL2] = (inst.locc & 8) ? regc.hi : regc.lo;
  147. break;
  148. case 5:
  149. case 6:
  150. case 7:
  151. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  152. scratchpad[addr % ScratchpadL1] = (inst.locc & 8) ? regc.hi : regc.lo;
  153. default:
  154. break;
  155. }
  156. }
  157. void InterpretedVirtualMachine::writecflo(Instruction& inst, fpu_reg_t& regc) {
  158. addr_t addr;
  159. switch (inst.locc & 7)
  160. {
  161. case 4:
  162. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  163. scratchpad[addr % ScratchpadL2] = regc.lo;
  164. break;
  165. case 5:
  166. case 6:
  167. case 7:
  168. addr = reg.r[inst.regc % RegistersCount].u32 ^ inst.addrc;
  169. scratchpad[addr % ScratchpadL1] = regc.lo;
  170. default:
  171. break;
  172. }
  173. }
  174. #define ALU_RETIRE(x) x(a, b, c); \
  175. if(trace) std::cout << std::hex << /*a.u64 << " " << b.u64 << " " <<*/ c.u64 << std::endl;
  176. #define FPU_RETIRE(x) x(a, b, c); \
  177. writecf(inst, c); \
  178. if(trace) { \
  179. std::cout << std::hex << ((inst.locc & 8) ? c.hi.u64 : c.lo.u64) << std::endl; \
  180. } \
  181. if(fpuCheck) { \
  182. if(c.hi.f64 != c.hi.f64 || c.lo.f64 != c.lo.f64) { \
  183. std::stringstream ss; \
  184. ss << "NaN result of " << #x << "(" << std::hex << a.u64 << ", " << b.hi.u64 << " " << b.lo.u64 << ") = " << c.hi.u64 << " " << c.lo.u64 << std::endl; \
  185. throw std::runtime_error(ss.str()); \
  186. } else if (std::fpclassify(c.hi.f64) == FP_SUBNORMAL || std::fpclassify(c.lo.f64) == FP_SUBNORMAL) {\
  187. std::stringstream ss; \
  188. ss << "Denormal result of " << #x << "(" << std::hex << a.u64 << ", " << b.hi.u64 << " " << b.lo.u64 << ") = " << c.hi.u64 << " " << c.lo.u64 << std::endl; \
  189. throw std::runtime_error(ss.str()); \
  190. } \
  191. }
  192. #ifdef STATS
  193. #define INC_COUNT(x) count_##x++;
  194. #else
  195. #define INC_COUNT(x)
  196. #endif
  197. #define FPU_RETIRE_FPSQRT(x) FPSQRT(a, b, c); \
  198. writecf(inst, c); \
  199. if(trace) std::cout << std::hex << ((inst.locc & 8) ? c.hi.u64 : c.lo.u64) << std::endl;
  200. #define FPU_RETIRE_FPROUND(x) FPROUND(a, b, c); \
  201. writecflo(inst, c); \
  202. if(trace) std::cout << std::hex << c.lo.u64 << std::endl;
  203. #define ALU_INST(x) void InterpretedVirtualMachine::h_##x(Instruction& inst) { \
  204. INC_COUNT(x) \
  205. convertible_t a = loada(inst); \
  206. convertible_t b = loadbr1(inst); \
  207. convertible_t& c = getcr(inst); \
  208. ALU_RETIRE(x) \
  209. }
  210. #define ALU_INST_SR(x) void InterpretedVirtualMachine::h_##x(Instruction& inst) { \
  211. INC_COUNT(x) \
  212. convertible_t a = loada(inst); \
  213. convertible_t b = loadbr0(inst); \
  214. convertible_t& c = getcr(inst); \
  215. ALU_RETIRE(x) \
  216. }
  217. #define FPU_INST(x) void InterpretedVirtualMachine::h_##x(Instruction& inst) { \
  218. INC_COUNT(x) \
  219. convertible_t a = loada(inst); \
  220. fpu_reg_t& b = reg.f[inst.regb % RegistersCount]; \
  221. fpu_reg_t& c = reg.f[inst.regc % RegistersCount]; \
  222. FPU_RETIRE(x) \
  223. }
  224. #define FPU_INST_NB(x) void InterpretedVirtualMachine::h_##x(Instruction& inst) { \
  225. INC_COUNT(x) \
  226. convertible_t a = loada(inst); \
  227. fpu_reg_t b; \
  228. fpu_reg_t& c = reg.f[inst.regc % RegistersCount]; \
  229. FPU_RETIRE_##x(x) \
  230. }
  231. ALU_INST(ADD_64)
  232. ALU_INST(ADD_32)
  233. ALU_INST(SUB_64)
  234. ALU_INST(SUB_32)
  235. ALU_INST(MUL_64)
  236. ALU_INST(MULH_64)
  237. ALU_INST(MUL_32)
  238. ALU_INST(IMUL_32)
  239. ALU_INST(IMULH_64)
  240. ALU_INST(DIV_64)
  241. ALU_INST(IDIV_64)
  242. ALU_INST(AND_64)
  243. ALU_INST(AND_32)
  244. ALU_INST(OR_64)
  245. ALU_INST(OR_32)
  246. ALU_INST(XOR_64)
  247. ALU_INST(XOR_32)
  248. ALU_INST_SR(SHL_64)
  249. ALU_INST_SR(SHR_64)
  250. ALU_INST_SR(SAR_64)
  251. ALU_INST_SR(ROL_64)
  252. ALU_INST_SR(ROR_64)
  253. FPU_INST(FPADD)
  254. FPU_INST(FPSUB)
  255. FPU_INST(FPMUL)
  256. FPU_INST(FPDIV)
  257. FPU_INST_NB(FPSQRT)
  258. FPU_INST_NB(FPROUND)
  259. void InterpretedVirtualMachine::h_CALL(Instruction& inst) {
  260. convertible_t a = loada(inst);
  261. if (JMP_COND(inst.locb, reg.r[inst.regb % RegistersCount], inst.imm32)) {
  262. #ifdef STATS
  263. count_CALL_taken++;
  264. count_jump_taken[inst.locb & 7]++;
  265. count_retdepth = std::max(0, count_retdepth - 1);
  266. #endif
  267. stackPush(a);
  268. stackPush(pc);
  269. #ifdef STATS
  270. count_max_stack = std::max(count_max_stack, (int)stack.size());
  271. #endif
  272. pc += (inst.imm8 & 127) + 1;
  273. pc = pc % ProgramLength;
  274. if (trace) std::cout << std::hex << a.u64 << std::endl;
  275. }
  276. else {
  277. convertible_t& c = getcr(inst);
  278. #ifdef STATS
  279. count_CALL_not_taken++;
  280. count_jump_not_taken[inst.locb & 7]++;
  281. #endif
  282. c.u64 = a.u64;
  283. if (trace) std::cout << std::hex << /*a.u64 << " " <<*/ c.u64 << std::endl;
  284. }
  285. }
  286. void InterpretedVirtualMachine::h_RET(Instruction& inst) {
  287. convertible_t a = loada(inst);
  288. convertible_t b = loadbr1(inst);
  289. convertible_t& c = getcr(inst);
  290. if (stack.size() > 0) {
  291. #ifdef STATS
  292. count_RET_taken++;
  293. count_retdepth++;
  294. count_retdepth_max = std::max(count_retdepth_max, count_retdepth);
  295. #endif
  296. auto raddr = stackPopAddress();
  297. auto retval = stackPopValue();
  298. c.u64 = a.u64 ^ retval.u64;
  299. pc = raddr;
  300. }
  301. else {
  302. #ifdef STATS
  303. if (stack.size() == 0)
  304. count_RET_stack_empty++;
  305. else {
  306. count_RET_not_taken++;
  307. count_jump_not_taken[inst.locb & 7]++;
  308. }
  309. #endif
  310. c.u64 = a.u64;
  311. }
  312. if (trace) std::cout << std::hex << /*a.u64 << " " <<*/ c.u64 << std::endl;
  313. }
  314. #include "instructionWeights.hpp"
  315. #define INST_HANDLE(x) REPN(&InterpretedVirtualMachine::h_##x, WT(x))
  316. InstructionHandler InterpretedVirtualMachine::engine[256] = {
  317. INST_HANDLE(ADD_64)
  318. INST_HANDLE(ADD_32)
  319. INST_HANDLE(SUB_64)
  320. INST_HANDLE(SUB_32)
  321. INST_HANDLE(MUL_64)
  322. INST_HANDLE(MULH_64)
  323. INST_HANDLE(MUL_32)
  324. INST_HANDLE(IMUL_32)
  325. INST_HANDLE(IMULH_64)
  326. INST_HANDLE(DIV_64)
  327. INST_HANDLE(IDIV_64)
  328. INST_HANDLE(AND_64)
  329. INST_HANDLE(AND_32)
  330. INST_HANDLE(OR_64)
  331. INST_HANDLE(OR_32)
  332. INST_HANDLE(XOR_64)
  333. INST_HANDLE(XOR_32)
  334. INST_HANDLE(SHL_64)
  335. INST_HANDLE(SHR_64)
  336. INST_HANDLE(SAR_64)
  337. INST_HANDLE(ROL_64)
  338. INST_HANDLE(ROR_64)
  339. INST_HANDLE(FPADD)
  340. INST_HANDLE(FPSUB)
  341. INST_HANDLE(FPMUL)
  342. INST_HANDLE(FPDIV)
  343. INST_HANDLE(FPSQRT)
  344. INST_HANDLE(FPROUND)
  345. INST_HANDLE(CALL)
  346. INST_HANDLE(RET)
  347. };
  348. }