JitCompilerX86.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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. #include <cstring>
  16. #include <climits>
  17. #include <stdexcept>
  18. #include "JitCompilerX86.hpp"
  19. #include "Program.hpp"
  20. #include "reciprocal.h"
  21. #include "virtualMemory.hpp"
  22. #define RANDOMX_JUMP
  23. namespace RandomX {
  24. #if !defined(_M_X64) && !defined(__x86_64__)
  25. JitCompilerX86::JitCompilerX86() {
  26. throw std::runtime_error("JIT compiler only supports x86-64 CPUs");
  27. }
  28. void JitCompilerX86::generateProgram(Program& p) {
  29. }
  30. void JitCompilerX86::generateProgramLight(Program& p) {
  31. }
  32. size_t JitCompilerX86::getCodeSize() {
  33. return 0;
  34. }
  35. #else
  36. /*
  37. REGISTER ALLOCATION:
  38. ; rax -> temporary
  39. ; rbx -> loop counter "lc"
  40. ; rcx -> temporary
  41. ; rdx -> temporary
  42. ; rsi -> scratchpad pointer
  43. ; rdi -> dataset pointer
  44. ; rbp -> memory registers "ma" (high 32 bits), "mx" (low 32 bits)
  45. ; rsp -> stack pointer
  46. ; r8 -> "r0"
  47. ; r9 -> "r1"
  48. ; r10 -> "r2"
  49. ; r11 -> "r3"
  50. ; r12 -> "r4"
  51. ; r13 -> "r5"
  52. ; r14 -> "r6"
  53. ; r15 -> "r7"
  54. ; xmm0 -> "f0"
  55. ; xmm1 -> "f1"
  56. ; xmm2 -> "f2"
  57. ; xmm3 -> "f3"
  58. ; xmm4 -> "e0"
  59. ; xmm5 -> "e1"
  60. ; xmm6 -> "e2"
  61. ; xmm7 -> "e3"
  62. ; xmm8 -> "a0"
  63. ; xmm9 -> "a1"
  64. ; xmm10 -> "a2"
  65. ; xmm11 -> "a3"
  66. ; xmm12 -> temporary
  67. ; xmm13 -> mantissa mask = 0x000fffffffffffff000fffffffffffff
  68. ; xmm14 -> exponent 2**-240 = 0x30f000000000000030f0000000000000
  69. ; xmm15 -> scale mask = 0x81f000000000000081f0000000000000
  70. */
  71. #include "JitCompilerX86-static.hpp"
  72. const uint8_t* codePrologue = (uint8_t*)&randomx_program_prologue;
  73. const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin;
  74. const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load;
  75. const uint8_t* codeProgamStart = (uint8_t*)&randomx_program_start;
  76. const uint8_t* codeReadDataset = (uint8_t*)&randomx_program_read_dataset;
  77. const uint8_t* codeReadDatasetLight = (uint8_t*)&randomx_program_read_dataset_light;
  78. const uint8_t* codeLoopStore = (uint8_t*)&randomx_program_loop_store;
  79. const uint8_t* codeLoopEnd = (uint8_t*)&randomx_program_loop_end;
  80. const uint8_t* codeReadDatasetLightSub = (uint8_t*)&randomx_program_read_dataset_light_sub;
  81. const uint8_t* codeEpilogue = (uint8_t*)&randomx_program_epilogue;
  82. const uint8_t* codeProgramEnd = (uint8_t*)&randomx_program_end;
  83. const int32_t prologueSize = codeLoopBegin - codePrologue;
  84. const int32_t epilogueSize = codeProgramEnd - codeEpilogue;
  85. const int32_t loopLoadSize = codeProgamStart - codeLoopLoad;
  86. const int32_t readDatasetSize = codeReadDatasetLight - codeReadDataset;
  87. const int32_t readDatasetLightSize = codeLoopStore - codeReadDatasetLight;
  88. const int32_t loopStoreSize = codeLoopEnd - codeLoopStore;
  89. const int32_t readDatasetLightSubSize = codeEpilogue - codeReadDatasetLightSub;
  90. const int32_t epilogueOffset = CodeSize - epilogueSize;
  91. const int32_t readDatasetLightSubOffset = epilogueOffset - readDatasetLightSubSize;
  92. static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 };
  93. static const uint8_t REX_ADD_RM[] = { 0x4c, 0x03 };
  94. static const uint8_t REX_SUB_RR[] = { 0x4d, 0x2b };
  95. static const uint8_t REX_SUB_RM[] = { 0x4c, 0x2b };
  96. static const uint8_t REX_MOV_RR[] = { 0x41, 0x8b };
  97. static const uint8_t REX_MOV_RR64[] = { 0x49, 0x8b };
  98. static const uint8_t REX_MOV_R64R[] = { 0x4c, 0x8b };
  99. static const uint8_t REX_IMUL_RR[] = { 0x4d, 0x0f, 0xaf };
  100. static const uint8_t REX_IMUL_RRI[] = { 0x4d, 0x69 };
  101. static const uint8_t REX_IMUL_RM[] = { 0x4c, 0x0f, 0xaf };
  102. static const uint8_t REX_MUL_R[] = { 0x49, 0xf7 };
  103. static const uint8_t REX_MUL_M[] = { 0x48, 0xf7 };
  104. static const uint8_t REX_81[] = { 0x49, 0x81 };
  105. static const uint8_t AND_EAX_I = 0x25;
  106. static const uint8_t MOV_EAX_I = 0xb8;
  107. static const uint8_t MOV_RAX_I[] = { 0x48, 0xb8 };
  108. static const uint8_t MOV_RCX_I[] = { 0x48, 0xb9 };
  109. static const uint8_t REX_LEA[] = { 0x4f, 0x8d };
  110. static const uint8_t REX_MUL_MEM[] = { 0x48, 0xf7, 0x24, 0x0e };
  111. static const uint8_t REX_IMUL_MEM[] = { 0x48, 0xf7, 0x2c, 0x0e };
  112. static const uint8_t REX_SHR_RAX[] = { 0x48, 0xc1, 0xe8 };
  113. static const uint8_t RAX_ADD_SBB_1[] = { 0x48, 0x83, 0xC0, 0x01, 0x48, 0x83, 0xD8, 0x00 };
  114. static const uint8_t MUL_RCX[] = { 0x48, 0xf7, 0xe1 };
  115. static const uint8_t REX_SHR_RDX[] = { 0x48, 0xc1, 0xea };
  116. static const uint8_t REX_SH[] = { 0x49, 0xc1 };
  117. static const uint8_t MOV_RCX_RAX_SAR_RCX_63[] = { 0x48, 0x89, 0xc1, 0x48, 0xc1, 0xf9, 0x3f };
  118. static const uint8_t AND_ECX_I[] = { 0x81, 0xe1 };
  119. static const uint8_t ADD_RAX_RCX[] = { 0x48, 0x01, 0xC8 };
  120. static const uint8_t SAR_RAX_I8[] = { 0x48, 0xC1, 0xF8 };
  121. static const uint8_t NEG_RAX[] = { 0x48, 0xF7, 0xD8 };
  122. static const uint8_t ADD_R_RAX[] = { 0x4C, 0x03 };
  123. static const uint8_t XOR_EAX_EAX[] = { 0x33, 0xC0 };
  124. static const uint8_t ADD_RDX_R[] = { 0x4c, 0x01 };
  125. static const uint8_t SUB_RDX_R[] = { 0x4c, 0x29 };
  126. static const uint8_t SAR_RDX_I8[] = { 0x48, 0xC1, 0xFA };
  127. static const uint8_t TEST_RDX_RDX[] = { 0x48, 0x85, 0xD2 };
  128. static const uint8_t SETS_AL_ADD_RDX_RAX[] = { 0x0F, 0x98, 0xC0, 0x48, 0x03, 0xD0 };
  129. static const uint8_t REX_NEG[] = { 0x49, 0xF7 };
  130. static const uint8_t REX_XOR_RR[] = { 0x4D, 0x33 };
  131. static const uint8_t REX_XOR_RI[] = { 0x49, 0x81 };
  132. static const uint8_t REX_XOR_RM[] = { 0x4c, 0x33 };
  133. static const uint8_t REX_ROT_CL[] = { 0x49, 0xd3 };
  134. static const uint8_t REX_ROT_I8[] = { 0x49, 0xc1 };
  135. static const uint8_t SHUFPD[] = { 0x66, 0x0f, 0xc6 };
  136. static const uint8_t REX_ADDPD[] = { 0x66, 0x41, 0x0f, 0x58 };
  137. static const uint8_t REX_CVTDQ2PD_XMM12[] = { 0xf3, 0x44, 0x0f, 0xe6, 0x24, 0x06 };
  138. static const uint8_t REX_SUBPD[] = { 0x66, 0x41, 0x0f, 0x5c };
  139. static const uint8_t REX_XORPS[] = { 0x41, 0x0f, 0x57 };
  140. static const uint8_t REX_MULPD[] = { 0x66, 0x41, 0x0f, 0x59 };
  141. static const uint8_t REX_MAXPD[] = { 0x66, 0x41, 0x0f, 0x5f };
  142. static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e };
  143. static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 };
  144. static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x44, 0x24, 0xF8, 0x0F, 0xAE, 0x54, 0x24, 0xF8 };
  145. static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 };
  146. static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 };
  147. static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 };
  148. static const uint8_t REX_CMP_M32I[] = { 0x81, 0x3c, 0x06 };
  149. static const uint8_t MOVAPD[] = { 0x66, 0x0f, 0x29 };
  150. static const uint8_t REX_MOV_MR[] = { 0x4c, 0x89 };
  151. static const uint8_t REX_XOR_EAX[] = { 0x41, 0x33 };
  152. static const uint8_t SUB_EBX[] = { 0x83, 0xEB, 0x01 };
  153. static const uint8_t JNZ[] = { 0x0f, 0x85 };
  154. static const uint8_t JMP = 0xe9;
  155. static const uint8_t REX_XOR_RAX_R64[] = { 0x49, 0x33 };
  156. static const uint8_t REX_XCHG[] = { 0x4d, 0x87 };
  157. static const uint8_t REX_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 };
  158. static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f };
  159. static const uint8_t PADD_OPCODES[] = { 0xfc, 0xfd, 0xfe, 0xd4 };
  160. static const uint8_t CALL = 0xe8;
  161. static const uint8_t REX_ADD_I[] = { 0x49, 0x81 };
  162. static const uint8_t REX_TEST[] = { 0x49, 0xF7 };
  163. static const uint8_t JZ[] = { 0x0f, 0x84 };
  164. size_t JitCompilerX86::getCodeSize() {
  165. return codePos - prologueSize;
  166. }
  167. JitCompilerX86::JitCompilerX86() {
  168. code = (uint8_t*)allocExecutableMemory(CodeSize);
  169. memcpy(code, codePrologue, prologueSize);
  170. memcpy(code + epilogueOffset, codeEpilogue, epilogueSize);
  171. memcpy(code + readDatasetLightSubOffset, codeReadDatasetLightSub, readDatasetLightSubSize);
  172. }
  173. void JitCompilerX86::generateProgram(Program& prog) {
  174. generateProgramPrologue(prog);
  175. memcpy(code + codePos, codeReadDataset, readDatasetSize);
  176. codePos += readDatasetSize;
  177. generateProgramEpilogue(prog);
  178. }
  179. void JitCompilerX86::generateProgramLight(Program& prog) {
  180. if (RANDOMX_CACHE_ACCESSES != 8)
  181. throw std::runtime_error("JIT compiler: Unsupported value of RANDOMX_CACHE_ACCESSES");
  182. if (RANDOMX_ARGON_GROWTH != 0)
  183. throw std::runtime_error("JIT compiler: Unsupported value of RANDOMX_ARGON_GROWTH");
  184. generateProgramPrologue(prog);
  185. memcpy(code + codePos, codeReadDatasetLight, readDatasetLightSize);
  186. codePos += readDatasetLightSize;
  187. emitByte(CALL);
  188. emit32(readDatasetLightSubOffset - (codePos + 4));
  189. generateProgramEpilogue(prog);
  190. }
  191. void JitCompilerX86::generateProgramPrologue(Program& prog) {
  192. #ifdef RANDOMX_JUMP
  193. instructionOffsets.clear();
  194. for (unsigned i = 0; i < 8; ++i) {
  195. registerUsage[i] = -1;
  196. }
  197. #endif
  198. auto addressRegisters = prog.getEntropy(12);
  199. uint32_t readReg0 = 0 + (addressRegisters & 1);
  200. addressRegisters >>= 1;
  201. uint32_t readReg1 = 2 + (addressRegisters & 1);
  202. addressRegisters >>= 1;
  203. uint32_t readReg2 = 4 + (addressRegisters & 1);
  204. addressRegisters >>= 1;
  205. uint32_t readReg3 = 6 + (addressRegisters & 1);
  206. codePos = prologueSize;
  207. emit(REX_XOR_RAX_R64);
  208. emitByte(0xc0 + readReg0);
  209. emit(REX_XOR_RAX_R64);
  210. emitByte(0xc0 + readReg1);
  211. memcpy(code + codePos, codeLoopLoad, loopLoadSize);
  212. codePos += loopLoadSize;
  213. generateCode(prog);
  214. emit(REX_MOV_RR);
  215. emitByte(0xc0 + readReg2);
  216. emit(REX_XOR_EAX);
  217. emitByte(0xc0 + readReg3);
  218. }
  219. void JitCompilerX86::generateProgramEpilogue(Program& prog) {
  220. memcpy(code + codePos, codeLoopStore, loopStoreSize);
  221. codePos += loopStoreSize;
  222. emit(SUB_EBX);
  223. emit(JNZ);
  224. emit32(prologueSize - codePos - 4);
  225. emitByte(JMP);
  226. emit32(epilogueOffset - codePos - 4);
  227. emitByte(0x90);
  228. }
  229. void JitCompilerX86::generateCode(Instruction& instr, int i) {
  230. #ifdef RANDOMX_JUMP
  231. instructionOffsets.push_back(codePos);
  232. #endif
  233. auto generator = engine[instr.opcode];
  234. (this->*generator)(instr, i);
  235. }
  236. void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
  237. emit(REX_MOV_RR);
  238. emitByte((rax ? 0xc0 : 0xc8) + instr.src);
  239. if (rax)
  240. emitByte(AND_EAX_I);
  241. else
  242. emit(AND_ECX_I);
  243. emit32((instr.mod % 4) ? ScratchpadL1Mask : ScratchpadL2Mask);
  244. }
  245. void JitCompilerX86::genAddressRegDst(Instruction& instr, bool align16 = false) {
  246. emit(REX_MOV_RR);
  247. emitByte(0xc0 + instr.dst);
  248. emitByte(AND_EAX_I);
  249. int32_t maskL1 = align16 ? ScratchpadL1Mask16 : ScratchpadL1Mask;
  250. int32_t maskL2 = align16 ? ScratchpadL2Mask16 : ScratchpadL2Mask;
  251. emit32((instr.mod % 4) ? maskL1 : maskL2);
  252. }
  253. void JitCompilerX86::genAddressImm(Instruction& instr) {
  254. emit32(instr.getImm32() & ScratchpadL3Mask);
  255. }
  256. void JitCompilerX86::h_IADD_R(Instruction& instr, int i) {
  257. registerUsage[instr.dst] = i;
  258. if (instr.src != instr.dst) {
  259. emit(REX_ADD_RR);
  260. emitByte(0xc0 + 8 * instr.dst + instr.src);
  261. }
  262. else {
  263. emit(REX_81);
  264. emitByte(0xc0 + instr.dst);
  265. emit32(instr.getImm32());
  266. }
  267. }
  268. void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
  269. registerUsage[instr.dst] = i;
  270. if (instr.src != instr.dst) {
  271. genAddressReg(instr);
  272. emit(REX_ADD_RM);
  273. emitByte(0x04 + 8 * instr.dst);
  274. emitByte(0x06);
  275. }
  276. else {
  277. emit(REX_ADD_RM);
  278. emitByte(0x86 + 8 * instr.dst);
  279. genAddressImm(instr);
  280. }
  281. }
  282. void JitCompilerX86::genSIB(int scale, int index, int base) {
  283. emitByte((scale << 6) | (index << 3) | base);
  284. }
  285. void JitCompilerX86::h_IADD_RC(Instruction& instr, int i) {
  286. registerUsage[instr.dst] = i;
  287. emit(REX_LEA);
  288. emitByte(0x84 + 8 * instr.dst);
  289. genSIB(0, instr.src, instr.dst);
  290. emit32(instr.getImm32());
  291. }
  292. void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
  293. registerUsage[instr.dst] = i;
  294. if (instr.src != instr.dst) {
  295. emit(REX_SUB_RR);
  296. emitByte(0xc0 + 8 * instr.dst + instr.src);
  297. }
  298. else {
  299. emit(REX_81);
  300. emitByte(0xe8 + instr.dst);
  301. emit32(instr.getImm32());
  302. }
  303. }
  304. void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
  305. registerUsage[instr.dst] = i;
  306. if (instr.src != instr.dst) {
  307. genAddressReg(instr);
  308. emit(REX_SUB_RM);
  309. emitByte(0x04 + 8 * instr.dst);
  310. emitByte(0x06);
  311. }
  312. else {
  313. emit(REX_SUB_RM);
  314. emitByte(0x86 + 8 * instr.dst);
  315. genAddressImm(instr);
  316. }
  317. }
  318. void JitCompilerX86::h_IMUL_9C(Instruction& instr, int i) {
  319. registerUsage[instr.dst] = i;
  320. emit(REX_LEA);
  321. emitByte(0x84 + 8 * instr.dst);
  322. genSIB(3, instr.dst, instr.dst);
  323. emit32(instr.getImm32());
  324. }
  325. void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
  326. registerUsage[instr.dst] = i;
  327. if (instr.src != instr.dst) {
  328. emit(REX_IMUL_RR);
  329. emitByte(0xc0 + 8 * instr.dst + instr.src);
  330. }
  331. else {
  332. emit(REX_IMUL_RRI);
  333. emitByte(0xc0 + 9 * instr.dst);
  334. emit32(instr.getImm32());
  335. }
  336. }
  337. void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
  338. registerUsage[instr.dst] = i;
  339. if (instr.src != instr.dst) {
  340. genAddressReg(instr);
  341. emit(REX_IMUL_RM);
  342. emitByte(0x04 + 8 * instr.dst);
  343. emitByte(0x06);
  344. }
  345. else {
  346. emit(REX_IMUL_RM);
  347. emitByte(0x86 + 8 * instr.dst);
  348. genAddressImm(instr);
  349. }
  350. }
  351. void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
  352. registerUsage[instr.dst] = i;
  353. emit(REX_MOV_RR64);
  354. emitByte(0xc0 + instr.dst);
  355. emit(REX_MUL_R);
  356. emitByte(0xe0 + instr.src);
  357. emit(REX_MOV_R64R);
  358. emitByte(0xc2 + 8 * instr.dst);
  359. }
  360. void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
  361. registerUsage[instr.dst] = i;
  362. if (instr.src != instr.dst) {
  363. genAddressReg(instr, false);
  364. emit(REX_MOV_RR64);
  365. emitByte(0xc0 + instr.dst);
  366. emit(REX_MUL_MEM);
  367. }
  368. else {
  369. emit(REX_MOV_RR64);
  370. emitByte(0xc0 + instr.dst);
  371. emit(REX_MUL_M);
  372. emitByte(0xa6);
  373. genAddressImm(instr);
  374. }
  375. emit(REX_MOV_R64R);
  376. emitByte(0xc2 + 8 * instr.dst);
  377. }
  378. void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
  379. registerUsage[instr.dst] = i;
  380. emit(REX_MOV_RR64);
  381. emitByte(0xc0 + instr.dst);
  382. emit(REX_MUL_R);
  383. emitByte(0xe8 + instr.src);
  384. emit(REX_MOV_R64R);
  385. emitByte(0xc2 + 8 * instr.dst);
  386. }
  387. void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
  388. registerUsage[instr.dst] = i;
  389. if (instr.src != instr.dst) {
  390. genAddressReg(instr, false);
  391. emit(REX_MOV_RR64);
  392. emitByte(0xc0 + instr.dst);
  393. emit(REX_IMUL_MEM);
  394. }
  395. else {
  396. emit(REX_MOV_RR64);
  397. emitByte(0xc0 + instr.dst);
  398. emit(REX_MUL_M);
  399. emitByte(0xae);
  400. genAddressImm(instr);
  401. }
  402. emit(REX_MOV_R64R);
  403. emitByte(0xc2 + 8 * instr.dst);
  404. }
  405. void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
  406. if (instr.getImm32() != 0) {
  407. registerUsage[instr.dst] = i;
  408. emit(MOV_RAX_I);
  409. emit64(reciprocal(instr.getImm32()));
  410. emit(REX_IMUL_RM);
  411. emitByte(0xc0 + 8 * instr.dst);
  412. }
  413. }
  414. void JitCompilerX86::h_ISDIV_C(Instruction& instr, int i) {
  415. }
  416. void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
  417. registerUsage[instr.dst] = i;
  418. emit(REX_NEG);
  419. emitByte(0xd8 + instr.dst);
  420. }
  421. void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
  422. registerUsage[instr.dst] = i;
  423. if (instr.src != instr.dst) {
  424. emit(REX_XOR_RR);
  425. emitByte(0xc0 + 8 * instr.dst + instr.src);
  426. }
  427. else {
  428. emit(REX_XOR_RI);
  429. emitByte(0xf0 + instr.dst);
  430. emit32(instr.getImm32());
  431. }
  432. }
  433. void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
  434. registerUsage[instr.dst] = i;
  435. if (instr.src != instr.dst) {
  436. genAddressReg(instr);
  437. emit(REX_XOR_RM);
  438. emitByte(0x04 + 8 * instr.dst);
  439. emitByte(0x06);
  440. }
  441. else {
  442. emit(REX_XOR_RM);
  443. emitByte(0x86 + 8 * instr.dst);
  444. genAddressImm(instr);
  445. }
  446. }
  447. void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
  448. registerUsage[instr.dst] = i;
  449. if (instr.src != instr.dst) {
  450. emit(REX_MOV_RR);
  451. emitByte(0xc8 + instr.src);
  452. emit(REX_ROT_CL);
  453. emitByte(0xc8 + instr.dst);
  454. }
  455. else {
  456. emit(REX_ROT_I8);
  457. emitByte(0xc8 + instr.dst);
  458. emitByte(instr.getImm32() & 63);
  459. }
  460. }
  461. void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
  462. registerUsage[instr.dst] = i;
  463. if (instr.src != instr.dst) {
  464. emit(REX_MOV_RR);
  465. emitByte(0xc8 + instr.src);
  466. emit(REX_ROT_CL);
  467. emitByte(0xc0 + instr.dst);
  468. }
  469. else {
  470. emit(REX_ROT_I8);
  471. emitByte(0xc0 + instr.dst);
  472. emitByte(instr.getImm32() & 63);
  473. }
  474. }
  475. void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
  476. if (instr.src != instr.dst) {
  477. registerUsage[instr.dst] = i;
  478. registerUsage[instr.src] = i;
  479. emit(REX_XCHG);
  480. emitByte(0xc0 + instr.src + 8 * instr.dst);
  481. }
  482. }
  483. void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
  484. emit(SHUFPD);
  485. emitByte(0xc0 + 9 * instr.dst);
  486. emitByte(1);
  487. }
  488. void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
  489. instr.dst %= 4;
  490. instr.src %= 4;
  491. emit(REX_ADDPD);
  492. emitByte(0xc0 + instr.src + 8 * instr.dst);
  493. //emit(REX_PADD);
  494. //emitByte(PADD_OPCODES[instr.mod % 4]);
  495. //emitByte(0xf8 + instr.dst);
  496. }
  497. void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
  498. instr.dst %= 4;
  499. genAddressReg(instr);
  500. emit(REX_CVTDQ2PD_XMM12);
  501. emit(REX_ADDPD);
  502. emitByte(0xc4 + 8 * instr.dst);
  503. }
  504. void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) {
  505. instr.dst %= 4;
  506. instr.src %= 4;
  507. emit(REX_SUBPD);
  508. emitByte(0xc0 + instr.src + 8 * instr.dst);
  509. //emit(REX_PADD);
  510. //emitByte(PADD_OPCODES[instr.mod % 4]);
  511. //emitByte(0xf8 + instr.dst);
  512. }
  513. void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
  514. instr.dst %= 4;
  515. genAddressReg(instr);
  516. emit(REX_CVTDQ2PD_XMM12);
  517. emit(REX_SUBPD);
  518. emitByte(0xc4 + 8 * instr.dst);
  519. }
  520. void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
  521. instr.dst %= 4;
  522. emit(REX_XORPS);
  523. emitByte(0xc7 + 8 * instr.dst);
  524. }
  525. void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) {
  526. instr.dst %= 4;
  527. instr.src %= 4;
  528. emit(REX_MULPD);
  529. emitByte(0xe0 + instr.src + 8 * instr.dst);
  530. }
  531. void JitCompilerX86::h_FMUL_M(Instruction& instr, int i) {
  532. instr.dst %= 4;
  533. genAddressReg(instr);
  534. emit(REX_CVTDQ2PD_XMM12);
  535. emit(REX_ANDPS_XMM12);
  536. emit(REX_MULPD);
  537. emitByte(0xe4 + 8 * instr.dst);
  538. emit(REX_MAXPD);
  539. emitByte(0xe5 + 8 * instr.dst);
  540. }
  541. void JitCompilerX86::h_FDIV_R(Instruction& instr, int i) {
  542. instr.dst %= 4;
  543. instr.src %= 4;
  544. emit(REX_DIVPD);
  545. emitByte(0xe0 + instr.src + 8 * instr.dst);
  546. emit(REX_MAXPD);
  547. emitByte(0xe5 + 8 * instr.dst);
  548. }
  549. void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
  550. instr.dst %= 4;
  551. genAddressReg(instr);
  552. emit(REX_CVTDQ2PD_XMM12);
  553. emit(REX_ANDPS_XMM12);
  554. emit(REX_DIVPD);
  555. emitByte(0xe4 + 8 * instr.dst);
  556. }
  557. void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
  558. instr.dst %= 4;
  559. emit(SQRTPD);
  560. emitByte(0xe4 + 9 * instr.dst);
  561. }
  562. void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
  563. emit(REX_MOV_RR64);
  564. emitByte(0xc0 + instr.src);
  565. int rotate = (13 - (instr.getImm32() & 63)) & 63;
  566. if (rotate != 0) {
  567. emit(ROL_RAX);
  568. emitByte(rotate);
  569. }
  570. emit(AND_OR_MOV_LDMXCSR);
  571. }
  572. static inline uint8_t jumpCondition(Instruction& instr, bool invert = false) {
  573. switch (((instr.mod >> 2) & 7) ^ invert)
  574. {
  575. case 0:
  576. return 0x76; //jbe
  577. case 1:
  578. return 0x77; //ja
  579. case 2:
  580. return 0x78; //js
  581. case 3:
  582. return 0x79; //jns
  583. case 4:
  584. return 0x70; //jo
  585. case 5:
  586. return 0x71; //jno
  587. case 6:
  588. return 0x7c; //jl
  589. case 7:
  590. return 0x7d; //jge
  591. }
  592. }
  593. static inline uint8_t condition(Instruction& instr) {
  594. switch ((instr.mod >> 2) & 7)
  595. {
  596. case 0:
  597. return 0x96; //setbe
  598. case 1:
  599. return 0x97; //seta
  600. case 2:
  601. return 0x98; //sets
  602. case 3:
  603. return 0x99; //setns
  604. case 4:
  605. return 0x90; //seto
  606. case 5:
  607. return 0x91; //setno
  608. case 6:
  609. return 0x9c; //setl
  610. case 7:
  611. return 0x9d; //setge
  612. default:
  613. UNREACHABLE;
  614. }
  615. }
  616. int JitCompilerX86::getConditionRegister() {
  617. int min = INT_MAX;
  618. int minIndex;
  619. for (unsigned i = 0; i < 8; ++i) {
  620. if (registerUsage[i] < min) {
  621. min = registerUsage[i];
  622. minIndex = i;
  623. }
  624. }
  625. return minIndex;
  626. }
  627. void JitCompilerX86::handleCondition(Instruction& instr, int i) {
  628. const int shift = (instr.mod >> 5);
  629. const int conditionMask = ((1 << RANDOMX_CONDITION_BITS) - 1) << shift;
  630. int reg = getConditionRegister();
  631. int target = registerUsage[reg] + 1;
  632. emit(REX_ADD_I);
  633. emitByte(0xc0 + reg);
  634. emit32(1 << shift);
  635. emit(REX_TEST);
  636. emitByte(0xc0 + reg);
  637. emit32(conditionMask);
  638. emit(JZ);
  639. emit32(instructionOffsets[target] - (codePos + 4));
  640. for (unsigned j = 0; j < 8; ++j) { //mark all registers as used
  641. registerUsage[j] = i;
  642. }
  643. }
  644. void JitCompilerX86::h_COND_R(Instruction& instr, int i) {
  645. #ifdef RANDOMX_JUMP
  646. handleCondition(instr, i);
  647. #endif
  648. emit(XOR_ECX_ECX);
  649. emit(REX_CMP_R32I);
  650. emitByte(0xf8 + instr.src);
  651. emit32(instr.getImm32());
  652. emitByte(0x0f);
  653. emitByte(condition(instr));
  654. emitByte(0xc1);
  655. emit(REX_ADD_RM);
  656. emitByte(0xc1 + 8 * instr.dst);
  657. }
  658. void JitCompilerX86::h_COND_M(Instruction& instr, int i) {
  659. #ifdef RANDOMX_JUMP
  660. handleCondition(instr, i);
  661. #endif
  662. emit(XOR_ECX_ECX);
  663. genAddressReg(instr);
  664. emit(REX_CMP_M32I);
  665. emit32(instr.getImm32());
  666. emitByte(0x0f);
  667. emitByte(condition(instr));
  668. emitByte(0xc1);
  669. emit(REX_ADD_RM);
  670. emitByte(0xc1 + 8 * instr.dst);
  671. }
  672. void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
  673. genAddressRegDst(instr);
  674. emit(REX_MOV_MR);
  675. emitByte(0x04 + 8 * instr.src);
  676. emitByte(0x06);
  677. }
  678. void JitCompilerX86::h_FSTORE(Instruction& instr, int i) {
  679. genAddressRegDst(instr, true);
  680. emit(MOVAPD);
  681. emitByte(0x04 + 8 * instr.src);
  682. emitByte(0x06);
  683. }
  684. void JitCompilerX86::h_NOP(Instruction& instr, int i) {
  685. emitByte(0x90);
  686. }
  687. #include "instructionWeights.hpp"
  688. #define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
  689. InstructionGeneratorX86 JitCompilerX86::engine[256] = {
  690. INST_HANDLE(IADD_R)
  691. INST_HANDLE(IADD_M)
  692. INST_HANDLE(IADD_RC)
  693. INST_HANDLE(ISUB_R)
  694. INST_HANDLE(ISUB_M)
  695. INST_HANDLE(IMUL_9C)
  696. INST_HANDLE(IMUL_R)
  697. INST_HANDLE(IMUL_M)
  698. INST_HANDLE(IMULH_R)
  699. INST_HANDLE(IMULH_M)
  700. INST_HANDLE(ISMULH_R)
  701. INST_HANDLE(ISMULH_M)
  702. INST_HANDLE(IMUL_RCP)
  703. INST_HANDLE(INEG_R)
  704. INST_HANDLE(IXOR_R)
  705. INST_HANDLE(IXOR_M)
  706. INST_HANDLE(IROR_R)
  707. INST_HANDLE(IROL_R)
  708. INST_HANDLE(ISWAP_R)
  709. INST_HANDLE(FSWAP_R)
  710. INST_HANDLE(FADD_R)
  711. INST_HANDLE(FADD_M)
  712. INST_HANDLE(FSUB_R)
  713. INST_HANDLE(FSUB_M)
  714. INST_HANDLE(FSCAL_R)
  715. INST_HANDLE(FMUL_R)
  716. INST_HANDLE(FDIV_M)
  717. INST_HANDLE(FSQRT_R)
  718. INST_HANDLE(COND_R)
  719. INST_HANDLE(COND_M)
  720. INST_HANDLE(CFROUND)
  721. INST_HANDLE(ISTORE)
  722. INST_HANDLE(NOP)
  723. };
  724. #endif
  725. }