From 24b395119b4df7f16915b9f01a6aded647b79bbd Mon Sep 17 00:00:00 2001 From: Mark Ryan Date: Tue, 10 Dec 2024 17:02:26 +0100 Subject: [PATCH] cmd/internal/obj/riscv: prevent duplicate error reports The riscv64 Go assembler can output certain errors, ones produced by instructionsForProg, multiple times. These errors are guaranteed to be output at least twice and can appear three or more times if a rescan is needed to recompute branch addresses. For example, the syntactically incorrect instruction MOV (X10), $1 will generate at least two identical errors asm: 86076 (asm.s:21524) MOV (X10), $1: unsupported MOV asm: 86076 (asm.s:21524) MOV (X10), $1: unsupported MOV asm: assembly failed In addition to confusing the user, these duplicate errors make it difficult to write negative tests for certain types of instructions, e.g., branches, whose duplicate errors are not always identical, and so not ignored by endtoend_test.go. We fix the issue by returning from preprocess if any errors have been generated by the time we reach the end of the rescan loop. One implication of this change is that validation errors will no longer be reported if an error is generated earlier in the preprocess stage. Negative test cases for validation errors are therefore moved to their own file as the existing riscv64error.s file contains errors generated by instructionsForProg that will now suppress the validation errors. Change-Id: Iffacdbefce28f44970dd5dda44990b822b8a23d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/637315 LUCI-TryBot-Result: Go LUCI Reviewed-by: Joel Sing Reviewed-by: David Chase Reviewed-by: Cherry Mui --- src/cmd/asm/internal/asm/endtoend_test.go | 4 ++ .../asm/internal/asm/testdata/riscv64error.s | 34 -------------- .../internal/asm/testdata/riscv64validation.s | 46 +++++++++++++++++++ src/cmd/internal/obj/riscv/obj.go | 5 ++ 4 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 src/cmd/asm/internal/asm/testdata/riscv64validation.s diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go index 3760b77625..f33b1e75bf 100644 --- a/src/cmd/asm/internal/asm/endtoend_test.go +++ b/src/cmd/asm/internal/asm/endtoend_test.go @@ -489,6 +489,10 @@ func TestRISCVErrors(t *testing.T) { testErrors(t, "riscv64", "riscv64error") } +func TestRISCVValidation(t *testing.T) { + testErrors(t, "riscv64", "riscv64validation") +} + func TestS390XEndToEnd(t *testing.T) { testEndToEnd(t, "s390x", "s390x") } diff --git a/src/cmd/asm/internal/asm/testdata/riscv64error.s b/src/cmd/asm/internal/asm/testdata/riscv64error.s index 82a2348894..e8855f6cd5 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64error.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64error.s @@ -43,50 +43,16 @@ TEXT errors(SB),$0 SRLIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31" SRAIW $-1, X5, X6 // ERROR "immediate out of range 0 to 31" SD X5, 4294967296(X6) // ERROR "constant 4294967296 too large" - SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1" - SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1" FNES F1, (X5) // ERROR "needs an integer register output" - VSETVLI $32, E16, M1, TU, MU, X12 // ERROR "must be in range [0, 31] (5 bits)" - VSETVLI $-1, E32, M2, TA, MA, X12 // ERROR "must be in range [0, 31] (5 bits)" VSETIVLI X10, E32, M2, TA, MA, X12 // ERROR "expected immediate value" - VSETVL X10, X11 // ERROR "expected integer register in rs1 position" - VLE8V (X10), X10 // ERROR "expected vector register in rd position" - VLE8V (V1), V3 // ERROR "expected integer register in rs1 position" VLE8V (X10), V1, V3 // ERROR "invalid vector mask register" - VSE8V X10, (X10) // ERROR "expected vector register in rs1 position" - VSE8V V3, (V1) // ERROR "expected integer register in rd position" VSE8V V3, V1, (X10) // ERROR "invalid vector mask register" - VLSE8V (X10), V3 // ERROR "expected integer register in rs2 position" - VLSE8V (X10), X10, X11 // ERROR "expected vector register in rd position" - VLSE8V (V1), X10, V3 // ERROR "expected integer register in rs1 position" - VLSE8V (X10), V1, V0, V3 // ERROR "expected integer register in rs2 position" VLSE8V (X10), X10, V1, V3 // ERROR "invalid vector mask register" - VSSE8V V3, (X10) // ERROR "expected integer register in rs2 position" - VSSE8V X10, X11, (X10) // ERROR "expected vector register in rd position" - VSSE8V V3, X11, (V1) // ERROR "expected integer register in rs1 position" - VSSE8V V3, V1, V0, (X10) // ERROR "expected integer register in rs2 position" VSSE8V V3, X11, V1, (X10) // ERROR "invalid vector mask register" - VLUXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" - VLUXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" - VLUXEI8V (V1), V2, V3 // ERROR "expected integer register in rs1 position" - VLUXEI8V (X10), X11, V0, V3 // ERROR "expected vector register in rs2 position" VLUXEI8V (X10), V2, V1, V3 // ERROR "invalid vector mask register" - VSUXEI8V X10, V2, (X10) // ERROR "expected vector register in rd position" - VSUXEI8V V3, V2, (V1) // ERROR "expected integer register in rs1 position" - VSUXEI8V V3, X11, V0, (X10) // ERROR "expected vector register in rs2 position" VSUXEI8V V3, V2, V1, (X10) // ERROR "invalid vector mask register" - VLOXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" - VLOXEI8V (V1), V2, V3 // ERROR "expected integer register in rs1 position" - VLOXEI8V (X10), X11, V0, V3 // ERROR "expected vector register in rs2 position" VLOXEI8V (X10), V2, V1, V3 // ERROR "invalid vector mask register" - VSOXEI8V X10, V2, (X10) // ERROR "expected vector register in rd position" - VSOXEI8V V3, V2, (V1) // ERROR "expected integer register in rs1 position" - VSOXEI8V V3, X11, V0, (X10) // ERROR "expected vector register in rs2 position" VSOXEI8V V3, V2, V1, (X10) // ERROR "invalid vector mask register" VL1RV (X10), V0, V3 // ERROR "too many operands for instruction" - VL1RV (X10), X10 // ERROR "expected vector register in rd position" - VL1RV (V1), V3 // ERROR "expected integer register in rs1 position" VS1RV V3, V0, (X11) // ERROR "too many operands for instruction" - VS1RV X11, (X11) // ERROR "expected vector register in rs1 position" - VS1RV V3, (V1) // ERROR "expected integer register in rd position" RET diff --git a/src/cmd/asm/internal/asm/testdata/riscv64validation.s b/src/cmd/asm/internal/asm/testdata/riscv64validation.s new file mode 100644 index 0000000000..773f275dd3 --- /dev/null +++ b/src/cmd/asm/internal/asm/testdata/riscv64validation.s @@ -0,0 +1,46 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file is for validation errors only, i.e., errors reported by the validate function. +// Negative test cases for errors generated earlier in the assembler's preprocess stage +// should be added to riscv64error.s. If they are added to this file, they will prevent +// the validate function from being run and TestRISCVValidation will report missing +// errors. + +TEXT validation(SB),$0 + SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1" + SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1" + VSETVLI $32, E16, M1, TU, MU, X12 // ERROR "must be in range [0, 31] (5 bits)" + VSETVLI $-1, E32, M2, TA, MA, X12 // ERROR "must be in range [0, 31] (5 bits)" + VSETVL X10, X11 // ERROR "expected integer register in rs1 position" + VLE8V (X10), X10 // ERROR "expected vector register in rd position" + VLE8V (V1), V3 // ERROR "expected integer register in rs1 position" + VSE8V X10, (X10) // ERROR "expected vector register in rs1 position" + VSE8V V3, (V1) // ERROR "expected integer register in rd position" + VLSE8V (X10), V3 // ERROR "expected integer register in rs2 position" + VLSE8V (X10), X10, X11 // ERROR "expected vector register in rd position" + VLSE8V (V1), X10, V3 // ERROR "expected integer register in rs1 position" + VLSE8V (X10), V1, V0, V3 // ERROR "expected integer register in rs2 position" + VSSE8V V3, (X10) // ERROR "expected integer register in rs2 position" + VSSE8V X10, X11, (X10) // ERROR "expected vector register in rd position" + VSSE8V V3, X11, (V1) // ERROR "expected integer register in rs1 position" + VSSE8V V3, V1, V0, (X10) // ERROR "expected integer register in rs2 position" + VLUXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" + VLUXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" + VLUXEI8V (V1), V2, V3 // ERROR "expected integer register in rs1 position" + VLUXEI8V (X10), X11, V0, V3 // ERROR "expected vector register in rs2 position" + VSUXEI8V X10, V2, (X10) // ERROR "expected vector register in rd position" + VSUXEI8V V3, V2, (V1) // ERROR "expected integer register in rs1 position" + VSUXEI8V V3, X11, V0, (X10) // ERROR "expected vector register in rs2 position" + VLOXEI8V (X10), V2, X11 // ERROR "expected vector register in rd position" + VLOXEI8V (V1), V2, V3 // ERROR "expected integer register in rs1 position" + VLOXEI8V (X10), X11, V0, V3 // ERROR "expected vector register in rs2 position" + VSOXEI8V X10, V2, (X10) // ERROR "expected vector register in rd position" + VSOXEI8V V3, V2, (V1) // ERROR "expected integer register in rs1 position" + VSOXEI8V V3, X11, V0, (X10) // ERROR "expected vector register in rs2 position" + VL1RV (X10), X10 // ERROR "expected vector register in rd position" + VL1RV (V1), V3 // ERROR "expected integer register in rs1 position" + VS1RV X11, (X11) // ERROR "expected vector register in rs1 position" + VS1RV V3, (V1) // ERROR "expected integer register in rd position" + RET diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 16bd1310c1..de9851519a 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -833,6 +833,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } } + // Return if errors have been detected up to this point. Continuing + // may lead to duplicate errors being output. + if ctxt.Errors > 0 { + return + } if !rescan { break } -- 2.51.0