XSAVE, XSAVEOPT, XSAVEC and XSAVES with their restore twins, plain and 64, each pinned byte for byte against go tool asm through every corpus line the toolchain's own amd64enc.s carries for the family (24 lines). The toolchain emits XSAVEOPT without the manual's 0x66 prefix; the bytes are the oracle, so the family carries none. Assisted-by: GLM 5.3 Flash
104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package asm
|
|
|
|
import "strings"
|
|
|
|
// encodeAmd64Family routes a mnemonic through the amd64 corpus families the
|
|
// dedicated amd64_*.go files implement. The first family that owns the name
|
|
// decides the outcome: its bytes, or its error. A name no family claims
|
|
// falls through to the scalar dispatch in (*enc).encode untouched.
|
|
func (e *enc) encodeAmd64Family(upper string, ops []Operand) (bool, error) {
|
|
if ok, err := e.encodeX87(upper, ops); ok {
|
|
return true, err
|
|
}
|
|
if ok, err := e.encodeSystem(upper, ops); ok {
|
|
return true, err
|
|
}
|
|
if ok, err := e.encodeXsave(upper, ops); ok {
|
|
return true, err
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// amd64FamilyEncodable mirrors encodeAmd64Family for the lint-time
|
|
// predicate: true when some family owns the mnemonic, whatever the operand
|
|
// shapes. It must claim exactly the names encodeAmd64Family does.
|
|
func amd64FamilyEncodable(upper string) bool {
|
|
if _, ok := x87NoOperand[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := x87Arith[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := x87FCmov[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := x87Compare[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := x87MemUnary[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := x87Fxsav[upper]; ok {
|
|
return true
|
|
}
|
|
if upper == "FADDDP" {
|
|
return true
|
|
}
|
|
if _, ok := systemNoOperand[upper]; ok {
|
|
return true
|
|
}
|
|
if b, size := splitSize(upper); size != 0 {
|
|
switch upper[len(upper)-1] {
|
|
case 'B', 'W', 'L', 'Q':
|
|
if _, ok := stringOp[b]; ok {
|
|
return true
|
|
}
|
|
}
|
|
if m, ok := sysRm[b]; ok && m.sized {
|
|
return true
|
|
}
|
|
}
|
|
if _, ok := nopWidth[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := cacheControl[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := movbeSize[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := randSource[base(upper, 6)]; ok {
|
|
return true
|
|
}
|
|
if _, ok := fsGsBase[base(upper, 8)]; ok {
|
|
return true
|
|
}
|
|
if _, ok := descTable[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := sysRm[upper]; ok {
|
|
return true
|
|
}
|
|
if _, ok := selectorRead[base(upper, 3)]; ok {
|
|
return true
|
|
}
|
|
if _, ok := farSegLoad[base(upper, 3)]; ok {
|
|
return true
|
|
}
|
|
if upper == "CMPXCHG8B" || upper == "CMPXCHG16B" {
|
|
return true
|
|
}
|
|
if _, ok := xsaveTable[upper]; ok {
|
|
return true
|
|
}
|
|
if before, ok := strings.CutSuffix(upper, "64"); ok {
|
|
if _, ok := xsaveTable[before]; ok {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|