cmd/internal/gc: increase registerization limits

Also clean up code a little.

Change-Id: I23b7d2b7871b31e0974f1305e54f0c18dcab05d9
Reviewed-on: https://go-review.googlesource.com/7746
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go
index 4ec0ff2..1fbf79a 100644
--- a/src/cmd/6g/peep.go
+++ b/src/cmd/6g/peep.go
@@ -326,7 +326,7 @@
 	}
 
 	if b == nil {
-		if gc.Debug['v'] != 0 {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 			fmt.Printf("no pushback: %v\n", r0.Prog)
 			if r != nil {
 				fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil)
@@ -336,7 +336,7 @@
 		return
 	}
 
-	if gc.Debug['v'] != 0 {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("pushback\n")
 		for r := (*gc.Flow)(b); ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
@@ -366,7 +366,7 @@
 	p0.From = t.From
 	p0.To = t.To
 
-	if gc.Debug['v'] != 0 {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("\tafter\n")
 		for r := (*gc.Flow)(b); ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
diff --git a/src/cmd/internal/gc/bits.go b/src/cmd/internal/gc/bits.go
deleted file mode 100644
index 6e6ffe9..0000000
--- a/src/cmd/internal/gc/bits.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Inferno utils/cc/bits.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package gc
-
-import "fmt"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] | b.b[i];
-	return c;
-}
-
-Bits
-band(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] & b.b[i];
-	return c;
-}
-
-Bits
-bnot(Bits a)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = ~a.b[i];
-	return c;
-}
-*/
-func bany(a *Bits) bool {
-	for i := 0; i < BITS; i++ {
-		if a.b[i] != 0 {
-			return true
-		}
-	}
-	return false
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a.b[i] != b.b[i])
-			return 0;
-	return 1;
-}
-*/
-func bnum(a Bits) int {
-	var b uint64
-
-	for i := 0; i < BITS; i++ {
-		b = a.b[i]
-		if b != 0 {
-			return 64*i + Bitno(b)
-		}
-	}
-
-	Fatal("bad in bnum")
-	return 0
-}
-
-func blsh(n uint) Bits {
-	c := zbits
-	c.b[n/64] = 1 << (n % 64)
-	return c
-}
-
-func btest(a *Bits, n uint) bool {
-	return a.b[n/64]&(1<<(n%64)) != 0
-}
-
-func biset(a *Bits, n uint) {
-	a.b[n/64] |= 1 << (n % 64)
-}
-
-func biclr(a *Bits, n uint) {
-	a.b[n/64] &^= (1 << (n % 64))
-}
-
-func Bitno(b uint64) int {
-	for i := 0; i < 64; i++ {
-		if b&(1<<uint(i)) != 0 {
-			return i
-		}
-	}
-	Fatal("bad in bitno")
-	return 0
-}
-
-func Qconv(bits Bits, flag int) string {
-	var fp string
-
-	var i int
-
-	first := 1
-
-	for bany(&bits) {
-		i = bnum(bits)
-		if first != 0 {
-			first = 0
-		} else {
-			fp += " "
-		}
-		if var_[i].node == nil || var_[i].node.Sym == nil {
-			fp += fmt.Sprintf("$%d", i)
-		} else {
-			fp += fmt.Sprintf("%s(%d)", var_[i].node.Sym.Name, i)
-			if var_[i].offset != 0 {
-				fp += fmt.Sprintf("%+d", int64(var_[i].offset))
-			}
-		}
-
-		biclr(&bits, uint(i))
-	}
-
-	return fp
-}
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index b88f77e..e33b6f5 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -351,30 +351,6 @@
 	Ecomplit  = 1 << 11 // type in composite literal
 )
 
-const (
-	BITS = 3
-	NVAR = BITS * 64
-)
-
-type Bits struct {
-	b [BITS]uint64
-}
-
-var zbits Bits
-
-type Var struct {
-	offset     int64
-	node       *Node
-	nextinnode *Var
-	width      int
-	id         int
-	name       int8
-	etype      int8
-	addr       int8
-}
-
-var var_ [NVAR]Var
-
 type Typedef struct {
 	Name   string
 	Etype  int
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/internal/gc/popt.go
index 8dcd1df..ac6dd5e 100644
--- a/src/cmd/internal/gc/popt.go
+++ b/src/cmd/internal/gc/popt.go
@@ -1,44 +1,3 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package gc
-
-import (
-	"cmd/internal/obj"
-	"fmt"
-	"sort"
-	"strings"
-)
-
-// "Portable" optimizations.
-
 // Derived from Inferno utils/6c/gc.h
 // http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
 //
@@ -69,92 +28,17 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-const (
-	CLOAD = 5
-	CREF  = 5
-	CINF  = 1000
-	LOOP  = 3
+// "Portable" optimizations.
+
+package gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"sort"
+	"strings"
 )
 
-type Reg struct {
-	set  Bits // regopt variables written by this instruction.
-	use1 Bits // regopt variables read by prog->from.
-	use2 Bits // regopt variables read by prog->to.
-
-	// refahead/refbehind are the regopt variables whose current
-	// value may be used in the following/preceding instructions
-	// up to a CALL (or the value is clobbered).
-	refbehind Bits
-	refahead  Bits
-
-	// calahead/calbehind are similar, but for variables in
-	// instructions that are reachable after hitting at least one
-	// CALL.
-	calbehind Bits
-	calahead  Bits
-
-	regdiff Bits
-	act     Bits
-	regu    uint64 // register used bitmap
-}
-
-type Rgn struct {
-	enter *Flow
-	cost  int16
-	varno int16
-	regno int16
-}
-
-var Z *Node
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-
-var R *Reg
-
-const (
-	NRGN = 600
-)
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches.  A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-
-var zreg Reg
-
-var region [NRGN]Rgn
-
-var rgp *Rgn
-
-var nregion int
-
-var nvar int
-
-var regbits uint64
-
-var externs Bits
-
-var params Bits
-
-var consts Bits
-
-var addrs Bits
-
-var ivar Bits
-
-var ovar Bits
-
-var change int
-
-var maxnr int32
-
 type OptStats struct {
 	Ncvtreg int32
 	Nspill  int32
@@ -354,6 +238,11 @@
 
 var flowmark int
 
+// MaxFlowProg is the maximum size program (counted in instructions)
+// for which the flow code will build a graph. Functions larger than this limit
+// will not have flow graphs and consequently will not be optimized.
+const MaxFlowProg = 50000
+
 func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
 	// Count and mark instructions to annotate.
 	nf := 0
@@ -372,8 +261,10 @@
 		return nil
 	}
 
-	if nf >= 20000 {
-		// fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
+	if nf >= MaxFlowProg {
+		if Debug['v'] != 0 {
+			Warn("%v is too big (%d instructions)", Sconv(Curfn.Nname.Sym, 0), nf)
+		}
 		return nil
 	}
 
@@ -678,7 +569,7 @@
 
 func mergetemp(firstp *obj.Prog) {
 	const (
-		debugmerge = 1
+		debugmerge = 0
 	)
 
 	g := Flowstart(firstp, nil)
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/internal/gc/reg.go
index d1aa343..37fd3c3 100644
--- a/src/cmd/internal/gc/reg.go
+++ b/src/cmd/internal/gc/reg.go
@@ -31,14 +31,111 @@
 package gc
 
 import (
+	"bytes"
 	"cmd/internal/obj"
 	"fmt"
 	"sort"
+	"strings"
 )
 
-var firstf *Flow
+// A Var represents a single variable that may be stored in a register.
+// That variable may itself correspond to a hardware register,
+// to represent the use of registers in the unoptimized instruction stream.
+type Var struct {
+	offset     int64
+	node       *Node
+	nextinnode *Var
+	width      int
+	id         int // index in vars
+	name       int8
+	etype      int8
+	addr       int8
+}
 
-var first int = 1
+// Bits represents a set of Vars, stored as a bit set of var numbers
+// (the index in vars, or equivalently v.id).
+type Bits struct {
+	b [BITS]uint64
+}
+
+const (
+	BITS = 3
+	NVAR = BITS * 64
+)
+
+var (
+	vars [NVAR]Var // variables under consideration
+	nvar int       // number of vars
+
+	regbits uint64 // bits for hardware registers
+
+	zbits   Bits // zero
+	externs Bits // global variables
+	params  Bits // function parameters and results
+	ivar    Bits // function parameters (inputs)
+	ovar    Bits // function results (outputs)
+	consts  Bits // constant values
+	addrs   Bits // variables with address taken
+)
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+type Reg struct {
+	set  Bits // regopt variables written by this instruction.
+	use1 Bits // regopt variables read by prog->from.
+	use2 Bits // regopt variables read by prog->to.
+
+	// refahead/refbehind are the regopt variables whose current
+	// value may be used in the following/preceding instructions
+	// up to a CALL (or the value is clobbered).
+	refbehind Bits
+	refahead  Bits
+
+	// calahead/calbehind are similar, but for variables in
+	// instructions that are reachable after hitting at least one
+	// CALL.
+	calbehind Bits
+	calahead  Bits
+
+	regdiff Bits
+	act     Bits
+	regu    uint64 // register used bitmap
+}
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches.
+// A single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
+type Rgn struct {
+	enter *Flow
+	cost  int16
+	varno int16
+	regno int16
+}
+
+// The Plan 9 C compilers used a limit of 600 regions,
+// but the yacc-generated parser in y.go has 3100 regions.
+// We set MaxRgn large enough to handle that.
+// There's not a huge cost to having too many regions:
+// the main processing traces the live area for each variable,
+// which is limited by the number of variables times the area,
+// not the raw region count. If there are many regions, they
+// are almost certainly small and easy to trace.
+// The only operation that scales with region count is the
+// sorting by cost, which uses sort.Sort and is therefore
+// guaranteed n log n.
+const MaxRgn = 6000
+
+var (
+	region  []Rgn
+	nregion int
+)
 
 type rcmp []Rgn
 
@@ -75,13 +172,13 @@
 		// convert each bit to a variable
 		i = bnum(bit)
 
-		node = var_[i].node
-		n = int(var_[i].name)
+		node = vars[i].node
+		n = int(vars[i].name)
 		biclr(&bit, uint(i))
 
 		// disable all pieces of that variable
 		for i = 0; i < nvar; i++ {
-			v = &var_[i]
+			v = &vars[i]
 			if v.node == node && int(v.name) == n {
 				v.addr = 2
 			}
@@ -135,7 +232,7 @@
 	p.Link = p1
 	p1.Lineno = p.Lineno
 
-	v := &var_[bn]
+	v := &vars[bn]
 
 	a := &p1.To
 	a.Offset = v.offset
@@ -223,7 +320,7 @@
 		fallthrough
 
 	case obj.TYPE_MEM:
-		if r != R {
+		if r != nil {
 			r.use1.b[0] |= Thearch.RtoB(int(a.Reg))
 		}
 
@@ -233,11 +330,16 @@
 		*/
 		switch a.Name {
 		default:
+			// Note: This case handles NAME_EXTERN and NAME_STATIC.
+			// We treat these as requiring eager writes to memory, due to
+			// the possibility of a fault handler looking at them, so there is
+			// not much point in registerizing the loads.
+			// If we later choose the set of candidate variables from a
+			// larger list, these cases could be deprioritized instead of
+			// removed entirely.
 			return zbits
 
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC,
-			obj.NAME_PARAM,
+		case obj.NAME_PARAM,
 			obj.NAME_AUTO:
 			n = int(a.Name)
 		}
@@ -264,7 +366,7 @@
 	flag := 0
 	var v *Var
 	for i := 0; i < nvar; i++ {
-		v = &var_[i]
+		v = &vars[i]
 		if v.node == node && int(v.name) == n {
 			if v.offset == o {
 				if int(v.etype) == et {
@@ -297,6 +399,9 @@
 		if Debug['w'] > 1 && node != nil {
 			Fatal("variable not optimized: %v", Nconv(node, obj.FmtSharp))
 		}
+		if Debug['v'] > 0 {
+			Warn("variable not optimized: %v", Nconv(node, obj.FmtSharp))
+		}
 
 		// If we're not tracking a word in a variable, mark the rest as
 		// having its address taken, so that we keep the whole thing
@@ -304,7 +409,7 @@
 		// a variable but not all of it.
 		var v *Var
 		for i := 0; i < nvar; i++ {
-			v = &var_[i]
+			v = &vars[i]
 			if v.node == node {
 				v.addr = 1
 			}
@@ -315,7 +420,7 @@
 
 	i := nvar
 	nvar++
-	v = &var_[i]
+	v = &vars[i]
 	v.id = i
 	v.offset = o
 	v.name = int8(n)
@@ -394,6 +499,8 @@
 	return bit
 }
 
+var change int
+
 func prop(f *Flow, ref Bits, cal Bits) {
 	var f1 *Flow
 	var r1 *Reg
@@ -408,13 +515,13 @@
 			ref.b[z] |= r1.refahead.b[z]
 			if ref.b[z] != r1.refahead.b[z] {
 				r1.refahead.b[z] = ref.b[z]
-				change++
+				change = 1
 			}
 
 			cal.b[z] |= r1.calahead.b[z]
 			if cal.b[z] != r1.calahead.b[z] {
 				r1.calahead.b[z] = cal.b[z]
-				change++
+				change = 1
 			}
 		}
 
@@ -456,7 +563,7 @@
 					if z*64+i >= nvar || (cal.b[z]>>uint(i))&1 == 0 {
 						continue
 					}
-					v = &var_[z*64+i]
+					v = &vars[z*64+i]
 					if v.node.Opt == nil { // v represents fixed register, not Go variable
 						continue
 					}
@@ -527,7 +634,7 @@
 			dif.b[z] = dif.b[z]&^(^r1.refbehind.b[z]&r1.refahead.b[z]) | r1.set.b[z] | r1.regdiff.b[z]
 			if dif.b[z] != r1.regdiff.b[z] {
 				r1.regdiff.b[z] = dif.b[z]
-				change++
+				change = 1
 			}
 		}
 
@@ -545,7 +652,7 @@
 }
 
 func allreg(b uint64, r *Rgn) uint64 {
-	v := &var_[r.varno]
+	v := &vars[r.varno]
 	r.regno = 0
 	switch v.etype {
 	default:
@@ -591,6 +698,13 @@
 	return ^r.calbehind.b[z] & r.calahead.b[z]
 }
 
+// Cost parameters
+const (
+	CLOAD = 5 // cost of load
+	CREF  = 5 // cost of reference if not registerized
+	LOOP  = 3 // loop execution count (applied in popt.go)
+)
+
 func paint1(f *Flow, bn int) {
 	z := bn / 64
 	bb := uint64(1 << uint(bn%64))
@@ -855,31 +969,31 @@
 		if bany(&bit) {
 			fmt.Printf("\t")
 			if bany(&r.set) {
-				fmt.Printf(" s:%v", Qconv(r.set, 0))
+				fmt.Printf(" s:%v", &r.set)
 			}
 			if bany(&r.use1) {
-				fmt.Printf(" u1:%v", Qconv(r.use1, 0))
+				fmt.Printf(" u1:%v", &r.use1)
 			}
 			if bany(&r.use2) {
-				fmt.Printf(" u2:%v", Qconv(r.use2, 0))
+				fmt.Printf(" u2:%v", &r.use2)
 			}
 			if bany(&r.refbehind) {
-				fmt.Printf(" rb:%v ", Qconv(r.refbehind, 0))
+				fmt.Printf(" rb:%v ", &r.refbehind)
 			}
 			if bany(&r.refahead) {
-				fmt.Printf(" ra:%v ", Qconv(r.refahead, 0))
+				fmt.Printf(" ra:%v ", &r.refahead)
 			}
 			if bany(&r.calbehind) {
-				fmt.Printf(" cb:%v ", Qconv(r.calbehind, 0))
+				fmt.Printf(" cb:%v ", &r.calbehind)
 			}
 			if bany(&r.calahead) {
-				fmt.Printf(" ca:%v ", Qconv(r.calahead, 0))
+				fmt.Printf(" ca:%v ", &r.calahead)
 			}
 			if bany(&r.regdiff) {
-				fmt.Printf(" d:%v ", Qconv(r.regdiff, 0))
+				fmt.Printf(" d:%v ", &r.regdiff)
 			}
 			if bany(&r.act) {
-				fmt.Printf(" a:%v ", Qconv(r.act, 0))
+				fmt.Printf(" a:%v ", &r.act)
 			}
 		}
 	}
@@ -922,10 +1036,6 @@
 }
 
 func regopt(firstp *obj.Prog) {
-	if first != 0 {
-		first = 0
-	}
-
 	mergetemp(firstp)
 
 	/*
@@ -938,13 +1048,13 @@
 
 	nvar = nreg
 	for i := 0; i < nreg; i++ {
-		var_[i] = Var{}
+		vars[i] = Var{}
 	}
 	for i := 0; i < nreg; i++ {
 		if regnodes[i] == nil {
 			regnodes[i] = newname(Lookup(regnames[i]))
 		}
-		var_[i].node = regnodes[i]
+		vars[i].node = regnodes[i]
 	}
 
 	regbits = Thearch.Excludedregs()
@@ -962,15 +1072,14 @@
 	 * find use and set of variables
 	 */
 	g := Flowstart(firstp, func() interface{} { return new(Reg) })
-
 	if g == nil {
 		for i := 0; i < nvar; i++ {
-			var_[i].node.Opt = nil
+			vars[i].node.Opt = nil
 		}
 		return
 	}
 
-	firstf = g.Start
+	firstf := g.Start
 
 	for f := firstf; f != nil; f = f.Link {
 		p := f.Prog
@@ -1035,7 +1144,7 @@
 	}
 
 	for i := 0; i < nvar; i++ {
-		v := &var_[i]
+		v := &vars[i]
 		if v.addr != 0 {
 			bit := blsh(uint(i))
 			for z := 0; z < BITS; z++ {
@@ -1176,10 +1285,8 @@
 	 * isolate regions
 	 * calculate costs (paint1)
 	 */
-	f = firstf
-
 	var bit Bits
-	if f != nil {
+	if f := firstf; f != nil {
 		r := f.Data.(*Reg)
 		for z := 0; z < BITS; z++ {
 			bit.b[z] = (r.refahead.b[z] | r.calahead.b[z]) &^ (externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z])
@@ -1187,7 +1294,7 @@
 		if bany(&bit) && f.Refset == 0 {
 			// should never happen - all variables are preset
 			if Debug['w'] != 0 {
-				fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), Qconv(bit, 0))
+				fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), &bit)
 			}
 			f.Refset = 1
 		}
@@ -1197,6 +1304,7 @@
 		(f.Data.(*Reg)).act = zbits
 	}
 	nregion = 0
+	region = region[:0]
 	var rgp *Rgn
 	for f := firstf; f != nil; f = f.Link {
 		r := f.Data.(*Reg)
@@ -1205,7 +1313,7 @@
 		}
 		if bany(&bit) && f.Refset == 0 {
 			if Debug['w'] != 0 {
-				fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), Qconv(bit, 0))
+				fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), &bit)
 			}
 			f.Refset = 1
 			Thearch.Excise(f)
@@ -1222,22 +1330,30 @@
 			if change <= 0 {
 				continue
 			}
-			if nregion >= NRGN {
-				if Debug['R'] != 0 && Debug['v'] != 0 {
-					fmt.Printf("too many regions\n")
-				}
-				goto brk
+			if nregion >= MaxRgn {
+				nregion++
+				continue
 			}
 
-			rgp = &region[nregion]
-			rgp.enter = f
-			rgp.varno = int16(i)
-			rgp.cost = int16(change)
+			region = append(region, Rgn{
+				enter: f,
+				cost:  int16(change),
+				varno: int16(i),
+			})
 			nregion++
 		}
 	}
 
-brk:
+	if Debug['v'] != 0 && strings.Contains(Curfn.Nname.Sym.Name, "Parse") {
+		Warn("regions: %d\n", nregion)
+	}
+	if nregion >= MaxRgn {
+		if Debug['v'] != 0 {
+			Warn("too many regions: %d\n", nregion)
+		}
+		nregion = MaxRgn
+	}
+
 	sort.Sort(rcmp(region[:nregion]))
 
 	if Debug['R'] != 0 && Debug['v'] != 0 {
@@ -1264,7 +1380,7 @@
 		vreg = allreg(usedreg, rgp)
 		if rgp.regno != 0 {
 			if Debug['R'] != 0 && Debug['v'] != 0 {
-				v := &var_[rgp.varno]
+				v := &vars[rgp.varno]
 				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", Nconv(v.node, 0), v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
 			}
 
@@ -1276,7 +1392,7 @@
 	 * free aux structures. peep allocates new ones.
 	 */
 	for i := 0; i < nvar; i++ {
-		var_[i].node.Opt = nil
+		vars[i].node.Opt = nil
 	}
 	Flowend(g)
 	firstf = nil
@@ -1284,7 +1400,6 @@
 	if Debug['R'] != 0 && Debug['v'] != 0 {
 		// Rebuild flow graph, since we inserted instructions
 		g := Flowstart(firstp, nil)
-
 		firstf = g.Start
 		Dumpit("pass6", firstf, 0)
 		Flowend(g)
@@ -1340,3 +1455,107 @@
 		Ostats = OptStats{}
 	}
 }
+
+// bany reports whether any bits in a are set.
+func bany(a *Bits) bool {
+	for _, x := range &a.b { // & to avoid making a copy of a.b
+		if x != 0 {
+			return true
+		}
+	}
+	return false
+}
+
+// bnum reports the lowest index of a 1 bit in a.
+func bnum(a Bits) int {
+	for i, x := range &a.b { // & to avoid making a copy of a.b
+		if x != 0 {
+			return 64*i + Bitno(x)
+		}
+	}
+
+	Fatal("bad in bnum")
+	return 0
+}
+
+// blsh returns a Bits with 1 at index n, 0 elsewhere (1<<n).
+func blsh(n uint) Bits {
+	c := zbits
+	c.b[n/64] = 1 << (n % 64)
+	return c
+}
+
+// btest reports whether bit n is 1.
+func btest(a *Bits, n uint) bool {
+	return a.b[n/64]&(1<<(n%64)) != 0
+}
+
+// biset sets bit n to 1.
+func biset(a *Bits, n uint) {
+	a.b[n/64] |= 1 << (n % 64)
+}
+
+// biclr sets bit n to 0.
+func biclr(a *Bits, n uint) {
+	a.b[n/64] &^= (1 << (n % 64))
+}
+
+// Bitno reports the lowest index of a 1 bit in b.
+// It calls Fatal if there is no 1 bit.
+func Bitno(b uint64) int {
+	if b == 0 {
+		Fatal("bad in bitno")
+	}
+	n := 0
+	if b&(1<<32-1) == 0 {
+		n += 32
+		b >>= 32
+	}
+	if b&(1<<16-1) == 0 {
+		n += 16
+		b >>= 16
+	}
+	if b&(1<<8-1) == 0 {
+		n += 8
+		b >>= 8
+	}
+	if b&(1<<4-1) == 0 {
+		n += 4
+		b >>= 4
+	}
+	if b&(1<<2-1) == 0 {
+		n += 2
+		b >>= 2
+	}
+	if b&1 == 0 {
+		n++
+	}
+	return n
+}
+
+// String returns a space-separated list of the variables represented by bits.
+func (bits Bits) String() string {
+	// Note: This method takes a value receiver, both for convenience
+	// and to make it safe to modify the bits as we process them.
+	// Even so, most prints above use &bits, because then the value
+	// being stored in the interface{} is a pointer and does not require
+	// an allocation and copy to create the interface{}.
+	var buf bytes.Buffer
+	sep := ""
+	for bany(&bits) {
+		i := bnum(bits)
+		buf.WriteString(sep)
+		sep = " "
+		v := &vars[i]
+		if v.node == nil || v.node.Sym == nil {
+			fmt.Fprintf(&buf, "$%d", i)
+		} else {
+			fmt.Fprintf(&buf, "%s(%d)", v.node.Sym.Name, i)
+			if v.offset != 0 {
+				fmt.Fprintf(&buf, "%+d", int64(v.offset))
+			}
+		}
+		biclr(&bits, uint(i))
+	}
+	return buf.String()
+}