jit_compiler_x86.cpp 25 KB

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