10b57cec5SDimitry Andric //===- SimplifyCFGPass.cpp - CFG Simplification Pass ----------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements dead code elimination and basic block merging, along 100b57cec5SDimitry Andric // with a collection of other peephole control flow optimizations. For example: 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // * Removes basic blocks with no predecessors. 130b57cec5SDimitry Andric // * Merges a basic block into its predecessor if there is only one and the 140b57cec5SDimitry Andric // predecessor only has one successor. 150b57cec5SDimitry Andric // * Eliminates PHI nodes for basic blocks with a single predecessor. 160b57cec5SDimitry Andric // * Eliminates a basic block that only contains an unconditional branch. 170b57cec5SDimitry Andric // * Changes invoke instructions to nounwind functions to be calls. 180b57cec5SDimitry Andric // * Change things like "if (x) if (y)" into "if (x&y)". 190b57cec5SDimitry Andric // * etc.. 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 220b57cec5SDimitry Andric 23fe6060f1SDimitry Andric #include "llvm/ADT/MapVector.h" 240b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 250b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 260b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 270b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h" 280b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h" 29e8d8bef9SDimitry Andric #include "llvm/Analysis/DomTreeUpdater.h" 300b57cec5SDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 310b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 320b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 330b57cec5SDimitry Andric #include "llvm/IR/CFG.h" 3481ad6265SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 35e8d8bef9SDimitry Andric #include "llvm/IR/Dominators.h" 360b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 370b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 38e8d8bef9SDimitry Andric #include "llvm/IR/ValueHandle.h" 39480093f4SDimitry Andric #include "llvm/InitializePasses.h" 400b57cec5SDimitry Andric #include "llvm/Pass.h" 410b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 420b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h" 430b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/SimplifyCFG.h" 44480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 45e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/SimplifyCFGOptions.h" 460b57cec5SDimitry Andric #include <utility> 470b57cec5SDimitry Andric using namespace llvm; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric #define DEBUG_TYPE "simplifycfg" 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric static cl::opt<unsigned> UserBonusInstThreshold( 520b57cec5SDimitry Andric "bonus-inst-threshold", cl::Hidden, cl::init(1), 530b57cec5SDimitry Andric cl::desc("Control the number of bonus instructions (default = 1)")); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric static cl::opt<bool> UserKeepLoops( 560b57cec5SDimitry Andric "keep-loops", cl::Hidden, cl::init(true), 570b57cec5SDimitry Andric cl::desc("Preserve canonical loop structure (default = true)")); 580b57cec5SDimitry Andric 59fb03ea46SDimitry Andric static cl::opt<bool> UserSwitchRangeToICmp( 60fb03ea46SDimitry Andric "switch-range-to-icmp", cl::Hidden, cl::init(false), 61fb03ea46SDimitry Andric cl::desc( 62fb03ea46SDimitry Andric "Convert switches into an integer range comparison (default = false)")); 63fb03ea46SDimitry Andric 640b57cec5SDimitry Andric static cl::opt<bool> UserSwitchToLookup( 650b57cec5SDimitry Andric "switch-to-lookup", cl::Hidden, cl::init(false), 660b57cec5SDimitry Andric cl::desc("Convert switches to lookup tables (default = false)")); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric static cl::opt<bool> UserForwardSwitchCond( 690b57cec5SDimitry Andric "forward-switch-cond", cl::Hidden, cl::init(false), 700b57cec5SDimitry Andric cl::desc("Forward switch condition to phi ops (default = false)")); 710b57cec5SDimitry Andric 72e8d8bef9SDimitry Andric static cl::opt<bool> UserHoistCommonInsts( 73e8d8bef9SDimitry Andric "hoist-common-insts", cl::Hidden, cl::init(false), 74e8d8bef9SDimitry Andric cl::desc("hoist common instructions (default = false)")); 75e8d8bef9SDimitry Andric 760b57cec5SDimitry Andric static cl::opt<bool> UserSinkCommonInsts( 770b57cec5SDimitry Andric "sink-common-insts", cl::Hidden, cl::init(false), 780b57cec5SDimitry Andric cl::desc("Sink common instructions (default = false)")); 790b57cec5SDimitry Andric 80*0fca6ea1SDimitry Andric static cl::opt<bool> UserSpeculateUnpredictables( 81*0fca6ea1SDimitry Andric "speculate-unpredictables", cl::Hidden, cl::init(false), 82*0fca6ea1SDimitry Andric cl::desc("Speculate unpredictable branches (default = false)")); 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric STATISTIC(NumSimpl, "Number of blocks simplified"); 850b57cec5SDimitry Andric 8604eeddc0SDimitry Andric static bool 8704eeddc0SDimitry Andric performBlockTailMerging(Function &F, ArrayRef<BasicBlock *> BBs, 8804eeddc0SDimitry Andric std::vector<DominatorTree::UpdateType> *Updates) { 8904eeddc0SDimitry Andric SmallVector<PHINode *, 1> NewOps; 9004eeddc0SDimitry Andric 9104eeddc0SDimitry Andric // We don't want to change IR just because we can. 9204eeddc0SDimitry Andric // Only do that if there are at least two blocks we'll tail-merge. 9304eeddc0SDimitry Andric if (BBs.size() < 2) 9404eeddc0SDimitry Andric return false; 9504eeddc0SDimitry Andric 9604eeddc0SDimitry Andric if (Updates) 9704eeddc0SDimitry Andric Updates->reserve(Updates->size() + BBs.size()); 9804eeddc0SDimitry Andric 9904eeddc0SDimitry Andric BasicBlock *CanonicalBB; 10004eeddc0SDimitry Andric Instruction *CanonicalTerm; 10104eeddc0SDimitry Andric { 10204eeddc0SDimitry Andric auto *Term = BBs[0]->getTerminator(); 10304eeddc0SDimitry Andric 10404eeddc0SDimitry Andric // Create a canonical block for this function terminator type now, 10504eeddc0SDimitry Andric // placing it *before* the first block that will branch to it. 10604eeddc0SDimitry Andric CanonicalBB = BasicBlock::Create( 10704eeddc0SDimitry Andric F.getContext(), Twine("common.") + Term->getOpcodeName(), &F, BBs[0]); 10804eeddc0SDimitry Andric // We'll also need a PHI node per each operand of the terminator. 10904eeddc0SDimitry Andric NewOps.resize(Term->getNumOperands()); 11004eeddc0SDimitry Andric for (auto I : zip(Term->operands(), NewOps)) { 11104eeddc0SDimitry Andric std::get<1>(I) = PHINode::Create(std::get<0>(I)->getType(), 11204eeddc0SDimitry Andric /*NumReservedValues=*/BBs.size(), 11304eeddc0SDimitry Andric CanonicalBB->getName() + ".op"); 114bdd1243dSDimitry Andric std::get<1>(I)->insertInto(CanonicalBB, CanonicalBB->end()); 11504eeddc0SDimitry Andric } 11604eeddc0SDimitry Andric // Make it so that this canonical block actually has the right 11704eeddc0SDimitry Andric // terminator. 11804eeddc0SDimitry Andric CanonicalTerm = Term->clone(); 119bdd1243dSDimitry Andric CanonicalTerm->insertInto(CanonicalBB, CanonicalBB->end()); 12004eeddc0SDimitry Andric // If the canonical terminator has operands, rewrite it to take PHI's. 12104eeddc0SDimitry Andric for (auto I : zip(NewOps, CanonicalTerm->operands())) 12204eeddc0SDimitry Andric std::get<1>(I) = std::get<0>(I); 12304eeddc0SDimitry Andric } 12404eeddc0SDimitry Andric 12504eeddc0SDimitry Andric // Now, go through each block (with the current terminator type) 12604eeddc0SDimitry Andric // we've recorded, and rewrite it to branch to the new common block. 12706c3fb27SDimitry Andric DILocation *CommonDebugLoc = nullptr; 12804eeddc0SDimitry Andric for (BasicBlock *BB : BBs) { 12904eeddc0SDimitry Andric auto *Term = BB->getTerminator(); 13004eeddc0SDimitry Andric assert(Term->getOpcode() == CanonicalTerm->getOpcode() && 13104eeddc0SDimitry Andric "All blocks to be tail-merged must be the same " 13204eeddc0SDimitry Andric "(function-terminating) terminator type."); 13304eeddc0SDimitry Andric 13404eeddc0SDimitry Andric // Aha, found a new non-canonical function terminator. If it has operands, 13504eeddc0SDimitry Andric // forward them to the PHI nodes in the canonical block. 13604eeddc0SDimitry Andric for (auto I : zip(Term->operands(), NewOps)) 13704eeddc0SDimitry Andric std::get<1>(I)->addIncoming(std::get<0>(I), BB); 13804eeddc0SDimitry Andric 13904eeddc0SDimitry Andric // Compute the debug location common to all the original terminators. 14004eeddc0SDimitry Andric if (!CommonDebugLoc) 14104eeddc0SDimitry Andric CommonDebugLoc = Term->getDebugLoc(); 14204eeddc0SDimitry Andric else 14304eeddc0SDimitry Andric CommonDebugLoc = 14404eeddc0SDimitry Andric DILocation::getMergedLocation(CommonDebugLoc, Term->getDebugLoc()); 14504eeddc0SDimitry Andric 14604eeddc0SDimitry Andric // And turn BB into a block that just unconditionally branches 14704eeddc0SDimitry Andric // to the canonical block. 148*0fca6ea1SDimitry Andric Instruction *BI = BranchInst::Create(CanonicalBB, BB); 149*0fca6ea1SDimitry Andric BI->setDebugLoc(Term->getDebugLoc()); 15004eeddc0SDimitry Andric Term->eraseFromParent(); 151*0fca6ea1SDimitry Andric 15204eeddc0SDimitry Andric if (Updates) 15304eeddc0SDimitry Andric Updates->push_back({DominatorTree::Insert, BB, CanonicalBB}); 15404eeddc0SDimitry Andric } 15504eeddc0SDimitry Andric 15604eeddc0SDimitry Andric CanonicalTerm->setDebugLoc(CommonDebugLoc); 15704eeddc0SDimitry Andric 15804eeddc0SDimitry Andric return true; 15904eeddc0SDimitry Andric } 16004eeddc0SDimitry Andric 161fe6060f1SDimitry Andric static bool tailMergeBlocksWithSimilarFunctionTerminators(Function &F, 162fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 163fe6060f1SDimitry Andric SmallMapVector<unsigned /*TerminatorOpcode*/, SmallVector<BasicBlock *, 2>, 4> 164fe6060f1SDimitry Andric Structure; 1650b57cec5SDimitry Andric 166fe6060f1SDimitry Andric // Scan all the blocks in the function, record the interesting-ones. 167fe6060f1SDimitry Andric for (BasicBlock &BB : F) { 168e8d8bef9SDimitry Andric if (DTU && DTU->isBBPendingDeletion(&BB)) 169e8d8bef9SDimitry Andric continue; 1700b57cec5SDimitry Andric 171fe6060f1SDimitry Andric // We are only interested in function-terminating blocks. 172fe6060f1SDimitry Andric if (!succ_empty(&BB)) 1730b57cec5SDimitry Andric continue; 1740b57cec5SDimitry Andric 175fe6060f1SDimitry Andric auto *Term = BB.getTerminator(); 1760b57cec5SDimitry Andric 177fe6060f1SDimitry Andric // Fow now only support `ret`/`resume` function terminators. 178fe6060f1SDimitry Andric // FIXME: lift this restriction. 179fe6060f1SDimitry Andric switch (Term->getOpcode()) { 180fe6060f1SDimitry Andric case Instruction::Ret: 181fe6060f1SDimitry Andric case Instruction::Resume: 182d65cd7a5SDimitry Andric break; 183fe6060f1SDimitry Andric default: 184fe6060f1SDimitry Andric continue; 185d65cd7a5SDimitry Andric } 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric // We can't tail-merge block that contains a musttail call. 188fe6060f1SDimitry Andric if (BB.getTerminatingMustTailCall()) 189d65cd7a5SDimitry Andric continue; 190d65cd7a5SDimitry Andric 191fe6060f1SDimitry Andric // Calls to experimental_deoptimize must be followed by a return 192fe6060f1SDimitry Andric // of the value computed by experimental_deoptimize. 193fe6060f1SDimitry Andric // I.e., we can not change `ret` to `br` for this block. 194fe6060f1SDimitry Andric if (auto *CI = 195fe6060f1SDimitry Andric dyn_cast_or_null<CallInst>(Term->getPrevNonDebugInstruction())) { 196fe6060f1SDimitry Andric if (Function *F = CI->getCalledFunction()) 197fe6060f1SDimitry Andric if (Intrinsic::ID ID = F->getIntrinsicID()) 198fe6060f1SDimitry Andric if (ID == Intrinsic::experimental_deoptimize) 199fe6060f1SDimitry Andric continue; 200fe6060f1SDimitry Andric } 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric // PHI nodes cannot have token type, so if the terminator has an operand 203fe6060f1SDimitry Andric // with token type, we can not tail-merge this kind of function terminators. 204fe6060f1SDimitry Andric if (any_of(Term->operands(), 205fe6060f1SDimitry Andric [](Value *Op) { return Op->getType()->isTokenTy(); })) 206fe6060f1SDimitry Andric continue; 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric // Canonical blocks are uniqued based on the terminator type (opcode). 209fe6060f1SDimitry Andric Structure[Term->getOpcode()].emplace_back(&BB); 210fe6060f1SDimitry Andric } 211fe6060f1SDimitry Andric 212fe6060f1SDimitry Andric bool Changed = false; 213fe6060f1SDimitry Andric 214fe6060f1SDimitry Andric std::vector<DominatorTree::UpdateType> Updates; 215fe6060f1SDimitry Andric 21604eeddc0SDimitry Andric for (ArrayRef<BasicBlock *> BBs : make_second_range(Structure)) 21704eeddc0SDimitry Andric Changed |= performBlockTailMerging(F, BBs, DTU ? &Updates : nullptr); 218fe6060f1SDimitry Andric 219fe6060f1SDimitry Andric if (DTU) 220fe6060f1SDimitry Andric DTU->applyUpdates(Updates); 221fe6060f1SDimitry Andric 2220b57cec5SDimitry Andric return Changed; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric /// Call SimplifyCFG on all the blocks in the function, 2260b57cec5SDimitry Andric /// iterating until no more changes are made. 2270b57cec5SDimitry Andric static bool iterativelySimplifyCFG(Function &F, const TargetTransformInfo &TTI, 228e8d8bef9SDimitry Andric DomTreeUpdater *DTU, 2290b57cec5SDimitry Andric const SimplifyCFGOptions &Options) { 2300b57cec5SDimitry Andric bool Changed = false; 2310b57cec5SDimitry Andric bool LocalChange = true; 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric SmallVector<std::pair<const BasicBlock *, const BasicBlock *>, 32> Edges; 2340b57cec5SDimitry Andric FindFunctionBackedges(F, Edges); 235e8d8bef9SDimitry Andric SmallPtrSet<BasicBlock *, 16> UniqueLoopHeaders; 23606c3fb27SDimitry Andric for (const auto &Edge : Edges) 23706c3fb27SDimitry Andric UniqueLoopHeaders.insert(const_cast<BasicBlock *>(Edge.second)); 238e8d8bef9SDimitry Andric 239e8d8bef9SDimitry Andric SmallVector<WeakVH, 16> LoopHeaders(UniqueLoopHeaders.begin(), 240e8d8bef9SDimitry Andric UniqueLoopHeaders.end()); 2410b57cec5SDimitry Andric 242349cc55cSDimitry Andric unsigned IterCnt = 0; 243349cc55cSDimitry Andric (void)IterCnt; 2440b57cec5SDimitry Andric while (LocalChange) { 2454824e7fdSDimitry Andric assert(IterCnt++ < 1000 && "Iterative simplification didn't converge!"); 2460b57cec5SDimitry Andric LocalChange = false; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // Loop over all of the basic blocks and remove them if they are unneeded. 2490b57cec5SDimitry Andric for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) { 250e8d8bef9SDimitry Andric BasicBlock &BB = *BBIt++; 251e8d8bef9SDimitry Andric if (DTU) { 252e8d8bef9SDimitry Andric assert( 253e8d8bef9SDimitry Andric !DTU->isBBPendingDeletion(&BB) && 254e8d8bef9SDimitry Andric "Should not end up trying to simplify blocks marked for removal."); 255e8d8bef9SDimitry Andric // Make sure that the advanced iterator does not point at the blocks 256e8d8bef9SDimitry Andric // that are marked for removal, skip over all such blocks. 257e8d8bef9SDimitry Andric while (BBIt != F.end() && DTU->isBBPendingDeletion(&*BBIt)) 258e8d8bef9SDimitry Andric ++BBIt; 259e8d8bef9SDimitry Andric } 260e8d8bef9SDimitry Andric if (simplifyCFG(&BB, TTI, DTU, Options, LoopHeaders)) { 2610b57cec5SDimitry Andric LocalChange = true; 2620b57cec5SDimitry Andric ++NumSimpl; 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric Changed |= LocalChange; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric return Changed; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 270e8d8bef9SDimitry Andric static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI, 271e8d8bef9SDimitry Andric DominatorTree *DT, 2720b57cec5SDimitry Andric const SimplifyCFGOptions &Options) { 273e8d8bef9SDimitry Andric DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); 274e8d8bef9SDimitry Andric 275e8d8bef9SDimitry Andric bool EverChanged = removeUnreachableBlocks(F, DT ? &DTU : nullptr); 276fe6060f1SDimitry Andric EverChanged |= 277fe6060f1SDimitry Andric tailMergeBlocksWithSimilarFunctionTerminators(F, DT ? &DTU : nullptr); 278e8d8bef9SDimitry Andric EverChanged |= iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // If neither pass changed anything, we're done. 2810b57cec5SDimitry Andric if (!EverChanged) return false; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric // iterativelySimplifyCFG can (rarely) make some loops dead. If this happens, 2840b57cec5SDimitry Andric // removeUnreachableBlocks is needed to nuke them, which means we should 2850b57cec5SDimitry Andric // iterate between the two optimizations. We structure the code like this to 2860b57cec5SDimitry Andric // avoid rerunning iterativelySimplifyCFG if the second pass of 2870b57cec5SDimitry Andric // removeUnreachableBlocks doesn't do anything. 288e8d8bef9SDimitry Andric if (!removeUnreachableBlocks(F, DT ? &DTU : nullptr)) 2890b57cec5SDimitry Andric return true; 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric do { 292e8d8bef9SDimitry Andric EverChanged = iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options); 293e8d8bef9SDimitry Andric EverChanged |= removeUnreachableBlocks(F, DT ? &DTU : nullptr); 2940b57cec5SDimitry Andric } while (EverChanged); 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric return true; 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric 299e8d8bef9SDimitry Andric static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI, 300e8d8bef9SDimitry Andric DominatorTree *DT, 301e8d8bef9SDimitry Andric const SimplifyCFGOptions &Options) { 302e8d8bef9SDimitry Andric assert((!RequireAndPreserveDomTree || 303e8d8bef9SDimitry Andric (DT && DT->verify(DominatorTree::VerificationLevel::Full))) && 304e8d8bef9SDimitry Andric "Original domtree is invalid?"); 305e8d8bef9SDimitry Andric 306e8d8bef9SDimitry Andric bool Changed = simplifyFunctionCFGImpl(F, TTI, DT, Options); 307e8d8bef9SDimitry Andric 308e8d8bef9SDimitry Andric assert((!RequireAndPreserveDomTree || 309e8d8bef9SDimitry Andric (DT && DT->verify(DominatorTree::VerificationLevel::Full))) && 310e8d8bef9SDimitry Andric "Failed to maintain validity of domtree!"); 311e8d8bef9SDimitry Andric 312e8d8bef9SDimitry Andric return Changed; 313e8d8bef9SDimitry Andric } 314e8d8bef9SDimitry Andric 3150b57cec5SDimitry Andric // Command-line settings override compile-time settings. 316e8d8bef9SDimitry Andric static void applyCommandLineOverridesToOptions(SimplifyCFGOptions &Options) { 317e8d8bef9SDimitry Andric if (UserBonusInstThreshold.getNumOccurrences()) 318e8d8bef9SDimitry Andric Options.BonusInstThreshold = UserBonusInstThreshold; 319e8d8bef9SDimitry Andric if (UserForwardSwitchCond.getNumOccurrences()) 320e8d8bef9SDimitry Andric Options.ForwardSwitchCondToPhi = UserForwardSwitchCond; 321fb03ea46SDimitry Andric if (UserSwitchRangeToICmp.getNumOccurrences()) 322fb03ea46SDimitry Andric Options.ConvertSwitchRangeToICmp = UserSwitchRangeToICmp; 323e8d8bef9SDimitry Andric if (UserSwitchToLookup.getNumOccurrences()) 324e8d8bef9SDimitry Andric Options.ConvertSwitchToLookupTable = UserSwitchToLookup; 325e8d8bef9SDimitry Andric if (UserKeepLoops.getNumOccurrences()) 326e8d8bef9SDimitry Andric Options.NeedCanonicalLoop = UserKeepLoops; 327e8d8bef9SDimitry Andric if (UserHoistCommonInsts.getNumOccurrences()) 328e8d8bef9SDimitry Andric Options.HoistCommonInsts = UserHoistCommonInsts; 329e8d8bef9SDimitry Andric if (UserSinkCommonInsts.getNumOccurrences()) 330e8d8bef9SDimitry Andric Options.SinkCommonInsts = UserSinkCommonInsts; 331*0fca6ea1SDimitry Andric if (UserSpeculateUnpredictables.getNumOccurrences()) 332*0fca6ea1SDimitry Andric Options.SpeculateUnpredictables = UserSpeculateUnpredictables; 333e8d8bef9SDimitry Andric } 334e8d8bef9SDimitry Andric 33504eeddc0SDimitry Andric SimplifyCFGPass::SimplifyCFGPass() { 336e8d8bef9SDimitry Andric applyCommandLineOverridesToOptions(Options); 337e8d8bef9SDimitry Andric } 338e8d8bef9SDimitry Andric 339e8d8bef9SDimitry Andric SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts) 340e8d8bef9SDimitry Andric : Options(Opts) { 341e8d8bef9SDimitry Andric applyCommandLineOverridesToOptions(Options); 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 344349cc55cSDimitry Andric void SimplifyCFGPass::printPipeline( 345349cc55cSDimitry Andric raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { 346349cc55cSDimitry Andric static_cast<PassInfoMixin<SimplifyCFGPass> *>(this)->printPipeline( 347349cc55cSDimitry Andric OS, MapClassName2PassName); 34806c3fb27SDimitry Andric OS << '<'; 34906c3fb27SDimitry Andric OS << "bonus-inst-threshold=" << Options.BonusInstThreshold << ';'; 350349cc55cSDimitry Andric OS << (Options.ForwardSwitchCondToPhi ? "" : "no-") << "forward-switch-cond;"; 351fb03ea46SDimitry Andric OS << (Options.ConvertSwitchRangeToICmp ? "" : "no-") 352fb03ea46SDimitry Andric << "switch-range-to-icmp;"; 353349cc55cSDimitry Andric OS << (Options.ConvertSwitchToLookupTable ? "" : "no-") 354349cc55cSDimitry Andric << "switch-to-lookup;"; 355349cc55cSDimitry Andric OS << (Options.NeedCanonicalLoop ? "" : "no-") << "keep-loops;"; 356349cc55cSDimitry Andric OS << (Options.HoistCommonInsts ? "" : "no-") << "hoist-common-insts;"; 35706c3fb27SDimitry Andric OS << (Options.SinkCommonInsts ? "" : "no-") << "sink-common-insts;"; 35806c3fb27SDimitry Andric OS << (Options.SpeculateBlocks ? "" : "no-") << "speculate-blocks;"; 359*0fca6ea1SDimitry Andric OS << (Options.SimplifyCondBranch ? "" : "no-") << "simplify-cond-branch;"; 360*0fca6ea1SDimitry Andric OS << (Options.SpeculateUnpredictables ? "" : "no-") 361*0fca6ea1SDimitry Andric << "speculate-unpredictables"; 36206c3fb27SDimitry Andric OS << '>'; 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric 3650b57cec5SDimitry Andric PreservedAnalyses SimplifyCFGPass::run(Function &F, 3660b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 3670b57cec5SDimitry Andric auto &TTI = AM.getResult<TargetIRAnalysis>(F); 3680b57cec5SDimitry Andric Options.AC = &AM.getResult<AssumptionAnalysis>(F); 369e8d8bef9SDimitry Andric DominatorTree *DT = nullptr; 370e8d8bef9SDimitry Andric if (RequireAndPreserveDomTree) 371e8d8bef9SDimitry Andric DT = &AM.getResult<DominatorTreeAnalysis>(F); 372e8d8bef9SDimitry Andric if (!simplifyFunctionCFG(F, TTI, DT, Options)) 3730b57cec5SDimitry Andric return PreservedAnalyses::all(); 3740b57cec5SDimitry Andric PreservedAnalyses PA; 375e8d8bef9SDimitry Andric if (RequireAndPreserveDomTree) 376e8d8bef9SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 3770b57cec5SDimitry Andric return PA; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric namespace { 3810b57cec5SDimitry Andric struct CFGSimplifyPass : public FunctionPass { 3820b57cec5SDimitry Andric static char ID; 3830b57cec5SDimitry Andric SimplifyCFGOptions Options; 3840b57cec5SDimitry Andric std::function<bool(const Function &)> PredicateFtor; 3850b57cec5SDimitry Andric 386e8d8bef9SDimitry Andric CFGSimplifyPass(SimplifyCFGOptions Options_ = SimplifyCFGOptions(), 3870b57cec5SDimitry Andric std::function<bool(const Function &)> Ftor = nullptr) 388e8d8bef9SDimitry Andric : FunctionPass(ID), Options(Options_), PredicateFtor(std::move(Ftor)) { 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric initializeCFGSimplifyPassPass(*PassRegistry::getPassRegistry()); 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric // Check for command-line overrides of options for debug/customization. 393e8d8bef9SDimitry Andric applyCommandLineOverridesToOptions(Options); 3940b57cec5SDimitry Andric } 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric bool runOnFunction(Function &F) override { 3970b57cec5SDimitry Andric if (skipFunction(F) || (PredicateFtor && !PredicateFtor(F))) 3980b57cec5SDimitry Andric return false; 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric Options.AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F); 401e8d8bef9SDimitry Andric DominatorTree *DT = nullptr; 402e8d8bef9SDimitry Andric if (RequireAndPreserveDomTree) 403e8d8bef9SDimitry Andric DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 4045ffd83dbSDimitry Andric 4050b57cec5SDimitry Andric auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 406e8d8bef9SDimitry Andric return simplifyFunctionCFG(F, TTI, DT, Options); 4070b57cec5SDimitry Andric } 4080b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 4090b57cec5SDimitry Andric AU.addRequired<AssumptionCacheTracker>(); 410e8d8bef9SDimitry Andric if (RequireAndPreserveDomTree) 411e8d8bef9SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>(); 4120b57cec5SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 413e8d8bef9SDimitry Andric if (RequireAndPreserveDomTree) 414e8d8bef9SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 4150b57cec5SDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric }; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric char CFGSimplifyPass::ID = 0; 4210b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false, 4220b57cec5SDimitry Andric false) 4230b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 4240b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) 425e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 4260b57cec5SDimitry Andric INITIALIZE_PASS_END(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false, 4270b57cec5SDimitry Andric false) 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric // Public interface to the CFGSimplification pass 4300b57cec5SDimitry Andric FunctionPass * 431e8d8bef9SDimitry Andric llvm::createCFGSimplificationPass(SimplifyCFGOptions Options, 4320b57cec5SDimitry Andric std::function<bool(const Function &)> Ftor) { 433e8d8bef9SDimitry Andric return new CFGSimplifyPass(Options, std::move(Ftor)); 4340b57cec5SDimitry Andric } 435