Commit 7eef0ca1 authored by Matthew Dempsky's avatar Matthew Dempsky

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/+/196619Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent 55924135
...@@ -291,46 +291,32 @@ func (e *Escape) stmt(n *Node) { ...@@ -291,46 +291,32 @@ func (e *Escape) stmt(n *Node) {
case ORANGE: case ORANGE:
// for List = range Right { Nbody } // for List = range Right { Nbody }
// Right is evaluated outside the loop.
tv := e.newLoc(n, false)
e.expr(tv.asHole(), n.Right)
e.loopDepth++ e.loopDepth++
ks := e.addrs(n.List) 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 len(ks) >= 2 {
if n.Right.Type.IsArray() { if n.Right.Type.IsArray() {
e.flow(ks[1].note(n, "range"), tv) k = ks[1].note(n, "range")
} else { } else {
e.flow(ks[1].deref(n, "range-deref"), tv) k = ks[1].deref(n, "range-deref")
} }
} }
e.expr(e.later(k), n.Right)
e.block(n.Nbody)
e.loopDepth--
case OSWITCH: case OSWITCH:
var tv *EscLocation typesw := n.Left != nil && n.Left.Op == OTYPESW
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)
}
}
var ks []EscHole
for _, cas := range n.List.Slice() { // cases for _, cas := range n.List.Slice() { // cases
if tv != nil { if typesw && n.Left.Left != nil {
// type switch variables have no ODCL.
cv := cas.Rlist.First() cv := cas.Rlist.First()
k := e.dcl(cv) k := e.dcl(cv) // type switch variables have no ODCL.
if types.Haspointers(cv.Type) { 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) { ...@@ -338,6 +324,12 @@ func (e *Escape) stmt(n *Node) {
e.block(cas.Nbody) e.block(cas.Nbody)
} }
if typesw {
e.expr(e.teeHole(ks...), n.Left.Right)
} else {
e.discard(n.Left)
}
case OSELECT: case OSELECT:
for _, cas := range n.List.Slice() { for _, cas := range n.List.Slice() {
e.stmt(cas.Left) e.stmt(cas.Left)
...@@ -882,8 +874,7 @@ func (e *Escape) augmentParamHole(k EscHole, where *Node) EscHole { ...@@ -882,8 +874,7 @@ func (e *Escape) augmentParamHole(k EscHole, where *Node) EscHole {
// transiently allocated. // transiently allocated.
if where.Op == ODEFER && e.loopDepth == 1 { if where.Op == ODEFER && e.loopDepth == 1 {
where.Esc = EscNever // force stack allocation of defer record (see ssa.go) where.Esc = EscNever // force stack allocation of defer record (see ssa.go)
// TODO(mdempsky): Eliminate redundant EscLocation allocs. return e.later(k)
return e.teeHole(k, e.newLoc(nil, false).asHole())
} }
return e.heapHole() return e.heapHole()
...@@ -988,6 +979,9 @@ func (e *Escape) dcl(n *Node) EscHole { ...@@ -988,6 +979,9 @@ func (e *Escape) dcl(n *Node) EscHole {
return loc.asHole() 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 { func (e *Escape) spill(k EscHole, n *Node) EscHole {
// TODO(mdempsky): Optimize. E.g., if k is the heap or blank, // TODO(mdempsky): Optimize. E.g., if k is the heap or blank,
// then we already know whether n leaks, and we can return a // 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 { ...@@ -997,6 +991,15 @@ func (e *Escape) spill(k EscHole, n *Node) EscHole {
return loc.asHole() 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 // canonicalNode returns the canonical *Node that n logically
// represents. // represents.
func canonicalNode(n *Node) *Node { func canonicalNode(n *Node) *Node {
...@@ -1276,9 +1279,6 @@ func (e *Escape) finish(fns []*Node) { ...@@ -1276,9 +1279,6 @@ func (e *Escape) finish(fns []*Node) {
// Update n.Esc based on escape analysis results. // 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. // TODO(mdempsky): Describe path when Debug['m'] >= 2.
if loc.escapes { if loc.escapes {
...@@ -1288,15 +1288,12 @@ func (e *Escape) finish(fns []*Node) { ...@@ -1288,15 +1288,12 @@ func (e *Escape) finish(fns []*Node) {
n.Esc = EscHeap n.Esc = EscHeap
addrescapes(n) addrescapes(n)
} else { } 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) Warnl(n.Pos, "%S does not escape", n)
} }
n.Esc = EscNone n.Esc = EscNone
if loc.transient { if loc.transient {
switch n.Op { n.SetNoescape(true)
case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
n.SetNoescape(true)
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment