From d000963d045bb279d347dbd3551e9468422c17af Mon Sep 17 00:00:00 2001
From: Mark Ryan <markdryan@rivosinc.com>
Date: Thu, 1 May 2025 10:43:32 +0200
Subject: [PATCH] cmd/internal/obj/riscv: reject invalid vadc/vsbc encodings

The RISC-V Instruction Set Manual Volume states that "for vadc and
vsbc, the instruction encoding is reserved if the destination vector
register is v0". The assembler currently allows instructions like

VADCVVM	V1, V2, V0, V0

to be assembled. It's not clear what the behaviour of such
instructions will be on target hardware so it's best to disallow
them.

For reference, binutils (2.44-3.fc42) allows the instruction

vadc.vvm v0, v4, v8, v0

to be assembled and the instruction actually executes on a Banana PI
F3 without crashing. However, clang (20.1.2) refuses to assemble the
instruction, producing the following error.

error: the destination vector register group cannot be V0
        vadc.vvm v0, v4, v8, v0
                 ^
Change-Id: Ia913cbd864ae8dbcf9227f69b963c93a99481cff
Reviewed-on: https://go-review.googlesource.com/c/go/+/669315
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Joel Sing <joel@sing.id.au>
---
 src/cmd/asm/internal/asm/testdata/riscv64.s      | 10 ++++++++++
 src/cmd/asm/internal/asm/testdata/riscv64error.s |  5 +++++
 src/cmd/internal/obj/riscv/obj.go                |  9 +++++++--
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/cmd/asm/internal/asm/testdata/riscv64.s b/src/cmd/asm/internal/asm/testdata/riscv64.s
index 0db846a3a12..4e0226a2b6f 100644
--- a/src/cmd/asm/internal/asm/testdata/riscv64.s
+++ b/src/cmd/asm/internal/asm/testdata/riscv64.s
@@ -623,17 +623,27 @@ start:
 	VADCVXM		X11, V2, V0, V3			// d7c12540
 	VADCVIM		$15, V2, V0, V3			// d7b12740
 	VMADCVVM	V1, V2, V0, V3			// d7812044
+	VMADCVVM	V1, V2, V0, V0			// 57802044
 	VMADCVXM	X11, V2, V0, V3			// d7c12544
+	VMADCVXM	X11, V2, V0, V0			// 57c02544
 	VMADCVIM	$15, V2, V0, V3			// d7b12744
+	VMADCVIM	$15, V2, V0, V0			// 57b02744
 	VMADCVV		V1, V2, V3			// d7812046
+	VMADCVV		V1, V2, V0			// 57802046
 	VMADCVX		X11, V2, V3			// d7c12546
+	VMADCVX		X11, V2, V0			// 57c02546
 	VMADCVI		$15, V2, V3			// d7b12746
+	VMADCVI		$15, V2, V0			// 57b02746
 	VSBCVVM		V1, V2, V0, V3			// d7812048
 	VSBCVXM		X11, V2, V0, V3			// d7c12548
 	VMSBCVVM	V1, V2, V0, V3			// d781204c
+	VMSBCVVM	V1, V2, V0, V0			// 5780204c
 	VMSBCVXM	X11, V2, V0, V3			// d7c1254c
+	VMSBCVXM	X11, V2, V0, V0			// 57c0254c
 	VMSBCVV		V1, V2, V3			// d781204e
+	VMSBCVV		V1, V2, V0			// 5780204e
 	VMSBCVX		X11, V2, V3			// d7c1254e
+	VMSBCVX		X11, V2, V0			// 57c0254e
 
 	// 31.11.5: Vector Bitwise Logical Instructions
 	VANDVV		V1, V2, V3			// d7812026
diff --git a/src/cmd/asm/internal/asm/testdata/riscv64error.s b/src/cmd/asm/internal/asm/testdata/riscv64error.s
index 42381978931..4e6afa0ac2a 100644
--- a/src/cmd/asm/internal/asm/testdata/riscv64error.s
+++ b/src/cmd/asm/internal/asm/testdata/riscv64error.s
@@ -95,10 +95,13 @@ TEXT errors(SB),$0
 	VSEXTVF8	V2, V3, V4			// ERROR "invalid vector mask register"
 	VADCVVM		V1, V2, V4, V3			// ERROR "invalid vector mask register"
 	VADCVVM		V1, V2, V3			// ERROR "invalid vector mask register"
+	VADCVVM		V1, V2, V0, V0			// ERROR "invalid destination register V0"
 	VADCVXM		X10, V2, V4, V3			// ERROR "invalid vector mask register"
 	VADCVXM		X10, V2, V3			// ERROR "invalid vector mask register"
+	VADCVXM		X10, V2, V0, V0			// ERROR "invalid destination register V0"
 	VADCVIM		$15, V2, V1, V3			// ERROR "invalid vector mask register"
 	VADCVIM		$15, V2, V3			// ERROR "invalid vector mask register"
+	VADCVIM		$15, V2, V0, V0			// ERROR "invalid destination register V0"
 	VMADCVVM	V1, V2, V4, V3			// ERROR "invalid vector mask register"
 	VMADCVVM	V1, V2, V3			// ERROR "invalid vector mask register"
 	VMADCVXM	X10, V2, V4, V3			// ERROR "invalid vector mask register"
@@ -107,8 +110,10 @@ TEXT errors(SB),$0
 	VMADCVIM	$15, V2, V3			// ERROR "invalid vector mask register"
 	VSBCVVM		V1, V2, V4, V3			// ERROR "invalid vector mask register"
 	VSBCVVM		V1, V2, V3			// ERROR "invalid vector mask register"
+	VSBCVVM		V1, V2, V0, V0			// ERROR "invalid destination register V0"
 	VSBCVXM		X10, V2, V4, V3			// ERROR "invalid vector mask register"
 	VSBCVXM		X10, V2, V3			// ERROR "invalid vector mask register"
+	VSBCVXM		X10, V2, V0, V0			// ERROR "invalid destination register V0"
 	VMSBCVVM	V1, V2, V4, V3			// ERROR "invalid vector mask register"
 	VMSBCVVM	V1, V2, V3			// ERROR "invalid vector mask register"
 	VMSBCVXM	X10, V2, V4, V3			// ERROR "invalid vector mask register"
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index f4a2cb5fa4d..3c91a1f02c8 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -3773,8 +3773,13 @@ func instructionsForProg(p *obj.Prog) []*instruction {
 		ins.funct7 |= 1 // unmasked
 		ins.rd, ins.rs1, ins.rs2 = uint32(p.To.Reg), uint32(p.From.Reg), REG_V0
 
-	case AVADCVVM, AVADCVXM, AVMADCVVM, AVMADCVXM, AVSBCVVM, AVSBCVXM, AVMSBCVVM, AVMSBCVXM, AVADCVIM, AVMADCVIM,
-		AVMERGEVVM, AVMERGEVXM, AVMERGEVIM, AVFMERGEVFM:
+	case AVADCVIM, AVADCVVM, AVADCVXM, AVSBCVVM, AVSBCVXM:
+		if ins.rd == REG_V0 {
+			p.Ctxt.Diag("%v: invalid destination register V0", p)
+		}
+		fallthrough
+
+	case AVMADCVVM, AVMADCVXM, AVMSBCVVM, AVMSBCVXM, AVMADCVIM, AVMERGEVVM, AVMERGEVXM, AVMERGEVIM, AVFMERGEVFM:
 		if ins.rs3 != REG_V0 {
 			p.Ctxt.Diag("%v: invalid vector mask register", p)
 		}
-- 
GitLab