github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/internal/obj/x86/obj6_test.go (about)

     1  package x86_test
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"go/build"
     8  	"internal/testenv"
     9  	"io/ioutil"
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  const testdata = `
    20  MOVQ AX, AX -> MOVQ AX, AX
    21  
    22  LEAQ name(SB), AX -> MOVQ name@GOT(SB), AX
    23  LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX
    24  MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX
    25  MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX
    26  
    27  MOVQ name(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ (R15), AX
    28  MOVQ name+10(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX
    29  
    30  CMPQ name(SB), $0 -> NOP; MOVQ name@GOT(SB), R15; CMPQ (R15), $0
    31  
    32  MOVQ $1, name(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
    33  MOVQ $1, name+10(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
    34  `
    35  
    36  type ParsedTestData struct {
    37  	input              string
    38  	marks              []int
    39  	marker_to_input    map[int][]string
    40  	marker_to_expected map[int][]string
    41  	marker_to_output   map[int][]string
    42  }
    43  
    44  const marker_start = 1234
    45  
    46  func parseTestData(t *testing.T) *ParsedTestData {
    47  	r := &ParsedTestData{}
    48  	scanner := bufio.NewScanner(strings.NewReader(testdata))
    49  	r.marker_to_input = make(map[int][]string)
    50  	r.marker_to_expected = make(map[int][]string)
    51  	marker := marker_start
    52  	input_insns := []string{}
    53  	for scanner.Scan() {
    54  		line := scanner.Text()
    55  		if len(strings.TrimSpace(line)) == 0 {
    56  			continue
    57  		}
    58  		parts := strings.Split(line, "->")
    59  		if len(parts) != 2 {
    60  			t.Fatalf("malformed line %v", line)
    61  		}
    62  		r.marks = append(r.marks, marker)
    63  		marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker)
    64  		input_insns = append(input_insns, marker_insn)
    65  		for _, input_insn := range strings.Split(parts[0], ";") {
    66  			input_insns = append(input_insns, input_insn)
    67  			r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn))
    68  		}
    69  		for _, expected_insn := range strings.Split(parts[1], ";") {
    70  			r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn))
    71  		}
    72  		marker++
    73  	}
    74  	r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n"
    75  	return r
    76  }
    77  
    78  var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+")
    79  
    80  func normalize(s string) string {
    81  	return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
    82  }
    83  
    84  func asmOutput(t *testing.T, s string) []byte {
    85  	tmpdir, err := ioutil.TempDir("", "progedittest")
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	defer os.RemoveAll(tmpdir)
    90  	tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
    91  	if err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	defer tmpfile.Close()
    95  	_, err = tmpfile.WriteString(s)
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  	gofolder := filepath.Join(build.Default.GOROOT, "bin")
   100  	if gobin := os.Getenv("GOBIN"); len(gobin) != 0 {
   101  		gofolder = gobin
   102  	}
   103  
   104  	cmd := exec.Command(
   105  		filepath.Join(gofolder, "go"), "tool", "asm", "-S", "-dynlink",
   106  		"-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
   107  
   108  	var env []string
   109  	for _, v := range os.Environ() {
   110  		if !strings.HasPrefix(v, "GOARCH=") {
   111  			env = append(env, v)
   112  		}
   113  	}
   114  	cmd.Env = append(env, "GOARCH=amd64")
   115  	asmout, err := cmd.CombinedOutput()
   116  	if err != nil {
   117  		t.Fatalf("error %s output %s", err, asmout)
   118  	}
   119  	return asmout
   120  }
   121  
   122  func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
   123  	scanner := bufio.NewScanner(bytes.NewReader(asmout))
   124  	marker := regexp.MustCompile("MOVQ \\$([0-9]+), AX")
   125  	mark := -1
   126  	td.marker_to_output = make(map[int][]string)
   127  	for scanner.Scan() {
   128  		line := scanner.Text()
   129  		if line[0] != '\t' {
   130  			continue
   131  		}
   132  		parts := strings.SplitN(line, "\t", 3)
   133  		if len(parts) != 3 {
   134  			continue
   135  		}
   136  		n := normalize(parts[2])
   137  		mark_matches := marker.FindStringSubmatch(n)
   138  		if mark_matches != nil {
   139  			mark, _ = strconv.Atoi(mark_matches[1])
   140  			if _, ok := td.marker_to_input[mark]; !ok {
   141  				t.Fatalf("unexpected marker %d", mark)
   142  			}
   143  		} else if mark != -1 {
   144  			td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
   145  		}
   146  	}
   147  }
   148  
   149  func TestDynlink(t *testing.T) {
   150  	testenv.MustHaveGoBuild(t)
   151  
   152  	if os.Getenv("GOHOSTARCH") != "" {
   153  		// TODO: make this work? It was failing due to the
   154  		// GOARCH= filtering above and skipping is easiest for
   155  		// now.
   156  		t.Skip("skipping when GOHOSTARCH is set")
   157  	}
   158  
   159  	testdata := parseTestData(t)
   160  	asmout := asmOutput(t, testdata.input)
   161  	parseOutput(t, testdata, asmout)
   162  	for _, m := range testdata.marks {
   163  		i := strings.Join(testdata.marker_to_input[m], "; ")
   164  		o := strings.Join(testdata.marker_to_output[m], "; ")
   165  		e := strings.Join(testdata.marker_to_expected[m], "; ")
   166  		if o != e {
   167  			if o == i {
   168  				t.Errorf("%s was unchanged; should have become %s", i, e)
   169  			} else {
   170  				t.Errorf("%s became %s; should have become %s", i, o, e)
   171  			}
   172  		} else if i != e {
   173  			t.Logf("%s correctly became %s", i, o)
   174  		}
   175  	}
   176  }