github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/ir/func.go (about)

     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 ir
     6  
     7  // This file implements the Function and BasicBlock types.
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/ast"
    13  	"go/format"
    14  	"go/token"
    15  	"go/types"
    16  	"io"
    17  	"os"
    18  	"sort"
    19  	"strings"
    20  
    21  	"github.com/amarpal/go-tools/go/types/typeutil"
    22  )
    23  
    24  // addEdge adds a control-flow graph edge from from to to.
    25  func addEdge(from, to *BasicBlock) {
    26  	from.Succs = append(from.Succs, to)
    27  	to.Preds = append(to.Preds, from)
    28  }
    29  
    30  // Control returns the last instruction in the block.
    31  func (b *BasicBlock) Control() Instruction {
    32  	if len(b.Instrs) == 0 {
    33  		return nil
    34  	}
    35  	return b.Instrs[len(b.Instrs)-1]
    36  }
    37  
    38  // SigmaFor returns the sigma node for v coming from pred.
    39  func (b *BasicBlock) SigmaFor(v Value, pred *BasicBlock) *Sigma {
    40  	for _, instr := range b.Instrs {
    41  		sigma, ok := instr.(*Sigma)
    42  		if !ok {
    43  			// no more sigmas
    44  			return nil
    45  		}
    46  		if sigma.From == pred && sigma.X == v {
    47  			return sigma
    48  		}
    49  	}
    50  	return nil
    51  }
    52  
    53  // Parent returns the function that contains block b.
    54  func (b *BasicBlock) Parent() *Function { return b.parent }
    55  
    56  // String returns a human-readable label of this block.
    57  // It is not guaranteed unique within the function.
    58  func (b *BasicBlock) String() string {
    59  	return fmt.Sprintf("%d", b.Index)
    60  }
    61  
    62  // emit appends an instruction to the current basic block.
    63  // If the instruction defines a Value, it is returned.
    64  func (b *BasicBlock) emit(i Instruction, source ast.Node) Value {
    65  	i.setSource(source)
    66  	i.setBlock(b)
    67  	b.Instrs = append(b.Instrs, i)
    68  	v, _ := i.(Value)
    69  	return v
    70  }
    71  
    72  // predIndex returns the i such that b.Preds[i] == c or panics if
    73  // there is none.
    74  func (b *BasicBlock) predIndex(c *BasicBlock) int {
    75  	for i, pred := range b.Preds {
    76  		if pred == c {
    77  			return i
    78  		}
    79  	}
    80  	panic(fmt.Sprintf("no edge %s -> %s", c, b))
    81  }
    82  
    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 {
    86  		if succ == c {
    87  			return i
    88  		}
    89  	}
    90  	return -1
    91  }
    92  
    93  // hasPhi returns true if b.Instrs contains φ-nodes.
    94  func (b *BasicBlock) hasPhi() bool {
    95  	_, ok := b.Instrs[0].(*Phi)
    96  	return ok
    97  }
    98  
    99  func (b *BasicBlock) Phis() []Instruction {
   100  	return b.phis()
   101  }
   102  
   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 {
   107  			return b.Instrs[:i]
   108  		}
   109  	}
   110  	return nil // unreachable in well-formed blocks
   111  }
   112  
   113  // replacePred replaces all occurrences of p in b's predecessor list with q.
   114  // Ordinarily there should be at most one.
   115  func (b *BasicBlock) replacePred(p, q *BasicBlock) {
   116  	for i, pred := range b.Preds {
   117  		if pred == p {
   118  			b.Preds[i] = q
   119  		}
   120  	}
   121  }
   122  
   123  // replaceSucc replaces all occurrences of p in b's successor list with q.
   124  // Ordinarily there should be at most one.
   125  func (b *BasicBlock) replaceSucc(p, q *BasicBlock) {
   126  	for i, succ := range b.Succs {
   127  		if succ == p {
   128  			b.Succs[i] = q
   129  		}
   130  	}
   131  }
   132  
   133  // removePred removes all occurrences of p in b's
   134  // predecessor list and φ-nodes.
   135  // Ordinarily there should be at most one.
   136  func (b *BasicBlock) removePred(p *BasicBlock) {
   137  	phis := b.phis()
   138  
   139  	// We must preserve edge order for φ-nodes.
   140  	j := 0
   141  	for i, pred := range b.Preds {
   142  		if pred != p {
   143  			b.Preds[j] = b.Preds[i]
   144  			// Strike out φ-edge too.
   145  			for _, instr := range phis {
   146  				phi := instr.(*Phi)
   147  				phi.Edges[j] = phi.Edges[i]
   148  			}
   149  			j++
   150  		}
   151  	}
   152  	// Nil out b.Preds[j:] and φ-edges[j:] to aid GC.
   153  	for i := j; i < len(b.Preds); i++ {
   154  		b.Preds[i] = nil
   155  		for _, instr := range phis {
   156  			instr.(*Phi).Edges[i] = nil
   157  		}
   158  	}
   159  	b.Preds = b.Preds[:j]
   160  	for _, instr := range phis {
   161  		phi := instr.(*Phi)
   162  		phi.Edges = phi.Edges[:j]
   163  	}
   164  }
   165  
   166  // Destinations associated with unlabelled for/switch/select stmts.
   167  // We push/pop one of these as we enter/leave each construct and for
   168  // each BranchStmt we scan for the innermost target of the right type.
   169  type targets struct {
   170  	tail         *targets // rest of stack
   171  	_break       *BasicBlock
   172  	_continue    *BasicBlock
   173  	_fallthrough *BasicBlock
   174  }
   175  
   176  // Destinations associated with a labelled block.
   177  // We populate these as labels are encountered in forward gotos or
   178  // labelled statements.
   179  type lblock struct {
   180  	_goto     *BasicBlock
   181  	_break    *BasicBlock
   182  	_continue *BasicBlock
   183  }
   184  
   185  // labelledBlock returns the branch target associated with the
   186  // specified label, creating it if needed.
   187  func (f *Function) labelledBlock(label *ast.Ident) *lblock {
   188  	obj := f.Pkg.info.ObjectOf(label)
   189  	if obj == nil {
   190  		// Blank label, as in '_:' - don't store to f.lblocks, this label can never be referred to; just return a fresh
   191  		// lbock.
   192  		return &lblock{_goto: f.newBasicBlock(label.Name)}
   193  	}
   194  
   195  	lb := f.lblocks[obj]
   196  	if lb == nil {
   197  		lb = &lblock{_goto: f.newBasicBlock(label.Name)}
   198  		if f.lblocks == nil {
   199  			f.lblocks = make(map[types.Object]*lblock)
   200  		}
   201  		f.lblocks[obj] = lb
   202  	}
   203  	return lb
   204  }
   205  
   206  // addParam adds a (non-escaping) parameter to f.Params of the
   207  // specified name, type and source position.
   208  func (f *Function) addParam(name string, typ types.Type, source ast.Node) *Parameter {
   209  	var b *BasicBlock
   210  	if len(f.Blocks) > 0 {
   211  		b = f.Blocks[0]
   212  	}
   213  	v := &Parameter{
   214  		name: name,
   215  	}
   216  	v.setBlock(b)
   217  	v.setType(typ)
   218  	v.setSource(source)
   219  	f.Params = append(f.Params, v)
   220  	if b != nil {
   221  		// There may be no blocks if this function has no body. We
   222  		// still create params, but aren't interested in the
   223  		// instruction.
   224  		f.Blocks[0].Instrs = append(f.Blocks[0].Instrs, v)
   225  	}
   226  	return v
   227  }
   228  
   229  func (f *Function) addParamObj(obj types.Object, source ast.Node) *Parameter {
   230  	name := obj.Name()
   231  	if name == "" {
   232  		name = fmt.Sprintf("arg%d", len(f.Params))
   233  	}
   234  	param := f.addParam(name, obj.Type(), source)
   235  	param.object = obj
   236  	return param
   237  }
   238  
   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.
   242  func (f *Function) addSpilledParam(obj types.Object, source ast.Node) {
   243  	param := f.addParamObj(obj, source)
   244  	spill := &Alloc{}
   245  	spill.setType(types.NewPointer(obj.Type()))
   246  	spill.source = source
   247  	f.objects[obj] = spill
   248  	f.Locals = append(f.Locals, spill)
   249  	f.emit(spill, source)
   250  	emitStore(f, spill, param, source)
   251  	// f.emit(&Store{Addr: spill, Val: param})
   252  }
   253  
   254  // startBody initializes the function prior to generating IR code for its body.
   255  // Precondition: f.Type() already set.
   256  func (f *Function) startBody() {
   257  	entry := f.newBasicBlock("entry")
   258  	f.currentBlock = entry
   259  	f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init
   260  }
   261  
   262  func (f *Function) blockset(i int) *BlockSet {
   263  	bs := &f.blocksets[i]
   264  	if len(bs.values) != len(f.Blocks) {
   265  		if cap(bs.values) >= len(f.Blocks) {
   266  			bs.values = bs.values[:len(f.Blocks)]
   267  			bs.Clear()
   268  		} else {
   269  			bs.values = make([]bool, len(f.Blocks))
   270  		}
   271  	} else {
   272  		bs.Clear()
   273  	}
   274  	return bs
   275  }
   276  
   277  func (f *Function) exitBlock() {
   278  	old := f.currentBlock
   279  
   280  	f.Exit = f.newBasicBlock("exit")
   281  	f.currentBlock = f.Exit
   282  
   283  	ret := f.results()
   284  	results := make([]Value, len(ret))
   285  	// Run function calls deferred in this
   286  	// function when explicitly returning from it.
   287  	f.emit(new(RunDefers), nil)
   288  	for i, r := range ret {
   289  		results[i] = emitLoad(f, r, nil)
   290  	}
   291  
   292  	f.emit(&Return{Results: results}, nil)
   293  	f.currentBlock = old
   294  }
   295  
   296  // createSyntacticParams populates f.Params and generates code (spills
   297  // and named result locals) for all the parameters declared in the
   298  // syntax.  In addition it populates the f.objects mapping.
   299  //
   300  // Preconditions:
   301  // f.startBody() was called.
   302  // Postcondition:
   303  // len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
   304  func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) {
   305  	// Receiver (at most one inner iteration).
   306  	if recv != nil {
   307  		for _, field := range recv.List {
   308  			for _, n := range field.Names {
   309  				f.addSpilledParam(f.Pkg.info.Defs[n], n)
   310  			}
   311  			// Anonymous receiver?  No need to spill.
   312  			if field.Names == nil {
   313  				f.addParamObj(f.Signature.Recv(), field)
   314  			}
   315  		}
   316  	}
   317  
   318  	// Parameters.
   319  	if functype.Params != nil {
   320  		n := len(f.Params) // 1 if has recv, 0 otherwise
   321  		for _, field := range functype.Params.List {
   322  			for _, n := range field.Names {
   323  				f.addSpilledParam(f.Pkg.info.Defs[n], n)
   324  			}
   325  			// Anonymous parameter?  No need to spill.
   326  			if field.Names == nil {
   327  				f.addParamObj(f.Signature.Params().At(len(f.Params)-n), field)
   328  			}
   329  		}
   330  	}
   331  
   332  	// Named results.
   333  	if functype.Results != nil {
   334  		for _, field := range functype.Results.List {
   335  			// Implicit "var" decl of locals for named results.
   336  			for _, n := range field.Names {
   337  				f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
   338  			}
   339  		}
   340  
   341  		if len(f.namedResults) == 0 {
   342  			sig := f.Signature.Results()
   343  			for i := 0; i < sig.Len(); i++ {
   344  				// XXX position information
   345  				v := f.addLocal(sig.At(i).Type(), nil)
   346  				f.implicitResults = append(f.implicitResults, v)
   347  			}
   348  		}
   349  	}
   350  }
   351  
   352  func numberNodes(f *Function) {
   353  	var base ID
   354  	for _, b := range f.Blocks {
   355  		for _, instr := range b.Instrs {
   356  			if instr == nil {
   357  				continue
   358  			}
   359  			base++
   360  			instr.setID(base)
   361  		}
   362  	}
   363  }
   364  
   365  func updateOperandsReferrers(instr Instruction, ops []*Value) {
   366  	for _, op := range ops {
   367  		if r := *op; r != nil {
   368  			if refs := (*op).Referrers(); refs != nil {
   369  				if len(*refs) == 0 {
   370  					// per median, each value has two referrers, so we can avoid one call into growslice
   371  					//
   372  					// Note: we experimented with allocating
   373  					// sequential scratch space, but we
   374  					// couldn't find a value that gave better
   375  					// performance than making many individual
   376  					// allocations
   377  					*refs = make([]Instruction, 1, 2)
   378  					(*refs)[0] = instr
   379  				} else {
   380  					*refs = append(*refs, instr)
   381  				}
   382  			}
   383  		}
   384  	}
   385  }
   386  
   387  // buildReferrers populates the def/use information in all non-nil
   388  // Value.Referrers slice.
   389  // Precondition: all such slices are initially empty.
   390  func buildReferrers(f *Function) {
   391  	var rands []*Value
   392  
   393  	for _, b := range f.Blocks {
   394  		for _, instr := range b.Instrs {
   395  			rands = instr.Operands(rands[:0]) // recycle storage
   396  			updateOperandsReferrers(instr, rands)
   397  		}
   398  	}
   399  
   400  	for _, c := range f.consts {
   401  		rands = c.c.Operands(rands[:0])
   402  		updateOperandsReferrers(c.c, rands)
   403  	}
   404  }
   405  
   406  func (f *Function) emitConsts() {
   407  	defer func() {
   408  		f.consts = nil
   409  		f.aggregateConsts = typeutil.Map[[]*AggregateConst]{}
   410  	}()
   411  
   412  	if len(f.Blocks) == 0 {
   413  		return
   414  	}
   415  
   416  	// TODO(dh): our deduplication only works on booleans and
   417  	// integers. other constants are represented as pointers to
   418  	// things.
   419  	head := make([]constValue, 0, len(f.consts))
   420  	for _, c := range f.consts {
   421  		if len(*c.c.Referrers()) == 0 {
   422  			// TODO(dh): killing a const may make other consts dead, too
   423  			killInstruction(c.c)
   424  		} else {
   425  			head = append(head, c)
   426  		}
   427  	}
   428  	sort.Slice(head, func(i, j int) bool {
   429  		return head[i].idx < head[j].idx
   430  	})
   431  	entry := f.Blocks[0]
   432  	instrs := make([]Instruction, 0, len(entry.Instrs)+len(head))
   433  	for _, c := range head {
   434  		instrs = append(instrs, c.c)
   435  	}
   436  	f.aggregateConsts.Iterate(func(key types.Type, value []*AggregateConst) {
   437  		for _, c := range value {
   438  			instrs = append(instrs, c)
   439  		}
   440  	})
   441  
   442  	instrs = append(instrs, entry.Instrs...)
   443  	entry.Instrs = instrs
   444  }
   445  
   446  // buildFakeExits ensures that every block in the function is
   447  // reachable in reverse from the Exit block. This is required to build
   448  // a full post-dominator tree, and to ensure the exit block's
   449  // inclusion in the dominator tree.
   450  func buildFakeExits(fn *Function) {
   451  	// Find back-edges via forward DFS
   452  	fn.fakeExits = BlockSet{values: make([]bool, len(fn.Blocks))}
   453  	seen := fn.blockset(0)
   454  	backEdges := fn.blockset(1)
   455  
   456  	var dfs func(b *BasicBlock)
   457  	dfs = func(b *BasicBlock) {
   458  		if !seen.Add(b) {
   459  			backEdges.Add(b)
   460  			return
   461  		}
   462  		for _, pred := range b.Succs {
   463  			dfs(pred)
   464  		}
   465  	}
   466  	dfs(fn.Blocks[0])
   467  buildLoop:
   468  	for {
   469  		seen := fn.blockset(2)
   470  		var dfs func(b *BasicBlock)
   471  		dfs = func(b *BasicBlock) {
   472  			if !seen.Add(b) {
   473  				return
   474  			}
   475  			for _, pred := range b.Preds {
   476  				dfs(pred)
   477  			}
   478  			if b == fn.Exit {
   479  				for _, b := range fn.Blocks {
   480  					if fn.fakeExits.Has(b) {
   481  						dfs(b)
   482  					}
   483  				}
   484  			}
   485  		}
   486  		dfs(fn.Exit)
   487  
   488  		for _, b := range fn.Blocks {
   489  			if !seen.Has(b) && backEdges.Has(b) {
   490  				// Block b is not reachable from the exit block. Add a
   491  				// fake jump from b to exit, then try again. Note that we
   492  				// only add one fake edge at a time, as it may make
   493  				// multiple blocks reachable.
   494  				//
   495  				// We only consider those blocks that have back edges.
   496  				// Any unreachable block that doesn't have a back edge
   497  				// must flow into a loop, which by definition has a
   498  				// back edge. Thus, by looking for loops, we should
   499  				// need fewer fake edges overall.
   500  				fn.fakeExits.Add(b)
   501  				continue buildLoop
   502  			}
   503  		}
   504  
   505  		break
   506  	}
   507  }
   508  
   509  // finishBody() finalizes the function after IR code generation of its body.
   510  func (f *Function) finishBody() {
   511  	f.objects = nil
   512  	f.currentBlock = nil
   513  	f.lblocks = nil
   514  
   515  	// Remove from f.Locals any Allocs that escape to the heap.
   516  	j := 0
   517  	for _, l := range f.Locals {
   518  		if !l.Heap {
   519  			f.Locals[j] = l
   520  			j++
   521  		}
   522  	}
   523  	// Nil out f.Locals[j:] to aid GC.
   524  	for i := j; i < len(f.Locals); i++ {
   525  		f.Locals[i] = nil
   526  	}
   527  	f.Locals = f.Locals[:j]
   528  
   529  	optimizeBlocks(f)
   530  	buildFakeExits(f)
   531  	buildReferrers(f)
   532  	buildDomTree(f)
   533  	buildPostDomTree(f)
   534  
   535  	if f.Prog.mode&NaiveForm == 0 {
   536  		for lift(f) {
   537  		}
   538  		if doSimplifyConstantCompositeValues {
   539  			for simplifyConstantCompositeValues(f) {
   540  			}
   541  		}
   542  	}
   543  
   544  	// emit constants after lifting, because lifting may produce new constants, but before other variable splitting,
   545  	// because it expects constants to have been deduplicated.
   546  	f.emitConsts()
   547  
   548  	if f.Prog.mode&SplitAfterNewInformation != 0 {
   549  		splitOnNewInformation(f.Blocks[0], &StackMap{})
   550  	}
   551  
   552  	f.namedResults = nil // (used by lifting)
   553  	f.implicitResults = nil
   554  
   555  	numberNodes(f)
   556  
   557  	defer f.wr.Close()
   558  	f.wr.WriteFunc("start", "start", f)
   559  
   560  	if f.Prog.mode&PrintFunctions != 0 {
   561  		printMu.Lock()
   562  		f.WriteTo(os.Stdout)
   563  		printMu.Unlock()
   564  	}
   565  
   566  	if f.Prog.mode&SanityCheckFunctions != 0 {
   567  		mustSanityCheck(f, nil)
   568  	}
   569  }
   570  
   571  func isUselessPhi(phi *Phi) (Value, bool) {
   572  	var v0 Value
   573  	for _, e := range phi.Edges {
   574  		if e == phi {
   575  			continue
   576  		}
   577  		if v0 == nil {
   578  			v0 = e
   579  		}
   580  		if v0 != e {
   581  			if v0, ok := v0.(*Const); ok {
   582  				if e, ok := e.(*Const); ok {
   583  					if v0.typ == e.typ && v0.Value == e.Value {
   584  						continue
   585  					}
   586  				}
   587  			}
   588  			return nil, false
   589  		}
   590  	}
   591  	return v0, true
   592  }
   593  
   594  func (f *Function) RemoveNilBlocks() {
   595  	f.removeNilBlocks()
   596  }
   597  
   598  // removeNilBlocks eliminates nils from f.Blocks and updates each
   599  // BasicBlock.Index.  Use this after any pass that may delete blocks.
   600  func (f *Function) removeNilBlocks() {
   601  	j := 0
   602  	for _, b := range f.Blocks {
   603  		if b != nil {
   604  			b.Index = j
   605  			f.Blocks[j] = b
   606  			j++
   607  		}
   608  	}
   609  	// Nil out f.Blocks[j:] to aid GC.
   610  	for i := j; i < len(f.Blocks); i++ {
   611  		f.Blocks[i] = nil
   612  	}
   613  	f.Blocks = f.Blocks[:j]
   614  }
   615  
   616  // SetDebugMode sets the debug mode for package pkg.  If true, all its
   617  // functions will include full debug info.  This greatly increases the
   618  // size of the instruction stream, and causes Functions to depend upon
   619  // the ASTs, potentially keeping them live in memory for longer.
   620  func (pkg *Package) SetDebugMode(debug bool) {
   621  	// TODO(adonovan): do we want ast.File granularity?
   622  	pkg.debug = debug
   623  }
   624  
   625  // debugInfo reports whether debug info is wanted for this function.
   626  func (f *Function) debugInfo() bool {
   627  	return f.Pkg != nil && f.Pkg.debug
   628  }
   629  
   630  // addNamedLocal creates a local variable, adds it to function f and
   631  // returns it.  Its name and type are taken from obj.  Subsequent
   632  // calls to f.lookup(obj) will return the same local.
   633  func (f *Function) addNamedLocal(obj types.Object, source ast.Node) *Alloc {
   634  	l := f.addLocal(obj.Type(), source)
   635  	f.objects[obj] = l
   636  	return l
   637  }
   638  
   639  func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
   640  	return f.addNamedLocal(f.Pkg.info.Defs[id], id)
   641  }
   642  
   643  // addLocal creates an anonymous local variable of type typ, adds it
   644  // to function f and returns it.  pos is the optional source location.
   645  func (f *Function) addLocal(typ types.Type, source ast.Node) *Alloc {
   646  	v := &Alloc{}
   647  	v.setType(types.NewPointer(typ))
   648  	f.Locals = append(f.Locals, v)
   649  	f.emit(v, source)
   650  	return v
   651  }
   652  
   653  // lookup returns the address of the named variable identified by obj
   654  // that is local to function f or one of its enclosing functions.
   655  // If escaping, the reference comes from a potentially escaping pointer
   656  // expression and the referent must be heap-allocated.
   657  func (f *Function) lookup(obj types.Object, escaping bool) Value {
   658  	if v, ok := f.objects[obj]; ok {
   659  		if alloc, ok := v.(*Alloc); ok && escaping {
   660  			alloc.Heap = true
   661  		}
   662  		return v // function-local var (address)
   663  	}
   664  
   665  	// Definition must be in an enclosing function;
   666  	// plumb it through intervening closures.
   667  	if f.parent == nil {
   668  		panic("no ir.Value for " + obj.String())
   669  	}
   670  	outer := f.parent.lookup(obj, true) // escaping
   671  	v := &FreeVar{
   672  		name:   obj.Name(),
   673  		typ:    outer.Type(),
   674  		outer:  outer,
   675  		parent: f,
   676  	}
   677  	f.objects[obj] = v
   678  	f.FreeVars = append(f.FreeVars, v)
   679  	return v
   680  }
   681  
   682  // emit emits the specified instruction to function f.
   683  func (f *Function) emit(instr Instruction, source ast.Node) Value {
   684  	return f.currentBlock.emit(instr, source)
   685  }
   686  
   687  // RelString returns the full name of this function, qualified by
   688  // package name, receiver type, etc.
   689  //
   690  // The specific formatting rules are not guaranteed and may change.
   691  //
   692  // Examples:
   693  //
   694  //	"math.IsNaN"                  // a package-level function
   695  //	"(*bytes.Buffer).Bytes"       // a declared method or a wrapper
   696  //	"(*bytes.Buffer).Bytes$thunk" // thunk (func wrapping method; receiver is param 0)
   697  //	"(*bytes.Buffer).Bytes$bound" // bound (func wrapping method; receiver supplied by closure)
   698  //	"main.main$1"                 // an anonymous function in main
   699  //	"main.init#1"                 // a declared init function
   700  //	"main.init"                   // the synthesized package initializer
   701  //
   702  // When these functions are referred to from within the same package
   703  // (i.e. from == f.Pkg.Object), they are rendered without the package path.
   704  // For example: "IsNaN", "(*Buffer).Bytes", etc.
   705  //
   706  // All non-synthetic functions have distinct package-qualified names.
   707  // (But two methods may have the same name "(T).f" if one is a synthetic
   708  // wrapper promoting a non-exported method "f" from another package; in
   709  // that case, the strings are equal but the identifiers "f" are distinct.)
   710  func (f *Function) RelString(from *types.Package) string {
   711  	// Anonymous?
   712  	if f.parent != nil {
   713  		// An anonymous function's Name() looks like "parentName$1",
   714  		// but its String() should include the type/package/etc.
   715  		parent := f.parent.RelString(from)
   716  		for i, anon := range f.parent.AnonFuncs {
   717  			if anon == f {
   718  				return fmt.Sprintf("%s$%d", parent, 1+i)
   719  			}
   720  		}
   721  
   722  		return f.name // should never happen
   723  	}
   724  
   725  	// Method (declared or wrapper)?
   726  	if recv := f.Signature.Recv(); recv != nil {
   727  		return f.relMethod(from, recv.Type())
   728  	}
   729  
   730  	// Thunk?
   731  	if f.method != nil {
   732  		return f.relMethod(from, f.method.Recv())
   733  	}
   734  
   735  	// Bound?
   736  	if len(f.FreeVars) == 1 && strings.HasSuffix(f.name, "$bound") {
   737  		return f.relMethod(from, f.FreeVars[0].Type())
   738  	}
   739  
   740  	// Package-level function?
   741  	// Prefix with package name for cross-package references only.
   742  	if p := f.pkg(); p != nil && p != from {
   743  		return fmt.Sprintf("%s.%s", p.Path(), f.name)
   744  	}
   745  
   746  	// Unknown.
   747  	return f.name
   748  }
   749  
   750  func (f *Function) relMethod(from *types.Package, recv types.Type) string {
   751  	return fmt.Sprintf("(%s).%s", relType(recv, from), f.name)
   752  }
   753  
   754  // writeSignature writes to buf the signature sig in declaration syntax.
   755  func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) {
   756  	buf.WriteString("func ")
   757  	if recv := sig.Recv(); recv != nil {
   758  		buf.WriteString("(")
   759  		if n := params[0].Name(); n != "" {
   760  			buf.WriteString(n)
   761  			buf.WriteString(" ")
   762  		}
   763  		types.WriteType(buf, params[0].Type(), types.RelativeTo(from))
   764  		buf.WriteString(") ")
   765  	}
   766  	buf.WriteString(name)
   767  	types.WriteSignature(buf, sig, types.RelativeTo(from))
   768  }
   769  
   770  func (f *Function) pkg() *types.Package {
   771  	if f.Pkg != nil {
   772  		return f.Pkg.Pkg
   773  	}
   774  	return nil
   775  }
   776  
   777  var _ io.WriterTo = (*Function)(nil) // *Function implements io.Writer
   778  
   779  func (f *Function) WriteTo(w io.Writer) (int64, error) {
   780  	var buf bytes.Buffer
   781  	WriteFunction(&buf, f)
   782  	n, err := w.Write(buf.Bytes())
   783  	return int64(n), err
   784  }
   785  
   786  // WriteFunction writes to buf a human-readable "disassembly" of f.
   787  func WriteFunction(buf *bytes.Buffer, f *Function) {
   788  	fmt.Fprintf(buf, "# Name: %s\n", f.String())
   789  	if f.Pkg != nil {
   790  		fmt.Fprintf(buf, "# Package: %s\n", f.Pkg.Pkg.Path())
   791  	}
   792  	if syn := f.Synthetic; syn != 0 {
   793  		fmt.Fprintln(buf, "# Synthetic:", syn)
   794  	}
   795  	if pos := f.Pos(); pos.IsValid() {
   796  		fmt.Fprintf(buf, "# Location: %s\n", f.Prog.Fset.Position(pos))
   797  	}
   798  
   799  	if f.parent != nil {
   800  		fmt.Fprintf(buf, "# Parent: %s\n", f.parent.Name())
   801  	}
   802  
   803  	from := f.pkg()
   804  
   805  	if f.FreeVars != nil {
   806  		buf.WriteString("# Free variables:\n")
   807  		for i, fv := range f.FreeVars {
   808  			fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), from))
   809  		}
   810  	}
   811  
   812  	if len(f.Locals) > 0 {
   813  		buf.WriteString("# Locals:\n")
   814  		for i, l := range f.Locals {
   815  			fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), from))
   816  		}
   817  	}
   818  	writeSignature(buf, from, f.Name(), f.Signature, f.Params)
   819  	buf.WriteString(":\n")
   820  
   821  	if f.Blocks == nil {
   822  		buf.WriteString("\t(external)\n")
   823  	}
   824  
   825  	for _, b := range f.Blocks {
   826  		if b == nil {
   827  			// Corrupt CFG.
   828  			fmt.Fprintf(buf, ".nil:\n")
   829  			continue
   830  		}
   831  		fmt.Fprintf(buf, "b%d:", b.Index)
   832  		if len(b.Preds) > 0 {
   833  			fmt.Fprint(buf, " ←")
   834  			for _, pred := range b.Preds {
   835  				fmt.Fprintf(buf, " b%d", pred.Index)
   836  			}
   837  		}
   838  		if b.Comment != "" {
   839  			fmt.Fprintf(buf, " # %s", b.Comment)
   840  		}
   841  		buf.WriteByte('\n')
   842  
   843  		if false { // CFG debugging
   844  			fmt.Fprintf(buf, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
   845  		}
   846  
   847  		buf2 := &bytes.Buffer{}
   848  		for _, instr := range b.Instrs {
   849  			buf.WriteString("\t")
   850  			switch v := instr.(type) {
   851  			case Value:
   852  				// Left-align the instruction.
   853  				if name := v.Name(); name != "" {
   854  					fmt.Fprintf(buf, "%s = ", name)
   855  				}
   856  				buf.WriteString(instr.String())
   857  			case nil:
   858  				// Be robust against bad transforms.
   859  				buf.WriteString("<deleted>")
   860  			default:
   861  				buf.WriteString(instr.String())
   862  			}
   863  			if instr != nil && instr.Comment() != "" {
   864  				buf.WriteString(" # ")
   865  				buf.WriteString(instr.Comment())
   866  			}
   867  			buf.WriteString("\n")
   868  
   869  			if f.Prog.mode&PrintSource != 0 {
   870  				if s := instr.Source(); s != nil {
   871  					buf2.Reset()
   872  					format.Node(buf2, f.Prog.Fset, s)
   873  					for {
   874  						line, err := buf2.ReadString('\n')
   875  						if len(line) == 0 {
   876  							break
   877  						}
   878  						buf.WriteString("\t\t> ")
   879  						buf.WriteString(line)
   880  						if line[len(line)-1] != '\n' {
   881  							buf.WriteString("\n")
   882  						}
   883  						if err != nil {
   884  							break
   885  						}
   886  					}
   887  				}
   888  			}
   889  		}
   890  		buf.WriteString("\n")
   891  	}
   892  }
   893  
   894  // newBasicBlock adds to f a new basic block and returns it.  It does
   895  // not automatically become the current block for subsequent calls to emit.
   896  // comment is an optional string for more readable debugging output.
   897  func (f *Function) newBasicBlock(comment string) *BasicBlock {
   898  	var instrs []Instruction
   899  	if len(f.functionBody.scratchInstructions) > 0 {
   900  		instrs = f.functionBody.scratchInstructions[0:0:avgInstructionsPerBlock]
   901  		f.functionBody.scratchInstructions = f.functionBody.scratchInstructions[avgInstructionsPerBlock:]
   902  	} else {
   903  		instrs = make([]Instruction, 0, avgInstructionsPerBlock)
   904  	}
   905  
   906  	b := &BasicBlock{
   907  		Index:   len(f.Blocks),
   908  		Comment: comment,
   909  		parent:  f,
   910  		Instrs:  instrs,
   911  	}
   912  	b.Succs = b.succs2[:0]
   913  	f.Blocks = append(f.Blocks, b)
   914  	return b
   915  }
   916  
   917  // NewFunction returns a new synthetic Function instance belonging to
   918  // prog, with its name and signature fields set as specified.
   919  //
   920  // The caller is responsible for initializing the remaining fields of
   921  // the function object, e.g. Pkg, Params, Blocks.
   922  //
   923  // It is practically impossible for clients to construct well-formed
   924  // IR functions/packages/programs directly, so we assume this is the
   925  // job of the Builder alone.  NewFunction exists to provide clients a
   926  // little flexibility.  For example, analysis tools may wish to
   927  // construct fake Functions for the root of the callgraph, a fake
   928  // "reflect" package, etc.
   929  //
   930  // TODO(adonovan): think harder about the API here.
   931  func (prog *Program) NewFunction(name string, sig *types.Signature, provenance Synthetic) *Function {
   932  	return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
   933  }
   934  
   935  //lint:ignore U1000 we may make use of this for functions loaded from export data
   936  type extentNode [2]token.Pos
   937  
   938  func (n extentNode) Pos() token.Pos { return n[0] }
   939  func (n extentNode) End() token.Pos { return n[1] }
   940  
   941  func (f *Function) initHTML(name string) {
   942  	if name == "" {
   943  		return
   944  	}
   945  	if rel := f.RelString(nil); rel == name {
   946  		f.wr = NewHTMLWriter("ir.html", rel, "")
   947  	}
   948  }
   949  
   950  func killInstruction(instr Instruction) {
   951  	ops := instr.Operands(nil)
   952  	for _, op := range ops {
   953  		if refs := (*op).Referrers(); refs != nil {
   954  			*refs = removeInstr(*refs, instr)
   955  		}
   956  	}
   957  }