assembly_generator_x86.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /*
  2. Copyright (c) 2018 tevador
  3. This file is part of RandomX.
  4. RandomX is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. RandomX is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with RandomX. If not, see<http://www.gnu.org/licenses/>.
  14. */
  15. //#define TRACE
  16. #include <climits>
  17. #include "assembly_generator_x86.hpp"
  18. #include "common.hpp"
  19. #include "reciprocal.h"
  20. #include "program.hpp"
  21. #include "superscalar.hpp"
  22. namespace randomx {
  23. static const char* regR[] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
  24. static const char* regR32[] = { "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" };
  25. static const char* regFE[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" };
  26. static const char* regF[] = { "xmm0", "xmm1", "xmm2", "xmm3" };
  27. static const char* regE[] = { "xmm4", "xmm5", "xmm6", "xmm7" };
  28. static const char* regA[] = { "xmm8", "xmm9", "xmm10", "xmm11" };
  29. static const char* tempRegx = "xmm12";
  30. static const char* mantissaMask = "xmm13";
  31. static const char* exponentMask = "xmm14";
  32. static const char* scaleMask = "xmm15";
  33. static const char* regIc = "rbx";
  34. static const char* regIc32 = "ebx";
  35. static const char* regIc8 = "bl";
  36. static const char* regScratchpadAddr = "rsi";
  37. void AssemblyGeneratorX86::generateProgram(Program& prog) {
  38. for (unsigned i = 0; i < RegistersCount; ++i) {
  39. registerUsage[i].lastUsed = -1;
  40. registerUsage[i].count = 0;
  41. }
  42. asmCode.str(std::string()); //clear
  43. for (unsigned i = 0; i < prog.getSize(); ++i) {
  44. asmCode << "randomx_isn_" << i << ":" << std::endl;
  45. Instruction& instr = prog(i);
  46. instr.src %= RegistersCount;
  47. instr.dst %= RegistersCount;
  48. generateCode(instr, i);
  49. }
  50. }
  51. void AssemblyGeneratorX86::generateAsm(SuperscalarProgram& prog) {
  52. asmCode.str(std::string()); //clear
  53. asmCode << "ALIGN 16" << std::endl;
  54. for (unsigned i = 0; i < prog.getSize(); ++i) {
  55. Instruction& instr = prog(i);
  56. switch (instr.opcode)
  57. {
  58. case SuperscalarInstructionType::ISUB_R:
  59. asmCode << "sub " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  60. break;
  61. case SuperscalarInstructionType::IXOR_R:
  62. asmCode << "xor " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  63. break;
  64. case SuperscalarInstructionType::IADD_RS:
  65. asmCode << "lea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << "*" << (1 << (instr.getModMem())) << "]" << std::endl;
  66. break;
  67. case SuperscalarInstructionType::IMUL_R:
  68. asmCode << "imul " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  69. break;
  70. case SuperscalarInstructionType::IROR_C:
  71. asmCode << "ror " << regR[instr.dst] << ", " << instr.getImm32() << std::endl;
  72. break;
  73. case SuperscalarInstructionType::IADD_C7:
  74. asmCode << "add " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  75. break;
  76. case SuperscalarInstructionType::IXOR_C7:
  77. asmCode << "xor " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  78. break;
  79. case SuperscalarInstructionType::IADD_C8:
  80. asmCode << "add " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  81. asmCode << "nop" << std::endl;
  82. break;
  83. case SuperscalarInstructionType::IXOR_C8:
  84. asmCode << "xor " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  85. asmCode << "nop" << std::endl;
  86. break;
  87. case SuperscalarInstructionType::IADD_C9:
  88. asmCode << "add " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  89. asmCode << "xchg ax, ax ;nop" << std::endl;
  90. break;
  91. case SuperscalarInstructionType::IXOR_C9:
  92. asmCode << "xor " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  93. asmCode << "xchg ax, ax ;nop" << std::endl;
  94. break;
  95. case SuperscalarInstructionType::IMULH_R:
  96. asmCode << "mov rax, " << regR[instr.dst] << std::endl;
  97. asmCode << "mul " << regR[instr.src] << std::endl;
  98. asmCode << "mov " << regR[instr.dst] << ", rdx" << std::endl;
  99. break;
  100. case SuperscalarInstructionType::ISMULH_R:
  101. asmCode << "mov rax, " << regR[instr.dst] << std::endl;
  102. asmCode << "imul " << regR[instr.src] << std::endl;
  103. asmCode << "mov " << regR[instr.dst] << ", rdx" << std::endl;
  104. break;
  105. case SuperscalarInstructionType::IMUL_RCP:
  106. asmCode << "mov rax, " << (int64_t)randomx_reciprocal(instr.getImm32()) << std::endl;
  107. asmCode << "imul " << regR[instr.dst] << ", rax" << std::endl;
  108. break;
  109. default:
  110. UNREACHABLE;
  111. }
  112. }
  113. }
  114. void AssemblyGeneratorX86::generateC(SuperscalarProgram& prog) {
  115. asmCode.str(std::string()); //clear
  116. asmCode << "#include <stdint.h>" << std::endl;
  117. asmCode << "#if defined(__SIZEOF_INT128__)" << std::endl;
  118. asmCode << " static inline uint64_t mulh(uint64_t a, uint64_t b) {" << std::endl;
  119. asmCode << " return ((unsigned __int128)a * b) >> 64;" << std::endl;
  120. asmCode << " }" << std::endl;
  121. asmCode << " static inline int64_t smulh(int64_t a, int64_t b) {" << std::endl;
  122. asmCode << " return ((__int128)a * b) >> 64;" << std::endl;
  123. asmCode << " }" << std::endl;
  124. asmCode << " #define HAVE_MULH" << std::endl;
  125. asmCode << " #define HAVE_SMULH" << std::endl;
  126. asmCode << "#endif" << std::endl;
  127. asmCode << "#if defined(_MSC_VER)" << std::endl;
  128. asmCode << " #define HAS_VALUE(X) X ## 0" << std::endl;
  129. asmCode << " #define EVAL_DEFINE(X) HAS_VALUE(X)" << std::endl;
  130. asmCode << " #include <intrin.h>" << std::endl;
  131. asmCode << " #include <stdlib.h>" << std::endl;
  132. asmCode << " static __inline uint64_t rotr(uint64_t x , int c) {" << std::endl;
  133. asmCode << " return _rotr64(x, c);" << std::endl;
  134. asmCode << " }" << std::endl;
  135. asmCode << " #define HAVE_ROTR" << std::endl;
  136. asmCode << " #if EVAL_DEFINE(__MACHINEARM64_X64(1))" << std::endl;
  137. asmCode << " static __inline uint64_t mulh(uint64_t a, uint64_t b) {" << std::endl;
  138. asmCode << " return __umulh(a, b);" << std::endl;
  139. asmCode << " }" << std::endl;
  140. asmCode << " #define HAVE_MULH" << std::endl;
  141. asmCode << " #endif" << std::endl;
  142. asmCode << " #if EVAL_DEFINE(__MACHINEX64(1))" << std::endl;
  143. asmCode << " static __inline int64_t smulh(int64_t a, int64_t b) {" << std::endl;
  144. asmCode << " int64_t hi;" << std::endl;
  145. asmCode << " _mul128(a, b, &hi);" << std::endl;
  146. asmCode << " return hi;" << std::endl;
  147. asmCode << " }" << std::endl;
  148. asmCode << " #define HAVE_SMULH" << std::endl;
  149. asmCode << " #endif" << std::endl;
  150. asmCode << "#endif" << std::endl;
  151. asmCode << "#ifndef HAVE_ROTR" << std::endl;
  152. asmCode << " static inline uint64_t rotr(uint64_t a, int b) {" << std::endl;
  153. asmCode << " return (a >> b) | (a << (64 - b));" << std::endl;
  154. asmCode << " }" << std::endl;
  155. asmCode << " #define HAVE_ROTR" << std::endl;
  156. asmCode << "#endif" << std::endl;
  157. asmCode << "#if !defined(HAVE_MULH) || !defined(HAVE_SMULH) || !defined(HAVE_ROTR)" << std::endl;
  158. asmCode << " #error \"Required functions are not defined\"" << std::endl;
  159. asmCode << "#endif" << std::endl;
  160. asmCode << "void superScalar(uint64_t r[8]) {" << std::endl;
  161. asmCode << "uint64_t r8 = r[0], r9 = r[1], r10 = r[2], r11 = r[3], r12 = r[4], r13 = r[5], r14 = r[6], r15 = r[7];" << std::endl;
  162. for (unsigned i = 0; i < prog.getSize(); ++i) {
  163. Instruction& instr = prog(i);
  164. switch (instr.opcode)
  165. {
  166. case SuperscalarInstructionType::ISUB_R:
  167. asmCode << regR[instr.dst] << " -= " << regR[instr.src] << ";" << std::endl;
  168. break;
  169. case SuperscalarInstructionType::IXOR_R:
  170. asmCode << regR[instr.dst] << " ^= " << regR[instr.src] << ";" << std::endl;
  171. break;
  172. case SuperscalarInstructionType::IADD_RS:
  173. asmCode << regR[instr.dst] << " += " << regR[instr.src] << "*" << (1 << (instr.getModMem())) << ";" << std::endl;
  174. break;
  175. case SuperscalarInstructionType::IMUL_R:
  176. asmCode << regR[instr.dst] << " *= " << regR[instr.src] << ";" << std::endl;
  177. break;
  178. case SuperscalarInstructionType::IROR_C:
  179. asmCode << regR[instr.dst] << " = rotr(" << regR[instr.dst] << ", " << instr.getImm32() << ");" << std::endl;
  180. break;
  181. case SuperscalarInstructionType::IADD_C7:
  182. case SuperscalarInstructionType::IADD_C8:
  183. case SuperscalarInstructionType::IADD_C9:
  184. asmCode << regR[instr.dst] << " += " << (int32_t)instr.getImm32() << ";" << std::endl;
  185. break;
  186. case SuperscalarInstructionType::IXOR_C7:
  187. case SuperscalarInstructionType::IXOR_C8:
  188. case SuperscalarInstructionType::IXOR_C9:
  189. asmCode << regR[instr.dst] << " ^= " << (int32_t)instr.getImm32() << ";" << std::endl;
  190. break;
  191. case SuperscalarInstructionType::IMULH_R:
  192. asmCode << regR[instr.dst] << " = mulh(" << regR[instr.dst] << ", " << regR[instr.src] << ");" << std::endl;
  193. break;
  194. case SuperscalarInstructionType::ISMULH_R:
  195. asmCode << regR[instr.dst] << " = smulh(" << regR[instr.dst] << ", " << regR[instr.src] << ");" << std::endl;
  196. break;
  197. case SuperscalarInstructionType::IMUL_RCP:
  198. asmCode << regR[instr.dst] << " *= " << (int64_t)randomx_reciprocal(instr.getImm32()) << ";" << std::endl;
  199. break;
  200. default:
  201. UNREACHABLE;
  202. }
  203. }
  204. asmCode << "r[0] = r8; r[1] = r9; r[2] = r10; r[3] = r11; r[4] = r12; r[5] = r13; r[6] = r14; r[7] = r15;" << std::endl;
  205. asmCode << "}" << std::endl;
  206. }
  207. void AssemblyGeneratorX86::traceint(Instruction& instr) {
  208. if (trace) {
  209. asmCode << "\tpush " << regR[instr.dst] << std::endl;
  210. }
  211. }
  212. void AssemblyGeneratorX86::traceflt(Instruction& instr) {
  213. if (trace) {
  214. asmCode << "\tpush 0" << std::endl;
  215. }
  216. }
  217. void AssemblyGeneratorX86::tracenop(Instruction& instr) {
  218. if (trace) {
  219. asmCode << "\tpush 0" << std::endl;
  220. }
  221. }
  222. void AssemblyGeneratorX86::generateCode(Instruction& instr, int i) {
  223. asmCode << "\t; " << instr;
  224. auto generator = engine[instr.opcode];
  225. (this->*generator)(instr, i);
  226. }
  227. void AssemblyGeneratorX86::genAddressReg(Instruction& instr, const char* reg = "eax") {
  228. asmCode << "\tlea " << reg << ", [" << regR32[instr.src] << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
  229. asmCode << "\tand " << reg << ", " << ((instr.getModMem()) ? ScratchpadL1Mask : ScratchpadL2Mask) << std::endl;
  230. }
  231. void AssemblyGeneratorX86::genAddressRegDst(Instruction& instr, int maskAlign = 8) {
  232. asmCode << "\tlea eax, [" << regR32[instr.dst] << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
  233. int mask;
  234. if (instr.getModCond() < StoreL3Condition) {
  235. mask = instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask;
  236. }
  237. else {
  238. mask = ScratchpadL3Mask;
  239. }
  240. asmCode << "\tand eax" << ", " << (mask & (-maskAlign)) << std::endl;
  241. }
  242. int32_t AssemblyGeneratorX86::genAddressImm(Instruction& instr) {
  243. return (int32_t)instr.getImm32() & ScratchpadL3Mask;
  244. }
  245. void AssemblyGeneratorX86::h_IADD_RS(Instruction& instr, int i) {
  246. registerUsage[instr.dst].lastUsed = i;
  247. if(instr.dst == RegisterNeedsDisplacement)
  248. asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << "*" << (1 << (instr.getModShift())) << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
  249. else
  250. asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << "*" << (1 << (instr.getModShift())) << "]" << std::endl;
  251. traceint(instr);
  252. }
  253. void AssemblyGeneratorX86::h_IADD_M(Instruction& instr, int i) {
  254. registerUsage[instr.dst].lastUsed = i;
  255. if (instr.src != instr.dst) {
  256. genAddressReg(instr);
  257. asmCode << "\tadd " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  258. }
  259. else {
  260. asmCode << "\tadd " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  261. }
  262. traceint(instr);
  263. }
  264. void AssemblyGeneratorX86::h_ISUB_R(Instruction& instr, int i) {
  265. registerUsage[instr.dst].lastUsed = i;
  266. if (instr.src != instr.dst) {
  267. asmCode << "\tsub " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  268. }
  269. else {
  270. asmCode << "\tsub " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  271. }
  272. traceint(instr);
  273. }
  274. void AssemblyGeneratorX86::h_ISUB_M(Instruction& instr, int i) {
  275. registerUsage[instr.dst].lastUsed = i;
  276. if (instr.src != instr.dst) {
  277. genAddressReg(instr);
  278. asmCode << "\tsub " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  279. }
  280. else {
  281. asmCode << "\tsub " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  282. }
  283. traceint(instr);
  284. }
  285. void AssemblyGeneratorX86::h_IMUL_R(Instruction& instr, int i) {
  286. registerUsage[instr.dst].lastUsed = i;
  287. if (instr.src != instr.dst) {
  288. asmCode << "\timul " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  289. }
  290. else {
  291. asmCode << "\timul " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  292. }
  293. traceint(instr);
  294. }
  295. void AssemblyGeneratorX86::h_IMUL_M(Instruction& instr, int i) {
  296. registerUsage[instr.dst].lastUsed = i;
  297. if (instr.src != instr.dst) {
  298. genAddressReg(instr);
  299. asmCode << "\timul " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  300. }
  301. else {
  302. asmCode << "\timul " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  303. }
  304. traceint(instr);
  305. }
  306. //4 uOPs
  307. void AssemblyGeneratorX86::h_IMULH_R(Instruction& instr, int i) {
  308. registerUsage[instr.dst].lastUsed = i;
  309. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  310. asmCode << "\tmul " << regR[instr.src] << std::endl;
  311. asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
  312. traceint(instr);
  313. }
  314. void AssemblyGeneratorX86::h_IMULH_M(Instruction& instr, int i) {
  315. registerUsage[instr.dst].lastUsed = i;
  316. if (instr.src != instr.dst) {
  317. genAddressReg(instr, "ecx");
  318. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  319. asmCode << "\tmul qword ptr [" << regScratchpadAddr << "+rcx]" << std::endl;
  320. }
  321. else {
  322. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  323. asmCode << "\tmul qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  324. }
  325. asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
  326. traceint(instr);
  327. }
  328. void AssemblyGeneratorX86::h_ISMULH_R(Instruction& instr, int i) {
  329. registerUsage[instr.dst].lastUsed = i;
  330. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  331. asmCode << "\timul " << regR[instr.src] << std::endl;
  332. asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
  333. traceint(instr);
  334. }
  335. void AssemblyGeneratorX86::h_ISMULH_M(Instruction& instr, int i) {
  336. registerUsage[instr.dst].lastUsed = i;
  337. if (instr.src != instr.dst) {
  338. genAddressReg(instr, "ecx");
  339. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  340. asmCode << "\timul qword ptr [" << regScratchpadAddr << "+rcx]" << std::endl;
  341. }
  342. else {
  343. asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
  344. asmCode << "\timul qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  345. }
  346. asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
  347. traceint(instr);
  348. }
  349. void AssemblyGeneratorX86::h_INEG_R(Instruction& instr, int i) {
  350. registerUsage[instr.dst].lastUsed = i;
  351. asmCode << "\tneg " << regR[instr.dst] << std::endl;
  352. traceint(instr);
  353. }
  354. void AssemblyGeneratorX86::h_IXOR_R(Instruction& instr, int i) {
  355. registerUsage[instr.dst].lastUsed = i;
  356. if (instr.src != instr.dst) {
  357. asmCode << "\txor " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  358. }
  359. else {
  360. asmCode << "\txor " << regR[instr.dst] << ", " << (int32_t)instr.getImm32() << std::endl;
  361. }
  362. traceint(instr);
  363. }
  364. void AssemblyGeneratorX86::h_IXOR_M(Instruction& instr, int i) {
  365. registerUsage[instr.dst].lastUsed = i;
  366. if (instr.src != instr.dst) {
  367. genAddressReg(instr);
  368. asmCode << "\txor " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  369. }
  370. else {
  371. asmCode << "\txor " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+" << genAddressImm(instr) << "]" << std::endl;
  372. }
  373. traceint(instr);
  374. }
  375. void AssemblyGeneratorX86::h_IROR_R(Instruction& instr, int i) {
  376. registerUsage[instr.dst].lastUsed = i;
  377. if (instr.src != instr.dst) {
  378. asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
  379. asmCode << "\tror " << regR[instr.dst] << ", cl" << std::endl;
  380. }
  381. else {
  382. asmCode << "\tror " << regR[instr.dst] << ", " << (instr.getImm32() & 63) << std::endl;
  383. }
  384. traceint(instr);
  385. }
  386. void AssemblyGeneratorX86::h_IROL_R(Instruction& instr, int i) {
  387. registerUsage[instr.dst].lastUsed = i;
  388. if (instr.src != instr.dst) {
  389. asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
  390. asmCode << "\trol " << regR[instr.dst] << ", cl" << std::endl;
  391. }
  392. else {
  393. asmCode << "\trol " << regR[instr.dst] << ", " << (instr.getImm32() & 63) << std::endl;
  394. }
  395. traceint(instr);
  396. }
  397. void AssemblyGeneratorX86::h_IMUL_RCP(Instruction& instr, int i) {
  398. if (instr.getImm32() != 0) {
  399. registerUsage[instr.dst].lastUsed = i;
  400. asmCode << "\tmov rax, " << randomx_reciprocal(instr.getImm32()) << std::endl;
  401. asmCode << "\timul " << regR[instr.dst] << ", rax" << std::endl;
  402. traceint(instr);
  403. }
  404. else {
  405. tracenop(instr);
  406. }
  407. }
  408. void AssemblyGeneratorX86::h_ISWAP_R(Instruction& instr, int i) {
  409. if (instr.src != instr.dst) {
  410. registerUsage[instr.dst].lastUsed = i;
  411. registerUsage[instr.src].lastUsed = i;
  412. asmCode << "\txchg " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
  413. traceint(instr);
  414. }
  415. else {
  416. tracenop(instr);
  417. }
  418. }
  419. void AssemblyGeneratorX86::h_FSWAP_R(Instruction& instr, int i) {
  420. asmCode << "\tshufpd " << regFE[instr.dst] << ", " << regFE[instr.dst] << ", 1" << std::endl;
  421. traceflt(instr);
  422. }
  423. void AssemblyGeneratorX86::h_FADD_R(Instruction& instr, int i) {
  424. instr.dst %= RegisterCountFlt;
  425. instr.src %= RegisterCountFlt;
  426. asmCode << "\taddpd " << regF[instr.dst] << ", " << regA[instr.src] << std::endl;
  427. traceflt(instr);
  428. }
  429. void AssemblyGeneratorX86::h_FADD_M(Instruction& instr, int i) {
  430. instr.dst %= RegisterCountFlt;
  431. genAddressReg(instr);
  432. asmCode << "\tcvtdq2pd " << tempRegx << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  433. asmCode << "\taddpd " << regF[instr.dst] << ", " << tempRegx << std::endl;
  434. traceflt(instr);
  435. }
  436. void AssemblyGeneratorX86::h_FSUB_R(Instruction& instr, int i) {
  437. instr.dst %= RegisterCountFlt;
  438. instr.src %= RegisterCountFlt;
  439. asmCode << "\tsubpd " << regF[instr.dst] << ", " << regA[instr.src] << std::endl;
  440. traceflt(instr);
  441. }
  442. void AssemblyGeneratorX86::h_FSUB_M(Instruction& instr, int i) {
  443. instr.dst %= RegisterCountFlt;
  444. genAddressReg(instr);
  445. asmCode << "\tcvtdq2pd " << tempRegx << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  446. asmCode << "\tsubpd " << regF[instr.dst] << ", " << tempRegx << std::endl;
  447. traceflt(instr);
  448. }
  449. void AssemblyGeneratorX86::h_FSCAL_R(Instruction& instr, int i) {
  450. instr.dst %= RegisterCountFlt;
  451. asmCode << "\txorps " << regF[instr.dst] << ", " << scaleMask << std::endl;
  452. traceflt(instr);
  453. }
  454. void AssemblyGeneratorX86::h_FMUL_R(Instruction& instr, int i) {
  455. instr.dst %= RegisterCountFlt;
  456. instr.src %= RegisterCountFlt;
  457. asmCode << "\tmulpd " << regE[instr.dst] << ", " << regA[instr.src] << std::endl;
  458. traceflt(instr);
  459. }
  460. void AssemblyGeneratorX86::h_FDIV_M(Instruction& instr, int i) {
  461. instr.dst %= RegisterCountFlt;
  462. genAddressReg(instr);
  463. asmCode << "\tcvtdq2pd " << tempRegx << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
  464. asmCode << "\tandps " << tempRegx << ", " << mantissaMask << std::endl;
  465. asmCode << "\torps " << tempRegx << ", " << exponentMask << std::endl;
  466. asmCode << "\tdivpd " << regE[instr.dst] << ", " << tempRegx << std::endl;
  467. traceflt(instr);
  468. }
  469. void AssemblyGeneratorX86::h_FSQRT_R(Instruction& instr, int i) {
  470. instr.dst %= RegisterCountFlt;
  471. asmCode << "\tsqrtpd " << regE[instr.dst] << ", " << regE[instr.dst] << std::endl;
  472. traceflt(instr);
  473. }
  474. void AssemblyGeneratorX86::h_CFROUND(Instruction& instr, int i) {
  475. asmCode << "\tmov rax, " << regR[instr.src] << std::endl;
  476. int rotate = (13 - (instr.getImm32() & 63)) & 63;
  477. if (rotate != 0)
  478. asmCode << "\trol rax, " << rotate << std::endl;
  479. asmCode << "\tand eax, 24576" << std::endl;
  480. asmCode << "\tor eax, 40896" << std::endl;
  481. asmCode << "\tpush rax" << std::endl;
  482. asmCode << "\tldmxcsr dword ptr [rsp]" << std::endl;
  483. asmCode << "\tpop rax" << std::endl;
  484. tracenop(instr);
  485. }
  486. void AssemblyGeneratorX86::h_CBRANCH(Instruction& instr, int i) {
  487. int reg = getConditionRegister(registerUsage);
  488. int target = registerUsage[reg].lastUsed + 1;
  489. registerUsage[reg].count++;
  490. int shift = instr.getModCond();
  491. asmCode << "\tadd " << regR[reg] << ", " << (int32_t)(instr.getImm32() | (1 << shift)) << std::endl;
  492. asmCode << "\ttest " << regR[reg] << ", " << (ConditionMask << shift) << std::endl;
  493. asmCode << "\tjz randomx_isn_" << target << std::endl;
  494. //mark all registers as used
  495. for (unsigned j = 0; j < RegistersCount; ++j) {
  496. registerUsage[j].lastUsed = i;
  497. }
  498. }
  499. void AssemblyGeneratorX86::h_ISTORE(Instruction& instr, int i) {
  500. genAddressRegDst(instr);
  501. asmCode << "\tmov qword ptr [" << regScratchpadAddr << "+rax], " << regR[instr.src] << std::endl;
  502. tracenop(instr);
  503. }
  504. void AssemblyGeneratorX86::h_NOP(Instruction& instr, int i) {
  505. asmCode << "\tnop" << std::endl;
  506. tracenop(instr);
  507. }
  508. #include "instruction_weights.hpp"
  509. #define INST_HANDLE(x) REPN(&AssemblyGeneratorX86::h_##x, WT(x))
  510. InstructionGenerator AssemblyGeneratorX86::engine[256] = {
  511. INST_HANDLE(IADD_RS)
  512. INST_HANDLE(IADD_M)
  513. INST_HANDLE(ISUB_R)
  514. INST_HANDLE(ISUB_M)
  515. INST_HANDLE(IMUL_R)
  516. INST_HANDLE(IMUL_M)
  517. INST_HANDLE(IMULH_R)
  518. INST_HANDLE(IMULH_M)
  519. INST_HANDLE(ISMULH_R)
  520. INST_HANDLE(ISMULH_M)
  521. INST_HANDLE(IMUL_RCP)
  522. INST_HANDLE(INEG_R)
  523. INST_HANDLE(IXOR_R)
  524. INST_HANDLE(IXOR_M)
  525. INST_HANDLE(IROR_R)
  526. INST_HANDLE(IROL_R)
  527. INST_HANDLE(ISWAP_R)
  528. INST_HANDLE(FSWAP_R)
  529. INST_HANDLE(FADD_R)
  530. INST_HANDLE(FADD_M)
  531. INST_HANDLE(FSUB_R)
  532. INST_HANDLE(FSUB_M)
  533. INST_HANDLE(FSCAL_R)
  534. INST_HANDLE(FMUL_R)
  535. INST_HANDLE(FDIV_M)
  536. INST_HANDLE(FSQRT_R)
  537. INST_HANDLE(CBRANCH)
  538. INST_HANDLE(CFROUND)
  539. INST_HANDLE(ISTORE)
  540. INST_HANDLE(NOP)
  541. };
  542. }