jit_compiler_a64.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. /*
  2. Copyright (c) 2018-2019, tevador <tevador@gmail.com>
  3. Copyright (c) 2019, SChernykh <https://github.com/SChernykh>
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. * Neither the name of the copyright holder nor the
  13. names of its contributors may be used to endorse or promote products
  14. derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  16. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "jit_compiler_a64.hpp"
  27. #include "superscalar.hpp"
  28. #include "program.hpp"
  29. #include "reciprocal.h"
  30. #include "virtual_memory.hpp"
  31. namespace ARMV8A {
  32. constexpr uint32_t B = 0x14000000;
  33. constexpr uint32_t EOR = 0xCA000000;
  34. constexpr uint32_t EOR32 = 0x4A000000;
  35. constexpr uint32_t ADD = 0x8B000000;
  36. constexpr uint32_t SUB = 0xCB000000;
  37. constexpr uint32_t MUL = 0x9B007C00;
  38. constexpr uint32_t UMULH = 0x9BC07C00;
  39. constexpr uint32_t SMULH = 0x9B407C00;
  40. constexpr uint32_t MOVZ = 0xD2800000;
  41. constexpr uint32_t MOVN = 0x92800000;
  42. constexpr uint32_t MOVK = 0xF2800000;
  43. constexpr uint32_t ADD_IMM_LO = 0x91000000;
  44. constexpr uint32_t ADD_IMM_HI = 0x91400000;
  45. constexpr uint32_t LDR_LITERAL = 0x58000000;
  46. constexpr uint32_t ROR = 0x9AC02C00;
  47. constexpr uint32_t ROR_IMM = 0x93C00000;
  48. constexpr uint32_t MOV_REG = 0xAA0003E0;
  49. constexpr uint32_t MOV_VREG_EL = 0x6E080400;
  50. constexpr uint32_t FADD = 0x4E60D400;
  51. constexpr uint32_t FSUB = 0x4EE0D400;
  52. constexpr uint32_t FEOR = 0x6E201C00;
  53. constexpr uint32_t FMUL = 0x6E60DC00;
  54. constexpr uint32_t FDIV = 0x6E60FC00;
  55. constexpr uint32_t FSQRT = 0x6EE1F800;
  56. }
  57. namespace randomx {
  58. static const size_t CodeSize = ((uint8_t*)randomx_init_dataset_aarch64_end) - ((uint8_t*)randomx_program_aarch64);
  59. static const size_t MainLoopBegin = ((uint8_t*)randomx_program_aarch64_main_loop) - ((uint8_t*)randomx_program_aarch64);
  60. static const size_t PrologueSize = ((uint8_t*)randomx_program_aarch64_vm_instructions) - ((uint8_t*)randomx_program_aarch64);
  61. static const size_t ImulRcpLiteralsEnd = ((uint8_t*)randomx_program_aarch64_imul_rcp_literals_end) - ((uint8_t*)randomx_program_aarch64);
  62. static const size_t CalcDatasetItemSize =
  63. // Prologue
  64. ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch - (uint8_t*)randomx_calc_dataset_item_aarch64) +
  65. // Main loop
  66. RANDOMX_CACHE_ACCESSES * (
  67. // Main loop prologue
  68. ((uint8_t*)randomx_calc_dataset_item_aarch64_mix - ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch)) + 4 +
  69. // Inner main loop (instructions)
  70. ((RANDOMX_SUPERSCALAR_LATENCY * 3) + 2) * 16 +
  71. // Main loop epilogue
  72. ((uint8_t*)randomx_calc_dataset_item_aarch64_store_result - (uint8_t*)randomx_calc_dataset_item_aarch64_mix) + 4
  73. ) +
  74. // Epilogue
  75. ((uint8_t*)randomx_calc_dataset_item_aarch64_end - (uint8_t*)randomx_calc_dataset_item_aarch64_store_result);
  76. constexpr uint32_t IntRegMap[8] = { 4, 5, 6, 7, 12, 13, 14, 15 };
  77. template<typename T> static constexpr size_t Log2(T value) { return (value > 1) ? (Log2(value / 2) + 1) : 0; }
  78. JitCompilerA64::JitCompilerA64()
  79. : code((uint8_t*) allocMemoryPages(CodeSize + CalcDatasetItemSize))
  80. , literalPos(ImulRcpLiteralsEnd)
  81. , num32bitLiterals(0)
  82. {
  83. memset(reg_changed_offset, 0, sizeof(reg_changed_offset));
  84. memcpy(code, (void*) randomx_program_aarch64, CodeSize);
  85. }
  86. JitCompilerA64::~JitCompilerA64()
  87. {
  88. freePagedMemory(code, CodeSize + CalcDatasetItemSize);
  89. }
  90. void JitCompilerA64::enableWriting()
  91. {
  92. setPagesRW(code, CodeSize + CalcDatasetItemSize);
  93. }
  94. void JitCompilerA64::enableExecution()
  95. {
  96. setPagesRX(code, CodeSize + CalcDatasetItemSize);
  97. }
  98. void JitCompilerA64::enableAll()
  99. {
  100. setPagesRWX(code, CodeSize + CalcDatasetItemSize);
  101. }
  102. void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& config)
  103. {
  104. uint32_t codePos = MainLoopBegin + 4;
  105. // and w16, w10, ScratchpadL3Mask64
  106. emit32(0x121A0000 | 16 | (10 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
  107. // and w17, w18, ScratchpadL3Mask64
  108. emit32(0x121A0000 | 17 | (18 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
  109. codePos = PrologueSize;
  110. literalPos = ImulRcpLiteralsEnd;
  111. num32bitLiterals = 0;
  112. for (uint32_t i = 0; i < RegistersCount; ++i)
  113. reg_changed_offset[i] = codePos;
  114. for (uint32_t i = 0; i < program.getSize(); ++i)
  115. {
  116. Instruction& instr = program(i);
  117. instr.src %= RegistersCount;
  118. instr.dst %= RegistersCount;
  119. (this->*engine[instr.opcode])(instr, codePos);
  120. }
  121. // Update spMix2
  122. // eor w18, config.readReg2, config.readReg3
  123. emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
  124. // Jump back to the main loop
  125. const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end) - ((uint8_t*)randomx_program_aarch64)) - codePos;
  126. emit32(ARMV8A::B | (offset / 4), code, codePos);
  127. // and w18, w18, CacheLineAlignMask
  128. codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask1) - ((uint8_t*)randomx_program_aarch64));
  129. emit32(0x121A0000 | 18 | (18 << 5) | ((Log2(RANDOMX_DATASET_BASE_SIZE) - 7) << 10), code, codePos);
  130. // and w10, w10, CacheLineAlignMask
  131. codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask2) - ((uint8_t*)randomx_program_aarch64));
  132. emit32(0x121A0000 | 10 | (10 << 5) | ((Log2(RANDOMX_DATASET_BASE_SIZE) - 7) << 10), code, codePos);
  133. // Update spMix1
  134. // eor x10, config.readReg0, config.readReg1
  135. codePos = ((uint8_t*)randomx_program_aarch64_update_spMix1) - ((uint8_t*)randomx_program_aarch64);
  136. emit32(ARMV8A::EOR | 10 | (IntRegMap[config.readReg0] << 5) | (IntRegMap[config.readReg1] << 16), code, codePos);
  137. #ifdef __GNUC__
  138. __builtin___clear_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
  139. #endif
  140. }
  141. void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration& config, uint32_t datasetOffset)
  142. {
  143. uint32_t codePos = MainLoopBegin + 4;
  144. // and w16, w10, ScratchpadL3Mask64
  145. emit32(0x121A0000 | 16 | (10 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
  146. // and w17, w18, ScratchpadL3Mask64
  147. emit32(0x121A0000 | 17 | (18 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
  148. codePos = PrologueSize;
  149. literalPos = ImulRcpLiteralsEnd;
  150. num32bitLiterals = 0;
  151. for (uint32_t i = 0; i < RegistersCount; ++i)
  152. reg_changed_offset[i] = codePos;
  153. for (uint32_t i = 0; i < program.getSize(); ++i)
  154. {
  155. Instruction& instr = program(i);
  156. instr.src %= RegistersCount;
  157. instr.dst %= RegistersCount;
  158. (this->*engine[instr.opcode])(instr, codePos);
  159. }
  160. // Update spMix2
  161. // eor w18, config.readReg2, config.readReg3
  162. emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
  163. // Jump back to the main loop
  164. const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end_light) - ((uint8_t*)randomx_program_aarch64)) - codePos;
  165. emit32(ARMV8A::B | (offset / 4), code, codePos);
  166. // and w2, w9, CacheLineAlignMask
  167. codePos = (((uint8_t*)randomx_program_aarch64_light_cacheline_align_mask) - ((uint8_t*)randomx_program_aarch64));
  168. emit32(0x121A0000 | 2 | (9 << 5) | ((Log2(RANDOMX_DATASET_BASE_SIZE) - 7) << 10), code, codePos);
  169. // Update spMix1
  170. // eor x10, config.readReg0, config.readReg1
  171. codePos = ((uint8_t*)randomx_program_aarch64_update_spMix1) - ((uint8_t*)randomx_program_aarch64);
  172. emit32(ARMV8A::EOR | 10 | (IntRegMap[config.readReg0] << 5) | (IntRegMap[config.readReg1] << 16), code, codePos);
  173. // Apply dataset offset
  174. codePos = ((uint8_t*)randomx_program_aarch64_light_dataset_offset) - ((uint8_t*)randomx_program_aarch64);
  175. datasetOffset /= CacheLineSize;
  176. const uint32_t imm_lo = datasetOffset & ((1 << 12) - 1);
  177. const uint32_t imm_hi = datasetOffset >> 12;
  178. emit32(ARMV8A::ADD_IMM_LO | 2 | (2 << 5) | (imm_lo << 10), code, codePos);
  179. emit32(ARMV8A::ADD_IMM_HI | 2 | (2 << 5) | (imm_hi << 10), code, codePos);
  180. #ifdef __GNUC__
  181. __builtin___clear_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
  182. #endif
  183. }
  184. template<size_t N>
  185. void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector<uint64_t> &reciprocalCache)
  186. {
  187. uint32_t codePos = CodeSize;
  188. uint8_t* p1 = (uint8_t*)randomx_calc_dataset_item_aarch64;
  189. uint8_t* p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_prefetch;
  190. memcpy(code + codePos, p1, p2 - p1);
  191. codePos += p2 - p1;
  192. num32bitLiterals = 64;
  193. constexpr uint32_t tmp_reg = 12;
  194. for (size_t i = 0; i < N; ++i)
  195. {
  196. // and x11, x10, CacheSize / CacheLineSize - 1
  197. emit32(0x92400000 | 11 | (10 << 5) | ((Log2(CacheSize / CacheLineSize) - 1) << 10), code, codePos);
  198. p1 = ((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch) + 4;
  199. p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_mix;
  200. memcpy(code + codePos, p1, p2 - p1);
  201. codePos += p2 - p1;
  202. SuperscalarProgram& prog = programs[i];
  203. const size_t progSize = prog.getSize();
  204. uint32_t jmp_pos = codePos;
  205. codePos += 4;
  206. // Fill in literal pool
  207. for (size_t j = 0; j < progSize; ++j)
  208. {
  209. const Instruction& instr = prog(j);
  210. if (static_cast<SuperscalarInstructionType>(instr.opcode) == randomx::SuperscalarInstructionType::IMUL_RCP)
  211. emit64(reciprocalCache[instr.getImm32()], code, codePos);
  212. }
  213. // Jump over literal pool
  214. uint32_t literal_pos = jmp_pos;
  215. emit32(ARMV8A::B | ((codePos - jmp_pos) / 4), code, literal_pos);
  216. for (size_t j = 0; j < progSize; ++j)
  217. {
  218. const Instruction& instr = prog(j);
  219. const uint32_t src = instr.src;
  220. const uint32_t dst = instr.dst;
  221. switch (static_cast<SuperscalarInstructionType>(instr.opcode))
  222. {
  223. case randomx::SuperscalarInstructionType::ISUB_R:
  224. emit32(ARMV8A::SUB | dst | (dst << 5) | (src << 16), code, codePos);
  225. break;
  226. case randomx::SuperscalarInstructionType::IXOR_R:
  227. emit32(ARMV8A::EOR | dst | (dst << 5) | (src << 16), code, codePos);
  228. break;
  229. case randomx::SuperscalarInstructionType::IADD_RS:
  230. emit32(ARMV8A::ADD | dst | (dst << 5) | (instr.getModShift() << 10) | (src << 16), code, codePos);
  231. break;
  232. case randomx::SuperscalarInstructionType::IMUL_R:
  233. emit32(ARMV8A::MUL | dst | (dst << 5) | (src << 16), code, codePos);
  234. break;
  235. case randomx::SuperscalarInstructionType::IROR_C:
  236. emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
  237. break;
  238. case randomx::SuperscalarInstructionType::IADD_C7:
  239. case randomx::SuperscalarInstructionType::IADD_C8:
  240. case randomx::SuperscalarInstructionType::IADD_C9:
  241. emitAddImmediate(dst, dst, instr.getImm32(), code, codePos);
  242. break;
  243. case randomx::SuperscalarInstructionType::IXOR_C7:
  244. case randomx::SuperscalarInstructionType::IXOR_C8:
  245. case randomx::SuperscalarInstructionType::IXOR_C9:
  246. emitMovImmediate(tmp_reg, instr.getImm32(), code, codePos);
  247. emit32(ARMV8A::EOR | dst | (dst << 5) | (tmp_reg << 16), code, codePos);
  248. break;
  249. case randomx::SuperscalarInstructionType::IMULH_R:
  250. emit32(ARMV8A::UMULH | dst | (dst << 5) | (src << 16), code, codePos);
  251. break;
  252. case randomx::SuperscalarInstructionType::ISMULH_R:
  253. emit32(ARMV8A::SMULH | dst | (dst << 5) | (src << 16), code, codePos);
  254. break;
  255. case randomx::SuperscalarInstructionType::IMUL_RCP:
  256. {
  257. int32_t offset = (literal_pos - codePos) / 4;
  258. offset &= (1 << 19) - 1;
  259. literal_pos += 8;
  260. // ldr tmp_reg, reciprocal
  261. emit32(ARMV8A::LDR_LITERAL | tmp_reg | (offset << 5), code, codePos);
  262. // mul dst, dst, tmp_reg
  263. emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, codePos);
  264. }
  265. break;
  266. default:
  267. break;
  268. }
  269. }
  270. p1 = (uint8_t*)randomx_calc_dataset_item_aarch64_mix;
  271. p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_store_result;
  272. memcpy(code + codePos, p1, p2 - p1);
  273. codePos += p2 - p1;
  274. // Update registerValue
  275. emit32(ARMV8A::MOV_REG | 10 | (prog.getAddressRegister() << 16), code, codePos);
  276. }
  277. p1 = (uint8_t*)randomx_calc_dataset_item_aarch64_store_result;
  278. p2 = (uint8_t*)randomx_calc_dataset_item_aarch64_end;
  279. memcpy(code + codePos, p1, p2 - p1);
  280. codePos += p2 - p1;
  281. #ifdef __GNUC__
  282. __builtin___clear_cache(reinterpret_cast<char*>(code + CodeSize), reinterpret_cast<char*>(code + codePos));
  283. #endif
  284. }
  285. template void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_ACCESSES], std::vector<uint64_t> &reciprocalCache);
  286. DatasetInitFunc* JitCompilerA64::getDatasetInitFunc()
  287. {
  288. return (DatasetInitFunc*)(code + (((uint8_t*)randomx_init_dataset_aarch64) - ((uint8_t*)randomx_program_aarch64)));
  289. }
  290. size_t JitCompilerA64::getCodeSize()
  291. {
  292. return CodeSize;
  293. }
  294. void JitCompilerA64::emitMovImmediate(uint32_t dst, uint32_t imm, uint8_t* code, uint32_t& codePos)
  295. {
  296. uint32_t k = codePos;
  297. if (imm < (1 << 16))
  298. {
  299. // movz tmp_reg, imm32 (16 low bits)
  300. emit32(ARMV8A::MOVZ | dst | (imm << 5), code, k);
  301. }
  302. else
  303. {
  304. if (num32bitLiterals < 64)
  305. {
  306. if (static_cast<int32_t>(imm) < 0)
  307. {
  308. // smov dst, vN.s[M]
  309. emit32(0x4E042C00 | dst | ((num32bitLiterals / 4) << 5) | ((num32bitLiterals % 4) << 19), code, k);
  310. }
  311. else
  312. {
  313. // umov dst, vN.s[M]
  314. emit32(0x0E043C00 | dst | ((num32bitLiterals / 4) << 5) | ((num32bitLiterals % 4) << 19), code, k);
  315. }
  316. ((uint32_t*)(code + ImulRcpLiteralsEnd))[num32bitLiterals] = imm;
  317. ++num32bitLiterals;
  318. }
  319. else
  320. {
  321. if (static_cast<int32_t>(imm) < 0)
  322. {
  323. // movn tmp_reg, ~imm32 (16 high bits)
  324. emit32(ARMV8A::MOVN | dst | (1 << 21) | ((~imm >> 16) << 5), code, k);
  325. }
  326. else
  327. {
  328. // movz tmp_reg, imm32 (16 high bits)
  329. emit32(ARMV8A::MOVZ | dst | (1 << 21) | ((imm >> 16) << 5), code, k);
  330. }
  331. // movk tmp_reg, imm32 (16 low bits)
  332. emit32(ARMV8A::MOVK | dst | ((imm & 0xFFFF) << 5), code, k);
  333. }
  334. }
  335. codePos = k;
  336. }
  337. void JitCompilerA64::emitAddImmediate(uint32_t dst, uint32_t src, uint32_t imm, uint8_t* code, uint32_t& codePos)
  338. {
  339. uint32_t k = codePos;
  340. if (imm < (1 << 24))
  341. {
  342. const uint32_t imm_lo = imm & ((1 << 12) - 1);
  343. const uint32_t imm_hi = imm >> 12;
  344. if (imm_lo && imm_hi)
  345. {
  346. emit32(ARMV8A::ADD_IMM_LO | dst | (src << 5) | (imm_lo << 10), code, k);
  347. emit32(ARMV8A::ADD_IMM_HI | dst | (dst << 5) | (imm_hi << 10), code, k);
  348. }
  349. else if (imm_lo)
  350. {
  351. emit32(ARMV8A::ADD_IMM_LO | dst | (src << 5) | (imm_lo << 10), code, k);
  352. }
  353. else
  354. {
  355. emit32(ARMV8A::ADD_IMM_HI | dst | (src << 5) | (imm_hi << 10), code, k);
  356. }
  357. }
  358. else
  359. {
  360. constexpr uint32_t tmp_reg = 18;
  361. emitMovImmediate(tmp_reg, imm, code, k);
  362. // add dst, src, tmp_reg
  363. emit32(ARMV8A::ADD | dst | (src << 5) | (tmp_reg << 16), code, k);
  364. }
  365. codePos = k;
  366. }
  367. template<uint32_t tmp_reg>
  368. void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos)
  369. {
  370. uint32_t k = codePos;
  371. uint32_t imm = instr.getImm32();
  372. if (src != dst)
  373. {
  374. imm &= instr.getModMem() ? (RANDOMX_SCRATCHPAD_L1 - 1) : (RANDOMX_SCRATCHPAD_L2 - 1);
  375. emitAddImmediate(tmp_reg, src, imm, code, k);
  376. constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
  377. constexpr uint32_t andInstrL1 = t | ((Log2(RANDOMX_SCRATCHPAD_L1) - 4) << 10);
  378. constexpr uint32_t andInstrL2 = t | ((Log2(RANDOMX_SCRATCHPAD_L2) - 4) << 10);
  379. emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
  380. // ldr tmp_reg, [x2, tmp_reg]
  381. emit32(0xf8606840 | tmp_reg | (tmp_reg << 16), code, k);
  382. }
  383. else
  384. {
  385. imm = (imm & ScratchpadL3Mask) >> 3;
  386. emitMovImmediate(tmp_reg, imm, code, k);
  387. // ldr tmp_reg, [x2, tmp_reg, lsl 3]
  388. emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k);
  389. }
  390. codePos = k;
  391. }
  392. template<uint32_t tmp_reg_fp>
  393. void JitCompilerA64::emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* code, uint32_t& codePos)
  394. {
  395. uint32_t k = codePos;
  396. uint32_t imm = instr.getImm32();
  397. constexpr uint32_t tmp_reg = 18;
  398. imm &= instr.getModMem() ? (RANDOMX_SCRATCHPAD_L1 - 1) : (RANDOMX_SCRATCHPAD_L2 - 1);
  399. emitAddImmediate(tmp_reg, src, imm, code, k);
  400. constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
  401. constexpr uint32_t andInstrL1 = t | ((Log2(RANDOMX_SCRATCHPAD_L1) - 4) << 10);
  402. constexpr uint32_t andInstrL2 = t | ((Log2(RANDOMX_SCRATCHPAD_L2) - 4) << 10);
  403. emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
  404. // add tmp_reg, x2, tmp_reg
  405. emit32(ARMV8A::ADD | tmp_reg | (2 << 5) | (tmp_reg << 16), code, k);
  406. // ldpsw tmp_reg, tmp_reg + 1, [tmp_reg]
  407. emit32(0x69400000 | tmp_reg | (tmp_reg << 5) | ((tmp_reg + 1) << 10), code, k);
  408. // ins tmp_reg_fp.d[0], tmp_reg
  409. emit32(0x4E081C00 | tmp_reg_fp | (tmp_reg << 5), code, k);
  410. // ins tmp_reg_fp.d[1], tmp_reg + 1
  411. emit32(0x4E181C00 | tmp_reg_fp | ((tmp_reg + 1) << 5), code, k);
  412. // scvtf tmp_reg_fp.2d, tmp_reg_fp.2d
  413. emit32(0x4E61D800 | tmp_reg_fp | (tmp_reg_fp << 5), code, k);
  414. codePos = k;
  415. }
  416. void JitCompilerA64::h_IADD_RS(Instruction& instr, uint32_t& codePos)
  417. {
  418. uint32_t k = codePos;
  419. const uint32_t src = IntRegMap[instr.src];
  420. const uint32_t dst = IntRegMap[instr.dst];
  421. const uint32_t shift = instr.getModShift();
  422. // add dst, src << shift
  423. emit32(ARMV8A::ADD | dst | (dst << 5) | (shift << 10) | (src << 16), code, k);
  424. if (instr.dst == RegisterNeedsDisplacement)
  425. emitAddImmediate(dst, dst, instr.getImm32(), code, k);
  426. reg_changed_offset[instr.dst] = k;
  427. codePos = k;
  428. }
  429. void JitCompilerA64::h_IADD_M(Instruction& instr, uint32_t& codePos)
  430. {
  431. uint32_t k = codePos;
  432. const uint32_t src = IntRegMap[instr.src];
  433. const uint32_t dst = IntRegMap[instr.dst];
  434. constexpr uint32_t tmp_reg = 18;
  435. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  436. // add dst, dst, tmp_reg
  437. emit32(ARMV8A::ADD | dst | (dst << 5) | (tmp_reg << 16), code, k);
  438. reg_changed_offset[instr.dst] = k;
  439. codePos = k;
  440. }
  441. void JitCompilerA64::h_ISUB_R(Instruction& instr, uint32_t& codePos)
  442. {
  443. uint32_t k = codePos;
  444. const uint32_t src = IntRegMap[instr.src];
  445. const uint32_t dst = IntRegMap[instr.dst];
  446. if (src != dst)
  447. {
  448. // sub dst, dst, src
  449. emit32(ARMV8A::SUB | dst | (dst << 5) | (src << 16), code, k);
  450. }
  451. else
  452. {
  453. emitAddImmediate(dst, dst, -instr.getImm32(), code, k);
  454. }
  455. reg_changed_offset[instr.dst] = k;
  456. codePos = k;
  457. }
  458. void JitCompilerA64::h_ISUB_M(Instruction& instr, uint32_t& codePos)
  459. {
  460. uint32_t k = codePos;
  461. const uint32_t src = IntRegMap[instr.src];
  462. const uint32_t dst = IntRegMap[instr.dst];
  463. constexpr uint32_t tmp_reg = 18;
  464. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  465. // sub dst, dst, tmp_reg
  466. emit32(ARMV8A::SUB | dst | (dst << 5) | (tmp_reg << 16), code, k);
  467. reg_changed_offset[instr.dst] = k;
  468. codePos = k;
  469. }
  470. void JitCompilerA64::h_IMUL_R(Instruction& instr, uint32_t& codePos)
  471. {
  472. uint32_t k = codePos;
  473. uint32_t src = IntRegMap[instr.src];
  474. const uint32_t dst = IntRegMap[instr.dst];
  475. if (src == dst)
  476. {
  477. src = 18;
  478. emitMovImmediate(src, instr.getImm32(), code, k);
  479. }
  480. // mul dst, dst, src
  481. emit32(ARMV8A::MUL | dst | (dst << 5) | (src << 16), code, k);
  482. reg_changed_offset[instr.dst] = k;
  483. codePos = k;
  484. }
  485. void JitCompilerA64::h_IMUL_M(Instruction& instr, uint32_t& codePos)
  486. {
  487. uint32_t k = codePos;
  488. const uint32_t src = IntRegMap[instr.src];
  489. const uint32_t dst = IntRegMap[instr.dst];
  490. constexpr uint32_t tmp_reg = 18;
  491. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  492. // sub dst, dst, tmp_reg
  493. emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, k);
  494. reg_changed_offset[instr.dst] = k;
  495. codePos = k;
  496. }
  497. void JitCompilerA64::h_IMULH_R(Instruction& instr, uint32_t& codePos)
  498. {
  499. uint32_t k = codePos;
  500. const uint32_t src = IntRegMap[instr.src];
  501. const uint32_t dst = IntRegMap[instr.dst];
  502. // umulh dst, dst, src
  503. emit32(ARMV8A::UMULH | dst | (dst << 5) | (src << 16), code, k);
  504. reg_changed_offset[instr.dst] = k;
  505. codePos = k;
  506. }
  507. void JitCompilerA64::h_IMULH_M(Instruction& instr, uint32_t& codePos)
  508. {
  509. uint32_t k = codePos;
  510. const uint32_t src = IntRegMap[instr.src];
  511. const uint32_t dst = IntRegMap[instr.dst];
  512. constexpr uint32_t tmp_reg = 18;
  513. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  514. // umulh dst, dst, tmp_reg
  515. emit32(ARMV8A::UMULH | dst | (dst << 5) | (tmp_reg << 16), code, k);
  516. reg_changed_offset[instr.dst] = k;
  517. codePos = k;
  518. }
  519. void JitCompilerA64::h_ISMULH_R(Instruction& instr, uint32_t& codePos)
  520. {
  521. uint32_t k = codePos;
  522. const uint32_t src = IntRegMap[instr.src];
  523. const uint32_t dst = IntRegMap[instr.dst];
  524. // smulh dst, dst, src
  525. emit32(ARMV8A::SMULH | dst | (dst << 5) | (src << 16), code, k);
  526. reg_changed_offset[instr.dst] = k;
  527. codePos = k;
  528. }
  529. void JitCompilerA64::h_ISMULH_M(Instruction& instr, uint32_t& codePos)
  530. {
  531. uint32_t k = codePos;
  532. const uint32_t src = IntRegMap[instr.src];
  533. const uint32_t dst = IntRegMap[instr.dst];
  534. constexpr uint32_t tmp_reg = 18;
  535. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  536. // smulh dst, dst, tmp_reg
  537. emit32(ARMV8A::SMULH | dst | (dst << 5) | (tmp_reg << 16), code, k);
  538. reg_changed_offset[instr.dst] = k;
  539. codePos = k;
  540. }
  541. void JitCompilerA64::h_IMUL_RCP(Instruction& instr, uint32_t& codePos)
  542. {
  543. const uint64_t divisor = instr.getImm32();
  544. if (isZeroOrPowerOf2(divisor))
  545. return;
  546. uint32_t k = codePos;
  547. constexpr uint32_t tmp_reg = 18;
  548. const uint32_t dst = IntRegMap[instr.dst];
  549. constexpr uint64_t N = 1ULL << 63;
  550. const uint64_t q = N / divisor;
  551. const uint64_t r = N % divisor;
  552. #ifdef __GNUC__
  553. const uint64_t shift = 64 - __builtin_clzll(divisor);
  554. #else
  555. uint64_t shift = 32;
  556. for (uint64_t k = 1U << 31; (k & divisor) == 0; k >>= 1)
  557. --shift;
  558. #endif
  559. const uint32_t literal_id = (ImulRcpLiteralsEnd - literalPos) / sizeof(uint64_t);
  560. literalPos -= sizeof(uint64_t);
  561. *(uint64_t*)(code + literalPos) = (q << shift) + ((r << shift) / divisor);
  562. if (literal_id < 13)
  563. {
  564. static constexpr uint32_t literal_regs[13] = { 30 << 16, 29 << 16, 28 << 16, 27 << 16, 26 << 16, 25 << 16, 24 << 16, 23 << 16, 22 << 16, 21 << 16, 20 << 16, 11 << 16, 0 };
  565. // mul dst, dst, literal_reg
  566. emit32(ARMV8A::MUL | dst | (dst << 5) | literal_regs[literal_id], code, k);
  567. }
  568. else
  569. {
  570. // ldr tmp_reg, reciprocal
  571. const uint32_t offset = (literalPos - k) / 4;
  572. emit32(ARMV8A::LDR_LITERAL | tmp_reg | (offset << 5), code, k);
  573. // mul dst, dst, tmp_reg
  574. emit32(ARMV8A::MUL | dst | (dst << 5) | (tmp_reg << 16), code, k);
  575. }
  576. reg_changed_offset[instr.dst] = k;
  577. codePos = k;
  578. }
  579. void JitCompilerA64::h_INEG_R(Instruction& instr, uint32_t& codePos)
  580. {
  581. const uint32_t dst = IntRegMap[instr.dst];
  582. // sub dst, xzr, dst
  583. emit32(ARMV8A::SUB | dst | (31 << 5) | (dst << 16), code, codePos);
  584. reg_changed_offset[instr.dst] = codePos;
  585. }
  586. void JitCompilerA64::h_IXOR_R(Instruction& instr, uint32_t& codePos)
  587. {
  588. uint32_t k = codePos;
  589. uint32_t src = IntRegMap[instr.src];
  590. const uint32_t dst = IntRegMap[instr.dst];
  591. if (src == dst)
  592. {
  593. src = 18;
  594. emitMovImmediate(src, instr.getImm32(), code, k);
  595. }
  596. // eor dst, dst, src
  597. emit32(ARMV8A::EOR | dst | (dst << 5) | (src << 16), code, k);
  598. reg_changed_offset[instr.dst] = k;
  599. codePos = k;
  600. }
  601. void JitCompilerA64::h_IXOR_M(Instruction& instr, uint32_t& codePos)
  602. {
  603. uint32_t k = codePos;
  604. const uint32_t src = IntRegMap[instr.src];
  605. const uint32_t dst = IntRegMap[instr.dst];
  606. constexpr uint32_t tmp_reg = 18;
  607. emitMemLoad<tmp_reg>(dst, src, instr, code, k);
  608. // eor dst, dst, tmp_reg
  609. emit32(ARMV8A::EOR | dst | (dst << 5) | (tmp_reg << 16), code, k);
  610. reg_changed_offset[instr.dst] = k;
  611. codePos = k;
  612. }
  613. void JitCompilerA64::h_IROR_R(Instruction& instr, uint32_t& codePos)
  614. {
  615. const uint32_t src = IntRegMap[instr.src];
  616. const uint32_t dst = IntRegMap[instr.dst];
  617. if (src != dst)
  618. {
  619. // ror dst, dst, src
  620. emit32(ARMV8A::ROR | dst | (dst << 5) | (src << 16), code, codePos);
  621. }
  622. else
  623. {
  624. // ror dst, dst, imm
  625. emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
  626. }
  627. reg_changed_offset[instr.dst] = codePos;
  628. }
  629. void JitCompilerA64::h_IROL_R(Instruction& instr, uint32_t& codePos)
  630. {
  631. uint32_t k = codePos;
  632. const uint32_t src = IntRegMap[instr.src];
  633. const uint32_t dst = IntRegMap[instr.dst];
  634. if (src != dst)
  635. {
  636. constexpr uint32_t tmp_reg = 18;
  637. // sub tmp_reg, xzr, src
  638. emit32(ARMV8A::SUB | tmp_reg | (31 << 5) | (src << 16), code, k);
  639. // ror dst, dst, tmp_reg
  640. emit32(ARMV8A::ROR | dst | (dst << 5) | (tmp_reg << 16), code, k);
  641. }
  642. else
  643. {
  644. // ror dst, dst, imm
  645. emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k);
  646. }
  647. reg_changed_offset[instr.dst] = k;
  648. codePos = k;
  649. }
  650. void JitCompilerA64::h_ISWAP_R(Instruction& instr, uint32_t& codePos)
  651. {
  652. const uint32_t src = IntRegMap[instr.src];
  653. const uint32_t dst = IntRegMap[instr.dst];
  654. if (src == dst)
  655. return;
  656. uint32_t k = codePos;
  657. constexpr uint32_t tmp_reg = 18;
  658. emit32(ARMV8A::MOV_REG | tmp_reg | (dst << 16), code, k);
  659. emit32(ARMV8A::MOV_REG | dst | (src << 16), code, k);
  660. emit32(ARMV8A::MOV_REG | src | (tmp_reg << 16), code, k);
  661. reg_changed_offset[instr.src] = k;
  662. reg_changed_offset[instr.dst] = k;
  663. codePos = k;
  664. }
  665. void JitCompilerA64::h_FSWAP_R(Instruction& instr, uint32_t& codePos)
  666. {
  667. uint32_t k = codePos;
  668. const uint32_t dst = instr.dst + 16;
  669. constexpr uint32_t tmp_reg_fp = 28;
  670. constexpr uint32_t src_index1 = 1 << 14;
  671. constexpr uint32_t dst_index1 = 1 << 20;
  672. emit32(ARMV8A::MOV_VREG_EL | tmp_reg_fp | (dst << 5) | src_index1, code, k);
  673. emit32(ARMV8A::MOV_VREG_EL | dst | (dst << 5) | dst_index1, code, k);
  674. emit32(ARMV8A::MOV_VREG_EL | dst | (tmp_reg_fp << 5), code, k);
  675. codePos = k;
  676. }
  677. void JitCompilerA64::h_FADD_R(Instruction& instr, uint32_t& codePos)
  678. {
  679. const uint32_t src = (instr.src % 4) + 24;
  680. const uint32_t dst = (instr.dst % 4) + 16;
  681. emit32(ARMV8A::FADD | dst | (dst << 5) | (src << 16), code, codePos);
  682. }
  683. void JitCompilerA64::h_FADD_M(Instruction& instr, uint32_t& codePos)
  684. {
  685. uint32_t k = codePos;
  686. const uint32_t src = IntRegMap[instr.src];
  687. const uint32_t dst = (instr.dst % 4) + 16;
  688. constexpr uint32_t tmp_reg_fp = 28;
  689. emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
  690. emit32(ARMV8A::FADD | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
  691. codePos = k;
  692. }
  693. void JitCompilerA64::h_FSUB_R(Instruction& instr, uint32_t& codePos)
  694. {
  695. const uint32_t src = (instr.src % 4) + 24;
  696. const uint32_t dst = (instr.dst % 4) + 16;
  697. emit32(ARMV8A::FSUB | dst | (dst << 5) | (src << 16), code, codePos);
  698. }
  699. void JitCompilerA64::h_FSUB_M(Instruction& instr, uint32_t& codePos)
  700. {
  701. uint32_t k = codePos;
  702. const uint32_t src = IntRegMap[instr.src];
  703. const uint32_t dst = (instr.dst % 4) + 16;
  704. constexpr uint32_t tmp_reg_fp = 28;
  705. emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
  706. emit32(ARMV8A::FSUB | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
  707. codePos = k;
  708. }
  709. void JitCompilerA64::h_FSCAL_R(Instruction& instr, uint32_t& codePos)
  710. {
  711. const uint32_t dst = (instr.dst % 4) + 16;
  712. emit32(ARMV8A::FEOR | dst | (dst << 5) | (31 << 16), code, codePos);
  713. }
  714. void JitCompilerA64::h_FMUL_R(Instruction& instr, uint32_t& codePos)
  715. {
  716. const uint32_t src = (instr.src % 4) + 24;
  717. const uint32_t dst = (instr.dst % 4) + 20;
  718. emit32(ARMV8A::FMUL | dst | (dst << 5) | (src << 16), code, codePos);
  719. }
  720. void JitCompilerA64::h_FDIV_M(Instruction& instr, uint32_t& codePos)
  721. {
  722. uint32_t k = codePos;
  723. const uint32_t src = IntRegMap[instr.src];
  724. const uint32_t dst = (instr.dst % 4) + 20;
  725. constexpr uint32_t tmp_reg_fp = 28;
  726. emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
  727. // and tmp_reg_fp, tmp_reg_fp, and_mask_reg
  728. emit32(0x4E201C00 | tmp_reg_fp | (tmp_reg_fp << 5) | (29 << 16), code, k);
  729. // orr tmp_reg_fp, tmp_reg_fp, or_mask_reg
  730. emit32(0x4EA01C00 | tmp_reg_fp | (tmp_reg_fp << 5) | (30 << 16), code, k);
  731. emit32(ARMV8A::FDIV | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
  732. codePos = k;
  733. }
  734. void JitCompilerA64::h_FSQRT_R(Instruction& instr, uint32_t& codePos)
  735. {
  736. const uint32_t dst = (instr.dst % 4) + 20;
  737. emit32(ARMV8A::FSQRT | dst | (dst << 5), code, codePos);
  738. }
  739. void JitCompilerA64::h_CBRANCH(Instruction& instr, uint32_t& codePos)
  740. {
  741. uint32_t k = codePos;
  742. const uint32_t dst = IntRegMap[instr.dst];
  743. const uint32_t modCond = instr.getModCond();
  744. const uint32_t shift = modCond + ConditionOffset;
  745. const uint32_t imm = (instr.getImm32() | (1U << shift)) & ~(1U << (shift - 1));
  746. emitAddImmediate(dst, dst, imm, code, k);
  747. // tst dst, mask
  748. static_assert((ConditionMask == 0xFF) && (ConditionOffset == 8), "Update tst encoding for different mask and offset");
  749. emit32((0xF2781C1F - (modCond << 16)) | (dst << 5), code, k);
  750. int32_t offset = reg_changed_offset[instr.dst];
  751. offset = ((offset - k) >> 2) & ((1 << 19) - 1);
  752. // beq target
  753. emit32(0x54000000 | (offset << 5), code, k);
  754. for (uint32_t i = 0; i < RegistersCount; ++i)
  755. reg_changed_offset[i] = k;
  756. codePos = k;
  757. }
  758. void JitCompilerA64::h_CFROUND(Instruction& instr, uint32_t& codePos)
  759. {
  760. uint32_t k = codePos;
  761. const uint32_t src = IntRegMap[instr.src];
  762. constexpr uint32_t tmp_reg = 18;
  763. constexpr uint32_t fpcr_tmp_reg = 8;
  764. // ror tmp_reg, src, imm
  765. emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k);
  766. // bfi fpcr_tmp_reg, tmp_reg, 40, 2
  767. emit32(0xB3580400 | fpcr_tmp_reg | (tmp_reg << 5), code, k);
  768. // rbit tmp_reg, fpcr_tmp_reg
  769. emit32(0xDAC00000 | tmp_reg | (fpcr_tmp_reg << 5), code, k);
  770. // msr fpcr, tmp_reg
  771. emit32(0xD51B4400 | tmp_reg, code, k);
  772. codePos = k;
  773. }
  774. void JitCompilerA64::h_ISTORE(Instruction& instr, uint32_t& codePos)
  775. {
  776. uint32_t k = codePos;
  777. const uint32_t src = IntRegMap[instr.src];
  778. const uint32_t dst = IntRegMap[instr.dst];
  779. constexpr uint32_t tmp_reg = 18;
  780. uint32_t imm = instr.getImm32();
  781. if (instr.getModCond() < StoreL3Condition)
  782. imm &= instr.getModMem() ? (RANDOMX_SCRATCHPAD_L1 - 1) : (RANDOMX_SCRATCHPAD_L2 - 1);
  783. else
  784. imm &= RANDOMX_SCRATCHPAD_L3 - 1;
  785. emitAddImmediate(tmp_reg, dst, imm, code, k);
  786. constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
  787. constexpr uint32_t andInstrL1 = t | ((Log2(RANDOMX_SCRATCHPAD_L1) - 4) << 10);
  788. constexpr uint32_t andInstrL2 = t | ((Log2(RANDOMX_SCRATCHPAD_L2) - 4) << 10);
  789. constexpr uint32_t andInstrL3 = t | ((Log2(RANDOMX_SCRATCHPAD_L3) - 4) << 10);
  790. emit32((instr.getModCond() < StoreL3Condition) ? (instr.getModMem() ? andInstrL1 : andInstrL2) : andInstrL3, code, k);
  791. // str src, [x2, tmp_reg]
  792. emit32(0xF8206840 | src | (tmp_reg << 16), code, k);
  793. codePos = k;
  794. }
  795. void JitCompilerA64::h_NOP(Instruction& instr, uint32_t& codePos)
  796. {
  797. }
  798. #include "instruction_weights.hpp"
  799. #define INST_HANDLE(x) REPN(&JitCompilerA64::h_##x, WT(x))
  800. InstructionGeneratorA64 JitCompilerA64::engine[256] = {
  801. INST_HANDLE(IADD_RS)
  802. INST_HANDLE(IADD_M)
  803. INST_HANDLE(ISUB_R)
  804. INST_HANDLE(ISUB_M)
  805. INST_HANDLE(IMUL_R)
  806. INST_HANDLE(IMUL_M)
  807. INST_HANDLE(IMULH_R)
  808. INST_HANDLE(IMULH_M)
  809. INST_HANDLE(ISMULH_R)
  810. INST_HANDLE(ISMULH_M)
  811. INST_HANDLE(IMUL_RCP)
  812. INST_HANDLE(INEG_R)
  813. INST_HANDLE(IXOR_R)
  814. INST_HANDLE(IXOR_M)
  815. INST_HANDLE(IROR_R)
  816. INST_HANDLE(IROL_R)
  817. INST_HANDLE(ISWAP_R)
  818. INST_HANDLE(FSWAP_R)
  819. INST_HANDLE(FADD_R)
  820. INST_HANDLE(FADD_M)
  821. INST_HANDLE(FSUB_R)
  822. INST_HANDLE(FSUB_M)
  823. INST_HANDLE(FSCAL_R)
  824. INST_HANDLE(FMUL_R)
  825. INST_HANDLE(FDIV_M)
  826. INST_HANDLE(FSQRT_R)
  827. INST_HANDLE(CBRANCH)
  828. INST_HANDLE(CFROUND)
  829. INST_HANDLE(ISTORE)
  830. INST_HANDLE(NOP)
  831. };
  832. }