cmd/compile: change Node.Nbody, Func.Inl from *NodeList to Nodes
Passes toolstash -cmp.
Casual timings show about a 3% improvement in compile times.
Update #14473.
Change-Id: I584add2e8f1a52486ba418b25ba6122b7347b643
Reviewed-on: https://go-review.googlesource.com/19989
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index f5c3265..8406565 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -79,7 +79,7 @@
}
if Debug['m'] > 2 {
- fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
+ fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconvslice(fn.Func.Inl.Slice(), obj.FmtSharp))
}
save_safemode := safemode
@@ -87,7 +87,7 @@
savefn := Curfn
Curfn = fn
- typechecklist(fn.Func.Inl, Etop)
+ typecheckslice(fn.Func.Inl.Slice(), Etop)
Curfn = savefn
safemode = save_safemode
@@ -112,7 +112,7 @@
}
// If fn has no body (is defined outside of Go), cannot inline it.
- if fn.Nbody == nil {
+ if len(fn.Nbody.Slice()) == 0 {
return
}
@@ -141,15 +141,15 @@
const maxBudget = 80
budget := maxBudget // allowed hairyness
- if ishairylist(fn.Nbody, &budget) || budget < 0 {
+ if ishairyslice(fn.Nbody.Slice(), &budget) || budget < 0 {
return
}
savefn := Curfn
Curfn = fn
- fn.Func.Nname.Func.Inl = fn.Nbody
- fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
+ fn.Func.Nname.Func.Inl.Set(fn.Nbody.Slice())
+ fn.Nbody.Set(inlcopyslice(fn.Func.Nname.Func.Inl.Slice()))
inldcl := inlcopyslice(fn.Func.Nname.Name.Defn.Func.Dcl)
if len(inldcl) > 0 {
fn.Func.Nname.Func.Inldcl = &inldcl
@@ -161,7 +161,7 @@
fn.Type.Nname = fn.Func.Nname
if Debug['m'] > 1 {
- fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Nname.Func.Inl, obj.FmtSharp))
+ fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconvslice(fn.Func.Nname.Func.Inl.Slice(), obj.FmtSharp))
} else if Debug['m'] != 0 {
fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
}
@@ -179,6 +179,15 @@
return false
}
+func ishairyslice(ll []*Node, budget *int) bool {
+ for _, n := range ll {
+ if ishairy(n, budget) {
+ return true
+ }
+ }
+ return false
+}
+
func ishairy(n *Node, budget *int) bool {
if n == nil {
return false
@@ -187,12 +196,12 @@
switch n.Op {
// Call is okay if inlinable and we have the budget for the body.
case OCALLFUNC:
- if n.Left.Func != nil && n.Left.Func.Inl != nil {
+ if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Func.InlCost)
break
}
if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
- if n.Left.Sym.Def != nil && n.Left.Sym.Def.Func.Inl != nil {
+ if n.Left.Sym.Def != nil && len(n.Left.Sym.Def.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Sym.Def.Func.InlCost)
break
}
@@ -209,7 +218,7 @@
if n.Left.Type.Nname == nil {
Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
}
- if n.Left.Type.Nname.Func.Inl != nil {
+ if len(n.Left.Type.Nname.Func.Inl.Slice()) != 0 {
*budget -= int(n.Left.Type.Nname.Func.InlCost)
break
}
@@ -239,7 +248,7 @@
(*budget)--
- return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairylist(n.Nbody, budget)
+ return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairyslice(n.Nbody.Slice(), budget)
}
// Inlcopy and inlcopylist recursively copy the body of a function.
@@ -266,14 +275,14 @@
m := Nod(OXXX, nil, nil)
*m = *n
if m.Func != nil {
- m.Func.Inl = nil
+ m.Func.Inl.Set(nil)
}
m.Left = inlcopy(n.Left)
m.Right = inlcopy(n.Right)
m.List = inlcopylist(n.List)
m.Rlist = inlcopylist(n.Rlist)
m.Ninit = inlcopylist(n.Ninit)
- m.Nbody = inlcopylist(n.Nbody)
+ m.Nbody.Set(inlcopyslice(n.Nbody.Slice()))
return m
}
@@ -307,9 +316,9 @@
n.Op = OBLOCK
// n->ninit stays
- n.List = n.Nbody
+ n.List = n.Nbody.NodeList()
- n.Nbody = nil
+ n.Nbody.Set(nil)
n.Rlist = nil
}
@@ -317,7 +326,7 @@
func inlconv2expr(np **Node) {
n := *np
r := n.Rlist.N
- addinit(&r, concat(n.Ninit, n.Nbody))
+ addinit(&r, concat(n.Ninit, n.Nbody.NodeList()))
*np = r
}
@@ -332,7 +341,7 @@
}
l := n.Rlist
- addinit(&l.N, concat(n.Ninit, n.Nbody))
+ addinit(&l.N, concat(n.Ninit, n.Nbody.NodeList()))
return l
}
@@ -342,6 +351,12 @@
}
}
+func inlnodeslice(l []*Node) {
+ for i := range l {
+ inlnode(&l[i])
+ }
+}
+
// inlnode recurses over the tree to find inlineable calls, which will
// be turned into OINLCALLs by mkinlcall. When the recursion comes
// back up will examine left, right, list, rlist, ninit, ntest, nincr,
@@ -454,10 +469,10 @@
}
}
- inlnodelist(n.Nbody)
- for l := n.Nbody; l != nil; l = l.Next {
- if l.N.Op == OINLCALL {
- inlconv2stmt(l.N)
+ inlnodeslice(n.Nbody.Slice())
+ for _, n := range n.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
}
}
@@ -477,7 +492,7 @@
if Debug['m'] > 3 {
fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
}
- if n.Left.Func != nil && n.Left.Func.Inl != nil { // normal case
+ if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 { // normal case
mkinlcall(np, n.Left, n.Isddd)
} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
if n.Left.Sym.Def != nil {
@@ -539,7 +554,7 @@
// parameters.
func mkinlcall1(np **Node, fn *Node, isddd bool) {
// For variadic fn.
- if fn.Func.Inl == nil {
+ if len(fn.Func.Inl.Slice()) == 0 {
return
}
@@ -555,7 +570,7 @@
// Bingo, we have a function node, and it has an inlineable body
if Debug['m'] > 1 {
- fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
+ fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconvslice(fn.Func.Inl.Slice(), obj.FmtSharp))
} else if Debug['m'] != 0 {
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
}
@@ -796,19 +811,19 @@
inlretlabel = newlabel_inl()
inlgen++
- body := inlsubstlist(fn.Func.Inl)
+ body := inlsubstslice(fn.Func.Inl.Slice())
- body = list(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
- body = list(body, Nod(OLABEL, inlretlabel, nil))
+ body = append(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
+ body = append(body, Nod(OLABEL, inlretlabel, nil))
- typechecklist(body, Etop)
+ typecheckslice(body, Etop)
//dumplist("ninit post", ninit);
call := Nod(OINLCALL, nil, nil)
call.Ninit = ninit
- call.Nbody = body
+ call.Nbody.Set(body)
call.Rlist = inlretvars
call.Type = n.Type
call.Typecheck = 1
@@ -834,15 +849,15 @@
// instead we emit the things that the body needs
// and each use must redo the inlining.
// luckily these are small.
- body = fn.Func.Inl
- fn.Func.Inl = nil // prevent infinite recursion (shouldn't happen anyway)
- inlnodelist(call.Nbody)
- for ll := call.Nbody; ll != nil; ll = ll.Next {
- if ll.N.Op == OINLCALL {
- inlconv2stmt(ll.N)
+ body = fn.Func.Inl.Slice()
+ fn.Func.Inl.Set(nil) // prevent infinite recursion (shouldn't happen anyway)
+ inlnodeslice(call.Nbody.Slice())
+ for _, n := range call.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
}
}
- fn.Func.Inl = body
+ fn.Func.Inl.Set(body)
if Debug['m'] > 2 {
fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
@@ -907,8 +922,8 @@
return n
}
-// inlsubst and inlsubstlist recursively copy the body of the saved
-// pristine ->inl body of the function while substituting references
+// inlsubst, inlsubstlist, and inlsubstslice recursively copy the body of the
+// saved pristine ->inl body of the function while substituting references
// to input/output parameters with ones to the tmpnames, and
// substituting returns with assignments to the output.
func inlsubstlist(ll *NodeList) *NodeList {
@@ -919,6 +934,14 @@
return l
}
+func inlsubstslice(ll []*Node) []*Node {
+ l := make([]*Node, 0, len(ll))
+ for _, n := range ll {
+ l = append(l, inlsubst(n))
+ }
+ return l
+}
+
func inlsubst(n *Node) *Node {
if n == nil {
return nil
@@ -990,7 +1013,7 @@
m.List = inlsubstlist(n.List)
m.Rlist = inlsubstlist(n.Rlist)
m.Ninit = concat(m.Ninit, inlsubstlist(n.Ninit))
- m.Nbody = inlsubstlist(n.Nbody)
+ m.Nbody.Set(inlsubstslice(n.Nbody.Slice()))
return m
}
@@ -1002,6 +1025,12 @@
}
}
+func setlnoslice(ll []*Node, lno int) {
+ for _, n := range ll {
+ setlno(n, lno)
+ }
+}
+
func setlno(n *Node, lno int) {
if n == nil {
return
@@ -1017,5 +1046,5 @@
setlnolist(n.List, lno)
setlnolist(n.Rlist, lno)
setlnolist(n.Ninit, lno)
- setlnolist(n.Nbody, lno)
+ setlnoslice(n.Nbody.Slice(), lno)
}