Files
gasm-sdk/lint/addressing.go
T

64 lines
2.3 KiB
Go
Raw Normal View History

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package lint
import (
"fmt"
"strings"
"sourcedock.dev/petrbalvin/gasm-sdk/ast"
)
// scanAddressing flags the two pseudo-register spellings the language
// reference (docs/asm/OPERANDS.md) calls its sharpest edge: a numeric offset
// against FP names no symbol, and a negative numeric offset against SP
// addresses the hardware stack pointer rather than the virtual frame.
func scanAddressing(t *ast.Text, cfg Config) []Diagnostic {
var out []Diagnostic
for _, s := range t.Body {
in, ok := s.(*ast.Instr)
if !ok {
continue
}
for _, op := range in.Operands {
if op.Kind != ast.OpAddr {
continue
}
// FP is a pseudo-register, never a base register of a memory
// operand; a Base of FP only arises from the numeric form
// 0(FP), which the parser routes through memory parsing. The
// toolchain rejects it with "cannot reference FP without a
// symbol" and gasm with "unknown base register FP".
if strings.EqualFold(op.Addr.Base, "FP") && !cfg.Disable[CodeUnnamedFPRef] {
out = append(out, Diagnostic{
Pos: op.Pos,
Severity: Error,
Code: CodeUnnamedFPRef,
Message: "FP is referenced without a symbol; the assembler requires name+offset(FP)",
})
continue
}
// A numeric offset against (SP) addresses the hardware stack
// pointer. Positive offsets are the deliberate runtime idiom
// for reading caller frames, but a negative offset is exactly
// the local-frame spelling with the name missing: x-8(SP) and
// -8(SP) are one character apart and mean different registers.
// Only the negative form is flagged, which keeps the rule
// silent across GOROOT's 140-odd deliberate hardware-SP
// references (all positive) while catching the mistyped local.
if strings.EqualFold(op.Addr.Base, "SP") && op.Addr.Sym == nil &&
op.Addr.HasOff && op.Addr.Offset < 0 && !cfg.Disable[CodeHardwareSP] {
out = append(out, Diagnostic{
Pos: op.Pos,
Severity: Warning,
Code: CodeHardwareSP,
Message: fmt.Sprintf("%d(SP) addresses the hardware stack pointer, not the virtual frame; "+
"a frame local is spelled x%d(SP)", op.Addr.Offset, op.Addr.Offset),
})
}
}
}
return out
}