Implement the groundwork for predecessor/successor iterators on basic blocks.
Give BasicBlock a use/def list, making references to them in TerminatorInst's
into a type that maintains the list.
PiperOrigin-RevId: 206166388
diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp
index a1cdcb3..7afaf68 100644
--- a/lib/IR/Instructions.cpp
+++ b/lib/IR/Instructions.cpp
@@ -22,7 +22,7 @@
/// Replace all uses of 'this' value with the new value, updating anything in
/// the IR that uses 'this' to use the other value instead. When this returns
/// there are zero uses of 'this'.
-void SSAValue::replaceAllUsesWith(SSAValue *newValue) {
+void IRObjectWithUseList::replaceAllUsesWith(IRObjectWithUseList *newValue) {
assert(this != newValue && "cannot RAUW a value with itself");
while (!use_empty()) {
use_begin()->set(newValue);
@@ -105,6 +105,10 @@
void Instruction::dropAllReferences() {
for (auto &op : getInstOperands())
op.drop();
+
+ if (auto *term = dyn_cast<TerminatorInst>(this))
+ for (auto &dest : term->getDestinations())
+ dest.drop();
}
//===----------------------------------------------------------------------===//
@@ -209,7 +213,7 @@
}
//===----------------------------------------------------------------------===//
-// Terminators
+// TerminatorInst
//===----------------------------------------------------------------------===//
/// Remove this terminator from its BasicBlock and delete it.
@@ -219,6 +223,25 @@
destroy();
}
+/// Return the list of destination entries that this terminator branches to.
+MutableArrayRef<BBDestination> TerminatorInst::getDestinations() {
+ switch (getKind()) {
+ case Kind::Operation:
+ assert(0 && "not a terminator");
+ case Kind::Branch:
+ return cast<BranchInst>(this)->getDestinations();
+ case Kind::CondBranch:
+ return cast<CondBranchInst>(this)->getDestinations();
+ case Kind::Return:
+ // Return has no basic block successors.
+ return {};
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// ReturnInst
+//===----------------------------------------------------------------------===//
+
/// Create a new OperationInst with the specific fields.
ReturnInst *ReturnInst::create(ArrayRef<CFGValue *> operands) {
auto byteSize = totalSizeToAlloc<InstOperand>(operands.size());
@@ -245,6 +268,15 @@
operand.~InstOperand();
}
+//===----------------------------------------------------------------------===//
+// BranchInst
+//===----------------------------------------------------------------------===//
+
+BranchInst::BranchInst(BasicBlock *dest)
+ : TerminatorInst(Kind::Branch), dest(this, dest) {}
+
+void BranchInst::setDest(BasicBlock *block) { dest.set(block); }
+
/// Add one value to the operand list.
void BranchInst::addOperand(CFGValue *value) {
operands.emplace_back(InstOperand(this, value));
@@ -257,6 +289,18 @@
addOperand(value);
}
+//===----------------------------------------------------------------------===//
+// CondBranchInst
+//===----------------------------------------------------------------------===//
+
+CondBranchInst::CondBranchInst(CFGValue *condition, BasicBlock *trueDest,
+ BasicBlock *falseDest)
+ : TerminatorInst(Kind::CondBranch),
+ condition(condition), dests{{this}, {this}}, numTrueOperands(0) {
+ dests[falseIndex].set(falseDest);
+ dests[trueIndex].set(trueDest);
+}
+
/// Add one value to the true operand list.
void CondBranchInst::addTrueOperand(CFGValue *value) {
assert(getNumFalseOperands() == 0 &&