RandomX v2 virtual machine changes

* CFROUND becomes conditional with a 1/16 chance of writing into fprc
    * F and E registers are mixed together with AES instead of XOR
This commit is contained in:
tevador
2023-09-08 23:26:17 +02:00
parent 1c603a23fa
commit 605217972e
11 changed files with 196 additions and 80 deletions
+125 -62
View File
@@ -193,6 +193,7 @@ namespace randomx {
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 JNZ_SHORT = 0x75;
static const uint8_t JMP = 0xe9;
static const uint8_t REX_XOR_RAX_R64[] = { 0x49, 0x33 };
static const uint8_t REX_XCHG[] = { 0x4d, 0x87 };
@@ -207,6 +208,7 @@ namespace randomx {
static const uint8_t LEA_32[] = { 0x41, 0x8d };
static const uint8_t MOVNTI[] = { 0x4c, 0x0f, 0xc3 };
static const uint8_t ADD_EBX_I[] = { 0x81, 0xc3 };
static const uint8_t TEST_EAX_60SL13[] = { 0xa9, 0x00, 0x80, 0x07, 0x00 };
static const uint8_t NOP1[] = { 0x90 };
static const uint8_t NOP2[] = { 0x66, 0x90 };
@@ -219,11 +221,13 @@ namespace randomx {
static const uint8_t* NOPX[] = { NOP1, NOP2, NOP3, NOP4, NOP5, NOP6, NOP7, NOP8 };
size_t JitCompilerX86::getCodeSize() {
template<randomx_flags vmFlags>
size_t JitCompilerX86<vmFlags>::getCodeSize() {
return CodeSize;
}
JitCompilerX86::JitCompilerX86() {
template<randomx_flags vmFlags>
JitCompilerX86<vmFlags>::JitCompilerX86() {
code = (uint8_t*)allocMemoryPages(CodeSize);
if (code == nullptr)
throw std::runtime_error("allocMemoryPages");
@@ -231,30 +235,36 @@ namespace randomx {
memcpy(code + epilogueOffset, codeEpilogue, epilogueSize);
}
JitCompilerX86::~JitCompilerX86() {
template<randomx_flags vmFlags>
JitCompilerX86<vmFlags>::~JitCompilerX86() {
freePagedMemory(code, CodeSize);
}
void JitCompilerX86::enableAll() {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::enableAll() {
setPagesRWX(code, CodeSize);
}
void JitCompilerX86::enableWriting() {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::enableWriting() {
setPagesRW(code, CodeSize);
}
void JitCompilerX86::enableExecution() {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::enableExecution() {
setPagesRX(code, CodeSize);
}
void JitCompilerX86::generateProgram(Program& prog, ProgramConfiguration& pcfg) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateProgram(Program& prog, ProgramConfiguration& pcfg) {
generateProgramPrologue(prog, pcfg);
memcpy(code + codePos, codeReadDataset, readDatasetSize);
codePos += readDatasetSize;
generateProgramEpilogue(prog, pcfg);
}
void JitCompilerX86::generateProgramLight(Program& prog, ProgramConfiguration& pcfg, uint32_t datasetOffset) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateProgramLight(Program& prog, ProgramConfiguration& pcfg, uint32_t datasetOffset) {
generateProgramPrologue(prog, pcfg);
emit(codeReadDatasetLightSshInit, readDatasetLightInitSize);
emit(ADD_EBX_I);
@@ -265,18 +275,18 @@ namespace randomx {
generateProgramEpilogue(prog, pcfg);
}
template<size_t N>
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[N], std::vector<uint64_t> &reciprocalCache) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateSuperscalarHash(SuperscalarProgramList &programs, std::vector<uint64_t> &reciprocalCache) {
memcpy(code + superScalarHashOffset, codeShhInit, codeSshInitSize);
codePos = superScalarHashOffset + codeSshInitSize;
for (unsigned j = 0; j < N; ++j) {
for (unsigned j = 0; j < programs.size(); ++j) {
SuperscalarProgram& prog = programs[j];
for (unsigned i = 0; i < prog.getSize(); ++i) {
Instruction& instr = prog(i);
generateSuperscalarCode(instr, reciprocalCache);
}
emit(codeShhLoad, codeSshLoadSize);
if (j < N - 1) {
if (j < programs.size() - 1) {
emit(REX_MOV_RR64);
emitByte(0xd8 + prog.getAddressRegister());
emit(codeShhPrefetch, codeSshPrefetchSize);
@@ -294,14 +304,13 @@ namespace randomx {
emitByte(RET);
}
template
void JitCompilerX86::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_ACCESSES], std::vector<uint64_t> &reciprocalCache);
void JitCompilerX86::generateDatasetInitCode() {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateDatasetInitCode() {
memcpy(code, codeDatasetInit, datasetInitSize);
}
void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) {
instructionOffsets.clear();
for (unsigned i = 0; i < RegistersCount; ++i) {
registerUsage[i] = -1;
@@ -323,7 +332,8 @@ namespace randomx {
emitByte(0xc0 + pcfg.readReg3);
}
void JitCompilerX86::generateProgramEpilogue(Program& prog, ProgramConfiguration& pcfg) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateProgramEpilogue(Program& prog, ProgramConfiguration& pcfg) {
emit(REX_MOV_RR64);
emitByte(0xc0 + pcfg.readReg0);
emit(REX_XOR_RAX_R64);
@@ -338,13 +348,15 @@ namespace randomx {
emit32(epilogueOffset - codePos - 4);
}
void JitCompilerX86::generateCode(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateCode(Instruction& instr, int i) {
instructionOffsets.push_back(codePos);
auto generator = engine[instr.opcode];
(this->*generator)(instr, i);
}
void JitCompilerX86::generateSuperscalarCode(Instruction& instr, std::vector<uint64_t> &reciprocalCache) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::generateSuperscalarCode(Instruction& instr, std::vector<uint64_t> &reciprocalCache) {
switch ((SuperscalarInstructionType)instr.opcode)
{
case randomx::SuperscalarInstructionType::ISUB_R:
@@ -438,7 +450,8 @@ namespace randomx {
}
}
void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::genAddressReg(Instruction& instr, bool rax) {
emit(LEA_32);
emitByte(0x80 + instr.src + (rax ? 0 : 8));
if (instr.src == RegisterNeedsSib) {
@@ -452,7 +465,8 @@ namespace randomx {
emit32(instr.getModMem() ? ScratchpadL1Mask : ScratchpadL2Mask);
}
void JitCompilerX86::genAddressRegDst(Instruction& instr) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::genAddressRegDst(Instruction& instr) {
emit(LEA_32);
emitByte(0x80 + instr.dst);
if (instr.dst == RegisterNeedsSib) {
@@ -468,11 +482,13 @@ namespace randomx {
}
}
void JitCompilerX86::genAddressImm(Instruction& instr) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::genAddressImm(Instruction& instr) {
emit32(instr.getImm32() & ScratchpadL3Mask);
}
void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IADD_RS(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_LEA);
if (instr.dst == RegisterNeedsDisplacement)
@@ -484,10 +500,11 @@ namespace randomx {
emit32(instr.getImm32());
}
void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IADD_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_ADD_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
@@ -499,11 +516,13 @@ namespace randomx {
}
}
void JitCompilerX86::genSIB(int scale, int index, int base) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::genSIB(int scale, int index, int base) {
emitByte((scale << 6) | (index << 3) | base);
}
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISUB_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_SUB_RR);
@@ -516,10 +535,11 @@ namespace randomx {
}
}
void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISUB_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_SUB_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
@@ -531,7 +551,8 @@ namespace randomx {
}
}
void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IMUL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_IMUL_RR);
@@ -544,10 +565,11 @@ namespace randomx {
}
}
void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IMUL_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_IMUL_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
@@ -559,7 +581,8 @@ namespace randomx {
}
}
void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst);
@@ -569,7 +592,8 @@ namespace randomx {
emitByte(0xc2 + 8 * instr.dst);
}
void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, false);
@@ -588,7 +612,8 @@ namespace randomx {
emitByte(0xc2 + 8 * instr.dst);
}
void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst);
@@ -598,7 +623,8 @@ namespace randomx {
emitByte(0xc2 + 8 * instr.dst);
}
void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr, false);
@@ -617,7 +643,8 @@ namespace randomx {
emitByte(0xc2 + 8 * instr.dst);
}
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IMUL_RCP(Instruction& instr, int i) {
uint64_t divisor = instr.getImm32();
if (!isZeroOrPowerOf2(divisor)) {
registerUsage[instr.dst] = i;
@@ -628,13 +655,15 @@ namespace randomx {
}
}
void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_INEG_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
emit(REX_NEG);
emitByte(0xd8 + instr.dst);
}
void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IXOR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_XOR_RR);
@@ -647,10 +676,11 @@ namespace randomx {
}
}
void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IXOR_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_XOR_RM);
emitByte(0x04 + 8 * instr.dst);
emitByte(0x06);
@@ -662,7 +692,8 @@ namespace randomx {
}
}
void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IROR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_MOV_RR);
@@ -677,7 +708,8 @@ namespace randomx {
}
}
void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_IROL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i;
if (instr.src != instr.dst) {
emit(REX_MOV_RR);
@@ -692,7 +724,8 @@ namespace randomx {
}
}
void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISWAP_R(Instruction& instr, int i) {
if (instr.src != instr.dst) {
registerUsage[instr.dst] = i;
registerUsage[instr.src] = i;
@@ -701,82 +734,107 @@ namespace randomx {
}
}
void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FSWAP_R(Instruction& instr, int i) {
emit(SHUFPD);
emitByte(0xc0 + 9 * instr.dst);
emitByte(1);
}
void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FADD_R(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
emit(REX_ADDPD);
emitByte(0xc0 + instr.src + 8 * instr.dst);
}
void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FADD_M(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_CVTDQ2PD_XMM12);
emit(REX_ADDPD);
emitByte(0xc4 + 8 * instr.dst);
}
void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FSUB_R(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
emit(REX_SUBPD);
emitByte(0xc0 + instr.src + 8 * instr.dst);
}
void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FSUB_M(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_CVTDQ2PD_XMM12);
emit(REX_SUBPD);
emitByte(0xc4 + 8 * instr.dst);
}
void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FSCAL_R(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
emit(REX_XORPS);
emitByte(0xc7 + 8 * instr.dst);
}
void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FMUL_R(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
instr.src %= RegisterCountFlt;
emit(REX_MULPD);
emitByte(0xe0 + instr.src + 8 * instr.dst);
}
void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FDIV_M(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
genAddressReg(instr);
genAddressReg(instr, true);
emit(REX_CVTDQ2PD_XMM12);
emit(REX_ANDPS_XMM12);
emit(REX_DIVPD);
emitByte(0xe4 + 8 * instr.dst);
}
void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_FSQRT_R(Instruction& instr, int i) {
instr.dst %= RegisterCountFlt;
emit(SQRTPD);
emitByte(0xe4 + 9 * instr.dst);
}
void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_CFROUND(Instruction& instr, int i) {
//mov rax {src}
emit(REX_MOV_RR64);
emitByte(0xc0 + instr.src);
int rotate = (13 - (instr.getImm32() & 63)) & 63;
if (rotate != 0) {
//rol rax, {imm32}
emit(ROL_RAX);
emitByte(rotate);
}
if (vmFlags & RANDOMX_FLAG_V2) {
//test eax, 491520
//jnz next
emit(TEST_EAX_60SL13);
emitByte(JNZ_SHORT);
emitByte(sizeof(AND_OR_MOV_LDMXCSR));
}
//and eax, 24576
//or eax, 40896
//push rax
//ldmxcsr dword ptr [rsp]
//pop rax
emit(AND_OR_MOV_LDMXCSR);
}
void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_CBRANCH(Instruction& instr, int i) {
int reg = instr.dst;
int target = registerUsage[reg] + 1;
emit(REX_ADD_I);
@@ -797,21 +855,24 @@ namespace randomx {
}
}
void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_ISTORE(Instruction& instr, int i) {
genAddressRegDst(instr);
emit(REX_MOV_MR);
emitByte(0x04 + 8 * instr.src);
emitByte(0x06);
}
void JitCompilerX86::h_NOP(Instruction& instr, int i) {
template<randomx_flags vmFlags>
void JitCompilerX86<vmFlags>::h_NOP(Instruction& instr, int i) {
emit(NOP1);
}
#include "instruction_weights.hpp"
#define INST_HANDLE(x) REPN(&JitCompilerX86::h_##x, WT(x))
InstructionGeneratorX86 JitCompilerX86::engine[256] = {
template<randomx_flags vmFlags>
InstructionGeneratorX86<vmFlags> JitCompilerX86<vmFlags>::engine[256] = {
INST_HANDLE(IADD_RS)
INST_HANDLE(IADD_M)
INST_HANDLE(ISUB_R)
@@ -844,4 +905,6 @@ namespace randomx {
INST_HANDLE(NOP)
};
template class JitCompilerX86<RANDOMX_FLAG_DEFAULT>;
template class JitCompilerX86<RANDOMX_FLAG_V2>;
}