redo JIT superscalar to include less custom assembly

This commit is contained in:
DataHoarder 2024-04-19 10:41:55 +02:00
parent a71d8f6a2e
commit 34cfab4176
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
8 changed files with 82 additions and 90 deletions

View file

@ -12,8 +12,7 @@ type MemoryBlock [128]uint64
func (m *MemoryBlock) GetLine(addr uint64) *RegisterLine {
addr >>= 3
//[addr : addr+8 : addr+8]
return (*RegisterLine)(unsafe.Add(unsafe.Pointer(m), addr*8))
return (*RegisterLine)(unsafe.Pointer(unsafe.SliceData(m[addr : addr+8 : addr+8])))
}
type Randomx_Cache struct {
@ -21,7 +20,7 @@ type Randomx_Cache struct {
Programs [RANDOMX_PROGRAM_COUNT]SuperScalarProgram
JitPrograms [RANDOMX_PROGRAM_COUNT]ProgramFunc
JitPrograms [RANDOMX_PROGRAM_COUNT]SuperScalarProgramFunc
Flags uint64
}

View file

@ -1,3 +1,3 @@
package randomx
type ProgramFunc []byte
type SuperScalarProgramFunc []byte

View file

@ -2,10 +2,6 @@
package randomx
func (f ProgramFunc) Execute(v uintptr) {
}
func (f ProgramFunc) Close() error {
func (f SuperScalarProgramFunc) Close() error {
return nil
}

View file

@ -4,35 +4,13 @@ package randomx
import (
"golang.org/x/sys/unix"
"runtime"
"unsafe"
)
func (f ProgramFunc) Execute(v uintptr) {
if f == nil {
panic("program is nil")
}
var reservedStackHack [8 * 8]byte
for i := range reservedStackHack {
reservedStackHack[i] = uint8(i)
}
memoryPtr := &f
fun := *(*func(v uintptr))(unsafe.Pointer(&memoryPtr))
fun(v)
for i := range reservedStackHack {
reservedStackHack[i] = uint8(-i)
}
runtime.KeepAlive(reservedStackHack)
}
func (f ProgramFunc) Close() error {
func (f SuperScalarProgramFunc) Close() error {
return unix.Munmap(f)
}
func mapProgram(program []byte) ProgramFunc {
func mapProgram(program []byte) []byte {
// Write only
execFunc, err := unix.Mmap(-1, 0, len(program), unix.PROT_WRITE, unix.MAP_PRIVATE|unix.MAP_ANONYMOUS)
if err != nil {

View file

@ -11,8 +11,8 @@ package randomx
; rcx -> temporary
; rdx -> temporary
; rsi -> scratchpad pointer
; rdi -> dataset pointer
; rbp -> memory registers "ma" (high 32 bits), "mx" (low 32 bits)
; rdi -> return address // dataset pointer
; rbp -> (do not use, it's used by Golang sampling) jump target //todo: memory registers "ma" (high 32 bits), "mx" (low 32 bits)
; rsp -> stack pointer
; r8 -> "r0"
; r9 -> "r1"
@ -154,53 +154,3 @@ var NOP8 = []byte{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}
func genSIB(scale, index, base int) byte {
return byte((scale << 6) | (index << 3) | base)
}
/*
push rbp
push rbx
push rsi
push r12
push r13
push r14
push r15
mov rbp,rsp
sub rsp,(0x8*7)
mov rsi, rax; # register dataset
prefetchnta byte ptr [rsi]
mov r8, qword ptr [rsi+0]
mov r9, qword ptr [rsi+8]
mov r10, qword ptr [rsi+16]
mov r11, qword ptr [rsi+24]
mov r12, qword ptr [rsi+32]
mov r13, qword ptr [rsi+40]
mov r14, qword ptr [rsi+48]
mov r15, qword ptr [rsi+56]
*/
var codeInitBlock = []byte{0x55, 0x53, 0x56, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x38, 0x48, 0x89, 0xC6, 0x0F, 0x18, 0x06, 0x4C, 0x8B, 0x06, 0x4C, 0x8B, 0x4E, 0x08, 0x4C, 0x8B, 0x56, 0x10, 0x4C, 0x8B, 0x5E, 0x18, 0x4C, 0x8B, 0x66, 0x20, 0x4C, 0x8B, 0x6E, 0x28, 0x4C, 0x8B, 0x76, 0x30, 0x4C, 0x8B, 0x7E, 0x38}
/*
prefetchw byte ptr [rsi]
mov qword ptr [rsi+0], r8
mov qword ptr [rsi+8], r9
mov qword ptr [rsi+16], r10
mov qword ptr [rsi+24], r11
mov qword ptr [rsi+32], r12
mov qword ptr [rsi+40], r13
mov qword ptr [rsi+48], r14
mov qword ptr [rsi+56], r15
add rsp,(0x8*7)
pop r15
pop r14
pop r13
pop r12
pop rsi
pop rbx
pop rbp
ret
*/
var codeRetBlock = []byte{0x0F, 0x0D, 0x0E, 0x4C, 0x89, 0x06, 0x4C, 0x89, 0x4E, 0x08, 0x4C, 0x89, 0x56, 0x10, 0x4C, 0x89, 0x5E, 0x18, 0x4C, 0x89, 0x66, 0x20, 0x4C, 0x89, 0x6E, 0x28, 0x4C, 0x89, 0x76, 0x30, 0x4C, 0x89, 0x7E, 0x38, 0x48, 0x83, 0xC4, 0x38, 0x41, 0x5F, 0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x5E, 0x5B, 0x5D, 0xC3}

View file

@ -4,15 +4,41 @@ package randomx
import (
"encoding/binary"
"runtime"
"unsafe"
)
//go:noescape
func superscalar_run(rf, jmp uintptr)
func (f SuperScalarProgramFunc) Execute(rf uintptr) {
if f == nil {
panic("program is nil")
}
superscalar_run(rf, uintptr(unsafe.Pointer(unsafe.SliceData(f))))
return
var reservedStackHack [8 * 8]byte
for i := range reservedStackHack {
reservedStackHack[i] = uint8(i)
}
memoryPtr := &f
fun := *(*func(v uintptr))(unsafe.Pointer(&memoryPtr))
fun(rf)
for i := range reservedStackHack {
reservedStackHack[i] = uint8(-i)
}
runtime.KeepAlive(reservedStackHack)
}
// generateSuperscalarCode
func generateSuperscalarCode(scalarProgram SuperScalarProgram) ProgramFunc {
func generateSuperscalarCode(scalarProgram SuperScalarProgram) SuperScalarProgramFunc {
var program []byte
program = append(program, codeInitBlock...)
p := scalarProgram.Program()
for i := range p {
instr := &p[i]
@ -78,7 +104,7 @@ func generateSuperscalarCode(scalarProgram SuperScalarProgram) ProgramFunc {
}
}
program = append(program, codeRetBlock...)
program = append(program, RET)
return mapProgram(program)
}

39
superscalar_jit_amd64.s Normal file
View file

@ -0,0 +1,39 @@
//go:build unix && amd64 && !disable_jit && !purego
#include "textflag.h"
TEXT ·superscalar_run(SB),$0-16
MOVQ rf+0(FP), SI
PREFETCHNTA 0(SI)
// move register line to registers
MOVQ 0(SI), R8
MOVQ 8(SI), R9
MOVQ 16(SI), R10
MOVQ 24(SI), R11
MOVQ 32(SI), R12
MOVQ 40(SI), R13
MOVQ 48(SI), R14
MOVQ 56(SI), R15
MOVQ jmp+8(FP), AX
// jump to JIT code
CALL AX
// todo: not supported by golang
// PREFETCHW 0(SI)
// move registers back to register line
MOVQ R8, 0(SI)
MOVQ R9, 8(SI)
MOVQ R10, 16(SI)
MOVQ R11, 24(SI)
MOVQ R12, 32(SI)
MOVQ R13, 40(SI)
MOVQ R14, 48(SI)
MOVQ R15, 56(SI)
RET

View file

@ -2,7 +2,11 @@
package randomx
func (f SuperScalarProgramFunc) Execute(rf uintptr) {
}
// generateSuperscalarCode
func generateSuperscalarCode(scalarProgram SuperScalarProgram) ProgramFunc {
func generateSuperscalarCode(scalarProgram SuperScalarProgram) SuperScalarProgramFunc {
return nil
}