mirror of
https://github.com/wownero/RandomWOW.git
synced 2026-10-17 23:41:36 +02:00
SuperscalarHash JIT compiler
(unfinished)
This commit is contained in:
+158
-18
@@ -88,29 +88,40 @@ namespace RandomX {
|
||||
|
||||
#include "JitCompilerX86-static.hpp"
|
||||
|
||||
#define NOP_TEST true
|
||||
|
||||
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;
|
||||
const uint8_t* codeReadDatasetLight = (uint8_t*)&randomx_program_read_dataset_light;
|
||||
const uint8_t* codeDatasetInit = (uint8_t*)&randomx_dataset_init;
|
||||
const uint8_t* codeLoopStore = (uint8_t*)&randomx_program_loop_store;
|
||||
const uint8_t* codeLoopEnd = (uint8_t*)&randomx_program_loop_end;
|
||||
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;
|
||||
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;
|
||||
|
||||
const int32_t prologueSize = codeLoopBegin - codePrologue;
|
||||
const int32_t epilogueSize = codeProgramEnd - codeEpilogue;
|
||||
|
||||
const int32_t loopLoadSize = codeProgamStart - codeLoopLoad;
|
||||
const int32_t readDatasetSize = codeReadDatasetLight - codeReadDataset;
|
||||
const int32_t readDatasetLightSize = codeLoopStore - codeReadDatasetLight;
|
||||
const int32_t loopStoreSize = codeLoopEnd - codeLoopStore;
|
||||
const int32_t readDatasetLightSubSize = codeEpilogue - codeReadDatasetLightSub;
|
||||
const int32_t readDatasetLightSubSize = codeDatasetInit - codeReadDatasetLightSub;
|
||||
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;
|
||||
|
||||
const int32_t epilogueOffset = CodeSize - epilogueSize;
|
||||
const int32_t readDatasetLightSubOffset = epilogueOffset - readDatasetLightSubSize;
|
||||
constexpr int32_t superScalarHashOffset = 32768;
|
||||
|
||||
static const uint8_t REX_ADD_RR[] = { 0x4d, 0x03 };
|
||||
static const uint8_t REX_ADD_RM[] = { 0x4c, 0x03 };
|
||||
@@ -166,7 +177,7 @@ namespace RandomX {
|
||||
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 XOR_RCX_RCX[] = { 0x48, 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 };
|
||||
@@ -184,6 +195,18 @@ namespace RandomX {
|
||||
static const uint8_t REX_ADD_I[] = { 0x49, 0x81 };
|
||||
static const uint8_t REX_TEST[] = { 0x49, 0xF7 };
|
||||
static const uint8_t JZ[] = { 0x0f, 0x84 };
|
||||
static const uint8_t RET = 0xc3;
|
||||
|
||||
static const uint8_t NOP1[] = { 0x90 };
|
||||
static const uint8_t NOP2[] = { 0x66, 0x90 };
|
||||
static const uint8_t NOP3[] = { 0x0F, 0x1F, 0x00 };
|
||||
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 };
|
||||
|
||||
size_t JitCompilerX86::getCodeSize() {
|
||||
return codePos - prologueSize;
|
||||
@@ -196,6 +219,10 @@ namespace RandomX {
|
||||
memcpy(code + readDatasetLightSubOffset, codeReadDatasetLightSub, readDatasetLightSubSize);
|
||||
}
|
||||
|
||||
JitCompilerX86::~JitCompilerX86() {
|
||||
freePagedMemory(code, CodeSize);
|
||||
}
|
||||
|
||||
void JitCompilerX86::generateProgram(Program& prog) {
|
||||
generateProgramPrologue(prog);
|
||||
memcpy(code + codePos, codeReadDataset, readDatasetSize);
|
||||
@@ -216,6 +243,42 @@ namespace RandomX {
|
||||
generateProgramEpilogue(prog);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
void JitCompilerX86::generateSuperScalarHash(LightProgram(&programs)[N]) {
|
||||
memcpy(code + superScalarHashOffset, codeShhInit, codeSshInitSize);
|
||||
codePos = superScalarHashOffset + codeSshInitSize;
|
||||
for (unsigned j = 0; j < N; ++j) {
|
||||
LightProgram& prog = programs[j];
|
||||
for (unsigned i = 0; i < prog.getSize(); ++i) {
|
||||
Instruction& instr = prog(i);
|
||||
instr.src %= RegistersCount;
|
||||
instr.dst %= RegistersCount;
|
||||
generateCode(instr, i);
|
||||
}
|
||||
emit(codeShhLoad, codeSshLoadSize);
|
||||
if (j < N - 1) {
|
||||
emit(REX_MOV_RR64);
|
||||
emitByte(0xd8 + prog.getAddressRegister());
|
||||
emit(codeShhPrefetch, codeSshPrefetchSize);
|
||||
int align = (codePos % 16);
|
||||
while (align != 0) {
|
||||
int nopSize = 16 - align;
|
||||
if (nopSize > 8) nopSize = 8;
|
||||
emit(NOPX[nopSize - 1], nopSize);
|
||||
align = (codePos % 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
emitByte(RET);
|
||||
}
|
||||
|
||||
template
|
||||
void JitCompilerX86::generateSuperScalarHash(LightProgram(&programs)[RANDOMX_CACHE_ACCESSES]);
|
||||
|
||||
void JitCompilerX86::generateDatasetInitCode() {
|
||||
memcpy(code, codeDatasetInit, datasetInitSize);
|
||||
}
|
||||
|
||||
void JitCompilerX86::generateProgramPrologue(Program& prog) {
|
||||
#ifdef RANDOMX_JUMP
|
||||
instructionOffsets.clear();
|
||||
@@ -253,7 +316,6 @@ namespace RandomX {
|
||||
emit32(prologueSize - codePos - 4);
|
||||
emitByte(JMP);
|
||||
emit32(epilogueOffset - codePos - 4);
|
||||
emitByte(0x90);
|
||||
}
|
||||
|
||||
void JitCompilerX86::generateCode(Instruction& instr, int i) {
|
||||
@@ -287,9 +349,9 @@ namespace RandomX {
|
||||
emit32(instr.getImm32() & ScratchpadL3Mask);
|
||||
}
|
||||
|
||||
void JitCompilerX86::h_IADD_R(Instruction& instr, int i) {
|
||||
void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (instr.src != instr.dst) {
|
||||
/*if (instr.src != instr.dst) {
|
||||
emit(REX_ADD_RR);
|
||||
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
||||
}
|
||||
@@ -297,7 +359,19 @@ namespace RandomX {
|
||||
emit(REX_81);
|
||||
emitByte(0xc0 + instr.dst);
|
||||
emit32(instr.getImm32());
|
||||
}*/
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP4);
|
||||
return;
|
||||
}
|
||||
emit(REX_LEA);
|
||||
if (instr.dst == 5) //rbp,r13 cannot be the base register without offset
|
||||
emitByte(0xac);
|
||||
else
|
||||
emitByte(0x04 + 8 * instr.dst);
|
||||
genSIB(instr.mod % 4, instr.src, instr.dst);
|
||||
if (instr.dst == 5)
|
||||
emit32(instr.getImm32());
|
||||
}
|
||||
|
||||
void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
|
||||
@@ -330,10 +404,18 @@ namespace RandomX {
|
||||
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (instr.src != instr.dst) {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(REX_SUB_RR);
|
||||
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
||||
}
|
||||
else {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP7);
|
||||
return;
|
||||
}
|
||||
emit(REX_81);
|
||||
emitByte(0xe8 + instr.dst);
|
||||
emit32(instr.getImm32());
|
||||
@@ -366,10 +448,18 @@ namespace RandomX {
|
||||
void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (instr.src != instr.dst) {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP4);
|
||||
return;
|
||||
}
|
||||
emit(REX_IMUL_RR);
|
||||
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
||||
}
|
||||
else {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP7);
|
||||
return;
|
||||
}
|
||||
emit(REX_IMUL_RRI);
|
||||
emitByte(0xc0 + 9 * instr.dst);
|
||||
emit32(instr.getImm32());
|
||||
@@ -393,6 +483,12 @@ namespace RandomX {
|
||||
|
||||
void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(REX_MOV_RR64);
|
||||
emitByte(0xc0 + instr.dst);
|
||||
emit(REX_MUL_R);
|
||||
@@ -422,6 +518,12 @@ namespace RandomX {
|
||||
|
||||
void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(REX_MOV_RR64);
|
||||
emitByte(0xc0 + instr.dst);
|
||||
emit(REX_MUL_R);
|
||||
@@ -451,6 +553,13 @@ namespace RandomX {
|
||||
|
||||
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
|
||||
if (instr.getImm32() != 0) {
|
||||
if (false && NOP_TEST) {
|
||||
emitByte(0x66);
|
||||
emitByte(0x66);
|
||||
emit(NOP8);
|
||||
emit(NOP4);
|
||||
return;
|
||||
}
|
||||
registerUsage[instr.dst] = i;
|
||||
emit(MOV_RAX_I);
|
||||
emit64(reciprocal(instr.getImm32()));
|
||||
@@ -472,10 +581,18 @@ namespace RandomX {
|
||||
void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (instr.src != instr.dst) {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(REX_XOR_RR);
|
||||
emitByte(0xc0 + 8 * instr.dst + instr.src);
|
||||
}
|
||||
else {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP7);
|
||||
return;
|
||||
}
|
||||
emit(REX_XOR_RI);
|
||||
emitByte(0xf0 + instr.dst);
|
||||
emit32(instr.getImm32());
|
||||
@@ -500,12 +617,21 @@ namespace RandomX {
|
||||
void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
|
||||
registerUsage[instr.dst] = i;
|
||||
if (instr.src != instr.dst) {
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(REX_MOV_RR);
|
||||
emitByte(0xc8 + instr.src);
|
||||
emit(REX_ROT_CL);
|
||||
emitByte(0xc8 + instr.dst);
|
||||
}
|
||||
else {
|
||||
if (NOP_TEST) {
|
||||
emit(NOP4);
|
||||
return;
|
||||
}
|
||||
emit(REX_ROT_I8);
|
||||
emitByte(0xc8 + instr.dst);
|
||||
emitByte(instr.getImm32() & 63);
|
||||
@@ -700,14 +826,21 @@ namespace RandomX {
|
||||
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);
|
||||
emit(REX_TEST);
|
||||
emitByte(0xc0 + reg);
|
||||
emit32(conditionMask);
|
||||
emit(JZ);
|
||||
emit32(instructionOffsets[target] - (codePos + 4));
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP7);
|
||||
emit(NOP7);
|
||||
emit(NOP6);
|
||||
}
|
||||
else {
|
||||
emit(REX_ADD_I);
|
||||
emitByte(0xc0 + reg);
|
||||
emit32(1 << shift);
|
||||
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;
|
||||
}
|
||||
@@ -717,7 +850,14 @@ namespace RandomX {
|
||||
#ifdef RANDOMX_JUMP
|
||||
handleCondition(instr, i);
|
||||
#endif
|
||||
emit(XOR_ECX_ECX);
|
||||
if (false && NOP_TEST) {
|
||||
emit(NOP3);
|
||||
emit(NOP7);
|
||||
emit(NOP3);
|
||||
emit(NOP3);
|
||||
return;
|
||||
}
|
||||
emit(XOR_RCX_RCX);
|
||||
emit(REX_CMP_R32I);
|
||||
emitByte(0xf8 + instr.src);
|
||||
emit32(instr.getImm32());
|
||||
@@ -732,7 +872,7 @@ namespace RandomX {
|
||||
#ifdef RANDOMX_JUMP
|
||||
handleCondition(instr, i);
|
||||
#endif
|
||||
emit(XOR_ECX_ECX);
|
||||
emit(XOR_RCX_RCX);
|
||||
genAddressReg(instr);
|
||||
emit(REX_CMP_M32I);
|
||||
emit32(instr.getImm32());
|
||||
@@ -765,7 +905,7 @@ namespace RandomX {
|
||||
#define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
|
||||
|
||||
InstructionGeneratorX86 JitCompilerX86::engine[256] = {
|
||||
INST_HANDLE(IADD_R)
|
||||
INST_HANDLE(IADD_RS)
|
||||
INST_HANDLE(IADD_M)
|
||||
INST_HANDLE(IADD_RC)
|
||||
INST_HANDLE(ISUB_R)
|
||||
|
||||
Reference in New Issue
Block a user