Explorar o código

Fixed biased condition register selection

tevador %!s(int64=7) %!d(string=hai) anos
pai
achega
3cf6a30076

+ 6 - 6
doc/program.asm

@@ -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
-	test r8, 1040384
+	add r10, 149087159
+	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
-	test r8, 520192
+	add r11, 1917049931
+	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
-	test r8, 1040384
+	add r13, -122249197
+	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

+ 26 - 35
src/assembly_generator_x86.cpp

@@ -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.src] = i;
+			registerUsage[instr.dst].lastUsed = 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 target = registerUsage[reg] + 1;
+		int reg = getConditionRegister(registerUsage);
+		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
-			registerUsage[j] = i;
+		//mark all registers as used
+		for (unsigned j = 0; j < RegistersCount; ++j) {
+			registerUsage[j].lastUsed = i;
 		}
 		}
 	}
 	}
 
 

+ 1 - 2
src/assembly_generator_x86.hpp

@@ -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];
 	};
 	};
 }
 }

+ 20 - 0
src/common.hpp

@@ -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;

+ 26 - 35
src/jit_compiler_x86.cpp

@@ -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.src] = i;
+			registerUsage[instr.dst].lastUsed = 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 target = registerUsage[reg] + 1;
+		int reg = getConditionRegister(registerUsage);
+		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
-			registerUsage[j] = i;
+		//mark all registers as used
+		for (unsigned j = 0; j < RegistersCount; ++j) {
+			registerUsage[j].lastUsed = i;
 		}
 		}
 	}
 	}
 
 

+ 1 - 2
src/jit_compiler_x86.hpp

@@ -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&);

+ 1 - 1
src/tests/benchmark.cpp

@@ -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;
 		}
 		}

+ 26 - 35
src/vm_interpreted.cpp

@@ -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[src] = i;
+						registerUsage[dst].lastUsed = 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
-						registerUsage[j] = i;
+					//mark all registers as used
+					for (unsigned j = 0; j < RegistersCount; ++j) {
+						registerUsage[j].lastUsed = i;
 					}
 					}
 				} break;
 				} break;