]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: enhance SSA filtering, add OpConvert
authorDavid Chase <drchase@google.com>
Mon, 19 Oct 2015 15:36:07 +0000 (11:36 -0400)
committerDavid Chase <drchase@google.com>
Fri, 23 Oct 2015 19:32:57 +0000 (19:32 +0000)
Modified GOSSA{HASH.PKG} environment variable filters to
make it easier to make/run with all SSA for testing.
Disable attempts at SSA for architectures that are not
amd64 (avoid spurious errors/unimplementeds.)

Removed easy out for unimplemented features.

Add convert op for proper liveness in presence of uintptr
to/from unsafe.Pointer conversions.

Tweaked stack sizes to get a pass on windows;
1024 instead 768, was observed to pass at least once.

Change-Id: Ida3800afcda67d529e3b1cf48ca4a3f0fa48b2c5
Reviewed-on: https://go-review.googlesource.com/16201
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>

12 files changed:
src/cmd/compile/internal/gc/pgen.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteAMD64.go
src/cmd/compile/internal/ssa/tighten.go
src/cmd/dist/test.go
src/cmd/internal/obj/stack.go
src/cmd/internal/obj/util.go
src/runtime/stack.go
test/nosplit.go

index a5010a31b45853fd0bd89161ac22ea306f77ad19..b3ba2fbb4673ffa9ac6704046b9909a56c644871 100644 (file)
@@ -414,7 +414,9 @@ func compile(fn *Node) {
 
        // Build an SSA backend function.
        // TODO: get rid of usessa.
-       ssafn, usessa = buildssa(Curfn)
+       if Thearch.Thestring == "amd64" {
+               ssafn, usessa = buildssa(Curfn)
+       }
 
        continpc = nil
        breakpc = nil
index 64391b0fca4c0d2cbb1fb96160bb8bb09ebb6727..8939f141365345661c6c6654b1b9e130172f2fe2 100644 (file)
@@ -24,8 +24,32 @@ import (
 // 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
+       // 1. IF GOSSAFUNC == current function name THEN
+       //       compile this function with SSA and log output to ssa.html
+
+       // 2. IF GOSSAHASH == "y" or "Y" THEN
+       //       compile this function (and everything else) with SSA
+
+       // 3. IF GOSSAHASH == "" THEN
+       //       IF GOSSAPKG == current package name THEN
+       //          compile this function (and everything in this package) with SSA
+       //       ELSE
+       //          use the old back end for this function.
+       //       This is for compatibility with existing test harness and should go away.
+
+       // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
+       //          compile this function with SSA
+       //       ELSE
+       //          compile this function with the old back end.
+
+       // Plan is for 3 to be remove, and the 2) dependence on GOSSAHASH changes
+       // from "y"/"Y" to empty -- then SSA is default, and is disabled by setting
+       // GOSSAHASH to a value that is neither 0 nor 1 (e.g., "N" or "X")
+
        if usessa {
                fmt.Println("generating SSA for", name)
                dumplist("buildssa-enter", fn.Func.Enter)
@@ -58,17 +82,6 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
                }
        }()
 
-       // If SSA support for the function is incomplete,
-       // assume that any panics are due to violated
-       // invariants. Swallow them silently.
-       defer func() {
-               if err := recover(); err != nil {
-                       if !e.unimplemented {
-                               panic(err)
-                       }
-               }
-       }()
-
        // We construct SSA using an algorithm similar to
        // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
        // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
@@ -167,27 +180,17 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
        // Main call to ssa package to compile function
        ssa.Compile(s.f)
 
-       // Calculate stats about what percentage of functions SSA handles.
-       if false {
-               fmt.Printf("SSA implemented: %t\n", !e.unimplemented)
-       }
-
-       if e.unimplemented {
-               return nil, false
-       }
-
-       // TODO: enable codegen more broadly once the codegen stabilizes
-       // and runtime support is in (gc maps, write barriers, etc.)
-       if usessa {
+       if usessa || gossahash == "y" || gossahash == "Y" {
                return s.f, true
        }
-       if localpkg.Name != os.Getenv("GOSSAPKG") {
-               return s.f, false
-       }
-       if os.Getenv("GOSSAHASH") == "" {
+       if gossahash == "" {
+               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.
@@ -195,10 +198,26 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
        for _, b := range sha1.Sum([]byte(name)) {
                hstr += fmt.Sprintf("%08b", b)
        }
-       if strings.HasSuffix(hstr, os.Getenv("GOSSAHASH")) {
+
+       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
 }
 
@@ -1353,6 +1372,15 @@ func (s *state) expr(n *Node) *ssa.Value {
                // Assume everything will work out, so set up our return value.
                // Anything interesting that happens from here is a fatal.
                x := s.expr(n.Left)
+
+               // Special case for not confusing GC and liveness.
+               // We don't want pointers accidentally classified
+               // as not-pointers or vice-versa because of copy
+               // elision.
+               if to.IsPtr() != from.IsPtr() {
+                       return s.newValue1(ssa.OpConvert, to, x)
+               }
+
                v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
 
                // CONVNOP closure
@@ -1364,6 +1392,7 @@ func (s *state) expr(n *Node) *ssa.Value {
                if from.Etype == to.Etype {
                        return v
                }
+
                // unsafe.Pointer <--> *T
                if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
                        return v
index dd50dd2d27d1f227e898edbc5b0f086dd6504ca7..abe103571d43830619543a55053bc02943dcad9c 100644 (file)
 (Store [2] ptr val mem) -> (MOVWstore ptr val mem)
 (Store [1] ptr val mem) -> (MOVBstore ptr val mem)
 
+// We want this to stick out so the to/from ptr conversion is obvious
+(Convert <t> x) -> (LEAQ <t> x)
+
 // checks
 (IsNonNil p) -> (SETNE (TESTQ p p))
 (IsInBounds idx len) -> (SETB (CMPQ idx len))
index 5881596441808ccdfc6d6a210ea4889f6410bcd0..8a8837c0e946ff2a62cc8af1b5437cf0a7480c03 100644 (file)
@@ -237,8 +237,9 @@ var genericOps = []opData{
        {name: "Sqrt"}, // sqrt(arg0), float64 only
 
        // Data movement
-       {name: "Phi"},  // select an argument based on which predecessor block we came from
-       {name: "Copy"}, // output = arg0
+       {name: "Phi"},     // select an argument based on which predecessor block we came from
+       {name: "Copy"},    // output = arg0
+       {name: "Convert"}, // output = arg0 -- a copy that converts to/from a pointer
 
        // constants.  Constant values are stored in the aux field.
        // booleans have a bool aux field, strings have a string aux
index d86dce354b12798c5a354868554ff8b9030f90c3..4c191807ba451946273cf9ade6d7b9808abbc7f8 100644 (file)
@@ -455,6 +455,7 @@ const (
        OpSqrt
        OpPhi
        OpCopy
+       OpConvert
        OpConstBool
        OpConstString
        OpConstNil
@@ -3866,6 +3867,10 @@ var opcodeTable = [...]opInfo{
                name:    "Copy",
                generic: true,
        },
+       {
+               name:    "Convert",
+               generic: true,
+       },
        {
                name:    "ConstBool",
                generic: true,
index 2fd9a08d5bb22c0acb6f4d2ed4f64fa1b374a887..3fe272c2042d62ca17bcd2c26fb8446009044097 100644 (file)
@@ -1670,6 +1670,24 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
                goto endc395c0a53eeccf597e225a07b53047d1
        endc395c0a53eeccf597e225a07b53047d1:
                ;
+       case OpConvert:
+               // match: (Convert <t> x)
+               // cond:
+               // result: (LEAQ <t> x)
+               {
+                       t := v.Type
+                       x := v.Args[0]
+                       v.Op = OpAMD64LEAQ
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.Type = t
+                       v.AddArg(x)
+                       return true
+               }
+               goto end1cac40a6074914d6ae3d4aa039a625ed
+       end1cac40a6074914d6ae3d4aa039a625ed:
+               ;
        case OpCvt32Fto32:
                // match: (Cvt32Fto32 x)
                // cond:
index 1da5071a2ac087cda78dd4f26d09e4382ab98d67..4fa26d2d1805b42708699660bbb7e8e122cd1bf4 100644 (file)
@@ -54,8 +54,12 @@ func tighten(f *Func) {
                for _, b := range f.Blocks {
                        for i := 0; i < len(b.Values); i++ {
                                v := b.Values[i]
-                               if v.Op == OpPhi || v.Op == OpGetClosurePtr {
-                                       // GetClosurePtr must stay in entry block
+                               if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert {
+                                       // GetClosurePtr must stay in entry block.
+                                       // OpConvert must not float over call sites.
+                                       // TODO do we instead need a dependence edge of some sort for OpConvert?
+                                       // Would memory do the trick, or do we need something else that relates
+                                       // to safe point operations?
                                        continue
                                }
                                if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
index c92109afa595c0184aff4b922dae76d5cbe2939e..be6cdb5c0ba1c48bd487cf71f063590c71381b6f 100644 (file)
@@ -278,11 +278,6 @@ func (t *tester) registerStdTest(pkg string) {
 
 // TODO: Remove when SSA codegen is used by default.
 func (t *tester) registerSSATest(pkg string) {
-       switch pkg {
-       // known failures
-       case "runtime":
-               return
-       }
        t.tests = append(t.tests, distTest{
                name:    "go_test_ssa:" + pkg,
                heading: "Testing packages with SSA codegen.",
index 87698b3eeb82e148f53b82cfd919c65e69ed2411..1ca673285a08e889b7ac73c08fcf70e29136d6fb 100644 (file)
@@ -41,7 +41,7 @@ const (
        STACKSYSTEM = 0
        StackSystem = STACKSYSTEM
        StackBig    = 4096
-       StackGuard  = 640*stackGuardMultiplier + StackSystem
+       StackGuard  = 1024*stackGuardMultiplier + StackSystem
        StackSmall  = 128
        StackLimit  = StackGuard - StackSystem - StackSmall
 )
index 73d33666e2777d1f270aeeb0f61bc85ff5cacdac..a71d69edfce4903436b64e23dd2aeb2dd95d1b10 100644 (file)
@@ -385,6 +385,9 @@ func Dconv(p *Prog, a *Addr) string {
                if a.Index != REG_NONE {
                        str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
                }
+               if p.As == ATYPE && a.Gotype != nil {
+                       str += fmt.Sprintf("%s", a.Gotype.Name)
+               }
 
        case TYPE_CONST:
                if a.Reg != 0 {
index 1809a4d9acf6cb81fe2e4f15ca82ad15ba68900c..128278ebdcaa046acdd909b4661789f4a68422e7 100644 (file)
@@ -86,7 +86,7 @@ const (
 
        // The stack guard is a pointer this many bytes above the
        // bottom of the stack.
-       _StackGuard = 640*stackGuardMultiplier + _StackSystem
+       _StackGuard = 1024*stackGuardMultiplier + _StackSystem
 
        // After a stack split check the SP is allowed to be this
        // many bytes below the stack guard.  This saves an instruction
index e5c2a9f30e2f708543b8c4387642fb682b1e936b..70e8fced86df40806ccafed6887f14eb3398ac64 100644 (file)
@@ -9,6 +9,7 @@ package main
 
 import (
        "bytes"
+       "cmd/internal/obj"
        "fmt"
        "io/ioutil"
        "log"
@@ -285,12 +286,13 @@ TestCases:
                                // Instead of rewriting the test cases above, adjust
                                // the first stack frame to use up the extra bytes.
                                if i == 0 {
-                                       size += 512 - 128
+                                       size += (obj.StackGuard - 128) - 128
                                        // Noopt builds have a larger stackguard.
-                                       // See ../cmd/dist/buildruntime.go:stackGuardMultiplier
+                                       // See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
+                                       // This increase is included in obj.StackGuard
                                        for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
                                                if s == "-N" {
-                                                       size += 640
+                                                       size += obj.StackGuard
                                                }
                                        }
                                }