cmd/internal/obj/riscv: correctly split immediates for FLW/FLD/FSW/FSD

The FLW/FLD/FSW/FSD instructions can have immediates that exceed 12-bits and
therefore cannot be encoded in the RISCV instruction. Handle these as we do
for other load/store instructions. Also add test coverage for all load/store
instructions with large immediates.

Fixes compilation issue reported by Carlos Eduardo de Paula.

Updates #27532

Change-Id: Ifa62f19493b3acaba5a90ac31d2df209a3afea81
Reviewed-on: https://go-review.googlesource.com/c/go/+/215037
Reviewed-by: Carlos Eduardo de Paula <me@carlosedp.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/internal/obj/riscv/asm_test.go b/src/cmd/internal/obj/riscv/asm_test.go
index 0fe0caf..849a87b 100644
--- a/src/cmd/internal/obj/riscv/asm_test.go
+++ b/src/cmd/internal/obj/riscv/asm_test.go
@@ -77,3 +77,57 @@
 		t.Errorf("%v\n%s", err, out)
 	}
 }
+
+func TestImmediateSplitting(t *testing.T) {
+	dir, err := ioutil.TempDir("", "testimmsplit")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	tmpfile := filepath.Join(dir, "x.s")
+	asm := `
+TEXT _stub(SB),$0-0
+	LB	4096(X5), X6
+	LH	4096(X5), X6
+	LW	4096(X5), X6
+	LD	4096(X5), X6
+	LBU	4096(X5), X6
+	LHU	4096(X5), X6
+	LWU	4096(X5), X6
+	SB	X6, 4096(X5)
+	SH	X6, 4096(X5)
+	SW	X6, 4096(X5)
+	SD	X6, 4096(X5)
+
+	FLW	4096(X5), F6
+	FLD	4096(X5), F6
+	FSW	F6, 4096(X5)
+	FSD	F6, 4096(X5)
+
+	MOVB	4096(X5), X6
+	MOVH	4096(X5), X6
+	MOVW	4096(X5), X6
+	MOV	4096(X5), X6
+	MOVBU	4096(X5), X6
+	MOVHU	4096(X5), X6
+	MOVWU	4096(X5), X6
+
+	MOVB	X6, 4096(X5)
+	MOVH	X6, 4096(X5)
+	MOVW	X6, 4096(X5)
+	MOV	X6, 4096(X5)
+
+	MOVF	4096(X5), F6
+	MOVD	4096(X5), F6
+	MOVF	F6, 4096(X5)
+	MOVD	F6, 4096(X5)
+`
+	if err := ioutil.WriteFile(tmpfile, []byte(asm), 0644); err != nil {
+		t.Fatal(err)
+	}
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
+	cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Errorf("%v\n%s", err, out)
+	}
+}
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 721908f..2da9512 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -716,11 +716,7 @@
 
 		// <load> $imm, REG, TO (load $imm+(REG), TO)
 		// <store> $imm, REG, TO (store $imm+(TO), REG)
-		case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU,
-			ASD, ASB, ASH, ASW:
-			// LUI $high, TMP
-			// ADDI $low, TMP, TMP
-			q := *p
+		case ALB, ALH, ALW, ALD, ALBU, ALHU, ALWU, AFLW, AFLD, ASB, ASH, ASW, ASD, AFSW, AFSD:
 			low, high, err := Split32BitImmediate(p.From.Offset)
 			if err != nil {
 				ctxt.Diag("%v: constant %d too large", p, p.From.Offset)
@@ -729,8 +725,9 @@
 				break // no need to split
 			}
 
+			q := *p
 			switch q.As {
-			case ALD, ALB, ALH, ALW, ALBU, ALHU, ALWU:
+			case ALB, ALH, ALW, ALD, ALBU, ALHU, ALWU, AFLW, AFLD:
 				// LUI $high, TMP
 				// ADD TMP, REG, TMP
 				// <load> $low, TMP, TO
@@ -752,7 +749,7 @@
 				p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: low}
 				p.Reg = REG_TMP
 
-			case ASD, ASB, ASH, ASW:
+			case ASB, ASH, ASW, ASD, AFSW, AFSD:
 				// LUI $high, TMP
 				// ADD TMP, TO, TMP
 				// <store> $low, REG, TMP