feat(amd64): encode legacy SSE packed binaries and imm8 shuffles
This commit is contained in:
@@ -756,6 +756,90 @@ func (e *enc) encodeSSEMove(m sseMove, ops []Operand) error {
|
||||
return e.emit(i)
|
||||
}
|
||||
|
||||
// --- legacy SSE packed binary and shuffles -----------------------------------
|
||||
|
||||
// sseBin describes a legacy (non-VEX) SSE packed/scalar binary op: an
|
||||
// optional mandatory prefix plus the 0F-prefixed opcode. Plan 9 asm
|
||||
// lists the source operand first, so MULPS X0, X1 computes X1 = X1 * X0.
|
||||
type sseBin struct {
|
||||
prefix byte // 0, 0x66, 0xF2 or 0xF3
|
||||
op byte
|
||||
}
|
||||
|
||||
var sseBinTable = map[string]sseBin{
|
||||
"ADDPS": {0, 0x58}, "ADDPD": {0x66, 0x58},
|
||||
"MULPS": {0, 0x59}, "MULPD": {0x66, 0x59},
|
||||
"SUBPS": {0, 0x5C}, "SUBPD": {0x66, 0x5C},
|
||||
"DIVPS": {0, 0x5E}, "DIVPD": {0x66, 0x5E},
|
||||
"ANDPS": {0, 0x54}, "ANDPD": {0x66, 0x54},
|
||||
"ORPS": {0, 0x56}, "ORPD": {0x66, 0x56},
|
||||
"XORPS": {0, 0x57}, "XORPD": {0x66, 0x57},
|
||||
"MINPS": {0, 0x5D}, "MINPD": {0x66, 0x5D},
|
||||
"MAXPS": {0, 0x5F}, "MAXPD": {0x66, 0x5F},
|
||||
"ADDSS": {0xF3, 0x58}, "ADDSD": {0xF2, 0x58},
|
||||
"MULSS": {0xF3, 0x59}, "MULSD": {0xF2, 0x59},
|
||||
"SUBSS": {0xF3, 0x5C}, "SUBSD": {0xF2, 0x5C},
|
||||
"DIVSS": {0xF3, 0x5E}, "DIVSD": {0xF2, 0x5E},
|
||||
"MINSS": {0xF3, 0x5D}, "MINSD": {0xF2, 0x5D},
|
||||
"MAXSS": {0xF3, 0x5F}, "MAXSD": {0xF2, 0x5F},
|
||||
"UNPCKLPS": {0, 0x14}, "UNPCKHPS": {0, 0x15},
|
||||
"UNPCKLPD": {0x66, 0x14}, "UNPCKHPD": {0x66, 0x15},
|
||||
}
|
||||
|
||||
// sseShuf describes a legacy SSE shuffle taking a trailing imm8
|
||||
// (PSHUFD/PSHUFHW/PSHUFLW also carry the packed-int 0x66/F3/F2 prefixes).
|
||||
type sseShuf struct {
|
||||
prefix byte
|
||||
op byte
|
||||
}
|
||||
|
||||
var sseShufTable = map[string]sseShuf{
|
||||
"SHUFPS": {0, 0xC6}, "SHUFPD": {0x66, 0xC6},
|
||||
"PSHUFD": {0x66, 0x70}, "PSHUFHW": {0xF3, 0x70}, "PSHUFLW": {0xF2, 0x70},
|
||||
}
|
||||
|
||||
// encodeSSEBin encodes reg = reg op rm (memory allowed for rm).
|
||||
func (e *enc) encodeSSEBin(m sseBin, ops []Operand) error {
|
||||
if len(ops) != 2 {
|
||||
return fmt.Errorf("SSE binary expects 2 operands, got %d", len(ops))
|
||||
}
|
||||
src, dst := ops[0], ops[1]
|
||||
dstReg, ok := dst.(Reg)
|
||||
if !ok || !dstReg.isVec() {
|
||||
return fmt.Errorf("SSE binary destination must be a vector register")
|
||||
}
|
||||
i := &instr{prefix: m.prefix, opcode: []byte{0x0F, m.op}, modrm: -1, sib: -1}
|
||||
if err := setRM(i, dstReg, src, 8); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.emit(i)
|
||||
}
|
||||
|
||||
// encodeSSEShuf encodes an imm8 shuffle: SHUFPS $imm, src, dst.
|
||||
func (e *enc) encodeSSEShuf(m sseShuf, ops []Operand) error {
|
||||
if len(ops) != 3 {
|
||||
return fmt.Errorf("SSE shuffle expects 3 operands, got %d", len(ops))
|
||||
}
|
||||
imm, ok := ops[0].(Imm)
|
||||
if !ok {
|
||||
return fmt.Errorf("SSE shuffle needs an imm8 first operand")
|
||||
}
|
||||
if imm < -128 || imm > 255 {
|
||||
return fmt.Errorf("SSE shuffle imm8 %d out of range", imm)
|
||||
}
|
||||
src, dst := ops[1], ops[2]
|
||||
dstReg, ok2 := dst.(Reg)
|
||||
if !ok2 || !dstReg.isVec() {
|
||||
return fmt.Errorf("SSE shuffle destination must be a vector register")
|
||||
}
|
||||
i := &instr{prefix: m.prefix, opcode: []byte{0x0F, m.op}, modrm: -1, sib: -1}
|
||||
if err := setRM(i, dstReg, src, 8); err != nil {
|
||||
return err
|
||||
}
|
||||
i.imm = []byte{byte(int8(imm))}
|
||||
return e.emit(i)
|
||||
}
|
||||
|
||||
// --- CVTSL2SD / CVTSQ2SD -----------------------------------------------------
|
||||
|
||||
// encodeCvtsi2sd encodes a signed integer to scalar double conversion
|
||||
|
||||
Reference in New Issue
Block a user