10 changes: 10 additions & 0 deletions llvm/include/llvm/IR/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,16 @@ class Instruction : public User,
/// 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) {
Expand Down
76 changes: 76 additions & 0 deletions llvm/include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -3354,6 +3354,33 @@ class BranchInst : public TerminatorInst {
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);
Expand Down Expand Up @@ -3408,6 +3435,18 @@ class BranchInst : public TerminatorInst {
/// 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);
Expand Down Expand Up @@ -3821,6 +3860,33 @@ class IndirectBrInst : public TerminatorInst {
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);
Expand Down Expand Up @@ -3863,6 +3929,16 @@ class IndirectBrInst : public TerminatorInst {
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;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Analysis/LoopInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/MemorySSAUpdater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/IR/BasicBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
36 changes: 36 additions & 0 deletions llvm/lib/IR/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
40 changes: 0 additions & 40 deletions llvm/lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Transforms/Scalar/GVNHoist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ class GVNHoist {

// 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;

Expand Down Expand Up @@ -584,8 +584,8 @@ class GVNHoist {
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;
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/Scalar/LoopInterchange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/CloneFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down