Source file 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  	"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  // 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 := 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},     // 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 = 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  // 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 := ioutil.TempDir("", "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  		// TODO: BI is interpreted as a register (the R???x/R0 should be $x)
   236  		// beq <-> bne conversion (insert one jump)
   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  		// 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,\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  		// 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,\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  		// 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 = ioutil.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 := 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  // 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 := ioutil.TempDir("", "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 = ioutil.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 := 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  	// generate a test with invalid use of PCALIGN
   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  	// build test with errors and check for messages
   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  // 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 + 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  		// 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, 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 << 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  		// Branch like arguments
   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