From 0153137a3b40e58572ae9678e4733bb54827950a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 2 Mar 2015 21:25:33 -0500 Subject: [PATCH] cmd/internal/gc: clean up liveness code - use Bvec, not *Bvec, and bulk allocate backing store - use range loops - put Bvecs in BasicBlock struct instead of indexing into parallel slices Change-Id: I5cb30f50dccb4d38cc18fae422f7f132c52876be Reviewed-on: https://go-review.googlesource.com/6602 Reviewed-by: Rob Pike --- src/cmd/internal/gc/bv.go | 63 ++++-- src/cmd/internal/gc/go.go | 5 - src/cmd/internal/gc/plive.go | 365 +++++++++++++---------------------- src/cmd/internal/gc/walk.go | 4 +- 4 files changed, 183 insertions(+), 254 deletions(-) diff --git a/src/cmd/internal/gc/bv.go b/src/cmd/internal/gc/bv.go index e7fdd70b71..07b17bb937 100644 --- a/src/cmd/internal/gc/bv.go +++ b/src/cmd/internal/gc/bv.go @@ -13,24 +13,51 @@ const ( WORDSHIFT = 5 ) +// A Bvec is a bit vector. +type Bvec struct { + n int32 // number of bits in vector + b []uint32 // words holding bits +} + func bvsize(n uint32) uint32 { return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE } -func bvbits(bv *Bvec) int32 { +func bvbits(bv Bvec) int32 { return bv.n } -func bvwords(bv *Bvec) int32 { +func bvwords(bv Bvec) int32 { return (bv.n + WORDBITS - 1) / WORDBITS } -func bvalloc(n int32) *Bvec { - return &Bvec{n, make([]uint32, bvsize(uint32(n))/4)} +func bvalloc(n int32) Bvec { + return Bvec{n, make([]uint32, bvsize(uint32(n))/4)} +} + +type bulkBvec struct { + words []uint32 + nbit int32 + nword int32 +} + +func bvbulkalloc(nbit int32, count int32) bulkBvec { + nword := (nbit + WORDBITS - 1) / WORDBITS + return bulkBvec{ + words: make([]uint32, nword*count), + nbit: nbit, + nword: nword, + } +} + +func (b *bulkBvec) next() Bvec { + out := Bvec{b.nbit, b.words[:b.nword]} + b.words = b.words[b.nword:] + return out } /* difference */ -func bvandnot(dst *Bvec, src1 *Bvec, src2 *Bvec) { +func bvandnot(dst Bvec, src1 Bvec, src2 Bvec) { var i int32 var w int32 @@ -44,7 +71,7 @@ func bvandnot(dst *Bvec, src1 *Bvec, src2 *Bvec) { } } -func bvcmp(bv1 *Bvec, bv2 *Bvec) int { +func bvcmp(bv1 Bvec, bv2 Bvec) int { if bv1.n != bv2.n { Fatal("bvequal: lengths %d and %d are not equal", bv1.n, bv2.n) } @@ -56,13 +83,13 @@ func bvcmp(bv1 *Bvec, bv2 *Bvec) int { return 0 } -func bvcopy(dst *Bvec, src *Bvec) { +func bvcopy(dst Bvec, src Bvec) { for i, x := range src.b { dst.b[i] = x } } -func bvconcat(src1 *Bvec, src2 *Bvec) *Bvec { +func bvconcat(src1 Bvec, src2 Bvec) Bvec { dst := bvalloc(src1.n + src2.n) for i := int32(0); i < src1.n; i++ { if bvget(src1, i) != 0 { @@ -77,7 +104,7 @@ func bvconcat(src1 *Bvec, src2 *Bvec) *Bvec { return dst } -func bvget(bv *Bvec, i int32) int { +func bvget(bv Bvec, i int32) int { if i < 0 || i >= bv.n { Fatal("bvget: index %d is out of bounds with length %d\n", i, bv.n) } @@ -86,7 +113,7 @@ func bvget(bv *Bvec, i int32) int { // bvnext returns the smallest index >= i for which bvget(bv, i) == 1. // If there is no such index, bvnext returns -1. -func bvnext(bv *Bvec, i int32) int { +func bvnext(bv Bvec, i int32) int { if i >= bv.n { return -1 } @@ -115,7 +142,7 @@ func bvnext(bv *Bvec, i int32) int { return int(i) } -func bvisempty(bv *Bvec) bool { +func bvisempty(bv Bvec) bool { for i := int32(0); i < bv.n; i += WORDBITS { if bv.b[i>>WORDSHIFT] != 0 { return false @@ -124,7 +151,7 @@ func bvisempty(bv *Bvec) bool { return true } -func bvnot(bv *Bvec) { +func bvnot(bv Bvec) { var i int32 var w int32 @@ -136,7 +163,7 @@ func bvnot(bv *Bvec) { } /* union */ -func bvor(dst *Bvec, src1 *Bvec, src2 *Bvec) { +func bvor(dst Bvec, src1 Bvec, src2 Bvec) { var i int32 var w int32 @@ -151,7 +178,7 @@ func bvor(dst *Bvec, src1 *Bvec, src2 *Bvec) { } /* intersection */ -func bvand(dst *Bvec, src1 *Bvec, src2 *Bvec) { +func bvand(dst Bvec, src1 Bvec, src2 Bvec) { var i int32 var w int32 @@ -165,14 +192,14 @@ func bvand(dst *Bvec, src1 *Bvec, src2 *Bvec) { } } -func bvprint(bv *Bvec) { +func bvprint(bv Bvec) { fmt.Printf("#*") for i := int32(0); i < bv.n; i++ { fmt.Printf("%d", bvget(bv, i)) } } -func bvreset(bv *Bvec, i int32) { +func bvreset(bv Bvec, i int32) { if i < 0 || i >= bv.n { Fatal("bvreset: index %d is out of bounds with length %d\n", i, bv.n) } @@ -180,13 +207,13 @@ func bvreset(bv *Bvec, i int32) { bv.b[i/WORDBITS] &= mask } -func bvresetall(bv *Bvec) { +func bvresetall(bv Bvec) { for i := range bv.b { bv.b[i] = 0 } } -func bvset(bv *Bvec, i int32) { +func bvset(bv Bvec, i int32) { if i < 0 || i >= bv.n { Fatal("bvset: index %d is out of bounds with length %d\n", i, bv.n) } diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index d23cdd4959..2d460f75c0 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -100,11 +100,6 @@ type Array struct { data string } -type Bvec struct { - n int32 - b []uint32 -} - type Pkg struct { Name string Path string diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go index ba13cdb1c3..229489f025 100644 --- a/src/cmd/internal/gc/plive.go +++ b/src/cmd/internal/gc/plive.go @@ -41,6 +41,13 @@ type BasicBlock struct { rpo int mark int lastbitmapindex int + uevar Bvec + varkill Bvec + livein Bvec + liveout Bvec + avarinit Bvec + avarinitany Bvec + avarinitall Bvec } // A collection of global state used by liveness analysis. @@ -49,15 +56,8 @@ type Liveness struct { ptxt *obj.Prog vars []*Node cfg []*BasicBlock - uevar []*Bvec - varkill []*Bvec - livein []*Bvec - liveout []*Bvec - avarinit []*Bvec - avarinitany []*Bvec - avarinitall []*Bvec - argslivepointers []*Bvec - livepointers []*Bvec + argslivepointers []Bvec + livepointers []Bvec } func xmalloc(size uint32) interface{} { @@ -143,23 +143,16 @@ func splicebefore(lv *Liveness, bb *BasicBlock, prev *obj.Prog, curr *obj.Prog) // A pretty printer for basic blocks. func printblock(bb *BasicBlock) { - var pred *BasicBlock - fmt.Printf("basic block %d\n", bb.rpo) fmt.Printf("\tpred:") - for i := 0; i < len(bb.pred); i++ { - pred = bb.pred[i] + for _, pred := range bb.pred { fmt.Printf(" %d", pred.rpo) } - fmt.Printf("\n") fmt.Printf("\tsucc:") - var succ *BasicBlock - for i := 0; i < len(bb.succ); i++ { - succ = bb.succ[i] + for _, succ := range bb.succ { fmt.Printf(" %d", succ.rpo) } - fmt.Printf("\n") fmt.Printf("\tprog:\n") for prog := bb.first; ; prog = prog.Link { @@ -231,10 +224,7 @@ func getvariables(fn *Node) []*Node { // A pretty printer for control flow graphs. Takes an array of BasicBlock*s. func printcfg(cfg []*BasicBlock) { - var bb *BasicBlock - - for i := int32(0); i < int32(len(cfg)); i++ { - bb = cfg[i] + for _, bb := range cfg { printblock(bb) } } @@ -242,16 +232,12 @@ func printcfg(cfg []*BasicBlock) { // Assigns a reverse post order number to each connected basic block using the // standard algorithm. Unconnected blocks will not be affected. func reversepostorder(root *BasicBlock, rpo *int32) { - var bb *BasicBlock - root.mark = VISITED - for i := 0; i < len(root.succ); i++ { - bb = root.succ[i] + for _, bb := range root.succ { if bb.mark == UNVISITED { reversepostorder(bb, rpo) } } - *rpo -= 1 root.rpo = int(*rpo) } @@ -282,18 +268,18 @@ func iscall(prog *obj.Prog, name *obj.LSym) bool { // Returns true for instructions that call a runtime function implementing a // select communication clause. -var isselectcommcasecall_names [5]*obj.LSym +var selectNames [4]*obj.LSym func isselectcommcasecall(prog *obj.Prog) bool { - if isselectcommcasecall_names[0] == nil { - isselectcommcasecall_names[0] = Linksym(Pkglookup("selectsend", Runtimepkg)) - isselectcommcasecall_names[1] = Linksym(Pkglookup("selectrecv", Runtimepkg)) - isselectcommcasecall_names[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg)) - isselectcommcasecall_names[3] = Linksym(Pkglookup("selectdefault", Runtimepkg)) + if selectNames[0] == nil { + selectNames[0] = Linksym(Pkglookup("selectsend", Runtimepkg)) + selectNames[1] = Linksym(Pkglookup("selectrecv", Runtimepkg)) + selectNames[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg)) + selectNames[3] = Linksym(Pkglookup("selectdefault", Runtimepkg)) } - for i := int32(0); isselectcommcasecall_names[i] != nil; i++ { - if iscall(prog, isselectcommcasecall_names[i]) { + for _, name := range selectNames { + if iscall(prog, name) { return true } } @@ -374,10 +360,7 @@ func addselectgosucc(selectgo *BasicBlock) { // The entry point for the missing selectgo control flow algorithm. Takes an // array of BasicBlock*s containing selectgo calls. func fixselectgo(selectgo []*BasicBlock) { - var bb *BasicBlock - - for i := int32(0); i < int32(len(selectgo)); i++ { - bb = selectgo[i] + for _, bb := range selectgo { addselectgosucc(bb) } } @@ -432,10 +415,8 @@ func newcfg(firstp *obj.Prog) []*BasicBlock { // Loop through all basic blocks maximally growing the list of // contained instructions until a label is reached. Add edges // for branches and fall-through instructions. - var p *obj.Prog - for i := int32(0); i < int32(len(cfg)); i++ { - bb = cfg[i] - for p = bb.last; p != nil; p = p.Link { + for _, bb := range cfg { + for p := bb.last; p != nil; p = p.Link { if p.Opt != nil && p != bb.last { break } @@ -467,11 +448,9 @@ func newcfg(firstp *obj.Prog) []*BasicBlock { // Add back links so the instructions in a basic block can be traversed // backward. This is the final state of the instruction opt field. - var prev *obj.Prog - for i := int32(0); i < int32(len(cfg)); i++ { - bb = cfg[i] - p = bb.first - prev = nil + for _, bb := range cfg { + p := bb.first + var prev *obj.Prog for { p.Opt = prev if p == bb.last { @@ -489,11 +468,9 @@ func newcfg(firstp *obj.Prog) []*BasicBlock { // Find a depth-first order and assign a depth-first number to // all basic blocks. - for i := int32(0); i < int32(len(cfg)); i++ { - bb = cfg[i] + for _, bb := range cfg { bb.mark = UNVISITED } - bb = cfg[0] rpo := int32(len(cfg)) reversepostorder(bb, &rpo) @@ -503,11 +480,10 @@ func newcfg(firstp *obj.Prog) []*BasicBlock { // node being the root. sort.Sort(blockrpocmp(cfg)) - bb = cfg[0] - // Unreachable control flow nodes are indicated by a -1 in the rpo // field. If we see these nodes something must have gone wrong in an // upstream compilation phase. + bb = cfg[0] if bb.rpo == -1 { fmt.Printf("newcfg: unreachable basic block for %v\n", bb.last) printcfg(cfg) @@ -520,18 +496,11 @@ func newcfg(firstp *obj.Prog) []*BasicBlock { // Frees a control flow graph (an array of BasicBlock*s) and all of its leaf // data structures. func freecfg(cfg []*BasicBlock) { - n := int32(len(cfg)) - if n > 0 { + if len(cfg) > 0 { bb0 := cfg[0] for p := bb0.first; p != nil; p = p.Link { p.Opt = nil } - - var bb *BasicBlock - for i := int32(0); i < n; i++ { - bb = cfg[i] - freeblock(bb) - } } } @@ -555,7 +524,7 @@ func isfunny(n *Node) bool { // The avarinit output serves as a signal that the data has been // initialized, because any use of a variable must come after its // initialization. -func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avarinit *Bvec) { +func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarinit Bvec) { bvresetall(uevar) bvresetall(varkill) bvresetall(avarinit) @@ -572,12 +541,10 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avari // all the parameters for correctness, and similarly it must not // read the out arguments - they won't be set until the new // function runs. - var node *Node - for i := int32(0); i < int32(len(vars)); i++ { - node = vars[i] + for i, node := range vars { switch node.Class &^ PHEAP { case PPARAM: - bvset(uevar, i) + bvset(uevar, int32(i)) // If the result had its address taken, it is being tracked // by the avarinit code, which does not use uevar. @@ -589,7 +556,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avari // the for loop for details. case PPARAMOUT: if node.Addrtaken == 0 && prog.To.Type == obj.TYPE_NONE { - bvset(uevar, i) + bvset(uevar, int32(i)) } } } @@ -600,15 +567,13 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avari if prog.As == obj.ATEXT { // A text instruction marks the entry point to a function and // the definition point of all in arguments. - var node *Node - for i := int32(0); i < int32(len(vars)); i++ { - node = vars[i] + for i, node := range vars { switch node.Class &^ PHEAP { case PPARAM: if node.Addrtaken != 0 { - bvset(avarinit, i) + bvset(avarinit, int32(i)) } - bvset(varkill, i) + bvset(varkill, int32(i)) } } @@ -701,27 +666,20 @@ func newliveness(fn *Node, ptxt *obj.Prog, cfg []*BasicBlock, vars []*Node) *Liv result.vars = vars nblocks := int32(len(cfg)) - result.uevar = make([]*Bvec, nblocks) - result.varkill = make([]*Bvec, nblocks) - result.livein = make([]*Bvec, nblocks) - result.liveout = make([]*Bvec, nblocks) - result.avarinit = make([]*Bvec, nblocks) - result.avarinitany = make([]*Bvec, nblocks) - result.avarinitall = make([]*Bvec, nblocks) - nvars := int32(len(vars)) - for i := int32(0); i < nblocks; i++ { - result.uevar[i] = bvalloc(nvars) - result.varkill[i] = bvalloc(nvars) - result.livein[i] = bvalloc(nvars) - result.liveout[i] = bvalloc(nvars) - result.avarinit[i] = bvalloc(nvars) - result.avarinitany[i] = bvalloc(nvars) - result.avarinitall[i] = bvalloc(nvars) - } - - result.livepointers = make([]*Bvec, 0, 0) - result.argslivepointers = make([]*Bvec, 0, 0) + bulk := bvbulkalloc(nvars, nblocks*7) + for _, bb := range cfg { + bb.uevar = bulk.next() + bb.varkill = bulk.next() + bb.livein = bulk.next() + bb.liveout = bulk.next() + bb.avarinit = bulk.next() + bb.avarinitany = bulk.next() + bb.avarinitall = bulk.next() + } + + result.livepointers = make([]Bvec, 0, 0) + result.argslivepointers = make([]Bvec, 0, 0) return result } @@ -730,18 +688,9 @@ func freeliveness(lv *Liveness) { if lv == nil { Fatal("freeliveness: cannot free nil") } - - for i := int32(0); i < int32(len(lv.livepointers)); i++ { - } - - for i := int32(0); i < int32(len(lv.argslivepointers)); i++ { - } - - for i := int32(0); i < int32(len(lv.cfg)); i++ { - } } -func printeffects(p *obj.Prog, uevar *Bvec, varkill *Bvec, avarinit *Bvec) { +func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) { fmt.Printf("effects of %v", p) fmt.Printf("\nuevar: ") bvprint(uevar) @@ -768,11 +717,11 @@ func printnode(node *Node) { } // Pretty print a list of variables. The vars argument is an array of Node*s. -func printvars(name string, bv *Bvec, vars []*Node) { +func printvars(name string, bv Bvec, vars []*Node) { fmt.Printf("%s:", name) - for i := int32(0); i < int32(len(vars)); i++ { - if bvget(bv, i) != 0 { - printnode(vars[i]) + for i, node := range vars { + if bvget(bv, int32(i)) != 0 { + printnode(node) } } fmt.Printf("\n") @@ -781,43 +730,34 @@ func printvars(name string, bv *Bvec, vars []*Node) { // Prints a basic block annotated with the information computed by liveness // analysis. func livenessprintblock(lv *Liveness, bb *BasicBlock) { - var pred *BasicBlock - fmt.Printf("basic block %d\n", bb.rpo) fmt.Printf("\tpred:") - for i := 0; i < len(bb.pred); i++ { - pred = bb.pred[i] + for _, pred := range bb.pred { fmt.Printf(" %d", pred.rpo) } - fmt.Printf("\n") fmt.Printf("\tsucc:") - var succ *BasicBlock - for i := 0; i < len(bb.succ); i++ { - succ = bb.succ[i] + for _, succ := range bb.succ { fmt.Printf(" %d", succ.rpo) } - fmt.Printf("\n") - printvars("\tuevar", lv.uevar[bb.rpo], []*Node(lv.vars)) - printvars("\tvarkill", lv.varkill[bb.rpo], []*Node(lv.vars)) - printvars("\tlivein", lv.livein[bb.rpo], []*Node(lv.vars)) - printvars("\tliveout", lv.liveout[bb.rpo], []*Node(lv.vars)) - printvars("\tavarinit", lv.avarinit[bb.rpo], []*Node(lv.vars)) - printvars("\tavarinitany", lv.avarinitany[bb.rpo], []*Node(lv.vars)) - printvars("\tavarinitall", lv.avarinitall[bb.rpo], []*Node(lv.vars)) + printvars("\tuevar", bb.uevar, []*Node(lv.vars)) + printvars("\tvarkill", bb.varkill, []*Node(lv.vars)) + printvars("\tlivein", bb.livein, []*Node(lv.vars)) + printvars("\tliveout", bb.liveout, []*Node(lv.vars)) + printvars("\tavarinit", bb.avarinit, []*Node(lv.vars)) + printvars("\tavarinitany", bb.avarinitany, []*Node(lv.vars)) + printvars("\tavarinitall", bb.avarinitall, []*Node(lv.vars)) fmt.Printf("\tprog:\n") - var live *Bvec - var pos int32 for prog := bb.first; ; prog = prog.Link { fmt.Printf("\t\t%v", prog) if prog.As == obj.APCDATA && prog.From.Offset == obj.PCDATA_StackMapIndex { - pos = int32(prog.To.Offset) - live = lv.livepointers[pos] + pos := int32(prog.To.Offset) + live := lv.livepointers[pos] fmt.Printf(" ") bvprint(live) } @@ -832,10 +772,7 @@ func livenessprintblock(lv *Liveness, bb *BasicBlock) { // Prints a control flow graph annotated with any information computed by // liveness analysis. func livenessprintcfg(lv *Liveness) { - var bb *BasicBlock - - for i := int32(0); i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] + for _, bb := range lv.cfg { livenessprintblock(lv, bb) } } @@ -919,7 +856,7 @@ func checkptxt(fn *Node, firstp *obj.Prog) { // and then simply copied into bv at the correct offset on future calls with // the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1 // accounts for 40% of the 6g execution time. -func twobitwalktype1(t *Type, xoffset *int64, bv *Bvec) { +func twobitwalktype1(t *Type, xoffset *int64, bv Bvec) { if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 { Fatal("twobitwalktype1: invalid initial alignment, %v", Tconv(t, 0)) } @@ -1027,7 +964,7 @@ func argswords() int32 { // Generates live pointer value maps for arguments and local variables. The // this argument and the in arguments are always assumed live. The vars // argument is an array of Node*s. -func twobitlivepointermap(lv *Liveness, liveout *Bvec, vars []*Node, args *Bvec, locals *Bvec) { +func twobitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) { var node *Node var xoffset int64 @@ -1100,39 +1037,34 @@ func issafepoint(prog *obj.Prog) bool { // instructions in each basic block to summarizes the information at each basic // block func livenessprologue(lv *Liveness) { - var bb *BasicBlock - var p *obj.Prog - nvars := int32(len(lv.vars)) uevar := bvalloc(nvars) varkill := bvalloc(nvars) avarinit := bvalloc(nvars) - for i := int32(0); i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] - + for _, bb := range lv.cfg { // Walk the block instructions backward and update the block // effects with the each prog effects. - for p = bb.last; p != nil; p = p.Opt.(*obj.Prog) { + for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) { progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit) if debuglive >= 3 { printeffects(p, uevar, varkill, avarinit) } - bvor(lv.varkill[i], lv.varkill[i], varkill) - bvandnot(lv.uevar[i], lv.uevar[i], varkill) - bvor(lv.uevar[i], lv.uevar[i], uevar) + bvor(bb.varkill, bb.varkill, varkill) + bvandnot(bb.uevar, bb.uevar, varkill) + bvor(bb.uevar, bb.uevar, uevar) } // Walk the block instructions forward to update avarinit bits. // avarinit describes the effect at the end of the block, not the beginning. bvresetall(varkill) - for p = bb.first; ; p = p.Link { + for p := bb.first; ; p = p.Link { progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit) if debuglive >= 3 { printeffects(p, uevar, varkill, avarinit) } - bvandnot(lv.avarinit[i], lv.avarinit[i], varkill) - bvor(lv.avarinit[i], lv.avarinit[i], avarinit) + bvandnot(bb.avarinit, bb.avarinit, varkill) + bvor(bb.avarinit, bb.avarinit, avarinit) if p == bb.last { break } @@ -1142,9 +1074,6 @@ func livenessprologue(lv *Liveness) { // Solve the liveness dataflow equations. func livenesssolve(lv *Liveness) { - var bb *BasicBlock - var rpo int32 - // These temporary bitvectors exist to avoid successive allocations and // frees within the loop. newlivein := bvalloc(int32(len(lv.vars))) @@ -1156,53 +1085,44 @@ func livenesssolve(lv *Liveness) { // Push avarinitall, avarinitany forward. // avarinitall says the addressed var is initialized along all paths reaching the block exit. // avarinitany says the addressed var is initialized along some path reaching the block exit. - for i := int32(0); i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] - rpo = int32(bb.rpo) + for i, bb := range lv.cfg { if i == 0 { - bvcopy(lv.avarinitall[rpo], lv.avarinit[rpo]) + bvcopy(bb.avarinitall, bb.avarinit) } else { - bvresetall(lv.avarinitall[rpo]) - bvnot(lv.avarinitall[rpo]) + bvresetall(bb.avarinitall) + bvnot(bb.avarinitall) } - - bvcopy(lv.avarinitany[rpo], lv.avarinit[rpo]) + bvcopy(bb.avarinitany, bb.avarinit) } change := int32(1) - var j int32 - var i int32 - var pred *BasicBlock for change != 0 { change = 0 - for i = 0; i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] - rpo = int32(bb.rpo) + for _, bb := range lv.cfg { bvresetall(any) bvresetall(all) - for j = 0; j < int32(len(bb.pred)); j++ { - pred = bb.pred[j] + for j, pred := range bb.pred { if j == 0 { - bvcopy(any, lv.avarinitany[pred.rpo]) - bvcopy(all, lv.avarinitall[pred.rpo]) + bvcopy(any, pred.avarinitany) + bvcopy(all, pred.avarinitall) } else { - bvor(any, any, lv.avarinitany[pred.rpo]) - bvand(all, all, lv.avarinitall[pred.rpo]) + bvor(any, any, pred.avarinitany) + bvand(all, all, pred.avarinitall) } } - bvandnot(any, any, lv.varkill[rpo]) - bvandnot(all, all, lv.varkill[rpo]) - bvor(any, any, lv.avarinit[rpo]) - bvor(all, all, lv.avarinit[rpo]) - if bvcmp(any, lv.avarinitany[rpo]) != 0 { + bvandnot(any, any, bb.varkill) + bvandnot(all, all, bb.varkill) + bvor(any, any, bb.avarinit) + bvor(all, all, bb.avarinit) + if bvcmp(any, bb.avarinitany) != 0 { change = 1 - bvcopy(lv.avarinitany[rpo], any) + bvcopy(bb.avarinitany, any) } - if bvcmp(all, lv.avarinitall[rpo]) != 0 { + if bvcmp(all, bb.avarinitall) != 0 { change = 1 - bvcopy(lv.avarinitall[rpo], all) + bvcopy(bb.avarinitall, all) } } } @@ -1212,29 +1132,26 @@ func livenesssolve(lv *Liveness) { // so low that it hardly seems to be worth the complexity. change = 1 - var succ *BasicBlock for change != 0 { change = 0 // Walk blocks in the general direction of propagation. This // improves convergence. - for i = int32(len(lv.cfg)) - 1; i >= 0; i-- { + for i := len(lv.cfg) - 1; i >= 0; i-- { + bb := lv.cfg[i] + // A variable is live on output from this block // if it is live on input to some successor. // // out[b] = \bigcup_{s \in succ[b]} in[s] - bb = lv.cfg[i] - - rpo = int32(bb.rpo) bvresetall(newliveout) - for j = 0; j < int32(len(bb.succ)); j++ { - succ = bb.succ[j] - bvor(newliveout, newliveout, lv.livein[succ.rpo]) + for _, succ := range bb.succ { + bvor(newliveout, newliveout, succ.livein) } - if bvcmp(lv.liveout[rpo], newliveout) != 0 { + if bvcmp(bb.liveout, newliveout) != 0 { change = 1 - bvcopy(lv.liveout[rpo], newliveout) + bvcopy(bb.liveout, newliveout) } // A variable is live on input to this block @@ -1242,16 +1159,16 @@ func livenesssolve(lv *Liveness) { // not set by the code in this block. // // in[b] = uevar[b] \cup (out[b] \setminus varkill[b]) - bvandnot(newlivein, lv.liveout[rpo], lv.varkill[rpo]) + bvandnot(newlivein, bb.liveout, bb.varkill) - bvor(lv.livein[rpo], newlivein, lv.uevar[rpo]) + bvor(bb.livein, newlivein, bb.uevar) } } } // This function is slow but it is only used for generating debug prints. // Check whether n is marked live in args/locals. -func islive(n *Node, args *Bvec, locals *Bvec) bool { +func islive(n *Node, args Bvec, locals Bvec) bool { switch n.Class { case PPARAM, PPARAMOUT: @@ -1275,10 +1192,9 @@ func islive(n *Node, args *Bvec, locals *Bvec) bool { // Visits all instructions in a basic block and computes a bit vector of live // variables at each safe point locations. func livenessepilogue(lv *Liveness) { - var bb *BasicBlock var pred *BasicBlock - var args *Bvec - var locals *Bvec + var args Bvec + var locals Bvec var n *Node var p *obj.Prog var j int32 @@ -1297,9 +1213,7 @@ func livenessepilogue(lv *Liveness) { nmsg := int32(0) startmsg := int32(0) - for i := int32(0); i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] - + for _, bb := range lv.cfg { // Compute avarinitany and avarinitall for entry to block. // This duplicates information known during livenesssolve // but avoids storing two more vectors for each block. @@ -1309,11 +1223,11 @@ func livenessepilogue(lv *Liveness) { for j = 0; j < int32(len(bb.pred)); j++ { pred = bb.pred[j] if j == 0 { - bvcopy(any, lv.avarinitany[pred.rpo]) - bvcopy(all, lv.avarinitall[pred.rpo]) + bvcopy(any, pred.avarinitany) + bvcopy(all, pred.avarinitall) } else { - bvor(any, any, lv.avarinitany[pred.rpo]) - bvand(all, all, lv.avarinitall[pred.rpo]) + bvor(any, any, pred.avarinitany) + bvand(all, all, pred.avarinitall) } } @@ -1390,9 +1304,7 @@ func livenessepilogue(lv *Liveness) { var next *obj.Prog var numlive int32 var msg []string - for i := int32(0); i < int32(len(lv.cfg)); i++ { - bb = lv.cfg[i] - + for _, bb := range lv.cfg { if debuglive >= 1 && Curfn.Nname.Sym.Name != "init" && Curfn.Nname.Sym.Name[0] != '.' { nmsg = int32(len(lv.livepointers)) startmsg = nmsg @@ -1411,7 +1323,7 @@ func livenessepilogue(lv *Liveness) { Fatal("livenessepilogue") } - bvcopy(livein, lv.liveout[bb.rpo]) + bvcopy(livein, bb.liveout) for p = bb.last; p != nil; p = next { next = p.Opt.(*obj.Prog) // splicebefore modifies p->opt @@ -1535,7 +1447,7 @@ const ( Hp = 16777619 ) -func hashbitmap(h uint32, bv *Bvec) uint32 { +func hashbitmap(h uint32, bv Bvec) uint32 { var w uint32 n := int((bv.n + 31) / 32) @@ -1589,12 +1501,12 @@ func livenesscompact(lv *Liveness) { // record in remap, record in lv->livepointers and lv->argslivepointers // under the new index, and add entry to hash table. // If already seen, record earlier index in remap and free bitmaps. - var jarg *Bvec + var jarg Bvec var j int var h uint32 - var arg *Bvec - var jlocal *Bvec - var local *Bvec + var arg Bvec + var jlocal Bvec + var local Bvec for i := 0; i < n; i++ { local = lv.livepointers[i] arg = lv.argslivepointers[i] @@ -1632,8 +1544,8 @@ func livenesscompact(lv *Liveness) { // array so that we can tell where the coalesced bitmaps stop // and so that we don't double-free when cleaning up. for j := uniq; j < n; j++ { - lv.livepointers[j] = nil - lv.argslivepointers[j] = nil + lv.livepointers[j] = Bvec{} + lv.argslivepointers[j] = Bvec{} } // Rewrite PCDATA instructions to use new numbering. @@ -1648,11 +1560,9 @@ func livenesscompact(lv *Liveness) { } } -func printbitset(printed int, name string, vars []*Node, bits *Bvec) int { - var n *Node - +func printbitset(printed int, name string, vars []*Node, bits Bvec) int { started := 0 - for i := 0; i < len(vars); i++ { + for i, n := range vars { if bvget(bits, int32(i)) == 0 { continue } @@ -1669,7 +1579,6 @@ func printbitset(printed int, name string, vars []*Node, bits *Bvec) int { fmt.Printf(",") } - n = vars[i] fmt.Printf("%s", n.Sym.Name) } @@ -1682,10 +1591,9 @@ func printbitset(printed int, name string, vars []*Node, bits *Bvec) int { func livenessprintdebug(lv *Liveness) { var j int var printed int - var bb *BasicBlock var p *obj.Prog - var args *Bvec - var locals *Bvec + var args Bvec + var locals Bvec var n *Node fmt.Printf("liveness: %s\n", Curfn.Nname.Sym.Name) @@ -1695,11 +1603,10 @@ func livenessprintdebug(lv *Liveness) { avarinit := bvalloc(int32(len(lv.vars))) pcdata := 0 - for i := 0; i < len(lv.cfg); i++ { + for i, bb := range lv.cfg { if i > 0 { fmt.Printf("\n") } - bb = lv.cfg[i] // bb#0 pred=1,2 succ=3,4 fmt.Printf("bb#%d pred=", i) @@ -1724,8 +1631,8 @@ func livenessprintdebug(lv *Liveness) { // initial settings printed = 0 - printed = printbitset(printed, "uevar", lv.vars, lv.uevar[bb.rpo]) - printed = printbitset(printed, "livein", lv.vars, lv.livein[bb.rpo]) + printed = printbitset(printed, "uevar", lv.vars, bb.uevar) + printed = printbitset(printed, "livein", lv.vars, bb.livein) if printed != 0 { fmt.Printf("\n") } @@ -1772,11 +1679,11 @@ func livenessprintdebug(lv *Liveness) { // bb bitsets fmt.Printf("end\n") - printed = printbitset(printed, "varkill", lv.vars, lv.varkill[bb.rpo]) - printed = printbitset(printed, "liveout", lv.vars, lv.liveout[bb.rpo]) - printed = printbitset(printed, "avarinit", lv.vars, lv.avarinit[bb.rpo]) - printed = printbitset(printed, "avarinitany", lv.vars, lv.avarinitany[bb.rpo]) - printed = printbitset(printed, "avarinitall", lv.vars, lv.avarinitall[bb.rpo]) + printed = printbitset(printed, "varkill", lv.vars, bb.varkill) + printed = printbitset(printed, "liveout", lv.vars, bb.liveout) + printed = printbitset(printed, "avarinit", lv.vars, bb.avarinit) + printed = printbitset(printed, "avarinitany", lv.vars, bb.avarinitany) + printed = printbitset(printed, "avarinitall", lv.vars, bb.avarinitall) if printed != 0 { fmt.Printf("\n") } @@ -1790,7 +1697,7 @@ func livenessprintdebug(lv *Liveness) { // length of the bitmaps. All bitmaps are assumed to be of equal length. The // words that are followed are the raw bitmap words. The arr argument is an // array of Node*s. -func twobitwritesymbol(arr []*Bvec, sym *Sym) { +func twobitwritesymbol(arr []Bvec, sym *Sym) { var i int var j int var word uint32 @@ -1804,7 +1711,7 @@ func twobitwritesymbol(arr []*Bvec, sym *Sym) { // bitmap words bv = arr[i] - if bv == nil { + if bv.b == nil { break } for j = 0; int32(j) < bv.n; j += 32 { diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index 0992c181cd..14396440f7 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -2196,7 +2196,7 @@ func needwritebarrier(l *Node, r *Node) bool { // TODO(rsc): Perhaps componentgen should run before this. -var applywritebarrier_bv *Bvec +var applywritebarrier_bv Bvec func applywritebarrier(n *Node, init **NodeList) *Node { if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { @@ -2216,7 +2216,7 @@ func applywritebarrier(n *Node, init **NodeList) *Node { n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right) } else if t.Width <= int64(4*Widthptr) { x := int64(0) - if applywritebarrier_bv == nil { + if applywritebarrier_bv.b == nil { applywritebarrier_bv = bvalloc(obj.BitsPerPointer * 4) } bvresetall(applywritebarrier_bv) -- 2.48.1