github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/obj/ppc64/asm_test.go (about) 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 "math" 11 "os" 12 "path/filepath" 13 "regexp" 14 "strings" 15 "testing" 16 17 "github.com/go-asm/go/buildcfg" 18 "github.com/go-asm/go/testenv" 19 20 "github.com/go-asm/go/cmd/obj" 21 "github.com/go-asm/go/cmd/objabi" 22 ) 23 24 var platformEnvs = [][]string{ 25 {"GOOS=aix", "GOARCH=ppc64"}, 26 {"GOOS=linux", "GOARCH=ppc64"}, 27 {"GOOS=linux", "GOARCH=ppc64le"}, 28 } 29 30 const invalidPCAlignSrc = ` 31 TEXT test(SB),0,$0-0 32 ADD $2, R3 33 PCALIGN $128 34 RET 35 ` 36 37 const validPCAlignSrc = ` 38 TEXT test(SB),0,$0-0 39 ADD $2, R3 40 PCALIGN $16 41 MOVD $8, R16 42 ADD $8, R4 43 PCALIGN $32 44 ADD $8, R3 45 PCALIGN $8 46 ADD $4, R8 47 RET 48 ` 49 50 const x64pgm = ` 51 TEXT test(SB),0,$0-0 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 OR R0, R0 67 PNOP 68 ` 69 const x32pgm = ` 70 TEXT test(SB),0,$0-0 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 OR R0, R0 78 PNOP 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 OR R0, R0 87 ` 88 89 const x16pgm = ` 90 TEXT test(SB),0,$0-0 91 OR R0, R0 92 OR R0, R0 93 OR R0, R0 94 PNOP 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 OR R0, R0 107 ` 108 109 const x0pgm = ` 110 TEXT test(SB),0,$0-0 111 OR R0, R0 112 OR R0, R0 113 OR R0, R0 114 OR R0, R0 115 PNOP 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 OR R0, R0 127 ` 128 const x64pgmA64 = ` 129 TEXT test(SB),0,$0-0 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 OR R0, R0 137 PNOP 138 OR R0, R0 139 OR R0, R0 140 OR R0, R0 141 OR R0, R0 142 OR R0, R0 143 OR R0, R0 144 PNOP 145 ` 146 147 const x64pgmA32 = ` 148 TEXT test(SB),0,$0-0 149 OR R0, R0 150 OR R0, R0 151 OR R0, R0 152 PNOP 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 OR R0, R0 163 PNOP 164 ` 165 166 // Test that nops are inserted when crossing 64B boundaries, and 167 // alignment is adjusted to avoid crossing. 168 func TestPfxAlign(t *testing.T) { 169 testenv.MustHaveGoBuild(t) 170 171 dir, err := os.MkdirTemp("", "testpfxalign") 172 if err != nil { 173 t.Fatalf("could not create directory: %v", err) 174 } 175 defer os.RemoveAll(dir) 176 177 pgms := []struct { 178 text []byte 179 align string 180 hasNop bool 181 }{ 182 {[]byte(x0pgm), "align=0x0", false}, // No alignment or nop adjustments needed 183 {[]byte(x16pgm), "align=0x20", false}, // Increased alignment needed 184 {[]byte(x32pgm), "align=0x40", false}, // Worst case alignment needed 185 {[]byte(x64pgm), "align=0x0", true}, // 0 aligned is default (16B) alignment 186 {[]byte(x64pgmA64), "align=0x40", true}, // extra alignment + nop 187 {[]byte(x64pgmA32), "align=0x20", true}, // extra alignment + nop 188 } 189 190 for _, pgm := range pgms { 191 tmpfile := filepath.Join(dir, "x.s") 192 err = os.WriteFile(tmpfile, pgm.text, 0644) 193 if err != nil { 194 t.Fatalf("can't write output: %v\n", err) 195 } 196 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile) 197 cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=ppc64le") 198 out, err := cmd.CombinedOutput() 199 if err != nil { 200 t.Errorf("Failed to compile %v: %v\n", pgm, err) 201 } 202 if !strings.Contains(string(out), pgm.align) { 203 t.Errorf("Fatal, misaligned text with prefixed instructions:\n%s", out) 204 } 205 hasNop := strings.Contains(string(out), "00 00 00 60") 206 if hasNop != pgm.hasNop { 207 t.Errorf("Fatal, prefixed instruction is missing nop padding:\n%s", out) 208 } 209 } 210 } 211 212 // TestLarge generates a very large file to verify that large 213 // program builds successfully, and branches which exceed the 214 // range of BC are rewritten to reach. 215 func TestLarge(t *testing.T) { 216 if testing.Short() { 217 t.Skip("Skip in short mode") 218 } 219 testenv.MustHaveGoBuild(t) 220 221 dir, err := os.MkdirTemp("", "testlarge") 222 if err != nil { 223 t.Fatalf("could not create directory: %v", err) 224 } 225 defer os.RemoveAll(dir) 226 227 // A few interesting test cases for long conditional branch fixups 228 tests := []struct { 229 jmpinsn string 230 backpattern []string 231 fwdpattern []string 232 }{ 233 // Test the interesting cases of conditional branch rewrites for too-far targets. Simple conditional 234 // branches can be made to reach with one JMP insertion, compound conditionals require two. 235 // 236 // beq <-> bne conversion (insert one jump) 237 {"BEQ", 238 []string{``, 239 `0x20030 131120\s\(.*\)\tBC\t\$4,\sCR0EQ,\s131128`, 240 `0x20034 131124\s\(.*\)\tJMP\t0`}, 241 []string{``, 242 `0x0000 00000\s\(.*\)\tBC\t\$4,\sCR0EQ,\s8`, 243 `0x0004 00004\s\(.*\)\tJMP\t131128`}, 244 }, 245 {"BNE", 246 []string{``, 247 `0x20030 131120\s\(.*\)\tBC\t\$12,\sCR0EQ,\s131128`, 248 `0x20034 131124\s\(.*\)\tJMP\t0`}, 249 []string{``, 250 `0x0000 00000\s\(.*\)\tBC\t\$12,\sCR0EQ,\s8`, 251 `0x0004 00004\s\(.*\)\tJMP\t131128`}}, 252 // bdnz (BC 16,0,tgt) <-> bdz (BC 18,0,+4) conversion (insert one jump) 253 {"BC 16,0,", 254 []string{``, 255 `0x20030 131120\s\(.*\)\tBC\t\$18,\sCR0LT,\s131128`, 256 `0x20034 131124\s\(.*\)\tJMP\t0`}, 257 []string{``, 258 `0x0000 00000\s\(.*\)\tBC\t\$18,\sCR0LT,\s8`, 259 `0x0004 00004\s\(.*\)\tJMP\t131128`}}, 260 {"BC 18,0,", 261 []string{``, 262 `0x20030 131120\s\(.*\)\tBC\t\$16,\sCR0LT,\s131128`, 263 `0x20034 131124\s\(.*\)\tJMP\t0`}, 264 []string{``, 265 `0x0000 00000\s\(.*\)\tBC\t\$16,\sCR0LT,\s8`, 266 `0x0004 00004\s\(.*\)\tJMP\t131128`}}, 267 // bdnzt (BC 8,0,tgt) <-> bdnzt (BC 8,0,+4) conversion (insert two jumps) 268 {"BC 8,0,", 269 []string{``, 270 `0x20034 131124\s\(.*\)\tBC\t\$8,\sCR0LT,\s131132`, 271 `0x20038 131128\s\(.*\)\tJMP\t131136`, 272 `0x2003c 131132\s\(.*\)\tJMP\t0\n`}, 273 []string{``, 274 `0x0000 00000\s\(.*\)\tBC\t\$8,\sCR0LT,\s8`, 275 `0x0004 00004\s\(.*\)\tJMP\t12`, 276 `0x0008 00008\s\(.*\)\tJMP\t131136\n`}}, 277 } 278 279 for _, test := range tests { 280 // generate a very large function 281 buf := bytes.NewBuffer(make([]byte, 0, 7000000)) 282 gen(buf, test.jmpinsn) 283 284 tmpfile := filepath.Join(dir, "x.s") 285 err = os.WriteFile(tmpfile, buf.Bytes(), 0644) 286 if err != nil { 287 t.Fatalf("can't write output: %v\n", err) 288 } 289 290 // Test on all supported ppc64 platforms 291 for _, platenv := range platformEnvs { 292 cmd := testenv.Command(t, 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 // gen generates a very large program with a very long forward and backwards conditional branch. 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 // TestPCalign generates two asm files containing the 331 // PCALIGN directive, to verify correct values are and 332 // accepted, and incorrect values are flagged in error. 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 := os.MkdirTemp("", "testpcalign") 341 if err != nil { 342 t.Fatalf("could not create directory: %v", err) 343 } 344 defer os.RemoveAll(dir) 345 346 // generate a test with valid uses of PCALIGN 347 348 tmpfile := filepath.Join(dir, "x.s") 349 err = os.WriteFile(tmpfile, []byte(validPCAlignSrc), 0644) 350 if err != nil { 351 t.Fatalf("can't write output: %v\n", err) 352 } 353 354 // build generated file without errors and assemble it 355 cmd := testenv.Command(t, 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 // generate a test with invalid use of PCALIGN 387 388 tmpfile = filepath.Join(dir, "xi.s") 389 err = os.WriteFile(tmpfile, []byte(invalidPCAlignSrc), 0644) 390 if err != nil { 391 t.Fatalf("can't write output: %v\n", err) 392 } 393 394 // build test with errors and check for messages 395 cmd = testenv.Command(t, 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 // Verify register constants are correctly aligned. Much of the ppc64 assembler assumes masking out significant 404 // bits will produce a valid register number: 405 // REG_Rx & 31 == x 406 // REG_Fx & 31 == x 407 // REG_Vx & 31 == x 408 // REG_VSx & 63 == x 409 // REG_SPRx & 1023 == x 410 // REG_CRx & 7 == x 411 // 412 // VR and FPR disjointly overlap VSR, interpreting as VSR registers should produce the correctly overlapped VSR. 413 // REG_FPx & 63 == x 414 // REG_Vx & 63 == x + 32 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 // Verify interesting obj.Addr arguments are classified correctly. 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 // Supported register type args 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 + 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 + 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: -0x10001}, C_S32CON}, 525 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON}, 526 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON}, 527 528 // Branch like arguments 529 {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}}, 530 {obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA}, 531 } 532 533 pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0} 534 pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0} 535 dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0} 536 nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0} 537 ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9} 538 name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"} 539 for _, tst := range tsts { 540 var expect []int 541 switch tst.output.(type) { 542 case cmplx: 543 v := tst.output.(cmplx) 544 expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic} 545 case int: 546 expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)} 547 } 548 for i := range ctxts { 549 if output := ctxts[i].aclass(&tst.arg); output != expect[i] { 550 t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i])) 551 } 552 } 553 } 554 } 555 556 // The optab size should remain constant when reinitializing the PPC64 assembler backend. 557 func TestOptabReinit(t *testing.T) { 558 buildcfg.GOOS = "linux" 559 buildcfg.GOARCH = "ppc64le" 560 buildcfg.GOPPC64 = 8 561 buildop(nil) 562 optabLen := len(optab) 563 buildcfg.GOPPC64 = 9 564 buildop(nil) 565 reinitOptabLen := len(optab) 566 if reinitOptabLen != optabLen { 567 t.Errorf("rerunning buildop changes optab size from %d to %d", optabLen, reinitOptabLen) 568 } 569 }