]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/riscv/asm_test.go
cmd/internal/obj/riscv: fix trampoline calls from large functions
[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         "io/ioutil"
12         "os"
13         "os/exec"
14         "path/filepath"
15         "runtime"
16         "testing"
17 )
18
19 // TestLargeBranch generates a large function with a very far conditional
20 // branch, in order to ensure that it assembles successfully.
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 := ioutil.TempDir("", "testlargebranch")
28         if err != nil {
29                 t.Fatalf("Could not create directory: %v", err)
30         }
31         defer os.RemoveAll(dir)
32
33         // Generate a very large function.
34         buf := bytes.NewBuffer(make([]byte, 0, 7000000))
35         genLargeBranch(buf)
36
37         tmpfile := filepath.Join(dir, "x.s")
38         if err := ioutil.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil {
39                 t.Fatalf("Failed to write file: %v", err)
40         }
41
42         // Assemble generated file.
43         cmd := exec.Command(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 // TestLargeCall generates a large function (>1MB of text) with a call to
62 // a following function, in order to ensure that it assembles and links
63 // correctly.
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 := ioutil.TempDir("", "testlargecall")
71         if err != nil {
72                 t.Fatalf("could not create directory: %v", err)
73         }
74         defer os.RemoveAll(dir)
75
76         if err := ioutil.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 := ioutil.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil {
88                 t.Fatalf("failed to write main: %v\n", err)
89         }
90
91         // Generate a very large function with call.
92         buf := bytes.NewBuffer(make([]byte, 0, 7000000))
93         genLargeCall(buf)
94
95         if err := ioutil.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil {
96                 t.Fatalf("Failed to write file: %v\n", err)
97         }
98
99         // Build generated files.
100         cmd := exec.Command(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 := exec.Command(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 // Issue 20348.
132 func TestNoRet(t *testing.T) {
133         dir, err := ioutil.TempDir("", "testnoret")
134         if err != nil {
135                 t.Fatal(err)
136         }
137         defer os.RemoveAll(dir)
138         tmpfile := filepath.Join(dir, "x.s")
139         if err := ioutil.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil {
140                 t.Fatal(err)
141         }
142         cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
143         cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
144         if out, err := cmd.CombinedOutput(); err != nil {
145                 t.Errorf("%v\n%s", err, out)
146         }
147 }
148
149 func TestImmediateSplitting(t *testing.T) {
150         dir, err := ioutil.TempDir("", "testimmsplit")
151         if err != nil {
152                 t.Fatal(err)
153         }
154         defer os.RemoveAll(dir)
155         tmpfile := filepath.Join(dir, "x.s")
156         asm := `
157 TEXT _stub(SB),$0-0
158         LB      4096(X5), X6
159         LH      4096(X5), X6
160         LW      4096(X5), X6
161         LD      4096(X5), X6
162         LBU     4096(X5), X6
163         LHU     4096(X5), X6
164         LWU     4096(X5), X6
165         SB      X6, 4096(X5)
166         SH      X6, 4096(X5)
167         SW      X6, 4096(X5)
168         SD      X6, 4096(X5)
169
170         FLW     4096(X5), F6
171         FLD     4096(X5), F6
172         FSW     F6, 4096(X5)
173         FSD     F6, 4096(X5)
174
175         MOVB    4096(X5), X6
176         MOVH    4096(X5), X6
177         MOVW    4096(X5), X6
178         MOV     4096(X5), X6
179         MOVBU   4096(X5), X6
180         MOVHU   4096(X5), X6
181         MOVWU   4096(X5), X6
182
183         MOVB    X6, 4096(X5)
184         MOVH    X6, 4096(X5)
185         MOVW    X6, 4096(X5)
186         MOV     X6, 4096(X5)
187
188         MOVF    4096(X5), F6
189         MOVD    4096(X5), F6
190         MOVF    F6, 4096(X5)
191         MOVD    F6, 4096(X5)
192 `
193         if err := ioutil.WriteFile(tmpfile, []byte(asm), 0644); err != nil {
194                 t.Fatal(err)
195         }
196         cmd := exec.Command(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 TestBranch(t *testing.T) {
204         if runtime.GOARCH != "riscv64" {
205                 t.Skip("Requires riscv64 to run")
206         }
207
208         testenv.MustHaveGoBuild(t)
209
210         cmd := exec.Command(testenv.GoToolPath(t), "test")
211         cmd.Dir = "testdata/testbranch"
212         if out, err := testenv.CleanCmdEnv(cmd).CombinedOutput(); err != nil {
213                 t.Errorf("Branch test failed: %v\n%s", err, out)
214         }
215 }