feat(asm): give riscv64 the END and GETCALLERPC the toolchain accepts

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 20:39:44 +02:00
1 parent 0211d6672d
commit 76f8ba6403
3 files changed
+195 -6

No files matched your search

+85
View File
@@ -241,6 +241,91 @@ func TestRISCVToolchainRejections(t *testing.T) {
}
}
// TestRISCVGetCallerPC_Differential proves the toolchain's GETCALLERPC
// rewrite: a leaf reads the caller's address straight from the link register
// (MOV X1, rd, compressed to C.MV; X0 stays the discarded ADDI), a body that
// calls out reads the prologue's save at 0(SP) (LD rd, 0(SP), compressed to
// C.LDSP, the reserved SP destination included; X0 stays uncompressed), and a
// memory destination stores it there, through the frame mapping and the
// static-data path alike.
func TestRISCVGetCallerPC_Differential(t *testing.T) {
leaf := `#include "textflag.h"
TEXT ·leafgcp(SB), NOSPLIT, $0
GETCALLERPC X5 // c.mv X5, X1
GETCALLERPC X0 // addi X0, X1, 0, discarded
GETCALLERPC 8(X6) // sd X1, 8(X6)
GETCALLERPC x+8(FP) // c.sdsp X1, 16
END
RET
`
path := writeRISCVSrc(t, "gcp_leaf_riscv64.s", leaf)
assertRISCVDifferential(t, path, leaf, "leafgcp")
framed := `#include "textflag.h"
TEXT ·framegcp(SB), $8
CALL extcall(SB)
GETCALLERPC X5 // c.ldsp X5, 0(SP)
GETCALLERPC X2 // c.ldsp X2, 0(SP)
GETCALLERPC X0 // ld X0, 0(SP), uncompressed
END
RET
`
path = writeRISCVSrc(t, "gcp_frame_riscv64.s", framed)
assertRISCVDifferential(t, path, framed, "framegcp")
}
// TestRISCVGetCallerPCRejections pins the rewrite's rejections: a framed
// body with a memory destination would read (SP) into a MOV with two memory
// ends, a non-integer register is the rd bank rejection, and no destination
// at all is the toolchain's unsupported MOV.
func TestRISCVGetCallerPCRejections(t *testing.T) {
cases := []struct {
name string
src string
want string
}{
{
name: "memory destination in a framed body",
src: "CALL extcall(SB)\n\tGETCALLERPC 8(X6)\n",
want: "GETCALLERPC: unsupported MOV",
},
{
name: "float destination",
src: "\tGETCALLERPC F5\n",
want: "GETCALLERPC: expected integer register in rd position but got non-integer register F5",
},
{
name: "vector destination",
src: "\tGETCALLERPC V1\n",
want: "GETCALLERPC: expected integer register in rd position but got non-integer register V1",
},
{
name: "immediate destination",
src: "\tGETCALLERPC $5\n",
want: "GETCALLERPC: expected integer register in rd position",
},
{
name: "no destination",
src: "\tGETCALLERPC\n",
want: "GETCALLERPC: unsupported MOV",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
fn := firstTextRISCV(t, "#include \"textflag.h\"\n\nTEXT ·r(SB), NOSPLIT, $0\n"+tc.src+"\tRET\n")
_, _, _, _, _, _, err := assembleRISCV(fn, nil)
if err == nil {
t.Fatalf("source assembled, want rejection %q", tc.want)
}
if !strings.Contains(err.Error(), tc.want) {
t.Errorf("error %q does not carry %q", err.Error(), tc.want)
}
})
}
}
// TestRISCVTLSRelocKind pins the relocation the TLS sequence records: one
// R_RISCV_TLS_LE field spanning the LUI + ADDIW pair, the symbol named and
// no addend for a plain tls(SB) reference.