1
2
3
4
5 package ppc64
6
7 import (
8 "bytes"
9 "cmd/internal/obj"
10 "cmd/internal/objabi"
11 "fmt"
12 "internal/testenv"
13 "io/ioutil"
14 "math"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "regexp"
19 "strings"
20 "testing"
21 )
22
23 var platformEnvs = [][]string{
24 {"GOOS=aix", "GOARCH=ppc64"},
25 {"GOOS=linux", "GOARCH=ppc64"},
26 {"GOOS=linux", "GOARCH=ppc64le"},
27 }
28
29 const invalidPCAlignSrc = `
30 TEXT test(SB),0,$0-0
31 ADD $2, R3
32 PCALIGN $64
33 RET
34 `
35
36 const validPCAlignSrc = `
37 TEXT test(SB),0,$0-0
38 ADD $2, R3
39 PCALIGN $16
40 MOVD $8, R16
41 ADD $8, R4
42 PCALIGN $32
43 ADD $8, R3
44 PCALIGN $8
45 ADD $4, R8
46 RET
47 `
48
49 const x64pgm = `
50 TEXT test(SB),0,$0-0
51 OR R0, R0
52 OR R0, R0
53 OR R0, R0
54 OR R0, R0
55 OR R0, R0
56 OR R0, R0
57 OR R0, R0
58 OR R0, R0
59 OR R0, R0
60 OR R0, R0
61 OR R0, R0
62 OR R0, R0
63 OR R0, R0
64 OR R0, R0
65 OR R0, R0
66 PNOP
67 `
68 const x32pgm = `
69 TEXT test(SB),0,$0-0
70 OR R0, R0
71 OR R0, R0
72 OR R0, R0
73 OR R0, R0
74 OR R0, R0
75 OR R0, R0
76 OR R0, R0
77 PNOP
78 OR R0, R0
79 OR R0, R0
80 OR R0, R0
81 OR R0, R0
82 OR R0, R0
83 OR R0, R0
84 OR R0, R0
85 OR R0, R0
86 `
87
88 const x16pgm = `
89 TEXT test(SB),0,$0-0
90 OR R0, R0
91 OR R0, R0
92 OR R0, R0
93 PNOP
94 OR R0, R0
95 OR R0, R0
96 OR R0, R0
97 OR R0, R0
98 OR R0, R0
99 OR R0, R0
100 OR R0, R0
101 OR R0, R0
102 OR R0, R0
103 OR R0, R0
104 OR R0, R0
105 OR R0, R0
106 `
107
108 const x0pgm = `
109 TEXT test(SB),0,$0-0
110 OR R0, R0
111 OR R0, R0
112 OR R0, R0
113 OR R0, R0
114 PNOP
115 OR R0, R0
116 OR R0, R0
117 OR R0, R0
118 OR R0, R0
119 OR R0, R0
120 OR R0, R0
121 OR R0, R0
122 OR R0, R0
123 OR R0, R0
124 OR R0, R0
125 OR R0, R0
126 `
127 const x64pgmA64 = `
128 TEXT test(SB),0,$0-0
129 OR R0, R0
130 OR R0, R0
131 OR R0, R0
132 OR R0, R0
133 OR R0, R0
134 OR R0, R0
135 OR R0, R0
136 PNOP
137 OR R0, R0
138 OR R0, R0
139 OR R0, R0
140 OR R0, R0
141 OR R0, R0
142 OR R0, R0
143 PNOP
144 `
145
146 const x64pgmA32 = `
147 TEXT test(SB),0,$0-0
148 OR R0, R0
149 OR R0, R0
150 OR R0, R0
151 PNOP
152 OR R0, R0
153 OR R0, R0
154 OR R0, R0
155 OR R0, R0
156 OR R0, R0
157 OR R0, R0
158 OR R0, R0
159 OR R0, R0
160 OR R0, R0
161 OR R0, R0
162 PNOP
163 `
164
165
166
167 func TestPfxAlign(t *testing.T) {
168 testenv.MustHaveGoBuild(t)
169
170 dir, err := ioutil.TempDir("", "testpfxalign")
171 if err != nil {
172 t.Fatalf("could not create directory: %v", err)
173 }
174 defer os.RemoveAll(dir)
175
176 pgms := []struct {
177 text []byte
178 align string
179 hasNop bool
180 }{
181 {[]byte(x0pgm), "align=0x0", false},
182 {[]byte(x16pgm), "align=0x20", false},
183 {[]byte(x32pgm), "align=0x40", false},
184 {[]byte(x64pgm), "align=0x0", true},
185 {[]byte(x64pgmA64), "align=0x40", true},
186 {[]byte(x64pgmA32), "align=0x20", true},
187 }
188
189 for _, pgm := range pgms {
190 tmpfile := filepath.Join(dir, "x.s")
191 err = ioutil.WriteFile(tmpfile, pgm.text, 0644)
192 if err != nil {
193 t.Fatalf("can't write output: %v\n", err)
194 }
195 cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
196 cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=ppc64le")
197 out, err := cmd.CombinedOutput()
198 if err != nil {
199 t.Errorf("Failed to compile %v: %v\n", pgm, err)
200 }
201 if !strings.Contains(string(out), pgm.align) {
202 t.Errorf(fmt.Sprintf("Fatal, misaligned text with prefixed instructions:\n%s\n", string(out)))
203 }
204 hasNop := strings.Contains(string(out), "00 00 00 60")
205 if hasNop != pgm.hasNop {
206 t.Errorf(fmt.Sprintf("Fatal, prefixed instruction is missing nop padding:\n%s\n", string(out)))
207 }
208 }
209 }
210
211
212
213
214 func TestLarge(t *testing.T) {
215 if testing.Short() {
216 t.Skip("Skip in short mode")
217 }
218 testenv.MustHaveGoBuild(t)
219
220 dir, err := ioutil.TempDir("", "testlarge")
221 if err != nil {
222 t.Fatalf("could not create directory: %v", err)
223 }
224 defer os.RemoveAll(dir)
225
226
227 tests := []struct {
228 jmpinsn string
229 backpattern []string
230 fwdpattern []string
231 }{
232
233
234
235
236
237 {"BEQ",
238 []string{``,
239 `0x20030 131120\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s131128`,
240 `0x20034 131124\s\(.*\)\tJMP\t0`},
241 []string{``,
242 `0x0000 00000\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s8`,
243 `0x0004 00004\s\(.*\)\tJMP\t131128`},
244 },
245 {"BNE",
246 []string{``,
247 `0x20030 131120\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s131128`,
248 `0x20034 131124\s\(.*\)\tJMP\t0`},
249 []string{``,
250 `0x0000 00000\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s8`,
251 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
252
253 {"BC 16,0,",
254 []string{``,
255 `0x20030 131120\s\(.*\)\tBC\t\$18,\s131128`,
256 `0x20034 131124\s\(.*\)\tJMP\t0`},
257 []string{``,
258 `0x0000 00000\s\(.*\)\tBC\t\$18,\s8`,
259 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
260 {"BC 18,0,",
261 []string{``,
262 `0x20030 131120\s\(.*\)\tBC\t\$16,\s131128`,
263 `0x20034 131124\s\(.*\)\tJMP\t0`},
264 []string{``,
265 `0x0000 00000\s\(.*\)\tBC\t\$16,\s8`,
266 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
267
268 {"BC 8,0,",
269 []string{``,
270 `0x20034 131124\s\(.*\)\tBC\t\$8,\sR0,\s131132`,
271 `0x20038 131128\s\(.*\)\tJMP\t131136`,
272 `0x2003c 131132\s\(.*\)\tJMP\t0\n`},
273 []string{``,
274 `0x0000 00000\s\(.*\)\tBC\t\$8,\sR0,\s8`,
275 `0x0004 00004\s\(.*\)\tJMP\t12`,
276 `0x0008 00008\s\(.*\)\tJMP\t131136\n`}},
277 }
278
279 for _, test := range tests {
280
281 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
282 gen(buf, test.jmpinsn)
283
284 tmpfile := filepath.Join(dir, "x.s")
285 err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
286 if err != nil {
287 t.Fatalf("can't write output: %v\n", err)
288 }
289
290
291 for _, platenv := range platformEnvs {
292 cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
293 cmd.Env = append(os.Environ(), platenv...)
294 out, err := cmd.CombinedOutput()
295 if err != nil {
296 t.Errorf("Assemble failed (%v): %v, output: %s", platenv, err, out)
297 }
298 matched, err := regexp.MatchString(strings.Join(test.fwdpattern, "\n\t*"), string(out))
299 if err != nil {
300 t.Fatal(err)
301 }
302 if !matched {
303 t.Errorf("Failed to detect long forward BC fixup in (%v):%s\n", platenv, out)
304 }
305 matched, err = regexp.MatchString(strings.Join(test.backpattern, "\n\t*"), string(out))
306 if err != nil {
307 t.Fatal(err)
308 }
309 if !matched {
310 t.Errorf("Failed to detect long backward BC fixup in (%v):%s\n", platenv, out)
311 }
312 }
313 }
314 }
315
316
317 func gen(buf *bytes.Buffer, jmpinsn string) {
318 fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
319 fmt.Fprintln(buf, "label_start:")
320 fmt.Fprintln(buf, jmpinsn, "label_end")
321 for i := 0; i < (1<<15 + 10); i++ {
322 fmt.Fprintln(buf, "MOVD R0, R1")
323 }
324 fmt.Fprintln(buf, jmpinsn, "label_start")
325 fmt.Fprintln(buf, "label_end:")
326 fmt.Fprintln(buf, "MOVD R0, R1")
327 fmt.Fprintln(buf, "RET")
328 }
329
330
331
332
333 func TestPCalign(t *testing.T) {
334 var pattern8 = `0x...8\s.*ADD\s..,\sR8`
335 var pattern16 = `0x...[80]\s.*MOVD\s..,\sR16`
336 var pattern32 = `0x...0\s.*ADD\s..,\sR3`
337
338 testenv.MustHaveGoBuild(t)
339
340 dir, err := ioutil.TempDir("", "testpcalign")
341 if err != nil {
342 t.Fatalf("could not create directory: %v", err)
343 }
344 defer os.RemoveAll(dir)
345
346
347
348 tmpfile := filepath.Join(dir, "x.s")
349 err = ioutil.WriteFile(tmpfile, []byte(validPCAlignSrc), 0644)
350 if err != nil {
351 t.Fatalf("can't write output: %v\n", err)
352 }
353
354
355 cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile)
356 cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
357 out, err := cmd.CombinedOutput()
358 if err != nil {
359 t.Errorf("Build failed: %v, output: %s", err, out)
360 }
361
362 matched, err := regexp.MatchString(pattern8, string(out))
363 if err != nil {
364 t.Fatal(err)
365 }
366 if !matched {
367 t.Errorf("The 8 byte alignment is not correct: %t, output:%s\n", matched, out)
368 }
369
370 matched, err = regexp.MatchString(pattern16, string(out))
371 if err != nil {
372 t.Fatal(err)
373 }
374 if !matched {
375 t.Errorf("The 16 byte alignment is not correct: %t, output:%s\n", matched, out)
376 }
377
378 matched, err = regexp.MatchString(pattern32, string(out))
379 if err != nil {
380 t.Fatal(err)
381 }
382 if !matched {
383 t.Errorf("The 32 byte alignment is not correct: %t, output:%s\n", matched, out)
384 }
385
386
387
388 tmpfile = filepath.Join(dir, "xi.s")
389 err = ioutil.WriteFile(tmpfile, []byte(invalidPCAlignSrc), 0644)
390 if err != nil {
391 t.Fatalf("can't write output: %v\n", err)
392 }
393
394
395 cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "xi.o"), "-S", tmpfile)
396 cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
397 out, err = cmd.CombinedOutput()
398 if !strings.Contains(string(out), "Unexpected alignment") {
399 t.Errorf("Invalid alignment not detected for PCALIGN\n")
400 }
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415 func TestRegValueAlignment(t *testing.T) {
416 tstFunc := func(rstart, rend, msk, rout int) {
417 for i := rstart; i <= rend; i++ {
418 if i&msk != rout {
419 t.Errorf("%v is not aligned to 0x%X (expected %d, got %d)\n", rconv(i), msk, rout, rstart&msk)
420 }
421 rout++
422 }
423 }
424 var testType = []struct {
425 rstart int
426 rend int
427 msk int
428 rout int
429 }{
430 {REG_VS0, REG_VS63, 63, 0},
431 {REG_R0, REG_R31, 31, 0},
432 {REG_F0, REG_F31, 31, 0},
433 {REG_V0, REG_V31, 31, 0},
434 {REG_V0, REG_V31, 63, 32},
435 {REG_F0, REG_F31, 63, 0},
436 {REG_SPR0, REG_SPR0 + 1023, 1023, 0},
437 {REG_CR0, REG_CR7, 7, 0},
438 {REG_CR0LT, REG_CR7SO, 31, 0},
439 }
440 for _, t := range testType {
441 tstFunc(t.rstart, t.rend, t.msk, t.rout)
442 }
443 }
444
445
446 func TestAddrClassifier(t *testing.T) {
447 type cmplx struct {
448 pic int
449 pic_dyn int
450 dyn int
451 nonpic int
452 }
453 tsts := [...]struct {
454 arg obj.Addr
455 output interface{}
456 }{
457
458 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R1}, C_REG},
459 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R2}, C_REGP},
460 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F1}, C_FREG},
461 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F2}, C_FREGP},
462 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_V2}, C_VREG},
463 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS1}, C_VSREG},
464 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS2}, C_VSREGP},
465 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR}, C_CREG},
466 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1}, C_CREG},
467 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1SO}, C_CRBIT},
468 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0}, C_SPR},
469 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 1}, C_XER},
470 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 8}, C_LR},
471 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR},
472 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR},
473
474
475 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_GOTREF}, C_ADDR},
476 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_TOCREF}, C_ADDR},
477 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.STLSBSS}}, cmplx{C_TLS_IE, C_TLS_IE, C_TLS_LE, C_TLS_LE}},
478 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_ADDR},
479 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO}, C_SOREG},
480 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: BIG}, C_LOREG},
481 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LOREG},
482 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM}, C_SOREG},
483 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: BIG}, C_LOREG},
484 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LOREG},
485 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG},
486 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: 1}, C_SOREG},
487 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: BIG}, C_LOREG},
488 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: -BIG - 33}, C_LOREG},
489
490
491 {obj.Addr{Type: obj.TYPE_TEXTSIZE}, C_TEXTSIZE},
492 {obj.Addr{Type: obj.TYPE_FCONST, Val: 0.0}, C_ZCON},
493 {obj.Addr{Type: obj.TYPE_FCONST, Val: math.Float64frombits(0x8000000000000000)}, C_S16CON},
494
495
496 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1}, C_SACON},
497 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: BIG}, C_LACON},
498 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: -BIG - 1}, C_LACON},
499 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1 << 32}, C_DACON},
500 {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
501 {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_STATIC, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
502 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: 1}, C_SACON},
503 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: BIG}, C_LACON},
504 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LACON},
505 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: 1}, C_SACON},
506 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: BIG}, C_LACON},
507 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LACON},
508
509
510 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 0}, C_ZCON},
511 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1}, C_U1CON},
512 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 2}, C_U2CON},
513 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 4}, C_U3CON},
514 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 8}, C_U4CON},
515 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 16}, C_U5CON},
516 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 32}, C_U8CON},
517 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 14}, C_U15CON},
518 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 15}, C_U16CON},
519 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 16}, C_U3216CON},
520 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 + 1<<16}, C_U32CON},
521 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 32}, C_S34CON},
522 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 33}, C_64CON},
523 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -1}, C_S16CON},
524 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10000}, C_S3216CON},
525 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10001}, C_S32CON},
526 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON},
527 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON},
528
529
530 {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}},
531 {obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA},
532 }
533
534 pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0}
535 pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
536 dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
537 nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0}
538 ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9}
539 name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"}
540 for _, tst := range tsts {
541 var expect []int
542 switch tst.output.(type) {
543 case cmplx:
544 v := tst.output.(cmplx)
545 expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic}
546 case int:
547 expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)}
548 }
549 for i, _ := range ctxts {
550 if output := ctxts[i].aclass(&tst.arg); output != expect[i] {
551 t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i]))
552 }
553 }
554 }
555 }
556
View as plain text