JitCompilerX86.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  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 "JitCompilerX86.hpp"
  16. #include "Pcg32.hpp"
  17. #include <cstring>
  18. #include <stdexcept>
  19. #ifdef _WIN32
  20. #include <windows.h>
  21. #elif defined(__linux__)
  22. #include <unistd.h>
  23. #include <malloc.h>
  24. #include <sys/mman.h>
  25. #else
  26. #error "Unsupported operating system"
  27. #endif
  28. namespace RandomX {
  29. /*
  30. REGISTER ALLOCATION:
  31. rax -> temporary
  32. rbx -> MemoryRegisters& memory
  33. rcx -> temporary
  34. rdx -> temporary
  35. rsi -> convertible_t& scratchpad
  36. rdi -> "ic" (instruction counter)
  37. rbp -> beginning of VM stack
  38. rsp -> end of VM stack
  39. r8 -> "r0"
  40. r9 -> "r1"
  41. r10 -> "r2"
  42. r11 -> "r3"
  43. r12 -> "r4"
  44. r13 -> "r5"
  45. r14 -> "r6"
  46. r15 -> "r7"
  47. xmm0 -> temporary
  48. xmm1 -> temporary
  49. xmm2 -> "f2"
  50. xmm3 -> "f3"
  51. xmm4 -> "f4"
  52. xmm5 -> "f5"
  53. xmm6 -> "f6"
  54. xmm7 -> "f7"
  55. xmm8 -> "f0"
  56. xmm9 -> "f1"
  57. STACK STRUCTURE:
  58. |
  59. |
  60. | saved registers
  61. |
  62. v
  63. [rbp] RegisterFile& registerFile
  64. |
  65. |
  66. | VM stack
  67. |
  68. v
  69. [rsp] last element of VM stack
  70. */
  71. const uint8_t prologue[] = {
  72. 0x53, //push rbx
  73. 0x55, //push rbp
  74. #ifdef _WIN32
  75. 0x57, //push rdi
  76. 0x56, //push rsi
  77. #endif
  78. 0x41, 0x54, //push r12
  79. 0x41, 0x55, //push r13
  80. 0x41, 0x56, //push r14
  81. 0x41, 0x57, //push r15
  82. #ifdef _WIN32
  83. 0x48, 0x83, 0xec, 0x48, //sub rsp,0x48
  84. 0xf3, 0x0f, 0x7f, 0x74, 0x24, 0x30, //movdqu XMMWORD PTR[rsp + 0x30],xmm6
  85. 0xf3, 0x0f, 0x7f, 0x7c, 0x24, 0x20, //movdqu XMMWORD PTR[rsp + 0x20],xmm7
  86. 0xf3, 0x44, 0x0f, 0x7f, 0x44, 0x24, 0x10, //movdqu XMMWORD PTR[rsp + 0x10],xmm8
  87. 0xf3, 0x44, 0x0f, 0x7f, 0x0c, 0x24, //movdqu XMMWORD PTR[rsp],xmm9
  88. 0x51, //push rcx
  89. 0x48, 0x8b, 0xda, //mov rbx,rdx
  90. 0x49, 0x8b, 0xf0, //mov rsi,r8
  91. #else
  92. 0x57, //push rdi
  93. 0x48, 0x8b, 0xde, //mov rbx, rsi
  94. 0x48, 0x8b, 0xf2, //mov rsi, rdx
  95. 0x48, 0x8b, 0xcf, //mov rcx, rdi
  96. #endif
  97. 0x48, 0x8b, 0xec, //mov rbp,rsp
  98. 0x48, 0xc7, 0xc7, 0x00, 0x00, 0x10, 0x00, //mov rdi,0x100000
  99. 0x4c, 0x8b, 0x01, //mov r8,QWORD PTR[rcx]
  100. 0x4c, 0x8b, 0x49, 0x08, //mov r9,QWORD PTR[rcx+0x8]
  101. 0x4c, 0x8b, 0x51, 0x10, //mov r10,QWORD PTR[rcx+0x10]
  102. 0x4c, 0x8b, 0x59, 0x18, //mov r11,QWORD PTR[rcx+0x18]
  103. 0x4c, 0x8b, 0x61, 0x20, //mov r12,QWORD PTR[rcx+0x20]
  104. 0x4c, 0x8b, 0x69, 0x28, //mov r13,QWORD PTR[rcx+0x28]
  105. 0x4c, 0x8b, 0x71, 0x30, //mov r14,QWORD PTR[rcx+0x30]
  106. 0x4c, 0x8b, 0x79, 0x38, //mov r15,QWORD PTR[rcx+0x38]
  107. 0xc7, 0x44, 0x24, 0xf8, 0xc0, 0x9f, 0x00, //mov DWORD PTR[rsp-0x8],0x9fc0
  108. 0x00,
  109. 0x0f, 0xae, 0x54, 0x24, 0xf8, //ldmxcsr DWORD PTR[rsp-0x8]
  110. 0xf2, 0x4c, 0x0f, 0x2a, 0x41, 0x40, //cvtsi2sd xmm8,QWORD PTR[rcx+0x40]
  111. 0xf2, 0x4c, 0x0f, 0x2a, 0x49, 0x48, //cvtsi2sd xmm9,QWORD PTR[rcx+0x48]
  112. 0xf2, 0x48, 0x0f, 0x2a, 0x51, 0x50, //cvtsi2sd xmm2,QWORD PTR[rcx+0x50]
  113. 0xf2, 0x48, 0x0f, 0x2a, 0x59, 0x58, //cvtsi2sd xmm3,QWORD PTR[rcx+0x58]
  114. 0xf2, 0x48, 0x0f, 0x2a, 0x61, 0x60, //cvtsi2sd xmm4,QWORD PTR[rcx+0x60]
  115. 0xf2, 0x48, 0x0f, 0x2a, 0x69, 0x68, //cvtsi2sd xmm5,QWORD PTR[rcx+0x68]
  116. 0xf2, 0x48, 0x0f, 0x2a, 0x71, 0x70, //cvtsi2sd xmm6,QWORD PTR[rcx+0x70]
  117. 0xf2, 0x48, 0x0f, 0x2a, 0x79, 0x78, //cvtsi2sd xmm7,QWORD PTR[rcx+0x78]
  118. };
  119. const uint8_t epilogue[] = {
  120. 0x48, 0x8b, 0xe5, //mov rsp,rbp
  121. 0x59, //pop rcx
  122. 0x4c, 0x89, 0x01, //mov QWORD PTR [rcx],r8
  123. 0x4c, 0x89, 0x49, 0x08, //mov QWORD PTR [rcx+0x8],r9
  124. 0x4c, 0x89, 0x51, 0x10, //mov QWORD PTR [rcx+0x10],r10
  125. 0x4c, 0x89, 0x59, 0x18, //mov QWORD PTR [rcx+0x18],r11
  126. 0x4c, 0x89, 0x61, 0x20, //mov QWORD PTR [rcx+0x20],r12
  127. 0x4c, 0x89, 0x69, 0x28, //mov QWORD PTR [rcx+0x28],r13
  128. 0x4c, 0x89, 0x71, 0x30, //mov QWORD PTR [rcx+0x30],r14
  129. 0x4c, 0x89, 0x79, 0x38, //mov QWORD PTR [rcx+0x38],r15
  130. 0x66, 0x4c, 0x0f, 0x7e, 0x41, 0x40, //movq QWORD PTR [rcx+0x40],xmm8
  131. 0x66, 0x4c, 0x0f, 0x7e, 0x49, 0x48, //movq QWORD PTR [rcx+0x48],xmm9
  132. 0x66, 0x48, 0x0f, 0x7e, 0x51, 0x50, //movq QWORD PTR [rcx+0x50],xmm2
  133. 0x66, 0x48, 0x0f, 0x7e, 0x59, 0x58, //movq QWORD PTR [rcx+0x58],xmm3
  134. 0x66, 0x48, 0x0f, 0x7e, 0x61, 0x60, //movq QWORD PTR [rcx+0x60],xmm4
  135. 0x66, 0x48, 0x0f, 0x7e, 0x69, 0x68, //movq QWORD PTR [rcx+0x68],xmm5
  136. 0x66, 0x48, 0x0f, 0x7e, 0x71, 0x70, //movq QWORD PTR [rcx+0x70],xmm6
  137. 0x66, 0x48, 0x0f, 0x7e, 0x79, 0x78, //movq QWORD PTR [rcx+0x78],xmm7
  138. #ifdef _WIN32
  139. 0xf3, 0x44, 0x0f, 0x6f, 0x0c, 0x24, //movdqu xmm9,XMMWORD PTR [rsp]
  140. 0xf3, 0x44, 0x0f, 0x6f, 0x44, 0x24, 0x10, //movdqu xmm8,XMMWORD PTR [rsp+0x10]
  141. 0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x20, //movdqu xmm7,XMMWORD PTR [rsp+0x20]
  142. 0xf3, 0x0f, 0x6f, 0x74, 0x24, 0x30, //movdqu xmm6,XMMWORD PTR [rsp+0x30]
  143. 0x48, 0x83, 0xc4, 0x48, //add rsp,0x48
  144. #endif
  145. 0x41, 0x5f, //pop r15
  146. 0x41, 0x5e, //pop r14
  147. 0x41, 0x5d, //pop r13
  148. 0x41, 0x5c, //pop r12
  149. #ifdef _WIN32
  150. 0x5e, //pop rsi
  151. 0x5f, //pop rdi
  152. #endif
  153. 0x5d, //pop rbp
  154. 0x5b, //pop rbx
  155. 0xc3, //ret
  156. };
  157. //41 bytes -> 1 cache line
  158. const uint8_t readDatasetSub[] = {
  159. 0x8b, 0x13, //mov edx,DWORD PTR [rbx]
  160. 0x48, 0x8b, 0x43, 0x08, //mov rax,QWORD PTR [rbx+0x8]
  161. 0x48, 0x8b, 0x04, 0x10, //mov rax,QWORD PTR [rax+rdx*1]
  162. 0x83, 0x03, 0x08, //add DWORD PTR [rbx],0x8
  163. 0x33, 0x4b, 0x04, //xor ecx,DWORD PTR [rbx+0x4]
  164. 0x89, 0x4b, 0x04, //mov DWORD PTR [rbx+0x4],ecx
  165. 0xf7, 0xc1, 0xf8, 0xff, 0x00, 0x00, //test ecx,0xfff8
  166. 0x75, 0x0d, //jne
  167. 0x83, 0xe1, 0xf8, //and ecx,0xfffffff8
  168. 0x89, 0x0b, //mov DWORD PTR [rbx],ecx
  169. 0x48, 0x8b, 0x53, 0x08, //mov rdx,QWORD PTR [rbx+0x8]
  170. 0x0f, 0x18, 0x0c, 0x0a, //prefetcht0 BYTE PTR [rdx+rcx*1]
  171. 0xc3, //ret
  172. };
  173. constexpr int getNumCacheLines(size_t size) {
  174. return (size + (CacheLineSize - 1)) / CacheLineSize;
  175. }
  176. constexpr int32_t align(int32_t pos, int32_t align) {
  177. return ((pos - 1) / align + 1) * align;
  178. }
  179. constexpr int32_t readDatasetSubOffset = CodeSize - CacheLineSize * getNumCacheLines(sizeof(readDatasetSub));
  180. constexpr int32_t epilogueOffset = readDatasetSubOffset - CacheLineSize * getNumCacheLines(sizeof(epilogue));
  181. constexpr int32_t startOffsetAligned = align(sizeof(prologue), CacheLineSize);
  182. JitCompilerX86::JitCompilerX86() {
  183. #ifdef _WIN32
  184. code = (uint8_t*)VirtualAlloc(nullptr, CodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  185. if (code == nullptr)
  186. throw std::runtime_error("VirtualAlloc failed");
  187. #else
  188. auto pagesize = sysconf(_SC_PAGE_SIZE);
  189. if (pagesize == -1)
  190. throw std::runtime_error("sysconf failed");
  191. code = (uint8_t*)memalign(pagesize, CodeSize);
  192. if (code == nullptr)
  193. throw std::runtime_error("memalign failed");
  194. if (mprotect(code, CodeSize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
  195. throw std::runtime_error("mprotect failed");
  196. #endif
  197. memcpy(code, prologue, sizeof(prologue));
  198. if (startOffsetAligned - sizeof(prologue) > 4) {
  199. codePos = sizeof(prologue);
  200. emitByte(0xeb);
  201. emitByte(startOffsetAligned - (codePos + 1));
  202. }
  203. memcpy(code + readDatasetSubOffset, readDatasetSub, sizeof(readDatasetSub));
  204. memcpy(code + epilogueOffset, epilogue, sizeof(epilogue));
  205. }
  206. void JitCompilerX86::generateProgram(Pcg32& gen) {
  207. instructionOffsets.clear();
  208. callOffsets.clear();
  209. codePos = startOffsetAligned;
  210. Instruction instr;
  211. for (unsigned i = 0; i < ProgramLength; ++i) {
  212. for (unsigned j = 0; j < sizeof(instr) / sizeof(Pcg32::result_type); ++j) {
  213. *(((uint32_t*)&instr) + j) = gen();
  214. }
  215. generateCode(instr, i);
  216. }
  217. emitByte(0xe9);
  218. emit(instructionOffsets[0] - (codePos + 4));
  219. fixCallOffsets();
  220. }
  221. void JitCompilerX86::generateCode(Instruction& instr, int i) {
  222. instructionOffsets.push_back(codePos);
  223. emit(0x880fcfff); //dec edx; js <epilogue>
  224. emit(epilogueOffset - (codePos + 4)); //jump offset (RIP-relative)
  225. gena(instr);
  226. auto generator = engine[instr.opcode];
  227. (this->*generator)(instr, i);
  228. }
  229. void JitCompilerX86::fixCallOffsets() {
  230. for (CallOffset& co : callOffsets) {
  231. *reinterpret_cast<int32_t*>(code + co.pos) = instructionOffsets[co.index] - (co.pos + 4);
  232. }
  233. }
  234. void JitCompilerX86::gena(Instruction& instr) {
  235. emit(uint16_t(0x8149)); //xor
  236. emitByte(0xf0 + (instr.rega % RegistersCount));
  237. emit(instr.addra);
  238. int32_t pc;
  239. switch (instr.loca & 7)
  240. {
  241. case 0:
  242. case 1:
  243. case 2:
  244. case 3:
  245. emit(uint16_t(0x8b41)); //mov
  246. emitByte(0xc8 + (instr.rega % RegistersCount)); //ecx, rega
  247. emitByte(0xe8); //call
  248. emit(readDatasetSubOffset - (codePos + 4));
  249. return;
  250. case 4:
  251. emit(uint16_t(0x8b41)); //mov
  252. emitByte(0xc0 + (instr.rega % RegistersCount)); //eax, rega
  253. emitByte(0x25); //and
  254. emit(ScratchpadL2 - 1); //whole scratchpad
  255. emit(0xc6048b48); // mov rax,QWORD PTR [rsi+rax*8]
  256. return;
  257. default:
  258. emit(uint16_t(0x8b41)); //mov
  259. emitByte(0xc0 + (instr.rega % RegistersCount)); //eax, rega
  260. emitByte(0x25); //and
  261. emit(ScratchpadL1 - 1); //first 16 KiB of scratchpad
  262. emit(0xc6048b48); // mov rax,QWORD PTR [rsi+rax*8]
  263. return;
  264. }
  265. }
  266. void JitCompilerX86::genbr0(Instruction& instr, uint16_t opcodeReg, uint16_t opcodeImm) {
  267. if ((instr.locb & 7) <= 5) {
  268. emit(uint16_t(0x8b49)); //mov
  269. emitByte(0xc8 + (instr.regb % RegistersCount)); //rcx, regb
  270. emitByte(0x48); //REX.W
  271. emit(opcodeReg); //xxx rax, cl
  272. }
  273. else {
  274. emitByte(0x48); //REX.W
  275. emit(opcodeImm); //xxx rax, imm8
  276. emitByte((instr.imm8 & 63));
  277. }
  278. }
  279. void JitCompilerX86::genbr1(Instruction& instr, uint16_t opcodeReg, uint16_t opcodeImm) {
  280. if ((instr.locb & 7) <= 5) {
  281. emit(opcodeReg); // xxx rax, r64
  282. emitByte(0xc0 + (instr.regb % RegistersCount));
  283. }
  284. else {
  285. emit(opcodeImm); // xxx rax, imm32
  286. emit(instr.imm32);
  287. }
  288. }
  289. void JitCompilerX86::genbr132(Instruction& instr, uint16_t opcodeReg, uint8_t opcodeImm) {
  290. if ((instr.locb & 7) <= 5) {
  291. emit(opcodeReg); // xxx eax, r32
  292. emitByte(0xc0 + (instr.regb % RegistersCount));
  293. }
  294. else {
  295. emitByte(opcodeImm); // xxx eax, imm32
  296. emit(instr.imm32);
  297. }
  298. }
  299. void JitCompilerX86::genbf(Instruction& instr, uint8_t opcode) {
  300. emit(0x48f2fffff8002548); //and rax,0xfffffffffffff800; cvtsi2sd xmm0,rax
  301. emit(uint16_t(0x2a0f));
  302. emitByte(0xc0);
  303. if ((instr.locb & 7) <= 5) {
  304. int regb = (instr.regb % RegistersCount);
  305. emitByte(0xf2); //xxxsd xmm0,regb
  306. if (regb <= 1) {
  307. emitByte(0x41); //REX
  308. }
  309. emitByte(0x0f);
  310. emitByte(opcode);
  311. emitByte(0xc0 + regb);
  312. }
  313. else {
  314. convertible_t bimm;
  315. bimm.f64 = (double)instr.imm32;
  316. emit(uint16_t(0xb848)); //movabs rax,imm64
  317. emit(bimm.i64);
  318. emitByte(0x66); //movq xmm1,rax
  319. emit(0xc86e0f48);
  320. emit(uint16_t(0x0ff2)); //xxxsd xmm0,xmm1
  321. emitByte(opcode);
  322. emitByte(0xc1);
  323. }
  324. }
  325. void JitCompilerX86::gencr(Instruction& instr) {
  326. switch (instr.locc & 7)
  327. {
  328. case 0:
  329. emit(0x41c88b48); //mov rcx, rax; REX
  330. emitByte(0x8b); // mov
  331. emitByte(0xc0 + (instr.regc % RegistersCount)); //eax, regc
  332. emitByte(0x35); // xor eax
  333. emit(instr.addrc);
  334. emitByte(0x25); //and
  335. emit(ScratchpadL2 - 1); //whole scratchpad
  336. emit(0xc60c8948); // mov QWORD PTR [rsi+rax*8],rcx
  337. break;
  338. case 1:
  339. case 2:
  340. case 3:
  341. emit(0x41c88b48); //mov rcx, rax; REX
  342. emitByte(0x8b); // mov
  343. emitByte(0xc0 + (instr.regc % RegistersCount)); //eax, regc
  344. emitByte(0x35); // xor eax
  345. emit(instr.addrc);
  346. emitByte(0x25); //and
  347. emit(ScratchpadL1 - 1); //first 16 KiB of scratchpad
  348. emit(0xc60c8948); // mov QWORD PTR [rsi+rax*8],rcx
  349. break;
  350. default:
  351. emit(uint16_t(0x8b4c)); //mov
  352. emitByte(0xc0 + 8 * (instr.regc % RegistersCount)); //regc, rax
  353. break;
  354. }
  355. }
  356. void JitCompilerX86::gencf(Instruction& instr) {
  357. int regc = (instr.regc % RegistersCount);
  358. switch (instr.locc & 7)
  359. {
  360. case 0:
  361. emit(uint16_t(0x8b41)); //mov
  362. emitByte(0xc0 + regc); //eax, regc
  363. emitByte(0x35); // xor eax
  364. emit(instr.addrc);
  365. emitByte(0x25); //and
  366. emit(ScratchpadL2 - 1); //whole scratchpad
  367. emit(uint16_t(0x4866)); //prefix
  368. emit(0xc6047e0f); // movq QWORD PTR [rsi+rax*8],xmm0
  369. break;
  370. case 1:
  371. case 2:
  372. case 3:
  373. emit(uint16_t(0x8b41)); //mov
  374. emitByte(0xc0 + regc); //eax, regc
  375. emitByte(0x35); // xor eax
  376. emit(instr.addrc);
  377. emitByte(0x25); //and
  378. emit(ScratchpadL1 - 1); //first 16 KiB of scratchpad
  379. emit(uint16_t(0x4866)); //prefix
  380. emit(0xc6047e0f); // movq QWORD PTR [rsi+rax*8],xmm0
  381. break;
  382. default:
  383. emitByte(0xf2);
  384. if (regc <= 1) {
  385. emitByte(0x44); //REX
  386. }
  387. emit(uint16_t(0x100f)); //movsd
  388. emitByte(0xc0 + 8 * regc); // regc, xmm0
  389. break;
  390. }
  391. }
  392. void JitCompilerX86::h_ADD_64(Instruction& instr, int i) {
  393. genbr1(instr, 0x0349, 0x0548);
  394. gencr(instr);
  395. }
  396. void JitCompilerX86::h_ADD_32(Instruction& instr, int i) {
  397. genbr132(instr, 0x0341, 0x05);
  398. gencr(instr);
  399. }
  400. void JitCompilerX86::h_SUB_64(Instruction& instr, int i) {
  401. genbr1(instr, 0x2b49, 0x2d48);
  402. gencr(instr);
  403. }
  404. void JitCompilerX86::h_SUB_32(Instruction& instr, int i) {
  405. genbr132(instr, 0x2b41, 0x2d);
  406. gencr(instr);
  407. }
  408. void JitCompilerX86::h_MUL_64(Instruction& instr, int i) {
  409. if ((instr.locb & 7) <= 5) {
  410. emitByte(0x49); //REX
  411. emit(uint16_t(0xaf0f)); // imul rax, r64
  412. emitByte(0xc0 + (instr.regb % RegistersCount));
  413. }
  414. else {
  415. emitByte(0x48); //REX
  416. emit(uint16_t(0xc069)); // imul rax, rax, imm32
  417. emit(instr.imm32);
  418. }
  419. gencr(instr);
  420. }
  421. void JitCompilerX86::h_MULH_64(Instruction& instr, int i) {
  422. if ((instr.locb & 7) <= 5) {
  423. emit(uint16_t(0x8b49)); //mov rcx, r64
  424. emitByte(0xc8 + (instr.regb % RegistersCount));
  425. }
  426. else {
  427. emitByte(0x48);
  428. emit(uint16_t(0xc1c7)); // mov rcx, imm32
  429. emit(instr.imm32);
  430. }
  431. emitByte(0x48);
  432. emit(uint16_t(0xe1f7)); // mul rcx
  433. emitByte(0x48);
  434. emit(uint16_t(0xc28b)); // mov rax,rdx
  435. gencr(instr);
  436. }
  437. void JitCompilerX86::h_MUL_32(Instruction& instr, int i) {
  438. emit(uint16_t(0xc88b)); //mov ecx, eax
  439. if ((instr.locb & 7) <= 5) {
  440. emit(uint16_t(0x8b41)); // mov eax, r32
  441. emitByte(0xc0 + (instr.regb % RegistersCount));
  442. }
  443. else {
  444. emitByte(0xb8); // mov eax, imm32
  445. emit(instr.imm32);
  446. }
  447. emit(0xc1af0f48); //imul rax,rcx
  448. gencr(instr);
  449. }
  450. void JitCompilerX86::h_IMUL_32(Instruction& instr, int i) {
  451. emitByte(0x48);
  452. emit(uint16_t(0xc863)); //movsxd rcx,eax
  453. if ((instr.locb & 7) <= 5) {
  454. emit(uint16_t(0x6349)); //movsxd rax,r32
  455. emitByte(0xc0 + (instr.regb % RegistersCount));
  456. }
  457. else {
  458. emitByte(0x48);
  459. emit(uint16_t(0xc0c7)); // mov rax, imm32
  460. emit(instr.imm32);
  461. }
  462. emit(0xc1af0f48); //imul rax,rcx
  463. gencr(instr);
  464. }
  465. void JitCompilerX86::h_IMULH_64(Instruction& instr, int i) {
  466. if ((instr.locb & 7) <= 5) {
  467. emit(uint16_t(0x8b49)); //mov rcx, r64
  468. emitByte(0xc8 + (instr.regb % RegistersCount));
  469. }
  470. else {
  471. emitByte(0x48);
  472. emit(uint16_t(0xc1c7)); // mov rcx, imm32
  473. emit(instr.imm32);
  474. }
  475. emitByte(0x48);
  476. emit(uint16_t(0xe9f7)); // imul rcx
  477. emitByte(0x48);
  478. emit(uint16_t(0xc28b)); // mov rax,rdx
  479. gencr(instr);
  480. }
  481. void JitCompilerX86::h_DIV_64(Instruction& instr, int i) {
  482. if ((instr.locb & 7) <= 5) {
  483. emitByte(0xb9); //mov ecx, 1
  484. emit(1);
  485. emit(uint16_t(0x8b41)); //mov edx, r32
  486. emitByte(0xd0 + (instr.regb % RegistersCount));
  487. emit(0x450fd285); //test edx, edx; cmovne ecx,edx
  488. emitByte(0xca);
  489. }
  490. else {
  491. emitByte(0xb9); //mov ecx, imm32
  492. emit(instr.imm32 != 0 ? instr.imm32 : 1);
  493. }
  494. emit(0xf748d233); //xor edx,edx; div rcx
  495. emitByte(0xf1);
  496. gencr(instr);
  497. }
  498. void JitCompilerX86::h_IDIV_64(Instruction& instr, int i) {
  499. if ((instr.locb & 7) <= 5) {
  500. emit(uint16_t(0x8b41)); //mov edx, r32
  501. emitByte(0xd0 + (instr.regb % RegistersCount));
  502. }
  503. else {
  504. emitByte(0xba); // xxx edx, imm32
  505. emit(instr.imm32);
  506. }
  507. emit(0xc88b480b75fffa83);
  508. emit(0x1274c9ff48c1d148);
  509. emit(0x0fd28500000001b9);
  510. emit(0x489948c96348ca45);
  511. emit(uint16_t(0xf9f7)); //idiv rcx
  512. gencr(instr);
  513. }
  514. void JitCompilerX86::h_AND_64(Instruction& instr, int i) {
  515. genbr1(instr, 0x2349, 0x2548);
  516. gencr(instr);
  517. }
  518. void JitCompilerX86::h_AND_32(Instruction& instr, int i) {
  519. genbr132(instr, 0x2341, 0x25);
  520. gencr(instr);
  521. }
  522. void JitCompilerX86::h_OR_64(Instruction& instr, int i) {
  523. genbr1(instr, 0x0b49, 0x0d48);
  524. gencr(instr);
  525. }
  526. void JitCompilerX86::h_OR_32(Instruction& instr, int i) {
  527. genbr132(instr, 0x0b41, 0x0d);
  528. gencr(instr);
  529. }
  530. void JitCompilerX86::h_XOR_64(Instruction& instr, int i) {
  531. genbr1(instr, 0x3349, 0x3548);
  532. gencr(instr);
  533. }
  534. void JitCompilerX86::h_XOR_32(Instruction& instr, int i) {
  535. genbr132(instr, 0x3341, 0x35);
  536. gencr(instr);
  537. }
  538. void JitCompilerX86::h_SHL_64(Instruction& instr, int i) {
  539. genbr0(instr, 0xe0d3, 0xe0c1);
  540. gencr(instr);
  541. }
  542. void JitCompilerX86::h_SHR_64(Instruction& instr, int i) {
  543. genbr0(instr, 0xe8d3, 0xe8c1);
  544. gencr(instr);
  545. }
  546. void JitCompilerX86::h_SAR_64(Instruction& instr, int i) {
  547. genbr0(instr, 0xf8d3, 0xf8c1);
  548. gencr(instr);
  549. }
  550. void JitCompilerX86::h_ROL_64(Instruction& instr, int i) {
  551. genbr0(instr, 0xc0d3, 0xc0c1);
  552. gencr(instr);
  553. }
  554. void JitCompilerX86::h_ROR_64(Instruction& instr, int i) {
  555. genbr0(instr, 0xc8d3, 0xc8c1);
  556. gencr(instr);
  557. }
  558. void JitCompilerX86::h_FPADD(Instruction& instr, int i) {
  559. genbf(instr, 0x58);
  560. gencf(instr);
  561. }
  562. void JitCompilerX86::h_FPSUB(Instruction& instr, int i) {
  563. genbf(instr, 0x5c);
  564. gencf(instr);
  565. }
  566. void JitCompilerX86::h_FPMUL(Instruction& instr, int i) {
  567. emit(uint16_t(0x0d48)); //or rax,0x800
  568. emit(0x00000800);
  569. genbf(instr, 0x59);
  570. gencf(instr);
  571. }
  572. void JitCompilerX86::h_FPDIV(Instruction& instr, int i) {
  573. emit(uint16_t(0x0d48)); //or rax,0x800
  574. emit(0x00000800);
  575. genbf(instr, 0x5e);
  576. gencf(instr);
  577. }
  578. void JitCompilerX86::h_FPSQRT(Instruction& instr, int i) {
  579. emit(uint16_t(0xb948)); //or movabs rcx, imm64
  580. emit(0x7ffffffffffff800);
  581. emit(0xc02a0f48f2c12348); //and rax,rcx; cvtsi2sd xmm0,rax
  582. emit(0xc0510ff2); //sqrtsd xmm0,xmm0
  583. gencf(instr);
  584. }
  585. void JitCompilerX86::h_FPROUND(Instruction& instr, int i) {
  586. emit(0x81480de0c1c88b48);
  587. emit(0x600025fffff800e1);
  588. emit(0x0dc12a0f48f20000);
  589. emit(0xf824448900009fc0);
  590. emit(0x2454ae0f); //ldmxcsr DWORD PTR [rsp-0x8]
  591. emitByte(0xf8);
  592. gencf(instr);
  593. }
  594. static inline uint8_t jumpCondition(Instruction& instr, bool invert = false) {
  595. switch ((instr.locb & 7) ^ invert)
  596. {
  597. case 0:
  598. return 0x76; //jbe
  599. case 1:
  600. return 0x77; //ja
  601. case 2:
  602. return 0x78; //js
  603. case 3:
  604. return 0x79; //jns
  605. case 4:
  606. return 0x70; //jo
  607. case 5:
  608. return 0x71; //jno
  609. case 6:
  610. return 0x7c; //jl
  611. case 7:
  612. return 0x7d; //jge
  613. }
  614. }
  615. void JitCompilerX86::h_CALL(Instruction& instr, int i) {
  616. emit(uint16_t(0x8141)); //cmp regb, imm32
  617. emitByte(0xf8 + (instr.regb % RegistersCount));
  618. emit(instr.imm32);
  619. emitByte(jumpCondition(instr));
  620. if ((instr.locc & 7) <= 3) {
  621. emitByte(0x16);
  622. }
  623. else {
  624. emitByte(0x05);
  625. }
  626. gencr(instr);
  627. emit(uint16_t(0x06eb)); //jmp to next
  628. emitByte(0x50); //push rax
  629. emitByte(0xe8); //call
  630. i = wrapInstr(i + (instr.imm8 & 127) + 2);
  631. if (i < instructionOffsets.size()) {
  632. emit(instructionOffsets[i] - (codePos + 4));
  633. }
  634. else {
  635. callOffsets.push_back(CallOffset(codePos, i));
  636. codePos += 4;
  637. }
  638. }
  639. void JitCompilerX86::h_RET(Instruction& instr, int i) {
  640. int crlen = 0;
  641. if ((instr.locc & 7) <= 3) {
  642. crlen = 17;
  643. }
  644. emit(0x74e53b48); //cmp rsp, rbp; je
  645. emitByte(20 + crlen);
  646. emit(uint16_t(0x8141)); //cmp regb, imm32
  647. emitByte(0xf8 + (instr.regb % RegistersCount));
  648. emit(instr.imm32);
  649. emitByte(jumpCondition(instr, true));
  650. emitByte(11 + crlen);
  651. emitByte(0x48);
  652. emit(0x08244433); //xor rax,QWORD PTR [rsp+0x8]
  653. gencr(instr);
  654. emitByte(0xc2); //ret 8
  655. emit(uint16_t(0x0008));
  656. gencr(instr);
  657. }
  658. #include "instructionWeights.hpp"
  659. #define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
  660. InstructionGeneratorX86 JitCompilerX86::engine[256] = {
  661. INST_HANDLE(ADD_64)
  662. INST_HANDLE(ADD_32)
  663. INST_HANDLE(SUB_64)
  664. INST_HANDLE(SUB_32)
  665. INST_HANDLE(MUL_64)
  666. INST_HANDLE(MULH_64)
  667. INST_HANDLE(MUL_32)
  668. INST_HANDLE(IMUL_32)
  669. INST_HANDLE(IMULH_64)
  670. INST_HANDLE(DIV_64)
  671. INST_HANDLE(IDIV_64)
  672. INST_HANDLE(AND_64)
  673. INST_HANDLE(AND_32)
  674. INST_HANDLE(OR_64)
  675. INST_HANDLE(OR_32)
  676. INST_HANDLE(XOR_64)
  677. INST_HANDLE(XOR_32)
  678. INST_HANDLE(SHL_64)
  679. INST_HANDLE(SHR_64)
  680. INST_HANDLE(SAR_64)
  681. INST_HANDLE(ROL_64)
  682. INST_HANDLE(ROR_64)
  683. INST_HANDLE(FPADD)
  684. INST_HANDLE(FPSUB)
  685. INST_HANDLE(FPMUL)
  686. INST_HANDLE(FPDIV)
  687. INST_HANDLE(FPSQRT)
  688. INST_HANDLE(FPROUND)
  689. INST_HANDLE(CALL)
  690. INST_HANDLE(RET)
  691. };
  692. }