[dev.regabi] cmd/compile: make ir.StaticValue safer

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>
This commit is contained in:
Matthew Dempsky 2021-01-05 03:27:46 -08:00
parent 9aa950c407
commit e09783cbc0

View 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.