summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/obj/ppc64/asm_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/obj/ppc64/asm_test.go')
-rw-r--r--src/cmd/internal/obj/ppc64/asm_test.go555
1 files changed, 555 insertions, 0 deletions
diff --git a/src/cmd/internal/obj/ppc64/asm_test.go b/src/cmd/internal/obj/ppc64/asm_test.go
new file mode 100644
index 0000000..1de6e76
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/asm_test.go
@@ -0,0 +1,555 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64
+
+import (
+ "bytes"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "math"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+var platformEnvs = [][]string{
+ {"GOOS=aix", "GOARCH=ppc64"},
+ {"GOOS=linux", "GOARCH=ppc64"},
+ {"GOOS=linux", "GOARCH=ppc64le"},
+}
+
+const invalidPCAlignSrc = `
+TEXT test(SB),0,$0-0
+ADD $2, R3
+PCALIGN $64
+RET
+`
+
+const validPCAlignSrc = `
+TEXT test(SB),0,$0-0
+ADD $2, R3
+PCALIGN $16
+MOVD $8, R16
+ADD $8, R4
+PCALIGN $32
+ADD $8, R3
+PCALIGN $8
+ADD $4, R8
+RET
+`
+
+const x64pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+const x32pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+
+const x16pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+
+const x0pgm = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+`
+const x64pgmA64 = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+
+const x64pgmA32 = `
+TEXT test(SB),0,$0-0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+OR R0, R0
+PNOP
+`
+
+// Test that nops are inserted when crossing 64B boundaries, and
+// alignment is adjusted to avoid crossing.
+func TestPfxAlign(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "testpfxalign")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ pgms := []struct {
+ text []byte
+ align string
+ hasNop bool
+ }{
+ {[]byte(x0pgm), "align=0x0", false}, // No alignment or nop adjustments needed
+ {[]byte(x16pgm), "align=0x20", false}, // Increased alignment needed
+ {[]byte(x32pgm), "align=0x40", false}, // Worst case alignment needed
+ {[]byte(x64pgm), "align=0x0", true}, // 0 aligned is default (16B) alignment
+ {[]byte(x64pgmA64), "align=0x40", true}, // extra alignment + nop
+ {[]byte(x64pgmA32), "align=0x20", true}, // extra alignment + nop
+ }
+
+ for _, pgm := range pgms {
+ tmpfile := filepath.Join(dir, "x.s")
+ err = ioutil.WriteFile(tmpfile, pgm.text, 0644)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
+ cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=ppc64le")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("Failed to compile %v: %v\n", pgm, err)
+ }
+ if !strings.Contains(string(out), pgm.align) {
+ t.Errorf(fmt.Sprintf("Fatal, misaligned text with prefixed instructions:\n%s\n", string(out)))
+ }
+ hasNop := strings.Contains(string(out), "00 00 00 60")
+ if hasNop != pgm.hasNop {
+ t.Errorf(fmt.Sprintf("Fatal, prefixed instruction is missing nop padding:\n%s\n", string(out)))
+ }
+ }
+}
+
+// TestLarge generates a very large file to verify that large
+// program builds successfully, and branches which exceed the
+// range of BC are rewritten to reach.
+func TestLarge(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skip in short mode")
+ }
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "testlarge")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // A few interesting test cases for long conditional branch fixups
+ tests := []struct {
+ jmpinsn string
+ backpattern []string
+ fwdpattern []string
+ }{
+ // Test the interesting cases of conditional branch rewrites for too-far targets. Simple conditional
+ // branches can be made to reach with one JMP insertion, compound conditionals require two.
+ //
+ // TODO: BI is interpreted as a register (the R???x/R0 should be $x)
+ // beq <-> bne conversion (insert one jump)
+ {"BEQ",
+ []string{``,
+ `0x20030 131120\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s131128`,
+ `0x20034 131124\s\(.*\)\tJMP\t0`},
+ []string{``,
+ `0x0000 00000\s\(.*\)\tBC\t\$4,\sR\?\?\?2,\s8`,
+ `0x0004 00004\s\(.*\)\tJMP\t131128`},
+ },
+ {"BNE",
+ []string{``,
+ `0x20030 131120\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s131128`,
+ `0x20034 131124\s\(.*\)\tJMP\t0`},
+ []string{``,
+ `0x0000 00000\s\(.*\)\tBC\t\$12,\sR\?\?\?2,\s8`,
+ `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+ // bdnz (BC 16,0,tgt) <-> bdz (BC 18,0,+4) conversion (insert one jump)
+ {"BC 16,0,",
+ []string{``,
+ `0x20030 131120\s\(.*\)\tBC\t\$18,\s131128`,
+ `0x20034 131124\s\(.*\)\tJMP\t0`},
+ []string{``,
+ `0x0000 00000\s\(.*\)\tBC\t\$18,\s8`,
+ `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+ {"BC 18,0,",
+ []string{``,
+ `0x20030 131120\s\(.*\)\tBC\t\$16,\s131128`,
+ `0x20034 131124\s\(.*\)\tJMP\t0`},
+ []string{``,
+ `0x0000 00000\s\(.*\)\tBC\t\$16,\s8`,
+ `0x0004 00004\s\(.*\)\tJMP\t131128`}},
+ // bdnzt (BC 8,0,tgt) <-> bdnzt (BC 8,0,+4) conversion (insert two jumps)
+ {"BC 8,0,",
+ []string{``,
+ `0x20034 131124\s\(.*\)\tBC\t\$8,\sR0,\s131132`,
+ `0x20038 131128\s\(.*\)\tJMP\t131136`,
+ `0x2003c 131132\s\(.*\)\tJMP\t0\n`},
+ []string{``,
+ `0x0000 00000\s\(.*\)\tBC\t\$8,\sR0,\s8`,
+ `0x0004 00004\s\(.*\)\tJMP\t12`,
+ `0x0008 00008\s\(.*\)\tJMP\t131136\n`}},
+ }
+
+ for _, test := range tests {
+ // generate a very large function
+ buf := bytes.NewBuffer(make([]byte, 0, 7000000))
+ gen(buf, test.jmpinsn)
+
+ tmpfile := filepath.Join(dir, "x.s")
+ err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+
+ // Test on all supported ppc64 platforms
+ for _, platenv := range platformEnvs {
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
+ cmd.Env = append(os.Environ(), platenv...)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("Assemble failed (%v): %v, output: %s", platenv, err, out)
+ }
+ matched, err := regexp.MatchString(strings.Join(test.fwdpattern, "\n\t*"), string(out))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !matched {
+ t.Errorf("Failed to detect long forward BC fixup in (%v):%s\n", platenv, out)
+ }
+ matched, err = regexp.MatchString(strings.Join(test.backpattern, "\n\t*"), string(out))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !matched {
+ t.Errorf("Failed to detect long backward BC fixup in (%v):%s\n", platenv, out)
+ }
+ }
+ }
+}
+
+// gen generates a very large program with a very long forward and backwards conditional branch.
+func gen(buf *bytes.Buffer, jmpinsn string) {
+ fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
+ fmt.Fprintln(buf, "label_start:")
+ fmt.Fprintln(buf, jmpinsn, "label_end")
+ for i := 0; i < (1<<15 + 10); i++ {
+ fmt.Fprintln(buf, "MOVD R0, R1")
+ }
+ fmt.Fprintln(buf, jmpinsn, "label_start")
+ fmt.Fprintln(buf, "label_end:")
+ fmt.Fprintln(buf, "MOVD R0, R1")
+ fmt.Fprintln(buf, "RET")
+}
+
+// TestPCalign generates two asm files containing the
+// PCALIGN directive, to verify correct values are and
+// accepted, and incorrect values are flagged in error.
+func TestPCalign(t *testing.T) {
+ var pattern8 = `0x...8\s.*ADD\s..,\sR8`
+ var pattern16 = `0x...[80]\s.*MOVD\s..,\sR16`
+ var pattern32 = `0x...0\s.*ADD\s..,\sR3`
+
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "testpcalign")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // generate a test with valid uses of PCALIGN
+
+ tmpfile := filepath.Join(dir, "x.s")
+ err = ioutil.WriteFile(tmpfile, []byte(validPCAlignSrc), 0644)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+
+ // build generated file without errors and assemble it
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), "-S", tmpfile)
+ cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("Build failed: %v, output: %s", err, out)
+ }
+
+ matched, err := regexp.MatchString(pattern8, string(out))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !matched {
+ t.Errorf("The 8 byte alignment is not correct: %t, output:%s\n", matched, out)
+ }
+
+ matched, err = regexp.MatchString(pattern16, string(out))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !matched {
+ t.Errorf("The 16 byte alignment is not correct: %t, output:%s\n", matched, out)
+ }
+
+ matched, err = regexp.MatchString(pattern32, string(out))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !matched {
+ t.Errorf("The 32 byte alignment is not correct: %t, output:%s\n", matched, out)
+ }
+
+ // generate a test with invalid use of PCALIGN
+
+ tmpfile = filepath.Join(dir, "xi.s")
+ err = ioutil.WriteFile(tmpfile, []byte(invalidPCAlignSrc), 0644)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+
+ // build test with errors and check for messages
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "xi.o"), "-S", tmpfile)
+ cmd.Env = append(os.Environ(), "GOARCH=ppc64le", "GOOS=linux")
+ out, err = cmd.CombinedOutput()
+ if !strings.Contains(string(out), "Unexpected alignment") {
+ t.Errorf("Invalid alignment not detected for PCALIGN\n")
+ }
+}
+
+// Verify register constants are correctly aligned. Much of the ppc64 assembler assumes masking out significant
+// bits will produce a valid register number:
+// REG_Rx & 31 == x
+// REG_Fx & 31 == x
+// REG_Vx & 31 == x
+// REG_VSx & 63 == x
+// REG_SPRx & 1023 == x
+// REG_CRx & 7 == x
+//
+// VR and FPR disjointly overlap VSR, interpreting as VSR registers should produce the correctly overlapped VSR.
+// REG_FPx & 63 == x
+// REG_Vx & 63 == x + 32
+func TestRegValueAlignment(t *testing.T) {
+ tstFunc := func(rstart, rend, msk, rout int) {
+ for i := rstart; i <= rend; i++ {
+ if i&msk != rout {
+ t.Errorf("%v is not aligned to 0x%X (expected %d, got %d)\n", rconv(i), msk, rout, rstart&msk)
+ }
+ rout++
+ }
+ }
+ var testType = []struct {
+ rstart int
+ rend int
+ msk int
+ rout int
+ }{
+ {REG_VS0, REG_VS63, 63, 0},
+ {REG_R0, REG_R31, 31, 0},
+ {REG_F0, REG_F31, 31, 0},
+ {REG_V0, REG_V31, 31, 0},
+ {REG_V0, REG_V31, 63, 32},
+ {REG_F0, REG_F31, 63, 0},
+ {REG_SPR0, REG_SPR0 + 1023, 1023, 0},
+ {REG_CR0, REG_CR7, 7, 0},
+ {REG_CR0LT, REG_CR7SO, 31, 0},
+ }
+ for _, t := range testType {
+ tstFunc(t.rstart, t.rend, t.msk, t.rout)
+ }
+}
+
+// Verify interesting obj.Addr arguments are classified correctly.
+func TestAddrClassifier(t *testing.T) {
+ type cmplx struct {
+ pic int
+ pic_dyn int
+ dyn int
+ nonpic int
+ }
+ tsts := [...]struct {
+ arg obj.Addr
+ output interface{}
+ }{
+ // Supported register type args
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R1}, C_REG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_R2}, C_REGP},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F1}, C_FREG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_F2}, C_FREGP},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_V2}, C_VREG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS1}, C_VSREG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_VS2}, C_VSREGP},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR}, C_CREG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1}, C_CREG},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_CR1SO}, C_CRBIT},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0}, C_SPR},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 1}, C_XER},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 8}, C_LR},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_SPR0 + 9}, C_CTR},
+ {obj.Addr{Type: obj.TYPE_REG, Reg: REG_FPSCR}, C_FPSCR},
+
+ // Memory type arguments.
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_GOTREF}, C_ADDR},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_TOCREF}, C_ADDR},
+ {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}},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_ADDR},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO}, C_SOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: BIG}, C_LOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM}, C_SOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: BIG}, C_LOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LOREG}, // 33 is FixedFrameSize-1
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE}, C_ZOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: 1}, C_SOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: BIG}, C_LOREG},
+ {obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_NONE, Offset: -BIG - 33}, C_LOREG},
+
+ // Misc (golang initializes -0.0 to 0.0, hence the obfuscation below)
+ {obj.Addr{Type: obj.TYPE_TEXTSIZE}, C_TEXTSIZE},
+ {obj.Addr{Type: obj.TYPE_FCONST, Val: 0.0}, C_ZCON},
+ {obj.Addr{Type: obj.TYPE_FCONST, Val: math.Float64frombits(0x8000000000000000)}, C_S16CON},
+
+ // Address type arguments
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1}, C_SACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: BIG}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: -BIG - 1}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_NONE, Offset: 1 << 32}, C_DACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_STATIC, Sym: &obj.LSym{Type: objabi.SDATA}}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: 1}, C_SACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: BIG}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_AUTO, Offset: -BIG - 1}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: 1}, C_SACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: BIG}, C_LACON},
+ {obj.Addr{Type: obj.TYPE_ADDR, Reg: REG_R0, Name: obj.NAME_PARAM, Offset: -BIG - 33}, C_LACON}, // 33 is FixedFrameSize-1
+
+ // Constant type arguments
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 0}, C_ZCON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1}, C_U1CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 2}, C_U2CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 4}, C_U3CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 8}, C_U4CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 16}, C_U5CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 32}, C_U8CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 14}, C_U15CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 15}, C_U16CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 16}, C_U3216CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 + 1<<16}, C_U32CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 32}, C_S34CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: 1 << 33}, C_64CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -1}, C_S16CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10000}, C_S3216CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -0x10001}, C_S32CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 33)}, C_S34CON},
+ {obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: -(1 << 34)}, C_64CON},
+
+ // Branch like arguments
+ {obj.Addr{Type: obj.TYPE_BRANCH, Sym: &obj.LSym{Type: objabi.SDATA}}, cmplx{C_SBRA, C_LBRAPIC, C_LBRAPIC, C_SBRA}},
+ {obj.Addr{Type: obj.TYPE_BRANCH}, C_SBRA},
+ }
+
+ pic_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Arch: &Linkppc64}, autosize: 0}
+ pic_dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_shared: true, Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
+ dyn_ctxt9 := ctxt9{ctxt: &obj.Link{Flag_dynlink: true, Arch: &Linkppc64}, autosize: 0}
+ nonpic_ctxt9 := ctxt9{ctxt: &obj.Link{Arch: &Linkppc64}, autosize: 0}
+ ctxts := [...]*ctxt9{&pic_ctxt9, &pic_dyn_ctxt9, &dyn_ctxt9, &nonpic_ctxt9}
+ name := [...]string{"pic", "pic_dyn", "dyn", "nonpic"}
+ for _, tst := range tsts {
+ var expect []int
+ switch tst.output.(type) {
+ case cmplx:
+ v := tst.output.(cmplx)
+ expect = []int{v.pic, v.pic_dyn, v.dyn, v.nonpic}
+ case int:
+ expect = []int{tst.output.(int), tst.output.(int), tst.output.(int), tst.output.(int)}
+ }
+ for i, _ := range ctxts {
+ if output := ctxts[i].aclass(&tst.arg); output != expect[i] {
+ t.Errorf("%s.aclass(%v) = %v, expected %v\n", name[i], tst.arg, DRconv(output), DRconv(expect[i]))
+ }
+ }
+ }
+}