github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/block.go (about)

     1  // Copyright 2022 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  import "fmt"
     8  
     9  // This file implements the BasicBlock type.
    10  
    11  // addEdge adds a control-flow graph edge from from to to.
    12  func addEdge(from, to *BasicBlock) {
    13  	from.Succs = append(from.Succs, to)
    14  	to.Preds = append(to.Preds, from)
    15  }
    16  
    17  // Parent returns the function that contains block b.
    18  func (b *BasicBlock) Parent() *Function { return b.parent }
    19  
    20  // String returns a human-readable label of this block.
    21  // It is not guaranteed unique within the function.
    22  //
    23  func (b *BasicBlock) String() string {
    24  	return fmt.Sprintf("%d", b.Index)
    25  }
    26  
    27  // emit appends an instruction to the current basic block.
    28  // If the instruction defines a Value, it is returned.
    29  //
    30  func (b *BasicBlock) emit(i Instruction) Value {
    31  	i.setBlock(b)
    32  	b.Instrs = append(b.Instrs, i)
    33  	v, _ := i.(Value)
    34  	return v
    35  }
    36  
    37  // predIndex returns the i such that b.Preds[i] == c or panics if
    38  // there is none.
    39  func (b *BasicBlock) predIndex(c *BasicBlock) int {
    40  	for i, pred := range b.Preds {
    41  		if pred == c {
    42  			return i
    43  		}
    44  	}
    45  	panic(fmt.Sprintf("no edge %s -> %s", c, b))
    46  }
    47  
    48  // hasPhi returns true if b.Instrs contains φ-nodes.
    49  func (b *BasicBlock) hasPhi() bool {
    50  	_, ok := b.Instrs[0].(*Phi)
    51  	return ok
    52  }
    53  
    54  // phis returns the prefix of b.Instrs containing all the block's φ-nodes.
    55  func (b *BasicBlock) phis() []Instruction {
    56  	for i, instr := range b.Instrs {
    57  		if _, ok := instr.(*Phi); !ok {
    58  			return b.Instrs[:i]
    59  		}
    60  	}
    61  	return nil // unreachable in well-formed blocks
    62  }
    63  
    64  // replacePred replaces all occurrences of p in b's predecessor list with q.
    65  // Ordinarily there should be at most one.
    66  //
    67  func (b *BasicBlock) replacePred(p, q *BasicBlock) {
    68  	for i, pred := range b.Preds {
    69  		if pred == p {
    70  			b.Preds[i] = q
    71  		}
    72  	}
    73  }
    74  
    75  // replaceSucc replaces all occurrences of p in b's successor list with q.
    76  // Ordinarily there should be at most one.
    77  //
    78  func (b *BasicBlock) replaceSucc(p, q *BasicBlock) {
    79  	for i, succ := range b.Succs {
    80  		if succ == p {
    81  			b.Succs[i] = q
    82  		}
    83  	}
    84  }
    85  
    86  // removePred removes all occurrences of p in b's
    87  // predecessor list and φ-nodes.
    88  // Ordinarily there should be at most one.
    89  //
    90  func (b *BasicBlock) removePred(p *BasicBlock) {
    91  	phis := b.phis()
    92  
    93  	// We must preserve edge order for φ-nodes.
    94  	j := 0
    95  	for i, pred := range b.Preds {
    96  		if pred != p {
    97  			b.Preds[j] = b.Preds[i]
    98  			// Strike out φ-edge too.
    99  			for _, instr := range phis {
   100  				phi := instr.(*Phi)
   101  				phi.Edges[j] = phi.Edges[i]
   102  			}
   103  			j++
   104  		}
   105  	}
   106  	// Nil out b.Preds[j:] and φ-edges[j:] to aid GC.
   107  	for i := j; i < len(b.Preds); i++ {
   108  		b.Preds[i] = nil
   109  		for _, instr := range phis {
   110  			instr.(*Phi).Edges[i] = nil
   111  		}
   112  	}
   113  	b.Preds = b.Preds[:j]
   114  	for _, instr := range phis {
   115  		phi := instr.(*Phi)
   116  		phi.Edges = phi.Edges[:j]
   117  	}
   118  }