Files
gasm-sdk/lint/liveness_test.go
T

80 lines
2.3 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package lint
import "testing"
// TestRegisterClobber detects writes to callee-saved registers that are not
// saved and restored.
func TestRegisterClobber(t *testing.T) {
// BX (callee-saved on amd64) is written but never saved → clobbered.
clob := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tMOVQ CX, BX\n"+
"\tRET\n")
if codes(clob)[CodeRegisterClobber] != 1 {
t.Fatalf("unsaved callee-saved write should be flagged: %+v", clob)
}
// Saved and restored → preserved.
saved := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $8\n"+
"\tPUSHQ BX\n"+
"\tMOVQ CX, BX\n"+
"\tPOPQ BX\n"+
"\tRET\n")
if codes(saved)[CodeRegisterClobber] != 0 {
t.Fatalf("saved/restored register must not be flagged: %+v", saved)
}
// A caller-saved register (CX) is fine to write.
caller := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tMOVQ $1, CX\n"+
"\tRET\n")
if codes(caller)[CodeRegisterClobber] != 0 {
t.Fatalf("caller-saved register must not be flagged: %+v", caller)
}
}
// TestFuncdata validates the FUNCDATA/PCDATA structural checks.
func TestFuncdata(t *testing.T) {
// Well formed: no findings.
good := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tFUNCDATA $0, gclocals·abc(SB)\n"+
"\tPCDATA $1, $0\n"+
"\tRET\n")
if codes(good)[CodeFuncdata] != 0 {
t.Fatalf("well-formed FUNCDATA/PCDATA must not be flagged: %+v", good)
}
// FUNCDATA with one operand.
bad1 := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tFUNCDATA $0\n"+
"\tRET\n")
if codes(bad1)[CodeFuncdata] == 0 {
t.Fatal("FUNCDATA with one operand should be flagged")
}
// PCDATA with a non-immediate value.
bad2 := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tPCDATA $0, AX\n"+
"\tRET\n")
if codes(bad2)[CodeFuncdata] == 0 {
t.Fatal("PCDATA with a register value should be flagged")
}
// FUNCDATA index out of range.
bad3 := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+
"\tFUNCDATA $99, gclocals·abc(SB)\n"+
"\tRET\n")
if codes(bad3)[CodeFuncdata] == 0 {
t.Fatal("out-of-range FUNCDATA index should be flagged")
}
}