Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

amd64: removes embeddings of pointers of bit masks for FP arithmetics #648

Merged
merged 2 commits into from Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions internal/asm/amd64/assembler.go
Expand Up @@ -88,7 +88,11 @@ type Assembler interface {
// the destination is the constant `value`.
CompileMemoryToConst(instruction asm.Instruction, srcBaseReg asm.Register, srcOffset int64, value int64) asm.Node

// CompileLoadStaticConstToRegister adds an instruction where the source operand is asm.StaticConst located in the
// CompileStaticConstToRegister adds an instruction where the source operand is asm.StaticConst located in the
// memory and the destination is the dstReg.
CompileLoadStaticConstToRegister(instruction asm.Instruction, c asm.StaticConst, dstReg asm.Register) error
CompileStaticConstToRegister(instruction asm.Instruction, c asm.StaticConst, dstReg asm.Register) error

// CompileRegisterToStaticConst adds an instruction where the destination operand is asm.StaticConst located in the
// memory and the source is the srcReg.
CompileRegisterToStaticConst(instruction asm.Instruction, srcReg asm.Register, c asm.StaticConst) error
}
2 changes: 1 addition & 1 deletion internal/asm/amd64/consts.go
Expand Up @@ -167,7 +167,7 @@ const (
MOVBQSX
// MOVBQZX is the MOVZX instruction for single-byte in 64-bit mode. https://www.felixcloutier.com/x86/movzx
MOVBQZX
// MOVL is the MOV instruction for a word.
// MOVL is the MOV instruction for a double word.
MOVL
// MOVLQSX is the MOVSXD instruction. https://www.felixcloutier.com/x86/movsx:movsxd
MOVLQSX
Expand Down
3 changes: 3 additions & 0 deletions internal/asm/amd64/impl.go
Expand Up @@ -204,6 +204,7 @@ var (
OperandTypesConstToRegister = OperandTypes{OperandTypeConst, OperandTypeRegister}
OperandTypesConstToMemory = OperandTypes{OperandTypeConst, OperandTypeMemory}
OperandTypesStaticConstToRegister = OperandTypes{OperandTypeStaticConst, OperandTypeRegister}
OperandTypesRegisterToStaticConst = OperandTypes{OperandTypeRegister, OperandTypeStaticConst}
)

// String implements fmt.Stringer
Expand Down Expand Up @@ -295,6 +296,8 @@ func (a *AssemblerImpl) EncodeNode(n *NodeImpl) (err error) {
err = a.EncodeMemoryToConst(n)
case OperandTypesStaticConstToRegister:
err = a.encodeStaticConstToRegister(n)
case OperandTypesRegisterToStaticConst:
err = a.encodeRegisterToStaticConst(n)
default:
err = fmt.Errorf("encoder undefined for [%s] operand type", n.Types)
}
Expand Down
129 changes: 102 additions & 27 deletions internal/asm/amd64/impl_staticconst.go
Expand Up @@ -74,15 +74,96 @@ func (a *AssemblerImpl) maybeFlushConstants(isEndOfFunction bool) {
}
}

type staticConstOpcode struct {
opcode []byte
mandatoryPrefix byte
rex RexPrefix
}

var registerToStaticConstOpcodes = map[asm.Instruction]staticConstOpcode{
// https://www.felixcloutier.com/x86/cmp
CMPL: {opcode: []byte{0x3b}},
CMPQ: {opcode: []byte{0x3b}, rex: RexPrefixW},
}

func (a *AssemblerImpl) encodeRegisterToStaticConst(n *NodeImpl) (err error) {
opc, ok := registerToStaticConstOpcodes[n.Instruction]
if !ok {
return errorEncodingUnsupported(n)
}
return a.encodeStaticConstImpl(n, opc.opcode, opc.rex, opc.mandatoryPrefix)
}

var staticConstToRegisterOpcodes = map[asm.Instruction]struct {
opcode []byte
mandatoryPrefix byte
rex RexPrefix
}{
// https://www.felixcloutier.com/x86/movdqu:vmovdqu8:vmovdqu16:vmovdqu32:vmovdqu64
MOVDQU: {mandatoryPrefix: 0xf3, opcode: []byte{0x0f, 0x6f}},
// https://www.felixcloutier.com/x86/lea
LEAQ: {opcode: []byte{0x8d}, rex: RexPrefixW},
// https://www.felixcloutier.com/x86/movupd
MOVUPD: {mandatoryPrefix: 0x66, opcode: []byte{0x0f, 0x10}},
// https://www.felixcloutier.com/x86/mov
MOVL: {opcode: []byte{0x8b}},
MOVQ: {opcode: []byte{0x8b}, rex: RexPrefixW},
// https://www.felixcloutier.com/x86/ucomisd
UCOMISD: {opcode: []byte{0x0f, 0x2e}, mandatoryPrefix: 0x66},
// https://www.felixcloutier.com/x86/ucomiss
UCOMISS: {opcode: []byte{0x0f, 0x2e}},
// https://www.felixcloutier.com/x86/subss
SUBSS: {opcode: []byte{0x0f, 0x5c}, mandatoryPrefix: 0xf3},
// https://www.felixcloutier.com/x86/subsd
SUBSD: {opcode: []byte{0x0f, 0x5c}, mandatoryPrefix: 0xf2},
// https://www.felixcloutier.com/x86/cmp
CMPL: {opcode: []byte{0x39}},
CMPQ: {opcode: []byte{0x39}, rex: RexPrefixW},
// https://www.felixcloutier.com/x86/add
ADDL: {opcode: []byte{0x03}},
ADDQ: {opcode: []byte{0x03}, rex: RexPrefixW},
}

var staticConstToVectorRegisterOpcodes = map[asm.Instruction]staticConstOpcode{
// https://www.felixcloutier.com/x86/mov
MOVL: {opcode: []byte{0x0f, 0x6e}, mandatoryPrefix: 0x66},
MOVQ: {opcode: []byte{0x0f, 0x7e}, mandatoryPrefix: 0xf3},
}

func (a *AssemblerImpl) encodeStaticConstToRegister(n *NodeImpl) (err error) {
var opc staticConstOpcode
var ok bool
if IsVectorRegister(n.DstReg) && (n.Instruction == MOVL || n.Instruction == MOVQ) {
opc, ok = staticConstToVectorRegisterOpcodes[n.Instruction]
} else {
opc, ok = staticConstToRegisterOpcodes[n.Instruction]
}
if !ok {
return errorEncodingUnsupported(n)
}
return a.encodeStaticConstImpl(n, opc.opcode, opc.rex, opc.mandatoryPrefix)
}

// encodeStaticConstImpl encodes an instruction where mod:r/m points to the memory location of the static constant n.staticConst,
// and the other operand is the register given at n.SrcReg or n.DstReg.
func (a *AssemblerImpl) encodeStaticConstImpl(n *NodeImpl, opcode []byte, rex RexPrefix, mandatoryPrefix byte) (err error) {
a.pool.addConst(n.staticConst)

dstReg3Bits, rexPrefix, err := register3bits(n.DstReg, registerSpecifierPositionModRMFieldReg)
var reg asm.Register
if n.DstReg != asm.NilRegister {
reg = n.DstReg
} else {
reg = n.SrcReg
}

reg3Bits, rexPrefix, err := register3bits(reg, registerSpecifierPositionModRMFieldReg)
if err != nil {
return err
}

var inst []byte // mandatory prefix
rexPrefix |= rex

var inst []byte
key := asm.StaticConstKey(n.staticConst)
a.pool.offsetFinalizedCallbacks[key] = append(a.pool.offsetFinalizedCallbacks[key],
func(offsetOfConstInBinary int) {
Expand All @@ -96,37 +177,18 @@ func (a *AssemblerImpl) encodeStaticConstToRegister(n *NodeImpl) (err error) {
a.pool.firstUseOffsetInBinary = &nodeOffset

// https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing
modRM := 0b00_000_101 | // Indicate "MOVDQU [RIP + 32bit displacement], DstReg" encoding.
(dstReg3Bits << 3) // Place the DstReg on ModRM:reg.

var mandatoryPrefix byte
var opcodes []byte
switch n.Instruction {
case MOVDQU:
// https://www.felixcloutier.com/x86/movdqu:vmovdqu8:vmovdqu16:vmovdqu32:vmovdqu64
mandatoryPrefix = 0xf3
opcodes = []byte{0x0f, 0x6f}
case LEAQ:
// https://www.felixcloutier.com/x86/lea
rexPrefix |= RexPrefixW
opcodes = []byte{0x8d}
case MOVUPD:
// https://www.felixcloutier.com/x86/movupd
mandatoryPrefix = 0x66
opcodes = []byte{0x0f, 0x10}
default:
err = errorEncodingUnsupported(n)
return
}
modRM := 0b00_000_101 | // Indicate "[RIP + 32bit displacement]" encoding.
(reg3Bits << 3) // Place the reg on ModRM:reg.

if mandatoryPrefix != 0 {
inst = append(inst, mandatoryPrefix)
}

if rexPrefix != RexPrefixNone {
inst = append(inst, rexPrefix)
}

inst = append(inst, opcodes...)
inst = append(inst, opcode...)
inst = append(inst, modRM,
0x0, 0x0, 0x0, 0x0, // Preserve 4 bytes for displacement.
)
Expand All @@ -135,8 +197,8 @@ func (a *AssemblerImpl) encodeStaticConstToRegister(n *NodeImpl) (err error) {
return
}

// CompileLoadStaticConstToRegister implements Assembler.CompileLoadStaticConstToRegister.
func (a *AssemblerImpl) CompileLoadStaticConstToRegister(instruction asm.Instruction, c asm.StaticConst, dstReg asm.Register) (err error) {
// CompileStaticConstToRegister implements Assembler.CompileStaticConstToRegister.
func (a *AssemblerImpl) CompileStaticConstToRegister(instruction asm.Instruction, c asm.StaticConst, dstReg asm.Register) (err error) {
if len(c)%2 != 0 {
err = fmt.Errorf("the length of a static constant must be even but was %d", len(c))
return
Expand All @@ -147,3 +209,16 @@ func (a *AssemblerImpl) CompileLoadStaticConstToRegister(instruction asm.Instruc
n.staticConst = c
return
}

// CompileRegisterToStaticConst implements Assembler.CompileRegisterToStaticConst.
func (a *AssemblerImpl) CompileRegisterToStaticConst(instruction asm.Instruction, srcReg asm.Register, c asm.StaticConst) (err error) {
if len(c)%2 != 0 {
err = fmt.Errorf("the length of a static constant must be even but was %d", len(c))
return
}

n := a.newNode(instruction, OperandTypesRegisterToStaticConst)
n.SrcReg = srcReg
n.staticConst = c
return
}