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