feat(amd64): encode legacy SSE packed binaries and imm8 shuffles
Test / vet (push) Successful in 47s
Test / test (push) Successful in 2m34s
Test / build (push) Successful in 41s

This commit is contained in:
2026-08-27 17:15:10 +02:00
parent 941f7fa990
commit be2ceaafb9
4 changed files with 154 additions and 0 deletions
+84
View File
@@ -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