Source file src/cmd/internal/obj/arm64/asm_arm64_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  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"regexp"
    16  	"testing"
    17  )
    18  
    19  // TestLarge generates a very large file to verify that large
    20  // program builds successfully, in particular, too-far
    21  // conditional branches are fixed, and also verify that the
    22  // instruction's pc can be correctly aligned even when branches
    23  // need to be fixed.
    24  func TestLarge(t *testing.T) {
    25  	if testing.Short() {
    26  		t.Skip("Skip in short mode")
    27  	}
    28  	testenv.MustHaveGoBuild(t)
    29  
    30  	dir, err := ioutil.TempDir("", "testlarge")
    31  	if err != nil {
    32  		t.Fatalf("could not create directory: %v", err)
    33  	}
    34  	defer os.RemoveAll(dir)
    35  
    36  	// generate a very large function
    37  	buf := bytes.NewBuffer(make([]byte, 0, 7000000))
    38  	gen(buf)
    39  
    40  	tmpfile := filepath.Join(dir, "x.s")
    41  	err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
    42  	if err != nil {
    43  		t.Fatalf("can't write output: %v\n", err)
    44  	}
    45  
    46  	pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3`
    47  
    48  	// assemble generated file
    49  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
    50  	cmd.Env = append(os.Environ(), "GOOS=linux")
    51  	out, err := cmd.CombinedOutput()
    52  	if err != nil {
    53  		t.Errorf("Assemble failed: %v, output: %s", err, out)
    54  	}
    55  	matched, err := regexp.MatchString(pattern, string(out))
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	if !matched {
    60  		t.Errorf("The alignment is not correct: %t, output:%s\n", matched, out)
    61  	}
    62  
    63  	// build generated file
    64  	cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
    65  	cmd.Env = append(os.Environ(), "GOOS=linux")
    66  	out, err = cmd.CombinedOutput()
    67  	if err != nil {
    68  		t.Errorf("Build failed: %v, output: %s", err, out)
    69  	}
    70  }
    71  
    72  // gen generates a very large program, with a very far conditional branch.
    73  func gen(buf *bytes.Buffer) {
    74  	fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
    75  	fmt.Fprintln(buf, "TBZ $5, R0, label")
    76  	fmt.Fprintln(buf, "CBZ R0, label")
    77  	fmt.Fprintln(buf, "BEQ label")
    78  	fmt.Fprintln(buf, "PCALIGN $128")
    79  	fmt.Fprintln(buf, "MOVD $3, R3")
    80  	for i := 0; i < 1<<19; i++ {
    81  		fmt.Fprintln(buf, "MOVD R0, R1")
    82  	}
    83  	fmt.Fprintln(buf, "label:")
    84  	fmt.Fprintln(buf, "RET")
    85  }
    86  
    87  // Issue 20348.
    88  func TestNoRet(t *testing.T) {
    89  	dir, err := ioutil.TempDir("", "testnoret")
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	defer os.RemoveAll(dir)
    94  	tmpfile := filepath.Join(dir, "x.s")
    95  	if err := ioutil.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
    99  	cmd.Env = append(os.Environ(), "GOOS=linux")
   100  	if out, err := cmd.CombinedOutput(); err != nil {
   101  		t.Errorf("%v\n%s", err, out)
   102  	}
   103  }
   104  
   105  // TestPCALIGN verifies the correctness of the PCALIGN by checking if the
   106  // code can be aligned to the alignment value.
   107  func TestPCALIGN(t *testing.T) {
   108  	testenv.MustHaveGoBuild(t)
   109  	dir, err := ioutil.TempDir("", "testpcalign")
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  	defer os.RemoveAll(dir)
   114  	tmpfile := filepath.Join(dir, "test.s")
   115  	tmpout := filepath.Join(dir, "test.o")
   116  
   117  	code1 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n")
   118  	code2 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n")
   119  	// If the output contains this pattern, the pc-offsite of "MOVD $1, R1" is 8 bytes aligned.
   120  	out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1`
   121  	// If the output contains this pattern, the pc-offsite of "MOVD $2, R2" is 16 bytes aligned.
   122  	out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2`
   123  	var testCases = []struct {
   124  		name string
   125  		code []byte
   126  		out  string
   127  	}{
   128  		{"8-byte alignment", code1, out1},
   129  		{"16-byte alignment", code2, out2},
   130  	}
   131  
   132  	for _, test := range testCases {
   133  		if err := ioutil.WriteFile(tmpfile, test.code, 0644); err != nil {
   134  			t.Fatal(err)
   135  		}
   136  		cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile)
   137  		cmd.Env = append(os.Environ(), "GOOS=linux")
   138  		out, err := cmd.CombinedOutput()
   139  		if err != nil {
   140  			t.Errorf("The %s build failed: %v, output: %s", test.name, err, out)
   141  			continue
   142  		}
   143  
   144  		matched, err := regexp.MatchString(test.out, string(out))
   145  		if err != nil {
   146  			t.Fatal(err)
   147  		}
   148  		if !matched {
   149  			t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out)
   150  		}
   151  	}
   152  }
   153  
   154  func testvmovq() (r1, r2 uint64)
   155  
   156  // TestVMOVQ checks if the arm64 VMOVQ instruction is working properly.
   157  func TestVMOVQ(t *testing.T) {
   158  	a, b := testvmovq()
   159  	if a != 0x7040201008040201 || b != 0x3040201008040201 {
   160  		t.Errorf("TestVMOVQ got: a=0x%x, b=0x%x, want: a=0x7040201008040201, b=0x3040201008040201", a, b)
   161  	}
   162  }
   163  

View as plain text