detached 012b8c4

internal/fakecgo: use riscv64 ABI macros for callee-saved register save/restore (#427)

In https://go-review.googlesource.com/c/go/+/749900 I added
SAVE_GPR/RESTORE_GPR/SAVE_FPR/RESTORE_FPR macros to the Go toolchain
for RISC-V. Pull down abi_riscv64.h with those macros and update
asm_riscv64.s and trampolines_riscv64.s to use them instead of
manually saving and restoring each callee-saved register.
commit
012b8c419e2d55b3b46310fdb5b7920fcf0831ab
author
George Adams · · 2026-03-02 04:31 UTC
committer
GitHub · · 2026-03-02 04:31 UTC
parent
23e4f41
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
3 files · +97 -57
A internal/fakecgo/abi_riscv64.h +72 -0
@@ -0,0 +1,72 @@
1+// Copyright 2026 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+// Macros for transitioning from the host ABI to Go ABI0.
6+//
7+// These macros save and restore the callee-saved registers
8+// from the stack, but they don't adjust stack pointer, so
9+// the user should prepare stack space in advance.
10+// SAVE_GPR(offset) saves X8, X9, X18-X27 to the stack space
11+// of ((offset)+0*8)(X2) ~ ((offset)+11*8)(X2).
12+//
13+// SAVE_FPR(offset) saves F8, F9, F18-F27 to the stack space
14+// of ((offset)+0*8)(X2) ~ ((offset)+11*8)(X2).
15+//
16+// Note: g is X27
17+
18+#define SAVE_GPR(offset) \
19+ MOV X8, ((offset)+0*8)(X2) \
20+ MOV X9, ((offset)+1*8)(X2) \
21+ MOV X18, ((offset)+2*8)(X2) \
22+ MOV X19, ((offset)+3*8)(X2) \
23+ MOV X20, ((offset)+4*8)(X2) \
24+ MOV X21, ((offset)+5*8)(X2) \
25+ MOV X22, ((offset)+6*8)(X2) \
26+ MOV X23, ((offset)+7*8)(X2) \
27+ MOV X24, ((offset)+8*8)(X2) \
28+ MOV X25, ((offset)+9*8)(X2) \
29+ MOV X26, ((offset)+10*8)(X2) \
30+ MOV g, ((offset)+11*8)(X2)
31+
32+#define RESTORE_GPR(offset) \
33+ MOV ((offset)+0*8)(X2), X8 \
34+ MOV ((offset)+1*8)(X2), X9 \
35+ MOV ((offset)+2*8)(X2), X18 \
36+ MOV ((offset)+3*8)(X2), X19 \
37+ MOV ((offset)+4*8)(X2), X20 \
38+ MOV ((offset)+5*8)(X2), X21 \
39+ MOV ((offset)+6*8)(X2), X22 \
40+ MOV ((offset)+7*8)(X2), X23 \
41+ MOV ((offset)+8*8)(X2), X24 \
42+ MOV ((offset)+9*8)(X2), X25 \
43+ MOV ((offset)+10*8)(X2), X26 \
44+ MOV ((offset)+11*8)(X2), g
45+
46+#define SAVE_FPR(offset) \
47+ MOVD F8, ((offset)+0*8)(X2) \
48+ MOVD F9, ((offset)+1*8)(X2) \
49+ MOVD F18, ((offset)+2*8)(X2) \
50+ MOVD F19, ((offset)+3*8)(X2) \
51+ MOVD F20, ((offset)+4*8)(X2) \
52+ MOVD F21, ((offset)+5*8)(X2) \
53+ MOVD F22, ((offset)+6*8)(X2) \
54+ MOVD F23, ((offset)+7*8)(X2) \
55+ MOVD F24, ((offset)+8*8)(X2) \
56+ MOVD F25, ((offset)+9*8)(X2) \
57+ MOVD F26, ((offset)+10*8)(X2) \
58+ MOVD F27, ((offset)+11*8)(X2)
59+
60+#define RESTORE_FPR(offset) \
61+ MOVD ((offset)+0*8)(X2), F8 \
62+ MOVD ((offset)+1*8)(X2), F9 \
63+ MOVD ((offset)+2*8)(X2), F18 \
64+ MOVD ((offset)+3*8)(X2), F19 \
65+ MOVD ((offset)+4*8)(X2), F20 \
66+ MOVD ((offset)+5*8)(X2), F21 \
67+ MOVD ((offset)+6*8)(X2), F22 \
68+ MOVD ((offset)+7*8)(X2), F23 \
69+ MOVD ((offset)+8*8)(X2), F24 \
70+ MOVD ((offset)+9*8)(X2), F25 \
71+ MOVD ((offset)+10*8)(X2), F26 \
72+ MOVD ((offset)+11*8)(X2), F27
@@ -0,0 +1,72 @@
1+// Copyright 2026 The Go Authors. All rights reserved.
2+// Use of this source code is governed by a BSD-style
3+// license that can be found in the LICENSE file.
4+
5+// Macros for transitioning from the host ABI to Go ABI0.
6+//
7+// These macros save and restore the callee-saved registers
8+// from the stack, but they don't adjust stack pointer, so
9+// the user should prepare stack space in advance.
10+// SAVE_GPR(offset) saves X8, X9, X18-X27 to the stack space
11+// of ((offset)+0*8)(X2) ~ ((offset)+11*8)(X2).
12+//
13+// SAVE_FPR(offset) saves F8, F9, F18-F27 to the stack space
14+// of ((offset)+0*8)(X2) ~ ((offset)+11*8)(X2).
15+//
16+// Note: g is X27
17+
18+#define SAVE_GPR(offset) \
19+ MOV X8, ((offset)+0*8)(X2) \
20+ MOV X9, ((offset)+1*8)(X2) \
21+ MOV X18, ((offset)+2*8)(X2) \
22+ MOV X19, ((offset)+3*8)(X2) \
23+ MOV X20, ((offset)+4*8)(X2) \
24+ MOV X21, ((offset)+5*8)(X2) \
25+ MOV X22, ((offset)+6*8)(X2) \
26+ MOV X23, ((offset)+7*8)(X2) \
27+ MOV X24, ((offset)+8*8)(X2) \
28+ MOV X25, ((offset)+9*8)(X2) \
29+ MOV X26, ((offset)+10*8)(X2) \
30+ MOV g, ((offset)+11*8)(X2)
31+
32+#define RESTORE_GPR(offset) \
33+ MOV ((offset)+0*8)(X2), X8 \
34+ MOV ((offset)+1*8)(X2), X9 \
35+ MOV ((offset)+2*8)(X2), X18 \
36+ MOV ((offset)+3*8)(X2), X19 \
37+ MOV ((offset)+4*8)(X2), X20 \
38+ MOV ((offset)+5*8)(X2), X21 \
39+ MOV ((offset)+6*8)(X2), X22 \
40+ MOV ((offset)+7*8)(X2), X23 \
41+ MOV ((offset)+8*8)(X2), X24 \
42+ MOV ((offset)+9*8)(X2), X25 \
43+ MOV ((offset)+10*8)(X2), X26 \
44+ MOV ((offset)+11*8)(X2), g
45+
46+#define SAVE_FPR(offset) \
47+ MOVD F8, ((offset)+0*8)(X2) \
48+ MOVD F9, ((offset)+1*8)(X2) \
49+ MOVD F18, ((offset)+2*8)(X2) \
50+ MOVD F19, ((offset)+3*8)(X2) \
51+ MOVD F20, ((offset)+4*8)(X2) \
52+ MOVD F21, ((offset)+5*8)(X2) \
53+ MOVD F22, ((offset)+6*8)(X2) \
54+ MOVD F23, ((offset)+7*8)(X2) \
55+ MOVD F24, ((offset)+8*8)(X2) \
56+ MOVD F25, ((offset)+9*8)(X2) \
57+ MOVD F26, ((offset)+10*8)(X2) \
58+ MOVD F27, ((offset)+11*8)(X2)
59+
60+#define RESTORE_FPR(offset) \
61+ MOVD ((offset)+0*8)(X2), F8 \
62+ MOVD ((offset)+1*8)(X2), F9 \
63+ MOVD ((offset)+2*8)(X2), F18 \
64+ MOVD ((offset)+3*8)(X2), F19 \
65+ MOVD ((offset)+4*8)(X2), F20 \
66+ MOVD ((offset)+5*8)(X2), F21 \
67+ MOVD ((offset)+6*8)(X2), F22 \
68+ MOVD ((offset)+7*8)(X2), F23 \
69+ MOVD ((offset)+8*8)(X2), F24 \
70+ MOVD ((offset)+9*8)(X2), F25 \
71+ MOVD ((offset)+10*8)(X2), F26 \
72+ MOVD ((offset)+11*8)(X2), F27
M internal/fakecgo/asm_riscv64.s +14 -55
@@ -3,6 +3,7 @@
33 // license that can be found in the LICENSE file.
44
55 #include "textflag.h"
6+#include "abi_riscv64.h"
67
78 // Called by C code generated by cmd/cgo.
89 // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
@@ -14,65 +15,23 @@ TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
1415 * registers. Note that at procedure entry the first argument is at
1516 * 8(X2).
1617 */
17- ADD $(-8*29), X2
18- MOV X10, (8*1)(X2) // fn unsafe.Pointer
19- MOV X11, (8*2)(X2) // a unsafe.Pointer
20- MOV X13, (8*3)(X2) // ctxt uintptr
21- MOV X8, (8*4)(X2)
22- MOV X9, (8*5)(X2)
23- MOV X18, (8*6)(X2)
24- MOV X19, (8*7)(X2)
25- MOV X20, (8*8)(X2)
26- MOV X21, (8*9)(X2)
27- MOV X22, (8*10)(X2)
28- MOV X23, (8*11)(X2)
29- MOV X24, (8*12)(X2)
30- MOV X25, (8*13)(X2)
31- MOV X26, (8*14)(X2)
32- MOV g, (8*15)(X2)
33- MOV X1, (8*16)(X2)
34- MOVD F8, (8*17)(X2)
35- MOVD F9, (8*18)(X2)
36- MOVD F18, (8*19)(X2)
37- MOVD F19, (8*20)(X2)
38- MOVD F20, (8*21)(X2)
39- MOVD F21, (8*22)(X2)
40- MOVD F22, (8*23)(X2)
41- MOVD F23, (8*24)(X2)
42- MOVD F24, (8*25)(X2)
43- MOVD F25, (8*26)(X2)
44- MOVD F26, (8*27)(X2)
45- MOVD F27, (8*28)(X2)
18+ ADD $(-8*29), X2
19+ MOV X10, (8*1)(X2) // fn unsafe.Pointer
20+ MOV X11, (8*2)(X2) // a unsafe.Pointer
21+ MOV X13, (8*3)(X2) // ctxt uintptr
22+
23+ SAVE_GPR((8*4))
24+ MOV X1, (8*16)(X2)
25+ SAVE_FPR((8*17))
4626
4727 // Initialize Go ABI environment
4828 CALL runtime·load_g(SB)
4929 CALL runtime·cgocallback(SB)
5030
51- MOV (8*4)(X2), X8
52- MOV (8*5)(X2), X9
53- MOV (8*6)(X2), X18
54- MOV (8*7)(X2), X19
55- MOV (8*8)(X2), X20
56- MOV (8*9)(X2), X21
57- MOV (8*10)(X2), X22
58- MOV (8*11)(X2), X23
59- MOV (8*12)(X2), X24
60- MOV (8*13)(X2), X25
61- MOV (8*14)(X2), X26
62- MOV (8*15)(X2), g
63- MOV (8*16)(X2), X1
64- MOVD (8*17)(X2), F8
65- MOVD (8*18)(X2), F9
66- MOVD (8*19)(X2), F18
67- MOVD (8*20)(X2), F19
68- MOVD (8*21)(X2), F20
69- MOVD (8*22)(X2), F21
70- MOVD (8*23)(X2), F22
71- MOVD (8*24)(X2), F23
72- MOVD (8*25)(X2), F24
73- MOVD (8*26)(X2), F25
74- MOVD (8*27)(X2), F26
75- MOVD (8*28)(X2), F27
76- ADD $(8*29), X2
31+ RESTORE_GPR((8*4))
32+ MOV (8*16)(X2), X1
33+ RESTORE_FPR((8*17))
34+
35+ ADD $(8*29), X2
7736
7837 RET
@@ -3,6 +3,7 @@
3 // license that can be found in the LICENSE file.3 // license that can be found in the LICENSE file.
4 4
5 #include "textflag.h"5 #include "textflag.h"
6+#include "abi_riscv64.h"
6 7
7 // Called by C code generated by cmd/cgo.8 // Called by C code generated by cmd/cgo.
8 // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)9 // func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
@@ -14,65 +15,23 @@ TEXT crosscall2(SB), NOSPLIT|NOFRAME, $0
14 * registers. Note that at procedure entry the first argument is at15 * registers. Note that at procedure entry the first argument is at
15 * 8(X2).16 * 8(X2).
16 */17 */
17- ADD $(-8*29), X218+ ADD $(-8*29), X2
18- MOV X10, (8*1)(X2) // fn unsafe.Pointer19+ MOV X10, (8*1)(X2) // fn unsafe.Pointer
19- MOV X11, (8*2)(X2) // a unsafe.Pointer20+ MOV X11, (8*2)(X2) // a unsafe.Pointer
20- MOV X13, (8*3)(X2) // ctxt uintptr21+ MOV X13, (8*3)(X2) // ctxt uintptr
21- MOV X8, (8*4)(X2)22+
22- MOV X9, (8*5)(X2)23+ SAVE_GPR((8*4))
23- MOV X18, (8*6)(X2)24+ MOV X1, (8*16)(X2)
24- MOV X19, (8*7)(X2)25+ SAVE_FPR((8*17))
25- MOV X20, (8*8)(X2)
26- MOV X21, (8*9)(X2)
27- MOV X22, (8*10)(X2)
28- MOV X23, (8*11)(X2)
29- MOV X24, (8*12)(X2)
30- MOV X25, (8*13)(X2)
31- MOV X26, (8*14)(X2)
32- MOV g, (8*15)(X2)
33- MOV X1, (8*16)(X2)
34- MOVD F8, (8*17)(X2)
35- MOVD F9, (8*18)(X2)
36- MOVD F18, (8*19)(X2)
37- MOVD F19, (8*20)(X2)
38- MOVD F20, (8*21)(X2)
39- MOVD F21, (8*22)(X2)
40- MOVD F22, (8*23)(X2)
41- MOVD F23, (8*24)(X2)
42- MOVD F24, (8*25)(X2)
43- MOVD F25, (8*26)(X2)
44- MOVD F26, (8*27)(X2)
45- MOVD F27, (8*28)(X2)
46 26
47 // Initialize Go ABI environment27 // Initialize Go ABI environment
48 CALL runtime·load_g(SB)28 CALL runtime·load_g(SB)
49 CALL runtime·cgocallback(SB)29 CALL runtime·cgocallback(SB)
50 30
51- MOV (8*4)(X2), X831+ RESTORE_GPR((8*4))
52- MOV (8*5)(X2), X932+ MOV (8*16)(X2), X1
53- MOV (8*6)(X2), X1833+ RESTORE_FPR((8*17))
54- MOV (8*7)(X2), X1934+
55- MOV (8*8)(X2), X2035+ ADD $(8*29), X2
56- MOV (8*9)(X2), X21
57- MOV (8*10)(X2), X22
58- MOV (8*11)(X2), X23
59- MOV (8*12)(X2), X24
60- MOV (8*13)(X2), X25
61- MOV (8*14)(X2), X26
62- MOV (8*15)(X2), g
63- MOV (8*16)(X2), X1
64- MOVD (8*17)(X2), F8
65- MOVD (8*18)(X2), F9
66- MOVD (8*19)(X2), F18
67- MOVD (8*20)(X2), F19
68- MOVD (8*21)(X2), F20
69- MOVD (8*22)(X2), F21
70- MOVD (8*23)(X2), F22
71- MOVD (8*24)(X2), F23
72- MOVD (8*25)(X2), F24
73- MOVD (8*26)(X2), F25
74- MOVD (8*27)(X2), F26
75- MOVD (8*28)(X2), F27
76- ADD $(8*29), X2
77 36
78 RET37 RET
M internal/fakecgo/trampolines_riscv64.s +11 -2
@@ -5,6 +5,7 @@
55
66 #include "textflag.h"
77 #include "go_asm.h"
8+#include "abi_riscv64.h"
89
910 // these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
1011 // X5 is used as temporary register.
@@ -48,11 +49,19 @@ TEXT ·setg_trampoline(SB), NOSPLIT, $0
4849 CALL X5
4950 RET
5051
51-TEXT threadentry_trampoline(SB), NOSPLIT, $16
52- MOV X10, 8(SP)
52+TEXT threadentry_trampoline(SB), NOSPLIT, $200
53+ MOV X10, 8(SP)
54+
55+ SAVE_GPR(8*2)
56+ SAVE_FPR(8*14)
57+
5358 MOV ·threadentry_call(SB), X5
5459 MOV (X5), X5
5560 CALL X5
61+
62+ RESTORE_GPR(8*2)
63+ RESTORE_FPR(8*14)
64+
5665 RET
5766
5867 TEXT ·call5(SB), NOSPLIT, $0-48
@@ -5,6 +5,7 @@
5 5
6 #include "textflag.h"6 #include "textflag.h"
7 #include "go_asm.h"7 #include "go_asm.h"
8+#include "abi_riscv64.h"
8 9
9 // these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.10 // these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
10 // X5 is used as temporary register.11 // X5 is used as temporary register.
@@ -48,11 +49,19 @@ TEXT ·setg_trampoline(SB), NOSPLIT, $0
48 CALL X549 CALL X5
49 RET50 RET
50 51
51-TEXT threadentry_trampoline(SB), NOSPLIT, $1652+TEXT threadentry_trampoline(SB), NOSPLIT, $200
52- MOV X10, 8(SP)53+ MOV X10, 8(SP)
54+
55+ SAVE_GPR(8*2)
56+ SAVE_FPR(8*14)
57+
53 MOV ·threadentry_call(SB), X558 MOV ·threadentry_call(SB), X5
54 MOV (X5), X559 MOV (X5), X5
55 CALL X560 CALL X5
61+
62+ RESTORE_GPR(8*2)
63+ RESTORE_FPR(8*14)
64+
56 RET65 RET
57 66
58 TEXT ·call5(SB), NOSPLIT, $0-4867 TEXT ·call5(SB), NOSPLIT, $0-48

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close