wazevo(amd64): scaffolds instructions + constant lowering (#1906)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -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
609
internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
Normal file
609
internal/engine/wazevo/backend/isa/amd64/instr_encoding.go
Normal 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)))
|
||||
}
|
||||
898
internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
Normal file
898
internal/engine/wazevo/backend/isa/amd64/instr_encoding_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
57
internal/engine/wazevo/backend/isa/amd64/lower_constant.go
Normal file
57
internal/engine/wazevo/backend/isa/amd64/lower_constant.go
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
78
internal/engine/wazevo/backend/isa/amd64/operands.go
Normal file
78
internal/engine/wazevo/backend/isa/amd64/operands.go
Normal 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")
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
internal/engine/wazevo/backend/isa/amd64/reg_test.go
Normal file
36
internal/engine/wazevo/backend/isa/amd64/reg_test.go
Normal 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))
|
||||
})
|
||||
}
|
||||
}
|
||||
125
internal/engine/wazevo/backend/isa/amd64/util_test.go
Normal file
125
internal/engine/wazevo/backend/isa/amd64/util_test.go
Normal 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
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user