//===- UnifyLoopExits.cpp - Redirect exiting edges to one block -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // For each natural loop with multiple exit blocks, this pass creates a new // block N such that all exiting blocks now branch to N, and then control flow // is redistributed to all the original exit blocks. // // Limitation: This assumes that all terminators in the CFG are direct branches // (the "br" instruction). The presence of any other control flow // such as indirectbr, switch or callbr will cause an assert. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/UnifyLoopExits.h" #include "llvm/ADT/MapVector.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ControlFlowUtils.h" #define DEBUG_TYPE … usingnamespacellvm; static cl::opt<unsigned> MaxBooleansInControlFlowHub( "max-booleans-in-control-flow-hub", cl::init(32), cl::Hidden, cl::desc("Set the maximum number of outgoing blocks for using a boolean " "value to record the exiting block in the ControlFlowHub.")); namespace { struct UnifyLoopExitsLegacyPass : public FunctionPass { … }; } // namespace char UnifyLoopExitsLegacyPass::ID = …; FunctionPass *llvm::createUnifyLoopExitsPass() { … } INITIALIZE_PASS_BEGIN(UnifyLoopExitsLegacyPass, "unify-loop-exits", "Fixup each natural loop to have a single exit block", false /* Only looks at CFG */, false /* Analysis Pass */) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(UnifyLoopExitsLegacyPass, "unify-loop-exits", "Fixup each natural loop to have a single exit block", false /* Only looks at CFG */, false /* Analysis Pass */) // The current transform introduces new control flow paths which may break the // SSA requirement that every def must dominate all its uses. For example, // consider a value D defined inside the loop that is used by some instruction // U outside the loop. It follows that D dominates U, since the original // program has valid SSA form. After merging the exits, all paths from D to U // now flow through the unified exit block. In addition, there may be other // paths that do not pass through D, but now reach the unified exit // block. Thus, D no longer dominates U. // // Restore the dominance by creating a phi for each such D at the new unified // loop exit. But when doing this, ignore any uses U that are in the new unified // loop exit, since those were introduced specially when the block was created. // // The use of SSAUpdater seems like overkill for this operation. The location // for creating the new PHI is well-known, and also the set of incoming blocks // to the new PHI. static void restoreSSA(const DominatorTree &DT, const Loop *L, SmallVectorImpl<BasicBlock *> &Incoming, BasicBlock *LoopExitBlock) { … } static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) { … } static bool runImpl(LoopInfo &LI, DominatorTree &DT) { … } bool UnifyLoopExitsLegacyPass::runOnFunction(Function &F) { … } namespace llvm { PreservedAnalyses UnifyLoopExitsPass::run(Function &F, FunctionAnalysisManager &AM) { … } } // namespace llvm