feat(asm): byte-identical go-flac AVX2 assembly with scalar families and jump relaxation
Assisted-by: Qwen 3.8 Max Preview
This commit is contained in:
+31
@@ -133,6 +133,17 @@ var vexTable = map[string]vexSpec{
|
||||
"VZEROUPPER": {1, 0x77, 0, 0, -1, vexZero},
|
||||
}
|
||||
|
||||
// vexVarShift maps the shift mnemonics to their variable-count opcode — the
|
||||
// form whose count comes from an XMM register or memory (VPSRLQ X0, Y8, Y8),
|
||||
// an ordinary NDS encoding rather than the /digit immediate form above.
|
||||
var vexVarShift = map[string]byte{
|
||||
"VPSLLD": 0xF2,
|
||||
"VPSLLQ": 0xF3,
|
||||
"VPSRAD": 0xE2,
|
||||
"VPSRLD": 0xD2,
|
||||
"VPSRLQ": 0xD3,
|
||||
}
|
||||
|
||||
// vexMoveSpec describes a VEX move, which takes different opcodes (and
|
||||
// sometimes a different VEX.W) per operand direction. The Go assembler
|
||||
// encodes a vector→vector move with the store-form opcode (reg = source,
|
||||
@@ -180,6 +191,17 @@ func (e *enc) encodeVex(mnemUpper string, ops []Operand) error {
|
||||
if ms, ok := vexMoveTable[mnemUpper]; ok {
|
||||
return e.encodeVexMove(mnemUpper, ms, ops)
|
||||
}
|
||||
// The shifts come in two shapes under one mnemonic: an immediate count
|
||||
// ($imm, src, dst) and a variable count in an XMM register or memory
|
||||
// (count, src, dst), the latter an ordinary NDS form.
|
||||
if op, ok := vexVarShift[mnemUpper]; ok && len(ops) == 3 {
|
||||
if _, isImm := ops[0].(Imm); !isImm {
|
||||
if !vecOrMem(ops[0]) {
|
||||
return fmt.Errorf("%s: shift count must be an immediate, a vector register or memory", mnemUpper)
|
||||
}
|
||||
return e.encodeVexNDS3(vexSpec{mapSel: 1, opcode: op, pp: 1, opdigit: -1, form: vexNDS3}, ops)
|
||||
}
|
||||
}
|
||||
spec := vexTable[mnemUpper]
|
||||
switch spec.form {
|
||||
case vexNDS3:
|
||||
@@ -483,6 +505,15 @@ func vecReg(op Operand) (Reg, bool) {
|
||||
return r, ok && r.isVec()
|
||||
}
|
||||
|
||||
// vecOrMem reports whether op is a vector register or a memory reference.
|
||||
func vecOrMem(op Operand) bool {
|
||||
if _, ok := op.(Mem); ok {
|
||||
return true
|
||||
}
|
||||
r, ok := op.(Reg)
|
||||
return ok && r.isVec()
|
||||
}
|
||||
|
||||
// validMoveOther reports whether the non-vector operand of a move is
|
||||
// acceptable: memory always is, a GPR only for VMOVD/VMOVQ.
|
||||
func validMoveOther(ms vexMoveSpec, op Operand) bool {
|
||||
|
||||
Reference in New Issue
Block a user