From: Matthew Dempsky Date: Thu, 19 Sep 2019 23:55:56 +0000 (-0700) Subject: cmd/compile: clean up escape graph construction X-Git-Tag: go1.14beta1~1009 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7eef0ca17ae09ae40027dcc78138179e0ed19b10;p=gostls13.git cmd/compile: clean up escape graph construction 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 --- diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index ce0462414f..85a495a769 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -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) } } }