]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: clean up escape graph construction
authorMatthew Dempsky <mdempsky@google.com>
Thu, 19 Sep 2019 23:55:56 +0000 (16:55 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 23 Sep 2019 21:24:59 +0000 (21:24 +0000)
OTYPESW and ORANGE were manually creating locations and flows around
them, which are relatively low-level graph construction primitives.
This CL changes them to use holes like the rest of the code.

Also, introduce "later" as an abstraction for assignment flows that
don't happen right away, and which need to prevent expressions from
being marked as "transient" (e.g., in ODEFER and ORANGE).

There's no behavior change here, but this does reduce the number of
newLoc call sites, which should help with restoring -m=2 diagnostics.

Passes toolstash-check.

Updates #31489.

Change-Id: Ic03d4488cb5162afe8b00b12432d203027e8d7d0
Reviewed-on: https://go-review.googlesource.com/c/go/+/196619
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/gc/escape.go

index ce0462414f44d5bbb9b4e75afa8bb01f66c633c5..85a495a769fd38c0e62f7606713f33481d2d5b71 100644 (file)
@@ -291,46 +291,32 @@ func (e *Escape) stmt(n *Node) {
 
        case ORANGE:
                // for List = range Right { Nbody }
-
-               // Right is evaluated outside the loop.
-               tv := e.newLoc(n, false)
-               e.expr(tv.asHole(), n.Right)
-
                e.loopDepth++
                ks := e.addrs(n.List)
+               e.block(n.Nbody)
+               e.loopDepth--
+
+               // Right is evaluated outside the loop.
+               k := e.discardHole()
                if len(ks) >= 2 {
                        if n.Right.Type.IsArray() {
-                               e.flow(ks[1].note(n, "range"), tv)
+                               k = ks[1].note(n, "range")
                        } else {
-                               e.flow(ks[1].deref(n, "range-deref"), tv)
+                               k = ks[1].deref(n, "range-deref")
                        }
                }
-
-               e.block(n.Nbody)
-               e.loopDepth--
+               e.expr(e.later(k), n.Right)
 
        case OSWITCH:
-               var tv *EscLocation
-               if n.Left != nil {
-                       if n.Left.Op == OTYPESW {
-                               k := e.discardHole()
-                               if n.Left.Left != nil {
-                                       tv = e.newLoc(n.Left, false)
-                                       k = tv.asHole()
-                               }
-                               e.expr(k, n.Left.Right)
-                       } else {
-                               e.discard(n.Left)
-                       }
-               }
+               typesw := n.Left != nil && n.Left.Op == OTYPESW
 
+               var ks []EscHole
                for _, cas := range n.List.Slice() { // cases
-                       if tv != nil {
-                               // type switch variables have no ODCL.
+                       if typesw && n.Left.Left != nil {
                                cv := cas.Rlist.First()
-                               k := e.dcl(cv)
+                               k := e.dcl(cv) // type switch variables have no ODCL.
                                if types.Haspointers(cv.Type) {
-                                       e.flow(k.dotType(cv.Type, n, "switch case"), tv)
+                                       ks = append(ks, k.dotType(cv.Type, n, "switch case"))
                                }
                        }
 
@@ -338,6 +324,12 @@ func (e *Escape) stmt(n *Node) {
                        e.block(cas.Nbody)
                }
 
+               if typesw {
+                       e.expr(e.teeHole(ks...), n.Left.Right)
+               } else {
+                       e.discard(n.Left)
+               }
+
        case OSELECT:
                for _, cas := range n.List.Slice() {
                        e.stmt(cas.Left)
@@ -882,8 +874,7 @@ func (e *Escape) augmentParamHole(k EscHole, where *Node) EscHole {
        // transiently allocated.
        if where.Op == ODEFER && e.loopDepth == 1 {
                where.Esc = EscNever // force stack allocation of defer record (see ssa.go)
-               // TODO(mdempsky): Eliminate redundant EscLocation allocs.
-               return e.teeHole(k, e.newLoc(nil, false).asHole())
+               return e.later(k)
        }
 
        return e.heapHole()
@@ -988,6 +979,9 @@ func (e *Escape) dcl(n *Node) EscHole {
        return loc.asHole()
 }
 
+// spill allocates a new location associated with expression n, flows
+// its address to k, and returns a hole that flows values to it. It's
+// intended for use with most expressions that allocate storage.
 func (e *Escape) spill(k EscHole, n *Node) EscHole {
        // TODO(mdempsky): Optimize. E.g., if k is the heap or blank,
        // then we already know whether n leaks, and we can return a
@@ -997,6 +991,15 @@ func (e *Escape) spill(k EscHole, n *Node) EscHole {
        return loc.asHole()
 }
 
+// later returns a new hole that flows into k, but some time later.
+// Its main effect is to prevent immediate reuse of temporary
+// variables introduced during Order.
+func (e *Escape) later(k EscHole) EscHole {
+       loc := e.newLoc(nil, false)
+       e.flow(k, loc)
+       return loc.asHole()
+}
+
 // canonicalNode returns the canonical *Node that n logically
 // represents.
 func canonicalNode(n *Node) *Node {
@@ -1276,9 +1279,6 @@ func (e *Escape) finish(fns []*Node) {
 
                // Update n.Esc based on escape analysis results.
                //
-               // TODO(mdempsky): Simplify once compatibility with
-               // esc.go is no longer necessary.
-               //
                // TODO(mdempsky): Describe path when Debug['m'] >= 2.
 
                if loc.escapes {
@@ -1288,15 +1288,12 @@ func (e *Escape) finish(fns []*Node) {
                        n.Esc = EscHeap
                        addrescapes(n)
                } else {
-                       if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
+                       if Debug['m'] != 0 && n.Op != ONAME {
                                Warnl(n.Pos, "%S does not escape", n)
                        }
                        n.Esc = EscNone
                        if loc.transient {
-                               switch n.Op {
-                               case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
-                                       n.SetNoescape(true)
-                               }
+                               n.SetNoescape(true)
                        }
                }
        }