vars []*Node
cfg []*BasicBlock
- // An array with a bit vector for each safe point tracking live pointers
- // in the arguments and locals area, indexed by bb.rpo.
- argslivepointers []bvec
- livepointers []bvec
+ // An array with a bit vector for each safe point tracking
+ // live variables, indexed by bb.rpo.
+ livevars []bvec
cache progeffectscache
}
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]
+ live := lv.livevars[pos]
fmt.Printf(" %s", live.String())
}
// These temporary bitvectors exist to avoid successive allocations and
// frees within the loop.
newlivein := bvalloc(int32(len(lv.vars)))
-
newliveout := bvalloc(int32(len(lv.vars)))
any := bvalloc(int32(len(lv.vars)))
all := bvalloc(int32(len(lv.vars)))
//
// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
newlivein.AndNot(bb.liveout, bb.varkill)
-
bb.livein.Or(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 {
- switch n.Class {
- case PPARAM, PPARAMOUT:
- for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
- if args.Get(int32(n.Xoffset/int64(Widthptr) + int64(i))) {
- return true
- }
- }
-
- case PAUTO:
- for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
- if locals.Get(int32((n.Xoffset+stkptrsize)/int64(Widthptr) + int64(i))) {
- return true
- }
- }
- }
-
- return false
-}
-
// Visits all instructions in a basic block and computes a bit vector of live
// variables at each safe point locations.
func livenessepilogue(lv *Liveness) {
liveout := bvalloc(nvars)
any := bvalloc(nvars)
all := bvalloc(nvars)
- outLive := bvalloc(argswords()) // always-live output params
- outLiveHeap := bvalloc(localswords()) // always-live pointers to heap-allocated copies of output params
+ livedefer := bvalloc(nvars) // always-live variables
// If there is a defer (that could recover), then all output
// parameters are live all the time. In addition, any locals
// TODO: if the output parameter is heap-allocated, then we
// don't need to keep the stack copy live?
if hasdefer {
- for _, n := range lv.vars {
+ for i, n := range lv.vars {
if n.Class == PPARAMOUT {
if n.IsOutputParamHeapAddr() {
// Just to be paranoid.
}
// Needzero not necessary, as the compiler
// explicitly zeroes output vars at start of fn.
- xoffset := n.Xoffset
- onebitwalktype1(n.Type, &xoffset, outLive)
+ livedefer.Set(int32(i))
}
if n.IsOutputParamHeapAddr() {
n.Name.Needzero = true
- xoffset := n.Xoffset + stkptrsize
- onebitwalktype1(n.Type, &xoffset, outLiveHeap)
+ livedefer.Set(int32(i))
}
}
}
// This duplicates information known during livenesssolve
// but avoids storing two more vectors for each block.
any.Clear()
-
all.Clear()
for j := 0; j < len(bb.pred); j++ {
pred := bb.pred[j]
// value we are tracking.
// Live stuff first.
- args := bvalloc(argswords())
-
- lv.argslivepointers = append(lv.argslivepointers, args)
- locals := bvalloc(localswords())
- lv.livepointers = append(lv.livepointers, locals)
+ live := bvalloc(nvars)
+ live.Copy(any)
+ lv.livevars = append(lv.livevars, live)
if debuglive >= 3 {
fmt.Printf("%v\n", p)
printvars("avarinitany", any, lv.vars)
}
-
- // Record any values with an "address taken" reaching
- // this code position as live. Must do now instead of below
- // because the any/all calculation requires walking forward
- // over the block (as this loop does), while the liveout
- // requires walking backward (as the next loop does).
- onebitlivepointermap(lv, any, lv.vars, args, locals)
}
if p == bb.last {
}
}
- bb.lastbitmapindex = len(lv.livepointers) - 1
+ bb.lastbitmapindex = len(lv.livevars) - 1
}
var msg []string
var nmsg, startmsg int
for _, bb := range lv.cfg {
if debuglive >= 1 && Curfn.Func.Nname.Sym.Name != "init" && Curfn.Func.Nname.Sym.Name[0] != '.' {
- nmsg = len(lv.livepointers)
+ nmsg = len(lv.livevars)
startmsg = nmsg
msg = make([]string, nmsg)
for j := 0; j < nmsg; j++ {
}
}
- // Record live pointers.
- args := lv.argslivepointers[pos]
-
- locals := lv.livepointers[pos]
- onebitlivepointermap(lv, liveout, lv.vars, args, locals)
+ // Record live variables.
+ live := lv.livevars[pos]
+ live.Or(live, liveout)
// Mark pparamout variables (as described above)
if p.As == obj.ACALL {
- args.Or(args, outLive)
- locals.Or(locals, outLiveHeap)
+ live.Or(live, livedefer)
}
- // Show live pointer bitmaps.
- // We're interpreting the args and locals bitmap instead of liveout so that we
- // include the bits added by the avarinit logic in the
- // previous loop.
+ // Show live variables.
if msg != nil {
fmt_ := fmt.Sprintf("%v: live at ", p.Line())
if p.As == obj.ACALL && p.To.Sym != nil {
fmt_ += fmt.Sprintf("entry to %s:", ((p.From.Node).(*Node)).Sym.Name)
}
numlive := 0
- for j := 0; j < len(lv.vars); j++ {
- n := lv.vars[j]
- if islive(n, args, locals) {
+ for j, n := range lv.vars {
+ if live.Get(int32(j)) {
fmt_ += fmt.Sprintf(" %v", n)
numlive++
}
// Only CALL instructions need a PCDATA annotation.
// The TEXT instruction annotation is implicit.
if p.As == obj.ACALL {
+ before := p
if isdeferreturn(p) {
// runtime.deferreturn modifies its return address to return
// back to the CALL, not to the subsequent instruction.
// the PCDATA must begin one instruction early too.
// The instruction before a call to deferreturn is always a
// no-op, to keep PC-specific data unambiguous.
- prev := p.Opt.(*obj.Prog)
+ before = p.Opt.(*obj.Prog)
if Ctxt.Arch.Family == sys.PPC64 {
// On ppc64 there is an additional instruction
// (another no-op or reload of toc pointer) before
// the call.
- prev = prev.Opt.(*obj.Prog)
+ before = before.Opt.(*obj.Prog)
}
- splicebefore(lv, bb, newpcdataprog(prev, pos), prev)
- } else {
- splicebefore(lv, bb, newpcdataprog(p, pos), p)
}
+ splicebefore(lv, bb, newpcdataprog(before, pos), before)
}
pos--
// Linear probing hash table of bitmaps seen so far.
// The hash table has 4n entries to keep the linear
// scan short. An entry of -1 indicates an empty slot.
- n := len(lv.livepointers)
+ n := len(lv.livevars)
tablesize := 4 * n
table := make([]int, tablesize)
// remap[i] = the new index of the old bit vector #i.
remap := make([]int, n)
-
for i := range remap {
remap[i] = -1
}
// Consider bit vectors in turn.
// If new, assign next number using uniq,
- // record in remap, record in lv.livepointers and lv.argslivepointers
+ // record in remap, record in lv.livevars
// under the new index, and add entry to hash table.
- // If already seen, record earlier index in remap and free bitmaps.
- for i := 0; i < n; i++ {
- local := lv.livepointers[i]
- arg := lv.argslivepointers[i]
- h := hashbitmap(hashbitmap(H0, local), arg) % uint32(tablesize)
+ // If already seen, record earlier index in remap.
+Outer:
+ for i, live := range lv.livevars {
+ h := hashbitmap(H0, live) % uint32(tablesize)
for {
j := table[h]
if j < 0 {
break
}
- jlocal := lv.livepointers[j]
- jarg := lv.argslivepointers[j]
- if local.Eq(jlocal) && arg.Eq(jarg) {
+ jlive := lv.livevars[j]
+ if live.Eq(jlive) {
remap[i] = j
- goto Next
+ continue Outer
}
h++
table[h] = uniq
remap[i] = uniq
- lv.livepointers[uniq] = local
- lv.argslivepointers[uniq] = arg
+ lv.livevars[uniq] = live
uniq++
- Next:
}
- // We've already reordered lv.livepointers[0:uniq]
- // and lv.argslivepointers[0:uniq] and freed the bitmaps
- // we don't need anymore. Clear the pointers later in the
- // 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] = bvec{}
- lv.argslivepointers[j] = bvec{}
+ // We've already reordered lv.livevars[0:uniq]. Clear the
+ // pointers later in the array so they can be GC'd.
+ tail := lv.livevars[uniq:]
+ for i := range tail { // memclr loop pattern
+ tail[i] = bvec{}
}
+ lv.livevars = lv.livevars[:uniq]
// Rewrite PCDATA instructions to use new numbering.
for p := lv.ptxt; p != nil; p = p.Link {
fmt.Printf("\n")
}
if issafepoint(p) {
- args := lv.argslivepointers[pcdata]
- locals := lv.livepointers[pcdata]
+ live := lv.livevars[pcdata]
fmt.Printf("\tlive=")
printed = false
- for j := 0; j < len(lv.vars); j++ {
- n := lv.vars[j]
- if islive(n, args, locals) {
+ for j, n := range lv.vars {
+ if live.Get(int32(j)) {
if printed {
fmt.Printf(",")
}
fmt.Printf("\n")
}
-// Dumps a slice of bitmaps to a symbol as a sequence of uint32 values. The
-// first word dumped is the total number of bitmaps. The second word is the
-// length of the bitmaps. All bitmaps are assumed to be of equal length. The
-// remaining bytes are the raw bitmaps.
-func onebitwritesymbol(arr []bvec, sym *Sym) {
- off := 4 // number of bitmaps, to fill in later
- off = duint32(sym, off, uint32(arr[0].n)) // number of bits in each bitmap
- var i int
- for i = 0; i < len(arr); i++ {
- // bitmap words
- bv := arr[i]
-
- if bv.b == nil {
- break
- }
- off = dbvec(sym, off, bv)
- }
-
- duint32(sym, 0, uint32(i)) // number of bitmaps
+func finishgclocals(sym *Sym) {
ls := Linksym(sym)
ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
ls.Set(obj.AttrDuplicateOK, true)
sym.Lsym = ls2
} else {
Ctxt.Hash[sv] = ls
- ggloblsym(sym, int32(off), obj.RODATA)
+ ggloblsym(sym, int32(ls.Size), obj.RODATA)
+ }
+}
+
+// Dumps a slice of bitmaps to a symbol as a sequence of uint32 values. The
+// first word dumped is the total number of bitmaps. The second word is the
+// length of the bitmaps. All bitmaps are assumed to be of equal length. The
+// remaining bytes are the raw bitmaps.
+func livenessemit(lv *Liveness, argssym, livesym *Sym) {
+ args := bvalloc(argswords())
+ aoff := duint32(argssym, 0, uint32(len(lv.livevars))) // number of bitmaps
+ aoff = duint32(argssym, aoff, uint32(args.n)) // number of bits in each bitmap
+
+ locals := bvalloc(localswords())
+ loff := duint32(livesym, 0, uint32(len(lv.livevars))) // number of bitmaps
+ loff = duint32(livesym, loff, uint32(locals.n)) // number of bits in each bitmap
+
+ for _, live := range lv.livevars {
+ args.Clear()
+ locals.Clear()
+
+ onebitlivepointermap(lv, live, lv.vars, args, locals)
+
+ aoff = dbvec(argssym, aoff, args)
+ loff = dbvec(livesym, loff, locals)
}
+
+ finishgclocals(livesym)
+ finishgclocals(argssym)
}
func printprog(p *obj.Prog) {
}
// Emit the live pointer map data structures
- onebitwritesymbol(lv.livepointers, livesym)
-
- onebitwritesymbol(lv.argslivepointers, argssym)
+ livenessemit(lv, argssym, livesym)
// Free everything.
for _, ln := range fn.Func.Dcl {