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/walk.go b/src/cmd/compile/internal/gc/walk.go
index f324d5e..acc923a 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -29,33 +29,34 @@
// Final typecheck for any unused variables.
// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
- for l := fn.Func.Dcl; l != nil; l = l.Next {
- if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
- typecheck(&l.N, Erv|Easgn)
+ for i, ln := range fn.Func.Dcl {
+ if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
+ typecheck(&ln, Erv|Easgn)
+ fn.Func.Dcl[i] = ln
}
}
// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
- for l := fn.Func.Dcl; l != nil; l = l.Next {
- if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used {
- l.N.Name.Defn.Left.Used = true
+ for _, ln := range fn.Func.Dcl {
+ if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
+ ln.Name.Defn.Left.Used = true
}
}
- for l := fn.Func.Dcl; l != nil; l = l.Next {
- if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
+ for _, ln := range fn.Func.Dcl {
+ if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used {
continue
}
- if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
+ if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
if defn.Left.Used {
continue
}
lineno = defn.Left.Lineno
- Yyerror("%v declared and not used", l.N.Sym)
+ Yyerror("%v declared and not used", ln.Sym)
defn.Left.Used = true // suppress repeats
} else {
- lineno = l.N.Lineno
- Yyerror("%v declared and not used", l.N.Sym)
+ lineno = ln.Lineno
+ Yyerror("%v declared and not used", ln.Sym)
}
}
@@ -92,11 +93,11 @@
}
func paramoutheap(fn *Node) bool {
- for l := fn.Func.Dcl; l != nil; l = l.Next {
- switch l.N.Class {
+ for _, ln := range fn.Func.Dcl {
+ switch ln.Class {
case PPARAMOUT,
PPARAMOUT | PHEAP:
- return l.N.Addrtaken
+ return ln.Addrtaken
// stop early - parameters are over
case PAUTO,
@@ -290,13 +291,13 @@
var rl *NodeList
var cl Class
- for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
- cl = ll.N.Class &^ PHEAP
+ for _, ln := range Curfn.Func.Dcl {
+ cl = ln.Class &^ PHEAP
if cl == PAUTO {
break
}
if cl == PPARAMOUT {
- rl = list(rl, ll.N)
+ rl = list(rl, ln)
}
}