mirror of
https://git.wownero.com/wownero/RandomWOW.git
synced 2024-12-22 15:58:53 +00:00
Assembly code generator for Windows 64-bit
This commit is contained in:
parent
c9102ee88c
commit
cb0721056a
14
makefile
14
makefile
@ -11,7 +11,7 @@ SRCDIR=src
|
||||
OBJDIR=obj
|
||||
LDFLAGS=
|
||||
TOBJS=$(addprefix $(OBJDIR)/,instructionsPortable.o TestAluFpu.o)
|
||||
ROBJS=$(addprefix $(OBJDIR)/,argon2_core.o argon2_ref.o blake2b.o dataset.o instructionsPortable.o InterpretedVirtualMachine.o main.o Program.o softAes.o VirtualMachine.o)
|
||||
ROBJS=$(addprefix $(OBJDIR)/,argon2_core.o argon2_ref.o AssemblyGeneratorX86.o blake2b.o CompiledVirtualMachine.o dataset.o executeProgram-linux.o instructionsPortable.o Instruction.o InterpretedVirtualMachine.o main.o Program.o softAes.o VirtualMachine.o)
|
||||
SRC1=$(addprefix $(SRCDIR)/,TestAluFpu.cpp instructions.hpp Pcg32.hpp)
|
||||
|
||||
all: release test
|
||||
@ -43,15 +43,27 @@ $(OBJDIR)/argon2_core.o: $(addprefix $(SRCDIR)/,argon2_core.c argon2_core.h blak
|
||||
$(OBJDIR)/argon2_ref.o: $(addprefix $(SRCDIR)/,argon2_ref.c argon2.h argon2_core.h blake2/blake2.h blake2/blake2-impl.h blake2/blamka-round-ref.h) | $(OBJDIR)
|
||||
$(CC) $(CCFLAGS) -c $(SRCDIR)/argon2_ref.c -o $@
|
||||
|
||||
$(OBJDIR)/AssemblyGeneratorX86.o: $(addprefix $(SRCDIR)/,AssemblyGeneratorX86.cpp AssemblyGeneratorX86.hpp Instruction.hpp Pcg32.hpp common.hpp instructions.hpp) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/AssemblyGeneratorX86.cpp -o $@
|
||||
|
||||
$(OBJDIR)/blake2b.o: $(addprefix $(SRCDIR)/blake2/,blake2b.c blake2.h blake2-impl.h) | $(OBJDIR)
|
||||
$(CC) $(CCFLAGS) -c $(SRCDIR)/blake2/blake2b.c -o $@
|
||||
|
||||
$(OBJDIR)/CompiledVirtualMachine.o: $(addprefix $(SRCDIR)/,CompiledVirtualMachine.cpp CompiledVirtualMachine.hpp Pcg32.hpp common.hpp instructions.hpp) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/CompiledVirtualMachine.cpp -o $@
|
||||
|
||||
$(OBJDIR)/dataset.o: $(addprefix $(SRCDIR)/,dataset.cpp common.hpp Pcg32.hpp argon2_core.h) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/dataset.cpp -o $@
|
||||
|
||||
$(OBJDIR)/executeProgram-linux.o: $(addprefix $(SRCDIR)/,executeProgram-linux.cpp common.hpp) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/executeProgram-linux.cpp -o $@
|
||||
|
||||
$(OBJDIR)/instructionsPortable.o: $(addprefix $(SRCDIR)/,instructionsPortable.cpp instructions.hpp intrinPortable.h) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/instructionsPortable.cpp -o $@
|
||||
|
||||
$(OBJDIR)/Instruction.o: $(addprefix $(SRCDIR)/,Instruction.cpp Instruction.hpp) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/Instruction.cpp -o $@
|
||||
|
||||
$(OBJDIR)/InterpretedVirtualMachine.o: $(addprefix $(SRCDIR)/,InterpretedVirtualMachine.cpp InterpretedVirtualMachine.hpp Pcg32.hpp instructions.hpp) | $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $(SRCDIR)/InterpretedVirtualMachine.cpp -o $@
|
||||
|
||||
|
523
src/AssemblyGeneratorX86.cpp
Normal file
523
src/AssemblyGeneratorX86.cpp
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AssemblyGeneratorX86.hpp"
|
||||
#include "Pcg32.hpp"
|
||||
#include "common.hpp"
|
||||
#include "instructions.hpp"
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
static const char* regR[8] = { "rbx", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
|
||||
static const char* regR32[8] = { "ebx", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" };
|
||||
static const char* regF[8] = { "xmm8", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" };
|
||||
|
||||
void AssemblyGeneratorX86::generateProgram(const void* seed) {
|
||||
asmCode.str(std::string()); //clear
|
||||
Pcg32 gen(seed);
|
||||
for (unsigned i = 0; i < sizeof(RegisterFile) / sizeof(Pcg32::result_type); ++i) {
|
||||
gen();
|
||||
}
|
||||
Instruction instr;
|
||||
for (unsigned i = 0; i < ProgramLength; ++i) {
|
||||
for (unsigned j = 0; j < sizeof(instr) / sizeof(Pcg32::result_type); ++j) {
|
||||
*(((uint32_t*)&instr) + j) = gen();
|
||||
}
|
||||
generateCode(instr, i);
|
||||
asmCode << std::endl;
|
||||
}
|
||||
if(ProgramLength > 0)
|
||||
asmCode << "\tjmp rx_i_0" << std::endl;
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::generateCode(Instruction& instr, int i) {
|
||||
asmCode << "rx_i_" << i << ": ;" << instr.getName() << std::endl;
|
||||
asmCode << "\tdec edi" << std::endl;
|
||||
asmCode << "\tjs rx_finish" << std::endl;
|
||||
auto generator = engine[instr.opcode];
|
||||
(this->*generator)(instr, i);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::gena(Instruction& instr) {
|
||||
asmCode << "\txor " << regR[instr.rega % RegistersCount] << ", 0" << std::hex << instr.addr0 << "h" << std::dec << std::endl;
|
||||
switch (instr.loca & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
asmCode << "\tmov ecx, " << regR32[instr.rega % RegistersCount] << std::endl;
|
||||
asmCode << "\tcall rx_read_dataset" << std::endl;
|
||||
return;
|
||||
|
||||
case 4:
|
||||
asmCode << "\tmov eax, " << regR32[instr.rega % RegistersCount] << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL2 - 1) << std::endl;
|
||||
asmCode << "\tmov rax, qword ptr [rsi + rax * 8]" << std::endl;
|
||||
return;
|
||||
|
||||
default:
|
||||
asmCode << "\tmov eax, " << regR32[instr.rega % RegistersCount] << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL1 - 1) << std::endl;
|
||||
asmCode << "\tmov rax, qword ptr [rsi + rax * 8]" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::genbr0(Instruction& instr, const char* instrx86) {
|
||||
switch (instr.locb & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
asmCode << "\tmov rcx, " << regR[instr.regb % RegistersCount] << std::endl;
|
||||
asmCode << "\t" << instrx86 << " rax, cl" << std::endl;
|
||||
return;
|
||||
default:
|
||||
asmCode << "\t" << instrx86 << " rax, " << (instr.imm0 & 63) << std::endl;;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::genbr1(Instruction& instr) {
|
||||
switch (instr.locb & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
asmCode << regR[instr.regb % RegistersCount] << std::endl;
|
||||
return;
|
||||
default:
|
||||
asmCode << instr.imm1 << std::endl;;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::genbr132(Instruction& instr) {
|
||||
switch (instr.locb & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
asmCode << regR32[instr.regb % RegistersCount] << std::endl;
|
||||
return;
|
||||
default:
|
||||
asmCode << instr.imm1 << std::endl;;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::genbf(Instruction& instr, const char* instrx86) {
|
||||
asmCode << "\tand rax, -2048" << std::endl;
|
||||
asmCode << "\tcvtsi2sd xmm0, rax" << std::endl;
|
||||
switch (instr.locb & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
asmCode << "\t" << instrx86 << " xmm0, " << regF[instr.regb % RegistersCount] << std::endl;
|
||||
return;
|
||||
default:
|
||||
convertible_t bimm;
|
||||
bimm.f64 = (double)instr.imm1;
|
||||
asmCode << "\tmov rax, " << bimm.i64 << std::endl;
|
||||
asmCode << "\tmovd xmm9, rax" << std::endl;
|
||||
asmCode << "\t" << instrx86 << " xmm0, xmm9" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::gencr(Instruction& instr) {
|
||||
switch (instr.locc & 7)
|
||||
{
|
||||
case 0:
|
||||
asmCode << "\tmov rcx, rax" << std::endl;
|
||||
asmCode << "\tmov eax, " << regR32[instr.regc % RegistersCount] << std::endl;
|
||||
asmCode << "\txor eax, 0" << std::hex << instr.addr1 << "h" << std::dec << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL2 - 1) << std::endl;
|
||||
asmCode << "\tmov qword ptr [rsi + rax * 8], rcx" << std::endl;
|
||||
return;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
asmCode << "\tmov rcx, rax" << std::endl;
|
||||
asmCode << "\tmov eax, " << regR32[instr.regc % RegistersCount] << std::endl;
|
||||
asmCode << "\txor eax, 0" << std::hex << instr.addr1 << "h" << std::dec << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL1 - 1) << std::endl;
|
||||
asmCode << "\tmov qword ptr [rsi + rax * 8], rcx" << std::endl;
|
||||
return;
|
||||
|
||||
default:
|
||||
asmCode << "\tmov " << regR[instr.regc % RegistersCount] << ", rax" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::gencf(Instruction& instr) {
|
||||
switch (instr.locc & 7)
|
||||
{
|
||||
case 0:
|
||||
asmCode << "\tmov eax, " << regR32[instr.regc % RegistersCount] << std::endl;
|
||||
asmCode << "\txor eax, 0" << std::hex << instr.addr1 << "h" << std::dec << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL2 - 1) << std::endl;
|
||||
asmCode << "\tmovd qword ptr [rsi + rax * 8], xmm0" << std::endl;
|
||||
return;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
asmCode << "\tmov eax, " << regR32[instr.regc % RegistersCount] << std::endl;
|
||||
asmCode << "\txor eax, 0" << std::hex << instr.addr1 << "h" << std::dec << std::endl;
|
||||
asmCode << "\tand eax, " << (ScratchpadL1 - 1) << std::endl;
|
||||
asmCode << "\tmovd qword ptr [rsi + rax * 8], xmm0" << std::endl;
|
||||
return;
|
||||
|
||||
default:
|
||||
asmCode << "\tmovsd " << regF[instr.regc % RegistersCount] << ", xmm0" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int wrapi(int i) {
|
||||
return i % RandomX::ProgramLength;
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_ADD_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tadd rax, ";
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_ADD_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tadd eax, ";
|
||||
genbr132(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_SUB_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tsub rax, ";
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_SUB_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tsub eax, ";
|
||||
genbr132(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_MUL_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\timul rax, ";
|
||||
if ((instr.locb & 7) >= 6) {
|
||||
asmCode << "rax, ";
|
||||
}
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_MULH_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov r8, rdx" << std::endl;
|
||||
asmCode << "\tmov rcx, ";
|
||||
genbr1(instr);
|
||||
asmCode << "\tmul rcx" << std::endl;
|
||||
asmCode << "\tmov rax, rdx" << std::endl;
|
||||
asmCode << "\tmov rdx, r8" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_MUL_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov ecx, eax" << std::endl;
|
||||
asmCode << "\tmov eax, ";
|
||||
genbr132(instr);
|
||||
asmCode << "\timul rax, rcx" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_IMUL_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmovsxd rcx, eax" << std::endl;
|
||||
if ((instr.locb & 7) >= 6) {
|
||||
asmCode << "\tmov rax, " << instr.imm1 << std::endl;
|
||||
}
|
||||
else {
|
||||
asmCode << "\tmovsxd rax, " << regR32[instr.regb % RegistersCount] << std::endl;
|
||||
}
|
||||
asmCode << "\timul rax, rcx" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_IMULH_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov r8, rdx" << std::endl;
|
||||
asmCode << "\tmov rcx, ";
|
||||
genbr1(instr);
|
||||
asmCode << "\timul rcx" << std::endl;
|
||||
asmCode << "\tmov rax, rdx" << std::endl;
|
||||
asmCode << "\tmov rdx, r8" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_DIV_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov r8, rdx" << std::endl;
|
||||
if ((instr.locb & 7) >= 6) {
|
||||
if (instr.imm1 == 0) {
|
||||
asmCode << "\tmov ecx, 1" << std::endl;
|
||||
}
|
||||
else {
|
||||
asmCode << "\tmov ecx, " << instr.imm1 << std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
asmCode << "mov ecx, 1" << std::endl;
|
||||
asmCode << "\tmov edx, " << regR32[instr.regb % RegistersCount] << std::endl;
|
||||
asmCode << "\ttest edx, edx" << std::endl;
|
||||
asmCode << "\tcmovne ecx, edx" << std::endl;
|
||||
}
|
||||
asmCode << "\txor edx, edx" << std::endl;
|
||||
asmCode << "\tdiv rcx" << std::endl;
|
||||
asmCode << "\tmov rdx, r8" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_IDIV_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov r8, rdx" << std::endl;
|
||||
asmCode << "\tmov edx, ";
|
||||
genbr132(instr);
|
||||
asmCode << "\tcmp edx, -1" << std::endl;
|
||||
asmCode << "\tjne short safe_idiv_" << i << std::endl;
|
||||
asmCode << "\tmov rcx, rax" << std::endl;
|
||||
asmCode << "\trol rcx, 1" << std::endl;
|
||||
asmCode << "\tdec rcx" << std::endl;
|
||||
asmCode << "\tjz short result_idiv_" << i << std::endl;
|
||||
asmCode << "safe_idiv_" << i << ":" << std::endl;
|
||||
asmCode << "\tmov ecx, 1" << std::endl;
|
||||
asmCode << "\ttest edx, edx" << std::endl;
|
||||
asmCode << "\tcmovne ecx, edx" << std::endl;
|
||||
asmCode << "\tmovsxd rcx, ecx" << std::endl;
|
||||
asmCode << "\tcqo" << std::endl;
|
||||
asmCode << "\tidiv rcx" << std::endl;
|
||||
asmCode << "result_idiv_" << i << ":" << std::endl;
|
||||
asmCode << "\tmov rdx, r8" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_AND_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tand rax, ";
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_AND_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tand eax, ";
|
||||
genbr132(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_OR_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tor rax, ";
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_OR_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tor eax, ";
|
||||
genbr132(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_XOR_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\txor rax, ";
|
||||
genbr1(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_XOR_32(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\txor eax, ";
|
||||
genbr132(instr);
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_SHL_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbr0(instr, "shl");
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_SHR_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbr0(instr, "shr");
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_SAR_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbr0(instr, "sar");
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_ROL_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbr0(instr, "rol");
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_ROR_64(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbr0(instr, "ror");
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPADD(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbf(instr, "addsd");
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPSUB(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
genbf(instr, "subsd");
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPMUL(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tor rax, 2048" << std::endl;
|
||||
genbf(instr, "mulsd");
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPDIV(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tor rax, 2048" << std::endl;
|
||||
genbf(instr, "divsd");
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPSQRT(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov rcx, 9223372036854773760" << std::endl;
|
||||
asmCode << "\tand rax, rcx" << std::endl;
|
||||
asmCode << "\tcvtsi2sd xmm0, rax" << std::endl;
|
||||
asmCode << "\tsqrtsd xmm0, xmm0" << std::endl;
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_FPROUND(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tmov rcx, rax" << std::endl;
|
||||
asmCode << "\tshl eax, 13" << std::endl;
|
||||
asmCode << "\tand rcx, -2048" << std::endl;
|
||||
asmCode << "\tand eax, 24576" << std::endl;
|
||||
asmCode << "\tcvtsi2sd xmm0, rcx" << std::endl;
|
||||
asmCode << "\tor eax, 40896" << std::endl;
|
||||
asmCode << "\tmov dword ptr [rsp - 8], eax" << std::endl;
|
||||
asmCode << "\tldmxcsr dword ptr [rsp - 8]" << std::endl;
|
||||
gencf(instr);
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_CALL(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
if ((instr.locb & 7) < 6) {
|
||||
asmCode << "\tcmp " << regR32[instr.regb % RegistersCount] << ", " << instr.imm1 << std::endl;
|
||||
asmCode << "\tjbe short taken_call_" << i << std::endl;
|
||||
gencr(instr);
|
||||
asmCode << "\tjmp rx_i_" << wrapi(i + 1) << std::endl;
|
||||
asmCode << "taken_call_" << i << ":" << std::endl;
|
||||
}
|
||||
asmCode << "\tpush rax" << std::endl;
|
||||
asmCode << "\tcall rx_i_" << wrapi(i + (instr.imm0 & 127) + 1) << std::endl;
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_RET(Instruction& instr, int i) {
|
||||
gena(instr);
|
||||
asmCode << "\tcmp rsp, rbp" << std::endl;
|
||||
asmCode << "\tje short not_taken_ret_" << i << std::endl;
|
||||
if ((instr.locb & 7) < 6) {
|
||||
asmCode << "\tcmp " << regR32[instr.regb % RegistersCount] << ", " << instr.imm1 << std::endl;
|
||||
asmCode << "\tja short not_taken_ret_" << i << std::endl;
|
||||
}
|
||||
asmCode << "\txor rax, qword ptr [rsp + 8]" << std::endl;
|
||||
gencr(instr);
|
||||
asmCode << "\tret 8" << std::endl;
|
||||
asmCode << "not_taken_ret_" << i << ":" << std::endl;
|
||||
gencr(instr);
|
||||
}
|
||||
|
||||
#include "instructionWeights.hpp"
|
||||
#define INST_HANDLE(x) REPN(&AssemblyGeneratorX86::h_##x, WT(x))
|
||||
|
||||
InstructionGenerator AssemblyGeneratorX86::engine[256] = {
|
||||
INST_HANDLE(ADD_64)
|
||||
INST_HANDLE(ADD_32)
|
||||
INST_HANDLE(SUB_64)
|
||||
INST_HANDLE(SUB_32)
|
||||
INST_HANDLE(MUL_64)
|
||||
INST_HANDLE(MULH_64)
|
||||
INST_HANDLE(MUL_32)
|
||||
INST_HANDLE(IMUL_32)
|
||||
INST_HANDLE(IMULH_64)
|
||||
INST_HANDLE(DIV_64)
|
||||
INST_HANDLE(IDIV_64)
|
||||
INST_HANDLE(AND_64)
|
||||
INST_HANDLE(AND_32)
|
||||
INST_HANDLE(OR_64)
|
||||
INST_HANDLE(OR_32)
|
||||
INST_HANDLE(XOR_64)
|
||||
INST_HANDLE(XOR_32)
|
||||
INST_HANDLE(SHL_64)
|
||||
INST_HANDLE(SHR_64)
|
||||
INST_HANDLE(SAR_64)
|
||||
INST_HANDLE(ROL_64)
|
||||
INST_HANDLE(ROR_64)
|
||||
INST_HANDLE(FPADD)
|
||||
INST_HANDLE(FPSUB)
|
||||
INST_HANDLE(FPMUL)
|
||||
INST_HANDLE(FPDIV)
|
||||
INST_HANDLE(FPSQRT)
|
||||
INST_HANDLE(FPROUND)
|
||||
INST_HANDLE(CALL)
|
||||
INST_HANDLE(RET)
|
||||
};
|
||||
}
|
82
src/AssemblyGeneratorX86.hpp
Normal file
82
src/AssemblyGeneratorX86.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Instruction.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
class AssemblyGeneratorX86;
|
||||
|
||||
typedef void(AssemblyGeneratorX86::*InstructionGenerator)(Instruction&, int);
|
||||
|
||||
class AssemblyGeneratorX86 {
|
||||
public:
|
||||
void generateProgram(const void* seed);
|
||||
void printCode(std::ostream& os) {
|
||||
os << asmCode.rdbuf();
|
||||
}
|
||||
private:
|
||||
static InstructionGenerator engine[256];
|
||||
std::stringstream asmCode;
|
||||
|
||||
void gena(Instruction&);
|
||||
void genbr0(Instruction&, const char*);
|
||||
void genbr1(Instruction&);
|
||||
void genbr132(Instruction&);
|
||||
void genbf(Instruction&, const char*);
|
||||
void gencr(Instruction&);
|
||||
void gencf(Instruction&);
|
||||
|
||||
void generateCode(Instruction&, int);
|
||||
|
||||
void h_ADD_64(Instruction&, int);
|
||||
void h_ADD_32(Instruction&, int);
|
||||
void h_SUB_64(Instruction&, int);
|
||||
void h_SUB_32(Instruction&, int);
|
||||
void h_MUL_64(Instruction&, int);
|
||||
void h_MULH_64(Instruction&, int);
|
||||
void h_MUL_32(Instruction&, int);
|
||||
void h_IMUL_32(Instruction&, int);
|
||||
void h_IMULH_64(Instruction&, int);
|
||||
void h_DIV_64(Instruction&, int);
|
||||
void h_IDIV_64(Instruction&, int);
|
||||
void h_AND_64(Instruction&, int);
|
||||
void h_AND_32(Instruction&, int);
|
||||
void h_OR_64(Instruction&, int);
|
||||
void h_OR_32(Instruction&, int);
|
||||
void h_XOR_64(Instruction&, int);
|
||||
void h_XOR_32(Instruction&, int);
|
||||
void h_SHL_64(Instruction&, int);
|
||||
void h_SHR_64(Instruction&, int);
|
||||
void h_SAR_64(Instruction&, int);
|
||||
void h_ROL_64(Instruction&, int);
|
||||
void h_ROR_64(Instruction&, int);
|
||||
void h_FPADD(Instruction&, int);
|
||||
void h_FPSUB(Instruction&, int);
|
||||
void h_FPMUL(Instruction&, int);
|
||||
void h_FPDIV(Instruction&, int);
|
||||
void h_FPSQRT(Instruction&, int);
|
||||
void h_FPROUND(Instruction&, int);
|
||||
void h_CALL(Instruction&, int);
|
||||
void h_RET(Instruction&, int);
|
||||
};
|
||||
}
|
47
src/CompiledVirtualMachine.cpp
Normal file
47
src/CompiledVirtualMachine.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CompiledVirtualMachine.hpp"
|
||||
#include "Pcg32.hpp"
|
||||
#include "common.hpp"
|
||||
#include "instructions.hpp"
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
void CompiledVirtualMachine::initializeProgram(const void* seed) {
|
||||
Pcg32 gen(seed);
|
||||
for (unsigned i = 0; i < sizeof(reg) / sizeof(Pcg32::result_type); ++i) {
|
||||
*(((uint32_t*)®) + i) = gen();
|
||||
}
|
||||
FPINIT();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
reg.f[i].f64 = (double)reg.f[i].i64;
|
||||
}
|
||||
for (unsigned i = 0; i < ProgramLength; ++i) {
|
||||
gen(); gen(); gen(); gen();
|
||||
}
|
||||
mem.ma = (gen() ^ *(((uint32_t*)seed) + 4)) & ~7;
|
||||
mem.mx = *(((uint32_t*)seed) + 5);
|
||||
}
|
||||
|
||||
void CompiledVirtualMachine::execute() {
|
||||
FPINIT();
|
||||
executeProgram(reg, mem, readDataset, scratchpad);
|
||||
}
|
||||
}
|
34
src/CompiledVirtualMachine.hpp
Normal file
34
src/CompiledVirtualMachine.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VirtualMachine.hpp"
|
||||
#include "Program.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
class CompiledVirtualMachine : public VirtualMachine {
|
||||
public:
|
||||
CompiledVirtualMachine(bool softAes) : VirtualMachine(softAes) {}
|
||||
virtual void initializeProgram(const void* seed) override;
|
||||
virtual void execute() override;
|
||||
};
|
||||
}
|
70
src/Instruction.cpp
Normal file
70
src/Instruction.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Instruction.hpp"
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
void Instruction::print(std::ostream& os) const {
|
||||
os << " A: loc = " << std::dec << (loca & 7) << ", reg: " << (rega & 7) << std::endl;
|
||||
os << " B: loc = " << (locb & 7) << ", reg: " << (regb & 7) << std::endl;
|
||||
os << " C: loc = " << (locc & 7) << ", reg: " << (regc & 7) << std::endl;
|
||||
os << " addr0 = " << std::hex << addr0 << std::endl;
|
||||
os << " addr1 = " << addr1 << std::endl;
|
||||
os << " imm0 = " << std::dec << (int)imm0 << std::endl;
|
||||
os << " imm1 = " << imm1 << std::endl;
|
||||
}
|
||||
|
||||
#include "instructionWeights.hpp"
|
||||
#define INST_NAME(x) REPN(#x, WT(x))
|
||||
|
||||
const char* Instruction::names[256] = {
|
||||
INST_NAME(ADD_64)
|
||||
INST_NAME(ADD_32)
|
||||
INST_NAME(SUB_64)
|
||||
INST_NAME(SUB_32)
|
||||
INST_NAME(MUL_64)
|
||||
INST_NAME(MULH_64)
|
||||
INST_NAME(MUL_32)
|
||||
INST_NAME(IMUL_32)
|
||||
INST_NAME(IMULH_64)
|
||||
INST_NAME(DIV_64)
|
||||
INST_NAME(IDIV_64)
|
||||
INST_NAME(AND_64)
|
||||
INST_NAME(AND_32)
|
||||
INST_NAME(OR_64)
|
||||
INST_NAME(OR_32)
|
||||
INST_NAME(XOR_64)
|
||||
INST_NAME(XOR_32)
|
||||
INST_NAME(SHL_64)
|
||||
INST_NAME(SHR_64)
|
||||
INST_NAME(SAR_64)
|
||||
INST_NAME(ROL_64)
|
||||
INST_NAME(ROR_64)
|
||||
INST_NAME(FPADD)
|
||||
INST_NAME(FPSUB)
|
||||
INST_NAME(FPMUL)
|
||||
INST_NAME(FPDIV)
|
||||
INST_NAME(FPSQRT)
|
||||
INST_NAME(FPROUND)
|
||||
INST_NAME(CALL)
|
||||
INST_NAME(RET)
|
||||
};
|
||||
|
||||
}
|
56
src/Instruction.hpp
Normal file
56
src/Instruction.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright (c) 2018 tevador
|
||||
|
||||
This file is part of RandomX.
|
||||
|
||||
RandomX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
RandomX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
uint8_t opcode;
|
||||
uint8_t loca;
|
||||
uint8_t rega;
|
||||
uint8_t locb;
|
||||
uint8_t regb;
|
||||
uint8_t locc;
|
||||
uint8_t regc;
|
||||
uint8_t imm0;
|
||||
uint32_t addr0;
|
||||
union {
|
||||
uint32_t addr1;
|
||||
int32_t imm1;
|
||||
};
|
||||
const char* getName() const {
|
||||
return names[opcode];
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream& os, const Instruction& i) {
|
||||
i.print(os);
|
||||
return os;
|
||||
}
|
||||
private:
|
||||
void print(std::ostream&) const;
|
||||
static const char* names[256];
|
||||
};
|
||||
|
||||
static_assert(sizeof(Instruction) == 16, "Invalid alignment of struct Instruction");
|
||||
|
||||
}
|
@ -55,7 +55,7 @@ namespace RandomX {
|
||||
void InterpretedVirtualMachine::execute() {
|
||||
while (ic > 0) {
|
||||
auto& inst = p(pc);
|
||||
if(trace) std::cout << p.getName(inst) << " (" << std::dec << pc << ")" << std::endl;
|
||||
if(trace) std::cout << inst.getName() << " (" << std::dec << pc << ")" << std::endl;
|
||||
pc = (pc + 1) % ProgramLength;
|
||||
auto handler = engine[inst.opcode];
|
||||
(this->*handler)(inst);
|
||||
|
@ -30,48 +30,8 @@ namespace RandomX {
|
||||
void Program::print(std::ostream& os) const {
|
||||
for (int i = 0; i < RandomX::ProgramLength; ++i) {
|
||||
auto instr = programBuffer[i];
|
||||
os << std::dec << instrNames[instr.opcode] << " (" << i << "):" << std::endl;
|
||||
os << " A: loc = " << (instr.loca & 7) << ", reg: " << (instr.rega & 7) << std::endl;
|
||||
os << " B: loc = " << (instr.locb & 7) << ", reg: " << (instr.regb & 7) << std::endl;
|
||||
os << " C: loc = " << (instr.locc & 7) << ", reg: " << (instr.regc & 7) << std::endl;
|
||||
os << " imm0 = " << (int)instr.imm0 << std::endl;
|
||||
os << " imm1 = " << std::hex << instr.imm1 << std::endl;
|
||||
os << std::dec << instr.getName() << " (" << i << "):" << std::endl;
|
||||
os << instr;
|
||||
}
|
||||
}
|
||||
|
||||
#include "instructionWeights.hpp"
|
||||
#define INST_NAME(x) REPN(#x, WT(x))
|
||||
|
||||
const char* Program::instrNames[256] = {
|
||||
INST_NAME(ADD_64)
|
||||
INST_NAME(ADD_32)
|
||||
INST_NAME(SUB_64)
|
||||
INST_NAME(SUB_32)
|
||||
INST_NAME(MUL_64)
|
||||
INST_NAME(MULH_64)
|
||||
INST_NAME(MUL_32)
|
||||
INST_NAME(IMUL_32)
|
||||
INST_NAME(IMULH_64)
|
||||
INST_NAME(DIV_64)
|
||||
INST_NAME(IDIV_64)
|
||||
INST_NAME(AND_64)
|
||||
INST_NAME(AND_32)
|
||||
INST_NAME(OR_64)
|
||||
INST_NAME(OR_32)
|
||||
INST_NAME(XOR_64)
|
||||
INST_NAME(XOR_32)
|
||||
INST_NAME(SHL_64)
|
||||
INST_NAME(SHR_64)
|
||||
INST_NAME(SAR_64)
|
||||
INST_NAME(ROL_64)
|
||||
INST_NAME(ROR_64)
|
||||
INST_NAME(FPADD)
|
||||
INST_NAME(FPSUB)
|
||||
INST_NAME(FPMUL)
|
||||
INST_NAME(FPDIV)
|
||||
INST_NAME(FPSQRT)
|
||||
INST_NAME(FPROUND)
|
||||
INST_NAME(CALL)
|
||||
INST_NAME(RET)
|
||||
};
|
||||
}
|
||||
|
@ -22,37 +22,17 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include "common.hpp"
|
||||
#include "Instruction.hpp"
|
||||
|
||||
class Pcg32;
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
struct Instruction {
|
||||
uint8_t opcode;
|
||||
uint8_t loca;
|
||||
uint8_t rega;
|
||||
uint8_t locb;
|
||||
uint8_t regb;
|
||||
uint8_t locc;
|
||||
uint8_t regc;
|
||||
uint8_t imm0;
|
||||
uint32_t addr0;
|
||||
union {
|
||||
uint32_t addr1;
|
||||
int32_t imm1;
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(Instruction) == 16, "Invalid alignment of struct Instruction");
|
||||
|
||||
class Program {
|
||||
public:
|
||||
Instruction& operator()(uint64_t pc) {
|
||||
return programBuffer[pc];
|
||||
}
|
||||
const char* getName(Instruction& instr) {
|
||||
return instrNames[instr.opcode];
|
||||
}
|
||||
void initialize(Pcg32& gen);
|
||||
friend std::ostream& operator<<(std::ostream& os, const Program& p) {
|
||||
p.print(os);
|
||||
@ -60,7 +40,6 @@ namespace RandomX {
|
||||
}
|
||||
private:
|
||||
void print(std::ostream&) const;
|
||||
static const char* instrNames[256];
|
||||
Instruction programBuffer[ProgramLength];
|
||||
};
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace RandomX {
|
||||
|
||||
typedef convertible_t(*DatasetReadFunc)(addr_t, MemoryRegisters&);
|
||||
|
||||
class VirtualMachine {
|
||||
public:
|
||||
VirtualMachine(bool softAes);
|
||||
|
@ -104,7 +104,9 @@ namespace RandomX {
|
||||
|
||||
static_assert(sizeof(RegisterFile) == 2 * RegistersCount * sizeof(convertible_t), "Invalid alignment of struct RandomX::RegisterFile");
|
||||
|
||||
typedef convertible_t(*DatasetReadFunc)(addr_t, MemoryRegisters&);
|
||||
|
||||
extern "C" {
|
||||
void executeProgram(RegisterFile& registerFile, convertible_t& scratchpad, MemoryRegisters& memory);
|
||||
void executeProgram(RegisterFile& registerFile, MemoryRegisters& memory, DatasetReadFunc readFunc, convertible_t* scratchpad);
|
||||
}
|
||||
}
|
10
src/executeProgram-linux.cpp
Normal file
10
src/executeProgram-linux.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "common.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace RandomX {
|
||||
extern "C" {
|
||||
void executeProgram(RegisterFile& registerFile, MemoryRegisters& memory, DatasetReadFunc readFunc, convertible_t* scratchpad) {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
}
|
||||
}
|
169
src/executeProgram-win64.asm
Normal file
169
src/executeProgram-win64.asm
Normal file
@ -0,0 +1,169 @@
|
||||
; Copyright (c) 2018 tevador
|
||||
;
|
||||
; This file is part of RandomX.
|
||||
;
|
||||
; RandomX is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; RandomX is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
|
||||
PUBLIC executeProgram
|
||||
|
||||
.code
|
||||
|
||||
executeProgram PROC
|
||||
; REGISTER ALLOCATION:
|
||||
; rax -> temporary
|
||||
; rbx -> "r0"
|
||||
; rcx -> temporary
|
||||
; rdx -> MemoryRegisters& memory
|
||||
; rsi -> convertible_t& scratchpad
|
||||
; rdi -> "ic" (instruction counter)
|
||||
; rbp -> beginning of VM stack
|
||||
; rsp -> end of VM stack
|
||||
; r8 -> temporary
|
||||
; r9 -> "r1"
|
||||
; r10 -> "r2"
|
||||
; r11 -> "r3"
|
||||
; r12 -> "r4"
|
||||
; r13 -> "r5"
|
||||
; r14 -> "r6"
|
||||
; r15 -> "r7"
|
||||
; xmm0 -> temporary
|
||||
; xmm1 -> "f1"
|
||||
; xmm2 -> "f2"
|
||||
; xmm3 -> "f3"
|
||||
; xmm4 -> "f4"
|
||||
; xmm5 -> "f5"
|
||||
; xmm6 -> "f6"
|
||||
; xmm7 -> "f7"
|
||||
; xmm8 -> "f0"
|
||||
; xmm9 -> temporary
|
||||
|
||||
; STACK STRUCTURE:
|
||||
; |
|
||||
; |
|
||||
; | saved registers
|
||||
; |
|
||||
; v
|
||||
; [rbp+8] RegisterFile& registerFile
|
||||
; [rbp] DatasetReadFunc readFunc
|
||||
; |
|
||||
; |
|
||||
; | VM stack
|
||||
; |
|
||||
; v
|
||||
; [rsp] last element of VM stack
|
||||
|
||||
; store callee-saved registers
|
||||
push rbx
|
||||
push rbp
|
||||
push rdi
|
||||
push rsi
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
sub rsp, 64
|
||||
movdqu xmmword ptr [rsp+48], xmm6
|
||||
movdqu xmmword ptr [rsp+32], xmm7
|
||||
movdqu xmmword ptr [rsp+16], xmm8
|
||||
movdqu xmmword ptr [rsp+0], xmm9
|
||||
|
||||
; function arguments
|
||||
push rcx ; RegisterFile& registerFile
|
||||
; mov rdx, rdx ; MemoryRegisters& memory
|
||||
push r8 ; DatasetReadFunc readFunc
|
||||
mov rsi, r9 ; convertible_t& scratchpad
|
||||
|
||||
mov rbp, rsp ; beginning of VM stack
|
||||
mov rdi, 1048576 ; number of VM instructions to execute
|
||||
|
||||
; load VM register values
|
||||
mov rbx, qword ptr [rcx+0]
|
||||
mov r9, qword ptr [rcx+8]
|
||||
mov r10, qword ptr [rcx+16]
|
||||
mov r11, qword ptr [rcx+24]
|
||||
mov r12, qword ptr [rcx+32]
|
||||
mov r13, qword ptr [rcx+40]
|
||||
mov r14, qword ptr [rcx+48]
|
||||
mov r15, qword ptr [rcx+56]
|
||||
movd xmm8, qword ptr [rcx+64]
|
||||
movd xmm1, qword ptr [rcx+72]
|
||||
movd xmm2, qword ptr [rcx+80]
|
||||
movd xmm3, qword ptr [rcx+88]
|
||||
movd xmm4, qword ptr [rcx+96]
|
||||
movd xmm5, qword ptr [rcx+104]
|
||||
movd xmm6, qword ptr [rcx+112]
|
||||
movd xmm7, qword ptr [rcx+120]
|
||||
|
||||
; program body
|
||||
|
||||
include program.inc
|
||||
|
||||
rx_finish:
|
||||
; unroll the stack
|
||||
mov rsp, rbp
|
||||
add rsp, 16
|
||||
|
||||
; save VM register values
|
||||
mov rcx, qword ptr [rbp+8]
|
||||
mov qword ptr [rcx+0], rbx
|
||||
mov qword ptr [rcx+8], r9
|
||||
mov qword ptr [rcx+16], r10
|
||||
mov qword ptr [rcx+24], r11
|
||||
mov qword ptr [rcx+32], r12
|
||||
mov qword ptr [rcx+40], r13
|
||||
mov qword ptr [rcx+48], r14
|
||||
mov qword ptr [rcx+56], r15
|
||||
movd qword ptr [rcx+64], xmm8
|
||||
movd qword ptr [rcx+72], xmm1
|
||||
movd qword ptr [rcx+80], xmm2
|
||||
movd qword ptr [rcx+88], xmm3
|
||||
movd qword ptr [rcx+96], xmm4
|
||||
movd qword ptr [rcx+104], xmm5
|
||||
movd qword ptr [rcx+112], xmm6
|
||||
movd qword ptr [rcx+120], xmm7
|
||||
|
||||
; load callee-saved registers
|
||||
movdqu xmm9, xmmword ptr [rsp+0]
|
||||
movdqu xmm8, xmmword ptr [rsp+16]
|
||||
movdqu xmm7, xmmword ptr [rsp+32]
|
||||
movdqu xmm6, xmmword ptr [rsp+48]
|
||||
add rsp, 64
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rbp
|
||||
pop rbx
|
||||
|
||||
; return
|
||||
ret 0
|
||||
|
||||
rx_read_dataset:
|
||||
push rdx
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
sub rsp, 32
|
||||
call qword ptr [rbp]
|
||||
add rsp, 32
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop rdx
|
||||
ret 0
|
||||
executeProgram ENDP
|
||||
|
||||
END
|
50
src/main.cpp
50
src/main.cpp
@ -18,6 +18,8 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//#define TRACE
|
||||
#include "InterpretedVirtualMachine.hpp"
|
||||
#include "CompiledVirtualMachine.hpp"
|
||||
#include "AssemblyGeneratorX86.hpp"
|
||||
#include "Stopwatch.hpp"
|
||||
#include "blake2/blake2.h"
|
||||
#include <fstream>
|
||||
@ -27,6 +29,7 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
#include <cstring>
|
||||
#include "Program.hpp"
|
||||
#include <string>
|
||||
#include "instructions.hpp"
|
||||
|
||||
const uint8_t seed[32] = { 191, 182, 222, 175, 249, 89, 134, 104, 241, 68, 191, 62, 162, 166, 61, 64, 123, 191, 227, 193, 118, 60, 188, 53, 223, 133, 175, 24, 123, 230, 55, 74 };
|
||||
|
||||
@ -73,16 +76,14 @@ std::ostream& operator<<(std::ostream& os, const RandomX::RegisterFile& rf) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool softAes, lightClient;
|
||||
bool softAes, lightClient, genAsm, compiled;
|
||||
int programCount;
|
||||
readOption("--softAes", argc, argv, softAes);
|
||||
readOption("--lightClient", argc, argv, lightClient);
|
||||
readOption("--genAsm", argc, argv, genAsm);
|
||||
readOption("--compiled", argc, argv, compiled);
|
||||
readInt(argc, argv, programCount, 1000);
|
||||
if (softAes)
|
||||
std::cout << "Using software AES." << std::endl;
|
||||
|
||||
uint8_t hash[32];
|
||||
char cumulative[32] = { 0 };
|
||||
unsigned char blockTemplate[] = {
|
||||
0x07, 0x07, 0xf7, 0xa4, 0xf0, 0xd6, 0x05, 0xb3, 0x03, 0x26, 0x08, 0x16, 0xba, 0x3f, 0x10, 0x90, 0x2e, 0x1a, 0x14,
|
||||
0x5a, 0xc5, 0xfa, 0xd3, 0xaa, 0x3a, 0xf6, 0xea, 0x44, 0xc1, 0x18, 0x69, 0xdc, 0x4f, 0x85, 0x3f, 0x00, 0x2b, 0x2e,
|
||||
@ -90,11 +91,34 @@ int main(int argc, char** argv) {
|
||||
0xc3, 0x8b, 0xde, 0xd3, 0x4d, 0x2d, 0xcd, 0xee, 0xf9, 0x5c, 0xd2, 0x0c, 0xef, 0xc1, 0x2f, 0x61, 0xd5, 0x61, 0x09
|
||||
};
|
||||
int* nonce = (int*)(blockTemplate + 39);
|
||||
RandomX::InterpretedVirtualMachine vm(softAes);
|
||||
uint8_t hash[32];
|
||||
|
||||
if (genAsm) {
|
||||
*nonce = programCount;
|
||||
blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0);
|
||||
RandomX::AssemblyGeneratorX86 asmX86;
|
||||
asmX86.generateProgram(hash);
|
||||
asmX86.printCode(std::cout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (softAes)
|
||||
std::cout << "Using software AES." << std::endl;
|
||||
|
||||
char cumulative[32] = { 0 };
|
||||
|
||||
RandomX::VirtualMachine* vm;
|
||||
|
||||
if (compiled) {
|
||||
vm = new RandomX::CompiledVirtualMachine(softAes);
|
||||
}
|
||||
else {
|
||||
vm = new RandomX::InterpretedVirtualMachine(softAes);
|
||||
}
|
||||
try {
|
||||
std::cout << "Initializing..." << std::endl;
|
||||
Stopwatch sw(true);
|
||||
vm.initializeDataset(seed, lightClient);
|
||||
vm->initializeDataset(seed, lightClient);
|
||||
if(lightClient)
|
||||
std::cout << "Cache (64 MiB) initialized in " << sw.getElapsed() << " s" << std::endl;
|
||||
else
|
||||
@ -106,16 +130,15 @@ int main(int argc, char** argv) {
|
||||
if (RandomX::trace) std::cout << "Nonce: " << i << " ";
|
||||
blake2b(hash, sizeof(hash), blockTemplate, sizeof(blockTemplate), nullptr, 0);
|
||||
int spIndex = hash[24] | ((hash[25] & 63) << 8);
|
||||
vm.initializeScratchpad(spIndex);
|
||||
vm->initializeScratchpad(spIndex);
|
||||
//dump((const char *)vm.getScratchpad(), RandomX::ScratchpadSize, "scratchpad-before.txt");
|
||||
//return 0;
|
||||
vm.initializeProgram(hash);
|
||||
vm.execute();
|
||||
vm->initializeProgram(hash);
|
||||
vm->execute();
|
||||
/*std::string fileName("scratchpad-after-");
|
||||
fileName = fileName + std::to_string(i) + ".txt";
|
||||
dump((const char *)vm.getScratchpad(), RandomX::ScratchpadSize, fileName.c_str());*/
|
||||
blake2b((void*)hash, sizeof(hash), &vm.getRegisterFile(), sizeof(RandomX::RegisterFile), nullptr, 0);
|
||||
//std::cout << vm.getRegisterFile();
|
||||
blake2b((void*)hash, sizeof(hash), &vm->getRegisterFile(), sizeof(RandomX::RegisterFile), nullptr, 0);
|
||||
if (RandomX::trace) {
|
||||
outputHex(std::cout, (char*)hash, sizeof(hash));
|
||||
}
|
||||
@ -124,9 +147,10 @@ int main(int argc, char** argv) {
|
||||
((uint64_t*)cumulative)[2] ^= ((uint64_t*)hash)[2];
|
||||
((uint64_t*)cumulative)[3] ^= ((uint64_t*)hash)[3];
|
||||
}
|
||||
double elapsed = sw.getElapsed();
|
||||
std::cout << "Cumulative output hash: ";
|
||||
outputHex(std::cout, cumulative, sizeof(cumulative));
|
||||
std::cout << "Performance: " << programCount / sw.getElapsed() << " programs per second" << std::endl;
|
||||
std::cout << "Performance: " << programCount / elapsed << " programs per second" << std::endl;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::cout << "ERROR: " << e.what() << std::endl;
|
||||
|
7033
src/program.inc
Normal file
7033
src/program.inc
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user