1
2
3
4
5 package arm64
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/testenv"
11 "os"
12 "path/filepath"
13 "regexp"
14 "testing"
15 )
16
17 func runAssembler(t *testing.T, srcdata string) []byte {
18 dir := t.TempDir()
19 defer os.RemoveAll(dir)
20 srcfile := filepath.Join(dir, "testdata.s")
21 outfile := filepath.Join(dir, "testdata.o")
22 os.WriteFile(srcfile, []byte(srcdata), 0644)
23 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", outfile, srcfile)
24 cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=arm64")
25 out, err := cmd.CombinedOutput()
26 if err != nil {
27 t.Errorf("The build failed: %v, output:\n%s", err, out)
28 }
29 return out
30 }
31
32 func TestSplitImm24uScaled(t *testing.T) {
33 tests := []struct {
34 v int32
35 shift int
36 wantErr bool
37 wantHi int32
38 wantLo int32
39 }{
40 {
41 v: 0,
42 shift: 0,
43 wantHi: 0,
44 wantLo: 0,
45 },
46 {
47 v: 0x1001,
48 shift: 0,
49 wantHi: 0x1000,
50 wantLo: 0x1,
51 },
52 {
53 v: 0xffffff,
54 shift: 0,
55 wantHi: 0xfff000,
56 wantLo: 0xfff,
57 },
58 {
59 v: 0xffffff,
60 shift: 1,
61 wantErr: true,
62 },
63 {
64 v: 0xfe,
65 shift: 1,
66 wantHi: 0x0,
67 wantLo: 0x7f,
68 },
69 {
70 v: 0x10fe,
71 shift: 1,
72 wantHi: 0x0,
73 wantLo: 0x87f,
74 },
75 {
76 v: 0x2002,
77 shift: 1,
78 wantHi: 0x2000,
79 wantLo: 0x1,
80 },
81 {
82 v: 0xfffffe,
83 shift: 1,
84 wantHi: 0xffe000,
85 wantLo: 0xfff,
86 },
87 {
88 v: 0x1000ffe,
89 shift: 1,
90 wantHi: 0xfff000,
91 wantLo: 0xfff,
92 },
93 {
94 v: 0x1001000,
95 shift: 1,
96 wantErr: true,
97 },
98 {
99 v: 0xfffffe,
100 shift: 2,
101 wantErr: true,
102 },
103 {
104 v: 0x4004,
105 shift: 2,
106 wantHi: 0x4000,
107 wantLo: 0x1,
108 },
109 {
110 v: 0xfffffc,
111 shift: 2,
112 wantHi: 0xffc000,
113 wantLo: 0xfff,
114 },
115 {
116 v: 0x1002ffc,
117 shift: 2,
118 wantHi: 0xfff000,
119 wantLo: 0xfff,
120 },
121 {
122 v: 0x1003000,
123 shift: 2,
124 wantErr: true,
125 },
126 {
127 v: 0xfffffe,
128 shift: 3,
129 wantErr: true,
130 },
131 {
132 v: 0x8008,
133 shift: 3,
134 wantHi: 0x8000,
135 wantLo: 0x1,
136 },
137 {
138 v: 0xfffff8,
139 shift: 3,
140 wantHi: 0xff8000,
141 wantLo: 0xfff,
142 },
143 {
144 v: 0x1006ff8,
145 shift: 3,
146 wantHi: 0xfff000,
147 wantLo: 0xfff,
148 },
149 {
150 v: 0x1007000,
151 shift: 3,
152 wantErr: true,
153 },
154 }
155 for _, test := range tests {
156 hi, lo, err := splitImm24uScaled(test.v, test.shift)
157 switch {
158 case err == nil && test.wantErr:
159 t.Errorf("splitImm24uScaled(%v, %v) succeeded, want error", test.v, test.shift)
160 case err != nil && !test.wantErr:
161 t.Errorf("splitImm24uScaled(%v, %v) failed: %v", test.v, test.shift, err)
162 case !test.wantErr:
163 if got, want := hi, test.wantHi; got != want {
164 t.Errorf("splitImm24uScaled(%x, %x) - got hi %x, want %x", test.v, test.shift, got, want)
165 }
166 if got, want := lo, test.wantLo; got != want {
167 t.Errorf("splitImm24uScaled(%x, %x) - got lo %x, want %x", test.v, test.shift, got, want)
168 }
169 }
170 }
171 for shift := 0; shift <= 3; shift++ {
172 for v := int32(0); v < 0xfff000+0xfff<<shift; v = v + 1<<shift {
173 hi, lo, err := splitImm24uScaled(v, shift)
174 if err != nil {
175 t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
176 }
177 if hi+lo<<shift != v {
178 t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
179 }
180 }
181 }
182 }
183
184
185
186
187
188
189 func TestLarge(t *testing.T) {
190 if testing.Short() {
191 t.Skip("Skip in short mode")
192 }
193 testenv.MustHaveGoBuild(t)
194
195
196 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
197 fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
198 fmt.Fprintln(buf, "TBZ $5, R0, label")
199 fmt.Fprintln(buf, "CBZ R0, label")
200 fmt.Fprintln(buf, "BEQ label")
201 fmt.Fprintln(buf, "PCALIGN $128")
202 fmt.Fprintln(buf, "MOVD $3, R3")
203 for i := 0; i < 1<<19; i++ {
204 fmt.Fprintln(buf, "MOVD R0, R1")
205 }
206 fmt.Fprintln(buf, "label:")
207 fmt.Fprintln(buf, "RET")
208
209
210 out := runAssembler(t, buf.String())
211
212 pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3`
213 matched, err := regexp.MatchString(pattern, string(out))
214
215 if err != nil {
216 t.Fatal(err)
217 }
218 if !matched {
219 t.Errorf("The alignment is not correct: %t\n", matched)
220 }
221 }
222
223
224 func TestNoRet(t *testing.T) {
225 runAssembler(t, "TEXT ·stub(SB),$0-0\nNOP\n")
226 }
227
228
229
230 func TestPCALIGN(t *testing.T) {
231 testenv.MustHaveGoBuild(t)
232
233 code1 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n"
234 code2 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n"
235
236 out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1`
237
238 out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2`
239 var testCases = []struct {
240 name string
241 code string
242 out string
243 }{
244 {"8-byte alignment", code1, out1},
245 {"16-byte alignment", code2, out2},
246 }
247
248 for _, test := range testCases {
249 out := runAssembler(t, test.code)
250 matched, err := regexp.MatchString(test.out, string(out))
251 if err != nil {
252 t.Fatal(err)
253 }
254 if !matched {
255 t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
256 }
257 }
258 }
259
View as plain text