Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions llvm/include/llvm/ADT/GenericCycleImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,17 @@ auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(CycleT *A,
return A;
}

/// \brief Find the innermost cycle containing both given blocks.
///
/// \returns the innermost cycle containing both \p A and \p B
/// or nullptr if there is no such cycle.
template <typename ContextT>
auto GenericCycleInfo<ContextT>::getSmallestCommonCycle(BlockT *A,
BlockT *B) const
-> CycleT * {
return getSmallestCommonCycle(getCycle(A), getCycle(B));
}

/// \brief get the depth for the cycle which containing a given block.
///
/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/ADT/GenericCycleInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ template <typename ContextT> class GenericCycleInfo {

CycleT *getCycle(const BlockT *Block) const;
CycleT *getSmallestCommonCycle(CycleT *A, CycleT *B) const;
CycleT *getSmallestCommonCycle(BlockT *A, BlockT *B) const;
unsigned getCycleDepth(const BlockT *Block) const;
CycleT *getTopLevelParentCycle(BlockT *Block);

Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/Support/GenericLoopInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,17 @@ template <class BlockT, class LoopT> class LoopInfoBase {
return L ? L->getLoopDepth() : 0;
}

/// \brief Find the innermost loop containing both given loops.
///
/// \returns the innermost loop containing both \p A and \p B
/// or nullptr if there is no such loop.
LoopT *getSmallestCommonLoop(LoopT *A, LoopT *B) const;
/// \brief Find the innermost loop containing both given blocks.
///
/// \returns the innermost loop containing both \p A and \p B
/// or nullptr if there is no such loop.
LoopT *getSmallestCommonLoop(BlockT *A, BlockT *B) const;

// True if the block is a loop header node
bool isLoopHeader(const BlockT *BB) const {
const LoopT *L = getLoopFor(BB);
Expand Down
32 changes: 31 additions & 1 deletion llvm/include/llvm/Support/GenericLoopInfoImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
if (BB == getHeader()) {
assert(!OutsideLoopPreds.empty() && "Loop is unreachable!");
} else if (!OutsideLoopPreds.empty()) {
// A non-header loop shouldn't be reachable from outside the loop,
// A non-header loop block shouldn't be reachable from outside the loop,
// though it is permitted if the predecessor is not itself actually
// reachable.
BlockT *EntryBB = &BB->getParent()->front();
Expand Down Expand Up @@ -645,6 +645,36 @@ LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() const {
return PreOrderLoops;
}

template <class BlockT, class LoopT>
LoopT *LoopInfoBase<BlockT, LoopT>::getSmallestCommonLoop(LoopT *A,
LoopT *B) const {
if (!A || !B)
return nullptr;

// If lops A and B have different depth replace them with parent loop
// until they have the same depth.
while (A->getLoopDepth() > B->getLoopDepth())
A = A->getParentLoop();
while (B->getLoopDepth() > A->getLoopDepth())
B = B->getParentLoop();

// Loops A and B are at same depth but may be disjoint, replace them with
// parent loops until we find loop that contains both or we run out of
// parent loops.
while (A != B) {
A = A->getParentLoop();
B = B->getParentLoop();
}

return A;
}

template <class BlockT, class LoopT>
LoopT *LoopInfoBase<BlockT, LoopT>::getSmallestCommonLoop(BlockT *A,
BlockT *B) const {
return getSmallestCommonLoop(getLoopFor(A), getLoopFor(B));
}

// Debugging
template <class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Printable.h"
#include <cassert>

namespace llvm {
Expand Down Expand Up @@ -611,6 +612,8 @@ LLVM_ABI void InvertBranch(BranchInst *PBI, IRBuilderBase &Builder);
// br/brcond/unreachable/ret
LLVM_ABI bool hasOnlySimpleTerminator(const Function &F);

LLVM_ABI Printable printBasicBlock(const BasicBlock *BB);

} // end namespace llvm

#endif // LLVM_TRANSFORMS_UTILS_BASICBLOCKUTILS_H
34 changes: 33 additions & 1 deletion llvm/include/llvm/Transforms/Utils/ControlFlowUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/CycleInfo.h"

namespace llvm {

class BasicBlock;
class CallBrInst;
class LoopInfo;
class DomTreeUpdater;

/// Given a set of branch descriptors [BB, Succ0, Succ1], create a "hub" such
Expand Down Expand Up @@ -104,7 +107,8 @@ struct ControlFlowHub {
: BB(BB), Succ0(Succ0), Succ1(Succ1) {}
};

void addBranch(BasicBlock *BB, BasicBlock *Succ0, BasicBlock *Succ1) {
void addBranch(BasicBlock *BB, BasicBlock *Succ0,
BasicBlock *Succ1 = nullptr) {
assert(BB);
assert(Succ0 || Succ1);
Branches.emplace_back(BB, Succ0, Succ1);
Expand All @@ -118,6 +122,34 @@ struct ControlFlowHub {
std::optional<unsigned> MaxControlFlowBooleans = std::nullopt);

SmallVector<BranchDescriptor> Branches;

/// \brief Create a new intermediate target block for a callbr edge.
///
/// This function creates a new basic block (the "target block") that sits
/// between a callbr instruction and one of its successors. The callbr's
/// successor is rewired to this new block, and the new block unconditionally
/// branches to the original successor. This is useful for normalizing control
/// flow, e.g., when transforming irreducible loops.
///
/// \param CallBr The callbr instruction whose edge is to be split.
/// \param Succ The original successor basic block to be reached.
/// \param SuccIdx The index of the successor in the callbr
/// instruction.
/// \param CI Optional CycleInfo for updating cycle membership.
/// \param DTU Optional DomTreeUpdater for updating the dominator
/// tree.
/// \param LI Optional LoopInfo for updating loop membership.
/// \param UpdatedLI Optional output flag indicating if LoopInfo has been
/// updated.
///
/// \returns The newly created intermediate target block.
///
/// \note This function updates PHI nodes, dominator tree, loop info, and
/// cycle info as needed.
static BasicBlock *
createCallBrTarget(CallBrInst *CallBr, BasicBlock *Succ, unsigned SuccIdx,
CycleInfo *CI = nullptr, DomTreeUpdater *DTU = nullptr,
LoopInfo *LI = nullptr, bool *UpdatedLI = nullptr);
};

} // end namespace llvm
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1775,3 +1775,10 @@ bool llvm::hasOnlySimpleTerminator(const Function &F) {
}
return true;
}

Printable llvm::printBasicBlock(const BasicBlock *BB) {
return Printable([BB](raw_ostream &OS) {
if (BB)
return BB->printAsOperand(OS);
});
}
58 changes: 57 additions & 1 deletion llvm/lib/Transforms/Utils/ControlFlowUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/ValueHandle.h"
Expand Down Expand Up @@ -282,7 +283,9 @@ std::pair<BasicBlock *, bool> ControlFlowHub::finalize(

for (auto [BB, Succ0, Succ1] : Branches) {
#ifndef NDEBUG
assert(Incoming.insert(BB).second && "Duplicate entry for incoming block.");
assert(
(Incoming.insert(BB).second || isa<CallBrInst>(BB->getTerminator())) &&
"Duplicate entry for incoming block.");
#endif
if (Succ0)
Outgoing.insert(Succ0);
Expand Down Expand Up @@ -342,3 +345,56 @@ std::pair<BasicBlock *, bool> ControlFlowHub::finalize(

return {FirstGuardBlock, true};
}

template <typename TI, typename T>
static bool updateCycleLoopInfo(TI *LCI, BasicBlock *CallBrBlock,
BasicBlock *CallBrTarget, BasicBlock *Succ) {
static_assert(std::is_same_v<TI, CycleInfo> || std::is_same_v<TI, LoopInfo>,
"type must be CycleInfo or LoopInfo");
if (!LCI)
return false;

T *LC;
if constexpr (std::is_same_v<TI, CycleInfo>)
LC = LCI->getSmallestCommonCycle(CallBrBlock, Succ);
else
LC = LCI->getSmallestCommonLoop(CallBrBlock, Succ);
if (!LC)
return false;

if constexpr (std::is_same_v<TI, CycleInfo>)
LCI->addBlockToCycle(CallBrTarget, LC);
else
LC->addBasicBlockToLoop(CallBrTarget, *LCI);

return true;
}

BasicBlock *ControlFlowHub::createCallBrTarget(CallBrInst *CallBr,
BasicBlock *Succ,
unsigned SuccIdx, CycleInfo *CI,
DomTreeUpdater *DTU,
LoopInfo *LI, bool *UpdatedLI) {
BasicBlock *CallBrBlock = CallBr->getParent();
BasicBlock *CallBrTarget =
BasicBlock::Create(CallBrBlock->getContext(),
CallBrBlock->getName() + ".target." + Succ->getName(),
CallBrBlock->getParent());
// Rewire control flow from callbr to the new target block.
Succ->replacePhiUsesWith(CallBrBlock, CallBrTarget);
CallBr->setSuccessor(SuccIdx, CallBrTarget);
// Jump from the new target block to the original successor.
BranchInst::Create(Succ, CallBrTarget);
bool Updated =
updateCycleLoopInfo<LoopInfo, Loop>(LI, CallBrBlock, CallBrTarget, Succ);
if (UpdatedLI)
*UpdatedLI = Updated;
updateCycleLoopInfo<CycleInfo, Cycle>(CI, CallBrBlock, CallBrTarget, Succ);
if (DTU) {
DTU->applyUpdates({{DominatorTree::Insert, CallBrBlock, CallBrTarget}});
if (DTU->getDomTree().dominates(CallBrBlock, Succ))
DTU->applyUpdates({{DominatorTree::Delete, CallBrBlock, Succ},
{DominatorTree::Insert, CallBrTarget, Succ}});
}
return CallBrTarget;
}
Loading
Loading