Files
gasm-sdk/asm/amd64_families.go
T
petrbalvin 6af3fd60d5 feat(asm): encode the legacy amd64 SSE and MMX families
The packed integer and float binaries, the imm8-controlled SSE4.1 forms,
the variable blends with their X0 mask, the high/low half moves, the
sign-mask extractions, the non-temporal stores, the MOVQ bank crossings
and their odd spellings, the MMX shifts and shuffle and the cache-line
mask stores, plus the scalar leaves LEAVE, INVPCID and the RTM controls.
Every encoding is pinned byte for byte against go tool asm through every
corpus line the toolchain's own amd64enc.s carries for the families
(1465 lines).  Two corpus-wide gaps fell out of the comparison: the
64-bit MOV immediate uses the zero-extending form across the unsigned
32-bit span, and the MMX-to-GPR MOVQ puts the bank register in reg.

Assisted-by: GLM 5.3 Flash
2026-10-06 23:59:47 +02:00

123 lines
2.8 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
}
if ok, err := e.encodeSSEMore(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 upper == "INVPCID" || upper == "XABORT" {
return true
}
if _, ok := xsaveTable[upper]; ok {
return true
}
if before, ok := strings.CutSuffix(upper, "64"); ok {
if _, ok := xsaveTable[before]; ok {
return true
}
}
switch upper {
case "EMMS", "PSHUFW", "PSLLO", "PSRLO", "PMOVMSKB", "MOVQOZX", "MOVZWW", "MOVSWW":
return true
}
if _, ok := sseMaskmov[upper]; ok {
return true
}
if _, ok := mmxShiftImm[upper]; ok {
return true
}
if _, ok := mmxShiftVar[upper]; ok {
return true
}
return false
}