summaryrefslogtreecommitdiff
path: root/include/llvm/IR/CFG.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/IR/CFG.h')
-rw-r--r--include/llvm/IR/CFG.h169
1 files changed, 152 insertions, 17 deletions
diff --git a/include/llvm/IR/CFG.h b/include/llvm/IR/CFG.h
index f4988e7f1fec..8385c4647e12 100644
--- a/include/llvm/IR/CFG.h
+++ b/include/llvm/IR/CFG.h
@@ -1,4 +1,4 @@
-//===- CFG.h - Process LLVM structures as graphs ----------------*- C++ -*-===//
+//===- CFG.h ----------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,10 +6,15 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines specializations of GraphTraits that allow Function and
-// BasicBlock graphs to be treated as proper graphs for generic algorithms.
-//
+/// \file
+///
+/// This file provides various utilities for inspecting and working with the
+/// control flow graph in LLVM IR. This includes generic facilities for
+/// iterating successors and predecessors of basic blocks, the successors of
+/// specific terminator instructions, etc. It also defines specializations of
+/// GraphTraits that allow Function and BasicBlock graphs to be treated as
+/// proper graphs for generic algorithms.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_CFG_H
@@ -44,8 +49,13 @@ class PredIterator : public std::iterator<std::forward_iterator_tag,
inline void advancePastNonTerminators() {
// Loop to ignore non-terminator uses (for example BlockAddresses).
- while (!It.atEnd() && !isa<TerminatorInst>(*It))
+ while (!It.atEnd()) {
+ if (auto *Inst = dyn_cast<Instruction>(*It))
+ if (Inst->isTerminator())
+ break;
+
++It;
+ }
}
public:
@@ -63,7 +73,7 @@ public:
inline reference operator*() const {
assert(!It.atEnd() && "pred_iterator out of range!");
- return cast<TerminatorInst>(*It)->getParent();
+ return cast<Instruction>(*It)->getParent();
}
inline pointer *operator->() const { return &operator*(); }
@@ -107,6 +117,8 @@ inline const_pred_iterator pred_end(const BasicBlock *BB) {
inline bool pred_empty(const BasicBlock *BB) {
return pred_begin(BB) == pred_end(BB);
}
+/// Get the number of predecessors of \p BB. This is a linear time operation.
+/// Use \ref BasicBlock::hasNPredecessors() or hasNPredecessorsOrMore if able.
inline unsigned pred_size(const BasicBlock *BB) {
return std::distance(pred_begin(BB), pred_end(BB));
}
@@ -118,16 +130,144 @@ inline pred_const_range predecessors(const BasicBlock *BB) {
}
//===----------------------------------------------------------------------===//
-// BasicBlock succ_iterator helpers
+// Instruction and BasicBlock succ_iterator helpers
//===----------------------------------------------------------------------===//
-using succ_iterator =
- TerminatorInst::SuccIterator<TerminatorInst *, BasicBlock>;
-using succ_const_iterator =
- TerminatorInst::SuccIterator<const TerminatorInst *, const BasicBlock>;
+template <class InstructionT, class BlockT>
+class SuccIterator
+ : public iterator_facade_base<SuccIterator<InstructionT, BlockT>,
+ std::random_access_iterator_tag, BlockT, int,
+ BlockT *, BlockT *> {
+public:
+ using difference_type = int;
+ using pointer = BlockT *;
+ using reference = BlockT *;
+
+private:
+ InstructionT *Inst;
+ int Idx;
+ using Self = SuccIterator<InstructionT, BlockT>;
+
+ inline bool index_is_valid(int Idx) {
+ // Note that we specially support the index of zero being valid even in the
+ // face of a null instruction.
+ return Idx >= 0 && (Idx == 0 || Idx <= (int)Inst->getNumSuccessors());
+ }
+
+ /// Proxy object to allow write access in operator[]
+ class SuccessorProxy {
+ Self It;
+
+ public:
+ explicit SuccessorProxy(const Self &It) : It(It) {}
+
+ SuccessorProxy(const SuccessorProxy &) = default;
+
+ SuccessorProxy &operator=(SuccessorProxy RHS) {
+ *this = reference(RHS);
+ return *this;
+ }
+
+ SuccessorProxy &operator=(reference RHS) {
+ It.Inst->setSuccessor(It.Idx, RHS);
+ return *this;
+ }
+
+ operator reference() const { return *It; }
+ };
+
+public:
+ // begin iterator
+ explicit inline SuccIterator(InstructionT *Inst) : Inst(Inst), Idx(0) {}
+ // end iterator
+ inline SuccIterator(InstructionT *Inst, bool) : Inst(Inst) {
+ if (Inst)
+ Idx = Inst->getNumSuccessors();
+ else
+ // Inst == NULL happens, if a basic block is not fully constructed and
+ // consequently getTerminator() returns NULL. In this case we construct
+ // a SuccIterator which describes a basic block that has zero
+ // successors.
+ // Defining SuccIterator for incomplete and malformed CFGs is especially
+ // useful for debugging.
+ Idx = 0;
+ }
+
+ /// This is used to interface between code that wants to
+ /// operate on terminator instructions directly.
+ int getSuccessorIndex() const { return Idx; }
+
+ inline bool operator==(const Self &x) const { return Idx == x.Idx; }
+
+ inline BlockT *operator*() const { return Inst->getSuccessor(Idx); }
+
+ // We use the basic block pointer directly for operator->.
+ inline BlockT *operator->() const { return operator*(); }
+
+ inline bool operator<(const Self &RHS) const {
+ assert(Inst == RHS.Inst && "Cannot compare iterators of different blocks!");
+ return Idx < RHS.Idx;
+ }
+
+ int operator-(const Self &RHS) const {
+ assert(Inst == RHS.Inst && "Cannot compare iterators of different blocks!");
+ return Idx - RHS.Idx;
+ }
+
+ inline Self &operator+=(int RHS) {
+ int NewIdx = Idx + RHS;
+ assert(index_is_valid(NewIdx) && "Iterator index out of bound");
+ Idx = NewIdx;
+ return *this;
+ }
+
+ inline Self &operator-=(int RHS) { return operator+=(-RHS); }
+
+ // Specially implement the [] operation using a proxy object to support
+ // assignment.
+ inline SuccessorProxy operator[](int Offset) {
+ Self TmpIt = *this;
+ TmpIt += Offset;
+ return SuccessorProxy(TmpIt);
+ }
+
+ /// Get the source BlockT of this iterator.
+ inline BlockT *getSource() {
+ assert(Inst && "Source not available, if basic block was malformed");
+ return Inst->getParent();
+ }
+};
+
+template <typename T, typename U> struct isPodLike<SuccIterator<T, U>> {
+ static const bool value = isPodLike<T>::value;
+};
+
+using succ_iterator = SuccIterator<Instruction, BasicBlock>;
+using succ_const_iterator = SuccIterator<const Instruction, const BasicBlock>;
using succ_range = iterator_range<succ_iterator>;
using succ_const_range = iterator_range<succ_const_iterator>;
+inline succ_iterator succ_begin(Instruction *I) { return succ_iterator(I); }
+inline succ_const_iterator succ_begin(const Instruction *I) {
+ return succ_const_iterator(I);
+}
+inline succ_iterator succ_end(Instruction *I) { return succ_iterator(I, true); }
+inline succ_const_iterator succ_end(const Instruction *I) {
+ return succ_const_iterator(I, true);
+}
+inline bool succ_empty(const Instruction *I) {
+ return succ_begin(I) == succ_end(I);
+}
+inline unsigned succ_size(const Instruction *I) {
+ return std::distance(succ_begin(I), succ_end(I));
+}
+inline succ_range successors(Instruction *I) {
+ return succ_range(succ_begin(I), succ_end(I));
+}
+inline succ_const_range successors(const Instruction *I) {
+ return succ_const_range(succ_begin(I), succ_end(I));
+}
+
inline succ_iterator succ_begin(BasicBlock *BB) {
return succ_iterator(BB->getTerminator());
}
@@ -153,11 +293,6 @@ inline succ_const_range successors(const BasicBlock *BB) {
return succ_const_range(succ_begin(BB), succ_end(BB));
}
-template <typename T, typename U>
-struct isPodLike<TerminatorInst::SuccIterator<T, U>> {
- static const bool value = isPodLike<T>::value;
-};
-
//===--------------------------------------------------------------------===//
// GraphTraits specializations for basic block graphs (CFGs)
//===--------------------------------------------------------------------===//