]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/ppc64/asm_test.go
87d4156ef97873b525cdc75e46b51678f26a5036
[gostls13.git] / src / cmd / internal / obj / ppc64 / asm_test.go
1 // Copyright 2020 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 ppc64
6
7 import (
8         "bytes"
9         "fmt"
10         "internal/buildcfg"
11         "internal/testenv"
12         "math"
13         "os"
14         "path/filepath"
15         "regexp"
16         "strings"
17         "testing"
18
19         "cmd/internal/obj"
20         "cmd/internal/objabi"
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 $128
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 // Test that nops are inserted when crossing 64B boundaries, and
166 // alignment is adjusted to avoid crossing.
167 func TestPfxAlign(t *testing.T) {
168         testenv.MustHaveGoBuild(t)
169
170         dir, err := os.MkdirTemp("", "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},     // No alignment or nop adjustments needed
182                 {[]byte(x16pgm), "align=0x20", false},   // Increased alignment needed
183                 {[]byte(x32pgm), "align=0x40", false},   // Worst case alignment needed
184                 {[]byte(x64pgm), "align=0x0", true},     // 0 aligned is default (16B) alignment
185                 {[]byte(x64pgmA64), "align=0x40", true}, // extra alignment + nop
186                 {[]byte(x64pgmA32), "align=0x20", true}, // extra alignment + nop
187         }
188
189         for _, pgm := range pgms {
190                 tmpfile := filepath.Join(dir, "x.s")
191                 err = os.WriteFile(tmpfile, pgm.text, 0644)
192                 if err != nil {
193                         t.Fatalf("can't write output: %v\n", err)
194                 }
195                 cmd := testenv.Command(t, 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("Fatal, misaligned text with prefixed instructions:\n%s", out)
203                 }
204                 hasNop := strings.Contains(string(out), "00 00 00 60")
205                 if hasNop != pgm.hasNop {
206                         t.Errorf("Fatal, prefixed instruction is missing nop padding:\n%s", out)
207                 }
208         }
209 }
210
211 // TestLarge generates a very large file to verify that large
212 // program builds successfully, and branches which exceed the
213 // range of BC are rewritten to reach.
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 := os.MkdirTemp("", "testlarge")
221         if err != nil {
222                 t.Fatalf("could not create directory: %v", err)
223         }
224         defer os.RemoveAll(dir)
225
226         // A few interesting test cases for long conditional branch fixups
227         tests := []struct {
228                 jmpinsn     string
229                 backpattern []string
230                 fwdpattern  []string
231         }{
232                 // Test the interesting cases of conditional branch rewrites for too-far targets. Simple conditional
233                 // branches can be made to reach with one JMP insertion, compound conditionals require two.
234                 //
235                 // beq <-> bne conversion (insert one jump)
236                 {"BEQ",
237                         []string{``,
238                                 `0x20030 131120\s\(.*\)\tBC\t\$4,\sCR0EQ,\s131128`,
239                                 `0x20034 131124\s\(.*\)\tJMP\t0`},
240                         []string{``,
241                                 `0x0000 00000\s\(.*\)\tBC\t\$4,\sCR0EQ,\s8`,
242                                 `0x0004 00004\s\(.*\)\tJMP\t131128`},
243                 },
244                 {"BNE",
245                         []string{``,
246                                 `0x20030 131120\s\(.*\)\tBC\t\$12,\sCR0EQ,\s131128`,
247                                 `0x20034 131124\s\(.*\)\tJMP\t0`},
248                         []string{``,
249                                 `0x0000 00000\s\(.*\)\tBC\t\$12,\sCR0EQ,\s8`,
250                                 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
251                 // bdnz (BC 16,0,tgt) <-> bdz (BC 18,0,+4) conversion (insert one jump)
252                 {"BC 16,0,",
253                         []string{``,
254                                 `0x20030 131120\s\(.*\)\tBC\t\$18,\sCR0LT,\s131128`,
255                                 `0x20034 131124\s\(.*\)\tJMP\t0`},
256                         []string{``,
257                                 `0x0000 00000\s\(.*\)\tBC\t\$18,\sCR0LT,\s8`,
258                                 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
259                 {"BC 18,0,",
260                         []string{``,
261                                 `0x20030 131120\s\(.*\)\tBC\t\$16,\sCR0LT,\s131128`,
262                                 `0x20034 131124\s\(.*\)\tJMP\t0`},
263                         []string{``,
264                                 `0x0000 00000\s\(.*\)\tBC\t\$16,\sCR0LT,\s8`,
265                                 `0x0004 00004\s\(.*\)\tJMP\t131128`}},
266                 // bdnzt (BC 8,0,tgt) <-> bdnzt (BC 8,0,+4) conversion (insert two jumps)
267                 {"BC 8,0,",
268                         []string{``,
269                                 `0x20034 131124\s\(.*\)\tBC\t\$8,\sCR0LT,\s131132`,
270                                 `0x20038 131128\s\(.*\)\tJMP\t131136`,
271                                 `0x2003c 131132\s\(.*\)\tJMP\t0\n`},
272                         []string{``,
273                                 `0x0000 00000\s\(.*\)\tBC\t\$8,\sCR0LT,\s8`,
274                                 `0x0004 00004\s\(.*\)\tJMP\t12`,
275                                 `0x0008 00008\s\(.*\)\tJMP\t131136\n`}},
276         }
277
278         for _, test := range tests {
279                 // generate a very large function
280                 buf := bytes.NewBuffer(make([]byte, 0, 7000000))
281                 gen(buf, test.jmpinsn)
282
283                 tmpfile := filepath.Join(dir, "x.s")
284                 err = os.WriteFile(tmpfile, buf.Bytes(), 0644)
285                 if err != nil {
286                         t.Fatalf("can't write output: %v\n", err)
287                 }
288
289                 // Test on all supported ppc64 platforms
290                 for _, platenv := range platformEnvs {
291                         cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
292                         cmd.Env = append(os.Environ(), platenv...)
293                         out, err := cmd.CombinedOutput()
294                         if err != nil {
295                                 t.Errorf("Assemble failed (%v): %v, output: %s", platenv, err, out)
296                         }
297                         matched, err := regexp.MatchString(strings.Join(test.fwdpattern, "\n\t*"), string(out))
298                         if err != nil {
299                                 t.Fatal(err)
300                         }
301                         if !matched {
302                                 t.Errorf("Failed to detect long forward BC fixup in (%v):%s\n", platenv, out)
303                         }
304                         matched, err = regexp.MatchString(strings.Join(test.backpattern, "\n\t*"), string(out))
305                         if err != nil {
306                                 t.Fatal(err)
307                         }
308                         if !matched {
309                                 t.Errorf("Failed to detect long backward BC fixup in (%v):%s\n", platenv, out)
310                         }
311                 }
312         }
313 }
314
315 // gen generates a very large program with a very long forward and backwards conditional branch.
316 func gen(buf *bytes.Buffer, jmpinsn string) {
317         fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
318         fmt.Fprintln(buf, "label_start:")
319         fmt.Fprintln(buf, jmpinsn, "label_end")
320         for i := 0; i < (1<<15 + 10); i++ {
321                 fmt.Fprintln(buf, "MOVD R0, R1")
322         }
323         fmt.Fprintln(buf, jmpinsn, "label_start")
324         fmt.Fprintln(buf, "label_end:")
325         fmt.Fprintln(buf, "MOVD R0, R1")
326         fmt.Fprintln(buf, "RET")
327 }
328
329 // TestPCalign generates two asm files containing the
330 // PCALIGN directive, to verify correct values are and
331 // accepted, and incorrect values are flagged in error.
332 func TestPCalign(t *testing.T) {
333         var pattern8 = `0x...8\s.*ADD\s..,\sR8`
334         var pattern16 = `0x...[80]\s.*MOVD\s..,\sR16`
335         var pattern32 = `0x...0\s.*ADD\s..,\sR3`
336
337         testenv.MustHaveGoBuild(t)
338
339         dir, err := os.MkdirTemp("", "testpcalign")
340         if err != nil {
341                 t.Fatalf("could not create directory: %v", err)
342         }
343         defer os.RemoveAll(dir)
344
345         // generate a test with valid uses of PCALIGN
346
347         tmpfile := filepath.Join(dir, "x.s")
348         err = os.WriteFile(tmpfile, []byte(validPCAlignSrc), 0644)
349         if err != nil {
350                 t.Fatalf("can't write output: %v\n", err)
351         }
352
353         // build generated file without errors and assemble it
354         cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile)
355         cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
356         out, err := cmd.CombinedOutput()
357         if err != nil {
358                 t.Errorf("Build failed: %v, output: %s", err, out)
359         }
360
361         matched, err := regexp.MatchString(pattern8, string(out))
362         if err != nil {
363                 t.Fatal(err)
364         }
365         if !matched {
366                 t.Errorf("The 8 byte alignment is not correct: %t, output:%s\n", matched, out)
367         }
368
369         matched, err = regexp.MatchString(pattern16, string(out))
370         if err != nil {
371                 t.Fatal(err)
372         }
373         if !matched {
374                 t.Errorf("The 16 byte alignment is not correct: %t, output:%s\n", matched, out)
375         }
376
377         matched, err = regexp.MatchString(pattern32, string(out))
378         if err != nil {
379                 t.Fatal(err)
380         }
381         if !matched {
382                 t.Errorf("The 32 byte alignment is not correct: %t, output:%s\n", matched, out)
383         }
384
385         // generate a test with invalid use of PCALIGN
386
387         tmpfile = filepath.Join(dir, "xi.s")
388         err = os.WriteFile(tmpfile, []byte(invalidPCAlignSrc), 0644)
389         if err != nil {
390                 t.Fatalf("can't write output: %v\n", err)
391         }
392
393         // build test with errors and check for messages
394         cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "xi.o"), "-S", tmpfile)
395         cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
396         out, err = cmd.CombinedOutput()
397         if !strings.Contains(string(out), "Unexpected alignment") {
398                 t.Errorf("Invalid alignment not detected for PCALIGN\n")
399         }
400 }
401
402 // Verify register constants are correctly aligned. Much of the ppc64 assembler assumes masking out significant
403 // bits will produce a valid register number:
404 // REG_Rx & 31 == x
405 // REG_Fx & 31 == x
406 // REG_Vx & 31 == x
407 // REG_VSx & 63 == x
408 // REG_SPRx & 1023 == x
409 // REG_CRx & 7 == x
410 //
411 // VR and FPR disjointly overlap VSR, interpreting as VSR registers should produce the correctly overlapped VSR.
412 // REG_FPx & 63 == x
413 // REG_Vx & 63 == x + 32
414 func TestRegValueAlignment(t *testing.T) {
415         tstFunc := func(rstart, rend, msk, rout int) {
416                 for i := rstart; i <= rend; i++ {
417                         if i&msk != rout {
418                                 t.Errorf("%v is not aligned to 0x%X (expected %d, got %d)\n", rconv(i), msk, rout, rstart&msk)
419                         }
420                         rout++
421                 }
422         }
423         var testType = []struct {
424                 rstart int
425                 rend   int
426                 msk    int
427                 rout   int
428         }{
429                 {REG_VS0, REG_VS63, 63, 0},
430                 {REG_R0, REG_R31, 31, 0},
431                 {REG_F0, REG_F31, 31, 0},
432                 {REG_V0, REG_V31, 31, 0},
433                 {REG_V0, REG_V31, 63, 32},
434                 {REG_F0, REG_F31, 63, 0},
435                 {REG_SPR0, REG_SPR0 + 1023, 1023, 0},
436                 {REG_CR0, REG_CR7, 7, 0},
437                 {REG_CR0LT, REG_CR7SO, 31, 0},
438         }
439         for _, t := range testType {
440                 tstFunc(t.rstart, t.rend, t.msk, t.rout)
441         }
442 }
443
444 // Verify interesting obj.Addr arguments are classified correctly.
445 func TestAddrClassifier(t *testing.T) {
446         type cmplx struct {
447                 pic     int
448                 pic_dyn int
449                 dyn     int
450                 nonpic  int
451         }
452         tsts := [...]struct {
453                 arg    obj.Addr
454                 output interface{}
455         }{
456                 // Supported register type args
457                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R1}, C_REG},
458                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R2}, C_REGP},
459                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F1}, C_FREG},
460                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F2}, C_FREGP},
461                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_V2}, C_VREG},
462                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS1}, C_VSREG},
463                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS2}, C_VSREGP},
464                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR}, C_CREG},
465                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1}, C_CREG},
466                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1SO}, C_CRBIT},
467                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0}, C_SPR},
468                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 1}, C_XER},
469                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 8}, C_LR},
470                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR},
471                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR},
472                 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_A1}, C_AREG},
473
474                 // Memory type arguments.
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}, // 33 is FixedFrameSize-1
485                 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG},
486                 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Index: REG_R4}, C_XOREG},
487                 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: 1}, C_SOREG},
488                 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: BIG}, C_LOREG},
489                 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: -BIG - 33}, C_LOREG},
490
491                 // Misc (golang initializes -0.0 to 0.0, hence the obfuscation below)
492                 {obj.Addr{Type: obj.TYPE_TEXTSIZE}, C_TEXTSIZE},
493                 {obj.Addr{Type: obj.TYPE_FCONST, Val: 0.0}, C_ZCON},
494                 {obj.Addr{Type: obj.TYPE_FCONST, Val: math.Float64frombits(0x8000000000000000)}, C_S16CON},
495
496                 // Address type arguments
497                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1}, C_SACON},
498                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: BIG}, C_LACON},
499                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: -BIG - 1}, C_LACON},
500                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1 << 32}, C_DACON},
501                 {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
502                 {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_STATIC, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
503                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: 1}, C_SACON},
504                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: BIG}, C_LACON},
505                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LACON},
506                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: 1}, C_SACON},
507                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: BIG}, C_LACON},
508                 {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LACON}, // 33 is FixedFrameSize-1
509
510                 // Constant type arguments
511                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 0}, C_ZCON},
512                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1}, C_U1CON},
513                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 2}, C_U2CON},
514                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 4}, C_U3CON},
515                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 8}, C_U4CON},
516                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 16}, C_U5CON},
517                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 32}, C_U8CON},
518                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 14}, C_U15CON},
519                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 15}, C_U16CON},
520                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 16}, C_U3216CON},
521                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 + 1<<16}, C_U32CON},
522                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 32}, C_S34CON},
523                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 33}, C_64CON},
524                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -1}, C_S16CON},
525                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10000}, C_S3216CON},
526                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10001}, C_S32CON},
527                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON},
528                 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON},
529
530                 // Branch like arguments
531                 {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}},
532                 {obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA},
533         }
534
535         pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0}
536         pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
537         dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
538         nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0}
539         ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9}
540         name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"}
541         for _, tst := range tsts {
542                 var expect []int
543                 switch tst.output.(type) {
544                 case cmplx:
545                         v := tst.output.(cmplx)
546                         expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic}
547                 case int:
548                         expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)}
549                 }
550                 for i := range ctxts {
551                         if output := ctxts[i].aclass(&tst.arg); output != expect[i] {
552                                 t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i]))
553                         }
554                 }
555         }
556 }
557
558 // The optab size should remain constant when reinitializing the PPC64 assembler backend.
559 func TestOptabReinit(t *testing.T) {
560         buildcfg.GOOS = "linux"
561         buildcfg.GOARCH = "ppc64le"
562         buildcfg.GOPPC64 = 8
563         buildop(nil)
564         optabLen := len(optab)
565         buildcfg.GOPPC64 = 9
566         buildop(nil)
567         reinitOptabLen := len(optab)
568         if reinitOptabLen != optabLen {
569                 t.Errorf("rerunning buildop changes optab size from %d to %d", optabLen, reinitOptabLen)
570         }
571 }