Source file src/cmd/internal/obj/x86/obj6_test.go

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

View as plain text