feat(lint): abi0 register-args rule and go-asm width model

This commit is contained in:
2026-08-29 13:36:28 +02:00
parent 6699ebd34f
commit d75e6bcae6
5 changed files with 244 additions and 21 deletions
+76
View File
@@ -335,3 +335,79 @@ TEXT ·f(SB), NOSPLIT, $0
t.Fatalf("correct width must not be flagged: %+v", diags)
}
}
func TestABI0RegisterArgs(t *testing.T) {
// A kernel with a // func signature whose parameters are never read from
// the FP frame: the classic register-args port bug.
diags := lintSrc(t, `
// func kernel(text *byte, n int)
TEXT ·kernel(SB), NOSPLIT, $0-16
MOVQ DI, R10
MOVQ R9, AX
RET
`)
if codes(diags)[CodeABI0RegisterArgs] != 1 {
t.Fatalf("want one abi0-register-args, got %+v", diags)
}
// Reading every parameter from the frame is correct.
diags = lintSrc(t, `
// func kernel(text *byte, n int)
TEXT ·kernel(SB), NOSPLIT, $0-16
MOVQ text+0(FP), AX
MOVQ n+8(FP), BX
RET
`)
if codes(diags)[CodeABI0RegisterArgs] != 0 {
t.Fatalf("frame-reading kernel must not be flagged: %+v", diags)
}
// Only a result write to FP, no parameter read: still flagged.
diags = lintSrc(t, `
// func top(sa []int32) int
TEXT ·top(SB), NOSPLIT, $0-24
MOVQ SI, R10
MOVQ R10, ret+16(FP)
RET
`)
if codes(diags)[CodeABI0RegisterArgs] != 1 {
t.Fatalf("result-only FP write must still be flagged: %+v", diags)
}
// No signature: stay silent.
diags = lintSrc(t, `
TEXT ·bare(SB), NOSPLIT, $0-16
MOVQ DI, AX
RET
`)
if codes(diags)[CodeABI0RegisterArgs] != 0 {
t.Fatalf("signature-less function must not be flagged: %+v", diags)
}
}
func TestRegisterWidthCanonicalNames(t *testing.T) {
// Canonical Go asm names with an L operation: the correct spelling for a
// 32-bit operation, never a width mismatch.
diags := lintSrc(t, `
#include "textflag.h"
TEXT ·f(SB), NOSPLIT, $0
MOVL (BX)(R9*4), SI
XORL R9, R9
MOVL 128(BX)(R9*4), R12
RET
`)
if codes(diags)[CodeRegisterWidthMismatch] != 0 {
t.Fatalf("canonical 64-bit names with L ops must not be flagged: %+v", diags)
}
// A byte register in an L operation stays a mismatch.
diags = lintSrc(t, `
#include "textflag.h"
TEXT ·f(SB), NOSPLIT, $0
MOVL AL, DX
RET
`)
if codes(diags)[CodeRegisterWidthMismatch] != 1 {
t.Fatalf("byte register in L op must be flagged: %+v", diags)
}
}