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 5package ppc64 6 7import ( 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 23var platformEnvs = [][]string{ 24 {"GOOS=aix", "GOARCH=ppc64"}, 25 {"GOOS=linux", "GOARCH=ppc64"}, 26 {"GOOS=linux", "GOARCH=ppc64le"}, 27} 28 29const invalidPCAlignSrc = ` 30TEXT test(SB),0,$0-0 31ADD $2, R3 32PCALIGN $128 33RET 34` 35 36const validPCAlignSrc = ` 37TEXT test(SB),0,$0-0 38ADD $2, R3 39PCALIGN $16 40MOVD $8, R16 41ADD $8, R4 42PCALIGN $32 43ADD $8, R3 44PCALIGN $8 45ADD $4, R8 46RET 47` 48 49const x64pgm = ` 50TEXT test(SB),0,$0-0 51OR R0, R0 52OR R0, R0 53OR R0, R0 54OR R0, R0 55OR R0, R0 56OR R0, R0 57OR R0, R0 58OR R0, R0 59OR R0, R0 60OR R0, R0 61OR R0, R0 62OR R0, R0 63OR R0, R0 64OR R0, R0 65OR R0, R0 66PNOP 67` 68const x32pgm = ` 69TEXT test(SB),0,$0-0 70OR R0, R0 71OR R0, R0 72OR R0, R0 73OR R0, R0 74OR R0, R0 75OR R0, R0 76OR R0, R0 77PNOP 78OR R0, R0 79OR R0, R0 80OR R0, R0 81OR R0, R0 82OR R0, R0 83OR R0, R0 84OR R0, R0 85OR R0, R0 86` 87 88const x16pgm = ` 89TEXT test(SB),0,$0-0 90OR R0, R0 91OR R0, R0 92OR R0, R0 93PNOP 94OR R0, R0 95OR R0, R0 96OR R0, R0 97OR R0, R0 98OR R0, R0 99OR R0, R0 100OR R0, R0 101OR R0, R0 102OR R0, R0 103OR R0, R0 104OR R0, R0 105OR R0, R0 106` 107 108const x0pgm = ` 109TEXT test(SB),0,$0-0 110OR R0, R0 111OR R0, R0 112OR R0, R0 113OR R0, R0 114PNOP 115OR R0, R0 116OR R0, R0 117OR R0, R0 118OR R0, R0 119OR R0, R0 120OR R0, R0 121OR R0, R0 122OR R0, R0 123OR R0, R0 124OR R0, R0 125OR R0, R0 126` 127const x64pgmA64 = ` 128TEXT test(SB),0,$0-0 129OR R0, R0 130OR R0, R0 131OR R0, R0 132OR R0, R0 133OR R0, R0 134OR R0, R0 135OR R0, R0 136PNOP 137OR R0, R0 138OR R0, R0 139OR R0, R0 140OR R0, R0 141OR R0, R0 142OR R0, R0 143PNOP 144` 145 146const x64pgmA32 = ` 147TEXT test(SB),0,$0-0 148OR R0, R0 149OR R0, R0 150OR R0, R0 151PNOP 152OR R0, R0 153OR R0, R0 154OR R0, R0 155OR R0, R0 156OR R0, R0 157OR R0, R0 158OR R0, R0 159OR R0, R0 160OR R0, R0 161OR R0, R0 162PNOP 163` 164 165// Test that nops are inserted when crossing 64B boundaries, and 166// alignment is adjusted to avoid crossing. 167func 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. 214func 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. 316func 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. 332func 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 414func 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. 445func 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 + 8}, C_LR}, 469 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR}, 470 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR}, 471 {obj.Addr{Type: obj.TYPE_REG, Reg: REG_A1}, C_AREG}, 472 473 // Memory type arguments. 474 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_GOTREF}, C_ADDR}, 475 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_TOCREF}, C_ADDR}, 476 {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}}, 477 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_ADDR}, 478 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO}, C_SOREG}, 479 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: BIG}, C_LOREG}, 480 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LOREG}, 481 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM}, C_SOREG}, 482 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: BIG}, C_LOREG}, 483 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LOREG}, // 33 is FixedFrameSize-1 484 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG}, 485 {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Index: REG_R4}, C_XOREG}, 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 // Misc (golang initializes -0.0 to 0.0, hence the obfuscation below) 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 // Address type arguments 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}, // 33 is FixedFrameSize-1 508 509 // Constant type arguments 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 + 1<<16}, C_U31CON}, 520 {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 31}, 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: 0x10001}, C_U31CON}, 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 // Branch like arguments 530 {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_BRA, C_BRAPIC, C_BRAPIC, C_BRA}}, 531 {obj.Addr{Type: obj.TYPE_BRANCH}, C_BRA}, 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 557// The optab size should remain constant when reinitializing the PPC64 assembler backend. 558func TestOptabReinit(t *testing.T) { 559 buildcfg.GOOS = "linux" 560 buildcfg.GOARCH = "ppc64le" 561 buildcfg.GOPPC64 = 8 562 buildop(nil) 563 optabLen := len(optab) 564 buildcfg.GOPPC64 = 9 565 buildop(nil) 566 reinitOptabLen := len(optab) 567 if reinitOptabLen != optabLen { 568 t.Errorf("rerunning buildop changes optab size from %d to %d", optabLen, reinitOptabLen) 569 } 570} 571