1
0
mirror of https://github.com/golang/go synced 2024-10-05 09:21:22 -06:00

[dev.ssa] cmd/compile: change ssa compilation trigger

We used to compile everything with SSA and then decide whether
to use the result or not.  It was useful when we were working
on coverage without much regard for correctness, but not so much now.

Instead, let's decide what we're going to compile and go through
the SSA compiler for only those functions.

TODO: next CL: get rid of all the UnimplementedF stuff.

Change-Id: If629addd8b62cd38ef553fd5d835114137885ce0
Reviewed-on: https://go-review.googlesource.com/17763
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2015-12-11 20:41:52 -08:00
parent 4989337192
commit 5b355a7907
2 changed files with 68 additions and 57 deletions

View File

@ -364,7 +364,6 @@ func compile(fn *Node) {
var gcargs *Sym var gcargs *Sym
var gclocals *Sym var gclocals *Sym
var ssafn *ssa.Func var ssafn *ssa.Func
var usessa bool
if fn.Nbody == nil { if fn.Nbody == nil {
if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
@ -417,9 +416,8 @@ func compile(fn *Node) {
} }
// Build an SSA backend function. // Build an SSA backend function.
// TODO: get rid of usessa. if shouldssa(Curfn) {
if Thearch.Thestring == "amd64" { ssafn = buildssa(Curfn)
ssafn, usessa = buildssa(Curfn)
} }
continpc = nil continpc = nil
@ -485,7 +483,7 @@ func compile(fn *Node) {
} }
} }
if ssafn != nil && usessa { if ssafn != nil {
genssa(ssafn, ptxt, gcargs, gclocals) genssa(ssafn, ptxt, gcargs, gclocals)
if Curfn.Func.Endlineno != 0 { if Curfn.Func.Endlineno != 0 {
lineno = Curfn.Func.Endlineno lineno = Curfn.Func.Endlineno

View File

@ -21,14 +21,10 @@ import (
// Smallest possible faulting page at address zero. // Smallest possible faulting page at address zero.
const minZeroPage = 4096 const minZeroPage = 4096
// buildssa builds an SSA function func shouldssa(fn *Node) bool {
// and reports whether it should be used. if Thearch.Thestring != "amd64" {
// Once the SSA implementation is complete, return false
// it will never return nil, and the bool can be removed. }
func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
name := fn.Func.Nname.Sym.Name
gossahash := os.Getenv("GOSSAHASH")
usessa = strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
// Environment variable control of SSA CG // Environment variable control of SSA CG
// 1. IF GOSSAFUNC == current function name THEN // 1. IF GOSSAFUNC == current function name THEN
@ -54,7 +50,63 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// GOSSAHASH to n or N, or selectively with strings of // GOSSAHASH to n or N, or selectively with strings of
// 0 and 1. // 0 and 1.
if usessa { name := fn.Func.Nname.Sym.Name
funcname := os.Getenv("GOSSAFUNC")
if funcname != "" {
// If GOSSAFUNC is set, compile only that function.
return name == funcname
}
pkg := os.Getenv("GOSSAPKG")
if pkg != "" {
// If GOSSAPKG is set, compile only that package.
return localpkg.Name == pkg
}
gossahash := os.Getenv("GOSSAHASH")
if gossahash == "" || gossahash == "y" || gossahash == "Y" {
return true
}
if gossahash == "n" || gossahash == "N" {
return false
}
// Check the hash of the name against a partial input hash.
// We use this feature to do a binary search within a package to
// find a function that is incorrectly compiled.
hstr := ""
for _, b := range sha1.Sum([]byte(name)) {
hstr += fmt.Sprintf("%08b", b)
}
if strings.HasSuffix(hstr, gossahash) {
fmt.Printf("GOSSAHASH triggered %s\n", name)
return true
}
// Iteratively try additional hashes to allow tests for multi-point
// failure.
for i := 0; true; i++ {
ev := fmt.Sprintf("GOSSAHASH%d", i)
evv := os.Getenv(ev)
if evv == "" {
break
}
if strings.HasSuffix(hstr, evv) {
fmt.Printf("%s triggered %s\n", ev, name)
return true
}
}
return false
}
// buildssa builds an SSA function.
func buildssa(fn *Node) *ssa.Func {
name := fn.Func.Nname.Sym.Name
printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
if printssa {
fmt.Println("generating SSA for", name) fmt.Println("generating SSA for", name)
dumplist("buildssa-enter", fn.Func.Enter) dumplist("buildssa-enter", fn.Func.Enter)
dumplist("buildssa-body", fn.Nbody) dumplist("buildssa-body", fn.Nbody)
@ -68,7 +120,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// TODO(khr): build config just once at the start of the compiler binary // TODO(khr): build config just once at the start of the compiler binary
var e ssaExport var e ssaExport
e.log = usessa e.log = printssa
s.config = ssa.NewConfig(Thearch.Thestring, &e, Ctxt) s.config = ssa.NewConfig(Thearch.Thestring, &e, Ctxt)
s.f = s.config.NewFunc() s.f = s.config.NewFunc()
s.f.Name = name s.f.Name = name
@ -82,7 +134,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// TODO: generate and print a mapping from nodes to values and blocks // TODO: generate and print a mapping from nodes to values and blocks
} }
defer func() { defer func() {
if !usessa { if !printssa {
s.config.HTML.Close() s.config.HTML.Close()
} }
}() }()
@ -170,7 +222,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
} }
if nerrors > 0 { if nerrors > 0 {
return nil, false return nil
} }
// Link up variable uses to variable definitions // Link up variable uses to variable definitions
@ -182,46 +234,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
// Main call to ssa package to compile function // Main call to ssa package to compile function
ssa.Compile(s.f) ssa.Compile(s.f)
// gossahash = "y" is historical/symmetric-with-"n" -- i.e., not really needed. return s.f
if usessa || gossahash == "" || gossahash == "y" || gossahash == "Y" {
return s.f, true
}
if gossahash == "n" || gossahash == "N" {
if localpkg.Name != os.Getenv("GOSSAPKG") {
return s.f, false
}
// Use everything in the package
return s.f, true
}
// Check the hash of the name against a partial input hash.
// We use this feature to do a binary search within a package to
// find a function that is incorrectly compiled.
hstr := ""
for _, b := range sha1.Sum([]byte(name)) {
hstr += fmt.Sprintf("%08b", b)
}
if strings.HasSuffix(hstr, gossahash) {
fmt.Printf("GOSSAHASH triggered %s\n", name)
return s.f, true
}
// Iteratively try additional hashes to allow tests for multi-point
// failure.
for i := 0; true; i++ {
ev := fmt.Sprintf("GOSSAHASH%d", i)
evv := os.Getenv(ev)
if evv == "" {
break
}
if strings.HasSuffix(hstr, evv) {
fmt.Printf("%s triggered %s\n", ev, name)
return s.f, true
}
}
return s.f, false
} }
type state struct { type state struct {