fix(asm): tighten the arm64 acceptance toward the toolchain
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
82d741514a
commit
8ab99c9b0c
4 files changed
+250
-29
No files matched your search
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package asm
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"sourcedock.dev/petrbalvin/gasm-sdk/parser"
|
||||
)
|
||||
|
||||
// arm64AcceptedErrorShapes lists the toolchain's arm64error.s spellings gasm
|
||||
// still accepts, each an acceptance superset with a known shape. The list
|
||||
// only shrinks: every tightening of the encoder moves spellings out of it,
|
||||
// and a spelling reappearing here means a regression.
|
||||
var arm64AcceptedErrorShapes = []string{
|
||||
// VLD1/VST1 post-index shapes: the register post-index without the .P
|
||||
// spelling, the .P immediate against the aggregate register size, the
|
||||
// scaled register increment and the replicating register count.
|
||||
"VLD1 (R8)(R13), [V2.B16]",
|
||||
"VST1 [V1.B16], (R8)(R13)",
|
||||
"VST1.P [V4.S4,V5.S4], 48(R1)",
|
||||
"VST1.P [V4.S4], 8(R1)",
|
||||
"VLD1.P 32(R1), [V8.S4, V9.S4, V10.S4]",
|
||||
"VLD1.P 48(R1), [V7.S4, V8.S4, V9.S4, V10.S4]",
|
||||
"VLD1.P (R8)(R9<<2), [V2.B16]",
|
||||
"VST1.P [V1.B16], (R8)(R9<<1)",
|
||||
"VLD3R.P 24(R15), [V15.H4,V16.H4,V17.H4]",
|
||||
// REGTMP (R27) as an explicit operand the toolchain refuses, the pair
|
||||
// split paths included.
|
||||
"ADD $0x1234567, R27, R3",
|
||||
"ADD $0x3fffffffc000, R27, R5",
|
||||
"AND $0x22220000, R27, R4",
|
||||
"ANDW $0x6006000060060, R27, R5",
|
||||
"STP (R3, R4), 0x1234567(R27)",
|
||||
"LDP 0x1234567(R27), (R3, R4)",
|
||||
"STP (R26, R27), 700(R2)",
|
||||
// TLBI operand arity and the range-prefetch operand shapes.
|
||||
"TLBI VMALLE1IS, R0",
|
||||
"TLBI ALLE3OS, ZR",
|
||||
"TLBI VAE1IS",
|
||||
"TLBI RVALE3",
|
||||
"RPRFM (R1), RSP, PLDKEEP",
|
||||
// The GP register pairs on the FP mnemonics, the other way round.
|
||||
"LDP (R0), (F0, F1)",
|
||||
"STP (F2, F3), (R0)",
|
||||
// FCVTL exists for the S to D pair alone.
|
||||
"VFCVTL V1.H4, V2.S4",
|
||||
}
|
||||
|
||||
// TestArm64ToolchainErrorParity walks the toolchain's arm64error.s (Go
|
||||
// 1.27, arm64) and requires gasm to reject every case the toolchain rejects,
|
||||
// the documented acceptance supersets above excepted. A live Go toolchain
|
||||
// is needed for the source file; the test skips without one or in -short.
|
||||
func TestArm64ToolchainErrorParity(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("live arm64error.s corpus: skipped in -short mode")
|
||||
}
|
||||
goroot := os.Getenv("GOROOT")
|
||||
if goroot == "" {
|
||||
t.Skip("no GOROOT")
|
||||
}
|
||||
path := filepath.Join(goroot, "src", "cmd", "asm", "internal", "asm", "testdata", "arm64error.s")
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
allowed := map[string]bool{}
|
||||
for _, s := range arm64AcceptedErrorShapes {
|
||||
allowed[s] = true
|
||||
}
|
||||
for raw := range strings.SplitSeq(string(data), "\n") {
|
||||
line := strings.TrimSpace(raw)
|
||||
if line == "" || strings.HasPrefix(line, "//") || strings.HasPrefix(line, "TEXT") || !strings.Contains(line, "ERROR") {
|
||||
continue
|
||||
}
|
||||
body := line
|
||||
if i := strings.Index(body, "//"); i >= 0 {
|
||||
body = strings.TrimSpace(body[:i])
|
||||
}
|
||||
body = strings.ReplaceAll(body, "\t", " ")
|
||||
body = strings.Join(strings.Fields(body), " ")
|
||||
// Label-relative and non-operand lines need their function context.
|
||||
if strings.Contains(body, "(PC)") || strings.Contains(body, "(SB)") || strings.Contains(body, "PCALIGN") ||
|
||||
strings.HasPrefix(body, "RET") || strings.HasPrefix(body, "NOP") || strings.HasPrefix(body, "BRK") ||
|
||||
strings.Contains(body, "again") || strings.Contains(body, "next") || strings.Contains(body, "loop") {
|
||||
continue
|
||||
}
|
||||
src := "#include \"textflag.h\"\n\nTEXT ·f(SB), NOSPLIT, $0-0\n\t" + body + "\n\tRET\n"
|
||||
f, perr := parser.Parse("errorparity.s", src)
|
||||
if len(perr) > 0 {
|
||||
continue // the parser already rejects the spelling
|
||||
}
|
||||
if _, aerr := AssembleFileARM64(f); aerr == nil && !allowed[body] {
|
||||
t.Errorf("gasm accepts what the toolchain rejects: %s", body)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user