Fixed biased condition register selection

This commit is contained in:
tevador 2019-04-30 10:20:28 +02:00
parent 5543fb5f2f
commit 3cf6a30076
8 changed files with 107 additions and 116 deletions

View File

@ -95,8 +95,8 @@ randomx_isn_23:
mulpd xmm6, xmm8 mulpd xmm6, xmm8
randomx_isn_24: randomx_isn_24:
; CBRANCH 149087159, COND 13 ; CBRANCH 149087159, COND 13
add r8, 149087159 add r10, 149087159
test r8, 1040384 test r10, 1040384
jz randomx_isn_21 jz randomx_isn_21
randomx_isn_25: randomx_isn_25:
; FADD_R f3, a0 ; FADD_R f3, a0
@ -197,8 +197,8 @@ randomx_isn_53:
subpd xmm2, xmm8 subpd xmm2, xmm8
randomx_isn_54: randomx_isn_54:
; CBRANCH 1917049931, COND 12 ; CBRANCH 1917049931, COND 12
add r8, 1917049931 add r11, 1917049931
test r8, 520192 test r11, 520192
jz randomx_isn_52 jz randomx_isn_52
randomx_isn_55: randomx_isn_55:
; IXOR_R r2, r3 ; IXOR_R r2, r3
@ -329,8 +329,8 @@ randomx_isn_88:
imul r9, r11 imul r9, r11
randomx_isn_89: randomx_isn_89:
; CBRANCH -122257389, COND 13 ; CBRANCH -122257389, COND 13
add r8, -122249197 add r13, -122249197
test r8, 1040384 test r13, 1040384
jz randomx_isn_75 jz randomx_isn_75
randomx_isn_90: randomx_isn_90:
; ISTORE L1[r5+228116180], r7 ; ISTORE L1[r5+228116180], r7

View File

@ -45,7 +45,8 @@ namespace randomx {
void AssemblyGeneratorX86::generateProgram(Program& prog) { void AssemblyGeneratorX86::generateProgram(Program& prog) {
for (unsigned i = 0; i < RegistersCount; ++i) { for (unsigned i = 0; i < RegistersCount; ++i) {
registerUsage[i] = -1; registerUsage[i].lastUsed = -1;
registerUsage[i].count = 0;
} }
asmCode.str(std::string()); //clear asmCode.str(std::string()); //clear
for (unsigned i = 0; i < prog.getSize(); ++i) { for (unsigned i = 0; i < prog.getSize(); ++i) {
@ -215,18 +216,6 @@ namespace randomx {
asmCode << "}" << std::endl; asmCode << "}" << std::endl;
} }
int AssemblyGeneratorX86::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 AssemblyGeneratorX86::traceint(Instruction& instr) { void AssemblyGeneratorX86::traceint(Instruction& instr) {
if (trace) { if (trace) {
asmCode << "\tpush " << regR[instr.dst] << std::endl; asmCode << "\tpush " << regR[instr.dst] << std::endl;
@ -273,7 +262,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IADD_RS(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IADD_RS(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if(instr.dst == RegisterNeedsDisplacement) if(instr.dst == RegisterNeedsDisplacement)
asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << "*" << (1 << (instr.getModShift())) << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl; asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << "*" << (1 << (instr.getModShift())) << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
else else
@ -282,7 +271,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IADD_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IADD_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
asmCode << "\tadd " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl; asmCode << "\tadd " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
@ -294,7 +283,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_ISUB_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_ISUB_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
asmCode << "\tsub " << regR[instr.dst] << ", " << regR[instr.src] << std::endl; asmCode << "\tsub " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
} }
@ -305,7 +294,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_ISUB_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_ISUB_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
asmCode << "\tsub " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl; asmCode << "\tsub " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
@ -317,7 +306,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IMUL_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IMUL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
asmCode << "\timul " << regR[instr.dst] << ", " << regR[instr.src] << std::endl; asmCode << "\timul " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
} }
@ -328,7 +317,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IMUL_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IMUL_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
asmCode << "\timul " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl; asmCode << "\timul " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
@ -341,7 +330,7 @@ namespace randomx {
//4 uOPs //4 uOPs
void AssemblyGeneratorX86::h_IMULH_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
asmCode << "\tmov rax, " << regR[instr.dst] << std::endl; asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
asmCode << "\tmul " << regR[instr.src] << std::endl; asmCode << "\tmul " << regR[instr.src] << std::endl;
asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl; asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
@ -349,7 +338,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IMULH_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, "ecx"); genAddressReg(instr, "ecx");
asmCode << "\tmov rax, " << regR[instr.dst] << std::endl; asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
@ -364,7 +353,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_ISMULH_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_ISMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
asmCode << "\tmov rax, " << regR[instr.dst] << std::endl; asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
asmCode << "\timul " << regR[instr.src] << std::endl; asmCode << "\timul " << regR[instr.src] << std::endl;
asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl; asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
@ -372,7 +361,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_ISMULH_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_ISMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, "ecx"); genAddressReg(instr, "ecx");
asmCode << "\tmov rax, " << regR[instr.dst] << std::endl; asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
@ -387,13 +376,13 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_INEG_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_INEG_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
asmCode << "\tneg " << regR[instr.dst] << std::endl; asmCode << "\tneg " << regR[instr.dst] << std::endl;
traceint(instr); traceint(instr);
} }
void AssemblyGeneratorX86::h_IXOR_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IXOR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
asmCode << "\txor " << regR[instr.dst] << ", " << regR[instr.src] << std::endl; asmCode << "\txor " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
} }
@ -404,7 +393,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IXOR_M(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IXOR_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
asmCode << "\txor " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl; asmCode << "\txor " << regR[instr.dst] << ", qword ptr [" << regScratchpadAddr << "+rax]" << std::endl;
@ -416,7 +405,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IROR_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IROR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl; asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
asmCode << "\tror " << regR[instr.dst] << ", cl" << std::endl; asmCode << "\tror " << regR[instr.dst] << ", cl" << std::endl;
@ -428,7 +417,7 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_IROL_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IROL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl; asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
asmCode << "\trol " << regR[instr.dst] << ", cl" << std::endl; asmCode << "\trol " << regR[instr.dst] << ", cl" << std::endl;
@ -441,7 +430,7 @@ namespace randomx {
void AssemblyGeneratorX86::h_IMUL_RCP(Instruction& instr, int i) { void AssemblyGeneratorX86::h_IMUL_RCP(Instruction& instr, int i) {
if (instr.getImm32() != 0) { if (instr.getImm32() != 0) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
asmCode << "\tmov rax, " << randomx_reciprocal(instr.getImm32()) << std::endl; asmCode << "\tmov rax, " << randomx_reciprocal(instr.getImm32()) << std::endl;
asmCode << "\timul " << regR[instr.dst] << ", rax" << std::endl; asmCode << "\timul " << regR[instr.dst] << ", rax" << std::endl;
traceint(instr); traceint(instr);
@ -453,8 +442,8 @@ namespace randomx {
void AssemblyGeneratorX86::h_ISWAP_R(Instruction& instr, int i) { void AssemblyGeneratorX86::h_ISWAP_R(Instruction& instr, int i) {
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
registerUsage[instr.src] = i; registerUsage[instr.src].lastUsed = i;
asmCode << "\txchg " << regR[instr.dst] << ", " << regR[instr.src] << std::endl; asmCode << "\txchg " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
traceint(instr); traceint(instr);
} }
@ -541,14 +530,16 @@ namespace randomx {
} }
void AssemblyGeneratorX86::h_CBRANCH(Instruction& instr, int i) { void AssemblyGeneratorX86::h_CBRANCH(Instruction& instr, int i) {
int reg = getConditionRegister(); int reg = getConditionRegister(registerUsage);
int target = registerUsage[reg] + 1; int target = registerUsage[reg].lastUsed + 1;
registerUsage[reg].count++;
int shift = instr.getModCond(); int shift = instr.getModCond();
asmCode << "\tadd " << regR[reg] << ", " << (int32_t)(instr.getImm32() | (1 << shift)) << std::endl; asmCode << "\tadd " << regR[reg] << ", " << (int32_t)(instr.getImm32() | (1 << shift)) << std::endl;
asmCode << "\ttest " << regR[reg] << ", " << (ConditionMask << shift) << std::endl; asmCode << "\ttest " << regR[reg] << ", " << (ConditionMask << shift) << std::endl;
asmCode << "\tjz randomx_isn_" << target << std::endl; asmCode << "\tjz randomx_isn_" << target << std::endl;
for (unsigned j = 0; j < RegistersCount; ++j) { //mark all registers as used //mark all registers as used
registerUsage[j] = i; for (unsigned j = 0; j < RegistersCount; ++j) {
registerUsage[j].lastUsed = i;
} }
} }

View File

@ -43,7 +43,6 @@ namespace randomx {
void genAddressReg(Instruction&, const char*); void genAddressReg(Instruction&, const char*);
void genAddressRegDst(Instruction&, int); void genAddressRegDst(Instruction&, int);
int32_t genAddressImm(Instruction&); int32_t genAddressImm(Instruction&);
int getConditionRegister();
void generateCode(Instruction&, int); void generateCode(Instruction&, int);
void traceint(Instruction&); void traceint(Instruction&);
void traceflt(Instruction&); void traceflt(Instruction&);
@ -82,6 +81,6 @@ namespace randomx {
static InstructionGenerator engine[256]; static InstructionGenerator engine[256];
std::stringstream asmCode; std::stringstream asmCode;
int registerUsage[RegistersCount]; RegisterUsage registerUsage[RegistersCount];
}; };
} }

View File

@ -88,6 +88,11 @@ namespace randomx {
double hi; double hi;
}; };
struct RegisterUsage {
int32_t lastUsed;
int32_t count;
};
constexpr uint32_t ScratchpadL1 = RANDOMX_SCRATCHPAD_L1 / sizeof(int_reg_t); constexpr uint32_t ScratchpadL1 = RANDOMX_SCRATCHPAD_L1 / sizeof(int_reg_t);
constexpr uint32_t ScratchpadL2 = RANDOMX_SCRATCHPAD_L2 / sizeof(int_reg_t); constexpr uint32_t ScratchpadL2 = RANDOMX_SCRATCHPAD_L2 / sizeof(int_reg_t);
constexpr uint32_t ScratchpadL3 = RANDOMX_SCRATCHPAD_L3 / sizeof(int_reg_t); constexpr uint32_t ScratchpadL3 = RANDOMX_SCRATCHPAD_L3 / sizeof(int_reg_t);
@ -102,6 +107,21 @@ namespace randomx {
constexpr int RegisterNeedsDisplacement = 5; //x86 r13 register constexpr int RegisterNeedsDisplacement = 5; //x86 r13 register
constexpr int RegisterNeedsSib = 4; //x86 r12 register constexpr int RegisterNeedsSib = 4; //x86 r12 register
inline int getConditionRegister(RegisterUsage(&registerUsage)[RegistersCount]) {
int min = INT_MAX;
int minCount = 0;
int minIndex;
//prefer registers that have been used as a condition register fewer times
for (unsigned i = 0; i < RegistersCount; ++i) {
if (registerUsage[i].lastUsed < min || (registerUsage[i].lastUsed == min && registerUsage[i].count < minCount)) {
min = registerUsage[i].lastUsed;
minCount = registerUsage[i].count;
minIndex = i;
}
}
return minIndex;
}
struct MemoryRegisters { struct MemoryRegisters {
addr_t mx, ma; addr_t mx, ma;
uint8_t* memory = nullptr; uint8_t* memory = nullptr;

View File

@ -299,7 +299,8 @@ namespace randomx {
void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) { void JitCompilerX86::generateProgramPrologue(Program& prog, ProgramConfiguration& pcfg) {
instructionOffsets.clear(); instructionOffsets.clear();
for (unsigned i = 0; i < 8; ++i) { for (unsigned i = 0; i < 8; ++i) {
registerUsage[i] = -1; registerUsage[i].lastUsed = -1;
registerUsage[i].count = 0;
} }
codePos = prologueSize; codePos = prologueSize;
memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask)); memcpy(code + codePos - 48, &pcfg.eMask, sizeof(pcfg.eMask));
@ -468,7 +469,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) { void JitCompilerX86::h_IADD_RS(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
emit(REX_LEA); emit(REX_LEA);
if (instr.dst == RegisterNeedsDisplacement) if (instr.dst == RegisterNeedsDisplacement)
emitByte(0xac); emitByte(0xac);
@ -480,7 +481,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IADD_M(Instruction& instr, int i) { void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_ADD_RM); emit(REX_ADD_RM);
@ -499,7 +500,7 @@ namespace randomx {
} }
void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) { void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
emit(REX_SUB_RR); emit(REX_SUB_RR);
emitByte(0xc0 + 8 * instr.dst + instr.src); emitByte(0xc0 + 8 * instr.dst + instr.src);
@ -512,7 +513,7 @@ namespace randomx {
} }
void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) { void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_SUB_RM); emit(REX_SUB_RM);
@ -527,7 +528,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) { void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
emit(REX_IMUL_RR); emit(REX_IMUL_RR);
emitByte(0xc0 + 8 * instr.dst + instr.src); emitByte(0xc0 + 8 * instr.dst + instr.src);
@ -540,7 +541,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) { void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_IMUL_RM); emit(REX_IMUL_RM);
@ -555,7 +556,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) { void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst); emitByte(0xc0 + instr.dst);
emit(REX_MUL_R); emit(REX_MUL_R);
@ -565,7 +566,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) { void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, false); genAddressReg(instr, false);
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
@ -584,7 +585,7 @@ namespace randomx {
} }
void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) { void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst); emitByte(0xc0 + instr.dst);
emit(REX_MUL_R); emit(REX_MUL_R);
@ -594,7 +595,7 @@ namespace randomx {
} }
void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) { void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr, false); genAddressReg(instr, false);
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
@ -614,7 +615,7 @@ namespace randomx {
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) { void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
if (instr.getImm32() != 0) { if (instr.getImm32() != 0) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
emit(MOV_RAX_I); emit(MOV_RAX_I);
emit64(randomx_reciprocal(instr.getImm32())); emit64(randomx_reciprocal(instr.getImm32()));
emit(REX_IMUL_RM); emit(REX_IMUL_RM);
@ -623,13 +624,13 @@ namespace randomx {
} }
void JitCompilerX86::h_INEG_R(Instruction& instr, int i) { void JitCompilerX86::h_INEG_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
emit(REX_NEG); emit(REX_NEG);
emitByte(0xd8 + instr.dst); emitByte(0xd8 + instr.dst);
} }
void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) { void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
emit(REX_XOR_RR); emit(REX_XOR_RR);
emitByte(0xc0 + 8 * instr.dst + instr.src); emitByte(0xc0 + 8 * instr.dst + instr.src);
@ -642,7 +643,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) { void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_XOR_RM); emit(REX_XOR_RM);
@ -657,7 +658,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IROR_R(Instruction& instr, int i) { void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
emit(REX_MOV_RR); emit(REX_MOV_RR);
emitByte(0xc8 + instr.src); emitByte(0xc8 + instr.src);
@ -672,7 +673,7 @@ namespace randomx {
} }
void JitCompilerX86::h_IROL_R(Instruction& instr, int i) { void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
emit(REX_MOV_RR); emit(REX_MOV_RR);
emitByte(0xc8 + instr.src); emitByte(0xc8 + instr.src);
@ -688,8 +689,8 @@ namespace randomx {
void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) { void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
if (instr.src != instr.dst) { if (instr.src != instr.dst) {
registerUsage[instr.dst] = i; registerUsage[instr.dst].lastUsed = i;
registerUsage[instr.src] = i; registerUsage[instr.src].lastUsed = i;
emit(REX_XCHG); emit(REX_XCHG);
emitByte(0xc0 + instr.src + 8 * instr.dst); emitByte(0xc0 + instr.src + 8 * instr.dst);
} }
@ -770,21 +771,10 @@ namespace randomx {
emit(AND_OR_MOV_LDMXCSR); emit(AND_OR_MOV_LDMXCSR);
} }
int JitCompilerX86::getConditionRegister() {
int min = INT_MAX;
int minIndex;
for (unsigned i = 0; i < RegistersCount; ++i) {
if (registerUsage[i] < min) {
min = registerUsage[i];
minIndex = i;
}
}
return minIndex;
}
void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) { void JitCompilerX86::h_CBRANCH(Instruction& instr, int i) {
int reg = getConditionRegister(); int reg = getConditionRegister(registerUsage);
int target = registerUsage[reg] + 1; int target = registerUsage[reg].lastUsed + 1;
registerUsage[reg].count++;
int shift = instr.getModCond(); int shift = instr.getModCond();
emit(REX_ADD_I); emit(REX_ADD_I);
emitByte(0xc0 + reg); emitByte(0xc0 + reg);
@ -794,8 +784,9 @@ namespace randomx {
emit32(ConditionMask << shift); emit32(ConditionMask << shift);
emit(JZ); emit(JZ);
emit32(instructionOffsets[target] - (codePos + 4)); emit32(instructionOffsets[target] - (codePos + 4));
for (unsigned j = 0; j < RegistersCount; ++j) { //mark all registers as used //mark all registers as used
registerUsage[j] = i; for (unsigned j = 0; j < RegistersCount; ++j) {
registerUsage[j].lastUsed = i;
} }
} }

View File

@ -58,13 +58,12 @@ namespace randomx {
private: private:
static InstructionGeneratorX86 engine[256]; static InstructionGeneratorX86 engine[256];
std::vector<int32_t> instructionOffsets; std::vector<int32_t> instructionOffsets;
int registerUsage[8]; RegisterUsage registerUsage[RegistersCount];
uint8_t* code; uint8_t* code;
int32_t codePos; int32_t codePos;
void generateProgramPrologue(Program&, ProgramConfiguration&); void generateProgramPrologue(Program&, ProgramConfiguration&);
void generateProgramEpilogue(Program&); void generateProgramEpilogue(Program&);
int getConditionRegister();
void genAddressReg(Instruction&, bool); void genAddressReg(Instruction&, bool);
void genAddressRegDst(Instruction&, bool); void genAddressRegDst(Instruction&, bool);
void genAddressImm(Instruction&); void genAddressImm(Instruction&);

View File

@ -229,7 +229,7 @@ int main(int argc, char** argv) {
std::cout << "Calculated result: "; std::cout << "Calculated result: ";
result.print(std::cout); result.print(std::cout);
if (noncesCount == 1000 && seedValue == 0) if (noncesCount == 1000 && seedValue == 0)
std::cout << "Reference result: 804fed4a3dc4ed12917a210aad295925544e688e28549d7178eb27f412476a10" << std::endl; std::cout << "Reference result: df0862de0bedf2da0432a5eeb097453f2b020d00eadc60c32ae27b8d9d10ee0c" << std::endl;
if (!miningMode) { if (!miningMode) {
std::cout << "Performance: " << 1000 * elapsed / noncesCount << " ms per hash" << std::endl; std::cout << "Performance: " << 1000 * elapsed / noncesCount << " ms per hash" << std::endl;
} }

View File

@ -265,18 +265,6 @@ namespace randomx {
_mm_store_pd(&reg.e[i].lo, e[i]); _mm_store_pd(&reg.e[i].lo, e[i]);
} }
static int getConditionRegister(int(&registerUsage)[RegistersCount]) {
int min = INT_MAX;
int minIndex;
for (unsigned i = 0; i < RegistersCount; ++i) {
if (registerUsage[i] < min) {
min = registerUsage[i];
minIndex = i;
}
}
return minIndex;
}
template<class Allocator, bool softAes> template<class Allocator, bool softAes>
void InterpretedVm<Allocator, softAes>::datasetRead(uint32_t address, int_reg_t(&r)[RegistersCount]) { void InterpretedVm<Allocator, softAes>::datasetRead(uint32_t address, int_reg_t(&r)[RegistersCount]) {
uint64_t* datasetLine = (uint64_t*)(mem.memory + address); uint64_t* datasetLine = (uint64_t*)(mem.memory + address);
@ -288,9 +276,10 @@ namespace randomx {
template<class Allocator, bool softAes> template<class Allocator, bool softAes>
void InterpretedVm<Allocator, softAes>::precompileProgram(int_reg_t(&r)[RegistersCount], __m128d (&f)[RegisterCountFlt], __m128d (&e)[RegisterCountFlt], __m128d (&a)[RegisterCountFlt]) { void InterpretedVm<Allocator, softAes>::precompileProgram(int_reg_t(&r)[RegistersCount], __m128d (&f)[RegisterCountFlt], __m128d (&e)[RegisterCountFlt], __m128d (&a)[RegisterCountFlt]) {
int registerUsage[RegistersCount]; RegisterUsage registerUsage[RegistersCount];
for (unsigned i = 0; i < RegistersCount; ++i) { for (unsigned i = 0; i < RegistersCount; ++i) {
registerUsage[i] = -1; registerUsage[i].lastUsed = -1;
registerUsage[i].count = 0;
} }
for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) { for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
auto& instr = program(i); auto& instr = program(i);
@ -311,7 +300,7 @@ namespace randomx {
ibc.shift = instr.getModShift(); ibc.shift = instr.getModShift();
ibc.imm = signExtend2sCompl(instr.getImm32()); ibc.imm = signExtend2sCompl(instr.getImm32());
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IADD_M) { CASE_REP(IADD_M) {
@ -328,7 +317,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(ISUB_R) { CASE_REP(ISUB_R) {
@ -343,7 +332,7 @@ namespace randomx {
ibc.imm = signExtend2sCompl(instr.getImm32()); ibc.imm = signExtend2sCompl(instr.getImm32());
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(ISUB_M) { CASE_REP(ISUB_M) {
@ -360,7 +349,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IMUL_R) { CASE_REP(IMUL_R) {
@ -375,7 +364,7 @@ namespace randomx {
ibc.imm = signExtend2sCompl(instr.getImm32()); ibc.imm = signExtend2sCompl(instr.getImm32());
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IMUL_M) { CASE_REP(IMUL_M) {
@ -392,7 +381,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IMULH_R) { CASE_REP(IMULH_R) {
@ -401,7 +390,7 @@ namespace randomx {
ibc.type = InstructionType::IMULH_R; ibc.type = InstructionType::IMULH_R;
ibc.idst = &r[dst]; ibc.idst = &r[dst];
ibc.isrc = &r[src]; ibc.isrc = &r[src];
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IMULH_M) { CASE_REP(IMULH_M) {
@ -418,7 +407,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(ISMULH_R) { CASE_REP(ISMULH_R) {
@ -427,7 +416,7 @@ namespace randomx {
ibc.type = InstructionType::ISMULH_R; ibc.type = InstructionType::ISMULH_R;
ibc.idst = &r[dst]; ibc.idst = &r[dst];
ibc.isrc = &r[src]; ibc.isrc = &r[src];
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(ISMULH_M) { CASE_REP(ISMULH_M) {
@ -444,7 +433,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IMUL_RCP) { CASE_REP(IMUL_RCP) {
@ -455,7 +444,7 @@ namespace randomx {
ibc.idst = &r[dst]; ibc.idst = &r[dst];
ibc.imm = randomx_reciprocal(divisor); ibc.imm = randomx_reciprocal(divisor);
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} }
else { else {
ibc.type = InstructionType::NOP; ibc.type = InstructionType::NOP;
@ -466,7 +455,7 @@ namespace randomx {
auto dst = instr.dst % RegistersCount; auto dst = instr.dst % RegistersCount;
ibc.type = InstructionType::INEG_R; ibc.type = InstructionType::INEG_R;
ibc.idst = &r[dst]; ibc.idst = &r[dst];
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IXOR_R) { CASE_REP(IXOR_R) {
@ -481,7 +470,7 @@ namespace randomx {
ibc.imm = signExtend2sCompl(instr.getImm32()); ibc.imm = signExtend2sCompl(instr.getImm32());
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IXOR_M) { CASE_REP(IXOR_M) {
@ -498,7 +487,7 @@ namespace randomx {
ibc.isrc = &Zero; ibc.isrc = &Zero;
ibc.memMask = ScratchpadL3Mask; ibc.memMask = ScratchpadL3Mask;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IROR_R) { CASE_REP(IROR_R) {
@ -513,7 +502,7 @@ namespace randomx {
ibc.imm = instr.getImm32(); ibc.imm = instr.getImm32();
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(IROL_R) { CASE_REP(IROL_R) {
@ -528,7 +517,7 @@ namespace randomx {
ibc.imm = instr.getImm32(); ibc.imm = instr.getImm32();
ibc.isrc = &ibc.imm; ibc.isrc = &ibc.imm;
} }
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
} break; } break;
CASE_REP(ISWAP_R) { CASE_REP(ISWAP_R) {
@ -538,8 +527,8 @@ namespace randomx {
ibc.idst = &r[dst]; ibc.idst = &r[dst];
ibc.isrc = &r[src]; ibc.isrc = &r[src];
ibc.type = InstructionType::ISWAP_R; ibc.type = InstructionType::ISWAP_R;
registerUsage[dst] = i; registerUsage[dst].lastUsed = i;
registerUsage[src] = i; registerUsage[src].lastUsed = i;
} }
else { else {
ibc.type = InstructionType::NOP; ibc.type = InstructionType::NOP;
@ -626,13 +615,15 @@ namespace randomx {
//jump condition //jump condition
int reg = getConditionRegister(registerUsage); int reg = getConditionRegister(registerUsage);
ibc.isrc = &r[reg]; ibc.isrc = &r[reg];
ibc.target = registerUsage[reg]; ibc.target = registerUsage[reg].lastUsed;
registerUsage[reg].count++;
int shift = instr.getModCond(); int shift = instr.getModCond();
const uint64_t conditionMask = ConditionMask << instr.getModCond(); const uint64_t conditionMask = ConditionMask << instr.getModCond();
ibc.imm = signExtend2sCompl(instr.getImm32()) | (1ULL << shift); ibc.imm = signExtend2sCompl(instr.getImm32()) | (1ULL << shift);
ibc.memMask = ConditionMask << shift; ibc.memMask = ConditionMask << shift;
for (unsigned j = 0; j < RegistersCount; ++j) { //mark all registers as used //mark all registers as used
registerUsage[j] = i; for (unsigned j = 0; j < RegistersCount; ++j) {
registerUsage[j].lastUsed = i;
} }
} break; } break;