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 = ®ion[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()
+}