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.
7 // This file implements the Function and BasicBlock types.
22 // addEdge adds a control-flow graph edge from from to to.
23 func addEdge(from, to *BasicBlock) {
24 from.Succs = append(from.Succs, to)
25 to.Preds = append(to.Preds, from)
28 // Control returns the last instruction in the block.
29 func (b *BasicBlock) Control() Instruction {
30 if len(b.Instrs) == 0 {
33 return b.Instrs[len(b.Instrs)-1]
36 // SIgmaFor returns the sigma node for v coming from pred.
37 func (b *BasicBlock) SigmaFor(v Value, pred *BasicBlock) *Sigma {
38 for _, instr := range b.Instrs {
39 sigma, ok := instr.(*Sigma)
44 if sigma.From == pred && sigma.X == v {
51 // Parent returns the function that contains block b.
52 func (b *BasicBlock) Parent() *Function { return b.parent }
54 // String returns a human-readable label of this block.
55 // It is not guaranteed unique within the function.
57 func (b *BasicBlock) String() string {
58 return fmt.Sprintf("%d", b.Index)
61 // emit appends an instruction to the current basic block.
62 // If the instruction defines a Value, it is returned.
64 func (b *BasicBlock) emit(i Instruction, source ast.Node) Value {
67 b.Instrs = append(b.Instrs, i)
72 // predIndex returns the i such that b.Preds[i] == c or panics if
74 func (b *BasicBlock) predIndex(c *BasicBlock) int {
75 for i, pred := range b.Preds {
80 panic(fmt.Sprintf("no edge %s -> %s", c, b))
83 // succIndex returns the i such that b.Succs[i] == c or -1 if there is none.
84 func (b *BasicBlock) succIndex(c *BasicBlock) int {
85 for i, succ := range b.Succs {
93 // hasPhi returns true if b.Instrs contains φ-nodes.
94 func (b *BasicBlock) hasPhi() bool {
95 _, ok := b.Instrs[0].(*Phi)
99 func (b *BasicBlock) Phis() []Instruction {
103 // phis returns the prefix of b.Instrs containing all the block's φ-nodes.
104 func (b *BasicBlock) phis() []Instruction {
105 for i, instr := range b.Instrs {
106 if _, ok := instr.(*Phi); !ok {
110 return nil // unreachable in well-formed blocks
113 // replacePred replaces all occurrences of p in b's predecessor list with q.
114 // Ordinarily there should be at most one.
116 func (b *BasicBlock) replacePred(p, q *BasicBlock) {
117 for i, pred := range b.Preds {
124 // replaceSucc replaces all occurrences of p in b's successor list with q.
125 // Ordinarily there should be at most one.
127 func (b *BasicBlock) replaceSucc(p, q *BasicBlock) {
128 for i, succ := range b.Succs {
135 // removePred removes all occurrences of p in b's
136 // predecessor list and φ-nodes.
137 // Ordinarily there should be at most one.
139 func (b *BasicBlock) removePred(p *BasicBlock) {
142 // We must preserve edge order for φ-nodes.
144 for i, pred := range b.Preds {
146 b.Preds[j] = b.Preds[i]
147 // Strike out φ-edge too.
148 for _, instr := range phis {
150 phi.Edges[j] = phi.Edges[i]
155 // Nil out b.Preds[j:] and φ-edges[j:] to aid GC.
156 for i := j; i < len(b.Preds); i++ {
158 for _, instr := range phis {
159 instr.(*Phi).Edges[i] = nil
162 b.Preds = b.Preds[:j]
163 for _, instr := range phis {
165 phi.Edges = phi.Edges[:j]
169 // Destinations associated with unlabelled for/switch/select stmts.
170 // We push/pop one of these as we enter/leave each construct and for
171 // each BranchStmt we scan for the innermost target of the right type.
173 type targets struct {
174 tail *targets // rest of stack
176 _continue *BasicBlock
177 _fallthrough *BasicBlock
180 // Destinations associated with a labelled block.
181 // We populate these as labels are encountered in forward gotos or
182 // labelled statements.
187 _continue *BasicBlock
190 // labelledBlock returns the branch target associated with the
191 // specified label, creating it if needed.
193 func (f *Function) labelledBlock(label *ast.Ident) *lblock {
194 lb := f.lblocks[label.Obj]
196 lb = &lblock{_goto: f.newBasicBlock(label.Name)}
197 if f.lblocks == nil {
198 f.lblocks = make(map[*ast.Object]*lblock)
200 f.lblocks[label.Obj] = lb
205 // addParam adds a (non-escaping) parameter to f.Params of the
206 // specified name, type and source position.
208 func (f *Function) addParam(name string, typ types.Type, source ast.Node) *Parameter {
210 if len(f.Blocks) > 0 {
219 f.Params = append(f.Params, v)
221 // There may be no blocks if this function has no body. We
222 // still create params, but aren't interested in the
224 f.Blocks[0].Instrs = append(f.Blocks[0].Instrs, v)
229 func (f *Function) addParamObj(obj types.Object, source ast.Node) *Parameter {
232 name = fmt.Sprintf("arg%d", len(f.Params))
234 param := f.addParam(name, obj.Type(), source)
239 // addSpilledParam declares a parameter that is pre-spilled to the
240 // stack; the function body will load/store the spilled location.
241 // Subsequent lifting will eliminate spills where possible.
243 func (f *Function) addSpilledParam(obj types.Object, source ast.Node) {
244 param := f.addParamObj(obj, source)
246 spill.setType(types.NewPointer(obj.Type()))
247 spill.source = source
248 f.objects[obj] = spill
249 f.Locals = append(f.Locals, spill)
250 f.emit(spill, source)
251 emitStore(f, spill, param, source)
252 // f.emit(&Store{Addr: spill, Val: param})
255 // startBody initializes the function prior to generating IR code for its body.
256 // Precondition: f.Type() already set.
258 func (f *Function) startBody() {
259 entry := f.newBasicBlock("entry")
260 f.currentBlock = entry
261 f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init
264 func (f *Function) blockset(i int) *BlockSet {
265 bs := &f.blocksets[i]
266 if len(bs.values) != len(f.Blocks) {
267 if cap(bs.values) >= len(f.Blocks) {
268 bs.values = bs.values[:len(f.Blocks)]
271 bs.values = make([]bool, len(f.Blocks))
279 func (f *Function) exitBlock() {
280 old := f.currentBlock
282 f.Exit = f.newBasicBlock("exit")
283 f.currentBlock = f.Exit
286 results := make([]Value, len(ret))
287 // Run function calls deferred in this
288 // function when explicitly returning from it.
289 f.emit(new(RunDefers), nil)
290 for i, r := range ret {
291 results[i] = emitLoad(f, r, nil)
294 f.emit(&Return{Results: results}, nil)
298 // createSyntacticParams populates f.Params and generates code (spills
299 // and named result locals) for all the parameters declared in the
300 // syntax. In addition it populates the f.objects mapping.
303 // f.startBody() was called.
305 // len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
307 func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) {
308 // Receiver (at most one inner iteration).
310 for _, field := range recv.List {
311 for _, n := range field.Names {
312 f.addSpilledParam(f.Pkg.info.Defs[n], n)
314 // Anonymous receiver? No need to spill.
315 if field.Names == nil {
316 f.addParamObj(f.Signature.Recv(), field)
322 if functype.Params != nil {
323 n := len(f.Params) // 1 if has recv, 0 otherwise
324 for _, field := range functype.Params.List {
325 for _, n := range field.Names {
326 f.addSpilledParam(f.Pkg.info.Defs[n], n)
328 // Anonymous parameter? No need to spill.
329 if field.Names == nil {
330 f.addParamObj(f.Signature.Params().At(len(f.Params)-n), field)
336 if functype.Results != nil {
337 for _, field := range functype.Results.List {
338 // Implicit "var" decl of locals for named results.
339 for _, n := range field.Names {
340 f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
344 if len(f.namedResults) == 0 {
345 sig := f.Signature.Results()
346 for i := 0; i < sig.Len(); i++ {
347 // XXX position information
348 v := f.addLocal(sig.At(i).Type(), nil)
349 f.implicitResults = append(f.implicitResults, v)
355 func numberNodes(f *Function) {
357 for _, b := range f.Blocks {
358 for _, instr := range b.Instrs {
368 // buildReferrers populates the def/use information in all non-nil
369 // Value.Referrers slice.
370 // Precondition: all such slices are initially empty.
371 func buildReferrers(f *Function) {
373 for _, b := range f.Blocks {
374 for _, instr := range b.Instrs {
375 rands = instr.Operands(rands[:0]) // recycle storage
376 for _, rand := range rands {
377 if r := *rand; r != nil {
378 if ref := r.Referrers(); ref != nil {
379 *ref = append(*ref, instr)
387 func (f *Function) emitConsts() {
388 if len(f.Blocks) == 0 {
393 // TODO(dh): our deduplication only works on booleans and
394 // integers. other constants are represented as pointers to
396 if len(f.consts) == 0 {
398 } else if len(f.consts) <= 32 {
405 func (f *Function) emitConstsFew() {
406 dedup := make([]*Const, 0, 32)
407 for _, c := range f.consts {
408 if len(*c.Referrers()) == 0 {
412 for _, d := range dedup {
413 if c.typ == d.typ && c.Value == d.Value {
420 dedup = append(dedup, c)
424 instrs := make([]Instruction, len(f.Blocks[0].Instrs)+len(dedup))
425 for i, c := range dedup {
427 c.setBlock(f.Blocks[0])
429 copy(instrs[len(dedup):], f.Blocks[0].Instrs)
430 f.Blocks[0].Instrs = instrs
434 func (f *Function) emitConstsMany() {
435 type constKey struct {
440 m := make(map[constKey]Value, len(f.consts))
442 for i, c := range f.consts {
443 if len(*c.Referrers()) == 0 {
453 if dup, ok := m[k]; !ok {
462 instrs := make([]Instruction, len(f.Blocks[0].Instrs)+len(f.consts)-areNil)
464 for _, c := range f.consts {
467 c.setBlock(f.Blocks[0])
471 copy(instrs[i:], f.Blocks[0].Instrs)
472 f.Blocks[0].Instrs = instrs
476 // buildFakeExits ensures that every block in the function is
477 // reachable in reverse from the Exit block. This is required to build
478 // a full post-dominator tree, and to ensure the exit block's
479 // inclusion in the dominator tree.
480 func buildFakeExits(fn *Function) {
481 // Find back-edges via forward DFS
482 fn.fakeExits = BlockSet{values: make([]bool, len(fn.Blocks))}
483 seen := fn.blockset(0)
484 backEdges := fn.blockset(1)
486 var dfs func(b *BasicBlock)
487 dfs = func(b *BasicBlock) {
492 for _, pred := range b.Succs {
499 seen := fn.blockset(2)
500 var dfs func(b *BasicBlock)
501 dfs = func(b *BasicBlock) {
505 for _, pred := range b.Preds {
509 for _, b := range fn.Blocks {
510 if fn.fakeExits.Has(b) {
518 for _, b := range fn.Blocks {
519 if !seen.Has(b) && backEdges.Has(b) {
520 // Block b is not reachable from the exit block. Add a
521 // fake jump from b to exit, then try again. Note that we
522 // only add one fake edge at a time, as it may make
523 // multiple blocks reachable.
525 // We only consider those blocks that have back edges.
526 // Any unreachable block that doesn't have a back edge
527 // must flow into a loop, which by definition has a
528 // back edge. Thus, by looking for loops, we should
529 // need fewer fake edges overall.
539 // finishBody() finalizes the function after IR code generation of its body.
540 func (f *Function) finishBody() {
545 // Remove from f.Locals any Allocs that escape to the heap.
547 for _, l := range f.Locals {
553 // Nil out f.Locals[j:] to aid GC.
554 for i := j; i < len(f.Locals); i++ {
557 f.Locals = f.Locals[:j]
564 if f.Prog.mode&NaiveForm == 0 {
568 // emit constants after lifting, because lifting may produce new constants.
571 f.namedResults = nil // (used by lifting)
572 f.implicitResults = nil
577 f.wr.WriteFunc("start", "start", f)
579 if f.Prog.mode&PrintFunctions != 0 {
585 if f.Prog.mode&SanityCheckFunctions != 0 {
586 mustSanityCheck(f, nil)
590 func isUselessPhi(phi *Phi) (Value, bool) {
592 for _, e := range phi.Edges {
600 if v0, ok := v0.(*Const); ok {
601 if e, ok := e.(*Const); ok {
602 if v0.typ == e.typ && v0.Value == e.Value {
613 func (f *Function) RemoveNilBlocks() {
617 // removeNilBlocks eliminates nils from f.Blocks and updates each
618 // BasicBlock.Index. Use this after any pass that may delete blocks.
620 func (f *Function) removeNilBlocks() {
622 for _, b := range f.Blocks {
629 // Nil out f.Blocks[j:] to aid GC.
630 for i := j; i < len(f.Blocks); i++ {
633 f.Blocks = f.Blocks[:j]
636 // SetDebugMode sets the debug mode for package pkg. If true, all its
637 // functions will include full debug info. This greatly increases the
638 // size of the instruction stream, and causes Functions to depend upon
639 // the ASTs, potentially keeping them live in memory for longer.
641 func (pkg *Package) SetDebugMode(debug bool) {
642 // TODO(adonovan): do we want ast.File granularity?
646 // debugInfo reports whether debug info is wanted for this function.
647 func (f *Function) debugInfo() bool {
648 return f.Pkg != nil && f.Pkg.debug
651 // addNamedLocal creates a local variable, adds it to function f and
652 // returns it. Its name and type are taken from obj. Subsequent
653 // calls to f.lookup(obj) will return the same local.
655 func (f *Function) addNamedLocal(obj types.Object, source ast.Node) *Alloc {
656 l := f.addLocal(obj.Type(), source)
661 func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
662 return f.addNamedLocal(f.Pkg.info.Defs[id], id)
665 // addLocal creates an anonymous local variable of type typ, adds it
666 // to function f and returns it. pos is the optional source location.
668 func (f *Function) addLocal(typ types.Type, source ast.Node) *Alloc {
670 v.setType(types.NewPointer(typ))
671 f.Locals = append(f.Locals, v)
676 // lookup returns the address of the named variable identified by obj
677 // that is local to function f or one of its enclosing functions.
678 // If escaping, the reference comes from a potentially escaping pointer
679 // expression and the referent must be heap-allocated.
681 func (f *Function) lookup(obj types.Object, escaping bool) Value {
682 if v, ok := f.objects[obj]; ok {
683 if alloc, ok := v.(*Alloc); ok && escaping {
686 return v // function-local var (address)
689 // Definition must be in an enclosing function;
690 // plumb it through intervening closures.
692 panic("no ir.Value for " + obj.String())
694 outer := f.parent.lookup(obj, true) // escaping
702 f.FreeVars = append(f.FreeVars, v)
706 // emit emits the specified instruction to function f.
707 func (f *Function) emit(instr Instruction, source ast.Node) Value {
708 return f.currentBlock.emit(instr, source)
711 // RelString returns the full name of this function, qualified by
712 // package name, receiver type, etc.
714 // The specific formatting rules are not guaranteed and may change.
717 // "math.IsNaN" // a package-level function
718 // "(*bytes.Buffer).Bytes" // a declared method or a wrapper
719 // "(*bytes.Buffer).Bytes$thunk" // thunk (func wrapping method; receiver is param 0)
720 // "(*bytes.Buffer).Bytes$bound" // bound (func wrapping method; receiver supplied by closure)
721 // "main.main$1" // an anonymous function in main
722 // "main.init#1" // a declared init function
723 // "main.init" // the synthesized package initializer
725 // When these functions are referred to from within the same package
726 // (i.e. from == f.Pkg.Object), they are rendered without the package path.
727 // For example: "IsNaN", "(*Buffer).Bytes", etc.
729 // All non-synthetic functions have distinct package-qualified names.
730 // (But two methods may have the same name "(T).f" if one is a synthetic
731 // wrapper promoting a non-exported method "f" from another package; in
732 // that case, the strings are equal but the identifiers "f" are distinct.)
734 func (f *Function) RelString(from *types.Package) string {
737 // An anonymous function's Name() looks like "parentName$1",
738 // but its String() should include the type/package/etc.
739 parent := f.parent.RelString(from)
740 for i, anon := range f.parent.AnonFuncs {
742 return fmt.Sprintf("%s$%d", parent, 1+i)
746 return f.name // should never happen
749 // Method (declared or wrapper)?
750 if recv := f.Signature.Recv(); recv != nil {
751 return f.relMethod(from, recv.Type())
756 return f.relMethod(from, f.method.Recv())
760 if len(f.FreeVars) == 1 && strings.HasSuffix(f.name, "$bound") {
761 return f.relMethod(from, f.FreeVars[0].Type())
764 // Package-level function?
765 // Prefix with package name for cross-package references only.
766 if p := f.pkg(); p != nil && p != from {
767 return fmt.Sprintf("%s.%s", p.Path(), f.name)
774 func (f *Function) relMethod(from *types.Package, recv types.Type) string {
775 return fmt.Sprintf("(%s).%s", relType(recv, from), f.name)
778 // writeSignature writes to buf the signature sig in declaration syntax.
779 func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) {
780 buf.WriteString("func ")
781 if recv := sig.Recv(); recv != nil {
783 if n := params[0].Name(); n != "" {
787 types.WriteType(buf, params[0].Type(), types.RelativeTo(from))
788 buf.WriteString(") ")
790 buf.WriteString(name)
791 types.WriteSignature(buf, sig, types.RelativeTo(from))
794 func (f *Function) pkg() *types.Package {
801 var _ io.WriterTo = (*Function)(nil) // *Function implements io.Writer
803 func (f *Function) WriteTo(w io.Writer) (int64, error) {
805 WriteFunction(&buf, f)
806 n, err := w.Write(buf.Bytes())
810 // WriteFunction writes to buf a human-readable "disassembly" of f.
811 func WriteFunction(buf *bytes.Buffer, f *Function) {
812 fmt.Fprintf(buf, "# Name: %s\n", f.String())
814 fmt.Fprintf(buf, "# Package: %s\n", f.Pkg.Pkg.Path())
816 if syn := f.Synthetic; syn != "" {
817 fmt.Fprintln(buf, "# Synthetic:", syn)
819 if pos := f.Pos(); pos.IsValid() {
820 fmt.Fprintf(buf, "# Location: %s\n", f.Prog.Fset.Position(pos))
824 fmt.Fprintf(buf, "# Parent: %s\n", f.parent.Name())
829 if f.FreeVars != nil {
830 buf.WriteString("# Free variables:\n")
831 for i, fv := range f.FreeVars {
832 fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), from))
836 if len(f.Locals) > 0 {
837 buf.WriteString("# Locals:\n")
838 for i, l := range f.Locals {
839 fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), from))
842 writeSignature(buf, from, f.Name(), f.Signature, f.Params)
843 buf.WriteString(":\n")
846 buf.WriteString("\t(external)\n")
849 for _, b := range f.Blocks {
852 fmt.Fprintf(buf, ".nil:\n")
855 fmt.Fprintf(buf, "b%d:", b.Index)
856 if len(b.Preds) > 0 {
857 fmt.Fprint(buf, " ←")
858 for _, pred := range b.Preds {
859 fmt.Fprintf(buf, " b%d", pred.Index)
863 fmt.Fprintf(buf, " # %s", b.Comment)
867 if false { // CFG debugging
868 fmt.Fprintf(buf, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
871 buf2 := &bytes.Buffer{}
872 for _, instr := range b.Instrs {
873 buf.WriteString("\t")
874 switch v := instr.(type) {
876 // Left-align the instruction.
877 if name := v.Name(); name != "" {
878 fmt.Fprintf(buf, "%s = ", name)
880 buf.WriteString(instr.String())
882 // Be robust against bad transforms.
883 buf.WriteString("<deleted>")
885 buf.WriteString(instr.String())
887 buf.WriteString("\n")
889 if f.Prog.mode&PrintSource != 0 {
890 if s := instr.Source(); s != nil {
892 format.Node(buf2, f.Prog.Fset, s)
894 line, err := buf2.ReadString('\n')
898 buf.WriteString("\t\t> ")
899 buf.WriteString(line)
900 if line[len(line)-1] != '\n' {
901 buf.WriteString("\n")
910 buf.WriteString("\n")
914 // newBasicBlock adds to f a new basic block and returns it. It does
915 // not automatically become the current block for subsequent calls to emit.
916 // comment is an optional string for more readable debugging output.
918 func (f *Function) newBasicBlock(comment string) *BasicBlock {
920 Index: len(f.Blocks),
924 b.Succs = b.succs2[:0]
925 f.Blocks = append(f.Blocks, b)
929 // NewFunction returns a new synthetic Function instance belonging to
930 // prog, with its name and signature fields set as specified.
932 // The caller is responsible for initializing the remaining fields of
933 // the function object, e.g. Pkg, Params, Blocks.
935 // It is practically impossible for clients to construct well-formed
936 // IR functions/packages/programs directly, so we assume this is the
937 // job of the Builder alone. NewFunction exists to provide clients a
938 // little flexibility. For example, analysis tools may wish to
939 // construct fake Functions for the root of the callgraph, a fake
940 // "reflect" package, etc.
942 // TODO(adonovan): think harder about the API here.
944 func (prog *Program) NewFunction(name string, sig *types.Signature, provenance string) *Function {
945 return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
948 //lint:ignore U1000 we may make use of this for functions loaded from export data
949 type extentNode [2]token.Pos
951 func (n extentNode) Pos() token.Pos { return n[0] }
952 func (n extentNode) End() token.Pos { return n[1] }
954 func (f *Function) initHTML(name string) {
958 if rel := f.RelString(nil); rel == name {
959 f.wr = NewHTMLWriter("ir.html", rel, "")