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>
This commit is contained in:
Ian Lance Taylor 2016-02-25 10:35:19 -08:00
parent 67dbde0d71
commit b66a892358
21 changed files with 161 additions and 163 deletions

View file

@ -476,35 +476,35 @@ func escfunc(e *EscState, func_ *Node) {
savefn := Curfn
Curfn = func_
for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
if ll.N.Op != ONAME {
for _, ln := range Curfn.Func.Dcl {
if ln.Op != ONAME {
continue
}
llNE := e.nodeEscState(ll.N)
switch ll.N.Class {
llNE := e.nodeEscState(ln)
switch ln.Class {
// out params are in a loopdepth between the sink and all local variables
case PPARAMOUT:
llNE.Escloopdepth = 0
case PPARAM:
llNE.Escloopdepth = 1
if ll.N.Type != nil && !haspointers(ll.N.Type) {
if ln.Type != nil && !haspointers(ln.Type) {
break
}
if Curfn.Nbody == nil && !Curfn.Noescape {
ll.N.Esc = EscHeap
ln.Esc = EscHeap
} else {
ll.N.Esc = EscNone // prime for escflood later
ln.Esc = EscNone // prime for escflood later
}
e.noesc = list(e.noesc, ll.N)
e.noesc = list(e.noesc, ln)
}
}
// in a mutually recursive group we lose track of the return values
if e.recursive {
for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT {
escflows(e, &e.theSink, ll.N)
for _, ln := range Curfn.Func.Dcl {
if ln.Op == ONAME && ln.Class == PPARAMOUT {
escflows(e, &e.theSink, ln)
}
}
}
@ -779,11 +779,14 @@ func esc(e *EscState, n *Node, up *Node) {
ll = e.nodeEscState(n.List.N).Escretval
}
for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
for _, lrn := range Curfn.Func.Dcl {
if ll == nil {
break
}
if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
continue
}
escassign(e, lr.N, ll.N)
escassign(e, lrn, ll.N)
ll = ll.Next
}
@ -1870,16 +1873,16 @@ func esctag(e *EscState, func_ *Node) {
savefn := Curfn
Curfn = func_
for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
if ll.N.Op != ONAME {
for _, ln := range Curfn.Func.Dcl {
if ln.Op != ONAME {
continue
}
switch ll.N.Esc & EscMask {
switch ln.Esc & EscMask {
case EscNone, // not touched by escflood
EscReturn:
if haspointers(ll.N.Type) { // don't bother tagging for scalars
ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc))
if haspointers(ln.Type) { // don't bother tagging for scalars
ln.Name.Param.Field.Note = mktag(int(ln.Esc))
}
case EscHeap, // touched by escflood, moved to heap