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

     1  // Copyright 2019 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 riscv
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"runtime"
    16  	"testing"
    17  )
    18  
    19  // TestLargeBranch generates a large function with a very far conditional
    20  // branch, in order to ensure that it assembles successfully.
    21  func TestLargeBranch(t *testing.T) {
    22  	if testing.Short() {
    23  		t.Skip("Skipping test in short mode")
    24  	}
    25  	testenv.MustHaveGoBuild(t)
    26  
    27  	dir, err := ioutil.TempDir("", "testlargebranch")
    28  	if err != nil {
    29  		t.Fatalf("Could not create directory: %v", err)
    30  	}
    31  	defer os.RemoveAll(dir)
    32  
    33  	// Generate a very large function.
    34  	buf := bytes.NewBuffer(make([]byte, 0, 7000000))
    35  	genLargeBranch(buf)
    36  
    37  	tmpfile := filepath.Join(dir, "x.s")
    38  	if err := ioutil.WriteFile(tmpfile, buf.Bytes(), 0644); err != nil {
    39  		t.Fatalf("Failed to write file: %v", err)
    40  	}
    41  
    42  	// Assemble generated file.
    43  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
    44  	cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
    45  	out, err := cmd.CombinedOutput()
    46  	if err != nil {
    47  		t.Errorf("Build failed: %v, output: %s", err, out)
    48  	}
    49  }
    50  
    51  func genLargeBranch(buf *bytes.Buffer) {
    52  	fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
    53  	fmt.Fprintln(buf, "BEQ X0, X0, label")
    54  	for i := 0; i < 1<<19; i++ {
    55  		fmt.Fprintln(buf, "ADD $0, X0, X0")
    56  	}
    57  	fmt.Fprintln(buf, "label:")
    58  	fmt.Fprintln(buf, "ADD $0, X0, X0")
    59  }
    60  
    61  // TestLargeCall generates a large function (>1MB of text) with a call to
    62  // a following function, in order to ensure that it assembles and links
    63  // correctly.
    64  func TestLargeCall(t *testing.T) {
    65  	if testing.Short() {
    66  		t.Skip("Skipping test in short mode")
    67  	}
    68  	testenv.MustHaveGoBuild(t)
    69  
    70  	dir, err := ioutil.TempDir("", "testlargecall")
    71  	if err != nil {
    72  		t.Fatalf("could not create directory: %v", err)
    73  	}
    74  	defer os.RemoveAll(dir)
    75  
    76  	if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module largecall"), 0644); err != nil {
    77  		t.Fatalf("Failed to write file: %v\n", err)
    78  	}
    79  	main := `package main
    80  func main() {
    81          x()
    82  }
    83  
    84  func x()
    85  func y()
    86  `
    87  	if err := ioutil.WriteFile(filepath.Join(dir, "x.go"), []byte(main), 0644); err != nil {
    88  		t.Fatalf("failed to write main: %v\n", err)
    89  	}
    90  
    91  	// Generate a very large function with call.
    92  	buf := bytes.NewBuffer(make([]byte, 0, 7000000))
    93  	genLargeCall(buf)
    94  
    95  	if err := ioutil.WriteFile(filepath.Join(dir, "x.s"), buf.Bytes(), 0644); err != nil {
    96  		t.Fatalf("Failed to write file: %v\n", err)
    97  	}
    98  
    99  	// Build generated files.
   100  	cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal")
   101  	cmd.Dir = dir
   102  	cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
   103  	out, err := cmd.CombinedOutput()
   104  	if err != nil {
   105  		t.Errorf("Build failed: %v, output: %s", err, out)
   106  	}
   107  
   108  	if runtime.GOARCH == "riscv64" && testenv.HasCGO() {
   109  		cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-linkmode=external")
   110  		cmd.Dir = dir
   111  		cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
   112  		out, err := cmd.CombinedOutput()
   113  		if err != nil {
   114  			t.Errorf("Build failed: %v, output: %s", err, out)
   115  		}
   116  	}
   117  }
   118  
   119  func genLargeCall(buf *bytes.Buffer) {
   120  	fmt.Fprintln(buf, "TEXT ·x(SB),0,$0-0")
   121  	fmt.Fprintln(buf, "CALL ·y(SB)")
   122  	for i := 0; i < 1<<19; i++ {
   123  		fmt.Fprintln(buf, "ADD $0, X0, X0")
   124  	}
   125  	fmt.Fprintln(buf, "RET")
   126  	fmt.Fprintln(buf, "TEXT ·y(SB),0,$0-0")
   127  	fmt.Fprintln(buf, "ADD $0, X0, X0")
   128  	fmt.Fprintln(buf, "RET")
   129  }
   130  
   131  // Issue 20348.
   132  func TestNoRet(t *testing.T) {
   133  	dir, err := ioutil.TempDir("", "testnoret")
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	defer os.RemoveAll(dir)
   138  	tmpfile := filepath.Join(dir, "x.s")
   139  	if err := ioutil.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil {
   140  		t.Fatal(err)
   141  	}
   142  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
   143  	cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
   144  	if out, err := cmd.CombinedOutput(); err != nil {
   145  		t.Errorf("%v\n%s", err, out)
   146  	}
   147  }
   148  
   149  func TestImmediateSplitting(t *testing.T) {
   150  	dir, err := ioutil.TempDir("", "testimmsplit")
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	defer os.RemoveAll(dir)
   155  	tmpfile := filepath.Join(dir, "x.s")
   156  	asm := `
   157  TEXT _stub(SB),$0-0
   158  	LB	4096(X5), X6
   159  	LH	4096(X5), X6
   160  	LW	4096(X5), X6
   161  	LD	4096(X5), X6
   162  	LBU	4096(X5), X6
   163  	LHU	4096(X5), X6
   164  	LWU	4096(X5), X6
   165  	SB	X6, 4096(X5)
   166  	SH	X6, 4096(X5)
   167  	SW	X6, 4096(X5)
   168  	SD	X6, 4096(X5)
   169  
   170  	FLW	4096(X5), F6
   171  	FLD	4096(X5), F6
   172  	FSW	F6, 4096(X5)
   173  	FSD	F6, 4096(X5)
   174  
   175  	MOVB	4096(X5), X6
   176  	MOVH	4096(X5), X6
   177  	MOVW	4096(X5), X6
   178  	MOV	4096(X5), X6
   179  	MOVBU	4096(X5), X6
   180  	MOVHU	4096(X5), X6
   181  	MOVWU	4096(X5), X6
   182  
   183  	MOVB	X6, 4096(X5)
   184  	MOVH	X6, 4096(X5)
   185  	MOVW	X6, 4096(X5)
   186  	MOV	X6, 4096(X5)
   187  
   188  	MOVF	4096(X5), F6
   189  	MOVD	4096(X5), F6
   190  	MOVF	F6, 4096(X5)
   191  	MOVD	F6, 4096(X5)
   192  `
   193  	if err := ioutil.WriteFile(tmpfile, []byte(asm), 0644); err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
   197  	cmd.Env = append(os.Environ(), "GOARCH=riscv64", "GOOS=linux")
   198  	if out, err := cmd.CombinedOutput(); err != nil {
   199  		t.Errorf("%v\n%s", err, out)
   200  	}
   201  }
   202  
   203  func TestBranch(t *testing.T) {
   204  	if runtime.GOARCH != "riscv64" {
   205  		t.Skip("Requires riscv64 to run")
   206  	}
   207  
   208  	testenv.MustHaveGoBuild(t)
   209  
   210  	cmd := exec.Command(testenv.GoToolPath(t), "test")
   211  	cmd.Dir = "testdata/testbranch"
   212  	if out, err := testenv.CleanCmdEnv(cmd).CombinedOutput(); err != nil {
   213  		t.Errorf("Branch test failed: %v\n%s", err, out)
   214  	}
   215  }
   216  

View as plain text