114 lines
3.5 KiB
Java
114 lines
3.5 KiB
Java
package cd.ir;
|
|
|
|
import cd.ir.Ast.Expr;
|
|
import cd.ir.Ast.Stmt;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* Node in a control flow graph. New instances should be created
|
|
* via the methods in {@link ControlFlowGraph}.
|
|
* Basic blocks consist of a list of statements ({@link #stmts}) which are
|
|
* executed at runtime. When the basic block ends, control flows into its
|
|
* {@link #successors}. If the block has more than one successor, it must also
|
|
* have a non-{@code null} value for {@link #condition}, which describes an expression
|
|
* that will determine which successor to take. Basic blocks also have fields
|
|
* for storing the parent and children in the dominator tree. These are generally computed
|
|
* in a second pass once the graph is fully built.
|
|
* <p>
|
|
* Your team will have to write code that builds the control flow graph and computes the
|
|
* relevant dominator information.
|
|
*/
|
|
public class BasicBlock {
|
|
|
|
/**
|
|
* Unique numerical index assigned by CFG builder between 0 and the total number of
|
|
* basic blocks. Useful for indexing into arrays and the like.
|
|
*/
|
|
public final int index;
|
|
|
|
/**
|
|
* List of predecessor blocks in the flow graph (i.e., blocks for
|
|
* which {@code this} is a successor).
|
|
*/
|
|
public final List<BasicBlock> predecessors = new ArrayList<BasicBlock>();
|
|
|
|
/**
|
|
* List of successor blocks in the flow graph (those that come after the
|
|
* current block). This list is always either of size 0, 1 or 2: 1 indicates
|
|
* that control flow continues directly into the next block, and 2 indicates
|
|
* that control flow goes in one of two directions, depending on the
|
|
* value that results when {@link #condition} is evaluated at runtime.
|
|
* If there are two successors, then the 0th entry is taken when {@code condition}
|
|
* evaluates to {@code true}.
|
|
*
|
|
* @see #trueSuccessor()
|
|
* @see #falseSuccessor()
|
|
*/
|
|
public final List<BasicBlock> successors = new ArrayList<BasicBlock>();
|
|
|
|
/**
|
|
* List of statements in this basic block.
|
|
*/
|
|
public final List<Stmt> stmts = new ArrayList<>();
|
|
|
|
/**
|
|
* If non-null, indicates that this basic block should have
|
|
* two successors. Control flows to the first successor if
|
|
* this condition evaluates at runtime to true, otherwise to
|
|
* the second successor. If null, the basic block should have
|
|
* only one successor.
|
|
*/
|
|
public Expr condition;
|
|
|
|
/**
|
|
* Parent of this basic block in the dominator tree (initially null until computed).
|
|
* Otherwise known as the immediate dominator.
|
|
*/
|
|
public BasicBlock dominatorTreeParent = null;
|
|
|
|
/**
|
|
* Children of this basic block in the dominator tree (initially empty until
|
|
* computed).
|
|
*/
|
|
public final List<BasicBlock> dominatorTreeChildren = new ArrayList<BasicBlock>();
|
|
|
|
/**
|
|
* Contains the dominance frontier of this block. A block b is in the dominance
|
|
* frontier of another block c if c does not dominate b, but c DOES dominate a
|
|
* predecessor of b.
|
|
*/
|
|
public final Set<BasicBlock> dominanceFrontier = new HashSet<BasicBlock>();
|
|
|
|
public BasicBlock(int index) {
|
|
this.index = index;
|
|
}
|
|
|
|
public BasicBlock trueSuccessor() {
|
|
assert this.condition != null;
|
|
return this.successors.get(0);
|
|
}
|
|
|
|
public BasicBlock falseSuccessor() {
|
|
assert this.condition != null;
|
|
return this.successors.get(1);
|
|
}
|
|
|
|
public <A, B> A accept(AstVisitor<A, B> visitor, B arg) {
|
|
A lastA = null;
|
|
for (Stmt stmt : stmts)
|
|
lastA = visitor.visit(stmt, arg);
|
|
if (condition != null)
|
|
lastA = visitor.visit(condition, arg);
|
|
return lastA;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "BB" + index;
|
|
}
|
|
}
|