src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

func.go (24199B)


      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.
      4 
      5 package ssa
      6 
      7 // This file implements the Function type.
      8 
      9 import (
     10 	"bytes"
     11 	"fmt"
     12 	"go/ast"
     13 	"go/token"
     14 	"go/types"
     15 	"io"
     16 	"iter"
     17 	"os"
     18 	"strings"
     19 
     20 	"golang.org/x/tools/internal/typeparams"
     21 )
     22 
     23 // Like ObjectOf, but panics instead of returning nil.
     24 // Only valid during f's create and build phases.
     25 func (f *Function) objectOf(id *ast.Ident) types.Object {
     26 	if o := f.info.ObjectOf(id); o != nil {
     27 		return o
     28 	}
     29 	panic(fmt.Sprintf("no types.Object for ast.Ident %s @ %s",
     30 		id.Name, f.Prog.Fset.Position(id.Pos())))
     31 }
     32 
     33 // Like TypeOf, but panics instead of returning nil.
     34 // Only valid during f's create and build phases.
     35 func (f *Function) typeOf(e ast.Expr) types.Type {
     36 	if T := f.info.TypeOf(e); T != nil {
     37 		return f.typ(T)
     38 	}
     39 	panic(fmt.Sprintf("no type for %T @ %s", e, f.Prog.Fset.Position(e.Pos())))
     40 }
     41 
     42 // typ is the locally instantiated type of T.
     43 // If f is not an instantiation, then f.typ(T)==T.
     44 func (f *Function) typ(T types.Type) types.Type {
     45 	return f.subst.typ(T)
     46 }
     47 
     48 // If id is an Instance, returns info.Instances[id].Type.
     49 // Otherwise returns f.typeOf(id).
     50 func (f *Function) instanceType(id *ast.Ident) types.Type {
     51 	if t, ok := f.info.Instances[id]; ok {
     52 		return t.Type
     53 	}
     54 	return f.typeOf(id)
     55 }
     56 
     57 // selection returns a *selection corresponding to f.info.Selections[selector]
     58 // with potential updates for type substitution.
     59 func (f *Function) selection(selector *ast.SelectorExpr) *selection {
     60 	sel := f.info.Selections[selector]
     61 	if sel == nil {
     62 		return nil
     63 	}
     64 
     65 	switch sel.Kind() {
     66 	case types.MethodExpr, types.MethodVal:
     67 		if recv := f.typ(sel.Recv()); recv != sel.Recv() {
     68 			// recv changed during type substitution.
     69 			pkg := f.declaredPackage().Pkg
     70 			obj, index, indirect := types.LookupFieldOrMethod(recv, true, pkg, sel.Obj().Name())
     71 
     72 			// sig replaces sel.Type(). See (types.Selection).Typ() for details.
     73 			sig := obj.Type().(*types.Signature)
     74 			sig = changeRecv(sig, newVar(sig.Recv().Name(), recv))
     75 			if sel.Kind() == types.MethodExpr {
     76 				sig = recvAsFirstArg(sig)
     77 			}
     78 			return &selection{
     79 				kind:     sel.Kind(),
     80 				recv:     recv,
     81 				typ:      sig,
     82 				obj:      obj,
     83 				index:    index,
     84 				indirect: indirect,
     85 			}
     86 		}
     87 	}
     88 	return toSelection(sel)
     89 }
     90 
     91 // Destinations associated with unlabelled for/switch/select stmts.
     92 // We push/pop one of these as we enter/leave each construct and for
     93 // each BranchStmt we scan for the innermost target of the right type.
     94 type targets struct {
     95 	tail         *targets // rest of stack
     96 	_break       *BasicBlock
     97 	_continue    *BasicBlock
     98 	_fallthrough *BasicBlock
     99 }
    100 
    101 // Destinations associated with a labelled block.
    102 // We populate these as labels are encountered in forward gotos or
    103 // labelled statements.
    104 // Forward gotos are resolved once it is known which statement they
    105 // are associated with inside the Function.
    106 type lblock struct {
    107 	label     *types.Label // Label targeted by the blocks.
    108 	resolved  bool         // _goto block encountered (back jump or resolved fwd jump)
    109 	_goto     *BasicBlock
    110 	_break    *BasicBlock
    111 	_continue *BasicBlock
    112 }
    113 
    114 // label returns the symbol denoted by a label identifier.
    115 //
    116 // label should be a non-blank identifier (label.Name != "_").
    117 func (f *Function) label(label *ast.Ident) *types.Label {
    118 	return f.objectOf(label).(*types.Label)
    119 }
    120 
    121 // lblockOf returns the branch target associated with the
    122 // specified label, creating it if needed.
    123 func (f *Function) lblockOf(label *types.Label) *lblock {
    124 	lb := f.lblocks[label]
    125 	if lb == nil {
    126 		lb = &lblock{
    127 			label: label,
    128 			_goto: f.newBasicBlock(label.Name()),
    129 		}
    130 		if f.lblocks == nil {
    131 			f.lblocks = make(map[*types.Label]*lblock)
    132 		}
    133 		f.lblocks[label] = lb
    134 	}
    135 	return lb
    136 }
    137 
    138 // labelledBlock searches f for the block of the specified label.
    139 //
    140 // If f is a yield function, it additionally searches ancestor Functions
    141 // corresponding to enclosing range-over-func statements within the
    142 // same source function, so the returned block may belong to a different Function.
    143 func labelledBlock(f *Function, label *types.Label, tok token.Token) *BasicBlock {
    144 	if lb := f.lblocks[label]; lb != nil {
    145 		var block *BasicBlock
    146 		switch tok {
    147 		case token.BREAK:
    148 			block = lb._break
    149 		case token.CONTINUE:
    150 			block = lb._continue
    151 		case token.GOTO:
    152 			block = lb._goto
    153 		}
    154 		if block != nil {
    155 			return block
    156 		}
    157 	}
    158 	// Search ancestors if this is a yield function.
    159 	if f.jump != nil {
    160 		return labelledBlock(f.parent, label, tok)
    161 	}
    162 	return nil
    163 }
    164 
    165 // targetedBlock looks for the nearest block in f.targets
    166 // (and f's ancestors) that matches tok's type, and returns
    167 // the block and function it was found in.
    168 func targetedBlock(f *Function, tok token.Token) *BasicBlock {
    169 	if f == nil {
    170 		return nil
    171 	}
    172 	for t := f.targets; t != nil; t = t.tail {
    173 		var block *BasicBlock
    174 		switch tok {
    175 		case token.BREAK:
    176 			block = t._break
    177 		case token.CONTINUE:
    178 			block = t._continue
    179 		case token.FALLTHROUGH:
    180 			block = t._fallthrough
    181 		}
    182 		if block != nil {
    183 			return block
    184 		}
    185 	}
    186 	// Search f's ancestors (in case f is a yield function).
    187 	return targetedBlock(f.parent, tok)
    188 }
    189 
    190 // instrs returns an iterator that returns each reachable instruction of the SSA function.
    191 func (f *Function) instrs() iter.Seq[Instruction] {
    192 	return func(yield func(i Instruction) bool) {
    193 		for _, block := range f.Blocks {
    194 			for _, instr := range block.Instrs {
    195 				if !yield(instr) {
    196 					return
    197 				}
    198 			}
    199 		}
    200 	}
    201 }
    202 
    203 // addResultVar adds a result for a variable v to f.results and v to f.returnVars.
    204 func (f *Function) addResultVar(v *types.Var) {
    205 	result := emitLocalVar(f, v)
    206 	f.results = append(f.results, result)
    207 	f.returnVars = append(f.returnVars, v)
    208 }
    209 
    210 // addParamVar adds a parameter to f.Params.
    211 func (f *Function) addParamVar(v *types.Var) *Parameter {
    212 	name := v.Name()
    213 	if name == "" {
    214 		name = fmt.Sprintf("arg%d", len(f.Params))
    215 	}
    216 	param := &Parameter{
    217 		name:   name,
    218 		object: v,
    219 		typ:    f.typ(v.Type()),
    220 		parent: f,
    221 	}
    222 	f.Params = append(f.Params, param)
    223 	return param
    224 }
    225 
    226 // addSpilledParam declares a parameter that is pre-spilled to the
    227 // stack; the function body will load/store the spilled location.
    228 // Subsequent lifting will eliminate spills where possible.
    229 func (f *Function) addSpilledParam(obj *types.Var) {
    230 	param := f.addParamVar(obj)
    231 	spill := emitLocalVar(f, obj)
    232 	f.emit(&Store{Addr: spill, Val: param})
    233 }
    234 
    235 // startBody initializes the function prior to generating SSA code for its body.
    236 // Precondition: f.Type() already set.
    237 func (f *Function) startBody() {
    238 	f.currentBlock = f.newBasicBlock("entry")
    239 	f.vars = make(map[*types.Var]Value) // needed for some synthetics, e.g. init
    240 }
    241 
    242 // createSyntacticParams populates f.Params and generates code (spills
    243 // and named result locals) for all the parameters declared in the
    244 // syntax.  In addition it populates the f.objects mapping.
    245 //
    246 // Preconditions:
    247 // f.startBody() was called. f.info != nil.
    248 // Postcondition:
    249 // len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
    250 func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) {
    251 	// Receiver (at most one inner iteration).
    252 	if recv != nil {
    253 		for _, field := range recv.List {
    254 			for _, n := range field.Names {
    255 				f.addSpilledParam(identVar(f, n))
    256 			}
    257 			// Anonymous receiver?  No need to spill.
    258 			if field.Names == nil {
    259 				f.addParamVar(f.Signature.Recv())
    260 			}
    261 		}
    262 	}
    263 
    264 	// Parameters.
    265 	if functype.Params != nil {
    266 		n := len(f.Params) // 1 if has recv, 0 otherwise
    267 		for _, field := range functype.Params.List {
    268 			for _, n := range field.Names {
    269 				f.addSpilledParam(identVar(f, n))
    270 			}
    271 			// Anonymous parameter?  No need to spill.
    272 			if field.Names == nil {
    273 				f.addParamVar(f.Signature.Params().At(len(f.Params) - n))
    274 			}
    275 		}
    276 	}
    277 
    278 	// Results.
    279 	if functype.Results != nil {
    280 		for _, field := range functype.Results.List {
    281 			// Implicit "var" decl of locals for named results.
    282 			for _, n := range field.Names {
    283 				v := identVar(f, n)
    284 				f.addResultVar(v)
    285 			}
    286 			// Implicit "var" decl of local for an unnamed result.
    287 			if field.Names == nil {
    288 				v := f.Signature.Results().At(len(f.results))
    289 				f.addResultVar(v)
    290 			}
    291 		}
    292 	}
    293 }
    294 
    295 // createDeferStack initializes fn.deferstack to local variable
    296 // initialized to a ssa:deferstack() call.
    297 func (fn *Function) createDeferStack() {
    298 	// Each syntactic function makes a call to ssa:deferstack,
    299 	// which is spilled to a local. Unused ones are later removed.
    300 	fn.deferstack = newVar("defer$stack", tDeferStack)
    301 	call := &Call{Call: CallCommon{Value: vDeferStack}}
    302 	call.setType(tDeferStack)
    303 	deferstack := fn.emit(call)
    304 	spill := emitLocalVar(fn, fn.deferstack)
    305 	emitStore(fn, spill, deferstack, token.NoPos)
    306 }
    307 
    308 type setNumable interface {
    309 	setNum(int)
    310 }
    311 
    312 // numberRegisters assigns numbers to all SSA registers
    313 // (value-defining Instructions) in f, to aid debugging.
    314 // (Non-Instruction Values are named at construction.)
    315 func numberRegisters(f *Function) {
    316 	v := 0
    317 	for _, b := range f.Blocks {
    318 		for _, instr := range b.Instrs {
    319 			switch instr.(type) {
    320 			case Value:
    321 				instr.(setNumable).setNum(v)
    322 				v++
    323 			}
    324 		}
    325 	}
    326 }
    327 
    328 // buildReferrers populates the def/use information in all non-nil
    329 // Value.Referrers slice.
    330 // Precondition: all such slices are initially empty.
    331 func buildReferrers(f *Function) {
    332 	var rands []*Value
    333 	for _, b := range f.Blocks {
    334 		for _, instr := range b.Instrs {
    335 			rands = instr.Operands(rands[:0]) // recycle storage
    336 			for _, rand := range rands {
    337 				if r := *rand; r != nil {
    338 					if ref := r.Referrers(); ref != nil {
    339 						*ref = append(*ref, instr)
    340 					}
    341 				}
    342 			}
    343 		}
    344 	}
    345 }
    346 
    347 // finishBody() finalizes the contents of the function after SSA code generation of its body.
    348 //
    349 // The function is not done being built until done() is called.
    350 func (f *Function) finishBody() {
    351 	f.currentBlock = nil
    352 	f.lblocks = nil
    353 	f.returnVars = nil
    354 	f.jump = nil
    355 	f.source = nil
    356 	f.exits = nil
    357 
    358 	// Remove from f.Locals any Allocs that escape to the heap.
    359 	j := 0
    360 	for _, l := range f.Locals {
    361 		if !l.Heap {
    362 			f.Locals[j] = l
    363 			j++
    364 		}
    365 	}
    366 	// Nil out f.Locals[j:] to aid GC.
    367 	for i := j; i < len(f.Locals); i++ {
    368 		f.Locals[i] = nil
    369 	}
    370 	f.Locals = f.Locals[:j]
    371 
    372 	optimizeBlocks(f)
    373 
    374 	buildReferrers(f)
    375 
    376 	buildDomTree(f)
    377 
    378 	if f.Prog.mode&NaiveForm == 0 {
    379 		// For debugging pre-state of lifting pass:
    380 		// numberRegisters(f)
    381 		// f.WriteTo(os.Stderr)
    382 		lift(f)
    383 	}
    384 
    385 	// clear remaining builder state
    386 	f.results = nil    // (used by lifting)
    387 	f.deferstack = nil // (used by lifting)
    388 	f.vars = nil       // (used by lifting)
    389 
    390 	// clear out other function state (keep consistent with buildParamsOnly)
    391 	f.subst = nil
    392 
    393 	numberRegisters(f) // uses f.namedRegisters
    394 }
    395 
    396 // done marks the building of f's SSA body complete,
    397 // along with any nested functions, and optionally prints them.
    398 func (f *Function) done() {
    399 	assert(f.parent == nil, "done called on an anonymous function")
    400 
    401 	var visit func(*Function)
    402 	visit = func(f *Function) {
    403 		for _, anon := range f.AnonFuncs {
    404 			visit(anon) // anon is done building before f.
    405 		}
    406 
    407 		f.uniq = 0    // done with uniq
    408 		f.build = nil // function is built
    409 
    410 		if f.Prog.mode&PrintFunctions != 0 {
    411 			printMu.Lock()
    412 			f.WriteTo(os.Stdout)
    413 			printMu.Unlock()
    414 		}
    415 
    416 		if f.Prog.mode&SanityCheckFunctions != 0 {
    417 			mustSanityCheck(f, nil)
    418 		}
    419 	}
    420 	visit(f)
    421 }
    422 
    423 // removeNilBlocks eliminates nils from f.Blocks and updates each
    424 // BasicBlock.Index.  Use this after any pass that may delete blocks.
    425 func (f *Function) removeNilBlocks() {
    426 	j := 0
    427 	for _, b := range f.Blocks {
    428 		if b != nil {
    429 			b.Index = j
    430 			f.Blocks[j] = b
    431 			j++
    432 		}
    433 	}
    434 	// Nil out f.Blocks[j:] to aid GC.
    435 	for i := j; i < len(f.Blocks); i++ {
    436 		f.Blocks[i] = nil
    437 	}
    438 	f.Blocks = f.Blocks[:j]
    439 }
    440 
    441 // SetDebugMode sets the debug mode for package pkg.  If true, all its
    442 // functions will include full debug info.  This greatly increases the
    443 // size of the instruction stream, and causes Functions to depend upon
    444 // the ASTs, potentially keeping them live in memory for longer.
    445 func (pkg *Package) SetDebugMode(debug bool) {
    446 	pkg.debug = debug
    447 }
    448 
    449 // debugInfo reports whether debug info is wanted for this function.
    450 func (f *Function) debugInfo() bool {
    451 	// debug info for instantiations follows the debug info of their origin.
    452 	p := f.declaredPackage()
    453 	return p != nil && p.debug
    454 }
    455 
    456 // lookup returns the address of the named variable identified by obj
    457 // that is local to function f or one of its enclosing functions.
    458 // If escaping, the reference comes from a potentially escaping pointer
    459 // expression and the referent must be heap-allocated.
    460 // We assume the referent is a *Alloc or *Phi.
    461 // (The only Phis at this stage are those created directly by go1.22 "for" loops.)
    462 func (f *Function) lookup(obj *types.Var, escaping bool) Value {
    463 	if v, ok := f.vars[obj]; ok {
    464 		if escaping {
    465 			switch v := v.(type) {
    466 			case *Alloc:
    467 				v.Heap = true
    468 			case *Phi:
    469 				for _, edge := range v.Edges {
    470 					if alloc, ok := edge.(*Alloc); ok {
    471 						alloc.Heap = true
    472 					}
    473 				}
    474 			}
    475 		}
    476 		return v // function-local var (address)
    477 	}
    478 
    479 	// Definition must be in an enclosing function;
    480 	// plumb it through intervening closures.
    481 	if f.parent == nil {
    482 		panic("no ssa.Value for " + obj.String())
    483 	}
    484 	outer := f.parent.lookup(obj, true) // escaping
    485 	v := &FreeVar{
    486 		name:   obj.Name(),
    487 		typ:    outer.Type(),
    488 		pos:    outer.Pos(),
    489 		outer:  outer,
    490 		parent: f,
    491 	}
    492 	f.vars[obj] = v
    493 	f.FreeVars = append(f.FreeVars, v)
    494 	return v
    495 }
    496 
    497 // emit emits the specified instruction to function f.
    498 func (f *Function) emit(instr Instruction) Value {
    499 	return f.currentBlock.emit(instr)
    500 }
    501 
    502 // RelString returns the full name of this function, qualified by
    503 // package name, receiver type, etc.
    504 //
    505 // The specific formatting rules are not guaranteed and may change.
    506 //
    507 // Examples:
    508 //
    509 //	"math.IsNaN"                  // a package-level function
    510 //	"(*bytes.Buffer).Bytes"       // a declared method or a wrapper
    511 //	"(*bytes.Buffer).Bytes$thunk" // thunk (func wrapping method; receiver is param 0)
    512 //	"(*bytes.Buffer).Bytes$bound" // bound (func wrapping method; receiver supplied by closure)
    513 //	"main.main$1"                 // an anonymous function in main
    514 //	"main.init#1"                 // a declared init function
    515 //	"main.init"                   // the synthesized package initializer
    516 //
    517 // When these functions are referred to from within the same package
    518 // (i.e. from == f.Pkg.Object), they are rendered without the package path.
    519 // For example: "IsNaN", "(*Buffer).Bytes", etc.
    520 //
    521 // All non-synthetic functions have distinct package-qualified names.
    522 // (But two methods may have the same name "(T).f" if one is a synthetic
    523 // wrapper promoting a non-exported method "f" from another package; in
    524 // that case, the strings are equal but the identifiers "f" are distinct.)
    525 func (f *Function) RelString(from *types.Package) string {
    526 	// Anonymous?
    527 	if f.parent != nil {
    528 		// An anonymous function's Name() looks like "parentName$1",
    529 		// but its String() should include the type/package/etc.
    530 		parent := f.parent.RelString(from)
    531 		for i, anon := range f.parent.AnonFuncs {
    532 			if anon == f {
    533 				return fmt.Sprintf("%s$%d", parent, 1+i)
    534 			}
    535 		}
    536 
    537 		return f.name // should never happen
    538 	}
    539 
    540 	// Method (declared or wrapper)?
    541 	if recv := f.Signature.Recv(); recv != nil {
    542 		return f.relMethod(from, recv.Type())
    543 	}
    544 
    545 	// Thunk?
    546 	if f.method != nil {
    547 		return f.relMethod(from, f.method.recv)
    548 	}
    549 
    550 	// Bound?
    551 	if len(f.FreeVars) == 1 && strings.HasSuffix(f.name, "$bound") {
    552 		return f.relMethod(from, f.FreeVars[0].Type())
    553 	}
    554 
    555 	// Package-level function?
    556 	// Prefix with package name for cross-package references only.
    557 	if p := f.relPkg(); p != nil && p != from {
    558 		return fmt.Sprintf("%s.%s", p.Path(), f.name)
    559 	}
    560 
    561 	// Unknown.
    562 	return f.name
    563 }
    564 
    565 func (f *Function) relMethod(from *types.Package, recv types.Type) string {
    566 	return fmt.Sprintf("(%s).%s", relType(recv, from), f.name)
    567 }
    568 
    569 // writeSignature writes to buf the signature sig in declaration syntax.
    570 func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature) {
    571 	buf.WriteString("func ")
    572 	if recv := sig.Recv(); recv != nil {
    573 		buf.WriteString("(")
    574 		if name := recv.Name(); name != "" {
    575 			buf.WriteString(name)
    576 			buf.WriteString(" ")
    577 		}
    578 		types.WriteType(buf, recv.Type(), types.RelativeTo(from))
    579 		buf.WriteString(") ")
    580 	}
    581 	buf.WriteString(name)
    582 	types.WriteSignature(buf, sig, types.RelativeTo(from))
    583 }
    584 
    585 // declaredPackage returns the package fn is declared in or nil if the
    586 // function is not declared in a package.
    587 func (fn *Function) declaredPackage() *Package {
    588 	switch {
    589 	case fn.Pkg != nil:
    590 		return fn.Pkg // non-generic function  (does that follow??)
    591 	case fn.topLevelOrigin != nil:
    592 		return fn.topLevelOrigin.Pkg // instance of a named generic function
    593 	case fn.parent != nil:
    594 		return fn.parent.declaredPackage() // instance of an anonymous [generic] function
    595 	default:
    596 		return nil // function is not declared in a package, e.g. a wrapper.
    597 	}
    598 }
    599 
    600 // relPkg returns types.Package fn is printed in relationship to.
    601 func (fn *Function) relPkg() *types.Package {
    602 	if p := fn.declaredPackage(); p != nil {
    603 		return p.Pkg
    604 	}
    605 	return nil
    606 }
    607 
    608 var _ io.WriterTo = (*Function)(nil) // *Function implements io.Writer
    609 
    610 func (f *Function) WriteTo(w io.Writer) (int64, error) {
    611 	var buf bytes.Buffer
    612 	WriteFunction(&buf, f)
    613 	n, err := w.Write(buf.Bytes())
    614 	return int64(n), err
    615 }
    616 
    617 // WriteFunction writes to buf a human-readable "disassembly" of f.
    618 func WriteFunction(buf *bytes.Buffer, f *Function) {
    619 	fmt.Fprintf(buf, "# Name: %s\n", f.String())
    620 	if f.Pkg != nil {
    621 		fmt.Fprintf(buf, "# Package: %s\n", f.Pkg.Pkg.Path())
    622 	}
    623 	if syn := f.Synthetic; syn != "" {
    624 		fmt.Fprintln(buf, "# Synthetic:", syn)
    625 	}
    626 	if pos := f.Pos(); pos.IsValid() {
    627 		fmt.Fprintf(buf, "# Location: %s\n", f.Prog.Fset.Position(pos))
    628 	}
    629 
    630 	if f.parent != nil {
    631 		fmt.Fprintf(buf, "# Parent: %s\n", f.parent.Name())
    632 	}
    633 
    634 	if f.Recover != nil {
    635 		fmt.Fprintf(buf, "# Recover: %s\n", f.Recover)
    636 	}
    637 
    638 	from := f.relPkg()
    639 
    640 	if f.FreeVars != nil {
    641 		buf.WriteString("# Free variables:\n")
    642 		for i, fv := range f.FreeVars {
    643 			fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), from))
    644 		}
    645 	}
    646 
    647 	if len(f.Locals) > 0 {
    648 		buf.WriteString("# Locals:\n")
    649 		for i, l := range f.Locals {
    650 			fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(typeparams.MustDeref(l.Type()), from))
    651 		}
    652 	}
    653 	writeSignature(buf, from, f.Name(), f.Signature)
    654 	buf.WriteString(":\n")
    655 
    656 	if f.Blocks == nil {
    657 		buf.WriteString("\t(external)\n")
    658 	}
    659 
    660 	// NB. column calculations are confused by non-ASCII
    661 	// characters and assume 8-space tabs.
    662 	const punchcard = 80 // for old time's sake.
    663 	const tabwidth = 8
    664 	for _, b := range f.Blocks {
    665 		if b == nil {
    666 			// Corrupt CFG.
    667 			fmt.Fprintf(buf, ".nil:\n")
    668 			continue
    669 		}
    670 		n, _ := fmt.Fprintf(buf, "%d:", b.Index)
    671 		// (|predecessors|, |successors|, immediate dominator)
    672 		bmsg := fmt.Sprintf("%s P:%d S:%d", b.Comment, len(b.Preds), len(b.Succs))
    673 		if b.Idom() != nil {
    674 			bmsg = fmt.Sprintf("%s idom:%d", bmsg, b.Idom().Index)
    675 		}
    676 		fmt.Fprintf(buf, "%*s%s\n", punchcard-1-n-len(bmsg), "", bmsg)
    677 
    678 		if false { // CFG debugging
    679 			fmt.Fprintf(buf, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
    680 		}
    681 		for _, instr := range b.Instrs {
    682 			buf.WriteString("\t")
    683 			switch v := instr.(type) {
    684 			case Value:
    685 				l := punchcard - tabwidth
    686 				// Left-align the instruction.
    687 				if name := v.Name(); name != "" {
    688 					n, _ := fmt.Fprintf(buf, "%s = ", name)
    689 					l -= n
    690 				}
    691 				n, _ := buf.WriteString(instr.String())
    692 				l -= n
    693 				// Right-align the type if there's space.
    694 				if t := v.Type(); t != nil {
    695 					buf.WriteByte(' ')
    696 					ts := relType(t, from)
    697 					l -= len(ts) + len("  ") // (spaces before and after type)
    698 					if l > 0 {
    699 						fmt.Fprintf(buf, "%*s", l, "")
    700 					}
    701 					buf.WriteString(ts)
    702 				}
    703 			case nil:
    704 				// Be robust against bad transforms.
    705 				buf.WriteString("<deleted>")
    706 			default:
    707 				buf.WriteString(instr.String())
    708 			}
    709 			// -mode=S: show line numbers
    710 			if f.Prog.mode&LogSource != 0 {
    711 				if pos := instr.Pos(); pos.IsValid() {
    712 					fmt.Fprintf(buf, " L%d", f.Prog.Fset.Position(pos).Line)
    713 				}
    714 			}
    715 			buf.WriteString("\n")
    716 		}
    717 	}
    718 	fmt.Fprintf(buf, "\n")
    719 }
    720 
    721 // newBasicBlock adds to f a new basic block and returns it.  It does
    722 // not automatically become the current block for subsequent calls to emit.
    723 // comment is an optional string for more readable debugging output.
    724 func (f *Function) newBasicBlock(comment string) *BasicBlock {
    725 	b := &BasicBlock{
    726 		Index:   len(f.Blocks),
    727 		Comment: comment,
    728 		parent:  f,
    729 	}
    730 	b.Succs = b.succs2[:0]
    731 	f.Blocks = append(f.Blocks, b)
    732 	return b
    733 }
    734 
    735 // NewFunction returns a new synthetic Function instance belonging to
    736 // prog, with its name and signature fields set as specified.
    737 //
    738 // The caller is responsible for initializing the remaining fields of
    739 // the function object, e.g. Pkg, Params, Blocks.
    740 //
    741 // It is practically impossible for clients to construct well-formed
    742 // SSA functions/packages/programs directly, so we assume this is the
    743 // job of the Builder alone.  NewFunction exists to provide clients a
    744 // little flexibility.  For example, analysis tools may wish to
    745 // construct fake Functions for the root of the callgraph, a fake
    746 // "reflect" package, etc.
    747 //
    748 // TODO(adonovan): think harder about the API here.
    749 func (prog *Program) NewFunction(name string, sig *types.Signature, provenance string) *Function {
    750 	return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
    751 }
    752 
    753 // Syntax returns the function's syntax (*ast.Func{Decl,Lit})
    754 // if it was produced from syntax or an *ast.RangeStmt if
    755 // it is a range-over-func yield function.
    756 func (f *Function) Syntax() ast.Node { return f.syntax }
    757 
    758 // identVar returns the variable defined by id.
    759 func identVar(fn *Function, id *ast.Ident) *types.Var {
    760 	return fn.info.Defs[id].(*types.Var)
    761 }
    762 
    763 // unique returns a unique positive int within the source tree of f.
    764 // The source tree of f includes all of f's ancestors by parent and all
    765 // of the AnonFuncs contained within these.
    766 func unique(f *Function) int64 {
    767 	f.uniq++
    768 	return f.uniq
    769 }
    770 
    771 // exit is a change of control flow going from a range-over-func
    772 // yield function to an ancestor function caused by a break, continue,
    773 // goto, or return statement.
    774 //
    775 // There are 3 types of exits:
    776 // * return from the source function (from ReturnStmt),
    777 // * jump to a block (from break and continue statements [labelled/unlabelled]),
    778 // * go to a label (from goto statements).
    779 //
    780 // As the builder does one pass over the ast, it is unclear whether
    781 // a forward goto statement will leave a range-over-func body.
    782 // The function being exited to is unresolved until the end
    783 // of building the range-over-func body.
    784 type exit struct {
    785 	id   int64     // unique value for exit within from and to
    786 	from *Function // the function the exit starts from
    787 	to   *Function // the function being exited to (nil if unresolved)
    788 	pos  token.Pos
    789 
    790 	block *BasicBlock  // basic block within to being jumped to.
    791 	label *types.Label // forward label being jumped to via goto.
    792 	// block == nil && label == nil => return
    793 }
    794 
    795 // storeVar emits to function f code to store a value v to a *types.Var x.
    796 func storeVar(f *Function, x *types.Var, v Value, pos token.Pos) {
    797 	emitStore(f, f.lookup(x, true), v, pos)
    798 }
    799 
    800 // labelExit creates a new exit to a yield fn to exit the function using a label.
    801 func labelExit(fn *Function, label *types.Label, pos token.Pos) *exit {
    802 	e := &exit{
    803 		id:    unique(fn),
    804 		from:  fn,
    805 		to:    nil,
    806 		pos:   pos,
    807 		label: label,
    808 	}
    809 	fn.exits = append(fn.exits, e)
    810 	return e
    811 }
    812 
    813 // blockExit creates a new exit to a yield fn that jumps to a basic block.
    814 func blockExit(fn *Function, block *BasicBlock, pos token.Pos) *exit {
    815 	e := &exit{
    816 		id:    unique(fn),
    817 		from:  fn,
    818 		to:    block.parent,
    819 		pos:   pos,
    820 		block: block,
    821 	}
    822 	fn.exits = append(fn.exits, e)
    823 	return e
    824 }
    825 
    826 // returnExit creates a new exit to a yield fn that returns the source function.
    827 func returnExit(fn *Function, pos token.Pos) *exit {
    828 	e := &exit{
    829 		id:   unique(fn),
    830 		from: fn,
    831 		to:   fn.source,
    832 		pos:  pos,
    833 	}
    834 	fn.exits = append(fn.exits, e)
    835 	return e
    836 }