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