github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/gc/asm_test.go (about) 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 gc 6 7 import ( 8 "bytes" 9 "fmt" 10 "internal/testenv" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "regexp" 16 "runtime" 17 "strings" 18 "testing" 19 ) 20 21 // TestAssembly checks to make sure the assembly generated for 22 // functions contains certain expected instructions. 23 // Note: this test will fail if -ssa=0. 24 func TestAssembly(t *testing.T) { 25 testenv.MustHaveGoBuild(t) 26 if runtime.GOOS == "windows" { 27 // TODO: remove if we can get "go tool compile -S" to work on windows. 28 t.Skipf("skipping test: recursive windows compile not working") 29 } 30 dir, err := ioutil.TempDir("", "TestAssembly") 31 if err != nil { 32 t.Fatalf("could not create directory: %v", err) 33 } 34 defer os.RemoveAll(dir) 35 36 for _, test := range asmTests { 37 asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function)) 38 // Get rid of code for "".init. Also gets rid of type algorithms & other junk. 39 if i := strings.Index(asm, "\n\"\".init "); i >= 0 { 40 asm = asm[:i+1] 41 } 42 for _, r := range test.regexps { 43 if b, err := regexp.MatchString(r, asm); !b || err != nil { 44 t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, test.function, asm) 45 } 46 } 47 } 48 } 49 50 // compile compiles the package pkg for architecture arch and 51 // returns the generated assembly. dir is a scratch directory. 52 func compileToAsm(dir, arch, pkg string) string { 53 // Create source. 54 src := filepath.Join(dir, "test.go") 55 f, err := os.Create(src) 56 if err != nil { 57 panic(err) 58 } 59 f.Write([]byte(pkg)) 60 f.Close() 61 62 var stdout, stderr bytes.Buffer 63 cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) 64 cmd.Env = mergeEnvLists([]string{"GOARCH=" + arch}, os.Environ()) 65 cmd.Stdout = &stdout 66 cmd.Stderr = &stderr 67 if err := cmd.Run(); err != nil { 68 panic(err) 69 } 70 if s := stderr.String(); s != "" { 71 panic(fmt.Errorf("Stderr = %s\nWant empty", s)) 72 } 73 return stdout.String() 74 } 75 76 // template to convert a function to a full file 77 const template = ` 78 package main 79 %s 80 ` 81 82 type asmTest struct { 83 // architecture to compile to 84 arch string 85 // function to compile 86 function string 87 // regexps that must match the generated assembly 88 regexps []string 89 } 90 91 var asmTests = [...]asmTest{ 92 {"amd64", ` 93 func f(x int) int { 94 return x * 64 95 } 96 `, 97 []string{"\tSHLQ\t\\$6,"}, 98 }, 99 {"amd64", ` 100 func f(x int) int { 101 return x * 96 102 }`, 103 []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, 104 }, 105 } 106 107 // mergeEnvLists merges the two environment lists such that 108 // variables with the same name in "in" replace those in "out". 109 // This always returns a newly allocated slice. 110 func mergeEnvLists(in, out []string) []string { 111 out = append([]string(nil), out...) 112 NextVar: 113 for _, inkv := range in { 114 k := strings.SplitAfterN(inkv, "=", 2)[0] 115 for i, outkv := range out { 116 if strings.HasPrefix(outkv, k) { 117 out[i] = inkv 118 continue NextVar 119 } 120 } 121 out = append(out, inkv) 122 } 123 return out 124 }