cmd/compile: change Func.{Dcl,Inldcl} from NodeList to slice
A slice uses less memory than a NodeList, and has better memory locality
when walking the list.
This uncovered a tricky case involving closures: the escape analysis
pass when run on a closure was appending to the Dcl list of the OCLOSURE
rather than the ODCLFUNC. This happened to work because they shared the
same NodeList. Fixed with a change to addrescapes, and a check to
Tempname to catch any recurrences.
This removes the last use of the listsort function outside of tests.
I'll send a separate CL to remove it.
Unfortunately, while this passes all tests, it does not pass toolstash
-cmp. The problem is that cmpstackvarlt does not fully determine the
sort order, and the change from listsort to sort.Sort, while generally
desirable, produces a different ordering. I could stage this by first
making cmpstackvarlt fully determined, but no matter what toolstash -cmp
is going to break at some point.
In my casual testing the compiler is 2.2% faster.
Update #14473.
Change-Id: I367d66daa4ec73ed95c14c66ccda3a2133ad95d5
Reviewed-on: https://go-review.googlesource.com/19919
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 a445f71..cae15f9 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -150,7 +150,7 @@
fn.Func.Nname.Func.Inl = fn.Nbody
fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
- fn.Func.Nname.Func.Inldcl = inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl)
+ fn.Func.Nname.Func.Inldcl = inlcopyslice(fn.Func.Nname.Name.Defn.Func.Dcl)
fn.Func.Nname.Func.InlCost = int32(maxBudget - budget)
// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
@@ -275,6 +275,18 @@
return m
}
+// Inlcopyslice is like inlcopylist, but for a slice.
+func inlcopyslice(ll []*Node) []*Node {
+ r := make([]*Node, 0, len(ll))
+ for _, ln := range ll {
+ c := inlcopy(ln)
+ if c != nil {
+ r = append(r, c)
+ }
+ }
+ return r
+}
+
// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
// calls made to inlineable functions. This is the external entry point.
func inlcalls(fn *Node) {
@@ -556,7 +568,7 @@
//dumplist("ninit pre", ninit);
- var dcl *NodeList
+ var dcl []*Node
if fn.Name.Defn != nil { // local function
dcl = fn.Func.Inldcl // imported function
} else {
@@ -567,18 +579,18 @@
i := 0
// Make temp names to use instead of the originals
- for ll := dcl; ll != nil; ll = ll.Next {
- if ll.N.Class == PPARAMOUT { // return values handled below.
+ for _, ln := range dcl {
+ if ln.Class == PPARAMOUT { // return values handled below.
continue
}
- if ll.N.Op == ONAME {
- ll.N.Name.Inlvar = inlvar(ll.N)
+ if ln.Op == ONAME {
+ ln.Name.Inlvar = inlvar(ln)
// Typecheck because inlvar is not necessarily a function parameter.
- typecheck(&ll.N.Name.Inlvar, Erv)
+ typecheck(&ln.Name.Inlvar, Erv)
- if ll.N.Class&^PHEAP != PAUTO {
- ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
+ if ln.Class&^PHEAP != PAUTO {
+ ninit = list(ninit, Nod(ODCL, ln.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
}
}
}
@@ -852,7 +864,7 @@
addrescapes(n)
}
- Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
return n
}
@@ -863,7 +875,7 @@
n.Class = PAUTO
n.Used = true
n.Name.Curfn = Curfn // the calling function, not the called one
- Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
return n
}
@@ -875,7 +887,7 @@
n.Class = PAUTO
n.Used = true
n.Name.Curfn = Curfn // the calling function, not the called one
- Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
return n
}