feat(lint): accept the wired extension mnemonics
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
9c951c232e
commit
83052ab466
2 files changed
+61
-1
No files matched your search
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package lint
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sourcedock.dev/petrbalvin/gasm-sdk/arch"
|
||||
"sourcedock.dev/petrbalvin/gasm-sdk/asm"
|
||||
)
|
||||
|
||||
// TestExtensionInstructionsAreKnown pins the lint side of the
|
||||
// extended-instruction layer: every mnemonic the arm64 registry carries
|
||||
// lints without unknown-instruction, and a kernel the encoder accepts lints
|
||||
// clean, because the wired layer is the acceptance rather than a gap of the
|
||||
// generated table.
|
||||
func TestExtensionInstructionsAreKnown(t *testing.T) {
|
||||
src := `#include "textflag.h"
|
||||
TEXT ·f(SB), NOSPLIT, $0
|
||||
ADD Z1.S, Z2.S, Z0.S
|
||||
SUBR Z1.S, P0/M, Z0.S
|
||||
SQADD Z0.D, Z1.D, Z2.D
|
||||
UQADD Z0.D, Z1.D, Z2.D
|
||||
SQSUB Z0.D, Z1.D, Z2.D
|
||||
UQSUB Z0.D, Z1.D, Z2.D
|
||||
SMULH Z3.D, Z4.D, Z5.D
|
||||
ADD $255, Z0.S
|
||||
MUL $-128, Z0.B
|
||||
RET
|
||||
`
|
||||
diags := lintArchFile(t, "ext_arm64.s", src, arch.ARM64, asm.AssembleFileARM64)
|
||||
for _, code := range []string{CodeUnknownInstr, CodeUnencodable} {
|
||||
if n := codes(diags)[code]; n != 0 {
|
||||
t.Errorf("%s fired %d times on the wired extension: %+v", code, n, diags)
|
||||
}
|
||||
}
|
||||
if len(diags) != 0 {
|
||||
t.Errorf("a kernel the encoder accepts must lint clean, got %+v", diags)
|
||||
}
|
||||
|
||||
// The registry consult is the layer's own, not a loosening of the rule:
|
||||
// a mnemonic neither table nor registry carries still fires.
|
||||
diags = lintSrcArch(t, "ext_arm64.s", `#include "textflag.h"
|
||||
TEXT ·f(SB), NOSPLIT, $0
|
||||
FROBNICATE Z0.S, Z1.S, Z2.S
|
||||
RET
|
||||
`)
|
||||
if codes(diags)[CodeUnknownInstr] != 1 {
|
||||
t.Errorf("an unregistered mnemonic must fire unknown-instruction once: %+v", diags)
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -328,7 +328,14 @@ func lintText(t *ast.Text, tab *arch.Table, archKnown bool, cfg Config, macros m
|
||||
}
|
||||
|
||||
if archKnown && !cfg.Disable[CodeUnknownInstr] && !pseudoOps[upper] && !isMacroInvocation(mnem, macros) {
|
||||
// The extended-instruction layer is a mnemonic's second home:
|
||||
// one registered there (arm64's SVE family today) is known,
|
||||
// and it encodes through the extension registry rather than
|
||||
// the encoder mirror the unencodable rule consults, so the
|
||||
// wired extensions are never flagged as a gap of the table.
|
||||
_, extended := asm.LookupExtension(cfg.Arch, mnem)
|
||||
if _, ok := tab.Lookup(mnem); !ok {
|
||||
if !extended {
|
||||
out = append(out, Diagnostic{
|
||||
Pos: st.Mnemonic.Pos,
|
||||
End: st.Mnemonic.End,
|
||||
@@ -336,7 +343,8 @@ func lintText(t *ast.Text, tab *arch.Table, archKnown bool, cfg Config, macros m
|
||||
Code: CodeUnknownInstr,
|
||||
Message: fmt.Sprintf("unknown %s instruction %q", cfg.Arch, mnem),
|
||||
})
|
||||
} else if cfg.Arch == arch.AMD64 && !cfg.Disable[CodeUnencodable] && !asm.Encodable(upper) {
|
||||
}
|
||||
} else if cfg.Arch == arch.AMD64 && !extended && !cfg.Disable[CodeUnencodable] && !asm.Encodable(upper) {
|
||||
// Known to the architecture table but missing from the
|
||||
// encoder: the file parses everywhere and then fails at
|
||||
// assembly time. Flag it at lint so the gap is visible
|
||||
|
||||
Reference in new issue
Block a user