package amd64
import (
"fmt"
"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"
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
)
func (i *instruction ) encode (c backend .Compiler ) (needsLabelResolution bool ) {
switch kind := i .kind ; kind {
case nop0 , sourceOffsetInfo , defineUninitializedReg , fcvtToSintSequence , fcvtToUintSequence , nopUseReg :
case ret :
encodeRet (c )
case imm :
dst := regEncodings [i .op2 .reg ().RealReg ()]
con := i .u1
if i .b1 {
if lower32willSignExtendTo64 (con ) {
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 :
var rex rexInfo
if i .b1 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
aluOp := aluRmiROpcode (i .u1 )
if aluOp == aluRmiROpcodeMul {
op1 := i .op1
const regMemOpc , regMemOpcNum = 0x0FAF , 2
switch op1 .kind {
case operandKindReg :
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , legacyPrefixesNone , regMemOpc , regMemOpcNum , dst , src , rex )
case operandKindMem :
m := i .op1 .addressMode ()
encodeRegMem (c , legacyPrefixesNone , regMemOpc , regMemOpcNum , dst , m , rex )
case operandKindImm32 :
imm8 := lower8willSignExtendTo32 (op1 .imm32 ())
var opc uint32
if imm8 {
opc = 0x6b
} else {
opc = 0x69
}
encodeRegReg (c , legacyPrefixesNone , opc , 1 , dst , dst , rex )
if imm8 {
c .EmitByte (byte (op1 .imm32 ()))
} else {
c .Emit4Bytes (op1 .imm32 ())
}
default :
panic ("BUG: invalid operand kind" )
}
} else {
const opcodeNum = 1
var opcR , opcM , subOpcImm uint32
switch aluOp {
case aluRmiROpcodeAdd :
opcR , opcM , subOpcImm = 0x01 , 0x03 , 0x0
case aluRmiROpcodeSub :
opcR , opcM , subOpcImm = 0x29 , 0x2b , 0x5
case aluRmiROpcodeAnd :
opcR , opcM , subOpcImm = 0x21 , 0x23 , 0x4
case aluRmiROpcodeOr :
opcR , opcM , subOpcImm = 0x09 , 0x0b , 0x1
case aluRmiROpcodeXor :
opcR , opcM , subOpcImm = 0x31 , 0x33 , 0x6
default :
panic ("BUG: invalid aluRmiROpcode" )
}
op1 := i .op1
switch op1 .kind {
case operandKindReg :
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , legacyPrefixesNone , opcR , opcodeNum , src , dst , rex )
case operandKindMem :
m := i .op1 .addressMode ()
encodeRegMem (c , legacyPrefixesNone , opcM , opcodeNum , dst , m , rex )
case operandKindImm32 :
imm8 := lower8willSignExtendTo32 (op1 .imm32 ())
var opc uint32
if imm8 {
opc = 0x83
} else {
opc = 0x81
}
encodeRegReg (c , legacyPrefixesNone , opc , opcodeNum , regEnc (subOpcImm ), dst , rex )
if imm8 {
c .EmitByte (byte (op1 .imm32 ()))
} else {
c .Emit4Bytes (op1 .imm32 ())
}
default :
panic ("BUG: invalid operand kind" )
}
}
case movRR :
src := regEncodings [i .op1 .reg ().RealReg ()]
dst := regEncodings [i .op2 .reg ().RealReg ()]
var rex rexInfo
if i .b1 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
encodeRegReg (c , legacyPrefixesNone , 0x89 , 1 , src , dst , rex )
case xmmRmR , blendvpd :
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 sseOpcodeBlendvps :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3814 , 3
case sseOpcodeBlendvpd :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3815 , 3
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
case sseOpcodePmulhrsw :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F380B , 3
case sseOpcodeUnpcklps :
legPrex , opcode , opcodeNum = legacyPrefixesNone , 0x0F14 , 2
case sseOpcodePmaddubsw :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3804 , 3
default :
if kind == blendvpd {
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3815 , 3
} else {
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , op ))
}
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 ).clearW ()
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , legPrex , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
m := i .op1 .addressMode ()
encodeRegMem (c , legPrex , opcode , opcodeNum , dst , m , rex )
} 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 ()
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , legPrefix , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
m := i .op1 .addressMode ()
encodeRegMem (c , legPrefix , opcode , opcodeNum , dst , m , rex )
} 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
case sseOpcodeXorps :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0F57 , 2
case sseOpcodeXorpd :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F57 , 2
case sseOpcodeCvtdq2ps :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0F5B , 2
case sseOpcodeCvtdq2pd :
prefix , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0FE6 , 2
case sseOpcodeCvtps2pd :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0F5A , 2
case sseOpcodeCvtpd2ps :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F5A , 2
case sseOpcodeCvttps2dq :
prefix , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0F5B , 2
case sseOpcodeCvttpd2dq :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0FE6 , 2
default :
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , op ))
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 ).clearW ()
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , prefix , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
m := i .op1 .addressMode ()
needsLabelResolution = encodeRegMem (c , prefix , opcode , opcodeNum , dst , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
case xmmUnaryRmRImm :
var prefix legacyPrefixes
var opcode uint32
var opcodeNum uint32
op := sseOpcode (i .u1 )
switch op {
case sseOpcodeRoundps :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f3a08 , 3
case sseOpcodeRoundss :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f3a0a , 3
case sseOpcodeRoundpd :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f3a09 , 3
case sseOpcodeRoundsd :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f3a0b , 3
}
rex := rexInfo (0 ).clearW ()
dst := regEncodings [i .op2 .reg ().RealReg ()]
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , prefix , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
m := i .op1 .addressMode ()
encodeRegMem (c , prefix , opcode , opcodeNum , dst , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
c .EmitByte (byte (i .u2 ))
case unaryRmR :
var prefix legacyPrefixes
var opcode uint32
var opcodeNum uint32
op := unaryRmROpcode (i .u1 )
switch op {
case unaryRmROpcodeBsr :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0fbd , 2
case unaryRmROpcodeBsf :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0fbc , 2
case unaryRmROpcodeLzcnt :
prefix , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0fbd , 2
case unaryRmROpcodeTzcnt :
prefix , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0fbc , 2
case unaryRmROpcodePopcnt :
prefix , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0fb8 , 2
default :
panic (fmt .Sprintf ("Unsupported unaryRmROpcode: %s" , op ))
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , prefix , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
m := i .op1 .addressMode ()
encodeRegMem (c , prefix , opcode , opcodeNum , dst , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
case not :
var prefix legacyPrefixes
src := regEncodings [i .op1 .reg ().RealReg ()]
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
subopcode := uint8 (2 )
encodeEncEnc (c , prefix , 0xf7 , 1 , subopcode , uint8 (src ), rex )
case neg :
var prefix legacyPrefixes
src := regEncodings [i .op1 .reg ().RealReg ()]
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
subopcode := uint8 (3 )
encodeEncEnc (c , prefix , 0xf7 , 1 , subopcode , uint8 (src ), rex )
case div :
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
var subopcode uint8
if i .u1 != 0 {
subopcode = 7
} else {
subopcode = 6
}
divisor := i .op1
if divisor .kind == operandKindReg {
src := regEncodings [divisor .reg ().RealReg ()]
encodeEncEnc (c , legacyPrefixesNone , 0xf7 , 1 , subopcode , uint8 (src ), rex )
} else if divisor .kind == operandKindMem {
m := divisor .addressMode ()
encodeEncMem (c , legacyPrefixesNone , 0xf7 , 1 , subopcode , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
case mulHi :
var prefix legacyPrefixes
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
signed := i .u1 != 0
var subopcode uint8
if signed {
subopcode = 5
} else {
subopcode = 4
}
src2 := i .op1
if src2 .kind == operandKindReg {
src := regEncodings [src2 .reg ().RealReg ()]
encodeEncEnc (c , prefix , 0xf7 , 1 , subopcode , uint8 (src ), rex )
} else if src2 .kind == operandKindMem {
m := src2 .addressMode ()
encodeEncMem (c , prefix , 0xf7 , 1 , subopcode , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
case signExtendData :
if i .b1 {
c .EmitByte (0x48 )
c .EmitByte (0x99 )
} else {
c .EmitByte (0x99 )
}
case movzxRmR , movsxRmR :
signed := i .kind == movsxRmR
ext := extMode (i .u1 )
var opcode uint32
var opcodeNum uint32
var rex rexInfo
switch ext {
case extModeBL :
if signed {
opcode , opcodeNum , rex = 0x0fbe , 2 , rex .clearW ()
} else {
opcode , opcodeNum , rex = 0x0fb6 , 2 , rex .clearW ()
}
case extModeBQ :
if signed {
opcode , opcodeNum , rex = 0x0fbe , 2 , rex .setW ()
} else {
opcode , opcodeNum , rex = 0x0fb6 , 2 , rex .setW ()
}
case extModeWL :
if signed {
opcode , opcodeNum , rex = 0x0fbf , 2 , rex .clearW ()
} else {
opcode , opcodeNum , rex = 0x0fb7 , 2 , rex .clearW ()
}
case extModeWQ :
if signed {
opcode , opcodeNum , rex = 0x0fbf , 2 , rex .setW ()
} else {
opcode , opcodeNum , rex = 0x0fb7 , 2 , rex .setW ()
}
case extModeLQ :
if signed {
opcode , opcodeNum , rex = 0x63 , 1 , rex .setW ()
} else {
opcode , opcodeNum , rex = 0x8b , 1 , rex .clearW ()
}
default :
panic ("BUG: invalid extMode" )
}
op := i .op1
dst := regEncodings [i .op2 .reg ().RealReg ()]
switch op .kind {
case operandKindReg :
src := regEncodings [op .reg ().RealReg ()]
if ext == extModeBL || ext == extModeBQ {
if e := src .encoding (); e >= 4 && e <= 7 {
rex = rex .always ()
}
}
encodeRegReg (c , legacyPrefixesNone , opcode , opcodeNum , dst , src , rex )
case operandKindMem :
m := op .addressMode ()
encodeRegMem (c , legacyPrefixesNone , opcode , opcodeNum , dst , m , rex )
default :
panic ("BUG: invalid operand kind" )
}
case mov64MR :
m := i .op1 .addressMode ()
encodeLoad64 (c , m , i .op2 .reg ().RealReg ())
case lea :
needsLabelResolution = true
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 ).setW ()
const opcode , opcodeNum = 0x8d , 1
switch i .op1 .kind {
case operandKindMem :
a := i .op1 .addressMode ()
encodeRegMem (c , legacyPrefixesNone , opcode , opcodeNum , dst , a , rex )
case operandKindLabel :
rex .encode (c , regRexBit (byte (dst )), 0 )
c .EmitByte (byte ((opcode ) & 0xff ))
c .EmitByte (encodeModRM (0b00 , dst .encoding (), 0b101 ))
c .Emit4Bytes (0xffffffff )
default :
panic ("BUG: invalid operand kind" )
}
case movRM :
m := i .op2 .addressMode ()
src := regEncodings [i .op1 .reg ().RealReg ()]
var rex rexInfo
switch i .u1 {
case 1 :
if e := src .encoding (); e >= 4 && e <= 7 {
rex = rex .always ()
}
encodeRegMem (c , legacyPrefixesNone , 0x88 , 1 , src , m , rex .clearW ())
case 2 :
encodeRegMem (c , legacyPrefixes0x66 , 0x89 , 1 , src , m , rex .clearW ())
case 4 :
encodeRegMem (c , legacyPrefixesNone , 0x89 , 1 , src , m , rex .clearW ())
case 8 :
encodeRegMem (c , legacyPrefixesNone , 0x89 , 1 , src , m , rex .setW ())
default :
panic (fmt .Sprintf ("BUG: invalid size %d: %s" , i .u1 , i .String ()))
}
case shiftR :
src := regEncodings [i .op2 .reg ().RealReg ()]
amount := i .op1
var opcode uint32
var prefix legacyPrefixes
rex := rexInfo (0 )
if i .b1 {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
switch amount .kind {
case operandKindReg :
if amount .reg () != rcxVReg {
panic ("BUG: invalid reg operand: must be rcx" )
}
opcode , prefix = 0xd3 , legacyPrefixesNone
encodeEncEnc (c , prefix , opcode , 1 , uint8 (i .u1 ), uint8 (src ), rex )
case operandKindImm32 :
opcode , prefix = 0xc1 , legacyPrefixesNone
encodeEncEnc (c , prefix , opcode , 1 , uint8 (i .u1 ), uint8 (src ), rex )
c .EmitByte (byte (amount .imm32 ()))
default :
panic ("BUG: invalid operand kind" )
}
case xmmRmiReg :
const legPrefix = legacyPrefixes0x66
rex := rexInfo (0 ).clearW ()
dst := regEncodings [i .op2 .reg ().RealReg ()]
var opcode uint32
var regDigit uint8
op := sseOpcode (i .u1 )
op1 := i .op1
if i .op1 .kind == operandKindImm32 {
switch op {
case sseOpcodePsllw :
opcode , regDigit = 0x0f71 , 6
case sseOpcodePslld :
opcode , regDigit = 0x0f72 , 6
case sseOpcodePsllq :
opcode , regDigit = 0x0f73 , 6
case sseOpcodePsraw :
opcode , regDigit = 0x0f71 , 4
case sseOpcodePsrad :
opcode , regDigit = 0x0f72 , 4
case sseOpcodePsrlw :
opcode , regDigit = 0x0f71 , 2
case sseOpcodePsrld :
opcode , regDigit = 0x0f72 , 2
case sseOpcodePsrlq :
opcode , regDigit = 0x0f73 , 2
default :
panic ("invalid opcode" )
}
encodeEncEnc (c , legPrefix , opcode , 2 , regDigit , uint8 (dst ), rex )
imm32 := op1 .imm32 ()
if imm32 > 0xff &imm32 {
panic ("immediate value does not fit 1 byte" )
}
c .EmitByte (uint8 (imm32 ))
} else {
switch op {
case sseOpcodePsllw :
opcode = 0x0ff1
case sseOpcodePslld :
opcode = 0x0ff2
case sseOpcodePsllq :
opcode = 0x0ff3
case sseOpcodePsraw :
opcode = 0x0fe1
case sseOpcodePsrad :
opcode = 0x0fe2
case sseOpcodePsrlw :
opcode = 0x0fd1
case sseOpcodePsrld :
opcode = 0x0fd2
case sseOpcodePsrlq :
opcode = 0x0fd3
default :
panic ("invalid opcode" )
}
if op1 .kind == operandKindReg {
reg := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , legPrefix , opcode , 2 , dst , reg , rex )
} else if op1 .kind == operandKindMem {
m := op1 .addressMode ()
encodeRegMem (c , legPrefix , opcode , 2 , dst , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
}
case cmpRmiR :
var opcode uint32
isCmp := i .u1 != 0
rex := rexInfo (0 )
_64 := i .b1
if _64 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
op1 := i .op1
switch op1 .kind {
case operandKindReg :
reg := regEncodings [op1 .reg ().RealReg ()]
if isCmp {
opcode = 0x39
} else {
opcode = 0x85
}
encodeRegReg (c , legacyPrefixesNone , opcode , 1 , reg , dst , rex )
case operandKindMem :
if isCmp {
opcode = 0x3b
} else {
opcode = 0x85
}
m := op1 .addressMode ()
encodeRegMem (c , legacyPrefixesNone , opcode , 1 , dst , m , rex )
case operandKindImm32 :
imm32 := op1 .imm32 ()
useImm8 := isCmp && lower8willSignExtendTo32 (imm32 )
var subopcode uint8
switch {
case isCmp && useImm8 :
opcode , subopcode = 0x83 , 7
case isCmp && !useImm8 :
opcode , subopcode = 0x81 , 7
default :
opcode , subopcode = 0xf7 , 0
}
encodeEncEnc (c , legacyPrefixesNone , opcode , 1 , subopcode , uint8 (dst ), rex )
if useImm8 {
c .EmitByte (uint8 (imm32 ))
} else {
c .Emit4Bytes (imm32 )
}
default :
panic ("BUG: invalid operand kind" )
}
case setcc :
cc := cond (i .u1 )
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 ).clearW ().always ()
opcode := uint32 (0x0f90 ) + uint32 (cc )
encodeEncEnc (c , legacyPrefixesNone , opcode , 2 , 0 , uint8 (dst ), rex )
case cmove :
cc := cond (i .u1 )
dst := regEncodings [i .op2 .reg ().RealReg ()]
rex := rexInfo (0 )
if i .b1 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
opcode := uint32 (0x0f40 ) + uint32 (cc )
src := i .op1
switch src .kind {
case operandKindReg :
srcReg := regEncodings [src .reg ().RealReg ()]
encodeRegReg (c , legacyPrefixesNone , opcode , 2 , dst , srcReg , rex )
case operandKindMem :
m := src .addressMode ()
encodeRegMem (c , legacyPrefixesNone , opcode , 2 , dst , m , rex )
default :
panic ("BUG: invalid operand kind" )
}
case push64 :
op := i .op1
switch op .kind {
case operandKindReg :
dst := regEncodings [op .reg ().RealReg ()]
if dst .rexBit () > 0 {
c .EmitByte (rexEncodingDefault | 0x1 )
}
c .EmitByte (0x50 | dst .encoding ())
case operandKindMem :
m := op .addressMode ()
encodeRegMem (
c , legacyPrefixesNone , 0xff , 1 , regEnc (6 ), m , rexInfo (0 ).clearW (),
)
case operandKindImm32 :
c .EmitByte (0x68 )
c .Emit4Bytes (op .imm32 ())
default :
panic ("BUG: invalid operand kind" )
}
case pop64 :
dst := regEncodings [i .op1 .reg ().RealReg ()]
if dst .rexBit () > 0 {
c .EmitByte (rexEncodingDefault | 0x1 )
}
c .EmitByte (0x58 | dst .encoding ())
case xmmMovRM :
var legPrefix legacyPrefixes
var opcode uint32
const opcodeNum = 2
switch sseOpcode (i .u1 ) {
case sseOpcodeMovaps :
legPrefix , opcode = legacyPrefixesNone , 0x0f29
case sseOpcodeMovapd :
legPrefix , opcode = legacyPrefixes0x66 , 0x0f29
case sseOpcodeMovdqa :
legPrefix , opcode = legacyPrefixes0x66 , 0x0f7f
case sseOpcodeMovdqu :
legPrefix , opcode = legacyPrefixes0xF3 , 0x0f7f
case sseOpcodeMovss :
legPrefix , opcode = legacyPrefixes0xF3 , 0x0f11
case sseOpcodeMovsd :
legPrefix , opcode = legacyPrefixes0xF2 , 0x0f11
case sseOpcodeMovups :
legPrefix , opcode = legacyPrefixesNone , 0x0f11
case sseOpcodeMovupd :
legPrefix , opcode = legacyPrefixes0x66 , 0x0f11
default :
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , sseOpcode (i .u1 )))
}
dst := regEncodings [i .op1 .reg ().RealReg ()]
encodeRegMem (c , legPrefix , opcode , opcodeNum , dst , i .op2 .addressMode (), rexInfo (0 ).clearW ())
case xmmLoadConst :
panic ("TODO" )
case xmmToGpr :
var legPrefix legacyPrefixes
var opcode uint32
var argSwap bool
const opcodeNum = 2
switch sseOpcode (i .u1 ) {
case sseOpcodeMovd , sseOpcodeMovq :
legPrefix , opcode , argSwap = legacyPrefixes0x66 , 0x0f7e , false
case sseOpcodeMovmskps :
legPrefix , opcode , argSwap = legacyPrefixesNone , 0x0f50 , true
case sseOpcodeMovmskpd :
legPrefix , opcode , argSwap = legacyPrefixes0x66 , 0x0f50 , true
case sseOpcodePmovmskb :
legPrefix , opcode , argSwap = legacyPrefixes0x66 , 0x0fd7 , true
case sseOpcodeCvttss2si :
legPrefix , opcode , argSwap = legacyPrefixes0xF3 , 0x0f2c , true
case sseOpcodeCvttsd2si :
legPrefix , opcode , argSwap = legacyPrefixes0xF2 , 0x0f2c , true
default :
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , sseOpcode (i .u1 )))
}
var rex rexInfo
if i .b1 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
src := regEncodings [i .op1 .reg ().RealReg ()]
dst := regEncodings [i .op2 .reg ().RealReg ()]
if argSwap {
src , dst = dst , src
}
encodeRegReg (c , legPrefix , opcode , opcodeNum , src , dst , rex )
case cvtUint64ToFloatSeq :
panic ("TODO" )
case cvtFloatToSintSeq :
panic ("TODO" )
case cvtFloatToUintSeq :
panic ("TODO" )
case xmmMinMaxSeq :
panic ("TODO" )
case xmmCmpRmR :
var prefix legacyPrefixes
var opcode uint32
var opcodeNum uint32
rex := rexInfo (0 )
_64 := i .b1
if _64 {
rex = rex .setW ()
} else {
rex = rex .clearW ()
}
op := sseOpcode (i .u1 )
switch op {
case sseOpcodePtest :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f3817 , 3
case sseOpcodeUcomisd :
prefix , opcode , opcodeNum = legacyPrefixes0x66 , 0x0f2e , 2
case sseOpcodeUcomiss :
prefix , opcode , opcodeNum = legacyPrefixesNone , 0x0f2e , 2
default :
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , op ))
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
op1 := i .op1
switch op1 .kind {
case operandKindReg :
reg := regEncodings [op1 .reg ().RealReg ()]
encodeRegReg (c , prefix , opcode , opcodeNum , dst , reg , rex )
case operandKindMem :
m := op1 .addressMode ()
encodeRegMem (c , prefix , opcode , opcodeNum , dst , m , rex )
default :
panic ("BUG: invalid operand kind" )
}
case xmmRmRImm :
op := sseOpcode (i .u1 )
var legPrex legacyPrefixes
var opcode uint32
var opcodeNum uint32
var swap bool
switch op {
case sseOpcodeCmpps :
legPrex , opcode , opcodeNum = legacyPrefixesNone , 0x0FC2 , 2
case sseOpcodeCmppd :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0FC2 , 2
case sseOpcodeCmpss :
legPrex , opcode , opcodeNum = legacyPrefixes0xF3 , 0x0FC2 , 2
case sseOpcodeCmpsd :
legPrex , opcode , opcodeNum = legacyPrefixes0xF2 , 0x0FC2 , 2
case sseOpcodeInsertps :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A21 , 3
case sseOpcodePalignr :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A0F , 3
case sseOpcodePinsrb :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A20 , 3
case sseOpcodePinsrw :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0FC4 , 2
case sseOpcodePinsrd , sseOpcodePinsrq :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A22 , 3
case sseOpcodePextrb :
swap = true
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A14 , 3
case sseOpcodePextrw :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0FC5 , 2
case sseOpcodePextrd , sseOpcodePextrq :
swap = true
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A16 , 3
case sseOpcodePshufd :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F70 , 2
case sseOpcodeRoundps :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A08 , 3
case sseOpcodeRoundpd :
legPrex , opcode , opcodeNum = legacyPrefixes0x66 , 0x0F3A09 , 3
case sseOpcodeShufps :
legPrex , opcode , opcodeNum = legacyPrefixesNone , 0x0FC6 , 2
default :
panic (fmt .Sprintf ("Unsupported sseOpcode: %s" , op ))
}
dst := regEncodings [i .op2 .reg ().RealReg ()]
var rex rexInfo
if op == sseOpcodePextrq || op == sseOpcodePinsrq {
rex = rexInfo (0 ).setW ()
} else {
rex = rexInfo (0 ).clearW ()
}
op1 := i .op1
if op1 .kind == operandKindReg {
src := regEncodings [op1 .reg ().RealReg ()]
if swap {
src , dst = dst , src
}
encodeRegReg (c , legPrex , opcode , opcodeNum , dst , src , rex )
} else if i .op1 .kind == operandKindMem {
if swap {
panic ("BUG: this is not possible to encode" )
}
m := i .op1 .addressMode ()
encodeRegMem (c , legPrex , opcode , opcodeNum , dst , m , rex )
} else {
panic ("BUG: invalid operand kind" )
}
c .EmitByte (byte (i .u2 ))
case jmp :
const (
regMemOpcode = 0xff
regMemOpcodeNum = 1
regMemSubOpcode = 4
)
op := i .op1
switch op .kind {
case operandKindLabel :
needsLabelResolution = true
fallthrough
case operandKindImm32 :
c .EmitByte (0xe9 )
c .Emit4Bytes (op .imm32 ())
case operandKindMem :
m := op .addressMode ()
encodeRegMem (c ,
legacyPrefixesNone ,
regMemOpcode , regMemOpcodeNum ,
regMemSubOpcode , m , rexInfo (0 ).clearW (),
)
case operandKindReg :
r := op .reg ().RealReg ()
encodeRegReg (
c ,
legacyPrefixesNone ,
regMemOpcode , regMemOpcodeNum ,
regMemSubOpcode ,
regEncodings [r ], rexInfo (0 ).clearW (),
)
default :
panic ("BUG: invalid operand kind" )
}
case jmpIf :
op := i .op1
switch op .kind {
case operandKindLabel :
needsLabelResolution = true
fallthrough
case operandKindImm32 :
c .EmitByte (0x0f )
c .EmitByte (0x80 | cond (i .u1 ).encoding ())
c .Emit4Bytes (op .imm32 ())
default :
panic ("BUG: invalid operand kind" )
}
case jmpTableIsland :
needsLabelResolution = true
for tc := uint64 (0 ); tc < i .u2 ; tc ++ {
c .Emit8Bytes (0 )
}
case exitSequence :
execCtx := i .op1 .reg ()
allocatedAmode := i .op2 .addressMode ()
*allocatedAmode = amode {
kindWithShift : uint32 (amodeImmReg ), base : execCtx ,
imm32 : wazevoapi .ExecutionContextOffsetOriginalFramePointer .U32 (),
}
encodeLoad64 (c , allocatedAmode , rbp )
allocatedAmode .imm32 = wazevoapi .ExecutionContextOffsetOriginalStackPointer .U32 ()
encodeLoad64 (c , allocatedAmode , rsp )
encodeRet (c )
case ud2 :
c .EmitByte (0x0f )
c .EmitByte (0x0b )
case call :
c .EmitByte (0xe8 )
c .AddRelocationInfo (ssa .FuncRef (i .u1 ))
c .Emit4Bytes (uint32 (i .u2 ))
case callIndirect :
op := i .op1
const opcodeNum = 1
const opcode = 0xff
rex := rexInfo (0 ).clearW ()
switch op .kind {
case operandKindReg :
dst := regEncodings [op .reg ().RealReg ()]
encodeRegReg (c ,
legacyPrefixesNone ,
opcode , opcodeNum ,
regEnc (2 ),
dst ,
rex ,
)
case operandKindMem :
m := op .addressMode ()
encodeRegMem (c ,
legacyPrefixesNone ,
opcode , opcodeNum ,
regEnc (2 ),
m ,
rex ,
)
default :
panic ("BUG: invalid operand kind" )
}
case xchg :
src , dst := regEncodings [i .op1 .reg ().RealReg ()], i .op2
size := i .u1
var rex rexInfo
var opcode uint32
lp := legacyPrefixesNone
switch size {
case 8 :
opcode = 0x87
rex = rexInfo (0 ).setW ()
case 4 :
opcode = 0x87
rex = rexInfo (0 ).clearW ()
case 2 :
lp = legacyPrefixes0x66
opcode = 0x87
rex = rexInfo (0 ).clearW ()
case 1 :
opcode = 0x86
if i .op2 .kind == operandKindReg {
panic ("TODO?: xchg on two 1-byte registers" )
}
if e := src .encoding (); e >= 4 && e <= 7 {
rex = rexInfo (0 ).always ()
}
default :
panic (fmt .Sprintf ("BUG: invalid size %d: %s" , size , i .String ()))
}
switch dst .kind {
case operandKindMem :
m := dst .addressMode ()
encodeRegMem (c , lp , opcode , 1 , src , m , rex )
case operandKindReg :
r := dst .reg ().RealReg ()
encodeRegReg (c , lp , opcode , 1 , src , regEncodings [r ], rex )
default :
panic ("BUG: invalid operand kind" )
}
case lockcmpxchg :
src , dst := regEncodings [i .op1 .reg ().RealReg ()], i .op2
size := i .u1
var rex rexInfo
var opcode uint32
lp := legacyPrefixes0xF0
switch size {
case 8 :
opcode = 0x0FB1
rex = rexInfo (0 ).setW ()
case 4 :
opcode = 0x0FB1
rex = rexInfo (0 ).clearW ()
case 2 :
lp = legacyPrefixes0x660xF0
opcode = 0x0FB1
rex = rexInfo (0 ).clearW ()
case 1 :
opcode = 0x0FB0
if e := src .encoding (); e >= 4 && e <= 7 {
rex = rexInfo (0 ).always ()
}
default :
panic (fmt .Sprintf ("BUG: invalid size %d: %s" , size , i .String ()))
}
switch dst .kind {
case operandKindMem :
m := dst .addressMode ()
encodeRegMem (c , lp , opcode , 2 , src , m , rex )
default :
panic ("BUG: invalid operand kind" )
}
case lockxadd :
src , dst := regEncodings [i .op1 .reg ().RealReg ()], i .op2
size := i .u1
var rex rexInfo
var opcode uint32
lp := legacyPrefixes0xF0
switch size {
case 8 :
opcode = 0x0FC1
rex = rexInfo (0 ).setW ()
case 4 :
opcode = 0x0FC1
rex = rexInfo (0 ).clearW ()
case 2 :
lp = legacyPrefixes0x660xF0
opcode = 0x0FC1
rex = rexInfo (0 ).clearW ()
case 1 :
opcode = 0x0FC0
if e := src .encoding (); e >= 4 && e <= 7 {
rex = rexInfo (0 ).always ()
}
default :
panic (fmt .Sprintf ("BUG: invalid size %d: %s" , size , i .String ()))
}
switch dst .kind {
case operandKindMem :
m := dst .addressMode ()
encodeRegMem (c , lp , opcode , 2 , src , m , rex )
default :
panic ("BUG: invalid operand kind" )
}
case zeros :
r := i .op2 .reg ()
if r .RegType () == regalloc .RegTypeInt {
i .asAluRmiR (aluRmiROpcodeXor , newOperandReg (r ), r , true )
} else {
i .asXmmRmR (sseOpcodePxor , newOperandReg (r ), r )
}
i .encode (c )
case mfence :
c .EmitByte (0x0f )
c .EmitByte (0xae )
c .EmitByte (0xf0 )
default :
panic (fmt .Sprintf ("TODO: %v" , i .kind ))
}
return
}
func encodeLoad64(c backend .Compiler , m *amode , rd regalloc .RealReg ) {
dst := regEncodings [rd ]
encodeRegMem (c , legacyPrefixesNone , 0x8b , 1 , dst , m , rexInfo (0 ).setW ())
}
func encodeRet(c backend .Compiler ) {
c .EmitByte (0xc3 )
}
func encodeEncEnc(
c backend .Compiler ,
legPrefixes legacyPrefixes ,
opcodes uint32 ,
opcodeNum uint32 ,
r uint8 ,
rm uint8 ,
rex rexInfo ,
) {
legPrefixes .encode (c )
rex .encode (c , r >>3 , rm >>3 )
for opcodeNum > 0 {
opcodeNum --
c .EmitByte (byte ((opcodes >> (opcodeNum << 3 )) & 0xff ))
}
c .EmitByte (encodeModRM (3 , r &7 , rm &7 ))
}
func encodeRegReg(
c backend .Compiler ,
legPrefixes legacyPrefixes ,
opcodes uint32 ,
opcodeNum uint32 ,
r regEnc ,
rm regEnc ,
rex rexInfo ,
) {
encodeEncEnc (c , legPrefixes , opcodes , opcodeNum , uint8 (r ), uint8 (rm ), rex )
}
func encodeModRM(mod byte , reg byte , rm byte ) byte {
return mod <<6 | reg <<3 | rm
}
func encodeSIB(shift byte , encIndex byte , encBase byte ) byte {
return shift <<6 | encIndex <<3 | encBase
}
func encodeRegMem(
c backend .Compiler , legPrefixes legacyPrefixes , opcodes uint32 , opcodeNum uint32 , r regEnc , m *amode , rex rexInfo ,
) (needsLabelResolution bool ) {
needsLabelResolution = encodeEncMem (c , legPrefixes , opcodes , opcodeNum , uint8 (r ), m , rex )
return
}
func encodeEncMem(
c backend .Compiler , legPrefixes legacyPrefixes , opcodes uint32 , opcodeNum uint32 , r uint8 , m *amode , rex rexInfo ,
) (needsLabelResolution bool ) {
legPrefixes .encode (c )
const (
modNoDisplacement = 0b00
modShortDisplacement = 0b01
modLongDisplacement = 0b10
useSBI = 4
)
switch m .kind () {
case amodeImmReg , amodeImmRBP :
base := m .base .RealReg ()
baseEnc := regEncodings [base ]
rex .encode (c , regRexBit (r ), baseEnc .rexBit ())
for opcodeNum > 0 {
opcodeNum --
c .EmitByte (byte ((opcodes >> (opcodeNum << 3 )) & 0xff ))
}
const sibByte = 0x24
immZero , baseRbp , baseR13 := m .imm32 == 0 , base == rbp , base == r13
short := lower8willSignExtendTo32 (m .imm32 )
rspOrR12 := base == rsp || base == r12
if immZero && !baseRbp && !baseR13 {
c .EmitByte (encodeModRM (modNoDisplacement , regEncoding (r ), baseEnc .encoding ()))
if rspOrR12 {
c .EmitByte (sibByte )
}
} else if short {
c .EmitByte (encodeModRM (modShortDisplacement , regEncoding (r ), baseEnc .encoding ()))
if rspOrR12 {
c .EmitByte (sibByte )
}
c .EmitByte (byte (m .imm32 ))
} else {
c .EmitByte (encodeModRM (modLongDisplacement , regEncoding (r ), baseEnc .encoding ()))
if rspOrR12 {
c .EmitByte (sibByte )
}
c .Emit4Bytes (m .imm32 )
}
case amodeRegRegShift :
base := m .base .RealReg ()
baseEnc := regEncodings [base ]
index := m .index .RealReg ()
indexEnc := regEncodings [index ]
if index == rsp {
panic ("BUG: rsp can't be used as index of addressing mode" )
}
rex .encodeForIndex (c , regEnc (r ), indexEnc , baseEnc )
for opcodeNum > 0 {
opcodeNum --
c .EmitByte (byte ((opcodes >> (opcodeNum << 3 )) & 0xff ))
}
immZero , baseRbp , baseR13 := m .imm32 == 0 , base == rbp , base == r13
if immZero && !baseRbp && !baseR13 {
c .EmitByte (encodeModRM (modNoDisplacement , regEncoding (r ), useSBI ))
c .EmitByte (encodeSIB (m .shift (), indexEnc .encoding (), baseEnc .encoding ()))
} else if lower8willSignExtendTo32 (m .imm32 ) {
c .EmitByte (encodeModRM (modShortDisplacement , regEncoding (r ), useSBI ))
c .EmitByte (encodeSIB (m .shift (), indexEnc .encoding (), baseEnc .encoding ()))
c .EmitByte (byte (m .imm32 ))
} else {
c .EmitByte (encodeModRM (modLongDisplacement , regEncoding (r ), useSBI ))
c .EmitByte (encodeSIB (m .shift (), indexEnc .encoding (), baseEnc .encoding ()))
c .Emit4Bytes (m .imm32 )
}
case amodeRipRel :
rex .encode (c , regRexBit (r ), 0 )
for opcodeNum > 0 {
opcodeNum --
c .EmitByte (byte ((opcodes >> (opcodeNum << 3 )) & 0xff ))
}
c .EmitByte (encodeModRM (0b00 , regEncoding (r ), 0b101 ))
needsLabelResolution = true
c .Emit4Bytes (0 )
default :
panic ("BUG: invalid addressing mode" )
}
return
}
const (
rexEncodingDefault byte = 0x40
rexEncodingW = rexEncodingDefault | 0x08
)
type rexInfo byte
func (ri rexInfo ) setW () rexInfo {
return ri | 0x01
}
func (ri rexInfo ) clearW () rexInfo {
return ri & 0x02
}
func (ri rexInfo ) always () rexInfo {
return ri | 0x02
}
func (ri rexInfo ) notAlways () rexInfo {
return ri & 0x01
}
func (ri rexInfo ) encode (c backend .Compiler , r uint8 , b uint8 ) {
var w byte = 0
if ri &0x01 != 0 {
w = 0x01
}
rex := rexEncodingDefault | w <<3 | r <<2 | b
if rex != rexEncodingDefault || ri &0x02 != 0 {
c .EmitByte (rex )
}
}
func (ri rexInfo ) encodeForIndex (c backend .Compiler , encR regEnc , encIndex regEnc , encBase regEnc ) {
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 != 0 {
c .EmitByte (rex )
}
}
type regEnc byte
func (r regEnc ) rexBit () byte {
return regRexBit (byte (r ))
}
func (r regEnc ) encoding () byte {
return regEncoding (byte (r ))
}
func regRexBit(r byte ) byte {
return r >> 3
}
func regEncoding(r byte ) byte {
return 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 )))
}
func lower8willSignExtendTo32(x uint32 ) bool {
xs := int32 (x )
return xs == ((xs << 24 ) >> 24 )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .