go-randomx/superscalar_instruction.go
DataHoarder 8b063bde61
All checks were successful
continuous-integration/drone/push Build is passing
Match functionality / API with upstream randomx
2024-05-02 02:25:17 +02:00

158 lines
3.7 KiB
Go

package randomx
import "git.gammaspectra.live/P2Pool/go-randomx/v3/internal/blake2"
// SuperScalarInstruction superscalar program is built with superscalar instructions
type SuperScalarInstruction struct {
Opcode byte
Dst uint8
Src uint8
Mod byte
Imm32 uint32
Imm64 uint64
OpGroup int
OpGroupPar int
GroupParIsSource int
ins *Instruction
CanReuse bool
}
func (sins *SuperScalarInstruction) FixSrcReg() {
if sins.Src == 0xff {
sins.Src = sins.Dst
}
}
func (sins *SuperScalarInstruction) Reset() {
sins.Opcode = 99
sins.Src = 0xff
sins.Dst = 0xff
sins.CanReuse = false
sins.GroupParIsSource = 0
}
func createSuperScalarInstruction(sins *SuperScalarInstruction, ins *Instruction, gen *blake2.Generator) {
sins.Reset()
sins.ins = ins
sins.OpGroupPar = -1
sins.Opcode = ins.Opcode
switch ins.Opcode {
case S_ISUB_R:
sins.Mod = 0
sins.Imm32 = 0
sins.OpGroup = S_IADD_RS
sins.GroupParIsSource = 1
case S_IXOR_R:
sins.Mod = 0
sins.Imm32 = 0
sins.OpGroup = S_IXOR_R
sins.GroupParIsSource = 1
case S_IADD_RS:
sins.Mod = gen.GetByte()
// set modshift on Imm32
sins.Imm32 = uint32((sins.Mod >> 2) % 4) // bits 2-3
//sins.Imm32 = 0
sins.OpGroup = S_IADD_RS
sins.GroupParIsSource = 1
case S_IMUL_R:
sins.Mod = 0
sins.Imm32 = 0
sins.OpGroup = S_IMUL_R
sins.GroupParIsSource = 1
case S_IROR_C:
sins.Mod = 0
for sins.Imm32 = 0; sins.Imm32 == 0; {
sins.Imm32 = uint32(gen.GetByte() & 63)
}
sins.OpGroup = S_IROR_C
sins.OpGroupPar = -1
case S_IADD_C7, S_IADD_C8, S_IADD_C9:
sins.Mod = 0
sins.Imm32 = gen.GetUint32()
sins.OpGroup = S_IADD_C7
sins.OpGroupPar = -1
case S_IXOR_C7, S_IXOR_C8, S_IXOR_C9:
sins.Mod = 0
sins.Imm32 = gen.GetUint32()
sins.OpGroup = S_IXOR_C7
sins.OpGroupPar = -1
case S_IMULH_R:
sins.CanReuse = true
sins.Mod = 0
sins.Imm32 = 0
sins.OpGroup = S_IMULH_R
sins.OpGroupPar = int(gen.GetUint32())
case S_ISMULH_R:
sins.CanReuse = true
sins.Mod = 0
sins.Imm32 = 0
sins.OpGroup = S_ISMULH_R
sins.OpGroupPar = int(gen.GetUint32())
case S_IMUL_RCP:
sins.Mod = 0
for {
sins.Imm32 = gen.GetUint32()
if (sins.Imm32&sins.Imm32 - 1) != 0 {
break
}
}
sins.Imm64 = reciprocal(sins.Imm32)
sins.OpGroup = S_IMUL_RCP
default:
panic("should not occur")
}
}
var slot3 = []*Instruction{&ISUB_R, &IXOR_R} // 3 length instruction will be filled with these
var slot3L = []*Instruction{&ISUB_R, &IXOR_R, &IMULH_R, &ISMULH_R}
var slot4 = []*Instruction{&IROR_C, &IADD_RS}
var slot7 = []*Instruction{&IXOR_C7, &IADD_C7}
var slot8 = []*Instruction{&IXOR_C8, &IADD_C8}
var slot9 = []*Instruction{&IXOR_C9, &IADD_C9}
var slot10 = []*Instruction{&IMUL_RCP}
func CreateSuperScalarInstruction(sins *SuperScalarInstruction, gen *blake2.Generator, instructionLen int, decoderType DecoderType, last, first bool) {
switch instructionLen {
case 3:
if last {
createSuperScalarInstruction(sins, slot3L[gen.GetByte()&3], gen)
} else {
createSuperScalarInstruction(sins, slot3[gen.GetByte()&1], gen)
}
case 4:
//if this is the 4-4-4-4 buffer, issue multiplications as the first 3 instructions
if decoderType == Decoder4444 && !last {
createSuperScalarInstruction(sins, &IMUL_R, gen)
} else {
createSuperScalarInstruction(sins, slot4[gen.GetByte()&1], gen)
}
case 7:
createSuperScalarInstruction(sins, slot7[gen.GetByte()&1], gen)
case 8:
createSuperScalarInstruction(sins, slot8[gen.GetByte()&1], gen)
case 9:
createSuperScalarInstruction(sins, slot9[gen.GetByte()&1], gen)
case 10:
createSuperScalarInstruction(sins, slot10[0], gen)
default:
panic("should not be possible")
}
}