fix(asm): encode BSF, BSR and POPCNT
Assisted-by: GLM 5.3
This commit is contained in:
+24
-10
@@ -597,25 +597,39 @@ func (e *enc) encodeSet(upper string, ops []Operand) error {
|
||||
return e.emit(i)
|
||||
}
|
||||
|
||||
// --- LZCNT / TZCNT ----------------------------------------------------------
|
||||
// --- bit scan / bit count ----------------------------------------------------
|
||||
|
||||
// encodeCount encodes LZCNT/TZCNT (leading / trailing zero count): F3 0F BD
|
||||
// or F3 0F BC, with reg = dst and rm = src. The size suffix selects the
|
||||
// operand width (LZCNTW/LZCNTL/LZCNTQ).
|
||||
// countOp maps the bit-scan and bit-count mnemonics to their opcode byte and
|
||||
// mandatory prefix. TZCNT/LZCNT/POPCNT are the F3-prefixed forms of the
|
||||
// same map as BSF/BSR's 0F BC/BD; POPCNT is F3 0F B8.
|
||||
var countOp = map[string]struct {
|
||||
op byte
|
||||
prefix byte
|
||||
}{
|
||||
"BSF": {0xBC, 0},
|
||||
"BSR": {0xBD, 0},
|
||||
"TZCNT": {0xBC, 0xF3},
|
||||
"LZCNT": {0xBD, 0xF3},
|
||||
"POPCNT": {0xB8, 0xF3},
|
||||
}
|
||||
|
||||
// encodeCount encodes the bit-scan and bit-count family — BSF (0F BC),
|
||||
// BSR (0F BD), TZCNT (F3 0F BC), LZCNT (F3 0F BD) and POPCNT (F3 0F B8) —
|
||||
// with reg = dst and rm = src. The size suffix selects the operand width
|
||||
// (BSFQ, TZCNTL, …). Note BSF/BSR leave the destination undefined when the
|
||||
// source is zero (unlike their F3-prefixed counterparts); callers must
|
||||
// guard non-zero inputs themselves.
|
||||
func (e *enc) encodeCount(base string, ops []Operand, size int) error {
|
||||
if len(ops) != 2 {
|
||||
return fmt.Errorf("%s expects 2 operands, got %d", base, len(ops))
|
||||
}
|
||||
op := byte(0xBD)
|
||||
if base == "TZCNT" {
|
||||
op = 0xBC
|
||||
}
|
||||
spec := countOp[base]
|
||||
dstReg, ok := ops[1].(Reg)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s destination must be a register", base)
|
||||
}
|
||||
i := newInstr(size, []byte{0x0F, op})
|
||||
i.prefix = 0xF3
|
||||
i := newInstr(size, []byte{0x0F, spec.op})
|
||||
i.prefix = spec.prefix
|
||||
if err := setRM(i, dstReg, ops[0], size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user