wazevo(amd64): scaffolds instructions + constant lowering (#1906)

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
Takeshi Yoneda
2024-01-09 13:49:47 -08:00
committed by GitHub
parent 3665e3c789
commit 2cb29a53c7
11 changed files with 2916 additions and 55 deletions

View File

@@ -97,9 +97,15 @@ type Compiler interface {
// SourceOffsetInfo returns the source offset information for the current buffer offset.
SourceOffsetInfo() []SourceOffsetInfo
// EmitByte appends a byte to the buffer. Used during the code emission.
EmitByte(b byte)
// Emit4Bytes appends 4 bytes to the buffer. Used during the code emission.
Emit4Bytes(b uint32)
// Emit8Bytes appends 8 bytes to the buffer. Used during the code emission.
Emit8Bytes(b uint64)
// GetFunctionABI returns the ABI information for the given signature.
GetFunctionABI(sig *ssa.Signature) *FunctionABI
}
@@ -380,11 +386,21 @@ func (c *compiler) AddRelocationInfo(funcRef ssa.FuncRef) {
})
}
// Emit4Bytes implements Compiler.Add4Bytes.
// Emit8Bytes implements Compiler.Emit8Bytes.
func (c *compiler) Emit8Bytes(b uint64) {
c.buf = append(c.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24), byte(b>>32), byte(b>>40), byte(b>>48), byte(b>>56))
}
// Emit4Bytes implements Compiler.Emit4Bytes.
func (c *compiler) Emit4Bytes(b uint32) {
c.buf = append(c.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24))
}
// EmitByte implements Compiler.EmitByte.
func (c *compiler) EmitByte(b byte) {
c.buf = append(c.buf, b)
}
// Buf implements Compiler.Buf.
func (c *compiler) Buf() []byte {
return c.buf

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,609 @@
package amd64
import (
"fmt"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
)
// Encode implements backend.Machine Encode.
func (m *machine) Encode() {
m.encode(m.ectx.RootInstr)
}
func (m *machine) encode(root *instruction) {
for cur := root; cur != nil; cur = cur.next {
cur.encode(m.c)
}
}
func (i *instruction) encode(c backend.Compiler) {
switch i.kind {
case nop0:
case ret:
c.EmitByte(0xc3)
case imm:
dst := regEncodings[i.op1.r.RealReg()]
con := i.u1
if i.b1 { // 64 bit.
if lower32willSignExtendTo64(con) {
// Sign extend mov(imm32).
encodeRegReg(c,
legacyPrefixesNone,
0xc7, 1,
0,
dst,
rexInfo(0).setW(),
)
c.Emit4Bytes(uint32(con))
} else {
c.EmitByte(rexEncodingW | dst.rexBit())
c.EmitByte(0xb8 | dst.encoding())
c.Emit8Bytes(con)
}
} else {
if dst.rexBit() > 0 {
c.EmitByte(rexEncodingDefault | 0x1)
}
c.EmitByte(0xb8 | dst.encoding())
c.Emit4Bytes(uint32(con))
}
case aluRmiR:
panic("TODO")
case movRR:
src := regEncodings[i.op1.r.RealReg()]
dst := regEncodings[i.op2.r.RealReg()]
var rex rexInfo
if i.b1 {
rex = rex.setW()
} else {
rex = rex.clearW()
}
encodeRegReg(c, legacyPrefixesNone, 0x89, 1, src, dst, rex)
case xmmRmR:
op := sseOpcode(i.u1)
var legPrex legacyPrefixes
var opcode uint32
var opcodeNum uint32
switch op {
case sseOpcodeAddps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F58, 2
case sseOpcodeAddpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F58, 2
case sseOpcodeAddss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F58, 2
case sseOpcodeAddsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F58, 2
case sseOpcodeAndps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F54, 2
case sseOpcodeAndpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F54, 2
case sseOpcodeAndnps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F55, 2
case sseOpcodeAndnpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F55, 2
case sseOpcodeCvttps2dq:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5B, 2
case sseOpcodeCvtdq2ps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F5B, 2
case sseOpcodeDivps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F5E, 2
case sseOpcodeDivpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F5E, 2
case sseOpcodeDivss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5E, 2
case sseOpcodeDivsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F5E, 2
case sseOpcodeMaxps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F5F, 2
case sseOpcodeMaxpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F5F, 2
case sseOpcodeMaxss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5F, 2
case sseOpcodeMaxsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F5F, 2
case sseOpcodeMinps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F5D, 2
case sseOpcodeMinpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F5D, 2
case sseOpcodeMinss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5D, 2
case sseOpcodeMinsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F5D, 2
case sseOpcodeMovlhps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F16, 2
case sseOpcodeMovsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F10, 2
case sseOpcodeMulps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F59, 2
case sseOpcodeMulpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F59, 2
case sseOpcodeMulss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F59, 2
case sseOpcodeMulsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F59, 2
case sseOpcodeOrpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F56, 2
case sseOpcodeOrps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F56, 2
case sseOpcodePackssdw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F6B, 2
case sseOpcodePacksswb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F63, 2
case sseOpcodePackusdw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F382B, 3
case sseOpcodePackuswb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F67, 2
case sseOpcodePaddb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FFC, 2
case sseOpcodePaddd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FFE, 2
case sseOpcodePaddq:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FD4, 2
case sseOpcodePaddw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FFD, 2
case sseOpcodePaddsb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FEC, 2
case sseOpcodePaddsw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FED, 2
case sseOpcodePaddusb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDC, 2
case sseOpcodePaddusw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDD, 2
case sseOpcodePand:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDB, 2
case sseOpcodePandn:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDF, 2
case sseOpcodePavgb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FE0, 2
case sseOpcodePavgw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FE3, 2
case sseOpcodePcmpeqb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F74, 2
case sseOpcodePcmpeqw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F75, 2
case sseOpcodePcmpeqd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F76, 2
case sseOpcodePcmpeqq:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3829, 3
case sseOpcodePcmpgtb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F64, 2
case sseOpcodePcmpgtw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F65, 2
case sseOpcodePcmpgtd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F66, 2
case sseOpcodePcmpgtq:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3837, 3
case sseOpcodePmaddwd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FF5, 2
case sseOpcodePmaxsb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383C, 3
case sseOpcodePmaxsw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FEE, 2
case sseOpcodePmaxsd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383D, 3
case sseOpcodePmaxub:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDE, 2
case sseOpcodePmaxuw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383E, 3
case sseOpcodePmaxud:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383F, 3
case sseOpcodePminsb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3838, 3
case sseOpcodePminsw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FEA, 2
case sseOpcodePminsd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3839, 3
case sseOpcodePminub:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FDA, 2
case sseOpcodePminuw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383A, 3
case sseOpcodePminud:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F383B, 3
case sseOpcodePmulld:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3840, 3
case sseOpcodePmullw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FD5, 2
case sseOpcodePmuludq:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FF4, 2
case sseOpcodePor:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FEB, 2
case sseOpcodePshufb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3800, 3
case sseOpcodePsubb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FF8, 2
case sseOpcodePsubd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FFA, 2
case sseOpcodePsubq:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FFB, 2
case sseOpcodePsubw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FF9, 2
case sseOpcodePsubsb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FE8, 2
case sseOpcodePsubsw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FE9, 2
case sseOpcodePsubusb:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FD8, 2
case sseOpcodePsubusw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FD9, 2
case sseOpcodePunpckhbw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F68, 2
case sseOpcodePunpcklbw:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F60, 2
case sseOpcodePxor:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0FEF, 2
case sseOpcodeSubps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F5C, 2
case sseOpcodeSubpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F5C, 2
case sseOpcodeSubss:
legPrex, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5C, 2
case sseOpcodeSubsd:
legPrex, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F5C, 2
case sseOpcodeXorps:
legPrex, opcode, opcodeNum = legacyPrefixesNone, 0x0F57, 2
case sseOpcodeXorpd:
legPrex, opcode, opcodeNum = legacyPrefixes0x66, 0x0F57, 2
default:
panic(fmt.Sprintf("Unsupported sseOpcode: %s", op))
}
op1 := i.op1
if op1.kind == operandKindReg {
src := regEncodings[op1.r.RealReg()]
dst := regEncodings[i.op2.r.RealReg()]
encodeRegReg(c, legPrex, opcode, opcodeNum, dst, src, rexInfo(0).clearW())
} else if i.op1.kind == operandKindMem {
panic("TODO")
} else {
panic("BUG: invalid operand kind")
}
case gprToXmm:
var legPrefix legacyPrefixes
var opcode uint32
const opcodeNum = 2
switch sseOpcode(i.u1) {
case sseOpcodeMovd, sseOpcodeMovq:
legPrefix, opcode = legacyPrefixes0x66, 0x0f6e
case sseOpcodeCvtsi2ss:
legPrefix, opcode = legacyPrefixes0xF3, 0x0f2a
case sseOpcodeCvtsi2sd:
legPrefix, opcode = legacyPrefixes0xF2, 0x0f2a
default:
panic(fmt.Sprintf("Unsupported sseOpcode: %s", sseOpcode(i.u1)))
}
var rex rexInfo
if i.b1 {
rex = rex.setW()
} else {
rex = rex.clearW()
}
op1 := i.op1
if op1.kind == operandKindReg {
src := regEncodings[op1.r.RealReg()]
dst := regEncodings[i.op2.r.RealReg()]
encodeRegReg(c, legPrefix, opcode, opcodeNum, dst, src, rex)
} else if i.op1.kind == operandKindMem {
panic("TODO")
} else {
panic("BUG: invalid operand kind")
}
case xmmUnaryRmR:
var prefix legacyPrefixes
var opcode uint32
var opcodeNum uint32
op := sseOpcode(i.u1)
switch op {
case sseOpcodeCvtss2sd:
prefix, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F5A, 2
case sseOpcodeCvtsd2ss:
prefix, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F5A, 2
case sseOpcodeMovaps:
prefix, opcode, opcodeNum = legacyPrefixesNone, 0x0F28, 2
case sseOpcodeMovapd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F28, 2
case sseOpcodeMovdqa:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F6F, 2
case sseOpcodeMovdqu:
prefix, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F6F, 2
case sseOpcodeMovsd:
prefix, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F10, 2
case sseOpcodeMovss:
prefix, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F10, 2
case sseOpcodeMovups:
prefix, opcode, opcodeNum = legacyPrefixesNone, 0x0F10, 2
case sseOpcodeMovupd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F10, 2
case sseOpcodePabsb:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F381C, 3
case sseOpcodePabsw:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F381D, 3
case sseOpcodePabsd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F381E, 3
case sseOpcodePmovsxbd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3821, 3
case sseOpcodePmovsxbw:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3820, 3
case sseOpcodePmovsxbq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3822, 3
case sseOpcodePmovsxwd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3823, 3
case sseOpcodePmovsxwq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3824, 3
case sseOpcodePmovsxdq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3825, 3
case sseOpcodePmovzxbd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3831, 3
case sseOpcodePmovzxbw:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3830, 3
case sseOpcodePmovzxbq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3832, 3
case sseOpcodePmovzxwd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3833, 3
case sseOpcodePmovzxwq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3834, 3
case sseOpcodePmovzxdq:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F3835, 3
case sseOpcodeSqrtps:
prefix, opcode, opcodeNum = legacyPrefixesNone, 0x0F51, 2
case sseOpcodeSqrtpd:
prefix, opcode, opcodeNum = legacyPrefixes0x66, 0x0F51, 2
case sseOpcodeSqrtss:
prefix, opcode, opcodeNum = legacyPrefixes0xF3, 0x0F51, 2
case sseOpcodeSqrtsd:
prefix, opcode, opcodeNum = legacyPrefixes0xF2, 0x0F51, 2
default:
panic(fmt.Sprintf("Unsupported sseOpcode: %s", op))
}
op1 := i.op1
if op1.kind == operandKindReg {
src := regEncodings[op1.r.RealReg()]
dst := regEncodings[i.op2.r.RealReg()]
encodeRegReg(c, prefix, opcode, opcodeNum, dst, src, rexInfo(0).clearW())
} else if i.op1.kind == operandKindMem {
panic("TODO")
} else {
panic("BUG: invalid operand kind")
}
case unaryRmR:
panic("TODO")
case not:
panic("TODO")
case neg:
panic("TODO")
case div:
panic("TODO")
case mulHi:
panic("TODO")
case checkedDivOrRemSeq:
panic("TODO")
case signExtendData:
panic("TODO")
case movzxRmR:
panic("TODO")
case mov64MR:
panic("TODO")
case loadEffectiveAddress:
panic("TODO")
case movsxRmR:
panic("TODO")
case movRM:
panic("TODO")
case shiftR:
panic("TODO")
case xmmRmiReg:
panic("TODO")
case cmpRmiR:
panic("TODO")
case setcc:
panic("TODO")
case cmove:
panic("TODO")
case push64:
panic("TODO")
case pop64:
panic("TODO")
case xmmMovRM:
panic("TODO")
case xmmLoadConst:
panic("TODO")
case xmmToGpr:
panic("TODO")
case cvtUint64ToFloatSeq:
panic("TODO")
case cvtFloatToSintSeq:
panic("TODO")
case cvtFloatToUintSeq:
panic("TODO")
case xmmMinMaxSeq:
panic("TODO")
case xmmCmove:
panic("TODO")
case xmmCmpRmR:
panic("TODO")
case xmmRmRImm:
panic("TODO")
case jmpKnown:
panic("TODO")
case jmpIf:
panic("TODO")
case jmpCond:
panic("TODO")
case jmpTableSeq:
panic("TODO")
case jmpUnknown:
panic("TODO")
case trapIf:
panic("TODO")
case ud2:
panic("TODO")
default:
panic(fmt.Sprintf("TODO: %v", i.kind))
}
}
func encodeRegReg(
c backend.Compiler,
legPrefixes legacyPrefixes,
opcodes uint32,
opcodeNum uint32,
r regEnc,
rm regEnc,
rex rexInfo,
) {
legPrefixes.encode(c)
rex.encode(c, r, rm)
for opcodeNum > 0 {
opcodeNum--
c.EmitByte(byte((opcodes >> (opcodeNum << 3)) & 0xff))
}
c.EmitByte(encodeModRM(3, r.encoding(), rm.encoding()))
}
func encodeModRM(mod byte, reg byte, rm byte) byte {
return mod<<6 | reg<<3 | rm
}
const (
rexEncodingDefault byte = 0x40
rexEncodingW = rexEncodingDefault | 0x08
)
// rexInfo is a bit set to indicate:
//
// 0x01: W bit must be cleared.
// 0x02: REX prefix must be emitted.
type rexInfo byte
func (ri rexInfo) setW() rexInfo {
return ri | 0x01
}
func (ri rexInfo) clearW() rexInfo { //nolint
return ri & 0x02
}
func (ri rexInfo) always() rexInfo { //nolint
return ri | 0x02
}
func (ri rexInfo) notAlways() rexInfo { //nolint
return ri & 0x01
}
func (ri rexInfo) encode(c backend.Compiler, encR regEnc, encRM regEnc) {
var w byte = 0
if ri&0x01 != 0 {
w = 0x01
}
r := encR.rexBit()
b := encRM.rexBit()
rex := rexEncodingDefault | w<<3 | r<<2 | b
if rex != rexEncodingDefault || ri&0x02 == 1 {
c.EmitByte(rex)
}
}
func (ri rexInfo) encodeForIndex(c backend.Compiler, encR regEnc, encIndex regEnc, encBase regEnc) { //nolint
var w byte = 0
if ri&0x01 != 0 {
w = 0x01
}
r := encR.rexBit()
x := encIndex.rexBit()
b := encBase.rexBit()
rex := byte(0x40) | w<<3 | r<<2 | x<<1 | b
if rex != 0x40 || ri&0x02 == 1 {
c.EmitByte(rex)
}
}
type regEnc byte
func (r regEnc) rexBit() byte {
return byte(r) >> 3
}
func (r regEnc) encoding() byte {
return byte(r) & 0x07
}
var regEncodings = [...]regEnc{
rax: 0b000,
rcx: 0b001,
rdx: 0b010,
rbx: 0b011,
rsp: 0b100,
rbp: 0b101,
rsi: 0b110,
rdi: 0b111,
r8: 0b1000,
r9: 0b1001,
r10: 0b1010,
r11: 0b1011,
r12: 0b1100,
r13: 0b1101,
r14: 0b1110,
r15: 0b1111,
xmm0: 0b000,
xmm1: 0b001,
xmm2: 0b010,
xmm3: 0b011,
xmm4: 0b100,
xmm5: 0b101,
xmm6: 0b110,
xmm7: 0b111,
xmm8: 0b1000,
xmm9: 0b1001,
xmm10: 0b1010,
xmm11: 0b1011,
xmm12: 0b1100,
xmm13: 0b1101,
xmm14: 0b1110,
xmm15: 0b1111,
}
type legacyPrefixes byte
const (
legacyPrefixesNone legacyPrefixes = iota
legacyPrefixes0x66
legacyPrefixes0xF0
legacyPrefixes0x660xF0
legacyPrefixes0xF2
legacyPrefixes0xF3
)
func (p legacyPrefixes) encode(c backend.Compiler) {
switch p {
case legacyPrefixesNone:
case legacyPrefixes0x66:
c.EmitByte(0x66)
case legacyPrefixes0xF0:
c.EmitByte(0xf0)
case legacyPrefixes0x660xF0:
c.EmitByte(0x66)
c.EmitByte(0xf0)
case legacyPrefixes0xF2:
c.EmitByte(0xf2)
case legacyPrefixes0xF3:
c.EmitByte(0xf3)
default:
panic("BUG: invalid legacy prefix")
}
}
func lower32willSignExtendTo64(x uint64) bool {
xs := int64(x)
return xs == int64(uint64(int32(xs)))
}

View File

@@ -0,0 +1,898 @@
package amd64
import (
"encoding/hex"
"testing"
"github.com/tetratelabs/wazero/internal/testing/require"
)
func TestInstruction_format_encode(t *testing.T) {
for _, tc := range []struct {
setup func(*instruction)
want string
wantFormat string
}{
{
setup: func(i *instruction) { i.asRet(nil) },
wantFormat: "ret",
want: "c3",
},
{
setup: func(i *instruction) { i.asImm(r14VReg, 1234567, false) },
wantFormat: "movl $1234567, %r14d",
want: "41be87d61200",
},
{
setup: func(i *instruction) {
v := -126
i.asImm(r14VReg, uint64(int64(v)), false)
},
wantFormat: "movl $-126, %r14d",
want: "41be82ffffff",
},
{
setup: func(i *instruction) { i.asImm(r14VReg, 0x200000000, true) },
want: "49be0000000002000000",
wantFormat: "movabsq $8589934592, %r14",
},
{
setup: func(i *instruction) {
v := -126
i.asImm(r14VReg, uint64(int64(v)), true)
},
want: "49c7c682ffffff",
wantFormat: "movabsq $-126, %r14",
},
{
setup: func(i *instruction) { i.asImm(rcxVReg, 1234567, false) },
wantFormat: "movl $1234567, %ecx",
want: "b987d61200",
},
{
setup: func(i *instruction) {
v := -126
i.asImm(rcxVReg, uint64(int64(v)), false)
},
wantFormat: "movl $-126, %ecx",
want: "b982ffffff",
},
{
setup: func(i *instruction) { i.asImm(rcxVReg, 0x200000000, true) },
want: "48b90000000002000000",
wantFormat: "movabsq $8589934592, %rcx",
},
{
setup: func(i *instruction) {
v := -126
i.asImm(rcxVReg, uint64(int64(v)), true)
},
want: "48c7c182ffffff",
wantFormat: "movabsq $-126, %rcx",
},
{
setup: func(i *instruction) { i.asMovRR(raxVReg, rdiVReg, false) },
want: "89c7",
wantFormat: "movl %eax, %edi",
},
{
setup: func(i *instruction) { i.asMovRR(raxVReg, r15VReg, false) },
want: "4189c7",
wantFormat: "movl %eax, %r15d",
},
{
setup: func(i *instruction) { i.asMovRR(r14VReg, r15VReg, false) },
want: "4589f7",
wantFormat: "movl %r14d, %r15d",
},
{
setup: func(i *instruction) { i.asMovRR(raxVReg, rcxVReg, true) },
want: "4889c1",
wantFormat: "movq %rax, %rcx",
},
{
setup: func(i *instruction) { i.asMovRR(raxVReg, r15VReg, true) },
want: "4989c7",
wantFormat: "movq %rax, %r15",
},
{
setup: func(i *instruction) { i.asMovRR(r11VReg, r12VReg, true) },
want: "4d89dc",
wantFormat: "movq %r11, %r12",
},
// addss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f58c1",
wantFormat: "addss %xmm1, %xmm0",
},
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddss, newOperandReg(xmm13VReg), xmm11VReg, false) },
want: "f3450f58dd",
wantFormat: "addss %xmm13, %xmm11",
},
// addsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f58c1",
wantFormat: "addsd %xmm1, %xmm0",
},
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddsd, newOperandReg(xmm13VReg), xmm11VReg, false) },
want: "f2450f58dd",
wantFormat: "addsd %xmm13, %xmm11",
},
// addps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f58c1",
wantFormat: "addps %xmm1, %xmm0",
},
// addpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f58c1",
wantFormat: "addpd %xmm1, %xmm0",
},
// addss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f58c1",
wantFormat: "addss %xmm1, %xmm0",
},
// addsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAddsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f58c1",
wantFormat: "addsd %xmm1, %xmm0",
},
// andps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAndps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f54c1",
wantFormat: "andps %xmm1, %xmm0",
},
// andpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAndpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f54c1",
wantFormat: "andpd %xmm1, %xmm0",
},
// andnps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAndnps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f55c1",
wantFormat: "andnps %xmm1, %xmm0",
},
// andnpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeAndnpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f55c1",
wantFormat: "andnpd %xmm1, %xmm0",
},
// cvttps2dq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeCvttps2dq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5bc1",
wantFormat: "cvttps2dq %xmm1, %xmm0",
},
// cvtdq2ps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeCvtdq2ps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f5bc1",
wantFormat: "cvtdq2ps %xmm1, %xmm0",
},
// divps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeDivps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f5ec1",
wantFormat: "divps %xmm1, %xmm0",
},
// divpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeDivpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f5ec1",
wantFormat: "divpd %xmm1, %xmm0",
},
// divss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeDivss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5ec1",
wantFormat: "divss %xmm1, %xmm0",
},
// divsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeDivsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f5ec1",
wantFormat: "divsd %xmm1, %xmm0",
},
// maxps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMaxps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f5fc1",
wantFormat: "maxps %xmm1, %xmm0",
},
// maxpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMaxpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f5fc1",
wantFormat: "maxpd %xmm1, %xmm0",
},
// maxss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMaxss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5fc1",
wantFormat: "maxss %xmm1, %xmm0",
},
// maxsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMaxsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f5fc1",
wantFormat: "maxsd %xmm1, %xmm0",
},
// minps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMinps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f5dc1",
wantFormat: "minps %xmm1, %xmm0",
},
// paddsw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddsw, newOperandReg(xmm7VReg), xmm6VReg, true) },
want: "660fedf7",
wantFormat: "paddsw %xmm7, %xmm6",
},
// paddusb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddusb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fdcc1",
wantFormat: "paddusb %xmm1, %xmm0",
},
// paddusw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddusw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fddc1",
wantFormat: "paddusw %xmm1, %xmm0",
},
// pand
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePand, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fdbc1",
wantFormat: "pand %xmm1, %xmm0",
},
// pandn
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePandn, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fdfc1",
wantFormat: "pandn %xmm1, %xmm0",
},
// pavgb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePavgb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fe0c1",
wantFormat: "pavgb %xmm1, %xmm0",
},
// pavgw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePavgw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fe3c1",
wantFormat: "pavgw %xmm1, %xmm0",
},
// pcmpeqb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpeqb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f74c1",
wantFormat: "pcmpeqb %xmm1, %xmm0",
},
// pcmpeqw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpeqw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f75c1",
wantFormat: "pcmpeqw %xmm1, %xmm0",
},
// pcmpeqd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpeqd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f76c1",
wantFormat: "pcmpeqd %xmm1, %xmm0",
},
// pcmpeqq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpeqq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3829c1",
wantFormat: "pcmpeqq %xmm1, %xmm0",
},
// pcmpgtb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpgtb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f64c1",
wantFormat: "pcmpgtb %xmm1, %xmm0",
},
// pcmpgtw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpgtw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f65c1",
wantFormat: "pcmpgtw %xmm1, %xmm0",
},
// pcmpgtd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpgtd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f66c1",
wantFormat: "pcmpgtd %xmm1, %xmm0",
},
// pcmpgtq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePcmpgtq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3837c1",
wantFormat: "pcmpgtq %xmm1, %xmm0",
},
// pmaddwd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaddwd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ff5c1",
wantFormat: "pmaddwd %xmm1, %xmm0",
},
// pmaxsb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxsb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383cc1",
wantFormat: "pmaxsb %xmm1, %xmm0",
},
// pmaxsw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxsw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660feec1",
wantFormat: "pmaxsw %xmm1, %xmm0",
},
// pmaxsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383dc1",
wantFormat: "pmaxsd %xmm1, %xmm0",
},
// pmaxub
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxub, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fdec1",
wantFormat: "pmaxub %xmm1, %xmm0",
},
// pmaxuw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxuw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383ec1",
wantFormat: "pmaxuw %xmm1, %xmm0",
},
// pmaxud
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmaxud, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383fc1",
wantFormat: "pmaxud %xmm1, %xmm0",
},
// pminsb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminsb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3838c1",
wantFormat: "pminsb %xmm1, %xmm0",
},
// pminsw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminsw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660feac1",
wantFormat: "pminsw %xmm1, %xmm0",
},
// pminsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3839c1",
wantFormat: "pminsd %xmm1, %xmm0",
},
// pminub
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminub, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fdac1",
wantFormat: "pminub %xmm1, %xmm0",
},
// pminuw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminuw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383ac1",
wantFormat: "pminuw %xmm1, %xmm0",
},
// pminud
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePminud, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f383bc1",
wantFormat: "pminud %xmm1, %xmm0",
},
// pmulld
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmulld, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3840c1",
wantFormat: "pmulld %xmm1, %xmm0",
},
// pmullw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmullw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fd5c1",
wantFormat: "pmullw %xmm1, %xmm0",
},
// pmuludq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePmuludq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ff4c1",
wantFormat: "pmuludq %xmm1, %xmm0",
},
// por
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePor, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660febc1",
wantFormat: "por %xmm1, %xmm0",
},
// pshufb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePshufb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3800c1",
wantFormat: "pshufb %xmm1, %xmm0",
},
// psubb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ff8c1",
wantFormat: "psubb %xmm1, %xmm0",
},
// psubd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ffac1",
wantFormat: "psubd %xmm1, %xmm0",
},
// psubq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ffbc1",
wantFormat: "psubq %xmm1, %xmm0",
},
// psubw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ff9c1",
wantFormat: "psubw %xmm1, %xmm0",
},
// psubsb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubsb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fe8c1",
wantFormat: "psubsb %xmm1, %xmm0",
},
// psubsw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubsw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fe9c1",
wantFormat: "psubsw %xmm1, %xmm0",
},
// psubusb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubusb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fd8c1",
wantFormat: "psubusb %xmm1, %xmm0",
},
// psubusw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePsubusw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fd9c1",
wantFormat: "psubusw %xmm1, %xmm0",
},
// punpckhbw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePunpckhbw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f68c1",
wantFormat: "punpckhbw %xmm1, %xmm0",
},
// punpcklbw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePunpcklbw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f60c1",
wantFormat: "punpcklbw %xmm1, %xmm0",
},
// pxor
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePxor, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fefc1",
wantFormat: "pxor %xmm1, %xmm0",
},
// subps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeSubps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f5cc1",
wantFormat: "subps %xmm1, %xmm0",
},
// subpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeSubpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f5cc1",
wantFormat: "subpd %xmm1, %xmm0",
},
// subss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeSubss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5cc1",
wantFormat: "subss %xmm1, %xmm0",
},
// subsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeSubsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f5cc1",
wantFormat: "subsd %xmm1, %xmm0",
},
// xorps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeXorps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f57c1",
wantFormat: "xorps %xmm1, %xmm0",
},
// xorpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeXorpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f57c1",
wantFormat: "xorpd %xmm1, %xmm0",
},
// minpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMinpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f5dc1",
wantFormat: "minpd %xmm1, %xmm0",
},
// minss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMinss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5dc1",
wantFormat: "minss %xmm1, %xmm0",
},
// minsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMinsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f5dc1",
wantFormat: "minsd %xmm1, %xmm0",
},
// movlhps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMovlhps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f16c1",
wantFormat: "movlhps %xmm1, %xmm0",
},
// movsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMovsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f10c1",
wantFormat: "movsd %xmm1, %xmm0",
},
// mulps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMulps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f59c1",
wantFormat: "mulps %xmm1, %xmm0",
},
// mulpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMulpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f59c1",
wantFormat: "mulpd %xmm1, %xmm0",
},
// mulss
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMulss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f59c1",
wantFormat: "mulss %xmm1, %xmm0",
},
// mulsd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeMulsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f59c1",
wantFormat: "mulsd %xmm1, %xmm0",
},
// orpd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeOrpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f56c1",
wantFormat: "orpd %xmm1, %xmm0",
},
// orps
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodeOrps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f56c1",
wantFormat: "orps %xmm1, %xmm0",
},
// packssdw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePackssdw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f6bc1",
wantFormat: "packssdw %xmm1, %xmm0",
},
// packsswb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePacksswb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f63c1",
wantFormat: "packsswb %xmm1, %xmm0",
},
// packusdw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePackusdw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f382bc1",
wantFormat: "packusdw %xmm1, %xmm0",
},
// packuswb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePackuswb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f67c1",
wantFormat: "packuswb %xmm1, %xmm0",
},
// paddb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ffcc1",
wantFormat: "paddb %xmm1, %xmm0",
},
// paddd
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ffec1",
wantFormat: "paddd %xmm1, %xmm0",
},
// paddq
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fd4c1",
wantFormat: "paddq %xmm1, %xmm0",
},
// paddw
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660ffdc1",
wantFormat: "paddw %xmm1, %xmm0",
},
// paddsb
{
setup: func(i *instruction) { i.asXmmRmR(sseOpcodePaddsb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660fecc1",
wantFormat: "paddsb %xmm1, %xmm0",
},
// cvtss2sd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeCvtss2sd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f5ac1",
wantFormat: "cvtss2sd %xmm1, %xmm0",
},
// cvtsd2ss
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeCvtsd2ss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f5ac1",
wantFormat: "cvtsd2ss %xmm1, %xmm0",
},
// movaps
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovaps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f28c1",
wantFormat: "movaps %xmm1, %xmm0",
},
// movapd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovapd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f28c1",
wantFormat: "movapd %xmm1, %xmm0",
},
// movdqa
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovdqa, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f6fc1",
wantFormat: "movdqa %xmm1, %xmm0",
},
// movdqu
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovdqu, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f6fc1",
wantFormat: "movdqu %xmm1, %xmm0",
},
// movsd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f10c1",
wantFormat: "movsd %xmm1, %xmm0",
},
// movss
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f10c1",
wantFormat: "movss %xmm1, %xmm0",
},
// movups
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovups, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f10c1",
wantFormat: "movups %xmm1, %xmm0",
},
// movupd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeMovupd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f10c1",
wantFormat: "movupd %xmm1, %xmm0",
},
// pabsb
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePabsb, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f381cc1",
wantFormat: "pabsb %xmm1, %xmm0",
},
// pabsw
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePabsw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f381dc1",
wantFormat: "pabsw %xmm1, %xmm0",
},
// pabsd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePabsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f381ec1",
wantFormat: "pabsd %xmm1, %xmm0",
},
// pmovsxbd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxbd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3821c1",
wantFormat: "pmovsxbd %xmm1, %xmm0",
},
// pmovsxbw
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxbw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3820c1",
wantFormat: "pmovsxbw %xmm1, %xmm0",
},
// pmovsxbq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxbq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3822c1",
wantFormat: "pmovsxbq %xmm1, %xmm0",
},
// pmovsxwd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxwd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3823c1",
wantFormat: "pmovsxwd %xmm1, %xmm0",
},
// pmovsxwq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxwq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3824c1",
wantFormat: "pmovsxwq %xmm1, %xmm0",
},
// pmovsxdq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovsxdq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3825c1",
wantFormat: "pmovsxdq %xmm1, %xmm0",
},
// pmovzxbd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxbd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3831c1",
wantFormat: "pmovzxbd %xmm1, %xmm0",
},
// pmovzxbw
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxbw, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3830c1",
wantFormat: "pmovzxbw %xmm1, %xmm0",
},
// pmovzxbq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxbq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3832c1",
wantFormat: "pmovzxbq %xmm1, %xmm0",
},
// pmovzxwd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxwd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3833c1",
wantFormat: "pmovzxwd %xmm1, %xmm0",
},
// pmovzxwq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxwq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3834c1",
wantFormat: "pmovzxwq %xmm1, %xmm0",
},
// pmovzxdq
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodePmovzxdq, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f3835c1",
wantFormat: "pmovzxdq %xmm1, %xmm0",
},
// sqrtps
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtps, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "0f51c1",
wantFormat: "sqrtps %xmm1, %xmm0",
},
// sqrtpd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtpd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "660f51c1",
wantFormat: "sqrtpd %xmm1, %xmm0",
},
// sqrtss
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtss, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f30f51c1",
wantFormat: "sqrtss %xmm1, %xmm0",
},
// sqrtsd
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtsd, newOperandReg(xmm1VReg), xmm0VReg, true) },
want: "f20f51c1",
wantFormat: "sqrtsd %xmm1, %xmm0",
},
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtsd, newOperandReg(xmm15VReg), xmm0VReg, true) },
want: "f2410f51c7",
wantFormat: "sqrtsd %xmm15, %xmm0",
},
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtsd, newOperandReg(xmm1VReg), xmm15VReg, true) },
want: "f2440f51f9",
wantFormat: "sqrtsd %xmm1, %xmm15",
},
{
setup: func(i *instruction) { i.asXmmUnaryRmR(sseOpcodeSqrtsd, newOperandReg(xmm11VReg), xmm15VReg, true) },
want: "f2450f51fb",
wantFormat: "sqrtsd %xmm11, %xmm15",
},
// movd
{
setup: func(i *instruction) { i.asGprToXmm(sseOpcodeMovd, newOperandReg(rdiVReg), xmm0VReg, false) },
want: "660f6ec7",
wantFormat: "movd %edi, %xmm0",
},
// movq
{
setup: func(i *instruction) { i.asGprToXmm(sseOpcodeMovq, newOperandReg(rcxVReg), xmm0VReg, true) },
want: "66480f6ec1",
wantFormat: "movq %rcx, %xmm0",
},
// cvtsi2ss
{
setup: func(i *instruction) { i.asGprToXmm(sseOpcodeCvtsi2ss, newOperandReg(rdiVReg), xmm0VReg, true) },
want: "f3480f2ac7",
wantFormat: "cvtsi2ss %rdi, %xmm0",
},
// cvtsi2sd
{
setup: func(i *instruction) { i.asGprToXmm(sseOpcodeCvtsi2sd, newOperandReg(rdiVReg), xmm0VReg, true) },
want: "f2480f2ac7",
wantFormat: "cvtsi2sd %rdi, %xmm0",
},
{
setup: func(i *instruction) { i.asGprToXmm(sseOpcodeCvtsi2sd, newOperandReg(rdiVReg), xmm0VReg, false) },
want: "f20f2ac7",
wantFormat: "cvtsi2sd %edi, %xmm0",
},
} {
tc := tc
t.Run(tc.wantFormat, func(t *testing.T) {
i := &instruction{}
tc.setup(i)
require.Equal(t, tc.wantFormat, i.String())
mc := &mockCompiler{}
m := &machine{c: mc}
i.encode(m.c)
require.Equal(t, tc.want, hex.EncodeToString(mc.buf))
// TODO: verify the size of the encoded instructions.
//var actualSize int
//for cur := i; cur != nil; cur = cur.next {
// actualSize += int(cur.size())
//}
//require.Equal(t, len(tc.want)/2, actualSize)
})
}
}

View File

@@ -0,0 +1,57 @@
package amd64
import (
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
)
// InsertLoadConstant implements backend.Machine.
func (m *machine) InsertLoadConstant(instr *ssa.Instruction, vr regalloc.VReg) {
val := instr.Return()
valType := val.Type()
v := instr.ConstantVal()
bits := valType.Bits()
if bits < 64 { // Clear the redundant bits just in case it's unexpectedly sign-extended, etc.
v = v & ((1 << valType.Bits()) - 1)
}
switch valType {
case ssa.TypeF32, ssa.TypeF64:
m.lowerFconst(vr, v, bits == 64)
case ssa.TypeI32, ssa.TypeI64:
m.lowerIconst(vr, v, bits == 64)
default:
panic("TODO")
}
}
func (m *machine) lowerFconst(dst regalloc.VReg, c uint64, _64 bool) {
if c == 0 {
xor := m.allocateInstr().asXmmRmR(sseOpcodeXorpd, operand{kind: operandKindReg, r: dst}, dst, _64)
m.insert(xor)
} else {
var tmpType ssa.Type
if _64 {
tmpType = ssa.TypeI64
} else {
tmpType = ssa.TypeI32
}
tmpInt := m.c.AllocateVReg(tmpType)
loadToGP := m.allocateInstr().asImm(tmpInt, c, _64)
m.insert(loadToGP)
movToXmm := m.allocateInstr().asGprToXmm(sseOpcodeMovq, operand{kind: operandKindReg, r: tmpInt}, dst, _64)
m.insert(movToXmm)
}
}
func (m *machine) lowerIconst(dst regalloc.VReg, c uint64, _64 bool) {
i := m.allocateInstr()
if c == 0 {
i.asAluRmiR(aluRmiROpcodeXor, operand{kind: operandKindReg, r: dst}, dst, _64)
} else {
i.asImm(dst, c, _64)
}
m.insert(i)
}

View File

@@ -2,6 +2,8 @@ package amd64
import (
"context"
"fmt"
"strings"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
@@ -23,20 +25,22 @@ func NewBackend() backend.Machine {
}
}
// machine implements backend.Machine for amd64.
type machine struct {
c backend.Compiler
ectx *backend.ExecutableContextT[instruction]
stackBoundsCheckDisabled bool
type (
// machine implements backend.Machine for amd64.
machine struct {
c backend.Compiler
ectx *backend.ExecutableContextT[instruction]
stackBoundsCheckDisabled bool
regAlloc regalloc.Allocator
regAllocFn *backend.RegAllocFunction[*instruction, *machine]
regAllocStarted bool
regAlloc regalloc.Allocator
regAllocFn *backend.RegAllocFunction[*instruction, *machine]
regAllocStarted bool
spillSlotSize int64
currentABI *backend.FunctionABI
clobberedRegs []regalloc.VReg
}
spillSlotSize int64
currentABI *backend.FunctionABI
clobberedRegs []regalloc.VReg
}
)
// Reset implements backend.Machine.
func (m *machine) Reset() {
@@ -75,6 +79,12 @@ func (m *machine) RegAlloc() {
m.spillSlotSize = (m.spillSlotSize + 15) &^ 15
}
// InsertReturn implements backend.Machine.
func (m *machine) InsertReturn() {
i := m.allocateInstr().asRet(m.currentABI)
m.insert(i)
}
// LowerSingleBranch implements backend.Machine.
func (m *machine) LowerSingleBranch(b *ssa.Instruction) {
// TODO implement me
@@ -95,26 +105,57 @@ func (m *machine) LowerInstr(instruction *ssa.Instruction) {
// InsertMove implements backend.Machine.
func (m *machine) InsertMove(dst, src regalloc.VReg, typ ssa.Type) {
// TODO implement me
panic("implement me")
}
// InsertReturn implements backend.Machine.
func (m *machine) InsertReturn() {
// TODO implement me
panic("implement me")
}
// InsertLoadConstant implements backend.Machine.
func (m *machine) InsertLoadConstant(instr *ssa.Instruction, vr regalloc.VReg) {
// TODO implement me
panic("implement me")
switch typ {
case ssa.TypeI32, ssa.TypeI64:
i := m.allocateInstr().asMovRR(src, dst, typ.Bits() == 64)
m.insert(i)
case ssa.TypeF32, ssa.TypeF64, ssa.TypeV128:
var op sseOpcode
switch typ {
case ssa.TypeF32:
op = sseOpcodeMovss
case ssa.TypeF64:
op = sseOpcodeMovsd
case ssa.TypeV128:
op = sseOpcodeMovdqa
}
i := m.allocateInstr().asXmmUnaryRmR(op, operand{kind: operandKindReg, r: src}, dst, typ.Bits() == 64)
m.insert(i)
default:
panic("BUG")
}
}
// Format implements backend.Machine.
func (m *machine) Format() string {
// TODO implement me
panic("implement me")
ectx := m.ectx
begins := map[*instruction]backend.Label{}
for l, pos := range ectx.LabelPositions {
begins[pos.Begin] = l
}
irBlocks := map[backend.Label]ssa.BasicBlockID{}
for i, l := range ectx.SsaBlockIDToLabels {
irBlocks[l] = ssa.BasicBlockID(i)
}
var lines []string
for cur := ectx.RootInstr; cur != nil; cur = cur.next {
if l, ok := begins[cur]; ok {
var labelStr string
if blkID, ok := irBlocks[l]; ok {
labelStr = fmt.Sprintf("%s (SSA Block: %s):", l, blkID)
} else {
labelStr = fmt.Sprintf("%s:", l)
}
lines = append(lines, labelStr)
}
if cur.kind == nop0 {
continue
}
lines = append(lines, "\t"+cur.String())
}
return "\n" + strings.Join(lines, "\n") + "\n"
}
// SetupPrologue implements backend.Machine.
@@ -141,12 +182,6 @@ func (m *machine) ResolveRelocations(refToBinaryOffset map[ssa.FuncRef]int, bina
panic("implement me")
}
// Encode implements backend.Machine.
func (m *machine) Encode() {
// TODO implement me
panic("implement me")
}
// CompileGoFunctionTrampoline implements backend.Machine.
func (m *machine) CompileGoFunctionTrampoline(exitCode wazevoapi.ExitCode, sig *ssa.Signature, needModuleContextPtr bool) []byte {
// TODO implement me
@@ -164,3 +199,17 @@ func (m *machine) CompileEntryPreamble(signature *ssa.Signature) []byte {
// TODO implement me
panic("implement me")
}
// allocateInstr allocates an instruction.
func (m *machine) allocateInstr() *instruction {
instr := m.ectx.InstructionPool.Allocate()
if !m.regAllocStarted {
instr.addedBeforeRegAlloc = true
}
return instr
}
func (m *machine) insert(i *instruction) {
ectx := m.ectx
ectx.PendingInstructions = append(ectx.PendingInstructions, i)
}

View File

@@ -0,0 +1,78 @@
package amd64
import (
"fmt"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
)
type operand struct {
kind operandKind
r regalloc.VReg
imm32 uint32
amode amode
}
type operandKind byte
const (
// operandKindReg is an operand which is an integer Register.
operandKindReg operandKind = iota + 1
// operandKindMem is an operand which is either an integer Register or a value in Memory. This can denote an 8, 16,
// 32, 64, or 128 bit value.
operandKindMem
// operandKindRegMemImm is either an integer Register, a value in Memory or an Immediate.
operandImm32
)
func (o *operand) format(_64 bool) string {
switch o.kind {
case operandKindReg:
return formatVRegSized(o.r, _64)
case operandKindMem:
return o.amode.String()
case operandImm32:
return fmt.Sprintf("$%d", o.imm32)
default:
panic("BUG: invalid operand kind")
}
}
func newOperandReg(r regalloc.VReg) operand {
return operand{kind: operandKindReg, r: r}
}
// nolint
type amode struct {
kind amodeKind
imm32 uint32
// For amodeRegRegShit:
base regalloc.VReg
index regalloc.VReg
shift byte // 0, 1, 2, 3
}
type amodeKind byte
const (
// immediate sign-extended and a Register.
amodeImmReg amodeKind = iota + 1
// sign-extend-32-to-64(Immediate) + Register1 + (Register2 << Shift)
amodeRegRegShit
)
func (a *amode) String() string {
switch a.kind {
case amodeImmReg:
panic("TODO")
case amodeRegRegShit:
panic("TODO")
}
panic("BUG: invalid amode kind")
}

View File

@@ -1,6 +1,8 @@
package amd64
import (
"fmt"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
)
@@ -147,3 +149,37 @@ var regNames = [...]string{
xmm14: "xmm14",
xmm15: "xmm15",
}
func formatVRegSized(r regalloc.VReg, _64 bool) string {
if r.IsRealReg() {
if r.RegType() == regalloc.RegTypeInt {
rr := r.RealReg()
orig := regNames[rr]
if rr <= rdi {
if _64 {
return "%" + orig
} else {
return "%e" + orig[1:]
}
} else {
if _64 {
return "%" + orig
} else {
return "%" + orig + "d"
}
}
} else {
return "%" + regNames[r.RealReg()]
}
} else {
if r.RegType() == regalloc.RegTypeInt {
if _64 {
return fmt.Sprintf("%%r%d?", r.ID())
} else {
return fmt.Sprintf("%%r%dd?", r.ID())
}
} else {
return fmt.Sprintf("%%xmm%d?", r.ID())
}
}
}

View File

@@ -0,0 +1,36 @@
package amd64
import (
"testing"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
"github.com/tetratelabs/wazero/internal/testing/require"
)
func Test_formatVRegSize(t *testing.T) {
tests := []struct {
r regalloc.VReg
_64 bool
exp string
}{
// Real registers.
{r: raxVReg, _64: true, exp: "%rax"},
{r: raxVReg, _64: false, exp: "%eax"},
{r: r15VReg, _64: true, exp: "%r15"},
{r: r15VReg, _64: false, exp: "%r15d"},
{r: xmm0VReg, _64: true, exp: "%xmm0"},
{r: xmm0VReg, _64: false, exp: "%xmm0"},
{r: xmm15VReg, _64: true, exp: "%xmm15"},
{r: xmm15VReg, _64: false, exp: "%xmm15"},
// Non-real registers.
{r: regalloc.VReg(5555).SetRegType(regalloc.RegTypeInt), _64: true, exp: "%r5555?"},
{r: regalloc.VReg(5555).SetRegType(regalloc.RegTypeInt), _64: false, exp: "%r5555d?"},
{r: regalloc.VReg(123).SetRegType(regalloc.RegTypeFloat), _64: true, exp: "%xmm123?"},
{r: regalloc.VReg(432).SetRegType(regalloc.RegTypeFloat), _64: false, exp: "%xmm432?"},
}
for _, tt := range tests {
t.Run(tt.exp, func(t *testing.T) {
require.Equal(t, tt.exp, formatVRegSized(tt.r, tt._64))
})
}
}

View File

@@ -0,0 +1,125 @@
package amd64
import (
"context"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
)
// mockCompiler implements backend.Compiler for testing.
type mockCompiler struct {
currentGID ssa.InstructionGroupID
vRegCounter int
vRegMap map[ssa.Value]regalloc.VReg
definitions map[ssa.Value]*backend.SSAValueDefinition
sigs map[ssa.SignatureID]*ssa.Signature
typeOf map[regalloc.VRegID]ssa.Type
relocs []backend.RelocationInfo
buf []byte
}
func (m *mockCompiler) GetFunctionABI(sig *ssa.Signature) *backend.FunctionABI {
// TODO implement me
panic("implement me")
}
func (m *mockCompiler) SSABuilder() ssa.Builder { return nil }
func (m *mockCompiler) LoopNestingForestRoots() []ssa.BasicBlock { panic("TODO") }
func (m *mockCompiler) SourceOffsetInfo() []backend.SourceOffsetInfo { return nil }
func (m *mockCompiler) AddSourceOffsetInfo(int64, ssa.SourceOffset) {}
func (m *mockCompiler) AddRelocationInfo(funcRef ssa.FuncRef) {
m.relocs = append(m.relocs, backend.RelocationInfo{FuncRef: funcRef, Offset: int64(len(m.buf))})
}
func (m *mockCompiler) Emit4Bytes(b uint32) {
m.buf = append(m.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24))
}
func (m *mockCompiler) EmitByte(b byte) {
m.buf = append(m.buf, b)
}
func (m *mockCompiler) Emit8Bytes(b uint64) {
m.buf = append(m.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24), byte(b>>32), byte(b>>40), byte(b>>48), byte(b>>56))
}
func (m *mockCompiler) Encode() {}
func (m *mockCompiler) Buf() []byte { return m.buf }
func (m *mockCompiler) TypeOf(v regalloc.VReg) (ret ssa.Type) {
return m.typeOf[v.ID()]
}
func (m *mockCompiler) Finalize(context.Context) {}
func (m *mockCompiler) RegAlloc() {}
func (m *mockCompiler) Lower() {}
func (m *mockCompiler) Format() string { return "" }
func (m *mockCompiler) Init() {}
func newMockCompilationContext() *mockCompiler { //nolint
return &mockCompiler{
vRegMap: make(map[ssa.Value]regalloc.VReg),
definitions: make(map[ssa.Value]*backend.SSAValueDefinition),
typeOf: map[regalloc.VRegID]ssa.Type{},
}
}
// ResolveSignature implements backend.Compiler.
func (m *mockCompiler) ResolveSignature(id ssa.SignatureID) *ssa.Signature {
return m.sigs[id]
}
// AllocateVReg implements backend.Compiler.
func (m *mockCompiler) AllocateVReg(typ ssa.Type) regalloc.VReg {
m.vRegCounter++
regType := regalloc.RegTypeOf(typ)
ret := regalloc.VReg(m.vRegCounter).SetRegType(regType)
m.typeOf[ret.ID()] = typ
return ret
}
// ValueDefinition implements backend.Compiler.
func (m *mockCompiler) ValueDefinition(value ssa.Value) *backend.SSAValueDefinition {
definition, exists := m.definitions[value]
if !exists {
return nil
}
return definition
}
// VRegOf implements backend.Compiler.
func (m *mockCompiler) VRegOf(value ssa.Value) regalloc.VReg {
vReg, exists := m.vRegMap[value]
if !exists {
panic("Value does not exist")
}
return vReg
}
// MatchInstr implements backend.Compiler.
func (m *mockCompiler) MatchInstr(def *backend.SSAValueDefinition, opcode ssa.Opcode) bool {
instr := def.Instr
return def.IsFromInstr() &&
instr.Opcode() == opcode &&
instr.GroupID() == m.currentGID &&
def.RefCount < 2
}
// MatchInstrOneOf implements backend.Compiler.
func (m *mockCompiler) MatchInstrOneOf(def *backend.SSAValueDefinition, opcodes []ssa.Opcode) ssa.Opcode {
for _, opcode := range opcodes {
if m.MatchInstr(def, opcode) {
return opcode
}
}
return ssa.OpcodeInvalid
}
// Compile implements backend.Compiler.
func (m *mockCompiler) Compile(context.Context) (_ []byte, _ []backend.RelocationInfo, _ error) {
return
}

View File

@@ -82,6 +82,14 @@ func (m *mockCompiler) Emit4Bytes(b uint32) {
m.buf = append(m.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24))
}
func (m *mockCompiler) EmitByte(b byte) {
m.buf = append(m.buf, b)
}
func (m *mockCompiler) Emit8Bytes(b uint64) {
m.buf = append(m.buf, byte(b), byte(b>>8), byte(b>>16), byte(b>>24), byte(b>>32), byte(b>>40), byte(b>>48), byte(b>>56))
}
func (m *mockCompiler) Encode() {}
func (m *mockCompiler) Buf() []byte { return m.buf }
func (m *mockCompiler) TypeOf(v regalloc.VReg) (ret ssa.Type) {