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 TestSplitImm24uScaled(t *testing.T) {
18 tests := []struct {
19 v int32
20 shift int
21 wantErr bool
22 wantHi int32
23 wantLo int32
24 }{
25 {
26 v: 0,
27 shift: 0,
28 wantHi: 0,
29 wantLo: 0,
30 },
31 {
32 v: 0x1001,
33 shift: 0,
34 wantHi: 0x1000,
35 wantLo: 0x1,
36 },
37 {
38 v: 0xffffff,
39 shift: 0,
40 wantHi: 0xfff000,
41 wantLo: 0xfff,
42 },
43 {
44 v: 0xffffff,
45 shift: 1,
46 wantErr: true,
47 },
48 {
49 v: 0xfe,
50 shift: 1,
51 wantHi: 0x0,
52 wantLo: 0x7f,
53 },
54 {
55 v: 0x10fe,
56 shift: 1,
57 wantHi: 0x0,
58 wantLo: 0x87f,
59 },
60 {
61 v: 0x2002,
62 shift: 1,
63 wantHi: 0x2000,
64 wantLo: 0x1,
65 },
66 {
67 v: 0xfffffe,
68 shift: 1,
69 wantHi: 0xffe000,
70 wantLo: 0xfff,
71 },
72 {
73 v: 0x1000ffe,
74 shift: 1,
75 wantHi: 0xfff000,
76 wantLo: 0xfff,
77 },
78 {
79 v: 0x1001000,
80 shift: 1,
81 wantErr: true,
82 },
83 {
84 v: 0xfffffe,
85 shift: 2,
86 wantErr: true,
87 },
88 {
89 v: 0x4004,
90 shift: 2,
91 wantHi: 0x4000,
92 wantLo: 0x1,
93 },
94 {
95 v: 0xfffffc,
96 shift: 2,
97 wantHi: 0xffc000,
98 wantLo: 0xfff,
99 },
100 {
101 v: 0x1002ffc,
102 shift: 2,
103 wantHi: 0xfff000,
104 wantLo: 0xfff,
105 },
106 {
107 v: 0x1003000,
108 shift: 2,
109 wantErr: true,
110 },
111 {
112 v: 0xfffffe,
113 shift: 3,
114 wantErr: true,
115 },
116 {
117 v: 0x8008,
118 shift: 3,
119 wantHi: 0x8000,
120 wantLo: 0x1,
121 },
122 {
123 v: 0xfffff8,
124 shift: 3,
125 wantHi: 0xff8000,
126 wantLo: 0xfff,
127 },
128 {
129 v: 0x1006ff8,
130 shift: 3,
131 wantHi: 0xfff000,
132 wantLo: 0xfff,
133 },
134 {
135 v: 0x1007000,
136 shift: 3,
137 wantErr: true,
138 },
139 }
140 for _, test := range tests {
141 hi, lo, err := splitImm24uScaled(test.v, test.shift)
142 switch {
143 case err == nil && test.wantErr:
144 t.Errorf("splitImm24uScaled(%v, %v) succeeded, want error", test.v, test.shift)
145 case err != nil && !test.wantErr:
146 t.Errorf("splitImm24uScaled(%v, %v) failed: %v", test.v, test.shift, err)
147 case !test.wantErr:
148 if got, want := hi, test.wantHi; got != want {
149 t.Errorf("splitImm24uScaled(%x, %x) - got hi %x, want %x", test.v, test.shift, got, want)
150 }
151 if got, want := lo, test.wantLo; got != want {
152 t.Errorf("splitImm24uScaled(%x, %x) - got lo %x, want %x", test.v, test.shift, got, want)
153 }
154 }
155 }
156 for shift := 0; shift <= 3; shift++ {
157 for v := int32(0); v < 0xfff000+0xfff<<shift; v = v + 1<<shift {
158 hi, lo, err := splitImm24uScaled(v, shift)
159 if err != nil {
160 t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
161 }
162 if hi+lo<<shift != v {
163 t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
164 }
165 }
166 }
167 }
168
169
170
171
172
173
174 func TestLarge(t *testing.T) {
175 if testing.Short() {
176 t.Skip("Skip in short mode")
177 }
178 testenv.MustHaveGoBuild(t)
179
180 dir, err := os.MkdirTemp("", "testlarge")
181 if err != nil {
182 t.Fatalf("could not create directory: %v", err)
183 }
184 defer os.RemoveAll(dir)
185
186
187 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
188 gen(buf)
189
190 tmpfile := filepath.Join(dir, "x.s")
191 err = os.WriteFile(tmpfile, buf.Bytes(), 0644)
192 if err != nil {
193 t.Fatalf("can't write output: %v\n", err)
194 }
195
196 pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3`
197
198
199 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
200 cmd.Env = append(os.Environ(), "GOOS=linux")
201 out, err := cmd.CombinedOutput()
202 if err != nil {
203 t.Errorf("Assemble failed: %v, output: %s", err, out)
204 }
205 matched, err := regexp.MatchString(pattern, string(out))
206 if err != nil {
207 t.Fatal(err)
208 }
209 if !matched {
210 t.Errorf("The alignment is not correct: %t, output:%s\n", matched, out)
211 }
212
213
214 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
215 cmd.Env = append(os.Environ(), "GOOS=linux")
216 out, err = cmd.CombinedOutput()
217 if err != nil {
218 t.Errorf("Build failed: %v, output: %s", err, out)
219 }
220 }
221
222
223 func gen(buf *bytes.Buffer) {
224 fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
225 fmt.Fprintln(buf, "TBZ $5, R0, label")
226 fmt.Fprintln(buf, "CBZ R0, label")
227 fmt.Fprintln(buf, "BEQ label")
228 fmt.Fprintln(buf, "PCALIGN $128")
229 fmt.Fprintln(buf, "MOVD $3, R3")
230 for i := 0; i < 1<<19; i++ {
231 fmt.Fprintln(buf, "MOVD R0, R1")
232 }
233 fmt.Fprintln(buf, "label:")
234 fmt.Fprintln(buf, "RET")
235 }
236
237
238 func TestNoRet(t *testing.T) {
239 dir, err := os.MkdirTemp("", "testnoret")
240 if err != nil {
241 t.Fatal(err)
242 }
243 defer os.RemoveAll(dir)
244 tmpfile := filepath.Join(dir, "x.s")
245 if err := os.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil {
246 t.Fatal(err)
247 }
248 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
249 cmd.Env = append(os.Environ(), "GOOS=linux")
250 if out, err := cmd.CombinedOutput(); err != nil {
251 t.Errorf("%v\n%s", err, out)
252 }
253 }
254
255
256
257 func TestPCALIGN(t *testing.T) {
258 testenv.MustHaveGoBuild(t)
259 dir, err := os.MkdirTemp("", "testpcalign")
260 if err != nil {
261 t.Fatal(err)
262 }
263 defer os.RemoveAll(dir)
264 tmpfile := filepath.Join(dir, "test.s")
265 tmpout := filepath.Join(dir, "test.o")
266
267 code1 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n")
268 code2 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n")
269
270 out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1`
271
272 out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2`
273 var testCases = []struct {
274 name string
275 code []byte
276 out string
277 }{
278 {"8-byte alignment", code1, out1},
279 {"16-byte alignment", code2, out2},
280 }
281
282 for _, test := range testCases {
283 if err := os.WriteFile(tmpfile, test.code, 0644); err != nil {
284 t.Fatal(err)
285 }
286 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile)
287 cmd.Env = append(os.Environ(), "GOOS=linux")
288 out, err := cmd.CombinedOutput()
289 if err != nil {
290 t.Errorf("The %s build failed: %v, output: %s", test.name, err, out)
291 continue
292 }
293
294 matched, err := regexp.MatchString(test.out, string(out))
295 if err != nil {
296 t.Fatal(err)
297 }
298 if !matched {
299 t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
300 }
301 }
302 }
303
304 func testvmovs() (r1, r2 uint64)
305 func testvmovd() (r1, r2 uint64)
306 func testvmovq() (r1, r2 uint64)
307
308 func TestVMOV(t *testing.T) {
309 tests := []struct {
310 op string
311 vmovFunc func() (uint64, uint64)
312 wantA, wantB uint64
313 }{
314 {"VMOVS", testvmovs, 0x80402010, 0},
315 {"VMOVD", testvmovd, 0x7040201008040201, 0},
316 {"VMOVQ", testvmovq, 0x7040201008040201, 0x3040201008040201},
317 }
318 for _, test := range tests {
319 gotA, gotB := test.vmovFunc()
320 if gotA != test.wantA || gotB != test.wantB {
321 t.Errorf("%v: got: a=0x%x, b=0x%x, want: a=0x%x, b=0x%x", test.op, gotA, gotB, test.wantA, test.wantB)
322 }
323 }
324 }
325
326 func testmovk() uint64
327
328
329 func TestMOVK(t *testing.T) {
330 x := testmovk()
331 want := uint64(40000 << 48)
332 if x != want {
333 t.Errorf("Got %x want %x\n", x, want)
334 }
335 }
336
View as plain text