Added branches - ASM and JIT only

This commit is contained in:
tevador 2019-03-17 23:09:11 +01:00
parent 6b344b81fd
commit 174754cb2b
7 changed files with 1190 additions and 746 deletions

View File

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

View File

@ -38,10 +38,13 @@ namespace RandomX {
private: private:
static InstructionGenerator engine[256]; static InstructionGenerator engine[256];
std::stringstream asmCode; std::stringstream asmCode;
int registerUsage[8];
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 handleCondition(Instruction&, int);
void generateCode(Instruction&, int); void generateCode(Instruction&, int);

View File

@ -18,12 +18,15 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
*/ */
#include <cstring> #include <cstring>
#include <climits>
#include <stdexcept> #include <stdexcept>
#include "JitCompilerX86.hpp" #include "JitCompilerX86.hpp"
#include "Program.hpp" #include "Program.hpp"
#include "reciprocal.h" #include "reciprocal.h"
#include "virtualMemory.hpp" #include "virtualMemory.hpp"
#define RANDOMX_JUMP
namespace RandomX { namespace RandomX {
#if !defined(_M_X64) && !defined(__x86_64__) #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_ANDPS_XMM12[] = { 0x45, 0x0F, 0x54, 0xE5, 0x45, 0x0F, 0x56, 0xE6 };
static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f }; static const uint8_t REX_PADD[] = { 0x66, 0x44, 0x0f };
static const uint8_t PADD_OPCODES[] = { 0xfc, 0xfd, 0xfe, 0xd4 }; 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() { size_t JitCompilerX86::getCodeSize() {
return codePos - prologueSize; return codePos - prologueSize;
@ -180,6 +186,12 @@ namespace RandomX {
} }
void JitCompilerX86::generateProgram(Program& prog) { 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); auto addressRegisters = prog.getEntropy(12);
uint32_t readReg0 = 0 + (addressRegisters & 1); uint32_t readReg0 = 0 + (addressRegisters & 1);
addressRegisters >>= 1; addressRegisters >>= 1;
@ -199,7 +211,7 @@ namespace RandomX {
Instruction& instr = prog(i); Instruction& instr = prog(i);
instr.src %= RegistersCount; instr.src %= RegistersCount;
instr.dst %= RegistersCount; instr.dst %= RegistersCount;
generateCode(instr); generateCode(instr, i);
} }
emit(REX_MOV_RR); emit(REX_MOV_RR);
emitByte(0xc0 + readReg2); emitByte(0xc0 + readReg2);
@ -217,9 +229,12 @@ namespace RandomX {
emitByte(0x90); 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]; auto generator = engine[instr.opcode];
(this->*generator)(instr); (this->*generator)(instr, i);
} }
void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) { void JitCompilerX86::genAddressReg(Instruction& instr, bool rax = true) {
@ -245,7 +260,8 @@ namespace RandomX {
emit32(instr.getImm32() & ScratchpadL3Mask); 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) { if (instr.src != instr.dst) {
emit(REX_ADD_RR); emit(REX_ADD_RR);
emitByte(0xc0 + 8 * instr.dst + instr.src); 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) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_ADD_RM); emit(REX_ADD_RM);
@ -275,14 +292,16 @@ namespace RandomX {
emitByte((scale << 6) | (index << 3) | base); 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); emit(REX_LEA);
emitByte(0x84 + 8 * instr.dst); emitByte(0x84 + 8 * instr.dst);
genSIB(0, instr.src, instr.dst); genSIB(0, instr.src, instr.dst);
emit32(instr.getImm32()); 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) { 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);
@ -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) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_SUB_RM); 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); emit(REX_LEA);
emitByte(0x84 + 8 * instr.dst); emitByte(0x84 + 8 * instr.dst);
genSIB(3, instr.dst, instr.dst); genSIB(3, instr.dst, instr.dst);
emit32(instr.getImm32()); 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) { 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);
@ -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) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_IMUL_RM); 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); emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst); emitByte(0xc0 + instr.dst);
emit(REX_MUL_R); emit(REX_MUL_R);
@ -350,7 +374,8 @@ namespace RandomX {
emitByte(0xc2 + 8 * instr.dst); 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) { if (instr.src != instr.dst) {
genAddressReg(instr, false); genAddressReg(instr, false);
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
@ -368,7 +393,8 @@ namespace RandomX {
emitByte(0xc2 + 8 * instr.dst); 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); emit(REX_MOV_RR64);
emitByte(0xc0 + instr.dst); emitByte(0xc0 + instr.dst);
emit(REX_MUL_R); emit(REX_MUL_R);
@ -377,7 +403,8 @@ namespace RandomX {
emitByte(0xc2 + 8 * instr.dst); 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) { if (instr.src != instr.dst) {
genAddressReg(instr, false); genAddressReg(instr, false);
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
@ -395,8 +422,9 @@ namespace RandomX {
emitByte(0xc2 + 8 * instr.dst); 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) { if (instr.getImm32() != 0) {
registerUsage[instr.dst] = i;
emit(MOV_RAX_I); emit(MOV_RAX_I);
emit64(reciprocal(instr.getImm32())); emit64(reciprocal(instr.getImm32()));
emit(REX_IMUL_RM); 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); emit(REX_NEG);
emitByte(0xd8 + instr.dst); 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) { 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);
@ -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) { if (instr.src != instr.dst) {
genAddressReg(instr); genAddressReg(instr);
emit(REX_XOR_RM); 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) { if (instr.src != instr.dst) {
emit(REX_MOV_RR); emit(REX_MOV_RR);
emitByte(0xc8 + instr.src); 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) { if (instr.src != instr.dst) {
emit(REX_MOV_RR); emit(REX_MOV_RR);
emitByte(0xc8 + instr.src); 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) { if (instr.src != instr.dst) {
registerUsage[instr.dst] = i;
registerUsage[instr.src] = i;
emit(REX_XCHG); emit(REX_XCHG);
emitByte(0xc0 + instr.src + 8 * instr.dst); 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); emit(SHUFPD);
emitByte(0xc0 + 9 * instr.dst); emitByte(0xc0 + 9 * instr.dst);
emitByte(1); emitByte(1);
} }
void JitCompilerX86::h_FADD_R(Instruction& instr) { void JitCompilerX86::h_FADD_R(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
instr.src %= 4; instr.src %= 4;
emit(REX_ADDPD); emit(REX_ADDPD);
@ -490,7 +525,7 @@ namespace RandomX {
//emitByte(0xf8 + instr.dst); //emitByte(0xf8 + instr.dst);
} }
void JitCompilerX86::h_FADD_M(Instruction& instr) { void JitCompilerX86::h_FADD_M(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
genAddressReg(instr); genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12); emit(REX_CVTDQ2PD_XMM12);
@ -498,7 +533,7 @@ namespace RandomX {
emitByte(0xc4 + 8 * instr.dst); 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.dst %= 4;
instr.src %= 4; instr.src %= 4;
emit(REX_SUBPD); emit(REX_SUBPD);
@ -508,7 +543,7 @@ namespace RandomX {
//emitByte(0xf8 + instr.dst); //emitByte(0xf8 + instr.dst);
} }
void JitCompilerX86::h_FSUB_M(Instruction& instr) { void JitCompilerX86::h_FSUB_M(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
genAddressReg(instr); genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12); emit(REX_CVTDQ2PD_XMM12);
@ -516,20 +551,20 @@ namespace RandomX {
emitByte(0xc4 + 8 * instr.dst); emitByte(0xc4 + 8 * instr.dst);
} }
void JitCompilerX86::h_FSCAL_R(Instruction& instr) { void JitCompilerX86::h_FSCAL_R(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
emit(REX_XORPS); emit(REX_XORPS);
emitByte(0xc7 + 8 * instr.dst); 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.dst %= 4;
instr.src %= 4; instr.src %= 4;
emit(REX_MULPD); emit(REX_MULPD);
emitByte(0xe0 + instr.src + 8 * instr.dst); 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; instr.dst %= 4;
genAddressReg(instr); genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12); emit(REX_CVTDQ2PD_XMM12);
@ -540,7 +575,7 @@ namespace RandomX {
emitByte(0xe5 + 8 * instr.dst); 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.dst %= 4;
instr.src %= 4; instr.src %= 4;
emit(REX_DIVPD); emit(REX_DIVPD);
@ -549,7 +584,7 @@ namespace RandomX {
emitByte(0xe5 + 8 * instr.dst); emitByte(0xe5 + 8 * instr.dst);
} }
void JitCompilerX86::h_FDIV_M(Instruction& instr) { void JitCompilerX86::h_FDIV_M(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
genAddressReg(instr); genAddressReg(instr);
emit(REX_CVTDQ2PD_XMM12); emit(REX_CVTDQ2PD_XMM12);
@ -558,13 +593,13 @@ namespace RandomX {
emitByte(0xe4 + 8 * instr.dst); emitByte(0xe4 + 8 * instr.dst);
} }
void JitCompilerX86::h_FSQRT_R(Instruction& instr) { void JitCompilerX86::h_FSQRT_R(Instruction& instr, int i) {
instr.dst %= 4; instr.dst %= 4;
emit(SQRTPD); emit(SQRTPD);
emitByte(0xe4 + 9 * instr.dst); emitByte(0xe4 + 9 * instr.dst);
} }
void JitCompilerX86::h_CFROUND(Instruction& instr) { void JitCompilerX86::h_CFROUND(Instruction& instr, int i) {
emit(REX_MOV_RR64); emit(REX_MOV_RR64);
emitByte(0xc0 + instr.src); emitByte(0xc0 + instr.src);
int rotate = (13 - (instr.getImm32() & 63)) & 63; int rotate = (13 - (instr.getImm32() & 63)) & 63;
@ -575,6 +610,28 @@ namespace RandomX {
emit(AND_OR_MOV_LDMXCSR); 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) { static inline uint8_t condition(Instruction& instr) {
switch ((instr.mod >> 2) & 7) 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(XOR_ECX_ECX);
emit(REX_CMP_R32I); emit(REX_CMP_R32I);
emitByte(0xf8 + instr.src); emitByte(0xf8 + instr.src);
@ -611,7 +702,10 @@ namespace RandomX {
emitByte(0xc1 + 8 * instr.dst); 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); emit(XOR_ECX_ECX);
genAddressReg(instr); genAddressReg(instr);
emit(REX_CMP_M32I); emit(REX_CMP_M32I);
@ -623,21 +717,21 @@ namespace RandomX {
emitByte(0xc1 + 8 * instr.dst); emitByte(0xc1 + 8 * instr.dst);
} }
void JitCompilerX86::h_ISTORE(Instruction& instr) { void JitCompilerX86::h_ISTORE(Instruction& instr, int i) {
genAddressRegDst(instr); genAddressRegDst(instr);
emit(REX_MOV_MR); emit(REX_MOV_MR);
emitByte(0x04 + 8 * instr.src); emitByte(0x04 + 8 * instr.src);
emitByte(0x06); emitByte(0x06);
} }
void JitCompilerX86::h_FSTORE(Instruction& instr) { void JitCompilerX86::h_FSTORE(Instruction& instr, int i) {
genAddressRegDst(instr, true); genAddressRegDst(instr, true);
emit(MOVAPD); emit(MOVAPD);
emitByte(0x04 + 8 * instr.src); emitByte(0x04 + 8 * instr.src);
emitByte(0x06); emitByte(0x06);
} }
void JitCompilerX86::h_NOP(Instruction& instr) { void JitCompilerX86::h_NOP(Instruction& instr, int i) {
emitByte(0x90); emitByte(0x90);
} }

View File

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

View File

@ -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. //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) #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) Instruction frequencies (per 256 opcodes)
Total sum of frequencies must be 256 Total sum of frequencies must be 256

View File

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

File diff suppressed because it is too large Load Diff