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

View as plain text