Преглед изворни кода

Added branches - ASM and JIT only

tevador пре 7 година
родитељ
комит
174754cb2b
7 измењених фајлова са 1043 додато и 695 уклоњено
  1. 54 0
      src/AssemblyGeneratorX86.cpp
  2. 3 0
      src/AssemblyGeneratorX86.hpp
  3. 134 40
      src/JitCompilerX86.cpp
  4. 43 39
      src/JitCompilerX86.hpp
  5. 3 0
      src/configuration.h
  6. 3 0
      src/instructionWeights.hpp
  7. 803 616
      src/program.inc

+ 54 - 0
src/AssemblyGeneratorX86.cpp

@@ -18,6 +18,7 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 */
 //#define TRACE
 
+#include <climits>
 #include "AssemblyGeneratorX86.hpp"
 #include "common.hpp"
 #include "reciprocal.h"
@@ -45,9 +46,25 @@ namespace RandomX {
 	static const char* regDatasetAddr = "rdi";
 	static const char* regScratchpadAddr = "rsi";
 
+	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::generateProgram(Program& prog) {
+		for (unsigned i = 0; i < 8; ++i) {
+			registerUsage[i] = -1;
+		}
 		asmCode.str(std::string()); //clear
 		for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
+			asmCode << "randomx_isn_" << i << ":" << std::endl;
 			Instruction& instr = prog(i);
 			instr.src %= RegistersCount;
 			instr.dst %= RegistersCount;
@@ -96,6 +113,7 @@ namespace RandomX {
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_IADD_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\tadd " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
 		}
@@ -107,6 +125,7 @@ namespace RandomX {
 
 	//2.75 uOP
 	void AssemblyGeneratorX86::h_IADD_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			asmCode << "\tadd " << regR[instr.dst] << ", qword ptr [rsi+rax]" << std::endl;
@@ -119,12 +138,14 @@ namespace RandomX {
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_IADD_RC(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.src] << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
 		traceint(instr);
 	}
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_ISUB_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\tsub " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
 		}
@@ -136,6 +157,7 @@ namespace RandomX {
 
 	//2.75 uOP
 	void AssemblyGeneratorX86::h_ISUB_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			asmCode << "\tsub " << regR[instr.dst] << ", qword ptr [rsi+rax]" << std::endl;
@@ -148,12 +170,14 @@ namespace RandomX {
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_IMUL_9C(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		asmCode << "\tlea " << regR[instr.dst] << ", [" << regR[instr.dst] << "+" << regR[instr.dst] << "*8" << std::showpos << (int32_t)instr.getImm32() << std::noshowpos << "]" << std::endl;
 		traceint(instr);
 	}
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_IMUL_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\timul " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
 		}
@@ -165,6 +189,7 @@ namespace RandomX {
 
 	//2.75 uOP
 	void AssemblyGeneratorX86::h_IMUL_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			asmCode << "\timul " << regR[instr.dst] << ", qword ptr [rsi+rax]" << std::endl;
@@ -177,6 +202,7 @@ namespace RandomX {
 
 	//4 uOPs
 	void AssemblyGeneratorX86::h_IMULH_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
 		asmCode << "\tmul " << regR[instr.src] << std::endl;
 		asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
@@ -185,6 +211,7 @@ namespace RandomX {
 
 	//5.75 uOPs
 	void AssemblyGeneratorX86::h_IMULH_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr, "ecx");
 			asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
@@ -200,6 +227,7 @@ namespace RandomX {
 
 	//4 uOPs
 	void AssemblyGeneratorX86::h_ISMULH_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
 		asmCode << "\timul " << regR[instr.src] << std::endl;
 		asmCode << "\tmov " << regR[instr.dst] << ", rdx" << std::endl;
@@ -208,6 +236,7 @@ namespace RandomX {
 
 	//5.75 uOPs
 	void AssemblyGeneratorX86::h_ISMULH_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr, "ecx");
 			asmCode << "\tmov rax, " << regR[instr.dst] << std::endl;
@@ -223,12 +252,14 @@ namespace RandomX {
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_INEG_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		asmCode << "\tneg " << regR[instr.dst] << std::endl;
 		traceint(instr);
 	}
 
 	//1 uOP
 	void AssemblyGeneratorX86::h_IXOR_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\txor " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
 		}
@@ -240,6 +271,7 @@ namespace RandomX {
 
 	//2.75 uOP
 	void AssemblyGeneratorX86::h_IXOR_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			asmCode << "\txor " << regR[instr.dst] << ", qword ptr [rsi+rax]" << std::endl;
@@ -252,6 +284,7 @@ namespace RandomX {
 
 	//1.75 uOPs
 	void AssemblyGeneratorX86::h_IROR_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
 			asmCode << "\tror " << regR[instr.dst] << ", cl" << std::endl;
@@ -264,6 +297,7 @@ namespace RandomX {
 
 	//1.75 uOPs
 	void AssemblyGeneratorX86::h_IROL_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			asmCode << "\tmov ecx, " << regR32[instr.src] << std::endl;
 			asmCode << "\trol " << regR[instr.dst] << ", cl" << std::endl;
@@ -277,6 +311,7 @@ namespace RandomX {
 	//2 uOPs
 	void AssemblyGeneratorX86::h_IMUL_RCP(Instruction& instr, int i) {
 		if (instr.getImm32() != 0) {
+			registerUsage[instr.dst] = i;
 			uint32_t divisor = instr.getImm32();
 			asmCode << "\tmov rax, " << reciprocal(instr.getImm32()) << std::endl;
 			asmCode << "\timul " << regR[instr.dst] << ", rax" << std::endl;
@@ -295,6 +330,9 @@ namespace RandomX {
 	//2 uOPs
 	void AssemblyGeneratorX86::h_ISWAP_R(Instruction& instr, int i) {
 		if (instr.src != instr.dst) {
+			//std::swap(registerUsage[instr.dst], registerUsage[instr.src]);
+			registerUsage[instr.dst] = i;
+			registerUsage[instr.src] = i;
 			asmCode << "\txchg " << regR[instr.dst] << ", " << regR[instr.src] << std::endl;
 			traceint(instr);
 		}
@@ -435,8 +473,23 @@ namespace RandomX {
 		}
 	}
 
+	void AssemblyGeneratorX86::handleCondition(Instruction& instr, int i) {
+		const int shift = (instr.mod >> 5);
+		const int conditionMask = ((1 << RANDOMX_CONDITION_BITS) - 1) << shift;
+		int reg = getConditionRegister();
+		int target = registerUsage[reg] + 1;
+		registerUsage[reg] = i;
+		asmCode << "\tadd " << regR[reg] << ", " << (1 << shift) << std::endl;
+		asmCode << "\ttest " << regR[reg] << ", " << conditionMask << std::endl;
+		asmCode << "\tjz randomx_isn_" << target << std::endl;
+		for (unsigned j = 0; j < 8; ++j) { //mark all registers as used
+			registerUsage[j] = i;
+		}
+	}
+
 	//4 uOPs
 	void AssemblyGeneratorX86::h_COND_R(Instruction& instr, int i) {
+		handleCondition(instr, i);
 		asmCode << "\txor ecx, ecx" << std::endl;
 		asmCode << "\tcmp " << regR32[instr.src] << ", " << (int32_t)instr.getImm32() << std::endl;
 		asmCode << "\tset" << condition(instr) << " cl" << std::endl;
@@ -446,6 +499,7 @@ namespace RandomX {
 
 	//6 uOPs
 	void AssemblyGeneratorX86::h_COND_M(Instruction& instr, int i) {
+		handleCondition(instr, i);
 		asmCode << "\txor ecx, ecx" << std::endl;
 		genAddressReg(instr);
 		asmCode << "\tcmp dword ptr [rsi+rax], " << (int32_t)instr.getImm32() << std::endl;

+ 3 - 0
src/AssemblyGeneratorX86.hpp

@@ -38,10 +38,13 @@ namespace RandomX {
 	private:
 		static InstructionGenerator engine[256];
 		std::stringstream asmCode;
+		int registerUsage[8];
 
 		void genAddressReg(Instruction&, const char*);
 		void genAddressRegDst(Instruction&, int);
 		int32_t genAddressImm(Instruction&);
+		int getConditionRegister();
+		void handleCondition(Instruction&, int);
 
 		void generateCode(Instruction&, int);
 

+ 134 - 40
src/JitCompilerX86.cpp

@@ -18,12 +18,15 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 */
 
 #include <cstring>
+#include <climits>
 #include <stdexcept>
 #include "JitCompilerX86.hpp"
 #include "Program.hpp"
 #include "reciprocal.h"
 #include "virtualMemory.hpp"
 
+#define RANDOMX_JUMP
+
 namespace RandomX {
 
 #if !defined(_M_X64) && !defined(__x86_64__)
@@ -168,6 +171,9 @@ namespace RandomX {
 	static const uint8_t REX_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 };
 	static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f };
 	static const uint8_t PADD_OPCODES[] = { 0xfc, 0xfd, 0xfe, 0xd4 };
+	static const uint8_t REX_ADD_I[] = { 0x49, 0x83 };
+	static const uint8_t REX_TEST[] = { 0x49, 0xF7 };
+	static const uint8_t JZ[] = { 0x0f, 0x84 };
 
 	size_t JitCompilerX86::getCodeSize() {
 		return codePos - prologueSize;
@@ -180,6 +186,12 @@ namespace RandomX {
 	}
 
 	void JitCompilerX86::generateProgram(Program& prog) {
+#ifdef RANDOMX_JUMP
+		instructionOffsets.clear();
+		for (unsigned i = 0; i < 8; ++i) {
+			registerUsage[i] = -1;
+		}
+#endif
 		auto addressRegisters = prog.getEntropy(12);
 		uint32_t readReg0 = 0 + (addressRegisters & 1);
 		addressRegisters >>= 1;
@@ -199,7 +211,7 @@ namespace RandomX {
 			Instruction& instr = prog(i);
 			instr.src %= RegistersCount;
 			instr.dst %= RegistersCount;
-			generateCode(instr);
+			generateCode(instr, i);
 		}
 		emit(REX_MOV_RR);
 		emitByte(0xc0 + readReg2);
@@ -217,9 +229,12 @@ namespace RandomX {
 		emitByte(0x90);
 	}
 
-	void JitCompilerX86::generateCode(Instruction& instr) {
+	void JitCompilerX86::generateCode(Instruction& instr, int i) {
+#ifdef RANDOMX_JUMP
+		instructionOffsets.push_back(codePos);
+#endif
 		auto generator = engine[instr.opcode];
-		(this->*generator)(instr);
+		(this->*generator)(instr, i);
 	}
 
 	void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
@@ -245,7 +260,8 @@ namespace RandomX {
 		emit32(instr.getImm32() & ScratchpadL3Mask);
 	}
 
-	void JitCompilerX86::h_IADD_R(Instruction& instr) {
+	void JitCompilerX86::h_IADD_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_ADD_RR);
 			emitByte(0xc0 + 8 * instr.dst + instr.src);
@@ -257,7 +273,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IADD_M(Instruction& instr) {
+	void JitCompilerX86::h_IADD_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			emit(REX_ADD_RM);
@@ -275,14 +292,16 @@ namespace RandomX {
 		emitByte((scale << 6) | (index << 3) | base);
 	}
 
-	void JitCompilerX86::h_IADD_RC(Instruction& instr) {
+	void JitCompilerX86::h_IADD_RC(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		emit(REX_LEA);
 		emitByte(0x84 + 8 * instr.dst);
 		genSIB(0, instr.src, instr.dst);
 		emit32(instr.getImm32());
 	}
 
-	void JitCompilerX86::h_ISUB_R(Instruction& instr) {
+	void JitCompilerX86::h_ISUB_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_SUB_RR);
 			emitByte(0xc0 + 8 * instr.dst + instr.src);
@@ -294,7 +313,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_ISUB_M(Instruction& instr) {
+	void JitCompilerX86::h_ISUB_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			emit(REX_SUB_RM);
@@ -308,14 +328,16 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IMUL_9C(Instruction& instr) {
+	void JitCompilerX86::h_IMUL_9C(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		emit(REX_LEA);
 		emitByte(0x84 + 8 * instr.dst);
 		genSIB(3, instr.dst, instr.dst);
 		emit32(instr.getImm32());
 	}
 
-	void JitCompilerX86::h_IMUL_R(Instruction& instr) {
+	void JitCompilerX86::h_IMUL_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_IMUL_RR);
 			emitByte(0xc0 + 8 * instr.dst + instr.src);
@@ -327,7 +349,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IMUL_M(Instruction& instr) {
+	void JitCompilerX86::h_IMUL_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			emit(REX_IMUL_RM);
@@ -341,7 +364,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IMULH_R(Instruction& instr) {
+	void JitCompilerX86::h_IMULH_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		emit(REX_MOV_RR64);
 		emitByte(0xc0 + instr.dst);
 		emit(REX_MUL_R);
@@ -350,7 +374,8 @@ namespace RandomX {
 		emitByte(0xc2 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_IMULH_M(Instruction& instr) {
+	void JitCompilerX86::h_IMULH_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr, false);
 			emit(REX_MOV_RR64);
@@ -368,7 +393,8 @@ namespace RandomX {
 		emitByte(0xc2 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_ISMULH_R(Instruction& instr) {
+	void JitCompilerX86::h_ISMULH_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		emit(REX_MOV_RR64);
 		emitByte(0xc0 + instr.dst);
 		emit(REX_MUL_R);
@@ -377,7 +403,8 @@ namespace RandomX {
 		emitByte(0xc2 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_ISMULH_M(Instruction& instr) {
+	void JitCompilerX86::h_ISMULH_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr, false);
 			emit(REX_MOV_RR64);
@@ -395,8 +422,9 @@ namespace RandomX {
 		emitByte(0xc2 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_IMUL_RCP(Instruction& instr) {
+	void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
 		if (instr.getImm32() != 0) {
+			registerUsage[instr.dst] = i;
 			emit(MOV_RAX_I);
 			emit64(reciprocal(instr.getImm32()));
 			emit(REX_IMUL_RM);
@@ -404,16 +432,18 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_ISDIV_C(Instruction& instr) {
+	void JitCompilerX86::h_ISDIV_C(Instruction& instr, int i) {
 
 	}
 
-	void JitCompilerX86::h_INEG_R(Instruction& instr) {
+	void JitCompilerX86::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) {
+	void JitCompilerX86::h_IXOR_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_XOR_RR);
 			emitByte(0xc0 + 8 * instr.dst + instr.src);
@@ -425,7 +455,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IXOR_M(Instruction& instr) {
+	void JitCompilerX86::h_IXOR_M(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			genAddressReg(instr);
 			emit(REX_XOR_RM);
@@ -439,7 +470,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IROR_R(Instruction& instr) {
+	void JitCompilerX86::h_IROR_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_MOV_RR);
 			emitByte(0xc8 + instr.src);
@@ -453,7 +485,8 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_IROL_R(Instruction& instr) {
+	void JitCompilerX86::h_IROL_R(Instruction& instr, int i) {
+		registerUsage[instr.dst] = i;
 		if (instr.src != instr.dst) {
 			emit(REX_MOV_RR);
 			emitByte(0xc8 + instr.src);
@@ -467,20 +500,22 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_ISWAP_R(Instruction& instr) {
+	void JitCompilerX86::h_ISWAP_R(Instruction& instr, int i) {
 		if (instr.src != instr.dst) {
+			registerUsage[instr.dst] = i;
+			registerUsage[instr.src] = i;
 			emit(REX_XCHG);
 			emitByte(0xc0 + instr.src + 8 * instr.dst);
 		}
 	}
 
-	void JitCompilerX86::h_FSWAP_R(Instruction& instr) {
+	void JitCompilerX86::h_FSWAP_R(Instruction& instr, int i) {
 		emit(SHUFPD);
 		emitByte(0xc0 + 9 * instr.dst);
 		emitByte(1);
 	}
 
-	void JitCompilerX86::h_FADD_R(Instruction& instr) {
+	void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		instr.src %= 4;
 		emit(REX_ADDPD);
@@ -490,7 +525,7 @@ namespace RandomX {
 		//emitByte(0xf8 + instr.dst);
 	}
 
-	void JitCompilerX86::h_FADD_M(Instruction& instr) {
+	void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
 		instr.dst %= 4;
 		genAddressReg(instr);
 		emit(REX_CVTDQ2PD_XMM12);
@@ -498,7 +533,7 @@ namespace RandomX {
 		emitByte(0xc4 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FSUB_R(Instruction& instr) {
+	void JitCompilerX86::h_FSUB_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		instr.src %= 4;
 		emit(REX_SUBPD);
@@ -508,7 +543,7 @@ namespace RandomX {
 		//emitByte(0xf8 + instr.dst);
 	}
 
-	void JitCompilerX86::h_FSUB_M(Instruction& instr) {
+	void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
 		instr.dst %= 4;
 		genAddressReg(instr);
 		emit(REX_CVTDQ2PD_XMM12);
@@ -516,20 +551,20 @@ namespace RandomX {
 		emitByte(0xc4 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FSCAL_R(Instruction& instr) {
+	void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		emit(REX_XORPS);
 		emitByte(0xc7 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FMUL_R(Instruction& instr) {
+	void JitCompilerX86::h_FMUL_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		instr.src %= 4;
 		emit(REX_MULPD);
 		emitByte(0xe0 + instr.src + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FMUL_M(Instruction& instr) {
+	void JitCompilerX86::h_FMUL_M(Instruction& instr, int i) {
 		instr.dst %= 4;
 		genAddressReg(instr);
 		emit(REX_CVTDQ2PD_XMM12);
@@ -540,7 +575,7 @@ namespace RandomX {
 		emitByte(0xe5 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FDIV_R(Instruction& instr) {
+	void JitCompilerX86::h_FDIV_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		instr.src %= 4;
 		emit(REX_DIVPD);
@@ -549,7 +584,7 @@ namespace RandomX {
 		emitByte(0xe5 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FDIV_M(Instruction& instr) {
+	void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
 		instr.dst %= 4;
 		genAddressReg(instr);
 		emit(REX_CVTDQ2PD_XMM12);
@@ -558,13 +593,13 @@ namespace RandomX {
 		emitByte(0xe4 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_FSQRT_R(Instruction& instr) {
+	void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
 		instr.dst %= 4;
 		emit(SQRTPD);
 		emitByte(0xe4 + 9 * instr.dst);
 	}
 
-	void JitCompilerX86::h_CFROUND(Instruction& instr) {
+	void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
 		emit(REX_MOV_RR64);
 		emitByte(0xc0 + instr.src);	
 		int rotate = (13 - (instr.getImm32() & 63)) & 63;
@@ -575,6 +610,28 @@ namespace RandomX {
 		emit(AND_OR_MOV_LDMXCSR);
 	}
 
+	static inline uint8_t jumpCondition(Instruction& instr, bool invert = false) {
+		switch (((instr.mod >> 2) & 7) ^ invert)
+		{
+		case 0:
+			return 0x76; //jbe
+		case 1:
+			return 0x77; //ja
+		case 2:
+			return 0x78; //js
+		case 3:
+			return 0x79; //jns
+		case 4:
+			return 0x70; //jo
+		case 5:
+			return 0x71; //jno
+		case 6:
+			return 0x7c; //jl
+		case 7:
+			return 0x7d; //jge
+		}
+	}
+
 	static inline uint8_t condition(Instruction& instr) {
 		switch ((instr.mod >> 2) & 7)
 		{
@@ -599,7 +656,41 @@ namespace RandomX {
 		}
 	}
 
-	void JitCompilerX86::h_COND_R(Instruction& instr) {
+	int JitCompilerX86::getConditionRegister() {
+		int min = INT_MAX;
+		int minIndex;
+		for (unsigned i = 0; i < 8; ++i) {
+			if (registerUsage[i] < min) {
+				min = registerUsage[i];
+				minIndex = i;
+			}
+		}
+		return minIndex;
+	}
+
+	void JitCompilerX86::handleCondition(Instruction& instr, int i) {
+		const int shift = (instr.mod >> 5);
+		const int conditionMask = ((1 << RANDOMX_CONDITION_BITS) - 1) << shift;
+		int reg = getConditionRegister();
+		int target = registerUsage[reg] + 1;
+		registerUsage[reg] = i;
+		emit(REX_ADD_I);
+		emitByte(0xc0 + reg);
+		emitByte(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;
+		}
+	}
+
+	void JitCompilerX86::h_COND_R(Instruction& instr, int i) {
+#ifdef RANDOMX_JUMP
+		handleCondition(instr, i);
+#endif
 		emit(XOR_ECX_ECX);
 		emit(REX_CMP_R32I);
 		emitByte(0xf8 + instr.src);
@@ -611,7 +702,10 @@ namespace RandomX {
 		emitByte(0xc1 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_COND_M(Instruction& instr) {
+	void JitCompilerX86::h_COND_M(Instruction& instr, int i) {
+#ifdef RANDOMX_JUMP
+		handleCondition(instr, i);
+#endif
 		emit(XOR_ECX_ECX);
 		genAddressReg(instr);
 		emit(REX_CMP_M32I);
@@ -623,21 +717,21 @@ namespace RandomX {
 		emitByte(0xc1 + 8 * instr.dst);
 	}
 
-	void JitCompilerX86::h_ISTORE(Instruction& instr) {
+	void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
 		genAddressRegDst(instr);
 		emit(REX_MOV_MR);
 		emitByte(0x04 + 8 * instr.src);
 		emitByte(0x06);
 	}
 
-	void JitCompilerX86::h_FSTORE(Instruction& instr) {
+	void JitCompilerX86::h_FSTORE(Instruction& instr, int i) {
 		genAddressRegDst(instr, true);
 		emit(MOVAPD);
 		emitByte(0x04 + 8 * instr.src);
 		emitByte(0x06);
 	}
 
-	void JitCompilerX86::h_NOP(Instruction& instr) {
+	void JitCompilerX86::h_NOP(Instruction& instr, int i) {
 		emitByte(0x90);
 	}
 

+ 43 - 39
src/JitCompilerX86.hpp

@@ -29,7 +29,7 @@ namespace RandomX {
 	class Program;
 	class JitCompilerX86;
 
-	typedef void(JitCompilerX86::*InstructionGeneratorX86)(Instruction&);
+	typedef void(JitCompilerX86::*InstructionGeneratorX86)(Instruction&, int);
 
 	constexpr uint32_t CodeSize = 64 * 1024;
 
@@ -46,15 +46,19 @@ namespace RandomX {
 		size_t getCodeSize();
 	private:
 		static InstructionGeneratorX86 engine[256];
+		std::vector<int32_t> instructionOffsets;
+		int registerUsage[8];
 		uint8_t* code;
 		int32_t codePos;
 
+		int getConditionRegister();
 		void genAddressReg(Instruction&, bool);
 		void genAddressRegDst(Instruction&, bool);
 		void genAddressImm(Instruction&);
 		void genSIB(int scale, int index, int base);
 
-		void generateCode(Instruction&);
+		void handleCondition(Instruction&, int);
+		void generateCode(Instruction&, int);
 
 		void emitByte(uint8_t val) {
 			code[codePos] = val;
@@ -89,43 +93,43 @@ namespace RandomX {
 			codePos += N;
 		}
 
-		void  h_IADD_R(Instruction&);
-		void  h_IADD_M(Instruction&);
-		void  h_IADD_RC(Instruction&);
-		void  h_ISUB_R(Instruction&);
-		void  h_ISUB_M(Instruction&);
-		void  h_IMUL_9C(Instruction&);
-		void  h_IMUL_R(Instruction&);
-		void  h_IMUL_M(Instruction&);
-		void  h_IMULH_R(Instruction&);
-		void  h_IMULH_M(Instruction&);
-		void  h_ISMULH_R(Instruction&);
-		void  h_ISMULH_M(Instruction&);
-		void  h_IMUL_RCP(Instruction&);
-		void  h_ISDIV_C(Instruction&);
-		void  h_INEG_R(Instruction&);
-		void  h_IXOR_R(Instruction&);
-		void  h_IXOR_M(Instruction&);
-		void  h_IROR_R(Instruction&);
-		void  h_IROL_R(Instruction&);
-		void  h_ISWAP_R(Instruction&);
-		void  h_FSWAP_R(Instruction&);
-		void  h_FADD_R(Instruction&);
-		void  h_FADD_M(Instruction&);
-		void  h_FSUB_R(Instruction&);
-		void  h_FSUB_M(Instruction&);
-		void  h_FSCAL_R(Instruction&);
-		void  h_FMUL_R(Instruction&);
-		void  h_FMUL_M(Instruction&);
-		void  h_FDIV_R(Instruction&);
-		void  h_FDIV_M(Instruction&);
-		void  h_FSQRT_R(Instruction&);
-		void  h_COND_R(Instruction&);
-		void  h_COND_M(Instruction&);
-		void  h_CFROUND(Instruction&);
-		void  h_ISTORE(Instruction&);
-		void  h_FSTORE(Instruction&);
-		void  h_NOP(Instruction&);
+		void  h_IADD_R(Instruction&, int);
+		void  h_IADD_M(Instruction&, int);
+		void  h_IADD_RC(Instruction&, int);
+		void  h_ISUB_R(Instruction&, int);
+		void  h_ISUB_M(Instruction&, int);
+		void  h_IMUL_9C(Instruction&, int);
+		void  h_IMUL_R(Instruction&, int);
+		void  h_IMUL_M(Instruction&, int);
+		void  h_IMULH_R(Instruction&, int);
+		void  h_IMULH_M(Instruction&, int);
+		void  h_ISMULH_R(Instruction&, int);
+		void  h_ISMULH_M(Instruction&, int);
+		void  h_IMUL_RCP(Instruction&, int);
+		void  h_ISDIV_C(Instruction&, int);
+		void  h_INEG_R(Instruction&, int);
+		void  h_IXOR_R(Instruction&, int);
+		void  h_IXOR_M(Instruction&, int);
+		void  h_IROR_R(Instruction&, int);
+		void  h_IROL_R(Instruction&, int);
+		void  h_ISWAP_R(Instruction&, int);
+		void  h_FSWAP_R(Instruction&, int);
+		void  h_FADD_R(Instruction&, int);
+		void  h_FADD_M(Instruction&, int);
+		void  h_FSUB_R(Instruction&, int);
+		void  h_FSUB_M(Instruction&, int);
+		void  h_FSCAL_R(Instruction&, int);
+		void  h_FMUL_R(Instruction&, int);
+		void  h_FMUL_M(Instruction&, int);
+		void  h_FDIV_R(Instruction&, int);
+		void  h_FDIV_M(Instruction&, int);
+		void  h_FSQRT_R(Instruction&, int);
+		void  h_COND_R(Instruction&, int);
+		void  h_COND_M(Instruction&, int);
+		void  h_CFROUND(Instruction&, int);
+		void  h_ISTORE(Instruction&, int);
+		void  h_FSTORE(Instruction&, int);
+		void  h_NOP(Instruction&, int);
 	};
 
 }

+ 3 - 0
src/configuration.h

@@ -67,6 +67,9 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 //Scratchpad L1 size in bytes. Must be a power of two and less than or equal to RANDOMX_SCRATCHPAD_L2.
 #define RANDOMX_SCRATCHPAD_L1      (16 * 1024)
 
+//How many register bits must be zero for a jump condition to be triggered
+#define RANDOMX_CONDITION_BITS     7
+
 /*
 Instruction frequencies (per 256 opcodes)
 Total sum of frequencies must be 256

+ 3 - 0
src/instructionWeights.hpp

@@ -54,6 +54,7 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 #define REP32(x) REP31(x) x,
 #define REP33(x) REP32(x) x,
 #define REP40(x) REP32(x) REP8(x)
+#define REP64(x) REP32(x) REP32(x)
 #define REP128(x) REP32(x) REP32(x) REP32(x) REP32(x)
 #define REP232(x) REP128(x) REP40(x) REP40(x) REP24(x)
 #define REP256(x) REP128(x) REP128(x)
@@ -95,6 +96,8 @@ along with RandomX.  If not, see<http://www.gnu.org/licenses/>.
 #define REPCASE30(x) REPCASE29(x) case __COUNTER__:
 #define REPCASE31(x) REPCASE30(x) case __COUNTER__:
 #define REPCASE32(x) REPCASE31(x) case __COUNTER__:
+#define REPCASE64(x) REPCASE32(x) REPCASE32(x)
+#define REPCASE128(x) REPCASE64(x) REPCASE64(x)
 #define REPCASENX(x,N) REPCASE##N(x)
 #define REPCASEN(x,N) REPCASENX(x,N)
 #define CASE_REP(x) REPCASEN(x, WT(x))

Разлика између датотеке није приказан због своје велике величине
+ 803 - 616
src/program.inc


Неке датотеке нису приказане због велике количине промена