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: 0x2,
50 wantLo: 0xfff,
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: 0x4,
79 wantLo: 0xfff,
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: 0x1000001,
100 shift: 1,
101 wantErr: true,
102 },
103 {
104 v: 0xfffffe,
105 shift: 2,
106 wantErr: true,
107 },
108 {
109 v: 0x4004,
110 shift: 2,
111 wantHi: 0x8,
112 wantLo: 0xfff,
113 },
114 {
115 v: 0xfffffc,
116 shift: 2,
117 wantHi: 0xffc000,
118 wantLo: 0xfff,
119 },
120 {
121 v: 0x1002ffc,
122 shift: 2,
123 wantHi: 0xfff000,
124 wantLo: 0xfff,
125 },
126 {
127 v: 0x1003000,
128 shift: 2,
129 wantErr: true,
130 },
131 {
132 v: 0xfffffe,
133 shift: 3,
134 wantErr: true,
135 },
136 {
137 v: 0x8008,
138 shift: 3,
139 wantHi: 0x10,
140 wantLo: 0xfff,
141 },
142 {
143 v: 0xfffff8,
144 shift: 3,
145 wantHi: 0xff8000,
146 wantLo: 0xfff,
147 },
148 {
149 v: 0x1006ff8,
150 shift: 3,
151 wantHi: 0xfff000,
152 wantLo: 0xfff,
153 },
154 {
155 v: 0x1007000,
156 shift: 3,
157 wantErr: true,
158 },
159
160 {
161 v: 7,
162 shift: 3,
163 wantHi: 7,
164 wantLo: 0,
165 },
166 {
167 v: 0x8ff7,
168 shift: 3,
169 wantHi: 0xfff,
170 wantLo: 0xfff,
171 },
172 {
173 v: 0x7ff8,
174 shift: 3,
175 wantHi: 0,
176 wantLo: 0xfff,
177 },
178 {
179 v: 0xfff,
180 shift: 1,
181 wantHi: 1,
182 wantLo: 0x7ff,
183 },
184 {
185 v: 0xfff,
186 shift: 2,
187 wantHi: 3,
188 wantLo: 0x3ff,
189 },
190 {
191 v: 0xfff,
192 shift: 3,
193 wantHi: 7,
194 wantLo: 0x1ff,
195 },
196 {
197 v: 0x1ffe,
198 shift: 2,
199 wantHi: 2,
200 wantLo: 0x7ff,
201 },
202 {
203 v: 0x1ffe,
204 shift: 3,
205 wantHi: 6,
206 wantLo: 0x3ff,
207 },
208 {
209 v: 0x1fff,
210 shift: 1,
211 wantHi: 1,
212 wantLo: 0xfff,
213 },
214 {
215 v: 0x1fff,
216 shift: 2,
217 wantHi: 3,
218 wantLo: 0x7ff,
219 },
220 {
221 v: 0x1fff,
222 shift: 3,
223 wantHi: 7,
224 wantLo: 0x3ff,
225 },
226 {
227 v: 0x1001,
228 shift: 1,
229 wantHi: 1,
230 wantLo: 0x800,
231 },
232 {
233 v: 0x1001,
234 shift: 2,
235 wantHi: 1,
236 wantLo: 0x400,
237 },
238 {
239 v: 0x1001,
240 shift: 3,
241 wantHi: 1,
242 wantLo: 0x200,
243 },
244 {
245 v: 0x1000,
246 shift: 0,
247 wantHi: 0x1,
248 wantLo: 0xfff,
249 },
250 {
251 v: 0x8000,
252 shift: 3,
253 wantHi: 0x8,
254 wantLo: 0xfff,
255 },
256 {
257 v: 0xfff,
258 shift: 0,
259 wantHi: 0,
260 wantLo: 0xfff,
261 },
262 {
263 v: 0x1ffe,
264 shift: 1,
265 wantHi: 0,
266 wantLo: 0xfff,
267 },
268 {
269 v: 0x3ffc,
270 shift: 2,
271 wantHi: 0,
272 wantLo: 0xfff,
273 },
274 {
275 v: 0x10fef,
276 shift: 4,
277 wantHi: 0xfff,
278 wantLo: 0xfff,
279 },
280 }
281 for _, test := range tests {
282 hi, lo, err := splitImm24uScaled(test.v, test.shift)
283 switch {
284 case err == nil && test.wantErr:
285 t.Errorf("splitImm24uScaled(%v, %v) succeeded, want error", test.v, test.shift)
286 case err != nil && !test.wantErr:
287 t.Errorf("splitImm24uScaled(%v, %v) failed: %v", test.v, test.shift, err)
288 case !test.wantErr:
289 if got, want := hi, test.wantHi; got != want {
290 t.Errorf("splitImm24uScaled(%x, %x) - got hi %x, want %x", test.v, test.shift, got, want)
291 }
292 if got, want := lo, test.wantLo; got != want {
293 t.Errorf("splitImm24uScaled(%x, %x) - got lo %x, want %x", test.v, test.shift, got, want)
294 }
295 }
296 }
297 for shift := 0; shift <= 3; shift++ {
298 for v := int32(0); v < 0xfff000+0xfff<<shift; v = v + 1<<shift {
299 hi, lo, err := splitImm24uScaled(v, shift)
300 if err != nil {
301 t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
302 }
303 if hi+lo<<shift != v {
304 t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
305 }
306 }
307 }
308
309
310
311 for shift := 0; shift <= 3; shift++ {
312 maxUnshifted := int32(0xfff + 0xfff<<shift)
313 for v := int32(0); v <= maxUnshifted; v++ {
314 hi, lo, err := splitImm24uScaled(v, shift)
315 if err != nil {
316 t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
317 }
318 if hi+lo<<shift != v {
319 t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
320 }
321 }
322 }
323 }
324
325
326
327
328
329
330 func TestLarge(t *testing.T) {
331 if testing.Short() {
332 t.Skip("Skip in short mode")
333 }
334 testenv.MustHaveGoBuild(t)
335
336
337 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
338 fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
339 fmt.Fprintln(buf, "TBZ $5, R0, label")
340 fmt.Fprintln(buf, "CBZ R0, label")
341 fmt.Fprintln(buf, "BEQ label")
342 fmt.Fprintln(buf, "PCALIGN $128")
343 fmt.Fprintln(buf, "MOVD $3, R3")
344 for i := 0; i < 1<<19; i++ {
345 fmt.Fprintln(buf, "MOVD R0, R1")
346 }
347 fmt.Fprintln(buf, "label:")
348 fmt.Fprintln(buf, "RET")
349
350
351 out := runAssembler(t, buf.String())
352
353 pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3`
354 matched, err := regexp.MatchString(pattern, string(out))
355
356 if err != nil {
357 t.Fatal(err)
358 }
359 if !matched {
360 t.Errorf("The alignment is not correct: %t\n", matched)
361 }
362 }
363
364
365 func TestNoRet(t *testing.T) {
366 runAssembler(t, "TEXT ·stub(SB),$0-0\nNOP\n")
367 }
368
369
370
371 func TestPCALIGN(t *testing.T) {
372 testenv.MustHaveGoBuild(t)
373
374 code1 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n"
375 code2 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n"
376
377 out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1`
378
379 out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2`
380 var testCases = []struct {
381 name string
382 code string
383 out string
384 }{
385 {"8-byte alignment", code1, out1},
386 {"16-byte alignment", code2, out2},
387 }
388
389 for _, test := range testCases {
390 out := runAssembler(t, test.code)
391 matched, err := regexp.MatchString(test.out, string(out))
392 if err != nil {
393 t.Fatal(err)
394 }
395 if !matched {
396 t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
397 }
398 }
399 }
400
View as plain text