Source file src/cmd/internal/obj/arm64/asm_test.go

     1  // Copyright 2016 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 arm64
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"path/filepath"
    13  	"regexp"
    14  	"testing"
    15  )
    16  
    17  func runAssembler(t *testing.T, srcdata string) []byte {
    18  	dir := t.TempDir()
    19  	defer os.RemoveAll(dir)
    20  	srcfile := filepath.Join(dir, "testdata.s")
    21  	outfile := filepath.Join(dir, "testdata.o")
    22  	os.WriteFile(srcfile, []byte(srcdata), 0644)
    23  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "asm", "-S", "-o", outfile, srcfile)
    24  	cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=arm64")
    25  	out, err := cmd.CombinedOutput()
    26  	if err != nil {
    27  		t.Errorf("The build failed: %v, output:\n%s", err, out)
    28  	}
    29  	return out
    30  }
    31  
    32  func TestSplitImm24uScaled(t *testing.T) {
    33  	tests := []struct {
    34  		v       int32
    35  		shift   int
    36  		wantErr bool
    37  		wantHi  int32
    38  		wantLo  int32
    39  	}{
    40  		{
    41  			v:      0,
    42  			shift:  0,
    43  			wantHi: 0,
    44  			wantLo: 0,
    45  		},
    46  		{
    47  			v:      0x1001,
    48  			shift:  0,
    49  			wantHi: 0x2,
    50  			wantLo: 0xfff,
    51  		},
    52  		{
    53  			v:      0xffffff,
    54  			shift:  0,
    55  			wantHi: 0xfff000,
    56  			wantLo: 0xfff,
    57  		},
    58  		{
    59  			v:       0xffffff,
    60  			shift:   1,
    61  			wantErr: true,
    62  		},
    63  		{
    64  			v:      0xfe,
    65  			shift:  1,
    66  			wantHi: 0x0,
    67  			wantLo: 0x7f,
    68  		},
    69  		{
    70  			v:      0x10fe,
    71  			shift:  1,
    72  			wantHi: 0x0,
    73  			wantLo: 0x87f,
    74  		},
    75  		{
    76  			v:      0x2002,
    77  			shift:  1,
    78  			wantHi: 0x4,
    79  			wantLo: 0xfff,
    80  		},
    81  		{
    82  			v:      0xfffffe,
    83  			shift:  1,
    84  			wantHi: 0xffe000,
    85  			wantLo: 0xfff,
    86  		},
    87  		{
    88  			v:      0x1000ffe,
    89  			shift:  1,
    90  			wantHi: 0xfff000,
    91  			wantLo: 0xfff,
    92  		},
    93  		{
    94  			v:       0x1001000,
    95  			shift:   1,
    96  			wantErr: true,
    97  		},
    98  		{
    99  			v:       0x1000001,
   100  			shift:   1,
   101  			wantErr: true,
   102  		},
   103  		{
   104  			v:       0xfffffe,
   105  			shift:   2,
   106  			wantErr: true,
   107  		},
   108  		{
   109  			v:      0x4004,
   110  			shift:  2,
   111  			wantHi: 0x8,
   112  			wantLo: 0xfff,
   113  		},
   114  		{
   115  			v:      0xfffffc,
   116  			shift:  2,
   117  			wantHi: 0xffc000,
   118  			wantLo: 0xfff,
   119  		},
   120  		{
   121  			v:      0x1002ffc,
   122  			shift:  2,
   123  			wantHi: 0xfff000,
   124  			wantLo: 0xfff,
   125  		},
   126  		{
   127  			v:       0x1003000,
   128  			shift:   2,
   129  			wantErr: true,
   130  		},
   131  		{
   132  			v:       0xfffffe,
   133  			shift:   3,
   134  			wantErr: true,
   135  		},
   136  		{
   137  			v:      0x8008,
   138  			shift:  3,
   139  			wantHi: 0x10,
   140  			wantLo: 0xfff,
   141  		},
   142  		{
   143  			v:      0xfffff8,
   144  			shift:  3,
   145  			wantHi: 0xff8000,
   146  			wantLo: 0xfff,
   147  		},
   148  		{
   149  			v:      0x1006ff8,
   150  			shift:  3,
   151  			wantHi: 0xfff000,
   152  			wantLo: 0xfff,
   153  		},
   154  		{
   155  			v:       0x1007000,
   156  			shift:   3,
   157  			wantErr: true,
   158  		},
   159  		// Unshifted hi cases - hi <= 0xfff fits directly
   160  		{
   161  			v:      7,
   162  			shift:  3,
   163  			wantHi: 7,
   164  			wantLo: 0,
   165  		},
   166  		{
   167  			v:      0x8ff7,
   168  			shift:  3,
   169  			wantHi: 0xfff,
   170  			wantLo: 0xfff,
   171  		},
   172  		{
   173  			v:      0x7ff8,
   174  			shift:  3,
   175  			wantHi: 0,
   176  			wantLo: 0xfff,
   177  		},
   178  		{
   179  			v:      0xfff,
   180  			shift:  1,
   181  			wantHi: 1,
   182  			wantLo: 0x7ff,
   183  		},
   184  		{
   185  			v:      0xfff,
   186  			shift:  2,
   187  			wantHi: 3,
   188  			wantLo: 0x3ff,
   189  		},
   190  		{
   191  			v:      0xfff,
   192  			shift:  3,
   193  			wantHi: 7,
   194  			wantLo: 0x1ff,
   195  		},
   196  		{
   197  			v:      0x1ffe,
   198  			shift:  2,
   199  			wantHi: 2,
   200  			wantLo: 0x7ff,
   201  		},
   202  		{
   203  			v:      0x1ffe,
   204  			shift:  3,
   205  			wantHi: 6,
   206  			wantLo: 0x3ff,
   207  		},
   208  		{
   209  			v:      0x1fff,
   210  			shift:  1,
   211  			wantHi: 1,
   212  			wantLo: 0xfff,
   213  		},
   214  		{
   215  			v:      0x1fff,
   216  			shift:  2,
   217  			wantHi: 3,
   218  			wantLo: 0x7ff,
   219  		},
   220  		{
   221  			v:      0x1fff,
   222  			shift:  3,
   223  			wantHi: 7,
   224  			wantLo: 0x3ff,
   225  		},
   226  		{
   227  			v:      0x1001,
   228  			shift:  1,
   229  			wantHi: 1,
   230  			wantLo: 0x800,
   231  		},
   232  		{
   233  			v:      0x1001,
   234  			shift:  2,
   235  			wantHi: 1,
   236  			wantLo: 0x400,
   237  		},
   238  		{
   239  			v:      0x1001,
   240  			shift:  3,
   241  			wantHi: 1,
   242  			wantLo: 0x200,
   243  		},
   244  		{
   245  			v:      0x1000,
   246  			shift:  0,
   247  			wantHi: 0x1,
   248  			wantLo: 0xfff,
   249  		},
   250  		{
   251  			v:      0x8000,
   252  			shift:  3,
   253  			wantHi: 0x8,
   254  			wantLo: 0xfff,
   255  		},
   256  		{
   257  			v:      0xfff,
   258  			shift:  0,
   259  			wantHi: 0,
   260  			wantLo: 0xfff,
   261  		},
   262  		{
   263  			v:      0x1ffe,
   264  			shift:  1,
   265  			wantHi: 0,
   266  			wantLo: 0xfff,
   267  		},
   268  		{
   269  			v:      0x3ffc,
   270  			shift:  2,
   271  			wantHi: 0,
   272  			wantLo: 0xfff,
   273  		},
   274  		{
   275  			v:      0x10fef,
   276  			shift:  4,
   277  			wantHi: 0xfff,
   278  			wantLo: 0xfff,
   279  		},
   280  	}
   281  	for _, test := range tests {
   282  		hi, lo, err := splitImm24uScaled(test.v, test.shift)
   283  		switch {
   284  		case err == nil && test.wantErr:
   285  			t.Errorf("splitImm24uScaled(%v, %v) succeeded, want error", test.v, test.shift)
   286  		case err != nil && !test.wantErr:
   287  			t.Errorf("splitImm24uScaled(%v, %v) failed: %v", test.v, test.shift, err)
   288  		case !test.wantErr:
   289  			if got, want := hi, test.wantHi; got != want {
   290  				t.Errorf("splitImm24uScaled(%x, %x) - got hi %x, want %x", test.v, test.shift, got, want)
   291  			}
   292  			if got, want := lo, test.wantLo; got != want {
   293  				t.Errorf("splitImm24uScaled(%x, %x) - got lo %x, want %x", test.v, test.shift, got, want)
   294  			}
   295  		}
   296  	}
   297  	for shift := 0; shift <= 3; shift++ {
   298  		for v := int32(0); v < 0xfff000+0xfff<<shift; v = v + 1<<shift {
   299  			hi, lo, err := splitImm24uScaled(v, shift)
   300  			if err != nil {
   301  				t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
   302  			}
   303  			if hi+lo<<shift != v {
   304  				t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
   305  			}
   306  		}
   307  	}
   308  
   309  	// Test the unshifted hi range specifically, including unaligned values.
   310  	// This exercises values where the unshifted path may be used.
   311  	for shift := 0; shift <= 3; shift++ {
   312  		maxUnshifted := int32(0xfff + 0xfff<<shift)
   313  		for v := int32(0); v <= maxUnshifted; v++ {
   314  			hi, lo, err := splitImm24uScaled(v, shift)
   315  			if err != nil {
   316  				t.Fatalf("splitImm24uScaled(%x, %x) failed: %v", v, shift, err)
   317  			}
   318  			if hi+lo<<shift != v {
   319  				t.Fatalf("splitImm24uScaled(%x, %x) = (%x, %x) is incorrect", v, shift, hi, lo)
   320  			}
   321  		}
   322  	}
   323  }
   324  
   325  // TestLarge generates a very large file to verify that large
   326  // program builds successfully, in particular, too-far
   327  // conditional branches are fixed, and also verify that the
   328  // instruction's pc can be correctly aligned even when branches
   329  // need to be fixed.
   330  func TestLarge(t *testing.T) {
   331  	if testing.Short() {
   332  		t.Skip("Skip in short mode")
   333  	}
   334  	testenv.MustHaveGoBuild(t)
   335  
   336  	// generate a very large function
   337  	buf := bytes.NewBuffer(make([]byte, 0, 7000000))
   338  	fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
   339  	fmt.Fprintln(buf, "TBZ $5, R0, label")
   340  	fmt.Fprintln(buf, "CBZ R0, label")
   341  	fmt.Fprintln(buf, "BEQ label")
   342  	fmt.Fprintln(buf, "PCALIGN $128")
   343  	fmt.Fprintln(buf, "MOVD $3, R3")
   344  	for i := 0; i < 1<<19; i++ {
   345  		fmt.Fprintln(buf, "MOVD R0, R1")
   346  	}
   347  	fmt.Fprintln(buf, "label:")
   348  	fmt.Fprintln(buf, "RET")
   349  
   350  	// assemble generated file
   351  	out := runAssembler(t, buf.String())
   352  
   353  	pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3`
   354  	matched, err := regexp.MatchString(pattern, string(out))
   355  
   356  	if err != nil {
   357  		t.Fatal(err)
   358  	}
   359  	if !matched {
   360  		t.Errorf("The alignment is not correct: %t\n", matched)
   361  	}
   362  }
   363  
   364  // Issue 20348.
   365  func TestNoRet(t *testing.T) {
   366  	runAssembler(t, "TEXT ·stub(SB),$0-0\nNOP\n")
   367  }
   368  
   369  // TestPCALIGN verifies the correctness of the PCALIGN by checking if the
   370  // code can be aligned to the alignment value.
   371  func TestPCALIGN(t *testing.T) {
   372  	testenv.MustHaveGoBuild(t)
   373  
   374  	code1 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n"
   375  	code2 := "TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n"
   376  	// If the output contains this pattern, the pc-offset of "MOVD $1, R1" is 8 bytes aligned.
   377  	out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1`
   378  	// If the output contains this pattern, the pc-offset of "MOVD $2, R2" is 16 bytes aligned.
   379  	out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2`
   380  	var testCases = []struct {
   381  		name string
   382  		code string
   383  		out  string
   384  	}{
   385  		{"8-byte alignment", code1, out1},
   386  		{"16-byte alignment", code2, out2},
   387  	}
   388  
   389  	for _, test := range testCases {
   390  		out := runAssembler(t, test.code)
   391  		matched, err := regexp.MatchString(test.out, string(out))
   392  		if err != nil {
   393  			t.Fatal(err)
   394  		}
   395  		if !matched {
   396  			t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
   397  		}
   398  	}
   399  }
   400  

View as plain text