Remove zero register from vm bytecode

This commit is contained in:
DataHoarder 2024-04-14 15:43:54 +02:00
parent 78b0645034
commit b72f79a653
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
6 changed files with 243 additions and 249 deletions

190
bytecode.go Normal file
View file

@ -0,0 +1,190 @@
package randomx
import (
"encoding/binary"
"git.gammaspectra.live/P2Pool/go-randomx/v2/asm"
"math"
"math/bits"
)
type ByteCodeInstruction struct {
dst, src byte
idst, isrc *uint64
fdst, fsrc *[2]float64
imm uint64
simm int64
Opcode ByteCodeInstructionOp
target int16
shift uint8
memMask uint32
/*
union {
int_reg_t* idst;
rx_vec_f128* fdst;
};
union {
int_reg_t* isrc;
rx_vec_f128* fsrc;
};
union {
uint64_t imm;
int64_t simm;
};
InstructionType type;
union {
int16_t target;
uint16_t shift;
};
uint32_t memMask;
*/
}
func (i ByteCodeInstruction) getScratchpadSrcAddress() uint64 {
return (*i.isrc + i.imm) & uint64(i.memMask)
}
func (i ByteCodeInstruction) getScratchpadZeroAddress() uint64 {
return i.imm & uint64(i.memMask)
}
func (i ByteCodeInstruction) getScratchpadDestAddress() uint64 {
return (*i.idst + i.imm) & uint64(i.memMask)
}
type ByteCode [RANDOMX_PROGRAM_SIZE]ByteCodeInstruction
func (c *ByteCode) Interpret(vm *VM) {
for pc := 0; pc < RANDOMX_PROGRAM_SIZE; pc++ {
ibc := c[pc]
switch ibc.Opcode {
case VM_IADD_RS:
*ibc.idst += (*ibc.isrc << ibc.shift) + ibc.imm
case VM_IADD_M:
*ibc.idst += vm.Load64(ibc.getScratchpadSrcAddress())
case VM_IADD_MZ:
*ibc.idst += vm.Load64(ibc.getScratchpadZeroAddress())
case VM_ISUB_R:
*ibc.idst -= *ibc.isrc
case VM_ISUB_M:
*ibc.idst -= vm.Load64(ibc.getScratchpadSrcAddress())
case VM_ISUB_MZ:
*ibc.idst -= vm.Load64(ibc.getScratchpadZeroAddress())
case VM_IMUL_R:
// also handles imul_rcp
*ibc.idst *= *ibc.isrc
case VM_IMUL_M:
*ibc.idst *= vm.Load64(ibc.getScratchpadSrcAddress())
case VM_IMUL_MZ:
*ibc.idst *= vm.Load64(ibc.getScratchpadZeroAddress())
case VM_IMULH_R:
*ibc.idst, _ = bits.Mul64(*ibc.idst, *ibc.isrc)
case VM_IMULH_M:
*ibc.idst, _ = bits.Mul64(*ibc.idst, vm.Load64(ibc.getScratchpadSrcAddress()))
case VM_IMULH_MZ:
*ibc.idst, _ = bits.Mul64(*ibc.idst, vm.Load64(ibc.getScratchpadZeroAddress()))
case VM_ISMULH_R:
*ibc.idst = smulh(int64(*ibc.idst), int64(*ibc.isrc))
case VM_ISMULH_M:
*ibc.idst = smulh(int64(*ibc.idst), int64(vm.Load64(ibc.getScratchpadSrcAddress())))
case VM_ISMULH_MZ:
*ibc.idst = smulh(int64(*ibc.idst), int64(vm.Load64(ibc.getScratchpadZeroAddress())))
case VM_INEG_R:
*ibc.idst = (^(*ibc.idst)) + 1 // 2's complement negative
case VM_IXOR_R:
*ibc.idst ^= *ibc.isrc
case VM_IXOR_M:
*ibc.idst ^= vm.Load64(ibc.getScratchpadSrcAddress())
case VM_IXOR_MZ:
*ibc.idst ^= vm.Load64(ibc.getScratchpadZeroAddress())
case VM_IROR_R:
*ibc.idst = bits.RotateLeft64(*ibc.idst, 0-int(*ibc.isrc&63))
case VM_IROL_R:
*ibc.idst = bits.RotateLeft64(*ibc.idst, int(*ibc.isrc&63))
case VM_ISWAP_R:
*ibc.idst, *ibc.isrc = *ibc.isrc, *ibc.idst
case VM_FSWAP_R:
ibc.fdst[HIGH], ibc.fdst[LOW] = ibc.fdst[LOW], ibc.fdst[HIGH]
case VM_FADD_R:
ibc.fdst[LOW] += ibc.fsrc[LOW]
ibc.fdst[HIGH] += ibc.fsrc[HIGH]
case VM_FADD_M:
lo, hi := vm.Load32F(ibc.getScratchpadSrcAddress())
ibc.fdst[LOW] += lo
ibc.fdst[HIGH] += hi
case VM_FSUB_R:
ibc.fdst[LOW] -= ibc.fsrc[LOW]
ibc.fdst[HIGH] -= ibc.fsrc[HIGH]
case VM_FSUB_M:
lo, hi := vm.Load32F(ibc.getScratchpadSrcAddress())
ibc.fdst[LOW] -= lo
ibc.fdst[HIGH] -= hi
case VM_FSCAL_R:
// no dependent on rounding modes
ibc.fdst[LOW] = math.Float64frombits(math.Float64bits(ibc.fdst[LOW]) ^ 0x80F0000000000000)
ibc.fdst[HIGH] = math.Float64frombits(math.Float64bits(ibc.fdst[HIGH]) ^ 0x80F0000000000000)
case VM_FMUL_R:
ibc.fdst[LOW] *= ibc.fsrc[LOW]
ibc.fdst[HIGH] *= ibc.fsrc[HIGH]
case VM_FDIV_M:
lo, hi := vm.Load32F(ibc.getScratchpadSrcAddress())
ibc.fdst[LOW] /= MaskRegisterExponentMantissa(lo, vm.config.eMask[LOW])
ibc.fdst[HIGH] /= MaskRegisterExponentMantissa(hi, vm.config.eMask[HIGH])
case VM_FSQRT_R:
ibc.fdst[LOW] = math.Sqrt(ibc.fdst[LOW])
ibc.fdst[HIGH] = math.Sqrt(ibc.fdst[HIGH])
case VM_CBRANCH:
*ibc.isrc += ibc.imm
if (*ibc.isrc & uint64(ibc.memMask)) == 0 {
pc = int(ibc.target)
}
case VM_CFROUND:
tmp := (bits.RotateLeft64(*ibc.isrc, 0-int(ibc.imm))) % 4 // rotate right
asm.SetRoundingMode(asm.RoundingMode(tmp))
case VM_ISTORE:
binary.LittleEndian.PutUint64(vm.ScratchPad[(*ibc.idst+ibc.imm)&uint64(ibc.memMask):], *ibc.isrc)
case VM_NOP: // we do nothing
}
}
}
type ByteCodeInstructionOp int
const (
VM_NOP = ByteCodeInstructionOp(iota)
VM_IADD_RS
VM_IADD_M
VM_IADD_MZ
VM_ISUB_R
VM_ISUB_M
VM_ISUB_MZ
VM_IMUL_R
VM_IMUL_M
VM_IMUL_MZ
VM_IMULH_R
VM_IMULH_M
VM_IMULH_MZ
VM_ISMULH_R
VM_ISMULH_M
VM_ISMULH_MZ
VM_IMUL_RCP
VM_INEG_R
VM_IXOR_R
VM_IXOR_M
VM_IXOR_MZ
VM_IROR_R
VM_IROL_R
VM_ISWAP_R
VM_FSWAP_R
VM_FADD_R
VM_FADD_M
VM_FSUB_R
VM_FSUB_M
VM_FSCAL_R
VM_FMUL_R
VM_FDIV_M
VM_FSQRT_R
VM_CBRANCH
VM_CFROUND
VM_ISTORE
)

View file

@ -90,9 +90,6 @@ const CONDITIONOFFSET = RANDOMX_JUMP_OFFSET
const CONDITIONMASK = ((1 << RANDOMX_JUMP_BITS) - 1)
const STOREL3CONDITION = 14
const REGISTERSCOUNT = 8
const REGISTERCOUNTFLT = 4
const mantissaSize = 52
const exponentSize = 11
const mantissaMask = (uint64(1) << mantissaSize) - 1

View file

@ -1,3 +1,17 @@
package randomx
type RegisterLine [REGISTERSCOUNT]uint64
const RegistersCount = 8
const RegistersCountFloat = 4
type RegisterLine [RegistersCount]uint64
type RegisterFile struct {
r RegisterLine
f [RegistersCountFloat][2]float64
e [RegistersCountFloat][2]float64
a [RegistersCountFloat][2]float64
}
type MemoryRegisters struct {
mx, ma uint64
}

View file

@ -85,8 +85,8 @@ func generateSuperscalarCode(scalarProgram SuperScalarProgram) ProgramFunc {
for i := range p {
instr := &p[i]
dst := instr.Dst_Reg % REGISTERSCOUNT
src := instr.Src_Reg % REGISTERSCOUNT
dst := instr.Dst_Reg % RegistersCount
src := instr.Src_Reg % RegistersCount
switch instr.Opcode {
case S_ISUB_R:

30
vm.go
View file

@ -49,13 +49,13 @@ type VM struct {
Prog []byte
ScratchPad [ScratchpadSize]byte
ByteCode [RANDOMX_PROGRAM_SIZE]InstructionByteCode
ByteCode ByteCode
// program configuration see program.hpp
entropy [16]uint64
reg REGISTER_FILE // the register file
reg RegisterFile // the register file
mem MemoryRegisters
config Config // configuration
datasetOffset uint64
@ -75,16 +75,6 @@ type Config struct {
readReg [4]uint64
}
type REGISTER_FILE struct {
r RegisterLine
f [4][2]float64
e [4][2]float64
a [4][2]float64
}
type MemoryRegisters struct {
mx, ma uint64
}
const LOW = 0
const HIGH = 1
@ -120,7 +110,7 @@ func (vm *VM) Run(input_hash [64]byte) {
vm.config.eMask[LOW] = getFloatMask(vm.entropy[14])
vm.config.eMask[HIGH] = getFloatMask(vm.entropy[15])
vm.Compile_TO_Bytecode()
vm.CompileToBytecode()
spAddr0 := vm.mem.mx
spAddr1 := vm.mem.ma
@ -135,23 +125,23 @@ func (vm *VM) Run(input_hash [64]byte) {
spAddr1 ^= spMix >> 32
spAddr1 &= ScratchpadL3Mask64
for i := uint64(0); i < REGISTERSCOUNT; i++ {
for i := uint64(0); i < RegistersCount; i++ {
vm.reg.r[i] ^= vm.Load64(spAddr0 + 8*i)
}
for i := uint64(0); i < REGISTERCOUNTFLT; i++ {
for i := uint64(0); i < RegistersCountFloat; i++ {
vm.reg.f[i] = vm.Load32FA(spAddr1 + 8*i)
}
for i := uint64(0); i < REGISTERCOUNTFLT; i++ {
vm.reg.e[i] = vm.Load32FA(spAddr1 + 8*(i+REGISTERCOUNTFLT))
for i := uint64(0); i < RegistersCountFloat; i++ {
vm.reg.e[i] = vm.Load32FA(spAddr1 + 8*(i+RegistersCountFloat))
vm.reg.e[i][LOW] = MaskRegisterExponentMantissa(vm.reg.e[i][LOW], vm.config.eMask[LOW])
vm.reg.e[i][HIGH] = MaskRegisterExponentMantissa(vm.reg.e[i][HIGH], vm.config.eMask[HIGH])
}
// todo: pass register file directly!
vm.InterpretByteCode()
vm.ByteCode.Interpret(vm)
vm.mem.mx ^= vm.reg.r[vm.config.readReg[2]] ^ vm.reg.r[vm.config.readReg[3]]
vm.mem.mx &= CacheLineAlignMask
@ -163,11 +153,11 @@ func (vm *VM) Run(input_hash [64]byte) {
// swap the elements
vm.mem.mx, vm.mem.ma = vm.mem.ma, vm.mem.mx
for i := uint64(0); i < REGISTERSCOUNT; i++ {
for i := uint64(0); i < RegistersCount; i++ {
binary.LittleEndian.PutUint64(vm.ScratchPad[spAddr1+8*i:], vm.reg.r[i])
}
for i := uint64(0); i < REGISTERCOUNTFLT; i++ {
for i := uint64(0); i < RegistersCountFloat; i++ {
vm.reg.f[i][LOW] = math.Float64frombits(math.Float64bits(vm.reg.f[i][LOW]) ^ math.Float64bits(vm.reg.e[i][LOW]))
vm.reg.f[i][HIGH] = math.Float64frombits(math.Float64bits(vm.reg.f[i][HIGH]) ^ math.Float64bits(vm.reg.e[i][HIGH]))

View file

@ -30,17 +30,12 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package randomx
import (
"git.gammaspectra.live/P2Pool/go-randomx/v2/asm"
"math"
"math/bits"
"unsafe"
)
import "encoding/binary"
//reference https://github.com/tevador/RandomX/blob/master/doc/specs.md#51-instruction-encoding
var Zero uint64 = 0
// since go does not have union, use byte array
type VM_Instruction []byte // it is hardcode 8 bytes
@ -60,80 +55,11 @@ func (ins VM_Instruction) Opcode() byte {
return ins[0]
}
type VM_Instruction_Type int
const (
VM_IADD_RS VM_Instruction_Type = 0
VM_IADD_M VM_Instruction_Type = 1
VM_ISUB_R VM_Instruction_Type = 2
VM_ISUB_M VM_Instruction_Type = 3
VM_IMUL_R VM_Instruction_Type = 4
VM_IMUL_M VM_Instruction_Type = 5
VM_IMULH_R VM_Instruction_Type = 6
VM_IMULH_M VM_Instruction_Type = 7
VM_ISMULH_R VM_Instruction_Type = 8
VM_ISMULH_M VM_Instruction_Type = 9
VM_IMUL_RCP VM_Instruction_Type = 10
VM_INEG_R VM_Instruction_Type = 11
VM_IXOR_R VM_Instruction_Type = 12
VM_IXOR_M VM_Instruction_Type = 13
VM_IROR_R VM_Instruction_Type = 14
VM_IROL_R VM_Instruction_Type = 15
VM_ISWAP_R VM_Instruction_Type = 16
VM_FSWAP_R VM_Instruction_Type = 17
VM_FADD_R VM_Instruction_Type = 18
VM_FADD_M VM_Instruction_Type = 19
VM_FSUB_R VM_Instruction_Type = 20
VM_FSUB_M VM_Instruction_Type = 21
VM_FSCAL_R VM_Instruction_Type = 22
VM_FMUL_R VM_Instruction_Type = 23
VM_FDIV_M VM_Instruction_Type = 24
VM_FSQRT_R VM_Instruction_Type = 25
VM_CBRANCH VM_Instruction_Type = 26
VM_CFROUND VM_Instruction_Type = 27
VM_ISTORE VM_Instruction_Type = 28
VM_NOP VM_Instruction_Type = 29
)
var Names = map[VM_Instruction_Type]string{
VM_IADD_RS: "VM_IADD_RS",
VM_IADD_M: "VM_IADD_M",
VM_ISUB_R: "VM_ISUB_R",
VM_ISUB_M: "VM_ISUB_M",
VM_IMUL_R: "VM_IMUL_R",
VM_IMUL_M: "VM_IMUL_M",
VM_IMULH_R: "VM_IMULH_R",
VM_IMULH_M: "VM_IMULH_M",
VM_ISMULH_R: "VM_ISMULH_R",
VM_ISMULH_M: "VM_ISMULH_M",
VM_IMUL_RCP: "VM_IMUL_RCP",
VM_INEG_R: "VM_INEG_R",
VM_IXOR_R: "VM_IXOR_R",
VM_IXOR_M: "VM_IXOR_M",
VM_IROR_R: "VM_IROR_R",
VM_IROL_R: "VM_IROL_R",
VM_ISWAP_R: "VM_ISWAP_R",
VM_FSWAP_R: "VM_FSWAP_R",
VM_FADD_R: "VM_FADD_R",
VM_FADD_M: "VM_FADD_M",
VM_FSUB_R: "VM_FSUB_R",
VM_FSUB_M: "VM_FSUB_M",
VM_FSCAL_R: "VM_FSCAL_R",
VM_FMUL_R: "VM_FMUL_R",
VM_FDIV_M: "VM_FDIV_M",
VM_FSQRT_R: "VM_FSQRT_R",
VM_CBRANCH: "VM_CBRANCH",
VM_CFROUND: "VM_CFROUND",
VM_ISTORE: "VM_ISTORE",
VM_NOP: "VM_NOP",
}
// this will interpret single vm instruction
// CompileToBytecode this will interpret single vm instruction
// reference https://github.com/tevador/RandomX/blob/master/doc/specs.md#52-integer-instructions
func (vm *VM) Compile_TO_Bytecode() {
func (vm *VM) CompileToBytecode() {
var registerUsage [REGISTERSCOUNT]int
var registerUsage [RegistersCount]int
for i := range registerUsage {
registerUsage[i] = -1
}
@ -143,8 +69,8 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc := &vm.ByteCode[i]
opcode := instr.Opcode()
dst := instr.Dst() % REGISTERSCOUNT // bit shift optimization
src := instr.Src() % REGISTERSCOUNT
dst := instr.Dst() % RegistersCount // bit shift optimization
src := instr.Src() % RegistersCount
ibc.dst = dst
ibc.src = src
switch opcode {
@ -174,7 +100,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_IADD_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -202,7 +128,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_ISUB_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -230,7 +156,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_IMUL_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -251,7 +177,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_IMULH_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -272,7 +198,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_ISMULH_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -316,7 +242,7 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.memMask = ScratchpadL2Mask
}
} else {
ibc.isrc = &Zero
ibc.Opcode = VM_IXOR_MZ
ibc.memMask = ScratchpadL3Mask
}
registerUsage[dst] = i
@ -360,20 +286,20 @@ func (vm *VM) Compile_TO_Bytecode() {
// below are floating point instructions
case 120, 121, 122, 123: // 4
ibc.Opcode = VM_FSWAP_R
if dst < REGISTERCOUNTFLT {
if dst < RegistersCountFloat {
ibc.fdst = &vm.reg.f[dst]
} else {
ibc.fdst = &vm.reg.e[dst-REGISTERCOUNTFLT]
ibc.fdst = &vm.reg.e[dst-RegistersCountFloat]
}
case 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139: //16
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
src := instr.Src() % REGISTERCOUNTFLT
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
src := instr.Src() % RegistersCountFloat
ibc.Opcode = VM_FADD_R
ibc.fdst = &vm.reg.f[dst]
ibc.fsrc = &vm.reg.a[src]
case 140, 141, 142, 143, 144: //5
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
ibc.Opcode = VM_FADD_M
ibc.fdst = &vm.reg.f[dst]
ibc.isrc = &vm.reg.r[src]
@ -385,13 +311,13 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.imm = signExtend2sCompl(instr.IMM())
case 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160: //16
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
src := instr.Src() % REGISTERCOUNTFLT
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
src := instr.Src() % RegistersCountFloat
ibc.Opcode = VM_FSUB_R
ibc.fdst = &vm.reg.f[dst]
ibc.fsrc = &vm.reg.a[src]
case 161, 162, 163, 164, 165: //5
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
ibc.Opcode = VM_FSUB_M
ibc.fdst = &vm.reg.f[dst]
ibc.isrc = &vm.reg.r[src]
@ -403,17 +329,17 @@ func (vm *VM) Compile_TO_Bytecode() {
ibc.imm = signExtend2sCompl(instr.IMM())
case 166, 167, 168, 169, 170, 171: //6
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
ibc.Opcode = VM_FSCAL_R
ibc.fdst = &vm.reg.f[dst]
case 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203: //32
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
src := instr.Src() % REGISTERCOUNTFLT
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
src := instr.Src() % RegistersCountFloat
ibc.Opcode = VM_FMUL_R
ibc.fdst = &vm.reg.e[dst]
ibc.fsrc = &vm.reg.a[src]
case 204, 205, 206, 207: //4
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
ibc.Opcode = VM_FDIV_M
ibc.fdst = &vm.reg.e[dst]
ibc.isrc = &vm.reg.r[src]
@ -424,13 +350,13 @@ func (vm *VM) Compile_TO_Bytecode() {
}
ibc.imm = signExtend2sCompl(instr.IMM())
case 208, 209, 210, 211, 212, 213: //6
dst := instr.Dst() % REGISTERCOUNTFLT // bit shift optimization
dst := instr.Dst() % RegistersCountFloat // bit shift optimization
ibc.Opcode = VM_FSQRT_R
ibc.fdst = &vm.reg.e[dst]
case 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238: //25 // CBRANCH and CFROUND are interchanged
ibc.Opcode = VM_CBRANCH
reg := instr.Dst() % REGISTERSCOUNT
reg := instr.Dst() % RegistersCount
ibc.isrc = &vm.reg.r[reg]
ibc.target = int16(registerUsage[reg])
shift := uint64(instr.Mod()>>4) + CONDITIONOFFSET
@ -441,7 +367,7 @@ func (vm *VM) Compile_TO_Bytecode() {
}
ibc.memMask = CONDITIONMASK << shift
for j := 0; j < REGISTERSCOUNT; j++ {
for j := 0; j < RegistersCount; j++ {
registerUsage[j] = i
}
@ -474,47 +400,6 @@ func (vm *VM) Compile_TO_Bytecode() {
}
type InstructionByteCode struct {
dst, src byte
idst, isrc *uint64
fdst, fsrc *[2]float64
imm uint64
simm int64
Opcode VM_Instruction_Type
target int16
shift uint8
memMask uint32
/*
union {
int_reg_t* idst;
rx_vec_f128* fdst;
};
union {
int_reg_t* isrc;
rx_vec_f128* fsrc;
};
union {
uint64_t imm;
int64_t simm;
};
InstructionType type;
union {
int16_t target;
uint16_t shift;
};
uint32_t memMask;
*/
}
func (ibc *InstructionByteCode) getScratchpadAddress() uint64 {
return (*ibc.isrc + ibc.imm) & uint64(ibc.memMask)
}
func (ibc *InstructionByteCode) getScratchpadDestAddress() uint64 {
return (*ibc.idst + ibc.imm) & uint64(ibc.memMask)
}
func (vm *VM) Load64(addr uint64) uint64 {
return *(*uint64)(unsafe.Pointer(&vm.ScratchPad[addr]))
}
@ -531,85 +416,3 @@ func (vm *VM) Load32FA(addr uint64) [2]float64 {
a := *(*[2]int32)(unsafe.Pointer(&vm.ScratchPad[addr]))
return [2]float64{float64(a[LOW]), float64(a[HIGH])}
}
func (vm *VM) InterpretByteCode() {
for pc := 0; pc < RANDOMX_PROGRAM_SIZE; pc++ {
ibc := &vm.ByteCode[pc]
switch ibc.Opcode {
case VM_IADD_RS:
*ibc.idst += (*ibc.isrc << ibc.shift) + ibc.imm
case VM_IADD_M:
*ibc.idst += vm.Load64(ibc.getScratchpadAddress())
case VM_ISUB_R:
*ibc.idst -= *ibc.isrc
case VM_ISUB_M:
*ibc.idst -= vm.Load64(ibc.getScratchpadAddress())
case VM_IMUL_R:
// also handles imul_rcp
*ibc.idst *= *ibc.isrc
case VM_IMUL_M:
*ibc.idst *= vm.Load64(ibc.getScratchpadAddress())
case VM_IMULH_R:
*ibc.idst, _ = bits.Mul64(*ibc.idst, *ibc.isrc)
case VM_IMULH_M:
*ibc.idst, _ = bits.Mul64(*ibc.idst, vm.Load64(ibc.getScratchpadAddress()))
case VM_ISMULH_R:
*ibc.idst = smulh(int64(*ibc.idst), int64(*ibc.isrc))
case VM_ISMULH_M:
*ibc.idst = smulh(int64(*ibc.idst), int64(vm.Load64(ibc.getScratchpadAddress())))
case VM_INEG_R:
*ibc.idst = (^(*ibc.idst)) + 1 // 2's complement negative
case VM_IXOR_R:
*ibc.idst ^= *ibc.isrc
case VM_IXOR_M:
*ibc.idst ^= vm.Load64(ibc.getScratchpadAddress())
case VM_IROR_R:
*ibc.idst = bits.RotateLeft64(*ibc.idst, 0-int(*ibc.isrc&63))
case VM_IROL_R:
*ibc.idst = bits.RotateLeft64(*ibc.idst, int(*ibc.isrc&63))
case VM_ISWAP_R:
*ibc.idst, *ibc.isrc = *ibc.isrc, *ibc.idst
case VM_FSWAP_R:
ibc.fdst[HIGH], ibc.fdst[LOW] = ibc.fdst[LOW], ibc.fdst[HIGH]
case VM_FADD_R:
ibc.fdst[LOW] += ibc.fsrc[LOW]
ibc.fdst[HIGH] += ibc.fsrc[HIGH]
case VM_FADD_M:
lo, hi := vm.Load32F(ibc.getScratchpadAddress())
ibc.fdst[LOW] += lo
ibc.fdst[HIGH] += hi
case VM_FSUB_R:
ibc.fdst[LOW] -= ibc.fsrc[LOW]
ibc.fdst[HIGH] -= ibc.fsrc[HIGH]
case VM_FSUB_M:
lo, hi := vm.Load32F(ibc.getScratchpadAddress())
ibc.fdst[LOW] -= lo
ibc.fdst[HIGH] -= hi
case VM_FSCAL_R:
// no dependent on rounding modes
ibc.fdst[LOW] = math.Float64frombits(math.Float64bits(ibc.fdst[LOW]) ^ 0x80F0000000000000)
ibc.fdst[HIGH] = math.Float64frombits(math.Float64bits(ibc.fdst[HIGH]) ^ 0x80F0000000000000)
case VM_FMUL_R:
ibc.fdst[LOW] *= ibc.fsrc[LOW]
ibc.fdst[HIGH] *= ibc.fsrc[HIGH]
case VM_FDIV_M:
lo, hi := vm.Load32F(ibc.getScratchpadAddress())
ibc.fdst[LOW] /= MaskRegisterExponentMantissa(lo, vm.config.eMask[LOW])
ibc.fdst[HIGH] /= MaskRegisterExponentMantissa(hi, vm.config.eMask[HIGH])
case VM_FSQRT_R:
ibc.fdst[LOW] = math.Sqrt(ibc.fdst[LOW])
ibc.fdst[HIGH] = math.Sqrt(ibc.fdst[HIGH])
case VM_CBRANCH:
*ibc.isrc += ibc.imm
if (*ibc.isrc & uint64(ibc.memMask)) == 0 {
pc = int(ibc.target)
}
case VM_CFROUND:
tmp := (bits.RotateLeft64(*ibc.isrc, 0-int(ibc.imm))) % 4 // rotate right
asm.SetRoundingMode(asm.RoundingMode(tmp))
case VM_ISTORE:
binary.LittleEndian.PutUint64(vm.ScratchPad[(*ibc.idst+ibc.imm)&uint64(ibc.memMask):], *ibc.isrc)
case VM_NOP: // we do nothing
}
}
}