]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: in escape analysis, propagate loop depth to field
authorCherry Zhang <cherryyz@google.com>
Fri, 6 Apr 2018 20:21:26 +0000 (16:21 -0400)
committerCherry Zhang <cherryyz@google.com>
Fri, 13 Apr 2018 14:48:23 +0000 (14:48 +0000)
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 <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/gc/esc.go
test/escape5.go

index 421595057670788720166701aaedad82cd646824..fcb4e96a75c9551549ff975348e49fcce49d3227 100644 (file)
@@ -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:
@@ -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,
@@ -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
index 0bae1e840107c81525e3e4e1e4f30b3e2130ba00..d02f735f8fc1faa3eb17af59c2580978028a7b88 100644 (file)
@@ -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
+       }
+}