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