Skip to content

Commit 7eef0ca

Browse files
committed
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 <[email protected]>
1 parent 5592413 commit 7eef0ca

File tree

1 file changed

+34
-37
lines changed

1 file changed

+34
-37
lines changed

src/cmd/compile/internal/gc/escape.go

+34-37
Original file line numberDiff line numberDiff line change
@@ -291,53 +291,45 @@ func (e *Escape) stmt(n *Node) {
291291

292292
case ORANGE:
293293
// for List = range Right { Nbody }
294-
295-
// Right is evaluated outside the loop.
296-
tv := e.newLoc(n, false)
297-
e.expr(tv.asHole(), n.Right)
298-
299294
e.loopDepth++
300295
ks := e.addrs(n.List)
296+
e.block(n.Nbody)
297+
e.loopDepth--
298+
299+
// Right is evaluated outside the loop.
300+
k := e.discardHole()
301301
if len(ks) >= 2 {
302302
if n.Right.Type.IsArray() {
303-
e.flow(ks[1].note(n, "range"), tv)
303+
k = ks[1].note(n, "range")
304304
} else {
305-
e.flow(ks[1].deref(n, "range-deref"), tv)
305+
k = ks[1].deref(n, "range-deref")
306306
}
307307
}
308-
309-
e.block(n.Nbody)
310-
e.loopDepth--
308+
e.expr(e.later(k), n.Right)
311309

312310
case OSWITCH:
313-
var tv *EscLocation
314-
if n.Left != nil {
315-
if n.Left.Op == OTYPESW {
316-
k := e.discardHole()
317-
if n.Left.Left != nil {
318-
tv = e.newLoc(n.Left, false)
319-
k = tv.asHole()
320-
}
321-
e.expr(k, n.Left.Right)
322-
} else {
323-
e.discard(n.Left)
324-
}
325-
}
311+
typesw := n.Left != nil && n.Left.Op == OTYPESW
326312

313+
var ks []EscHole
327314
for _, cas := range n.List.Slice() { // cases
328-
if tv != nil {
329-
// type switch variables have no ODCL.
315+
if typesw && n.Left.Left != nil {
330316
cv := cas.Rlist.First()
331-
k := e.dcl(cv)
317+
k := e.dcl(cv) // type switch variables have no ODCL.
332318
if types.Haspointers(cv.Type) {
333-
e.flow(k.dotType(cv.Type, n, "switch case"), tv)
319+
ks = append(ks, k.dotType(cv.Type, n, "switch case"))
334320
}
335321
}
336322

337323
e.discards(cas.List)
338324
e.block(cas.Nbody)
339325
}
340326

327+
if typesw {
328+
e.expr(e.teeHole(ks...), n.Left.Right)
329+
} else {
330+
e.discard(n.Left)
331+
}
332+
341333
case OSELECT:
342334
for _, cas := range n.List.Slice() {
343335
e.stmt(cas.Left)
@@ -882,8 +874,7 @@ func (e *Escape) augmentParamHole(k EscHole, where *Node) EscHole {
882874
// transiently allocated.
883875
if where.Op == ODEFER && e.loopDepth == 1 {
884876
where.Esc = EscNever // force stack allocation of defer record (see ssa.go)
885-
// TODO(mdempsky): Eliminate redundant EscLocation allocs.
886-
return e.teeHole(k, e.newLoc(nil, false).asHole())
877+
return e.later(k)
887878
}
888879

889880
return e.heapHole()
@@ -988,6 +979,9 @@ func (e *Escape) dcl(n *Node) EscHole {
988979
return loc.asHole()
989980
}
990981

982+
// spill allocates a new location associated with expression n, flows
983+
// its address to k, and returns a hole that flows values to it. It's
984+
// intended for use with most expressions that allocate storage.
991985
func (e *Escape) spill(k EscHole, n *Node) EscHole {
992986
// TODO(mdempsky): Optimize. E.g., if k is the heap or blank,
993987
// 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 {
997991
return loc.asHole()
998992
}
999993

994+
// later returns a new hole that flows into k, but some time later.
995+
// Its main effect is to prevent immediate reuse of temporary
996+
// variables introduced during Order.
997+
func (e *Escape) later(k EscHole) EscHole {
998+
loc := e.newLoc(nil, false)
999+
e.flow(k, loc)
1000+
return loc.asHole()
1001+
}
1002+
10001003
// canonicalNode returns the canonical *Node that n logically
10011004
// represents.
10021005
func canonicalNode(n *Node) *Node {
@@ -1276,9 +1279,6 @@ func (e *Escape) finish(fns []*Node) {
12761279

12771280
// Update n.Esc based on escape analysis results.
12781281
//
1279-
// TODO(mdempsky): Simplify once compatibility with
1280-
// esc.go is no longer necessary.
1281-
//
12821282
// TODO(mdempsky): Describe path when Debug['m'] >= 2.
12831283

12841284
if loc.escapes {
@@ -1288,15 +1288,12 @@ func (e *Escape) finish(fns []*Node) {
12881288
n.Esc = EscHeap
12891289
addrescapes(n)
12901290
} else {
1291-
if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
1291+
if Debug['m'] != 0 && n.Op != ONAME {
12921292
Warnl(n.Pos, "%S does not escape", n)
12931293
}
12941294
n.Esc = EscNone
12951295
if loc.transient {
1296-
switch n.Op {
1297-
case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
1298-
n.SetNoescape(true)
1299-
}
1296+
n.SetNoescape(true)
13001297
}
13011298
}
13021299
}

0 commit comments

Comments
 (0)