Commit e52d317d authored by Austin Clements's avatar Austin Clements

cmd/compile: convert ishairy into a visitor

The inliner's ishairy passes a budget and a reason down through the
walk. Lift these into a visitor object and turn ishairy and its
helpers into methods.

This will make it easy to add more state.

Change-Id: Ic6ae246e1affd67ed283c3205f9595ae33e22215
Reviewed-on: https://go-review.googlesource.com/41151
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 24c52ee5
...@@ -151,11 +151,12 @@ func caninl(fn *Node) { ...@@ -151,11 +151,12 @@ func caninl(fn *Node) {
} }
const maxBudget = 80 const maxBudget = 80
budget := int32(maxBudget) // allowed hairyness visitor := hairyVisitor{budget: maxBudget}
if ishairylist(fn.Nbody, &budget, &reason) { if visitor.visitList(fn.Nbody) {
reason = visitor.reason
return return
} }
if budget < 0 { if visitor.budget < 0 {
reason = "function too complex" reason = "function too complex"
return return
} }
...@@ -169,7 +170,7 @@ func caninl(fn *Node) { ...@@ -169,7 +170,7 @@ func caninl(fn *Node) {
fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice())) fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
inldcl := inlcopylist(n.Name.Defn.Func.Dcl) inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
n.Func.Inldcl.Set(inldcl) n.Func.Inldcl.Set(inldcl)
n.Func.InlCost = maxBudget - budget n.Func.InlCost = maxBudget - visitor.budget
// hack, TODO, check for better way to link method nodes back to the thing with the ->inl // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
// this is so export can find the body of a method // this is so export can find the body of a method
...@@ -184,17 +185,24 @@ func caninl(fn *Node) { ...@@ -184,17 +185,24 @@ func caninl(fn *Node) {
Curfn = savefn Curfn = savefn
} }
// hairyVisitor visits a function body to determine its inlining
// hairiness and whether or not it can be inlined.
type hairyVisitor struct {
budget int32
reason string
}
// Look for anything we want to punt on. // Look for anything we want to punt on.
func ishairylist(ll Nodes, budget *int32, reason *string) bool { func (v *hairyVisitor) visitList(ll Nodes) bool {
for _, n := range ll.Slice() { for _, n := range ll.Slice() {
if ishairy(n, budget, reason) { if v.visit(n) {
return true return true
} }
} }
return false return false
} }
func ishairy(n *Node, budget *int32, reason *string) bool { func (v *hairyVisitor) visit(n *Node) bool {
if n == nil { if n == nil {
return false return false
} }
...@@ -203,7 +211,7 @@ func ishairy(n *Node, budget *int32, reason *string) bool { ...@@ -203,7 +211,7 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
// Call is okay if inlinable and we have the budget for the body. // Call is okay if inlinable and we have the budget for the body.
case OCALLFUNC: case OCALLFUNC:
if isIntrinsicCall(n) { if isIntrinsicCall(n) {
*budget-- v.budget--
break break
} }
// Functions that call runtime.getcaller{pc,sp} can not be inlined // Functions that call runtime.getcaller{pc,sp} can not be inlined
...@@ -211,24 +219,24 @@ func ishairy(n *Node, budget *int32, reason *string) bool { ...@@ -211,24 +219,24 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
if n.Left.Op == ONAME && n.Left.Class == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) { if n.Left.Op == ONAME && n.Left.Class == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
fn := n.Left.Sym.Name fn := n.Left.Sym.Name
if fn == "getcallerpc" || fn == "getcallersp" { if fn == "getcallerpc" || fn == "getcallersp" {
*reason = "call to " + fn v.reason = "call to " + fn
return true return true
} }
} }
if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 { if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
*budget -= fn.InlCost v.budget -= fn.InlCost
break break
} }
if n.isMethodCalledAsFunction() { if n.isMethodCalledAsFunction() {
if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 { if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
*budget -= d.Func.InlCost v.budget -= d.Func.InlCost
break break
} }
} }
if Debug['l'] < 4 { if Debug['l'] < 4 {
*reason = "non-leaf function" v.reason = "non-leaf function"
return true return true
} }
...@@ -242,18 +250,18 @@ func ishairy(n *Node, budget *int32, reason *string) bool { ...@@ -242,18 +250,18 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
Fatalf("no function definition for [%p] %+v\n", t, t) Fatalf("no function definition for [%p] %+v\n", t, t)
} }
if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 { if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
*budget -= inlfn.InlCost v.budget -= inlfn.InlCost
break break
} }
if Debug['l'] < 4 { if Debug['l'] < 4 {
*reason = "non-leaf method" v.reason = "non-leaf method"
return true return true
} }
// Things that are too hairy, irrespective of the budget // Things that are too hairy, irrespective of the budget
case OCALL, OCALLINTER, OPANIC, ORECOVER: case OCALL, OCALLINTER, OPANIC, ORECOVER:
if Debug['l'] < 4 { if Debug['l'] < 4 {
*reason = "non-leaf op " + n.Op.String() v.reason = "non-leaf op " + n.Op.String()
return true return true
} }
...@@ -269,30 +277,30 @@ func ishairy(n *Node, budget *int32, reason *string) bool { ...@@ -269,30 +277,30 @@ func ishairy(n *Node, budget *int32, reason *string) bool {
ODCLTYPE, // can't print yet ODCLTYPE, // can't print yet
OBREAK, OBREAK,
ORETJMP: ORETJMP:
*reason = "unhandled op " + n.Op.String() v.reason = "unhandled op " + n.Op.String()
return true return true
} }
(*budget)-- v.budget--
// TODO(mdempsky/josharian): Hacks to appease toolstash; remove. // TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
// See issue 17566 and CL 31674 for discussion. // See issue 17566 and CL 31674 for discussion.
switch n.Op { switch n.Op {
case OSTRUCTKEY: case OSTRUCTKEY:
(*budget)-- v.budget--
case OSLICE, OSLICEARR, OSLICESTR: case OSLICE, OSLICEARR, OSLICESTR:
(*budget)-- v.budget--
case OSLICE3, OSLICE3ARR: case OSLICE3, OSLICE3ARR:
*budget -= 2 v.budget -= 2
} }
if *budget < 0 { if v.budget < 0 {
*reason = "function too complex" v.reason = "function too complex"
return true return true
} }
return ishairy(n.Left, budget, reason) || ishairy(n.Right, budget, reason) || return v.visit(n.Left) || v.visit(n.Right) ||
ishairylist(n.List, budget, reason) || ishairylist(n.Rlist, budget, reason) || v.visitList(n.List) || v.visitList(n.Rlist) ||
ishairylist(n.Ninit, budget, reason) || ishairylist(n.Nbody, budget, reason) v.visitList(n.Ninit) || v.visitList(n.Nbody)
} }
// Inlcopy and inlcopylist recursively copy the body of a function. // Inlcopy and inlcopylist recursively copy the body of a function.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment