github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/ssa/builder.go (about)

     1  package ssa
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
     9  )
    10  
    11  // Builder is used to builds SSA consisting of Basic Blocks per function.
    12  type Builder interface {
    13  	// Init must be called to reuse this builder for the next function.
    14  	Init(typ *Signature)
    15  
    16  	// Signature returns the Signature of the currently-compiled function.
    17  	Signature() *Signature
    18  
    19  	// BlockIDMax returns the maximum value of BasicBlocksID existing in the currently-compiled function.
    20  	BlockIDMax() BasicBlockID
    21  
    22  	// AllocateBasicBlock creates a basic block in SSA function.
    23  	AllocateBasicBlock() BasicBlock
    24  
    25  	// CurrentBlock returns the currently handled BasicBlock which is set by the latest call to SetCurrentBlock.
    26  	CurrentBlock() BasicBlock
    27  
    28  	// EntryBlock returns the entry BasicBlock of the currently-compiled function.
    29  	EntryBlock() BasicBlock
    30  
    31  	// SetCurrentBlock sets the instruction insertion target to the BasicBlock `b`.
    32  	SetCurrentBlock(b BasicBlock)
    33  
    34  	// DeclareVariable declares a Variable of the given Type.
    35  	DeclareVariable(Type) Variable
    36  
    37  	// DefineVariable defines a variable in the `block` with value.
    38  	// The defining instruction will be inserted into the `block`.
    39  	DefineVariable(variable Variable, value Value, block BasicBlock)
    40  
    41  	// DefineVariableInCurrentBB is the same as DefineVariable except the definition is
    42  	// inserted into the current BasicBlock. Alias to DefineVariable(x, y, CurrentBlock()).
    43  	DefineVariableInCurrentBB(variable Variable, value Value)
    44  
    45  	// AllocateInstruction returns a new Instruction.
    46  	AllocateInstruction() *Instruction
    47  
    48  	// InsertInstruction executes BasicBlock.InsertInstruction for the currently handled basic block.
    49  	InsertInstruction(raw *Instruction)
    50  
    51  	// allocateValue allocates an unused Value.
    52  	allocateValue(typ Type) Value
    53  
    54  	// MustFindValue searches the latest definition of the given Variable and returns the result.
    55  	MustFindValue(variable Variable) Value
    56  
    57  	// MustFindValueInBlk is the same as MustFindValue except it searches the latest definition from the given BasicBlock.
    58  	MustFindValueInBlk(variable Variable, blk BasicBlock) Value
    59  
    60  	// FindValueInLinearPath tries to find the latest definition of the given Variable in the linear path to the current BasicBlock.
    61  	// If it cannot find the definition, or it's not sealed yet, it returns ValueInvalid.
    62  	FindValueInLinearPath(variable Variable) Value
    63  
    64  	// Seal declares that we've known all the predecessors to this block and were added via AddPred.
    65  	// After calling this, AddPred will be forbidden.
    66  	Seal(blk BasicBlock)
    67  
    68  	// AnnotateValue is for debugging purpose.
    69  	AnnotateValue(value Value, annotation string)
    70  
    71  	// DeclareSignature appends the *Signature to be referenced by various instructions (e.g. OpcodeCall).
    72  	DeclareSignature(signature *Signature)
    73  
    74  	// Signatures returns the slice of declared Signatures.
    75  	Signatures() []*Signature
    76  
    77  	// ResolveSignature returns the Signature which corresponds to SignatureID.
    78  	ResolveSignature(id SignatureID) *Signature
    79  
    80  	// RunPasses runs various passes on the constructed SSA function.
    81  	RunPasses()
    82  
    83  	// Format returns the debugging string of the SSA function.
    84  	Format() string
    85  
    86  	// BlockIteratorBegin initializes the state to iterate over all the valid BasicBlock(s) compiled.
    87  	// Combined with BlockIteratorNext, we can use this like:
    88  	//
    89  	// 	for blk := builder.BlockIteratorBegin(); blk != nil; blk = builder.BlockIteratorNext() {
    90  	// 		// ...
    91  	//	}
    92  	//
    93  	// The returned blocks are ordered in the order of AllocateBasicBlock being called.
    94  	BlockIteratorBegin() BasicBlock
    95  
    96  	// BlockIteratorNext advances the state for iteration initialized by BlockIteratorBegin.
    97  	// Returns nil if there's no unseen BasicBlock.
    98  	BlockIteratorNext() BasicBlock
    99  
   100  	// ValueRefCounts returns the map of ValueID to its reference count.
   101  	// The returned slice must not be modified.
   102  	ValueRefCounts() []int
   103  
   104  	// BlockIteratorReversePostOrderBegin is almost the same as BlockIteratorBegin except it returns the BasicBlock in the reverse post-order.
   105  	// This is available after RunPasses is run.
   106  	BlockIteratorReversePostOrderBegin() BasicBlock
   107  
   108  	// BlockIteratorReversePostOrderNext is almost the same as BlockIteratorPostOrderNext except it returns the BasicBlock in the reverse post-order.
   109  	// This is available after RunPasses is run.
   110  	BlockIteratorReversePostOrderNext() BasicBlock
   111  
   112  	// ReturnBlock returns the BasicBlock which is used to return from the function.
   113  	ReturnBlock() BasicBlock
   114  
   115  	// InsertUndefined inserts an undefined instruction at the current position.
   116  	InsertUndefined()
   117  
   118  	// SetCurrentSourceOffset sets the current source offset. The incoming instruction will be annotated with this offset.
   119  	SetCurrentSourceOffset(line SourceOffset)
   120  
   121  	// LoopNestingForestRoots returns the roots of the loop nesting forest.
   122  	LoopNestingForestRoots() []BasicBlock
   123  
   124  	// LowestCommonAncestor returns the lowest common ancestor in the dominator tree of the given BasicBlock(s).
   125  	LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock
   126  
   127  	// Idom returns the immediate dominator of the given BasicBlock.
   128  	Idom(blk BasicBlock) BasicBlock
   129  
   130  	VarLengthPool() *wazevoapi.VarLengthPool[Value]
   131  }
   132  
   133  // NewBuilder returns a new Builder implementation.
   134  func NewBuilder() Builder {
   135  	return &builder{
   136  		instructionsPool:               wazevoapi.NewPool[Instruction](resetInstruction),
   137  		basicBlocksPool:                wazevoapi.NewPool[basicBlock](resetBasicBlock),
   138  		varLengthPool:                  wazevoapi.NewVarLengthPool[Value](),
   139  		valueAnnotations:               make(map[ValueID]string),
   140  		signatures:                     make(map[SignatureID]*Signature),
   141  		blkVisited:                     make(map[*basicBlock]int),
   142  		valueIDAliases:                 make(map[ValueID]Value),
   143  		redundantParameterIndexToValue: make(map[int]Value),
   144  		returnBlk:                      &basicBlock{id: basicBlockIDReturnBlock},
   145  	}
   146  }
   147  
   148  // builder implements Builder interface.
   149  type builder struct {
   150  	basicBlocksPool  wazevoapi.Pool[basicBlock]
   151  	instructionsPool wazevoapi.Pool[Instruction]
   152  	varLengthPool    wazevoapi.VarLengthPool[Value]
   153  	signatures       map[SignatureID]*Signature
   154  	currentSignature *Signature
   155  
   156  	// reversePostOrderedBasicBlocks are the BasicBlock(s) ordered in the reverse post-order after passCalculateImmediateDominators.
   157  	reversePostOrderedBasicBlocks []*basicBlock
   158  	currentBB                     *basicBlock
   159  	returnBlk                     *basicBlock
   160  
   161  	// variables track the types for Variable with the index regarded Variable.
   162  	variables []Type
   163  	// nextValueID is used by builder.AllocateValue.
   164  	nextValueID ValueID
   165  	// nextVariable is used by builder.AllocateVariable.
   166  	nextVariable Variable
   167  
   168  	valueIDAliases   map[ValueID]Value
   169  	valueAnnotations map[ValueID]string
   170  
   171  	// valueRefCounts is used to lower the SSA in backend, and will be calculated
   172  	// by the last SSA-level optimization pass.
   173  	valueRefCounts []int
   174  
   175  	// dominators stores the immediate dominator of each BasicBlock.
   176  	// The index is blockID of the BasicBlock.
   177  	dominators []*basicBlock
   178  	sparseTree dominatorSparseTree
   179  
   180  	// loopNestingForestRoots are the roots of the loop nesting forest.
   181  	loopNestingForestRoots []BasicBlock
   182  
   183  	// The followings are used for optimization passes/deterministic compilation.
   184  	instStack                      []*Instruction
   185  	blkVisited                     map[*basicBlock]int
   186  	valueIDToInstruction           []*Instruction
   187  	blkStack                       []*basicBlock
   188  	blkStack2                      []*basicBlock
   189  	ints                           []int
   190  	redundantParameterIndexToValue map[int]Value
   191  
   192  	// blockIterCur is used to implement blockIteratorBegin and blockIteratorNext.
   193  	blockIterCur int
   194  
   195  	// donePreBlockLayoutPasses is true if all the passes before LayoutBlocks are called.
   196  	donePreBlockLayoutPasses bool
   197  	// doneBlockLayout is true if LayoutBlocks is called.
   198  	doneBlockLayout bool
   199  	// donePostBlockLayoutPasses is true if all the passes after LayoutBlocks are called.
   200  	donePostBlockLayoutPasses bool
   201  
   202  	currentSourceOffset SourceOffset
   203  }
   204  
   205  func (b *builder) VarLengthPool() *wazevoapi.VarLengthPool[Value] {
   206  	return &b.varLengthPool
   207  }
   208  
   209  // ReturnBlock implements Builder.ReturnBlock.
   210  func (b *builder) ReturnBlock() BasicBlock {
   211  	return b.returnBlk
   212  }
   213  
   214  // Init implements Builder.Reset.
   215  func (b *builder) Init(s *Signature) {
   216  	b.nextVariable = 0
   217  	b.currentSignature = s
   218  	resetBasicBlock(b.returnBlk)
   219  	b.instructionsPool.Reset()
   220  	b.basicBlocksPool.Reset()
   221  	b.varLengthPool.Reset()
   222  	b.donePreBlockLayoutPasses = false
   223  	b.doneBlockLayout = false
   224  	b.donePostBlockLayoutPasses = false
   225  	for _, sig := range b.signatures {
   226  		sig.used = false
   227  	}
   228  
   229  	b.ints = b.ints[:0]
   230  	b.blkStack = b.blkStack[:0]
   231  	b.blkStack2 = b.blkStack2[:0]
   232  	b.dominators = b.dominators[:0]
   233  	b.loopNestingForestRoots = b.loopNestingForestRoots[:0]
   234  
   235  	for i := 0; i < b.basicBlocksPool.Allocated(); i++ {
   236  		blk := b.basicBlocksPool.View(i)
   237  		delete(b.blkVisited, blk)
   238  	}
   239  	b.basicBlocksPool.Reset()
   240  
   241  	for v := ValueID(0); v < b.nextValueID; v++ {
   242  		delete(b.valueAnnotations, v)
   243  		delete(b.valueIDAliases, v)
   244  		b.valueRefCounts[v] = 0
   245  		b.valueIDToInstruction[v] = nil
   246  	}
   247  	b.nextValueID = 0
   248  	b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0]
   249  	b.doneBlockLayout = false
   250  	for i := range b.valueRefCounts {
   251  		b.valueRefCounts[i] = 0
   252  	}
   253  
   254  	b.currentSourceOffset = sourceOffsetUnknown
   255  }
   256  
   257  // Signature implements Builder.Signature.
   258  func (b *builder) Signature() *Signature {
   259  	return b.currentSignature
   260  }
   261  
   262  // AnnotateValue implements Builder.AnnotateValue.
   263  func (b *builder) AnnotateValue(value Value, a string) {
   264  	b.valueAnnotations[value.ID()] = a
   265  }
   266  
   267  // AllocateInstruction implements Builder.AllocateInstruction.
   268  func (b *builder) AllocateInstruction() *Instruction {
   269  	instr := b.instructionsPool.Allocate()
   270  	instr.id = b.instructionsPool.Allocated()
   271  	return instr
   272  }
   273  
   274  // DeclareSignature implements Builder.AnnotateValue.
   275  func (b *builder) DeclareSignature(s *Signature) {
   276  	b.signatures[s.ID] = s
   277  	s.used = false
   278  }
   279  
   280  // Signatures implements Builder.Signatures.
   281  func (b *builder) Signatures() (ret []*Signature) {
   282  	for _, sig := range b.signatures {
   283  		ret = append(ret, sig)
   284  	}
   285  	sort.Slice(ret, func(i, j int) bool {
   286  		return ret[i].ID < ret[j].ID
   287  	})
   288  	return
   289  }
   290  
   291  // SetCurrentSourceOffset implements Builder.SetCurrentSourceOffset.
   292  func (b *builder) SetCurrentSourceOffset(l SourceOffset) {
   293  	b.currentSourceOffset = l
   294  }
   295  
   296  func (b *builder) usedSignatures() (ret []*Signature) {
   297  	for _, sig := range b.signatures {
   298  		if sig.used {
   299  			ret = append(ret, sig)
   300  		}
   301  	}
   302  	sort.Slice(ret, func(i, j int) bool {
   303  		return ret[i].ID < ret[j].ID
   304  	})
   305  	return
   306  }
   307  
   308  // ResolveSignature implements Builder.ResolveSignature.
   309  func (b *builder) ResolveSignature(id SignatureID) *Signature {
   310  	return b.signatures[id]
   311  }
   312  
   313  // AllocateBasicBlock implements Builder.AllocateBasicBlock.
   314  func (b *builder) AllocateBasicBlock() BasicBlock {
   315  	return b.allocateBasicBlock()
   316  }
   317  
   318  // allocateBasicBlock allocates a new basicBlock.
   319  func (b *builder) allocateBasicBlock() *basicBlock {
   320  	id := BasicBlockID(b.basicBlocksPool.Allocated())
   321  	blk := b.basicBlocksPool.Allocate()
   322  	blk.id = id
   323  	return blk
   324  }
   325  
   326  // Idom implements Builder.Idom.
   327  func (b *builder) Idom(blk BasicBlock) BasicBlock {
   328  	return b.dominators[blk.ID()]
   329  }
   330  
   331  // InsertInstruction implements Builder.InsertInstruction.
   332  func (b *builder) InsertInstruction(instr *Instruction) {
   333  	b.currentBB.InsertInstruction(instr)
   334  
   335  	if l := b.currentSourceOffset; l.Valid() {
   336  		// Emit the source offset info only when the instruction has side effect because
   337  		// these are the only instructions that are accessed by stack unwinding.
   338  		// This reduces the significant amount of the offset info in the binary.
   339  		if instr.sideEffect() != sideEffectNone {
   340  			instr.annotateSourceOffset(l)
   341  		}
   342  	}
   343  
   344  	resultTypesFn := instructionReturnTypes[instr.opcode]
   345  	if resultTypesFn == nil {
   346  		panic("TODO: " + instr.Format(b))
   347  	}
   348  
   349  	t1, ts := resultTypesFn(b, instr)
   350  	if t1.invalid() {
   351  		return
   352  	}
   353  
   354  	r1 := b.allocateValue(t1)
   355  	instr.rValue = r1
   356  
   357  	tsl := len(ts)
   358  	if tsl == 0 {
   359  		return
   360  	}
   361  
   362  	rValues := b.varLengthPool.Allocate(tsl)
   363  	for i := 0; i < tsl; i++ {
   364  		rValues = rValues.Append(&b.varLengthPool, b.allocateValue(ts[i]))
   365  	}
   366  	instr.rValues = rValues
   367  }
   368  
   369  // DefineVariable implements Builder.DefineVariable.
   370  func (b *builder) DefineVariable(variable Variable, value Value, block BasicBlock) {
   371  	if b.variables[variable].invalid() {
   372  		panic("BUG: trying to define variable " + variable.String() + " but is not declared yet")
   373  	}
   374  
   375  	if b.variables[variable] != value.Type() {
   376  		panic(fmt.Sprintf("BUG: inconsistent type for variable %d: expected %s but got %s", variable, b.variables[variable], value.Type()))
   377  	}
   378  	bb := block.(*basicBlock)
   379  	bb.lastDefinitions[variable] = value
   380  }
   381  
   382  // DefineVariableInCurrentBB implements Builder.DefineVariableInCurrentBB.
   383  func (b *builder) DefineVariableInCurrentBB(variable Variable, value Value) {
   384  	b.DefineVariable(variable, value, b.currentBB)
   385  }
   386  
   387  // SetCurrentBlock implements Builder.SetCurrentBlock.
   388  func (b *builder) SetCurrentBlock(bb BasicBlock) {
   389  	b.currentBB = bb.(*basicBlock)
   390  }
   391  
   392  // CurrentBlock implements Builder.CurrentBlock.
   393  func (b *builder) CurrentBlock() BasicBlock {
   394  	return b.currentBB
   395  }
   396  
   397  // EntryBlock implements Builder.EntryBlock.
   398  func (b *builder) EntryBlock() BasicBlock {
   399  	return b.entryBlk()
   400  }
   401  
   402  // DeclareVariable implements Builder.DeclareVariable.
   403  func (b *builder) DeclareVariable(typ Type) Variable {
   404  	v := b.allocateVariable()
   405  	iv := int(v)
   406  	if l := len(b.variables); l <= iv {
   407  		b.variables = append(b.variables, make([]Type, 2*(l+1))...)
   408  	}
   409  	b.variables[v] = typ
   410  	return v
   411  }
   412  
   413  // allocateVariable allocates a new variable.
   414  func (b *builder) allocateVariable() (ret Variable) {
   415  	ret = b.nextVariable
   416  	b.nextVariable++
   417  	return
   418  }
   419  
   420  // allocateValue implements Builder.AllocateValue.
   421  func (b *builder) allocateValue(typ Type) (v Value) {
   422  	v = Value(b.nextValueID)
   423  	v = v.setType(typ)
   424  	b.nextValueID++
   425  	return
   426  }
   427  
   428  // FindValueInLinearPath implements Builder.FindValueInLinearPath.
   429  func (b *builder) FindValueInLinearPath(variable Variable) Value {
   430  	return b.findValueInLinearPath(variable, b.currentBB)
   431  }
   432  
   433  func (b *builder) findValueInLinearPath(variable Variable, blk *basicBlock) Value {
   434  	if val, ok := blk.lastDefinitions[variable]; ok {
   435  		return val
   436  	} else if !blk.sealed {
   437  		return ValueInvalid
   438  	}
   439  
   440  	if pred := blk.singlePred; pred != nil {
   441  		// If this block is sealed and have only one predecessor,
   442  		// we can use the value in that block without ambiguity on definition.
   443  		return b.findValueInLinearPath(variable, pred)
   444  	}
   445  	if len(blk.preds) == 1 {
   446  		panic("BUG")
   447  	}
   448  	return ValueInvalid
   449  }
   450  
   451  func (b *builder) MustFindValueInBlk(variable Variable, blk BasicBlock) Value {
   452  	typ := b.definedVariableType(variable)
   453  	return b.findValue(typ, variable, blk.(*basicBlock))
   454  }
   455  
   456  // MustFindValue implements Builder.MustFindValue.
   457  func (b *builder) MustFindValue(variable Variable) Value {
   458  	typ := b.definedVariableType(variable)
   459  	return b.findValue(typ, variable, b.currentBB)
   460  }
   461  
   462  // findValue recursively tries to find the latest definition of a `variable`. The algorithm is described in
   463  // the section 2 of the paper https://link.springer.com/content/pdf/10.1007/978-3-642-37051-9_6.pdf.
   464  //
   465  // TODO: reimplement this in iterative, not recursive, to avoid stack overflow.
   466  func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value {
   467  	if val, ok := blk.lastDefinitions[variable]; ok {
   468  		// The value is already defined in this block!
   469  		return val
   470  	} else if !blk.sealed { // Incomplete CFG as in the paper.
   471  		// If this is not sealed, that means it might have additional unknown predecessor later on.
   472  		// So we temporarily define the placeholder value here (not add as a parameter yet!),
   473  		// and record it as unknown.
   474  		// The unknown values are resolved when we call seal this block via BasicBlock.Seal().
   475  		value := b.allocateValue(typ)
   476  		if wazevoapi.SSALoggingEnabled {
   477  			fmt.Printf("adding unknown value placeholder for %s at %d\n", variable, blk.id)
   478  		}
   479  		blk.lastDefinitions[variable] = value
   480  		blk.unknownValues = append(blk.unknownValues, unknownValue{
   481  			variable: variable,
   482  			value:    value,
   483  		})
   484  		return value
   485  	}
   486  
   487  	if pred := blk.singlePred; pred != nil {
   488  		// If this block is sealed and have only one predecessor,
   489  		// we can use the value in that block without ambiguity on definition.
   490  		return b.findValue(typ, variable, pred)
   491  	} else if len(blk.preds) == 0 {
   492  		panic("BUG: value is not defined for " + variable.String())
   493  	}
   494  
   495  	// If this block has multiple predecessors, we have to gather the definitions,
   496  	// and treat them as an argument to this block.
   497  	//
   498  	// The first thing is to define a new parameter to this block which may or may not be redundant, but
   499  	// later we eliminate trivial params in an optimization pass. This must be done before finding the
   500  	// definitions in the predecessors so that we can break the cycle.
   501  	paramValue := blk.AddParam(b, typ)
   502  	b.DefineVariable(variable, paramValue, blk)
   503  
   504  	// After the new param is added, we have to manipulate the original branching instructions
   505  	// in predecessors so that they would pass the definition of `variable` as the argument to
   506  	// the newly added PHI.
   507  	for i := range blk.preds {
   508  		pred := &blk.preds[i]
   509  		value := b.findValue(typ, variable, pred.blk)
   510  		pred.branch.addArgumentBranchInst(b, value)
   511  	}
   512  	return paramValue
   513  }
   514  
   515  // Seal implements Builder.Seal.
   516  func (b *builder) Seal(raw BasicBlock) {
   517  	blk := raw.(*basicBlock)
   518  	if len(blk.preds) == 1 {
   519  		blk.singlePred = blk.preds[0].blk
   520  	}
   521  	blk.sealed = true
   522  
   523  	for _, v := range blk.unknownValues {
   524  		variable, phiValue := v.variable, v.value
   525  		typ := b.definedVariableType(variable)
   526  		blk.addParamOn(typ, phiValue)
   527  		for i := range blk.preds {
   528  			pred := &blk.preds[i]
   529  			predValue := b.findValue(typ, variable, pred.blk)
   530  			if !predValue.Valid() {
   531  				panic("BUG: value is not defined anywhere in the predecessors in the CFG")
   532  			}
   533  			pred.branch.addArgumentBranchInst(b, predValue)
   534  		}
   535  	}
   536  }
   537  
   538  // definedVariableType returns the type of the given variable. If the variable is not defined yet, it panics.
   539  func (b *builder) definedVariableType(variable Variable) Type {
   540  	typ := b.variables[variable]
   541  	if typ.invalid() {
   542  		panic(fmt.Sprintf("%s is not defined yet", variable))
   543  	}
   544  	return typ
   545  }
   546  
   547  // Format implements Builder.Format.
   548  func (b *builder) Format() string {
   549  	str := strings.Builder{}
   550  	usedSigs := b.usedSignatures()
   551  	if len(usedSigs) > 0 {
   552  		str.WriteByte('\n')
   553  		str.WriteString("signatures:\n")
   554  		for _, sig := range usedSigs {
   555  			str.WriteByte('\t')
   556  			str.WriteString(sig.String())
   557  			str.WriteByte('\n')
   558  		}
   559  	}
   560  
   561  	var iterBegin, iterNext func() *basicBlock
   562  	if b.doneBlockLayout {
   563  		iterBegin, iterNext = b.blockIteratorReversePostOrderBegin, b.blockIteratorReversePostOrderNext
   564  	} else {
   565  		iterBegin, iterNext = b.blockIteratorBegin, b.blockIteratorNext
   566  	}
   567  	for bb := iterBegin(); bb != nil; bb = iterNext() {
   568  		str.WriteByte('\n')
   569  		str.WriteString(bb.FormatHeader(b))
   570  		str.WriteByte('\n')
   571  
   572  		for cur := bb.Root(); cur != nil; cur = cur.Next() {
   573  			str.WriteByte('\t')
   574  			str.WriteString(cur.Format(b))
   575  			str.WriteByte('\n')
   576  		}
   577  	}
   578  	return str.String()
   579  }
   580  
   581  // BlockIteratorNext implements Builder.BlockIteratorNext.
   582  func (b *builder) BlockIteratorNext() BasicBlock {
   583  	if blk := b.blockIteratorNext(); blk == nil {
   584  		return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil)
   585  	} else {
   586  		return blk
   587  	}
   588  }
   589  
   590  // BlockIteratorNext implements Builder.BlockIteratorNext.
   591  func (b *builder) blockIteratorNext() *basicBlock {
   592  	index := b.blockIterCur
   593  	for {
   594  		if index == b.basicBlocksPool.Allocated() {
   595  			return nil
   596  		}
   597  		ret := b.basicBlocksPool.View(index)
   598  		index++
   599  		if !ret.invalid {
   600  			b.blockIterCur = index
   601  			return ret
   602  		}
   603  	}
   604  }
   605  
   606  // BlockIteratorBegin implements Builder.BlockIteratorBegin.
   607  func (b *builder) BlockIteratorBegin() BasicBlock {
   608  	return b.blockIteratorBegin()
   609  }
   610  
   611  // BlockIteratorBegin implements Builder.BlockIteratorBegin.
   612  func (b *builder) blockIteratorBegin() *basicBlock {
   613  	b.blockIterCur = 0
   614  	return b.blockIteratorNext()
   615  }
   616  
   617  // BlockIteratorReversePostOrderBegin implements Builder.BlockIteratorReversePostOrderBegin.
   618  func (b *builder) BlockIteratorReversePostOrderBegin() BasicBlock {
   619  	return b.blockIteratorReversePostOrderBegin()
   620  }
   621  
   622  // BlockIteratorBegin implements Builder.BlockIteratorBegin.
   623  func (b *builder) blockIteratorReversePostOrderBegin() *basicBlock {
   624  	b.blockIterCur = 0
   625  	return b.blockIteratorReversePostOrderNext()
   626  }
   627  
   628  // BlockIteratorReversePostOrderNext implements Builder.BlockIteratorReversePostOrderNext.
   629  func (b *builder) BlockIteratorReversePostOrderNext() BasicBlock {
   630  	if blk := b.blockIteratorReversePostOrderNext(); blk == nil {
   631  		return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil)
   632  	} else {
   633  		return blk
   634  	}
   635  }
   636  
   637  // BlockIteratorNext implements Builder.BlockIteratorNext.
   638  func (b *builder) blockIteratorReversePostOrderNext() *basicBlock {
   639  	if b.blockIterCur >= len(b.reversePostOrderedBasicBlocks) {
   640  		return nil
   641  	} else {
   642  		ret := b.reversePostOrderedBasicBlocks[b.blockIterCur]
   643  		b.blockIterCur++
   644  		return ret
   645  	}
   646  }
   647  
   648  // ValueRefCounts implements Builder.ValueRefCounts.
   649  func (b *builder) ValueRefCounts() []int {
   650  	return b.valueRefCounts
   651  }
   652  
   653  // alias records the alias of the given values. The alias(es) will be
   654  // eliminated in the optimization pass via resolveArgumentAlias.
   655  func (b *builder) alias(dst, src Value) {
   656  	b.valueIDAliases[dst.ID()] = src
   657  }
   658  
   659  // resolveArgumentAlias resolves the alias of the arguments of the given instruction.
   660  func (b *builder) resolveArgumentAlias(instr *Instruction) {
   661  	if instr.v.Valid() {
   662  		instr.v = b.resolveAlias(instr.v)
   663  	}
   664  
   665  	if instr.v2.Valid() {
   666  		instr.v2 = b.resolveAlias(instr.v2)
   667  	}
   668  
   669  	if instr.v3.Valid() {
   670  		instr.v3 = b.resolveAlias(instr.v3)
   671  	}
   672  
   673  	view := instr.vs.View()
   674  	for i, v := range view {
   675  		view[i] = b.resolveAlias(v)
   676  	}
   677  }
   678  
   679  // resolveAlias resolves the alias of the given value.
   680  func (b *builder) resolveAlias(v Value) Value {
   681  	// Some aliases are chained, so we need to resolve them recursively.
   682  	for {
   683  		if src, ok := b.valueIDAliases[v.ID()]; ok {
   684  			v = src
   685  		} else {
   686  			break
   687  		}
   688  	}
   689  	return v
   690  }
   691  
   692  // entryBlk returns the entry block of the function.
   693  func (b *builder) entryBlk() *basicBlock {
   694  	return b.basicBlocksPool.View(0)
   695  }
   696  
   697  // isDominatedBy returns true if the given block `n` is dominated by the given block `d`.
   698  // Before calling this, the builder must pass by passCalculateImmediateDominators.
   699  func (b *builder) isDominatedBy(n *basicBlock, d *basicBlock) bool {
   700  	if len(b.dominators) == 0 {
   701  		panic("BUG: passCalculateImmediateDominators must be called before calling isDominatedBy")
   702  	}
   703  	ent := b.entryBlk()
   704  	doms := b.dominators
   705  	for n != d && n != ent {
   706  		n = doms[n.id]
   707  	}
   708  	return n == d
   709  }
   710  
   711  // BlockIDMax implements Builder.BlockIDMax.
   712  func (b *builder) BlockIDMax() BasicBlockID {
   713  	return BasicBlockID(b.basicBlocksPool.Allocated())
   714  }
   715  
   716  // InsertUndefined implements Builder.InsertUndefined.
   717  func (b *builder) InsertUndefined() {
   718  	instr := b.AllocateInstruction()
   719  	instr.opcode = OpcodeUndefined
   720  	b.InsertInstruction(instr)
   721  }
   722  
   723  // LoopNestingForestRoots implements Builder.LoopNestingForestRoots.
   724  func (b *builder) LoopNestingForestRoots() []BasicBlock {
   725  	return b.loopNestingForestRoots
   726  }
   727  
   728  // LowestCommonAncestor implements Builder.LowestCommonAncestor.
   729  func (b *builder) LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock {
   730  	return b.sparseTree.findLCA(blk1.ID(), blk2.ID())
   731  }