1
2
3
4
5 package riscv
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/testenv"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "runtime"
15 "strings"
16 "testing"
17 )
18
19
20
21 func TestLargeBranch(t *testing.T) {
22 if testing.Short() {
23 t.Skip("Skipping test in short mode")
24 }
25 testenv.MustHaveGoBuild(t)
26
27 dir := t.TempDir()
28
29
30 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
31 genLargeBranch(buf)
32
33 tmpfile := filepath.Join(dir, "x.s")
34 if err := os.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil {
35 t.Fatalf("Failed to write file: %v", err)
36 }
37
38
39 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
40 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
41 out, err := cmd.CombinedOutput()
42 if err != nil {
43 t.Errorf("Build failed: %v, output: %s", err, out)
44 }
45 }
46
47 func genLargeBranch(buf *bytes.Buffer) {
48 fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
49 fmt.Fprintln(buf, "BEQ X0, X0, label")
50 for i := 0; i < 1<<19; i++ {
51 fmt.Fprintln(buf, "ADD $0, X0, X0")
52 }
53 fmt.Fprintln(buf, "label:")
54 fmt.Fprintln(buf, "ADD $0, X0, X0")
55 }
56
57
58
59
60 func TestLargeCall(t *testing.T) {
61 if testing.Short() {
62 t.Skip("Skipping test in short mode")
63 }
64 testenv.MustHaveGoBuild(t)
65
66 dir := t.TempDir()
67
68 if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module largecall"), 0644); err != nil {
69 t.Fatalf("Failed to write file: %v\n", err)
70 }
71 main := `package main
72 func main() {
73 x()
74 }
75
76 func x()
77 func y()
78 `
79 if err := os.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil {
80 t.Fatalf("failed to write main: %v\n", err)
81 }
82
83
84 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
85 genLargeCall(buf)
86
87 if err := os.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil {
88 t.Fatalf("Failed to write file: %v\n", err)
89 }
90
91
92 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal")
93 cmd.Dir = dir
94 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
95 out, err := cmd.CombinedOutput()
96 if err != nil {
97 t.Errorf("Build failed: %v, output: %s", err, out)
98 }
99
100 if runtime.GOARCH == "riscv64" && testenv.HasCGO() {
101 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=external")
102 cmd.Dir = dir
103 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
104 out, err := cmd.CombinedOutput()
105 if err != nil {
106 t.Errorf("Build failed: %v, output: %s", err, out)
107 }
108 }
109 }
110
111 func genLargeCall(buf *bytes.Buffer) {
112 fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-0")
113 fmt.Fprintln(buf, "CALL ·y(SB)")
114 for i := 0; i < 1<<19; i++ {
115 fmt.Fprintln(buf, "ADD $0, X0, X0")
116 }
117 fmt.Fprintln(buf, "RET")
118 fmt.Fprintln(buf, "TEXT ·y(SB),0,$0-0")
119 fmt.Fprintln(buf, "ADD $0, X0, X0")
120 fmt.Fprintln(buf, "RET")
121 }
122
123
124
125 func TestLargeJump(t *testing.T) {
126 if testing.Short() {
127 t.Skip("Skipping test in short mode")
128 }
129 if runtime.GOARCH != "riscv64" {
130 t.Skip("Require riscv64 to run")
131 }
132 testenv.MustHaveGoBuild(t)
133
134 dir := t.TempDir()
135
136 if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module largejump"), 0644); err != nil {
137 t.Fatalf("Failed to write file: %v\n", err)
138 }
139 main := `package main
140
141 import "fmt"
142
143 func main() {
144 fmt.Print(x())
145 }
146
147 func x() uint64
148 `
149 if err := os.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil {
150 t.Fatalf("failed to write main: %v\n", err)
151 }
152
153
154 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
155 genLargeJump(buf)
156
157 if err := os.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil {
158 t.Fatalf("Failed to write file: %v\n", err)
159 }
160
161
162 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "x.exe")
163 cmd.Dir = dir
164 out, err := cmd.CombinedOutput()
165 if err != nil {
166 t.Errorf("Build failed: %v, output: %s", err, out)
167 }
168
169 cmd = testenv.Command(t, filepath.Join(dir, "x.exe"))
170 out, err = cmd.CombinedOutput()
171 if string(out) != "1" {
172 t.Errorf(`Got test output %q, want "1"`, string(out))
173 }
174 }
175
176 func genLargeJump(buf *bytes.Buffer) {
177 fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-8")
178 fmt.Fprintln(buf, "MOV X0, X10")
179 fmt.Fprintln(buf, "JMP end")
180 for i := 0; i < 1<<18; i++ {
181 fmt.Fprintln(buf, "ADD $1, X10, X10")
182 }
183 fmt.Fprintln(buf, "end:")
184 fmt.Fprintln(buf, "ADD $1, X10, X10")
185 fmt.Fprintln(buf, "MOV X10, r+0(FP)")
186 fmt.Fprintln(buf, "RET")
187 }
188
189
190 func TestNoRet(t *testing.T) {
191 dir := t.TempDir()
192 tmpfile := filepath.Join(dir, "x.s")
193 if err := os.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil {
194 t.Fatal(err)
195 }
196 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
197 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
198 if out, err := cmd.CombinedOutput(); err != nil {
199 t.Errorf("%v\n%s", err, out)
200 }
201 }
202
203 func TestImmediateSplitting(t *testing.T) {
204 dir := t.TempDir()
205 tmpfile := filepath.Join(dir, "x.s")
206 asm := `
207 TEXT _stub(SB),$0-0
208 LB 4096(X5), X6
209 LH 4096(X5), X6
210 LW 4096(X5), X6
211 LD 4096(X5), X6
212 LBU 4096(X5), X6
213 LHU 4096(X5), X6
214 LWU 4096(X5), X6
215 SB X6, 4096(X5)
216 SH X6, 4096(X5)
217 SW X6, 4096(X5)
218 SD X6, 4096(X5)
219
220 FLW 4096(X5), F6
221 FLD 4096(X5), F6
222 FSW F6, 4096(X5)
223 FSD F6, 4096(X5)
224
225 MOVB 4096(X5), X6
226 MOVH 4096(X5), X6
227 MOVW 4096(X5), X6
228 MOV 4096(X5), X6
229 MOVBU 4096(X5), X6
230 MOVHU 4096(X5), X6
231 MOVWU 4096(X5), X6
232
233 MOVB X6, 4096(X5)
234 MOVH X6, 4096(X5)
235 MOVW X6, 4096(X5)
236 MOV X6, 4096(X5)
237
238 MOVF 4096(X5), F6
239 MOVD 4096(X5), F6
240 MOVF F6, 4096(X5)
241 MOVD F6, 4096(X5)
242 `
243 if err := os.WriteFile(tmpfile, []byte(asm), 0644); err != nil {
244 t.Fatal(err)
245 }
246 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
247 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
248 if out, err := cmd.CombinedOutput(); err != nil {
249 t.Errorf("%v\n%s", err, out)
250 }
251 }
252
253 func TestBranch(t *testing.T) {
254 if runtime.GOARCH != "riscv64" {
255 t.Skip("Requires riscv64 to run")
256 }
257
258 testenv.MustHaveGoBuild(t)
259
260 cmd := testenv.Command(t, testenv.GoToolPath(t), "test")
261 cmd.Dir = "testdata/testbranch"
262 if out, err := testenv.CleanCmdEnv(cmd).CombinedOutput(); err != nil {
263 t.Errorf("Branch test failed: %v\n%s", err, out)
264 }
265 }
266
267 func TestPCAlign(t *testing.T) {
268 dir := t.TempDir()
269 tmpfile := filepath.Join(dir, "x.s")
270 asm := `
271 TEXT _stub(SB),$0-0
272 FENCE
273 PCALIGN $8
274 FENCE
275 RET
276 `
277 if err := os.WriteFile(tmpfile, []byte(asm), 0644); err != nil {
278 t.Fatal(err)
279 }
280 cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile)
281 cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
282 out, err := cmd.CombinedOutput()
283 if err != nil {
284 t.Errorf("Failed to assemble: %v\n%s", err, out)
285 }
286
287
288
289
290
291 want := "0f 00 f0 0f 13 00 00 00 0f 00 f0 0f 67 80 00 00"
292 if !strings.Contains(string(out), want) {
293 t.Errorf("PCALIGN test failed - got %s\nwant %s", out, want)
294 }
295 }
296
View as plain text