]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: make ir.StaticValue safer
authorMatthew Dempsky <mdempsky@google.com>
Tue, 5 Jan 2021 11:27:46 +0000 (03:27 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 5 Jan 2021 14:04:03 +0000 (14:04 +0000)
ir.StaticValue currently relies on CaptureVars setting Addrtaken for
variables that are assigned within nested function literals. We want
to move that logic to escape analysis, but ir.StaticValue is used in
inlining and devirtualization, which happen before escape
analysis.

The long-term solution here is to generalize escape analysis's precise
reassignment tracking for use by other optimization passes, but for
now we just generalize ir.StaticValue to not depend on Addrtaken
anymore. Instead, it now also pays attention to OADDR nodes as well as
recurses into OCLOSURE bodies.

Passes toolstash -cmp.

Change-Id: I6114e3277fb70b235f4423d2983d0433c881f79f
Reviewed-on: https://go-review.googlesource.com/c/go/+/281540
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/ir/expr.go

index 6d81bf8781ef5bd3c30fed98eca7b3821b6346a4..77b6c8a1037de75b9eb6351806ec881e7fe62312 100644 (file)
@@ -771,7 +771,7 @@ func staticValue1(nn Node) Node {
                return nil
        }
        n := nn.(*Name)
-       if n.Class != PAUTO || n.Addrtaken() {
+       if n.Class != PAUTO {
                return nil
        }
 
@@ -823,23 +823,51 @@ func reassigned(name *Name) bool {
        if name.Curfn == nil {
                return true
        }
-       return Any(name.Curfn, func(n Node) bool {
+
+       // TODO(mdempsky): This is inefficient and becoming increasingly
+       // unwieldy. Figure out a way to generalize escape analysis's
+       // reassignment detection for use by inlining and devirtualization.
+
+       // isName reports whether n is a reference to name.
+       isName := func(n Node) bool {
+               if n, ok := n.(*Name); ok && n.Op() == ONAME {
+                       if n.IsClosureVar() && n.Defn != nil {
+                               n = n.Defn.(*Name)
+                       }
+                       return n == name
+               }
+               return false
+       }
+
+       var do func(n Node) bool
+       do = func(n Node) bool {
                switch n.Op() {
                case OAS:
                        n := n.(*AssignStmt)
-                       if n.X == name && n != name.Defn {
+                       if isName(n.X) && n != name.Defn {
                                return true
                        }
                case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:
                        n := n.(*AssignListStmt)
                        for _, p := range n.Lhs {
-                               if p == name && n != name.Defn {
+                               if isName(p) && n != name.Defn {
                                        return true
                                }
                        }
+               case OADDR:
+                       n := n.(*AddrExpr)
+                       if isName(OuterValue(n.X)) {
+                               return true
+                       }
+               case OCLOSURE:
+                       n := n.(*ClosureExpr)
+                       if Any(n.Func, do) {
+                               return true
+                       }
                }
                return false
-       })
+       }
+       return Any(name.Curfn, do)
 }
 
 // IsIntrinsicCall reports whether the compiler back end will treat the call as an intrinsic operation.