// Copyright (c) 2026 Petr Balvín (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) } }