RandomWOW/src/JitCompilerX86.cpp

806 lines
22 KiB
C++
Raw Normal View History

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 <cstring>
2019-03-17 22:09:11 +00:00
#include <climits>
2018-12-18 21:00:58 +00:00
#include <stdexcept>
2019-02-12 17:18:02 +00:00
#include "JitCompilerX86.hpp"
#include "Program.hpp"
#include "reciprocal.h"
2019-02-12 17:18:02 +00:00
#include "virtualMemory.hpp"
2018-12-18 21:00:58 +00:00
2019-03-17 22:09:11 +00:00
#define RANDOMX_JUMP
2018-12-18 21:00:58 +00:00
namespace RandomX {
#if !defined(_M_X64) && !defined(__x86_64__)
JitCompilerX86::JitCompilerX86() {
2019-02-12 17:18:02 +00:00
throw std::runtime_error("JIT compiler only supports x86-64 CPUs");
}
void JitCompilerX86::generateProgram(Program& p) {
}
2019-01-18 16:57:47 +00:00
2019-03-22 11:03:39 +00:00
void JitCompilerX86::generateProgramLight(Program& p) {
}
2019-01-18 16:57:47 +00:00
size_t JitCompilerX86::getCodeSize() {
return 0;
}
#else
2018-12-18 21:00:58 +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
; xmm13 -> mantissa mask = 0x000fffffffffffff000fffffffffffff
; xmm14 -> exponent 2**-240 = 0x30f000000000000030f0000000000000
; xmm15 -> scale mask = 0x81f000000000000081f0000000000000
2018-12-18 21:00:58 +00:00
*/
#include "JitCompilerX86-static.hpp"
2018-12-18 21:00:58 +00:00
const uint8_t* codePrologue = (uint8_t*)&randomx_program_prologue;
const uint8_t* codeLoopBegin = (uint8_t*)&randomx_program_loop_begin;
const uint8_t* codeLoopLoad = (uint8_t*)&randomx_program_loop_load;
const uint8_t* codeProgamStart = (uint8_t*)&randomx_program_start;
const uint8_t* codeReadDataset = (uint8_t*)&randomx_program_read_dataset;
2019-03-21 19:44:59 +00:00
const uint8_t* codeReadDatasetLight = (uint8_t*)&randomx_program_read_dataset_light;
const uint8_t* codeLoopStore = (uint8_t*)&randomx_program_loop_store;
const uint8_t* codeLoopEnd = (uint8_t*)&randomx_program_loop_end;
2019-03-21 19:44:59 +00:00
const uint8_t* codeReadDatasetLightSub = (uint8_t*)&randomx_program_read_dataset_light_sub;
const uint8_t* codeEpilogue = (uint8_t*)&randomx_program_epilogue;
const uint8_t* codeProgramEnd = (uint8_t*)&randomx_program_end;
2018-12-18 21:00:58 +00:00
const int32_t prologueSize = codeLoopBegin - codePrologue;
const int32_t epilogueSize = codeProgramEnd - codeEpilogue;
const int32_t loopLoadSize = codeProgamStart - codeLoopLoad;
2019-03-21 19:44:59 +00:00
const int32_t readDatasetSize = codeReadDatasetLight - codeReadDataset;
const int32_t readDatasetLightSize = codeLoopStore - codeReadDatasetLight;
const int32_t loopStoreSize = codeLoopEnd - codeLoopStore;
2019-03-21 19:44:59 +00:00
const int32_t readDatasetLightSubSize = codeEpilogue - codeReadDatasetLightSub;
const int32_t epilogueOffset = CodeSize - epilogueSize;
2019-03-21 19:44:59 +00:00
const int32_t readDatasetLightSubOffset = epilogueOffset - readDatasetLightSubSize;
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 };
static const uint8_t ADD_R_RAX[] = { 0x4C, 0x03 };
static const uint8_t XOR_EAX_EAX[] = { 0x33, 0xC0 };
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 };
static const uint8_t SETS_AL_ADD_RDX_RAX[] = { 0x0F, 0x98, 0xC0, 0x48, 0x03, 0xD0 };
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 };
static const uint8_t AND_OR_MOV_LDMXCSR[] = { 0x25, 0x00, 0x60, 0x00, 0x00, 0x0D, 0xC0, 0x9F, 0x00, 0x00, 0x89, 0x44, 0x24, 0xF8, 0x0F, 0xAE, 0x54, 0x24, 0xF8 };
static const uint8_t ROL_RAX[] = { 0x48, 0xc1, 0xc0 };
static const uint8_t XOR_ECX_ECX[] = { 0x33, 0xC9 };
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;
static const uint8_t REX_XOR_RAX_R64[] = { 0x49, 0x33 };
static const uint8_t REX_XCHG[] = { 0x4d, 0x87 };
static const uint8_t REX_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 };
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;
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 };
2018-12-18 21:00:58 +00:00
size_t JitCompilerX86::getCodeSize() {
return codePos - prologueSize;
}
2018-12-18 21:00:58 +00:00
JitCompilerX86::JitCompilerX86() {
2019-02-12 17:18:02 +00:00
code = (uint8_t*)allocExecutableMemory(CodeSize);
memcpy(code, codePrologue, prologueSize);
2019-03-21 19:44:59 +00:00
memcpy(code + epilogueOffset, codeEpilogue, epilogueSize);
memcpy(code + readDatasetLightSubOffset, codeReadDatasetLightSub, readDatasetLightSubSize);
2018-12-18 21:00:58 +00:00
}
void JitCompilerX86::generateProgram(Program& prog) {
2019-03-21 19:44:59 +00:00
generateProgramPrologue(prog);
memcpy(code + codePos, codeReadDataset, readDatasetSize);
codePos += readDatasetSize;
generateProgramEpilogue(prog);
}
void JitCompilerX86::generateProgramLight(Program& prog) {
generateProgramPrologue(prog);
memcpy(code + codePos, codeReadDatasetLight, readDatasetLightSize);
codePos += readDatasetLightSize;
emitByte(CALL);
emit32(readDatasetLightSubOffset - (codePos + 4));
generateProgramEpilogue(prog);
}
void JitCompilerX86::generateProgramPrologue(Program& prog) {
2019-03-17 22:09:11 +00:00
#ifdef RANDOMX_JUMP
instructionOffsets.clear();
for (unsigned i = 0; i < 8; ++i) {
registerUsage[i] = -1;
}
#endif
auto addressRegisters = prog.getEntropy(12);
uint32_t readReg0 = 0 + (addressRegisters & 1);
addressRegisters >>= 1;
uint32_t readReg1 = 2 + (addressRegisters & 1);
addressRegisters >>= 1;
uint32_t readReg2 = 4 + (addressRegisters & 1);
addressRegisters >>= 1;
uint32_t readReg3 = 6 + (addressRegisters & 1);
codePos = prologueSize;
emit(REX_XOR_RAX_R64);
emitByte(0xc0 + readReg0);
emit(REX_XOR_RAX_R64);
emitByte(0xc0 + readReg1);
memcpy(code + codePos, codeLoopLoad, loopLoadSize);
codePos += loopLoadSize;
for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
Instruction& instr = prog(i);
instr.src %= RegistersCount;
instr.dst %= RegistersCount;
2019-03-17 22:09:11 +00:00
generateCode(instr, i);
}
emit(REX_MOV_RR);
emitByte(0xc0 + readReg2);
emit(REX_XOR_EAX);
emitByte(0xc0 + readReg3);
2019-03-21 19:44:59 +00:00
}
void JitCompilerX86::generateProgramEpilogue(Program& prog) {
memcpy(code + codePos, codeLoopStore, loopStoreSize);
codePos += loopStoreSize;
emit(SUB_EBX);
emit(JNZ);
emit32(prologueSize - codePos - 4);
emitByte(JMP);
emit32(epilogueOffset - codePos - 4);
emitByte(0x90);
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::generateCode(Instruction& instr, int i) {
#ifdef RANDOMX_JUMP
instructionOffsets.push_back(codePos);
#endif
auto generator = engine[instr.opcode];
2019-03-17 22:09:11 +00:00
(this->*generator)(instr, i);
}
void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
emit(REX_MOV_RR);
emitByte((rax ? 0xc0 : 0xc8) + instr.src);
if (rax)
emitByte(AND_EAX_I);
else
emit(AND_ECX_I);
emit32((instr.mod % 4) ? ScratchpadL1Mask : ScratchpadL2Mask);
}
void JitCompilerX86::genAddressRegDst(Instruction& instr, bool align16 = false) {
emit(REX_MOV_RR);
emitByte(0xc0 + instr.dst);
emitByte(AND_EAX_I);
int32_t maskL1 = align16 ? ScratchpadL1Mask16 : ScratchpadL1Mask;
int32_t maskL2 = align16 ? ScratchpadL2Mask16 : ScratchpadL2Mask;
emit32((instr.mod % 4) ? maskL1 : maskL2);
}
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-03-17 22:09:11 +00:00
void JitCompilerX86::h_IADD_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_ADD_RR);
emitByte(0xc0 + 8 * instr.dst + instr.src);
2018-12-18 21:00:58 +00:00
}
else {
emit(REX_81);
emitByte(0xc0 + 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_IADD_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
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 {
emit(REX_ADD_RM);
emitByte(0x86 + 8 * instr.dst);
genAddressImm(instr);
2018-12-18 21:00:58 +00:00
}
}
void JitCompilerX86::genSIB(int scale, int index, int base) {
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_IADD_RC(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_LEA);
emitByte(0x84 + 8 * instr.dst);
genSIB(0, instr.src, instr.dst);
2019-03-11 22:04:34 +00:00
emit32(instr.getImm32());
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
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 {
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) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
emit(REX_SUB_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
}
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_9C(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_LEA);
emitByte(0x84 + 8 * instr.dst);
genSIB(3, instr.dst, 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_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
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 {
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) {
registerUsage[instr.dst] = i;
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 {
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) {
registerUsage[instr.dst] = i;
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) {
registerUsage[instr.dst] = i;
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 {
emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst);
emit(REX_MUL_M);
emitByte(0xa6);
genAddressImm(instr);
2018-12-18 21:00:58 +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) {
registerUsage[instr.dst] = i;
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) {
registerUsage[instr.dst] = i;
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-03-11 22:04:34 +00:00
if (instr.getImm32() != 0) {
2019-03-17 22:09:11 +00:00
registerUsage[instr.dst] = i;
emit(MOV_RAX_I);
2019-03-11 22:04:34 +00:00
emit64(reciprocal(instr.getImm32()));
emit(REX_IMUL_RM);
emitByte(0xc0 + 8 * instr.dst);
2018-12-18 21:00:58 +00:00
}
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_ISDIV_C(Instruction& instr, int i) {
2018-12-18 21:00:58 +00:00
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
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) {
registerUsage[instr.dst] = i;
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());
}
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) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
emit(REX_XOR_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
}
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) {
registerUsage[instr.dst] = i;
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);
}
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) {
registerUsage[instr.dst] = i;
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);
}
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) {
if (instr.src != instr.dst) {
2019-03-17 22:09:11 +00:00
registerUsage[instr.dst] = i;
registerUsage[instr.src] = i;
emit(REX_XCHG);
emitByte(0xc0 + instr.src + 8 * instr.dst);
}
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
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) {
instr.dst %= 4;
instr.src %= 4;
emit(REX_ADDPD);
emitByte(0xc0 + instr.src + 8 * instr.dst);
//emit(REX_PADD);
//emitByte(PADD_OPCODES[instr.mod % 4]);
//emitByte(0xf8 + 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) {
instr.dst %= 4;
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) {
instr.dst %= 4;
instr.src %= 4;
emit(REX_SUBPD);
emitByte(0xc0 + instr.src + 8 * instr.dst);
//emit(REX_PADD);
//emitByte(PADD_OPCODES[instr.mod % 4]);
//emitByte(0xf8 + 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) {
instr.dst %= 4;
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) {
instr.dst %= 4;
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) {
instr.dst %= 4;
instr.src %= 4;
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_FMUL_M(Instruction& instr, int i) {
instr.dst %= 4;
genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12);
emit(REX_ANDPS_XMM12);
emit(REX_MULPD);
emitByte(0xe4 + 8 * instr.dst);
emit(REX_MAXPD);
emitByte(0xe5 + 8 * instr.dst);
2018-12-18 21:00:58 +00:00
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_FDIV_R(Instruction& instr, int i) {
instr.dst %= 4;
instr.src %= 4;
emit(REX_DIVPD);
emitByte(0xe0 + instr.src + 8 * instr.dst);
emit(REX_MAXPD);
emitByte(0xe5 + 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) {
instr.dst %= 4;
genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12);
emit(REX_ANDPS_XMM12);
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) {
instr.dst %= 4;
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) {
emit(REX_MOV_RR64);
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) {
emit(ROL_RAX);
2019-01-11 09:52:12 +00:00
emitByte(rotate);
}
emit(AND_OR_MOV_LDMXCSR);
2018-12-18 21:00:58 +00:00
}
2019-03-17 22:09:11 +00:00
static inline uint8_t jumpCondition(Instruction& instr, bool invert = false) {
switch (((instr.mod >> 2) & 7) ^ invert)
{
case 0:
return 0x76; //jbe
case 1:
return 0x77; //ja
case 2:
return 0x78; //js
case 3:
return 0x79; //jns
case 4:
return 0x70; //jo
case 5:
return 0x71; //jno
case 6:
return 0x7c; //jl
case 7:
return 0x7d; //jge
}
}
static inline uint8_t condition(Instruction& instr) {
switch ((instr.mod >> 2) & 7)
2018-12-21 21:41:35 +00:00
{
case 0:
return 0x96; //setbe
2018-12-21 21:41:35 +00:00
case 1:
return 0x97; //seta
2018-12-21 21:41:35 +00:00
case 2:
return 0x98; //sets
2018-12-21 21:41:35 +00:00
case 3:
return 0x99; //setns
2018-12-21 21:41:35 +00:00
case 4:
return 0x90; //seto
2018-12-21 21:41:35 +00:00
case 5:
return 0x91; //setno
2018-12-21 21:41:35 +00:00
case 6:
return 0x9c; //setl
2018-12-21 21:41:35 +00:00
case 7:
return 0x9d; //setge
default:
UNREACHABLE;
2018-12-21 21:41:35 +00:00
}
}
2019-03-17 22:09:11 +00:00
int JitCompilerX86::getConditionRegister() {
int min = INT_MAX;
int minIndex;
for (unsigned i = 0; i < 8; ++i) {
if (registerUsage[i] < min) {
min = registerUsage[i];
minIndex = i;
}
}
return minIndex;
}
void JitCompilerX86::handleCondition(Instruction& instr, int i) {
const int shift = (instr.mod >> 5);
const int conditionMask = ((1 << RANDOMX_CONDITION_BITS) - 1) << shift;
int reg = getConditionRegister();
int target = registerUsage[reg] + 1;
emit(REX_ADD_I);
emitByte(0xc0 + reg);
emit32(1 << shift);
2019-03-17 22:09:11 +00:00
emit(REX_TEST);
emitByte(0xc0 + reg);
emit32(conditionMask);
emit(JZ);
emit32(instructionOffsets[target] - (codePos + 4));
for (unsigned j = 0; j < 8; ++j) { //mark all registers as used
registerUsage[j] = i;
}
}
void JitCompilerX86::h_COND_R(Instruction& instr, int i) {
#ifdef RANDOMX_JUMP
handleCondition(instr, i);
#endif
emit(XOR_ECX_ECX);
emit(REX_CMP_R32I);
emitByte(0xf8 + instr.src);
2019-03-11 22:04:34 +00:00
emit32(instr.getImm32());
emitByte(0x0f);
emitByte(condition(instr));
emitByte(0xc1);
emit(REX_ADD_RM);
emitByte(0xc1 + 8 * instr.dst);
2019-01-11 08:58:06 +00:00
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_COND_M(Instruction& instr, int i) {
#ifdef RANDOMX_JUMP
handleCondition(instr, i);
#endif
emit(XOR_ECX_ECX);
genAddressReg(instr);
emit(REX_CMP_M32I);
2019-03-11 22:04:34 +00:00
emit32(instr.getImm32());
emitByte(0x0f);
emitByte(condition(instr));
emitByte(0xc1);
emit(REX_ADD_RM);
emitByte(0xc1 + 8 * instr.dst);
2018-12-18 21:00:58 +00:00
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
genAddressRegDst(instr);
emit(REX_MOV_MR);
emitByte(0x04 + 8 * instr.src);
emitByte(0x06);
2018-12-18 21:00:58 +00:00
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_FSTORE(Instruction& instr, int i) {
genAddressRegDst(instr, true);
emit(MOVAPD);
emitByte(0x04 + 8 * instr.src);
emitByte(0x06);
}
2019-03-17 22:09:11 +00:00
void JitCompilerX86::h_NOP(Instruction& instr, int i) {
emitByte(0x90);
}
2018-12-18 21:00:58 +00:00
#include "instructionWeights.hpp"
#define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
InstructionGeneratorX86 JitCompilerX86::engine[256] = {
INST_HANDLE(IADD_R)
INST_HANDLE(IADD_M)
INST_HANDLE(IADD_RC)
INST_HANDLE(ISUB_R)
INST_HANDLE(ISUB_M)
INST_HANDLE(IMUL_9C)
INST_HANDLE(IMUL_R)
INST_HANDLE(IMUL_M)
INST_HANDLE(IMULH_R)
INST_HANDLE(IMULH_M)
INST_HANDLE(ISMULH_R)
INST_HANDLE(ISMULH_M)
INST_HANDLE(IMUL_RCP)
INST_HANDLE(INEG_R)
INST_HANDLE(IXOR_R)
INST_HANDLE(IXOR_M)
INST_HANDLE(IROR_R)
INST_HANDLE(IROL_R)
INST_HANDLE(ISWAP_R)
INST_HANDLE(FSWAP_R)
INST_HANDLE(FADD_R)
INST_HANDLE(FADD_M)
INST_HANDLE(FSUB_R)
INST_HANDLE(FSUB_M)
INST_HANDLE(FSCAL_R)
INST_HANDLE(FMUL_R)
INST_HANDLE(FDIV_M)
INST_HANDLE(FSQRT_R)
INST_HANDLE(COND_R)
INST_HANDLE(COND_M)
INST_HANDLE(CFROUND)
INST_HANDLE(ISTORE)
INST_HANDLE(NOP)
2018-12-18 21:00:58 +00:00
};
#endif
2018-12-18 21:00:58 +00:00
}