Skip to content

Commit

Permalink
cmd/compile: in escape analysis, propagate loop depth to field
Browse files Browse the repository at this point in the history
The escape analysis models "loop depth". If the address of an
expression is assigned to something defined at a lower (outer)
loop depth, the escape analysis decides it escapes. However, it
uses the loop depth of the address operator instead of where
the RHS is defined. This causes an unnecessary escape if there is
an assignment inside a loop but the RHS is defined outside the
loop. This CL propagates the loop depth.

Fixes #24730.

Change-Id: I5ff1530688bdfd90561a7b39c8be9bfc009a9dae
Reviewed-on: https://go-review.googlesource.com/105257
Run-TryBot: Cherry Zhang <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: David Chase <[email protected]>
  • Loading branch information
cherrymui committed Apr 13, 2018
1 parent eb4f332 commit 5a91c83
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
22 changes: 15 additions & 7 deletions src/cmd/compile/internal/gc/esc.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
fmt.Printf("%v:[%d] %v esc: %v\n", linestr(lineno), e.loopdepth, funcSym(Curfn), n)
}

opSwitch:
switch n.Op {
// Record loop depth at declaration.
case ODCL:
Expand Down Expand Up @@ -1000,13 +1001,6 @@ func (e *EscState) esc(n *Node, parent *Node) {
// and keep the current loop depth.
if n.Left.Op == ONAME {
switch n.Left.Class() {
case PAUTO:
nE := e.nodeEscState(n)
leftE := e.nodeEscState(n.Left)
if leftE.Loopdepth != 0 {
nE.Loopdepth = leftE.Loopdepth
}

// PPARAM is loop depth 1 always.
// PPARAMOUT is loop depth 0 for writes
// but considered loop depth 1 for address-of,
Expand All @@ -1016,8 +1010,22 @@ func (e *EscState) esc(n *Node, parent *Node) {
case PPARAM, PPARAMOUT:
nE := e.nodeEscState(n)
nE.Loopdepth = 1
break opSwitch
}
}
nE := e.nodeEscState(n)
leftE := e.nodeEscState(n.Left)
if leftE.Loopdepth != 0 {
nE.Loopdepth = leftE.Loopdepth
}

case ODOT,
ODOTPTR,
OINDEX:
// Propagate the loopdepth of t to t.field.
if n.Left.Op != OLITERAL { // OLITERAL node doesn't have esc state
e.nodeEscState(n).Loopdepth = e.nodeEscState(n.Left).Loopdepth
}
}

lineno = lno
Expand Down
19 changes: 19 additions & 0 deletions test/escape5.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,22 @@ func _() {
u.M() // ERROR "u does not escape"
u.N() // ERROR "u does not escape"
}

// Issue 24730: taking address in a loop causes unnecessary escape
type T24730 struct {
x [64]byte
}

func (t *T24730) g() { // ERROR "t does not escape"
y := t.x[:] // ERROR "t\.x does not escape"
for i := range t.x[:] { // ERROR "t\.x does not escape"
y = t.x[:] // ERROR "t\.x does not escape"
y[i] = 1
}

var z *byte
for i := range t.x[:] { // ERROR "t\.x does not escape"
z = &t.x[i] // ERROR "t\.x\[i\] does not escape"
*z = 2
}
}

0 comments on commit 5a91c83

Please sign in to comment.