[IR] Begin removal of TerminatorInst by removing successor manipulation.

The core get and set routines move to the `Instruction` class. These
routines are only valid to call on instructions which are terminators.

The iterator and *generic* range based access move to `CFG.h` where all
the other generic successor and predecessor access lives. While moving
the iterator here, simplify it using the iterator utilities LLVM
provides and updates coding style as much as reasonable. The APIs remain
pointer-heavy when they could better use references, and retain the odd
behavior of `operator*` and `operator->` that is common in LLVM
iterators. Adjusting this API, if desired, should be a follow-up step.

Non-generic range iteration is added for the two instructions where
there is an especially easy mechanism and where there was code
attempting to use the range accessor from a specific subclass:
`indirectbr` and `br`. In both cases, the successors are contiguous
operands and can be easily iterated via the operand list.

This is the first major patch in removing the `TerminatorInst` type from
the IR's instruction type hierarchy. This change was discussed in an RFC
here and was pretty clearly positive:
http://lists.llvm.org/pipermail/llvm-dev/2018-May/123407.html

There will be a series of much more mechanical changes following this
one to complete this move.

Differential Revision: https://reviews.llvm.org/D47467

llvm-svn: 340698
This commit is contained in:
Chandler Carruth 2018-08-26 08:41:15 +00:00
parent 1fa5051bad
commit 96fc1de77d
18 changed files with 282 additions and 259 deletions

View File

@ -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
@ -118,16 +123,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 +286,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)
//===--------------------------------------------------------------------===//

View File

@ -64,15 +64,6 @@ protected:
: Instruction(Ty, iType, Ops, NumOps, InsertAtEnd) {}
public:
/// Return the number of successors that this terminator has.
unsigned getNumSuccessors() const;
/// Return the specified successor.
BasicBlock *getSuccessor(unsigned idx) const;
/// Update the specified successor to point at the provided block.
void setSuccessor(unsigned idx, BasicBlock *B);
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Instruction *I) {
return I->isTerminator();
@ -94,183 +85,6 @@ public:
return false;
}
}
//===--------------------------------------------------------------------===//
// succ_iterator definition
//===--------------------------------------------------------------------===//
template <class Term, class BB> // Successor Iterator
class SuccIterator : public std::iterator<std::random_access_iterator_tag, BB,
int, BB *, BB *> {
using super =
std::iterator<std::random_access_iterator_tag, BB, int, BB *, BB *>;
public:
using pointer = typename super::pointer;
using reference = typename super::reference;
private:
Term TermInst;
unsigned idx;
using Self = SuccIterator<Term, BB>;
inline bool index_is_valid(unsigned idx) {
return idx < TermInst->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 r) {
*this = reference(r);
return *this;
}
SuccessorProxy &operator=(reference r) {
it.TermInst->setSuccessor(it.idx, r);
return *this;
}
operator reference() const { return *it; }
};
public:
// begin iterator
explicit inline SuccIterator(Term T) : TermInst(T), idx(0) {}
// end iterator
inline SuccIterator(Term T, bool) : TermInst(T) {
if (TermInst)
idx = TermInst->getNumSuccessors();
else
// Term == 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.
unsigned getSuccessorIndex() const { return idx; }
inline bool operator==(const Self &x) const { return idx == x.idx; }
inline bool operator!=(const Self &x) const { return !operator==(x); }
inline reference operator*() const { return TermInst->getSuccessor(idx); }
inline pointer operator->() const { return operator*(); }
inline Self &operator++() {
++idx;
return *this;
} // Preincrement
inline Self operator++(int) { // Postincrement
Self tmp = *this;
++*this;
return tmp;
}
inline Self &operator--() {
--idx;
return *this;
} // Predecrement
inline Self operator--(int) { // Postdecrement
Self tmp = *this;
--*this;
return tmp;
}
inline bool operator<(const Self &x) const {
assert(TermInst == x.TermInst &&
"Cannot compare iterators of different blocks!");
return idx < x.idx;
}
inline bool operator<=(const Self &x) const {
assert(TermInst == x.TermInst &&
"Cannot compare iterators of different blocks!");
return idx <= x.idx;
}
inline bool operator>=(const Self &x) const {
assert(TermInst == x.TermInst &&
"Cannot compare iterators of different blocks!");
return idx >= x.idx;
}
inline bool operator>(const Self &x) const {
assert(TermInst == x.TermInst &&
"Cannot compare iterators of different blocks!");
return idx > x.idx;
}
inline Self &operator+=(int Right) {
unsigned new_idx = idx + Right;
assert(index_is_valid(new_idx) && "Iterator index out of bound");
idx = new_idx;
return *this;
}
inline Self operator+(int Right) const {
Self tmp = *this;
tmp += Right;
return tmp;
}
inline Self &operator-=(int Right) { return operator+=(-Right); }
inline Self operator-(int Right) const { return operator+(-Right); }
inline int operator-(const Self &x) const {
assert(TermInst == x.TermInst &&
"Cannot work on iterators of different blocks!");
int distance = idx - x.idx;
return distance;
}
inline SuccessorProxy operator[](int offset) {
Self tmp = *this;
tmp += offset;
return SuccessorProxy(tmp);
}
/// Get the source BB of this iterator.
inline BB *getSource() {
assert(TermInst && "Source not available, if basic block was malformed");
return TermInst->getParent();
}
};
using succ_iterator = SuccIterator<TerminatorInst *, BasicBlock>;
using succ_const_iterator =
SuccIterator<const TerminatorInst *, const BasicBlock>;
using succ_range = iterator_range<succ_iterator>;
using succ_const_range = iterator_range<succ_const_iterator>;
private:
inline succ_iterator succ_begin() { return succ_iterator(this); }
inline succ_const_iterator succ_begin() const {
return succ_const_iterator(this);
}
inline succ_iterator succ_end() { return succ_iterator(this, true); }
inline succ_const_iterator succ_end() const {
return succ_const_iterator(this, true);
}
public:
inline succ_range successors() {
return succ_range(succ_begin(), succ_end());
}
inline succ_const_range successors() const {
return succ_const_range(succ_begin(), succ_end());
}
};
//===----------------------------------------------------------------------===//

View File

@ -611,6 +611,16 @@ public:
/// operands in the corresponding predecessor block.
bool isUsedOutsideOfBlock(const BasicBlock *BB) const;
/// Return the number of successors that this instruction has. The instruction
/// must be a terminator.
unsigned getNumSuccessors() const;
/// Return the specified successor. This instruction must be a terminator.
BasicBlock *getSuccessor(unsigned Idx) const;
/// Update the specified successor to point at the provided block. This
/// instruction must be a terminator.
void setSuccessor(unsigned Idx, BasicBlock *BB);
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Value *V) {

View File

@ -3354,6 +3354,33 @@ protected:
BranchInst *cloneImpl() const;
public:
/// Iterator type that casts an operand to a basic block.
///
/// This only makes sense because the successors are stored as adjacent
/// operands for branch instructions.
struct succ_op_iterator
: iterator_adaptor_base<succ_op_iterator, value_op_iterator,
std::random_access_iterator_tag, BasicBlock *,
ptrdiff_t, BasicBlock *, BasicBlock *> {
explicit succ_op_iterator(value_op_iterator I) : iterator_adaptor_base(I) {}
BasicBlock *operator*() const { return cast<BasicBlock>(*I); }
BasicBlock *operator->() const { return operator*(); }
};
/// The const version of `succ_op_iterator`.
struct const_succ_op_iterator
: iterator_adaptor_base<const_succ_op_iterator, const_value_op_iterator,
std::random_access_iterator_tag,
const BasicBlock *, ptrdiff_t, const BasicBlock *,
const BasicBlock *> {
explicit const_succ_op_iterator(const_value_op_iterator I)
: iterator_adaptor_base(I) {}
const BasicBlock *operator*() const { return cast<BasicBlock>(*I); }
const BasicBlock *operator->() const { return operator*(); }
};
static BranchInst *Create(BasicBlock *IfTrue,
Instruction *InsertBefore = nullptr) {
return new(1) BranchInst(IfTrue, InsertBefore);
@ -3408,6 +3435,18 @@ public:
/// continues to map correctly to each operand.
void swapSuccessors();
iterator_range<succ_op_iterator> successors() {
return make_range(
succ_op_iterator(std::next(value_op_begin(), isConditional() ? 1 : 0)),
succ_op_iterator(value_op_end()));
}
iterator_range<const_succ_op_iterator> successors() const {
return make_range(const_succ_op_iterator(
std::next(value_op_begin(), isConditional() ? 1 : 0)),
const_succ_op_iterator(value_op_end()));
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Instruction *I) {
return (I->getOpcode() == Instruction::Br);
@ -3821,6 +3860,33 @@ protected:
IndirectBrInst *cloneImpl() const;
public:
/// Iterator type that casts an operand to a basic block.
///
/// This only makes sense because the successors are stored as adjacent
/// operands for indirectbr instructions.
struct succ_op_iterator
: iterator_adaptor_base<succ_op_iterator, value_op_iterator,
std::random_access_iterator_tag, BasicBlock *,
ptrdiff_t, BasicBlock *, BasicBlock *> {
explicit succ_op_iterator(value_op_iterator I) : iterator_adaptor_base(I) {}
BasicBlock *operator*() const { return cast<BasicBlock>(*I); }
BasicBlock *operator->() const { return operator*(); }
};
/// The const version of `succ_op_iterator`.
struct const_succ_op_iterator
: iterator_adaptor_base<const_succ_op_iterator, const_value_op_iterator,
std::random_access_iterator_tag,
const BasicBlock *, ptrdiff_t, const BasicBlock *,
const BasicBlock *> {
explicit const_succ_op_iterator(const_value_op_iterator I)
: iterator_adaptor_base(I) {}
const BasicBlock *operator*() const { return cast<BasicBlock>(*I); }
const BasicBlock *operator->() const { return operator*(); }
};
static IndirectBrInst *Create(Value *Address, unsigned NumDests,
Instruction *InsertBefore = nullptr) {
return new IndirectBrInst(Address, NumDests, InsertBefore);
@ -3863,6 +3929,16 @@ public:
setOperand(i + 1, NewSucc);
}
iterator_range<succ_op_iterator> successors() {
return make_range(succ_op_iterator(std::next(value_op_begin())),
succ_op_iterator(value_op_end()));
}
iterator_range<const_succ_op_iterator> successors() const {
return make_range(const_succ_op_iterator(std::next(value_op_begin())),
const_succ_op_iterator(value_op_end()));
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Instruction *I) {
return I->getOpcode() == Instruction::IndirectBr;

View File

@ -226,7 +226,7 @@ MDNode *Loop::getLoopID() const {
MDNode *MD = nullptr;
// Check if this terminator branches to the loop header.
for (BasicBlock *Successor : TI->successors()) {
for (BasicBlock *Successor : successors(TI)) {
if (Successor == H) {
MD = TI->getMetadata(LLVMContext::MD_loop);
break;
@ -262,7 +262,7 @@ void Loop::setLoopID(MDNode *LoopID) const {
BasicBlock *H = getHeader();
for (BasicBlock *BB : this->blocks()) {
TerminatorInst *TI = BB->getTerminator();
for (BasicBlock *Successor : TI->successors()) {
for (BasicBlock *Successor : successors(TI)) {
if (Successor == H)
TI->setMetadata(LLVMContext::MD_loop, LoopID);
}

View File

@ -580,7 +580,7 @@ void MemorySSAUpdater::removeBlocks(
for (BasicBlock *BB : DeadBlocks) {
TerminatorInst *TI = BB->getTerminator();
assert(TI && "Basic block expected to have a terminator instruction");
for (BasicBlock *Succ : TI->successors())
for (BasicBlock *Succ : successors(TI))
if (!DeadBlocks.count(Succ))
if (MemoryPhi *MP = MSSA->getMemoryAccess(Succ)) {
MP->unorderedDeleteIncomingBlock(BB);

View File

@ -355,7 +355,7 @@ bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) {
MIRBuilder.buildBr(TgtBB);
// Link successors.
for (const BasicBlock *Succ : BrInst.successors())
for (const BasicBlock *Succ : successors(&BrInst))
CurBB.addSuccessor(&getMBB(*Succ));
return true;
}
@ -415,7 +415,7 @@ bool IRTranslator::translateIndirectBr(const User &U,
// Link successors.
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
for (const BasicBlock *Succ : BrInst.successors())
for (const BasicBlock *Succ : successors(&BrInst))
CurBB.addSuccessor(&getMBB(*Succ));
return true;

View File

@ -442,7 +442,7 @@ void BasicBlock::replaceSuccessorsPhiUsesWith(BasicBlock *New) {
// Cope with being called on a BasicBlock that doesn't have a terminator
// yet. Clang's CodeGenFunction::EmitReturnBlock() likes to do this.
return;
for (BasicBlock *Succ : TI->successors()) {
for (BasicBlock *Succ : successors(TI)) {
// N.B. Succ might not be a complete BasicBlock, so don't assume
// that it ends with a non-phi instruction.
for (iterator II = Succ->begin(), IE = Succ->end(); II != IE; ++II) {

View File

@ -617,6 +617,42 @@ bool Instruction::isAssociative() const {
}
}
unsigned Instruction::getNumSuccessors() const {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<const CLASS *>(this)->getNumSuccessors();
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
BasicBlock *Instruction::getSuccessor(unsigned idx) const {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<const CLASS *>(this)->getSuccessor(idx);
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
void Instruction::setSuccessor(unsigned idx, BasicBlock *B) {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<CLASS *>(this)->setSuccessor(idx, B);
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
Instruction *Instruction::cloneImpl() const {
llvm_unreachable("Subclass of Instruction failed to implement cloneImpl");
}

View File

@ -71,46 +71,6 @@ User::op_iterator CallSite::getCallee() const {
: cast<InvokeInst>(II)->op_end() - 3; // Skip BB, BB, Callee
}
//===----------------------------------------------------------------------===//
// TerminatorInst Class
//===----------------------------------------------------------------------===//
unsigned TerminatorInst::getNumSuccessors() const {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<const CLASS *>(this)->getNumSuccessors();
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
BasicBlock *TerminatorInst::getSuccessor(unsigned idx) const {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<const CLASS *>(this)->getSuccessor(idx);
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
void TerminatorInst::setSuccessor(unsigned idx, BasicBlock *B) {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
case Instruction::OPC: \
return static_cast<CLASS *>(this)->setSuccessor(idx, B);
#include "llvm/IR/Instruction.def"
default:
break;
}
llvm_unreachable("not a terminator");
}
//===----------------------------------------------------------------------===//
// SelectInst Class
//===----------------------------------------------------------------------===//

View File

@ -3198,7 +3198,7 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB, const DataLayout &DL,
}
}
for (BasicBlock *SuccBB : TI->successors())
for (BasicBlock *SuccBB : successors(TI))
Worklist.push_back(SuccBB);
} while (!Worklist.empty());

View File

@ -365,7 +365,7 @@ private:
// Return true when a successor of BB dominates A.
bool successorDominate(const BasicBlock *BB, const BasicBlock *A) {
for (const BasicBlock *Succ : BB->getTerminator()->successors())
for (const BasicBlock *Succ : successors(BB))
if (DT->dominates(Succ, A))
return true;
@ -584,8 +584,8 @@ private:
for (auto CHI : C) {
BasicBlock *Dest = CHI.Dest;
// Find if all the edges have values flowing out of BB.
bool Found = llvm::any_of(TI->successors(), [Dest](const BasicBlock *BB) {
return BB == Dest; });
bool Found = llvm::any_of(
successors(TI), [Dest](const BasicBlock *BB) { return BB == Dest; });
if (!Found)
return false;
}

View File

@ -662,7 +662,7 @@ bool LoopInterchangeLegality::tightlyNested(Loop *OuterLoop, Loop *InnerLoop) {
if (!OuterLoopHeaderBI)
return false;
for (BasicBlock *Succ : OuterLoopHeaderBI->successors())
for (BasicBlock *Succ : successors(OuterLoopHeaderBI))
if (Succ != InnerLoopPreHeader && Succ != OuterLoopLatch)
return false;
@ -1336,7 +1336,7 @@ void LoopInterchangeTransform::updateIncomingBlock(BasicBlock *CurrBlock,
static void updateSuccessor(BranchInst *BI, BasicBlock *OldBB,
BasicBlock *NewBB,
std::vector<DominatorTree::UpdateType> &DTUpdates) {
assert(llvm::count_if(BI->successors(),
assert(llvm::count_if(successors(BI),
[OldBB](BasicBlock *BB) { return BB == OldBB; }) < 2 &&
"BI must jump to OldBB at most once.");
for (unsigned i = 0, e = BI->getNumSuccessors(); i < e; ++i) {

View File

@ -59,7 +59,7 @@ void llvm::DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU) {
// of their predecessors is going away.
if (DTU)
Updates.reserve(BBTerm->getNumSuccessors());
for (BasicBlock *Succ : BBTerm->successors()) {
for (BasicBlock *Succ : successors(BBTerm)) {
Succ->removePredecessor(BB);
if (DTU)
Updates.push_back({DominatorTree::Delete, BB, Succ});

View File

@ -415,7 +415,7 @@ void PruningFunctionCloner::CloneBlock(const BasicBlock *BB,
// Recursively clone any reachable successor blocks.
const TerminatorInst *TI = BB->getTerminator();
for (const BasicBlock *Succ : TI->successors())
for (const BasicBlock *Succ : successors(TI))
ToClone.push_back(Succ);
}

View File

@ -235,7 +235,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
Updates.reserve(SI->getNumSuccessors() - 1);
// Remove entries from PHI nodes which we no longer branch to...
for (BasicBlock *Succ : SI->successors()) {
for (BasicBlock *Succ : successors(SI)) {
// Found case matching a constant operand?
if (Succ == TheOnlyDest) {
TheOnlyDest = nullptr; // Don't modify the first branch to TheOnlyDest

View File

@ -375,8 +375,7 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) {
// Along with all the other instructions, we just cloned OrigHeader's
// terminator into OrigPreHeader. Fix up the PHI nodes in each of OrigHeader's
// successors by duplicating their incoming values for OrigHeader.
TerminatorInst *TI = OrigHeader->getTerminator();
for (BasicBlock *SuccBB : TI->successors())
for (BasicBlock *SuccBB : successors(OrigHeader))
for (BasicBlock::iterator BI = SuccBB->begin();
PHINode *PN = dyn_cast<PHINode>(BI); ++BI)
PN->addIncoming(PN->getIncomingValueForBlock(OrigHeader), OrigPreheader);

View File

@ -3414,7 +3414,7 @@ static bool SimplifyTerminatorOnSelect(TerminatorInst *OldTerm, Value *Cond,
BasicBlock *KeepEdge2 = TrueBB != FalseBB ? FalseBB : nullptr;
// Then remove the rest.
for (BasicBlock *Succ : OldTerm->successors()) {
for (BasicBlock *Succ : successors(OldTerm)) {
// Make sure only to keep exactly one copy of each edge.
if (Succ == KeepEdge1)
KeepEdge1 = nullptr;