2018-12-18 21:00:58 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2018 tevador
|
|
|
|
|
|
|
|
This file is part of RandomX.
|
|
|
|
|
|
|
|
RandomX is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
RandomX is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdexcept>
|
2019-04-20 14:53:06 +00:00
|
|
|
#include "jit_compiler_x86.hpp"
|
2018-12-18 21:00:58 +00:00
|
|
|
|
2019-04-20 14:53:06 +00:00
|
|
|
#if !defined(_M_X64) && !defined(__x86_64__)
|
2019-04-20 09:08:01 +00:00
|
|
|
namespace randomx {
|
2018-12-18 21:00:58 +00:00
|
|
|
|
2018-12-31 18:06:45 +00:00
|
|
|
JitCompilerX86::JitCompilerX86() {
|
2019-02-12 17:18:02 +00:00
|
|
|
throw std::runtime_error("JIT compiler only supports x86-64 CPUs");
|
2018-12-31 18:06:45 +00:00
|
|
|
}
|
|
|
|
|
2019-04-21 14:22:02 +00:00
|
|
|
JitCompilerX86::~JitCompilerX86() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompilerX86::generateProgram(Program& p, ProgramConfiguration& pcfg) {
|
2018-12-31 18:06:45 +00:00
|
|
|
|
|
|
|
}
|
2019-01-18 16:57:47 +00:00
|
|
|
|
2019-04-26 19:05:41 +00:00
|
|
|
void JitCompilerX86::generateProgramLight(Program& p, ProgramConfiguration& pcfg, uint32_t datasetOffset) {
|
2019-04-21 14:22:02 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
template<size_t N>
|
|
|
|
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector<uint64_t> &reciprocalCache) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
template
|
|
|
|
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_ACCESSES], std::vector<uint64_t> &reciprocalCache);
|
|
|
|
|
|
|
|
void JitCompilerX86::generateDatasetInitCode() {
|
2019-03-22 11:03:39 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-18 16:57:47 +00:00
|
|
|
size_t JitCompilerX86::getCodeSize() {
|
|
|
|
return 0;
|
|
|
|
}
|
2019-04-20 14:53:06 +00:00
|
|
|
|
|
|
|
}
|
2018-12-31 18:06:45 +00:00
|
|
|
#else
|
|
|
|
|
2019-04-20 14:53:06 +00:00
|
|
|
#include <cstring>
|
|
|
|
#include <climits>
|
|
|
|
#include "jit_compiler_x86_static.hpp"
|
|
|
|
#include "superscalar.hpp"
|
|
|
|
#include "program.hpp"
|
|
|
|
#include "reciprocal.h"
|
|
|
|
#include "virtual_memory.hpp"
|
|
|
|
|
|
|
|
namespace randomx {
|
2018-12-18 21:00:58 +00:00
|
|
|
/*
|
2019-01-27 09:52:30 +00:00
|
|
|
|
|
|
|
REGISTER ALLOCATION:
|
|
|
|
|
|
|
|
; rax -> temporary
|
|
|
|
; rbx -> loop counter "lc"
|
|
|
|
; rcx -> temporary
|
|
|
|
; rdx -> temporary
|
|
|
|
; rsi -> scratchpad pointer
|
|
|
|
; rdi -> dataset pointer
|
|
|
|
; rbp -> memory registers "ma" (high 32 bits), "mx" (low 32 bits)
|
|
|
|
; rsp -> stack pointer
|
|
|
|
; r8 -> "r0"
|
|
|
|
; r9 -> "r1"
|
|
|
|
; r10 -> "r2"
|
|
|
|
; r11 -> "r3"
|
|
|
|
; r12 -> "r4"
|
|
|
|
; r13 -> "r5"
|
|
|
|
; r14 -> "r6"
|
|
|
|
; r15 -> "r7"
|
|
|
|
; xmm0 -> "f0"
|
|
|
|
; xmm1 -> "f1"
|
|
|
|
; xmm2 -> "f2"
|
|
|
|
; xmm3 -> "f3"
|
|
|
|
; xmm4 -> "e0"
|
|
|
|
; xmm5 -> "e1"
|
|
|
|
; xmm6 -> "e2"
|
|
|
|
; xmm7 -> "e3"
|
|
|
|
; xmm8 -> "a0"
|
|
|
|
; xmm9 -> "a1"
|
|
|
|
; xmm10 -> "a2"
|
|
|
|
; xmm11 -> "a3"
|
|
|
|
; xmm12 -> temporary
|
2019-02-24 16:24:06 +00:00
|
|
|
; xmm13 -> mantissa mask = 0x000fffffffffffff000fffffffffffff
|
2019-04-22 16:20:46 +00:00
|
|
|
; xmm14 -> exponent 2**-240 = 0x30f00000000xxxxx30f00000000xxxxx
|
2019-02-24 16:24:06 +00:00
|
|
|
; xmm15 -> scale mask = 0x81f000000000000081f0000000000000
|
2018-12-18 21:00:58 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2018-12-31 18:06:45 +00:00
|
|
|
const uint8_t* codePrologue = (uint8_t*)&randomx_program_prologue;
|
2019-01-27 18:33:55 +00:00
|
|
|
const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin;
|
|
|
|
const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load;
|
2019-01-27 09:52:30 +00:00
|
|
|
const uint8_t* codeProgamStart = (uint8_t*)&randomx_program_start;
|
|
|
|
const uint8_t* codeReadDataset = (uint8_t*)&randomx_program_read_dataset;
|
2019-04-07 13:38:51 +00:00
|
|
|
const uint8_t* codeReadDatasetLightSshInit = (uint8_t*)&randomx_program_read_dataset_sshash_init;
|
|
|
|
const uint8_t* codeReadDatasetLightSshFin = (uint8_t*)&randomx_program_read_dataset_sshash_fin;
|
2019-04-06 10:00:56 +00:00
|
|
|
const uint8_t* codeDatasetInit = (uint8_t*)&randomx_dataset_init;
|
2019-01-27 18:33:55 +00:00
|
|
|
const uint8_t* codeLoopStore = (uint8_t*)&randomx_program_loop_store;
|
2019-01-27 09:52:30 +00:00
|
|
|
const uint8_t* codeLoopEnd = (uint8_t*)&randomx_program_loop_end;
|
2018-12-31 18:06:45 +00:00
|
|
|
const uint8_t* codeEpilogue = (uint8_t*)&randomx_program_epilogue;
|
|
|
|
const uint8_t* codeProgramEnd = (uint8_t*)&randomx_program_end;
|
2019-04-06 10:00:56 +00:00
|
|
|
const uint8_t* codeShhLoad = (uint8_t*)&randomx_sshash_load;
|
|
|
|
const uint8_t* codeShhPrefetch = (uint8_t*)&randomx_sshash_prefetch;
|
|
|
|
const uint8_t* codeShhEnd = (uint8_t*)&randomx_sshash_end;
|
|
|
|
const uint8_t* codeShhInit = (uint8_t*)&randomx_sshash_init;
|
2018-12-18 21:00:58 +00:00
|
|
|
|
2019-01-27 09:52:30 +00:00
|
|
|
const int32_t prologueSize = codeLoopBegin - codePrologue;
|
2019-01-27 18:33:55 +00:00
|
|
|
const int32_t loopLoadSize = codeProgamStart - codeLoopLoad;
|
2019-04-28 14:42:45 +00:00
|
|
|
const int32_t readDatasetSize = codeReadDatasetLightSshInit - codeReadDataset;
|
2019-04-07 13:38:51 +00:00
|
|
|
const int32_t readDatasetLightInitSize = codeReadDatasetLightSshFin - codeReadDatasetLightSshInit;
|
|
|
|
const int32_t readDatasetLightFinSize = codeLoopStore - codeReadDatasetLightSshFin;
|
2019-01-27 18:33:55 +00:00
|
|
|
const int32_t loopStoreSize = codeLoopEnd - codeLoopStore;
|
2019-04-06 10:00:56 +00:00
|
|
|
const int32_t datasetInitSize = codeEpilogue - codeDatasetInit;
|
|
|
|
const int32_t epilogueSize = codeShhLoad - codeEpilogue;
|
|
|
|
const int32_t codeSshLoadSize = codeShhPrefetch - codeShhLoad;
|
|
|
|
const int32_t codeSshPrefetchSize = codeShhEnd - codeShhPrefetch;
|
|
|
|
const int32_t codeSshInitSize = codeProgramEnd - codeShhInit;
|
2019-01-27 09:52:30 +00:00
|
|
|
|
|
|
|
const int32_t epilogueOffset = CodeSize - epilogueSize;
|
2019-04-06 10:00:56 +00:00
|
|
|
constexpr int32_t superScalarHashOffset = 32768;
|
2019-01-27 09:52:30 +00:00
|
|
|
|
|
|
|
static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 };
|
|
|
|
static const uint8_t REX_ADD_RM[] = { 0x4c, 0x03 };
|
|
|
|
static const uint8_t REX_SUB_RR[] = { 0x4d, 0x2b };
|
|
|
|
static const uint8_t REX_SUB_RM[] = { 0x4c, 0x2b };
|
|
|
|
static const uint8_t REX_MOV_RR[] = { 0x41, 0x8b };
|
|
|
|
static const uint8_t REX_MOV_RR64[] = { 0x49, 0x8b };
|
|
|
|
static const uint8_t REX_MOV_R64R[] = { 0x4c, 0x8b };
|
|
|
|
static const uint8_t REX_IMUL_RR[] = { 0x4d, 0x0f, 0xaf };
|
|
|
|
static const uint8_t REX_IMUL_RRI[] = { 0x4d, 0x69 };
|
|
|
|
static const uint8_t REX_IMUL_RM[] = { 0x4c, 0x0f, 0xaf };
|
|
|
|
static const uint8_t REX_MUL_R[] = { 0x49, 0xf7 };
|
|
|
|
static const uint8_t REX_MUL_M[] = { 0x48, 0xf7 };
|
|
|
|
static const uint8_t REX_81[] = { 0x49, 0x81 };
|
|
|
|
static const uint8_t AND_EAX_I = 0x25;
|
|
|
|
static const uint8_t MOV_EAX_I = 0xb8;
|
|
|
|
static const uint8_t MOV_RAX_I[] = { 0x48, 0xb8 };
|
|
|
|
static const uint8_t MOV_RCX_I[] = { 0x48, 0xb9 };
|
|
|
|
static const uint8_t REX_LEA[] = { 0x4f, 0x8d };
|
|
|
|
static const uint8_t REX_MUL_MEM[] = { 0x48, 0xf7, 0x24, 0x0e };
|
|
|
|
static const uint8_t REX_IMUL_MEM[] = { 0x48, 0xf7, 0x2c, 0x0e };
|
|
|
|
static const uint8_t REX_SHR_RAX[] = { 0x48, 0xc1, 0xe8 };
|
|
|
|
static const uint8_t RAX_ADD_SBB_1[] = { 0x48, 0x83, 0xC0, 0x01, 0x48, 0x83, 0xD8, 0x00 };
|
|
|
|
static const uint8_t MUL_RCX[] = { 0x48, 0xf7, 0xe1 };
|
|
|
|
static const uint8_t REX_SHR_RDX[] = { 0x48, 0xc1, 0xea };
|
|
|
|
static const uint8_t REX_SH[] = { 0x49, 0xc1 };
|
|
|
|
static const uint8_t MOV_RCX_RAX_SAR_RCX_63[] = { 0x48, 0x89, 0xc1, 0x48, 0xc1, 0xf9, 0x3f };
|
|
|
|
static const uint8_t AND_ECX_I[] = { 0x81, 0xe1 };
|
|
|
|
static const uint8_t ADD_RAX_RCX[] = { 0x48, 0x01, 0xC8 };
|
|
|
|
static const uint8_t SAR_RAX_I8[] = { 0x48, 0xC1, 0xF8 };
|
|
|
|
static const uint8_t NEG_RAX[] = { 0x48, 0xF7, 0xD8 };
|
2019-02-15 15:43:52 +00:00
|
|
|
static const uint8_t ADD_R_RAX[] = { 0x4C, 0x03 };
|
|
|
|
static const uint8_t XOR_EAX_EAX[] = { 0x33, 0xC0 };
|
2019-01-27 09:52:30 +00:00
|
|
|
static const uint8_t ADD_RDX_R[] = { 0x4c, 0x01 };
|
|
|
|
static const uint8_t SUB_RDX_R[] = { 0x4c, 0x29 };
|
|
|
|
static const uint8_t SAR_RDX_I8[] = { 0x48, 0xC1, 0xFA };
|
|
|
|
static const uint8_t TEST_RDX_RDX[] = { 0x48, 0x85, 0xD2 };
|
2019-02-15 15:43:52 +00:00
|
|
|
static const uint8_t SETS_AL_ADD_RDX_RAX[] = { 0x0F, 0x98, 0xC0, 0x48, 0x03, 0xD0 };
|
2019-01-27 09:52:30 +00:00
|
|
|
static const uint8_t REX_NEG[] = { 0x49, 0xF7 };
|
|
|
|
static const uint8_t REX_XOR_RR[] = { 0x4D, 0x33 };
|
|
|
|
static const uint8_t REX_XOR_RI[] = { 0x49, 0x81 };
|
|
|
|
static const uint8_t REX_XOR_RM[] = { 0x4c, 0x33 };
|
|
|
|
static const uint8_t REX_ROT_CL[] = { 0x49, 0xd3 };
|
|
|
|
static const uint8_t REX_ROT_I8[] = { 0x49, 0xc1 };
|
|
|
|
static const uint8_t SHUFPD[] = { 0x66, 0x0f, 0xc6 };
|
|
|
|
static const uint8_t REX_ADDPD[] = { 0x66, 0x41, 0x0f, 0x58 };
|
|
|
|
static const uint8_t REX_CVTDQ2PD_XMM12[] = { 0xf3, 0x44, 0x0f, 0xe6, 0x24, 0x06 };
|
|
|
|
static const uint8_t REX_SUBPD[] = { 0x66, 0x41, 0x0f, 0x5c };
|
|
|
|
static const uint8_t REX_XORPS[] = { 0x41, 0x0f, 0x57 };
|
|
|
|
static const uint8_t REX_MULPD[] = { 0x66, 0x41, 0x0f, 0x59 };
|
|
|
|
static const uint8_t REX_MAXPD[] = { 0x66, 0x41, 0x0f, 0x5f };
|
|
|
|
static const uint8_t REX_DIVPD[] = { 0x66, 0x41, 0x0f, 0x5e };
|
|
|
|
static const uint8_t SQRTPD[] = { 0x66, 0x0f, 0x51 };
|
2019-04-26 21:32:10 +00:00
|
|
|
static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x50, 0x0F, 0xAE, 0x14, 0x24, 0x58 };
|
2019-01-27 09:52:30 +00:00
|
|
|
static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 };
|
2019-04-16 16:58:44 +00:00
|
|
|
static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 };
|
2019-01-27 09:52:30 +00:00
|
|
|
static const uint8_t REX_CMP_R32I[] = { 0x41, 0x81 };
|
|
|
|
static const uint8_t REX_CMP_M32I[] = { 0x81, 0x3c, 0x06 };
|
|
|
|
static const uint8_t MOVAPD[] = { 0x66, 0x0f, 0x29 };
|
|
|
|
static const uint8_t REX_MOV_MR[] = { 0x4c, 0x89 };
|
|
|
|
static const uint8_t REX_XOR_EAX[] = { 0x41, 0x33 };
|
|
|
|
static const uint8_t SUB_EBX[] = { 0x83, 0xEB, 0x01 };
|
|
|
|
static const uint8_t JNZ[] = { 0x0f, 0x85 };
|
|
|
|
static const uint8_t JMP = 0xe9;
|
2019-01-27 18:33:55 +00:00
|
|
|
static const uint8_t REX_XOR_RAX_R64[] = { 0x49, 0x33 };
|
2019-02-04 16:07:00 +00:00
|
|
|
static const uint8_t REX_XCHG[] = { 0x4d, 0x87 };
|
2019-02-24 16:24:06 +00:00
|
|
|
static const uint8_t REX_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 };
|
2019-02-07 15:11:27 +00:00
|
|
|
static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f };
|
|
|
|
static const uint8_t PADD_OPCODES[] = { 0xfc, 0xfd, 0xfe, 0xd4 };
|
2019-03-21 19:44:59 +00:00
|
|
|
static const uint8_t CALL = 0xe8;
|
2019-03-20 22:38:37 +00:00
|
|
|
static const uint8_t REX_ADD_I[] = { 0x49, 0x81 };
|
2019-03-17 22:09:11 +00:00
|
|
|
static const uint8_t REX_TEST[] = { 0x49, 0xF7 };
|
|
|
|
static const uint8_t JZ[] = { 0x0f, 0x84 };
|
2019-04-06 10:00:56 +00:00
|
|
|
static const uint8_t RET = 0xc3;
|
2019-04-14 15:21:26 +00:00
|
|
|
static const uint8_t LEA_32[] = { 0x67, 0x41, 0x8d };
|
2019-04-16 16:58:44 +00:00
|
|
|
static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 };
|
2019-04-26 14:05:30 +00:00
|
|
|
static const uint8_t ADD_EBX_I[] = { 0x81, 0xc3 };
|
2019-04-06 10:00:56 +00:00
|
|
|
|
|
|
|
static const uint8_t NOP1[] = { 0x90 };
|
|
|
|
static const uint8_t NOP2[] = { 0x66, 0x90 };
|
2019-04-07 13:38:51 +00:00
|
|
|
static const uint8_t NOP3[] = { 0x66, 0x66, 0x90 };
|
2019-04-06 10:00:56 +00:00
|
|
|
static const uint8_t NOP4[] = { 0x0F, 0x1F, 0x40, 0x00 };
|
|
|
|
static const uint8_t NOP5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
|
|
|
|
static const uint8_t NOP6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
|
|
|
|
static const uint8_t NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
static const uint8_t NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
|
|
|
|
static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 };
|
2018-12-18 21:00:58 +00:00
|
|
|
|
2019-01-12 15:05:09 +00:00
|
|
|
size_t JitCompilerX86::getCodeSize() {
|
2019-01-27 17:19:49 +00:00
|
|
|
return codePos - prologueSize;
|
2019-01-12 15:05:09 +00:00
|
|
|
}
|
|
|
|
|
2018-12-18 21:00:58 +00:00
|
|
|
JitCompilerX86::JitCompilerX86() {
|
2019-02-12 17:18:02 +00:00
|
|
|
code = (uint8_t*)allocExecutableMemory(CodeSize);
|
2018-12-31 18:06:45 +00:00
|
|
|
memcpy(code, codePrologue, prologueSize);
|
2019-03-21 19:44:59 +00:00
|
|
|
memcpy(code + epilogueOffset, codeEpilogue, epilogueSize);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-06 10:00:56 +00:00
|
|
|
JitCompilerX86::~JitCompilerX86() {
|
|
|
|
freePagedMemory(code, CodeSize);
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:18:02 +00:00
|
|
|
void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) {
|
|
|
|
generateProgramPrologue(prog, pcfg);
|
2019-03-21 19:44:59 +00:00
|
|
|
memcpy(code + codePos, codeReadDataset, readDatasetSize);
|
|
|
|
codePos += readDatasetSize;
|
|
|
|
generateProgramEpilogue(prog);
|
|
|
|
}
|
|
|
|
|
2019-04-26 14:05:30 +00:00
|
|
|
void JitCompilerX86::generateProgramLight(Program& prog, ProgramConfiguration& pcfg, uint32_t datasetOffset) {
|
2019-04-17 14:18:02 +00:00
|
|
|
generateProgramPrologue(prog, pcfg);
|
2019-04-21 14:22:02 +00:00
|
|
|
emit(codeReadDatasetLightSshInit, readDatasetLightInitSize);
|
2019-04-26 14:05:30 +00:00
|
|
|
emit(ADD_EBX_I);
|
|
|
|
emit32(datasetOffset / CacheLineSize);
|
2019-04-21 14:22:02 +00:00
|
|
|
emitByte(CALL);
|
|
|
|
emit32(superScalarHashOffset - (codePos + 4));
|
|
|
|
emit(codeReadDatasetLightSshFin, readDatasetLightFinSize);
|
2019-03-21 19:44:59 +00:00
|
|
|
generateProgramEpilogue(prog);
|
|
|
|
}
|
|
|
|
|
2019-04-06 10:00:56 +00:00
|
|
|
template<size_t N>
|
2019-04-20 09:08:01 +00:00
|
|
|
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector<uint64_t> &reciprocalCache) {
|
2019-04-06 10:00:56 +00:00
|
|
|
memcpy(code + superScalarHashOffset, codeShhInit, codeSshInitSize);
|
|
|
|
codePos = superScalarHashOffset + codeSshInitSize;
|
|
|
|
for (unsigned j = 0; j < N; ++j) {
|
2019-04-12 17:36:08 +00:00
|
|
|
SuperscalarProgram& prog = programs[j];
|
2019-04-06 10:00:56 +00:00
|
|
|
for (unsigned i = 0; i < prog.getSize(); ++i) {
|
|
|
|
Instruction& instr = prog(i);
|
2019-04-20 09:08:01 +00:00
|
|
|
generateSuperscalarCode(instr, reciprocalCache);
|
2019-04-06 10:00:56 +00:00
|
|
|
}
|
|
|
|
emit(codeShhLoad, codeSshLoadSize);
|
|
|
|
if (j < N - 1) {
|
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xd8 + prog.getAddressRegister());
|
|
|
|
emit(codeShhPrefetch, codeSshPrefetchSize);
|
2019-04-29 18:19:34 +00:00
|
|
|
#ifdef RANDOMX_ALIGN
|
2019-04-06 10:00:56 +00:00
|
|
|
int align = (codePos % 16);
|
|
|
|
while (align != 0) {
|
|
|
|
int nopSize = 16 - align;
|
|
|
|
if (nopSize > 8) nopSize = 8;
|
|
|
|
emit(NOPX[nopSize - 1], nopSize);
|
|
|
|
align = (codePos % 16);
|
|
|
|
}
|
2019-04-29 18:19:34 +00:00
|
|
|
#endif
|
2019-04-06 10:00:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
emitByte(RET);
|
|
|
|
}
|
|
|
|
|
|
|
|
template
|
2019-04-21 14:22:02 +00:00
|
|
|
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_ACCESSES], std::vector<uint64_t> &reciprocalCache);
|
2019-04-06 10:00:56 +00:00
|
|
|
|
|
|
|
void JitCompilerX86::generateDatasetInitCode() {
|
|
|
|
memcpy(code, codeDatasetInit, datasetInitSize);
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:18:02 +00:00
|
|
|
void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) {
|
2019-03-17 22:09:11 +00:00
|
|
|
instructionOffsets.clear();
|
|
|
|
for (unsigned i = 0; i < 8; ++i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[i].lastUsed = -1;
|
|
|
|
registerUsage[i].count = 0;
|
2019-03-17 22:09:11 +00:00
|
|
|
}
|
2018-12-31 18:06:45 +00:00
|
|
|
codePos = prologueSize;
|
2019-04-17 14:18:02 +00:00
|
|
|
memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask));
|
2019-01-27 18:33:55 +00:00
|
|
|
emit(REX_XOR_RAX_R64);
|
2019-04-17 14:18:02 +00:00
|
|
|
emitByte(0xc0 + pcfg.readReg0);
|
2019-01-27 18:33:55 +00:00
|
|
|
emit(REX_XOR_RAX_R64);
|
2019-04-17 14:18:02 +00:00
|
|
|
emitByte(0xc0 + pcfg.readReg1);
|
2019-01-27 18:33:55 +00:00
|
|
|
memcpy(code + codePos, codeLoopLoad, loopLoadSize);
|
|
|
|
codePos += loopLoadSize;
|
2019-04-20 09:08:01 +00:00
|
|
|
for (unsigned i = 0; i < prog.getSize(); ++i) {
|
|
|
|
Instruction& instr = prog(i);
|
|
|
|
instr.src %= RegistersCount;
|
|
|
|
instr.dst %= RegistersCount;
|
|
|
|
generateCode(instr, i);
|
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_MOV_RR);
|
2019-04-17 14:18:02 +00:00
|
|
|
emitByte(0xc0 + pcfg.readReg2);
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_XOR_EAX);
|
2019-04-17 14:18:02 +00:00
|
|
|
emitByte(0xc0 + pcfg.readReg3);
|
2019-03-21 19:44:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompilerX86::generateProgramEpilogue(Program& prog) {
|
2019-01-27 18:33:55 +00:00
|
|
|
memcpy(code + codePos, codeLoopStore, loopStoreSize);
|
|
|
|
codePos += loopStoreSize;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(SUB_EBX);
|
|
|
|
emit(JNZ);
|
|
|
|
emit32(prologueSize - codePos - 4);
|
|
|
|
emitByte(JMP);
|
|
|
|
emit32(epilogueOffset - codePos - 4);
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::generateCode(Instruction& instr, int i) {
|
|
|
|
instructionOffsets.push_back(codePos);
|
2019-01-11 15:53:52 +00:00
|
|
|
auto generator = engine[instr.opcode];
|
2019-03-17 22:09:11 +00:00
|
|
|
(this->*generator)(instr, i);
|
2019-01-11 15:53:52 +00:00
|
|
|
}
|
|
|
|
|
2019-04-20 09:08:01 +00:00
|
|
|
void JitCompilerX86::generateSuperscalarCode(Instruction& instr, std::vector<uint64_t> &reciprocalCache) {
|
2019-04-07 13:38:51 +00:00
|
|
|
switch (instr.opcode)
|
|
|
|
{
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::ISUB_R:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_SUB_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IXOR_R:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_XOR_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IADD_RS:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_LEA);
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
2019-05-01 12:46:51 +00:00
|
|
|
genSIB(instr.getModShift(), instr.src, instr.dst);
|
2019-04-07 13:38:51 +00:00
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IMUL_R:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_IMUL_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IROR_C:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_ROT_I8);
|
|
|
|
emitByte(0xc8 + instr.dst);
|
|
|
|
emitByte(instr.getImm32() & 63);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IADD_C7:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_81);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IXOR_C7:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_XOR_RI);
|
|
|
|
emitByte(0xf0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IADD_C8:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_81);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
2019-04-29 18:19:34 +00:00
|
|
|
#ifdef RANDOMX_ALIGN
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(NOP1);
|
2019-04-29 18:19:34 +00:00
|
|
|
#endif
|
2019-04-07 13:38:51 +00:00
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IXOR_C8:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_XOR_RI);
|
|
|
|
emitByte(0xf0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
2019-04-29 18:19:34 +00:00
|
|
|
#ifdef RANDOMX_ALIGN
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(NOP1);
|
2019-04-29 18:19:34 +00:00
|
|
|
#endif
|
2019-04-07 13:38:51 +00:00
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IADD_C9:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_81);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
2019-04-29 18:19:34 +00:00
|
|
|
#ifdef RANDOMX_ALIGN
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(NOP2);
|
2019-04-29 18:19:34 +00:00
|
|
|
#endif
|
2019-04-07 13:38:51 +00:00
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IXOR_C9:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_XOR_RI);
|
|
|
|
emitByte(0xf0 + instr.dst);
|
|
|
|
emit32(instr.getImm32());
|
2019-04-29 18:19:34 +00:00
|
|
|
#ifdef RANDOMX_ALIGN
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(NOP2);
|
2019-04-29 18:19:34 +00:00
|
|
|
#endif
|
2019-04-07 13:38:51 +00:00
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IMULH_R:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_R);
|
|
|
|
emitByte(0xe0 + instr.src);
|
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::ISMULH_R:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_R);
|
|
|
|
emitByte(0xe8 + instr.src);
|
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
|
|
|
break;
|
2019-04-20 09:08:01 +00:00
|
|
|
case randomx::SuperscalarInstructionType::IMUL_RCP:
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(MOV_RAX_I);
|
2019-04-20 09:08:01 +00:00
|
|
|
emit64(reciprocalCache[instr.getImm32()]);
|
2019-04-07 13:38:51 +00:00
|
|
|
emit(REX_IMUL_RM);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-27 09:52:30 +00:00
|
|
|
void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
|
2019-04-14 15:21:26 +00:00
|
|
|
emit(LEA_32);
|
|
|
|
emitByte(0x80 + instr.src + (rax ? 0 : 8));
|
|
|
|
if (instr.src == RegisterNeedsSib) {
|
|
|
|
emitByte(0x24);
|
|
|
|
}
|
|
|
|
emit32(instr.getImm32());
|
2019-01-27 09:52:30 +00:00
|
|
|
if (rax)
|
|
|
|
emitByte(AND_EAX_I);
|
|
|
|
else
|
|
|
|
emit(AND_ECX_I);
|
2019-04-16 16:58:44 +00:00
|
|
|
emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
|
2019-01-11 15:53:52 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 09:52:30 +00:00
|
|
|
void JitCompilerX86::genAddressRegDst(Instruction& instr, bool align16 = false) {
|
2019-04-14 15:21:26 +00:00
|
|
|
emit(LEA_32);
|
|
|
|
emitByte(0x80 + instr.dst);
|
|
|
|
if (instr.dst == RegisterNeedsSib) {
|
|
|
|
emitByte(0x24);
|
|
|
|
}
|
|
|
|
emit32(instr.getImm32());
|
2019-01-27 09:52:30 +00:00
|
|
|
emitByte(AND_EAX_I);
|
2019-04-29 21:38:23 +00:00
|
|
|
if (instr.getModCond() < StoreL3Condition) {
|
2019-04-16 16:58:44 +00:00
|
|
|
int32_t maskL1 = align16 ? ScratchpadL1Mask16 : ScratchpadL1Mask;
|
|
|
|
int32_t maskL2 = align16 ? ScratchpadL2Mask16 : ScratchpadL2Mask;
|
|
|
|
emit32(instr.getModMem() ? maskL1 : maskL2);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit32(ScratchpadL3Mask);
|
|
|
|
}
|
2019-01-11 15:53:52 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 09:52:30 +00:00
|
|
|
void JitCompilerX86::genAddressImm(Instruction& instr) {
|
2019-03-11 22:04:34 +00:00
|
|
|
emit32(instr.getImm32() & ScratchpadL3Mask);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-06 10:00:56 +00:00
|
|
|
void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-04-06 10:00:56 +00:00
|
|
|
emit(REX_LEA);
|
2019-04-14 15:21:26 +00:00
|
|
|
if (instr.dst == RegisterNeedsDisplacement)
|
2019-04-06 10:00:56 +00:00
|
|
|
emitByte(0xac);
|
|
|
|
else
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
2019-04-29 21:38:23 +00:00
|
|
|
genSIB(instr.getModShift(), instr.src, instr.dst);
|
2019-04-14 15:21:26 +00:00
|
|
|
if (instr.dst == RegisterNeedsDisplacement)
|
2019-04-06 10:00:56 +00:00
|
|
|
emit32(instr.getImm32());
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_ADD_RM);
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
|
|
|
emitByte(0x06);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_ADD_RM);
|
|
|
|
emitByte(0x86 + 8 * instr.dst);
|
|
|
|
genAddressImm(instr);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-27 09:52:30 +00:00
|
|
|
void JitCompilerX86::genSIB(int scale, int index, int base) {
|
2019-02-15 15:43:52 +00:00
|
|
|
emitByte((scale << 6) | (index << 3) | base);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
emit(REX_SUB_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
2019-01-10 21:04:55 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_81);
|
|
|
|
emitByte(0xe8 + instr.dst);
|
2019-03-11 22:04:34 +00:00
|
|
|
emit32(instr.getImm32());
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_SUB_RM);
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
|
|
|
emitByte(0x06);
|
2018-12-31 18:06:45 +00:00
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
else {
|
|
|
|
emit(REX_SUB_RM);
|
|
|
|
emitByte(0x86 + 8 * instr.dst);
|
|
|
|
genAddressImm(instr);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
emit(REX_IMUL_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_IMUL_RRI);
|
|
|
|
emitByte(0xc0 + 9 * instr.dst);
|
2019-03-11 22:04:34 +00:00
|
|
|
emit32(instr.getImm32());
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_IMUL_RM);
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
|
|
|
emitByte(0x06);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_IMUL_RM);
|
|
|
|
emitByte(0x86 + 8 * instr.dst);
|
|
|
|
genAddressImm(instr);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-02-09 14:45:26 +00:00
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_R);
|
|
|
|
emitByte(0xe0 + instr.src);
|
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr, false);
|
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_MEM);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_M);
|
|
|
|
emitByte(0xa6);
|
|
|
|
genAddressImm(instr);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-02-09 14:45:26 +00:00
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_R);
|
|
|
|
emitByte(0xe8 + instr.src);
|
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr, false);
|
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_IMUL_MEM);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit(REX_MOV_RR64);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
emit(REX_MUL_M);
|
|
|
|
emitByte(0xae);
|
|
|
|
genAddressImm(instr);
|
|
|
|
}
|
|
|
|
emit(REX_MOV_R64R);
|
|
|
|
emitByte(0xc2 + 8 * instr.dst);
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
|
2019-05-04 16:00:17 +00:00
|
|
|
uint64_t divisor = instr.getImm32();
|
|
|
|
if (!isPowerOf2(divisor)) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-02-22 16:48:26 +00:00
|
|
|
emit(MOV_RAX_I);
|
2019-05-04 17:40:25 +00:00
|
|
|
emit64(randomx_reciprocal_fast(divisor));
|
2019-02-22 16:48:26 +00:00
|
|
|
emit(REX_IMUL_RM);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
2019-01-11 15:53:52 +00:00
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_NEG);
|
|
|
|
emitByte(0xd8 + instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
emit(REX_XOR_RR);
|
|
|
|
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit(REX_XOR_RI);
|
|
|
|
emitByte(0xf0 + instr.dst);
|
2019-03-11 22:04:34 +00:00
|
|
|
emit32(instr.getImm32());
|
2019-01-27 09:52:30 +00:00
|
|
|
}
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_XOR_RM);
|
|
|
|
emitByte(0x04 + 8 * instr.dst);
|
|
|
|
emitByte(0x06);
|
2019-04-21 14:22:02 +00:00
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
else {
|
|
|
|
emit(REX_XOR_RM);
|
|
|
|
emitByte(0x86 + 8 * instr.dst);
|
|
|
|
genAddressImm(instr);
|
|
|
|
}
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
emit(REX_MOV_RR);
|
|
|
|
emitByte(0xc8 + instr.src);
|
|
|
|
emit(REX_ROT_CL);
|
|
|
|
emitByte(0xc8 + instr.dst);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit(REX_ROT_I8);
|
|
|
|
emitByte(0xc8 + instr.dst);
|
2019-03-11 22:04:34 +00:00
|
|
|
emitByte(instr.getImm32() & 63);
|
2019-01-27 09:52:30 +00:00
|
|
|
}
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
2019-01-27 09:52:30 +00:00
|
|
|
if (instr.src != instr.dst) {
|
|
|
|
emit(REX_MOV_RR);
|
|
|
|
emitByte(0xc8 + instr.src);
|
|
|
|
emit(REX_ROT_CL);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit(REX_ROT_I8);
|
|
|
|
emitByte(0xc0 + instr.dst);
|
2019-03-11 22:04:34 +00:00
|
|
|
emitByte(instr.getImm32() & 63);
|
2019-01-27 09:52:30 +00:00
|
|
|
}
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
|
2019-02-04 16:07:00 +00:00
|
|
|
if (instr.src != instr.dst) {
|
2019-04-30 08:20:28 +00:00
|
|
|
registerUsage[instr.dst].lastUsed = i;
|
|
|
|
registerUsage[instr.src].lastUsed = i;
|
2019-02-04 16:07:00 +00:00
|
|
|
emit(REX_XCHG);
|
2019-02-15 15:43:52 +00:00
|
|
|
emitByte(0xc0 + instr.src + 8 * instr.dst);
|
2019-02-04 16:07:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(SHUFPD);
|
|
|
|
emitByte(0xc0 + 9 * instr.dst);
|
|
|
|
emitByte(1);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
|
|
|
instr.src %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_ADDPD);
|
|
|
|
emitByte(0xc0 + instr.src + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_CVTDQ2PD_XMM12);
|
|
|
|
emit(REX_ADDPD);
|
|
|
|
emitByte(0xc4 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
|
|
|
instr.src %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_SUBPD);
|
|
|
|
emitByte(0xc0 + instr.src + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_CVTDQ2PD_XMM12);
|
|
|
|
emit(REX_SUBPD);
|
|
|
|
emitByte(0xc4 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_XORPS);
|
|
|
|
emitByte(0xc7 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
|
|
|
instr.src %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_MULPD);
|
|
|
|
emitByte(0xe0 + instr.src + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
genAddressReg(instr);
|
|
|
|
emit(REX_CVTDQ2PD_XMM12);
|
2019-02-05 22:43:57 +00:00
|
|
|
emit(REX_ANDPS_XMM12);
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_DIVPD);
|
|
|
|
emitByte(0xe4 + 8 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
instr.dst %= RegisterCountFlt;
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(SQRTPD);
|
|
|
|
emitByte(0xe4 + 9 * instr.dst);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(REX_MOV_RR64);
|
2019-04-21 14:22:02 +00:00
|
|
|
emitByte(0xc0 + instr.src);
|
2019-03-11 22:04:34 +00:00
|
|
|
int rotate = (13 - (instr.getImm32() & 63)) & 63;
|
2019-01-11 09:52:12 +00:00
|
|
|
if (rotate != 0) {
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(ROL_RAX);
|
2019-01-11 09:52:12 +00:00
|
|
|
emitByte(rotate);
|
|
|
|
}
|
2019-01-27 09:52:30 +00:00
|
|
|
emit(AND_OR_MOV_LDMXCSR);
|
2018-12-18 21:00:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-29 21:38:23 +00:00
|
|
|
void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) {
|
2019-04-30 08:20:28 +00:00
|
|
|
int reg = getConditionRegister(registerUsage);
|
|
|
|
int target = registerUsage[reg].lastUsed + 1;
|
|
|
|
registerUsage[reg].count++;
|
2019-04-22 16:20:46 +00:00
|
|
|
emit(REX_ADD_I);
|
|
|
|
emitByte(0xc0 + reg);
|
2019-05-03 12:02:40 +00:00
|
|
|
int shift = instr.getModCond() + ConditionOffset;
|
|
|
|
uint32_t imm = instr.getImm32() | (1UL << shift);
|
|
|
|
if (ConditionOffset > 0 || shift > 0)
|
|
|
|
imm &= ~(1UL << (shift - 1));
|
|
|
|
emit32(imm);
|
2019-04-22 16:20:46 +00:00
|
|
|
emit(REX_TEST);
|
|
|
|
emitByte(0xc0 + reg);
|
2019-04-29 21:38:23 +00:00
|
|
|
emit32(ConditionMask << shift);
|
2019-04-22 16:20:46 +00:00
|
|
|
emit(JZ);
|
|
|
|
emit32(instructionOffsets[target] - (codePos + 4));
|
2019-04-30 08:20:28 +00:00
|
|
|
//mark all registers as used
|
|
|
|
for (unsigned j = 0; j < RegistersCount; ++j) {
|
|
|
|
registerUsage[j].lastUsed = i;
|
2019-03-17 22:09:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
|
2019-01-27 09:52:30 +00:00
|
|
|
genAddressRegDst(instr);
|
2019-04-21 14:22:02 +00:00
|
|
|
emit(REX_MOV_MR);
|
2019-01-27 09:52:30 +00:00
|
|
|
emitByte(0x04 + 8 * instr.src);
|
|
|
|
emitByte(0x06);
|
2019-01-12 15:05:09 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 22:09:11 +00:00
|
|
|
void JitCompilerX86::h_NOP(Instruction& instr, int i) {
|
2019-04-28 14:42:45 +00:00
|
|
|
emit(NOP1);
|
2019-01-27 17:19:49 +00:00
|
|
|
}
|
|
|
|
|
2019-04-20 14:53:06 +00:00
|
|
|
#include "instruction_weights.hpp"
|
2018-12-18 21:00:58 +00:00
|
|
|
#define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
|
|
|
|
|
|
|
|
InstructionGeneratorX86 JitCompilerX86::engine[256] = {
|
2019-04-06 10:00:56 +00:00
|
|
|
INST_HANDLE(IADD_RS)
|
2019-01-27 09:52:30 +00:00
|
|
|
INST_HANDLE(IADD_M)
|
|
|
|
INST_HANDLE(ISUB_R)
|
|
|
|
INST_HANDLE(ISUB_M)
|
|
|
|
INST_HANDLE(IMUL_R)
|
|
|
|
INST_HANDLE(IMUL_M)
|
|
|
|
INST_HANDLE(IMULH_R)
|
|
|
|
INST_HANDLE(IMULH_M)
|
|
|
|
INST_HANDLE(ISMULH_R)
|
|
|
|
INST_HANDLE(ISMULH_M)
|
2019-02-22 16:48:26 +00:00
|
|
|
INST_HANDLE(IMUL_RCP)
|
2019-01-27 09:52:30 +00:00
|
|
|
INST_HANDLE(INEG_R)
|
|
|
|
INST_HANDLE(IXOR_R)
|
|
|
|
INST_HANDLE(IXOR_M)
|
|
|
|
INST_HANDLE(IROR_R)
|
|
|
|
INST_HANDLE(IROL_R)
|
2019-02-04 16:07:00 +00:00
|
|
|
INST_HANDLE(ISWAP_R)
|
2019-02-05 22:43:57 +00:00
|
|
|
INST_HANDLE(FSWAP_R)
|
|
|
|
INST_HANDLE(FADD_R)
|
|
|
|
INST_HANDLE(FADD_M)
|
|
|
|
INST_HANDLE(FSUB_R)
|
|
|
|
INST_HANDLE(FSUB_M)
|
2019-02-12 23:01:34 +00:00
|
|
|
INST_HANDLE(FSCAL_R)
|
2019-02-05 22:43:57 +00:00
|
|
|
INST_HANDLE(FMUL_R)
|
|
|
|
INST_HANDLE(FDIV_M)
|
|
|
|
INST_HANDLE(FSQRT_R)
|
2019-04-29 21:38:23 +00:00
|
|
|
INST_HANDLE(CBRANCH)
|
2019-01-27 09:52:30 +00:00
|
|
|
INST_HANDLE(CFROUND)
|
|
|
|
INST_HANDLE(ISTORE)
|
2019-01-27 17:19:49 +00:00
|
|
|
INST_HANDLE(NOP)
|
2018-12-18 21:00:58 +00:00
|
|
|
};
|
2018-12-31 18:06:45 +00:00
|
|
|
|
2019-04-21 14:22:02 +00:00
|
|
|
}
|
2018-12-31 18:06:45 +00:00
|
|
|
#endif
|