1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Garbage collector liveness bitmap generation.
7 // The command line flag -live causes this code to print debug information.
10 // -live (aka -live=1): print liveness lists as code warnings at safe points
11 // -live=2: print an assembly listing with liveness annotations
12 // -live=3: print information during each computation phase (much chattier)
14 // Each level includes the earlier output as well.
30 // An ordinary basic block.
32 // Instructions are threaded together in a doubly-linked list. To iterate in
33 // program order follow the link pointer from the first node and stop after the
34 // last node has been visited
36 // for(p = bb->first;; p = p->link) {
42 // To iterate in reverse program order by following the opt pointer from the
45 // for(p = bb->last; p != nil; p = p->opt) {
48 type BasicBlock struct {
49 pred []*BasicBlock // predecessors; if none, probably start of CFG
50 succ []*BasicBlock // successors; if none, probably ends in return statement
51 first *obj.Prog // first instruction in block
52 last *obj.Prog // last instruction in block
53 rpo int // reverse post-order number (also index in cfg)
54 mark int // mark bit for traversals
55 lastbitmapindex int // for livenessepilogue
57 // Summary sets of block effects.
59 // Computed during livenessprologue using only the content of
62 // uevar: upward exposed variables (used before set in block)
63 // varkill: killed variables (set in block)
64 // avarinit: addrtaken variables set or used (proof of initialization)
69 // Computed during livenesssolve using control flow information:
71 // livein: variables live at block entry
72 // liveout: variables live at block exit
73 // avarinitany: addrtaken variables possibly initialized at block exit
74 // (initialized in block or at exit from any predecessor block)
75 // avarinitall: addrtaken variables certainly initialized at block exit
76 // (initialized in block or at exit from all predecessor blocks)
83 // A collection of global state used by liveness analysis.
84 type Liveness struct {
90 // An array with a bit vector for each safe point tracking live pointers
91 // in the arguments and locals area, indexed by bb.rpo.
92 argslivepointers []Bvec
96 // Constructs a new basic block containing a single instruction.
97 func newblock(prog *obj.Prog) *BasicBlock {
99 Fatalf("newblock: prog cannot be nil")
101 result := new(BasicBlock)
103 result.mark = UNVISITED
106 result.pred = make([]*BasicBlock, 0, 2)
107 result.succ = make([]*BasicBlock, 0, 2)
111 // Adds an edge between two basic blocks by making from a predecessor of to and
112 // to a successor of from.
113 func addedge(from *BasicBlock, to *BasicBlock) {
115 Fatalf("addedge: from is nil")
118 Fatalf("addedge: to is nil")
120 from.succ = append(from.succ, to)
121 to.pred = append(to.pred, from)
124 // Inserts prev before curr in the instruction
125 // stream. Any control flow, such as branches or fall-throughs, that target the
126 // existing instruction are adjusted to target the new instruction.
127 func splicebefore(lv *Liveness, bb *BasicBlock, prev *obj.Prog, curr *obj.Prog) {
128 // There may be other instructions pointing at curr,
129 // and we want them to now point at prev. Instead of
130 // trying to find all such instructions, swap the contents
131 // so that the problem becomes inserting next after curr.
132 // The "opt" field is the backward link in the linked list.
134 // Overwrite curr's data with prev, but keep the list links.
141 // Overwrite prev (now next) with curr's old data.
148 // Now insert next after curr.
149 next.Link = curr.Link
153 if next.Link != nil && next.Link.Opt == curr {
162 // A pretty printer for basic blocks.
163 func printblock(bb *BasicBlock) {
164 fmt.Printf("basic block %d\n", bb.rpo)
165 fmt.Printf("\tpred:")
166 for _, pred := range bb.pred {
167 fmt.Printf(" %d", pred.rpo)
170 fmt.Printf("\tsucc:")
171 for _, succ := range bb.succ {
172 fmt.Printf(" %d", succ.rpo)
175 fmt.Printf("\tprog:\n")
176 for prog := bb.first; ; prog = prog.Link {
177 fmt.Printf("\t\t%v\n", prog)
184 // Iterates over a basic block applying a callback to each instruction. There
185 // are two criteria for termination. If the end of basic block is reached a
186 // value of zero is returned. If the callback returns a non-zero value, the
187 // iteration is stopped and the value of the callback is returned.
188 func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
189 for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) {
197 // Collects and returns and array of Node*s for functions arguments and local
199 func getvariables(fn *Node) []*Node {
200 result := make([]*Node, 0, 0)
201 for _, ln := range fn.Func.Dcl {
203 // In order for GODEBUG=gcdead=1 to work, each bitmap needs
204 // to contain information about all variables covered by the bitmap.
205 // For local variables, the bitmap only covers the stkptrsize
206 // bytes in the frame where variables containing pointers live.
207 // For arguments and results, the bitmap covers all variables,
208 // so we must include all the variables, even the ones without
211 // The Node.opt field is available for use by optimization passes.
212 // We use it to hold the index of the node in the variables array, plus 1
213 // (so that 0 means the Node is not in the variables array).
214 // Each pass should clear opt when done, but you never know,
215 // so clear them all ourselves too.
216 // The Node.curfn field is supposed to be set to the current function
217 // already, but for some compiler-introduced names it seems not to be,
219 // Later, when we want to find the index of a node in the variables list,
220 // we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
221 // is the index in the variables list.
224 // The compiler doesn't emit initializations for zero-width parameters or results.
225 if ln.Type.Width == 0 {
229 ln.Name.Curfn = Curfn
232 if haspointers(ln.Type) {
233 ln.SetOpt(int32(len(result)))
234 result = append(result, ln)
237 case PPARAM, PPARAMOUT:
238 ln.SetOpt(int32(len(result)))
239 result = append(result, ln)
247 // A pretty printer for control flow graphs. Takes an array of BasicBlock*s.
248 func printcfg(cfg []*BasicBlock) {
249 for _, bb := range cfg {
254 // Assigns a reverse post order number to each connected basic block using the
255 // standard algorithm. Unconnected blocks will not be affected.
256 func reversepostorder(root *BasicBlock, rpo *int32) {
258 for _, bb := range root.succ {
259 if bb.mark == UNVISITED {
260 reversepostorder(bb, rpo)
267 // Comparison predicate used for sorting basic blocks by their rpo in ascending
269 type blockrpocmp []*BasicBlock
271 func (x blockrpocmp) Len() int { return len(x) }
272 func (x blockrpocmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
273 func (x blockrpocmp) Less(i, j int) bool { return x[i].rpo < x[j].rpo }
275 // A pattern matcher for call instructions. Returns true when the instruction
276 // is a call to a specific package qualified function name.
277 func iscall(prog *obj.Prog, name *obj.LSym) bool {
279 Fatalf("iscall: prog is nil")
282 Fatalf("iscall: function name is nil")
284 if prog.As != obj.ACALL {
287 return name == prog.To.Sym
290 // Returns true for instructions that call a runtime function implementing a
291 // select communication clause.
293 var selectNames [4]*obj.LSym
295 func isselectcommcasecall(prog *obj.Prog) bool {
296 if selectNames[0] == nil {
297 selectNames[0] = Linksym(Pkglookup("selectsend", Runtimepkg))
298 selectNames[1] = Linksym(Pkglookup("selectrecv", Runtimepkg))
299 selectNames[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg))
300 selectNames[3] = Linksym(Pkglookup("selectdefault", Runtimepkg))
303 for _, name := range selectNames {
304 if iscall(prog, name) {
311 // Returns true for call instructions that target runtime·newselect.
313 var isnewselect_sym *obj.LSym
315 func isnewselect(prog *obj.Prog) bool {
316 if isnewselect_sym == nil {
317 isnewselect_sym = Linksym(Pkglookup("newselect", Runtimepkg))
319 return iscall(prog, isnewselect_sym)
322 // Returns true for call instructions that target runtime·selectgo.
324 var isselectgocall_sym *obj.LSym
326 func isselectgocall(prog *obj.Prog) bool {
327 if isselectgocall_sym == nil {
328 isselectgocall_sym = Linksym(Pkglookup("selectgo", Runtimepkg))
330 return iscall(prog, isselectgocall_sym)
333 var isdeferreturn_sym *obj.LSym
335 func isdeferreturn(prog *obj.Prog) bool {
336 if isdeferreturn_sym == nil {
337 isdeferreturn_sym = Linksym(Pkglookup("deferreturn", Runtimepkg))
339 return iscall(prog, isdeferreturn_sym)
342 // Walk backwards from a runtime·selectgo call up to its immediately dominating
343 // runtime·newselect call. Any successor nodes of communication clause nodes
344 // are implicit successors of the runtime·selectgo call node. The goal of this
345 // analysis is to add these missing edges to complete the control flow graph.
346 func addselectgosucc(selectgo *BasicBlock) {
351 if len(pred.pred) == 0 {
352 Fatalf("selectgo does not have a newselect")
355 if blockany(pred, isselectcommcasecall) {
356 // A select comm case block should have exactly one
358 if len(pred.succ) != 1 {
359 Fatalf("select comm case has too many successors")
363 // Its successor should have exactly two successors.
364 // The drop through should flow to the selectgo block
365 // and the branch should lead to the select case
367 if len(succ.succ) != 2 {
368 Fatalf("select comm case successor has too many successors")
371 // Add the block as a successor of the selectgo block.
372 addedge(selectgo, succ)
375 if blockany(pred, isnewselect) {
376 // Reached the matching newselect.
382 // The entry point for the missing selectgo control flow algorithm. Takes an
383 // array of BasicBlock*s containing selectgo calls.
384 func fixselectgo(selectgo []*BasicBlock) {
385 for _, bb := range selectgo {
390 // Constructs a control flow graph from a sequence of instructions. This
391 // procedure is complicated by various sources of implicit control flow that are
392 // not accounted for using the standard cfg construction algorithm. Returns an
393 // array of BasicBlock*s in control flow graph form (basic blocks ordered by
394 // their RPO number).
395 func newcfg(firstp *obj.Prog) []*BasicBlock {
396 // Reset the opt field of each prog to nil. In the first and second
397 // passes, instructions that are labels temporarily use the opt field to
398 // point to their basic block. In the third pass, the opt field reset
399 // to point to the predecessor of an instruction in its basic block.
400 for p := firstp; p != nil; p = p.Link {
404 // Allocate an array to remember where we have seen selectgo calls.
405 // These blocks will be revisited to add successor control flow edges.
406 selectgo := make([]*BasicBlock, 0, 0)
408 // Loop through all instructions identifying branch targets
409 // and fall-throughs and allocate basic blocks.
410 cfg := make([]*BasicBlock, 0, 0)
412 bb := newblock(firstp)
413 cfg = append(cfg, bb)
414 for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
416 if p.To.Type == obj.TYPE_BRANCH {
418 Fatalf("prog branch to nil")
420 if p.To.Val.(*obj.Prog).Opt == nil {
421 p.To.Val.(*obj.Prog).Opt = newblock(p.To.Val.(*obj.Prog))
422 cfg = append(cfg, p.To.Val.(*obj.Prog).Opt.(*BasicBlock))
425 if p.As != obj.AJMP && p.Link != nil && p.Link.Opt == nil {
426 p.Link.Opt = newblock(p.Link)
427 cfg = append(cfg, p.Link.Opt.(*BasicBlock))
429 } else if isselectcommcasecall(p) || isselectgocall(p) {
430 // Accommodate implicit selectgo control flow.
431 if p.Link.Opt == nil {
432 p.Link.Opt = newblock(p.Link)
433 cfg = append(cfg, p.Link.Opt.(*BasicBlock))
438 // Loop through all basic blocks maximally growing the list of
439 // contained instructions until a label is reached. Add edges
440 // for branches and fall-through instructions.
441 for _, bb := range cfg {
442 for p := bb.last; p != nil && p.As != obj.AEND; p = p.Link {
443 if p.Opt != nil && p != bb.last {
448 // Stop before an unreachable RET, to avoid creating
449 // unreachable control flow nodes.
450 if p.Link != nil && p.Link.As == obj.ARET && p.Link.Mode == 1 {
451 // TODO: remove after SSA is done. SSA does not
452 // generate any unreachable RET instructions.
456 // Collect basic blocks with selectgo calls.
457 if isselectgocall(p) {
458 selectgo = append(selectgo, bb)
462 if bb.last.To.Type == obj.TYPE_BRANCH {
463 addedge(bb, bb.last.To.Val.(*obj.Prog).Opt.(*BasicBlock))
465 if bb.last.Link != nil {
466 // Add a fall-through when the instruction is
467 // not an unconditional control transfer.
468 if bb.last.As != obj.AJMP && bb.last.As != obj.ARET && bb.last.As != obj.AUNDEF {
469 addedge(bb, bb.last.Link.Opt.(*BasicBlock))
474 // Add back links so the instructions in a basic block can be traversed
475 // backward. This is the final state of the instruction opt field.
476 for _, bb := range cfg {
489 // Add missing successor edges to the selectgo blocks.
490 if len(selectgo) != 0 {
491 fixselectgo([]*BasicBlock(selectgo))
494 // Find a depth-first order and assign a depth-first number to
496 for _, bb := range cfg {
500 rpo := int32(len(cfg))
501 reversepostorder(bb, &rpo)
503 // Sort the basic blocks by their depth first number. The
504 // array is now a depth-first spanning tree with the first
505 // node being the root.
506 sort.Sort(blockrpocmp(cfg))
508 // Unreachable control flow nodes are indicated by a -1 in the rpo
509 // field. If we see these nodes something must have gone wrong in an
510 // upstream compilation phase.
513 fmt.Printf("newcfg: unreachable basic block for %v\n", bb.last)
515 Fatalf("newcfg: invalid control flow graph")
521 // Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
523 func freecfg(cfg []*BasicBlock) {
526 for p := bb0.first; p != nil; p = p.Link {
532 // Returns true if the node names a variable that is otherwise uninteresting to
533 // the liveness computation.
534 func isfunny(n *Node) bool {
535 return n.Sym != nil && (n.Sym.Name == ".fp" || n.Sym.Name == ".args")
538 // Computes the effects of an instruction on a set of
539 // variables. The vars argument is an array of Node*s.
541 // The output vectors give bits for variables:
542 // uevar - used by this instruction
543 // varkill - killed by this instruction
544 // for variables without address taken, means variable was set
545 // for variables with address taken, means variable was marked dead
546 // avarinit - initialized or referred to by this instruction,
547 // only for variables with address taken but not escaping to heap
549 // The avarinit output serves as a signal that the data has been
550 // initialized, because any use of a variable must come after its
552 func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarinit Bvec) {
557 if prog.As == obj.ARET {
558 // Return instructions implicitly read all the arguments. For
559 // the sake of correctness, out arguments must be read. For the
560 // sake of backtrace quality, we read in arguments as well.
562 // A return instruction with a p->to is a tail return, which brings
563 // the stack pointer back up (if it ever went down) and then jumps
564 // to a new function entirely. That form of instruction must read
565 // all the parameters for correctness, and similarly it must not
566 // read the out arguments - they won't be set until the new
568 for i, node := range vars {
569 switch node.Class &^ PHEAP {
571 bvset(uevar, int32(i))
573 // If the result had its address taken, it is being tracked
574 // by the avarinit code, which does not use uevar.
575 // If we added it to uevar too, we'd not see any kill
576 // and decide that the variable was live entry, which it is not.
577 // So only use uevar in the non-addrtaken case.
578 // The p->to.type == thearch.D_NONE limits the bvset to
579 // non-tail-call return instructions; see note above
580 // the for loop for details.
582 if !node.Addrtaken && prog.To.Type == obj.TYPE_NONE {
583 bvset(uevar, int32(i))
591 if prog.As == obj.ATEXT {
592 // A text instruction marks the entry point to a function and
593 // the definition point of all in arguments.
594 for i, node := range vars {
595 switch node.Class &^ PHEAP {
598 bvset(avarinit, int32(i))
600 bvset(varkill, int32(i))
607 if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
609 if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn {
610 switch ((from.Node).(*Node)).Class &^ PHEAP {
611 case PAUTO, PPARAM, PPARAMOUT:
612 pos, ok := from.Node.(*Node).Opt().(int32) // index in vars
616 if pos >= int32(len(vars)) || vars[pos] != from.Node {
617 Fatalf("bad bookkeeping in liveness %v %d", Nconv(from.Node.(*Node), 0), pos)
619 if ((from.Node).(*Node)).Addrtaken {
622 if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
625 if prog.Info.Flags&LeftWrite != 0 {
626 if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
636 if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
638 if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn {
639 switch ((to.Node).(*Node)).Class &^ PHEAP {
640 case PAUTO, PPARAM, PPARAMOUT:
641 pos, ok := to.Node.(*Node).Opt().(int32) // index in vars
645 if pos >= int32(len(vars)) || vars[pos] != to.Node {
646 Fatalf("bad bookkeeping in liveness %v %d", Nconv(to.Node.(*Node), 0), pos)
648 if ((to.Node).(*Node)).Addrtaken {
649 if prog.As != obj.AVARKILL {
652 if prog.As == obj.AVARDEF || prog.As == obj.AVARKILL {
656 // RightRead is a read, obviously.
657 // RightAddr by itself is also implicitly a read.
659 // RightAddr|RightWrite means that the address is being taken
660 // but only so that the instruction can write to the value.
661 // It is not a read. It is equivalent to RightWrite except that
662 // having the RightAddr bit set keeps the registerizer from
663 // trying to substitute a register for the memory location.
664 if (prog.Info.Flags&RightRead != 0) || prog.Info.Flags&(RightAddr|RightWrite) == RightAddr {
667 if prog.Info.Flags&RightWrite != 0 {
668 if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
678 // Constructs a new liveness structure used to hold the global state of the
679 // liveness computation. The cfg argument is an array of BasicBlock*s and the
680 // vars argument is an array of Node*s.
681 func newliveness(fn *Node, ptxt *obj.Prog, cfg []*BasicBlock, vars []*Node) *Liveness {
682 result := new(Liveness)
688 nblocks := int32(len(cfg))
689 nvars := int32(len(vars))
690 bulk := bvbulkalloc(nvars, nblocks*7)
691 for _, bb := range cfg {
692 bb.uevar = bulk.next()
693 bb.varkill = bulk.next()
694 bb.livein = bulk.next()
695 bb.liveout = bulk.next()
696 bb.avarinit = bulk.next()
697 bb.avarinitany = bulk.next()
698 bb.avarinitall = bulk.next()
701 result.livepointers = make([]Bvec, 0, 0)
702 result.argslivepointers = make([]Bvec, 0, 0)
706 // Frees the liveness structure and all of its leaf data structures.
707 func freeliveness(lv *Liveness) {
709 Fatalf("freeliveness: cannot free nil")
713 func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) {
714 fmt.Printf("effects of %v", p)
715 fmt.Printf("\nuevar: ")
717 fmt.Printf("\nvarkill: ")
719 fmt.Printf("\navarinit: ")
724 // Pretty print a variable node. Uses Pascal like conventions for pointers and
725 // addresses to avoid confusing the C like conventions used in the node variable
727 func printnode(node *Node) {
729 if haspointers(node.Type) {
736 fmt.Printf(" %v%s%s", node, p, a)
739 // Pretty print a list of variables. The vars argument is an array of Node*s.
740 func printvars(name string, bv Bvec, vars []*Node) {
741 fmt.Printf("%s:", name)
742 for i, node := range vars {
743 if bvget(bv, int32(i)) != 0 {
750 // Prints a basic block annotated with the information computed by liveness
752 func livenessprintblock(lv *Liveness, bb *BasicBlock) {
753 fmt.Printf("basic block %d\n", bb.rpo)
755 fmt.Printf("\tpred:")
756 for _, pred := range bb.pred {
757 fmt.Printf(" %d", pred.rpo)
761 fmt.Printf("\tsucc:")
762 for _, succ := range bb.succ {
763 fmt.Printf(" %d", succ.rpo)
767 printvars("\tuevar", bb.uevar, []*Node(lv.vars))
768 printvars("\tvarkill", bb.varkill, []*Node(lv.vars))
769 printvars("\tlivein", bb.livein, []*Node(lv.vars))
770 printvars("\tliveout", bb.liveout, []*Node(lv.vars))
771 printvars("\tavarinit", bb.avarinit, []*Node(lv.vars))
772 printvars("\tavarinitany", bb.avarinitany, []*Node(lv.vars))
773 printvars("\tavarinitall", bb.avarinitall, []*Node(lv.vars))
775 fmt.Printf("\tprog:\n")
776 for prog := bb.first; ; prog = prog.Link {
777 fmt.Printf("\t\t%v", prog)
778 if prog.As == obj.APCDATA && prog.From.Offset == obj.PCDATA_StackMapIndex {
779 pos := int32(prog.To.Offset)
780 live := lv.livepointers[pos]
792 // Prints a control flow graph annotated with any information computed by
793 // liveness analysis.
794 func livenessprintcfg(lv *Liveness) {
795 for _, bb := range lv.cfg {
796 livenessprintblock(lv, bb)
800 func checkauto(fn *Node, p *obj.Prog, n *Node) {
801 for _, ln := range fn.Func.Dcl {
802 if ln.Op == ONAME && ln.Class == PAUTO && ln == n {
808 fmt.Printf("%v: checkauto %v: nil node in %v\n", p.Line(), Curfn, p)
812 fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %p %v\n", funcSym(Curfn), n, n, n.Class, p, p)
813 for _, ln := range fn.Func.Dcl {
814 fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
816 Yyerror("checkauto: invariant lost")
819 func checkparam(fn *Node, p *obj.Prog, n *Node) {
824 for _, a := range fn.Func.Dcl {
825 class = a.Class &^ PHEAP
826 if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
831 fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
832 for _, ln := range fn.Func.Dcl {
833 fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
835 Yyerror("checkparam: invariant lost")
838 func checkprog(fn *Node, p *obj.Prog) {
839 if p.From.Name == obj.NAME_AUTO {
840 checkauto(fn, p, p.From.Node.(*Node))
842 if p.From.Name == obj.NAME_PARAM {
843 checkparam(fn, p, p.From.Node.(*Node))
845 if p.To.Name == obj.NAME_AUTO {
846 checkauto(fn, p, p.To.Node.(*Node))
848 if p.To.Name == obj.NAME_PARAM {
849 checkparam(fn, p, p.To.Node.(*Node))
853 // Check instruction invariants. We assume that the nodes corresponding to the
854 // sources and destinations of memory operations will be declared in the
855 // function. This is not strictly true, as is the case for the so-called funny
856 // nodes and there are special cases to skip over that stuff. The analysis will
857 // fail if this invariant blindly changes.
858 func checkptxt(fn *Node, firstp *obj.Prog) {
863 for p := firstp; p != nil; p = p.Link {
865 fmt.Printf("analyzing '%v'\n", p)
867 if p.As != obj.ADATA && p.As != obj.AGLOBL && p.As != obj.ATYPE {
873 // NOTE: The bitmap for a specific type t should be cached in t after the first run
874 // and then simply copied into bv at the correct offset on future calls with
875 // the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, onebitwalktype1
876 // accounts for 40% of the 6g execution time.
877 func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
878 if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
879 Fatalf("onebitwalktype1: invalid initial alignment, %v", t)
907 if *xoffset&int64(Widthptr-1) != 0 {
908 Fatalf("onebitwalktype1: invalid alignment, %v", t)
910 bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer
914 // struct { byte *str; intgo len; }
915 if *xoffset&int64(Widthptr-1) != 0 {
916 Fatalf("onebitwalktype1: invalid alignment, %v", t)
918 bvset(bv, int32(*xoffset/int64(Widthptr))) //pointer in first slot
922 // struct { Itab *tab; void *data; }
923 // or, when isnilinter(t)==true:
924 // struct { Type *type; void *data; }
925 if *xoffset&int64(Widthptr-1) != 0 {
926 Fatalf("onebitwalktype1: invalid alignment, %v", t)
928 bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot
929 bvset(bv, int32(*xoffset/int64(Widthptr)+1)) // pointer in second slot
933 // The value of t->bound is -1 for slices types and >=0 for
934 // for fixed array types. All other values are invalid.
936 Fatalf("onebitwalktype1: invalid bound, %v", t)
939 // struct { byte *array; uintgo len; uintgo cap; }
940 if *xoffset&int64(Widthptr-1) != 0 {
941 Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
943 bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
946 for i := int64(0); i < t.Bound; i++ {
947 onebitwalktype1(t.Type, xoffset, bv)
953 var fieldoffset int64
954 for t1 := t.Type; t1 != nil; t1 = t1.Down {
955 fieldoffset = t1.Width
956 *xoffset += fieldoffset - o
957 onebitwalktype1(t1.Type, xoffset, bv)
958 o = fieldoffset + t1.Type.Width
961 *xoffset += t.Width - o
964 Fatalf("onebitwalktype1: unexpected type, %v", t)
968 // Returns the number of words of local variables.
969 func localswords() int32 {
970 return int32(stkptrsize / int64(Widthptr))
973 // Returns the number of words of in and out arguments.
974 func argswords() int32 {
975 return int32(Curfn.Type.Argwid / int64(Widthptr))
978 // Generates live pointer value maps for arguments and local variables. The
979 // this argument and the in arguments are always assumed live. The vars
980 // argument is an array of Node*s.
981 func onebitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) {
985 for i := int32(0); ; i++ {
986 i = int32(bvnext(liveout, i))
993 xoffset = node.Xoffset + stkptrsize
994 onebitwalktype1(node.Type, &xoffset, locals)
996 case PPARAM, PPARAMOUT:
997 xoffset = node.Xoffset
998 onebitwalktype1(node.Type, &xoffset, args)
1002 // The node list only contains declared names.
1003 // If the receiver or arguments are unnamed, they will be omitted
1004 // from the list above. Preserve those values - even though they are unused -
1005 // in order to keep their addresses live for use in stack traces.
1006 thisargtype := getthisx(lv.fn.Type)
1008 if thisargtype != nil {
1010 onebitwalktype1(thisargtype, &xoffset, args)
1013 inargtype := getinargx(lv.fn.Type)
1014 if inargtype != nil {
1016 onebitwalktype1(inargtype, &xoffset, args)
1020 // Construct a disembodied instruction.
1021 func unlinkedprog(as int) *obj.Prog {
1028 // Construct a new PCDATA instruction associated with and for the purposes of
1029 // covering an existing instruction.
1030 func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog {
1034 Nodconst(&from, Types[TINT32], obj.PCDATA_StackMapIndex)
1035 Nodconst(&to, Types[TINT32], int64(index))
1036 pcdata := unlinkedprog(obj.APCDATA)
1037 pcdata.Lineno = prog.Lineno
1038 Naddr(&pcdata.From, &from)
1039 Naddr(&pcdata.To, &to)
1043 // Returns true for instructions that are safe points that must be annotated
1044 // with liveness information.
1045 func issafepoint(prog *obj.Prog) bool {
1046 return prog.As == obj.ATEXT || prog.As == obj.ACALL
1049 // Initializes the sets for solving the live variables. Visits all the
1050 // instructions in each basic block to summarizes the information at each basic
1052 func livenessprologue(lv *Liveness) {
1053 nvars := int32(len(lv.vars))
1054 uevar := bvalloc(nvars)
1055 varkill := bvalloc(nvars)
1056 avarinit := bvalloc(nvars)
1057 for _, bb := range lv.cfg {
1058 // Walk the block instructions backward and update the block
1059 // effects with the each prog effects.
1060 for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) {
1061 progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
1063 printeffects(p, uevar, varkill, avarinit)
1065 bvor(bb.varkill, bb.varkill, varkill)
1066 bvandnot(bb.uevar, bb.uevar, varkill)
1067 bvor(bb.uevar, bb.uevar, uevar)
1070 // Walk the block instructions forward to update avarinit bits.
1071 // avarinit describes the effect at the end of the block, not the beginning.
1074 for p := bb.first; ; p = p.Link {
1075 progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
1077 printeffects(p, uevar, varkill, avarinit)
1079 bvandnot(bb.avarinit, bb.avarinit, varkill)
1080 bvor(bb.avarinit, bb.avarinit, avarinit)
1088 // Solve the liveness dataflow equations.
1089 func livenesssolve(lv *Liveness) {
1090 // These temporary bitvectors exist to avoid successive allocations and
1091 // frees within the loop.
1092 newlivein := bvalloc(int32(len(lv.vars)))
1094 newliveout := bvalloc(int32(len(lv.vars)))
1095 any := bvalloc(int32(len(lv.vars)))
1096 all := bvalloc(int32(len(lv.vars)))
1098 // Push avarinitall, avarinitany forward.
1099 // avarinitall says the addressed var is initialized along all paths reaching the block exit.
1100 // avarinitany says the addressed var is initialized along some path reaching the block exit.
1101 for i, bb := range lv.cfg {
1103 bvcopy(bb.avarinitall, bb.avarinit)
1105 bvresetall(bb.avarinitall)
1106 bvnot(bb.avarinitall)
1108 bvcopy(bb.avarinitany, bb.avarinit)
1114 for _, bb := range lv.cfg {
1117 for j, pred := range bb.pred {
1119 bvcopy(any, pred.avarinitany)
1120 bvcopy(all, pred.avarinitall)
1122 bvor(any, any, pred.avarinitany)
1123 bvand(all, all, pred.avarinitall)
1127 bvandnot(any, any, bb.varkill)
1128 bvandnot(all, all, bb.varkill)
1129 bvor(any, any, bb.avarinit)
1130 bvor(all, all, bb.avarinit)
1131 if bvcmp(any, bb.avarinitany) != 0 {
1133 bvcopy(bb.avarinitany, any)
1136 if bvcmp(all, bb.avarinitall) != 0 {
1138 bvcopy(bb.avarinitall, all)
1143 // Iterate through the blocks in reverse round-robin fashion. A work
1144 // queue might be slightly faster. As is, the number of iterations is
1145 // so low that it hardly seems to be worth the complexity.
1151 // Walk blocks in the general direction of propagation. This
1152 // improves convergence.
1153 for i := len(lv.cfg) - 1; i >= 0; i-- {
1156 // A variable is live on output from this block
1157 // if it is live on input to some successor.
1159 // out[b] = \bigcup_{s \in succ[b]} in[s]
1160 bvresetall(newliveout)
1161 for _, succ := range bb.succ {
1162 bvor(newliveout, newliveout, succ.livein)
1165 if bvcmp(bb.liveout, newliveout) != 0 {
1167 bvcopy(bb.liveout, newliveout)
1170 // A variable is live on input to this block
1171 // if it is live on output from this block and
1172 // not set by the code in this block.
1174 // in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
1175 bvandnot(newlivein, bb.liveout, bb.varkill)
1177 bvor(bb.livein, newlivein, bb.uevar)
1182 // This function is slow but it is only used for generating debug prints.
1183 // Check whether n is marked live in args/locals.
1184 func islive(n *Node, args Bvec, locals Bvec) bool {
1186 case PPARAM, PPARAMOUT:
1187 for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
1188 if bvget(args, int32(n.Xoffset/int64(Widthptr)+int64(i))) != 0 {
1194 for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
1195 if bvget(locals, int32((n.Xoffset+stkptrsize)/int64(Widthptr)+int64(i))) != 0 {
1204 // Visits all instructions in a basic block and computes a bit vector of live
1205 // variables at each safe point locations.
1206 func livenessepilogue(lv *Liveness) {
1207 var pred *BasicBlock
1216 nvars := int32(len(lv.vars))
1217 livein := bvalloc(nvars)
1218 liveout := bvalloc(nvars)
1219 uevar := bvalloc(nvars)
1220 varkill := bvalloc(nvars)
1221 avarinit := bvalloc(nvars)
1222 any := bvalloc(nvars)
1223 all := bvalloc(nvars)
1224 ambig := bvalloc(localswords())
1226 startmsg := int32(0)
1228 for _, bb := range lv.cfg {
1229 // Compute avarinitany and avarinitall for entry to block.
1230 // This duplicates information known during livenesssolve
1231 // but avoids storing two more vectors for each block.
1235 for j = 0; j < int32(len(bb.pred)); j++ {
1238 bvcopy(any, pred.avarinitany)
1239 bvcopy(all, pred.avarinitall)
1241 bvor(any, any, pred.avarinitany)
1242 bvand(all, all, pred.avarinitall)
1246 // Walk forward through the basic block instructions and
1247 // allocate liveness maps for those instructions that need them.
1248 // Seed the maps with information about the addrtaken variables.
1249 for p = bb.first; ; p = p.Link {
1250 progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
1251 bvandnot(any, any, varkill)
1252 bvandnot(all, all, varkill)
1253 bvor(any, any, avarinit)
1254 bvor(all, all, avarinit)
1257 // Annotate ambiguously live variables so that they can
1258 // be zeroed at function entry.
1259 // livein and liveout are dead here and used as temporaries.
1262 bvandnot(liveout, any, all)
1263 if !bvisempty(liveout) {
1264 for pos = 0; pos < liveout.n; pos++ {
1265 if bvget(liveout, pos) == 0 {
1268 bvset(all, pos) // silence future warnings in this block
1270 if !n.Name.Needzero {
1271 n.Name.Needzero = true
1273 Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Func.Nname, Nconv(n, obj.FmtLong))
1276 // Record in 'ambiguous' bitmap.
1277 xoffset = n.Xoffset + stkptrsize
1279 onebitwalktype1(n.Type, &xoffset, ambig)
1284 // Allocate a bit vector for each class and facet of
1285 // value we are tracking.
1287 // Live stuff first.
1288 args = bvalloc(argswords())
1290 lv.argslivepointers = append(lv.argslivepointers, args)
1291 locals = bvalloc(localswords())
1292 lv.livepointers = append(lv.livepointers, locals)
1295 fmt.Printf("%v\n", p)
1296 printvars("avarinitany", any, lv.vars)
1299 // Record any values with an "address taken" reaching
1300 // this code position as live. Must do now instead of below
1301 // because the any/all calculation requires walking forward
1302 // over the block (as this loop does), while the liveout
1303 // requires walking backward (as the next loop does).
1304 onebitlivepointermap(lv, any, lv.vars, args, locals)
1312 bb.lastbitmapindex = len(lv.livepointers) - 1
1319 for _, bb := range lv.cfg {
1320 if debuglive >= 1 && Curfn.Func.Nname.Sym.Name != "init" && Curfn.Func.Nname.Sym.Name[0] != '.' {
1321 nmsg = int32(len(lv.livepointers))
1323 msg = make([]string, nmsg)
1324 for j = 0; j < nmsg; j++ {
1329 // walk backward, emit pcdata and populate the maps
1330 pos = int32(bb.lastbitmapindex)
1333 // the first block we encounter should have the ATEXT so
1334 // at no point should pos ever be less than zero.
1335 Fatalf("livenessepilogue")
1338 bvcopy(livein, bb.liveout)
1339 for p = bb.last; p != nil; p = next {
1340 next = p.Opt.(*obj.Prog) // splicebefore modifies p->opt
1342 // Propagate liveness information
1343 progeffects(p, lv.vars, uevar, varkill, avarinit)
1345 bvcopy(liveout, livein)
1346 bvandnot(livein, liveout, varkill)
1347 bvor(livein, livein, uevar)
1348 if debuglive >= 3 && issafepoint(p) {
1349 fmt.Printf("%v\n", p)
1350 printvars("uevar", uevar, lv.vars)
1351 printvars("varkill", varkill, lv.vars)
1352 printvars("livein", livein, lv.vars)
1353 printvars("liveout", liveout, lv.vars)
1357 // Found an interesting instruction, record the
1358 // corresponding liveness information.
1360 // Useful sanity check: on entry to the function,
1361 // the only things that can possibly be live are the
1362 // input parameters.
1363 if p.As == obj.ATEXT {
1364 for j = 0; j < liveout.n; j++ {
1365 if bvget(liveout, j) == 0 {
1369 if n.Class != PPARAM {
1370 yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, Nconv(n, obj.FmtLong), p.Pc)
1375 // Record live pointers.
1376 args = lv.argslivepointers[pos]
1378 locals = lv.livepointers[pos]
1379 onebitlivepointermap(lv, liveout, lv.vars, args, locals)
1381 // Ambiguously live variables are zeroed immediately after
1382 // function entry. Mark them live for all the non-entry bitmaps
1383 // so that GODEBUG=gcdead=1 mode does not poison them.
1384 if p.As == obj.ACALL {
1385 bvor(locals, locals, ambig)
1388 // Show live pointer bitmaps.
1389 // We're interpreting the args and locals bitmap instead of liveout so that we
1390 // include the bits added by the avarinit logic in the
1394 fmt_ += fmt.Sprintf("%v: live at ", p.Line())
1395 if p.As == obj.ACALL && p.To.Sym != nil {
1396 name := p.To.Sym.Name
1397 i := strings.Index(name, ".")
1401 fmt_ += fmt.Sprintf("call to %s:", name)
1402 } else if p.As == obj.ACALL {
1403 fmt_ += "indirect call:"
1405 fmt_ += fmt.Sprintf("entry to %s:", ((p.From.Node).(*Node)).Sym.Name)
1408 for j = 0; j < int32(len(lv.vars)); j++ {
1410 if islive(n, args, locals) {
1411 fmt_ += fmt.Sprintf(" %v", n)
1417 if numlive == 0 { // squelch message
1421 msg[startmsg] = fmt_
1425 // Only CALL instructions need a PCDATA annotation.
1426 // The TEXT instruction annotation is implicit.
1427 if p.As == obj.ACALL {
1428 if isdeferreturn(p) {
1429 // runtime.deferreturn modifies its return address to return
1430 // back to the CALL, not to the subsequent instruction.
1431 // Because the return comes back one instruction early,
1432 // the PCDATA must begin one instruction early too.
1433 // The instruction before a call to deferreturn is always a
1434 // no-op, to keep PC-specific data unambiguous.
1435 prev := p.Opt.(*obj.Prog)
1436 if Ctxt.Arch.Thechar == '9' {
1437 // On ppc64 there is an additional instruction
1438 // (another no-op or reload of toc pointer) before
1440 prev = prev.Opt.(*obj.Prog)
1442 splicebefore(lv, bb, newpcdataprog(prev, pos), prev)
1444 splicebefore(lv, bb, newpcdataprog(p, pos), p)
1453 for j = startmsg; j < nmsg; j++ {
1455 fmt.Printf("%s", msg[j])
1468 // FNV-1 hash function constants.
1474 func hashbitmap(h uint32, bv Bvec) uint32 {
1477 n := int((bv.n + 31) / 32)
1478 for i := 0; i < n; i++ {
1480 h = (h * Hp) ^ (w & 0xff)
1481 h = (h * Hp) ^ ((w >> 8) & 0xff)
1482 h = (h * Hp) ^ ((w >> 16) & 0xff)
1483 h = (h * Hp) ^ ((w >> 24) & 0xff)
1489 // Compact liveness information by coalescing identical per-call-site bitmaps.
1490 // The merging only happens for a single function, not across the entire binary.
1492 // There are actually two lists of bitmaps, one list for the local variables and one
1493 // list for the function arguments. Both lists are indexed by the same PCDATA
1494 // index, so the corresponding pairs must be considered together when
1495 // merging duplicates. The argument bitmaps change much less often during
1496 // function execution than the local variable bitmaps, so it is possible that
1497 // we could introduce a separate PCDATA index for arguments vs locals and
1498 // then compact the set of argument bitmaps separately from the set of
1499 // local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
1500 // is actually a net loss: we save about 50k of argument bitmaps but the new
1501 // PCDATA tables cost about 100k. So for now we keep using a single index for
1502 // both bitmap lists.
1503 func livenesscompact(lv *Liveness) {
1504 // Linear probing hash table of bitmaps seen so far.
1505 // The hash table has 4n entries to keep the linear
1506 // scan short. An entry of -1 indicates an empty slot.
1507 n := len(lv.livepointers)
1510 table := make([]int, tablesize)
1511 for i := range table {
1515 // remap[i] = the new index of the old bit vector #i.
1516 remap := make([]int, n)
1518 for i := range remap {
1521 uniq := 0 // unique tables found so far
1523 // Consider bit vectors in turn.
1524 // If new, assign next number using uniq,
1525 // record in remap, record in lv->livepointers and lv->argslivepointers
1526 // under the new index, and add entry to hash table.
1527 // If already seen, record earlier index in remap and free bitmaps.
1534 for i := 0; i < n; i++ {
1535 local = lv.livepointers[i]
1536 arg = lv.argslivepointers[i]
1537 h = hashbitmap(hashbitmap(H0, local), arg) % uint32(tablesize)
1544 jlocal = lv.livepointers[j]
1545 jarg = lv.argslivepointers[j]
1546 if bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0 {
1552 if h == uint32(tablesize) {
1559 lv.livepointers[uniq] = local
1560 lv.argslivepointers[uniq] = arg
1565 // We've already reordered lv->livepointers[0:uniq]
1566 // and lv->argslivepointers[0:uniq] and freed the bitmaps
1567 // we don't need anymore. Clear the pointers later in the
1568 // array so that we can tell where the coalesced bitmaps stop
1569 // and so that we don't double-free when cleaning up.
1570 for j := uniq; j < n; j++ {
1571 lv.livepointers[j] = Bvec{}
1572 lv.argslivepointers[j] = Bvec{}
1575 // Rewrite PCDATA instructions to use new numbering.
1577 for p := lv.ptxt; p != nil; p = p.Link {
1578 if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
1579 i = int(p.To.Offset)
1581 p.To.Offset = int64(remap[i])
1587 func printbitset(printed int, name string, vars []*Node, bits Bvec) int {
1589 for i, n := range vars {
1590 if bvget(bits, int32(i)) == 0 {
1601 fmt.Printf("%s=", name)
1606 fmt.Printf("%s", n.Sym.Name)
1612 // Prints the computed liveness information and inputs, for debugging.
1613 // This format synthesizes the information used during the multiple passes
1614 // into a single presentation.
1615 func livenessprintdebug(lv *Liveness) {
1623 fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
1625 uevar := bvalloc(int32(len(lv.vars)))
1626 varkill := bvalloc(int32(len(lv.vars)))
1627 avarinit := bvalloc(int32(len(lv.vars)))
1630 for i, bb := range lv.cfg {
1635 // bb#0 pred=1,2 succ=3,4
1636 fmt.Printf("bb#%d pred=", i)
1638 for j = 0; j < len(bb.pred); j++ {
1642 fmt.Printf("%d", (bb.pred[j]).rpo)
1645 fmt.Printf(" succ=")
1646 for j = 0; j < len(bb.succ); j++ {
1650 fmt.Printf("%d", (bb.succ[j]).rpo)
1658 printed = printbitset(printed, "uevar", lv.vars, bb.uevar)
1659 printed = printbitset(printed, "livein", lv.vars, bb.livein)
1664 // program listing, with individual effects listed
1665 for p = bb.first; ; p = p.Link {
1666 fmt.Printf("%v\n", p)
1667 if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
1668 pcdata = int(p.To.Offset)
1670 progeffects(p, lv.vars, uevar, varkill, avarinit)
1672 printed = printbitset(printed, "uevar", lv.vars, uevar)
1673 printed = printbitset(printed, "varkill", lv.vars, varkill)
1674 printed = printbitset(printed, "avarinit", lv.vars, avarinit)
1679 args = lv.argslivepointers[pcdata]
1680 locals = lv.livepointers[pcdata]
1681 fmt.Printf("\tlive=")
1683 for j = 0; j < len(lv.vars); j++ {
1685 if islive(n, args, locals) {
1704 printed = printbitset(printed, "varkill", lv.vars, bb.varkill)
1705 printed = printbitset(printed, "liveout", lv.vars, bb.liveout)
1706 printed = printbitset(printed, "avarinit", lv.vars, bb.avarinit)
1707 printed = printbitset(printed, "avarinitany", lv.vars, bb.avarinitany)
1708 printed = printbitset(printed, "avarinitall", lv.vars, bb.avarinitall)
1717 // Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The
1718 // first word dumped is the total number of bitmaps. The second word is the
1719 // length of the bitmaps. All bitmaps are assumed to be of equal length. The
1720 // words that are followed are the raw bitmap words. The arr argument is an
1722 func onebitwritesymbol(arr []Bvec, sym *Sym) {
1729 off += 4 // number of bitmaps, to fill in later
1731 off = duint32(sym, off, uint32(bv.n)) // number of bits in each bitmap
1732 for i = 0; i < n; i++ {
1739 for j = 0; int32(j) < bv.n; j += 32 {
1742 // Runtime reads the bitmaps as byte arrays. Oblige.
1743 off = duint8(sym, off, uint8(word))
1745 off = duint8(sym, off, uint8(word>>8))
1746 off = duint8(sym, off, uint8(word>>16))
1747 off = duint8(sym, off, uint8(word>>24))
1751 duint32(sym, 0, uint32(i)) // number of bitmaps
1752 ggloblsym(sym, int32(off), obj.RODATA)
1755 func printprog(p *obj.Prog) {
1757 fmt.Printf("%v\n", p)
1762 // Entry pointer for liveness analysis. Constructs a complete CFG, solves for
1763 // the liveness of pointer variables in the function, and emits a runtime data
1764 // structure read by the garbage collector.
1765 func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
1766 // Change name to dump debugging information only for a specific function.
1769 if Curfn.Func.Nname.Sym.Name == "!" {
1773 debuglive += debugdelta
1775 fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
1779 checkptxt(fn, firstp)
1781 // Construct the global liveness state.
1782 cfg := newcfg(firstp)
1785 printcfg([]*BasicBlock(cfg))
1787 vars := getvariables(fn)
1788 lv := newliveness(fn, firstp, cfg, vars)
1790 // Run the dataflow framework.
1791 livenessprologue(lv)
1794 livenessprintcfg(lv)
1798 livenessprintcfg(lv)
1800 livenessepilogue(lv)
1802 livenessprintcfg(lv)
1807 livenessprintdebug(lv)
1810 // Emit the live pointer map data structures
1811 onebitwritesymbol(lv.livepointers, livesym)
1813 onebitwritesymbol(lv.argslivepointers, argssym)
1816 for _, ln := range fn.Func.Dcl {
1823 freecfg([]*BasicBlock(cfg))
1825 debuglive -= debugdelta