1fe6060f1SDimitry Andric //===- DFAJumpThreading.cpp - Threads a switch statement inside a loop ----===// 2fe6060f1SDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // Transform each threading path to effectively jump thread the DFA. For 10fe6060f1SDimitry Andric // example, the CFG below could be transformed as follows, where the cloned 11fe6060f1SDimitry Andric // blocks unconditionally branch to the next correct case based on what is 12fe6060f1SDimitry Andric // identified in the analysis. 13fe6060f1SDimitry Andric // 14fe6060f1SDimitry Andric // sw.bb sw.bb 15fe6060f1SDimitry Andric // / | \ / | \ 16fe6060f1SDimitry Andric // case1 case2 case3 case1 case2 case3 17fe6060f1SDimitry Andric // \ | / | | | 18fe6060f1SDimitry Andric // determinator det.2 det.3 det.1 19fe6060f1SDimitry Andric // br sw.bb / | \ 20fe6060f1SDimitry Andric // sw.bb.2 sw.bb.3 sw.bb.1 21fe6060f1SDimitry Andric // br case2 br case3 br case1§ 22fe6060f1SDimitry Andric // 23fe6060f1SDimitry Andric // Definitions and Terminology: 24fe6060f1SDimitry Andric // 25fe6060f1SDimitry Andric // * Threading path: 26fe6060f1SDimitry Andric // a list of basic blocks, the exit state, and the block that determines 27fe6060f1SDimitry Andric // the next state, for which the following notation will be used: 28fe6060f1SDimitry Andric // < path of BBs that form a cycle > [ state, determinator ] 29fe6060f1SDimitry Andric // 30fe6060f1SDimitry Andric // * Predictable switch: 31fe6060f1SDimitry Andric // The switch variable is always a known constant so that all conditional 32fe6060f1SDimitry Andric // jumps based on switch variable can be converted to unconditional jump. 33fe6060f1SDimitry Andric // 34fe6060f1SDimitry Andric // * Determinator: 35fe6060f1SDimitry Andric // The basic block that determines the next state of the DFA. 36fe6060f1SDimitry Andric // 37fe6060f1SDimitry Andric // Representing the optimization in C-like pseudocode: the code pattern on the 38fe6060f1SDimitry Andric // left could functionally be transformed to the right pattern if the switch 39fe6060f1SDimitry Andric // condition is predictable. 40fe6060f1SDimitry Andric // 41fe6060f1SDimitry Andric // X = A goto A 42fe6060f1SDimitry Andric // for (...) A: 43fe6060f1SDimitry Andric // switch (X) ... 44fe6060f1SDimitry Andric // case A goto B 45fe6060f1SDimitry Andric // X = B B: 46fe6060f1SDimitry Andric // case B ... 47fe6060f1SDimitry Andric // X = C goto C 48fe6060f1SDimitry Andric // 49fe6060f1SDimitry Andric // The pass first checks that switch variable X is decided by the control flow 50fe6060f1SDimitry Andric // path taken in the loop; for example, in case B, the next value of X is 51fe6060f1SDimitry Andric // decided to be C. It then enumerates through all paths in the loop and labels 52fe6060f1SDimitry Andric // the basic blocks where the next state is decided. 53fe6060f1SDimitry Andric // 54fe6060f1SDimitry Andric // Using this information it creates new paths that unconditionally branch to 55fe6060f1SDimitry Andric // the next case. This involves cloning code, so it only gets triggered if the 56fe6060f1SDimitry Andric // amount of code duplicated is below a threshold. 57fe6060f1SDimitry Andric // 58fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 59fe6060f1SDimitry Andric 60fe6060f1SDimitry Andric #include "llvm/Transforms/Scalar/DFAJumpThreading.h" 61fe6060f1SDimitry Andric #include "llvm/ADT/APInt.h" 62fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h" 63fe6060f1SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 64fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h" 65fe6060f1SDimitry Andric #include "llvm/ADT/Statistic.h" 66fe6060f1SDimitry Andric #include "llvm/Analysis/AssumptionCache.h" 67fe6060f1SDimitry Andric #include "llvm/Analysis/CodeMetrics.h" 68fe6060f1SDimitry Andric #include "llvm/Analysis/LoopIterator.h" 69fe6060f1SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 70fe6060f1SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 71fe6060f1SDimitry Andric #include "llvm/IR/CFG.h" 72fe6060f1SDimitry Andric #include "llvm/IR/Constants.h" 73fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 74fe6060f1SDimitry Andric #include "llvm/IR/Verifier.h" 75fe6060f1SDimitry Andric #include "llvm/InitializePasses.h" 76fe6060f1SDimitry Andric #include "llvm/Pass.h" 77fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h" 78fe6060f1SDimitry Andric #include "llvm/Support/Debug.h" 79fe6060f1SDimitry Andric #include "llvm/Transforms/Scalar.h" 80fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 81fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 82fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/SSAUpdaterBulk.h" 83fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/ValueMapper.h" 84fe6060f1SDimitry Andric #include <algorithm> 85fe6060f1SDimitry Andric #include <deque> 86fe6060f1SDimitry Andric 87fe6060f1SDimitry Andric using namespace llvm; 88fe6060f1SDimitry Andric 89fe6060f1SDimitry Andric #define DEBUG_TYPE "dfa-jump-threading" 90fe6060f1SDimitry Andric 91fe6060f1SDimitry Andric STATISTIC(NumTransforms, "Number of transformations done"); 92fe6060f1SDimitry Andric STATISTIC(NumCloned, "Number of blocks cloned"); 93fe6060f1SDimitry Andric STATISTIC(NumPaths, "Number of individual paths threaded"); 94fe6060f1SDimitry Andric 95fe6060f1SDimitry Andric static cl::opt<bool> 96fe6060f1SDimitry Andric ClViewCfgBefore("dfa-jump-view-cfg-before", 97fe6060f1SDimitry Andric cl::desc("View the CFG before DFA Jump Threading"), 98fe6060f1SDimitry Andric cl::Hidden, cl::init(false)); 99fe6060f1SDimitry Andric 100fe6060f1SDimitry Andric static cl::opt<unsigned> MaxPathLength( 101fe6060f1SDimitry Andric "dfa-max-path-length", 102fe6060f1SDimitry Andric cl::desc("Max number of blocks searched to find a threading path"), 103fe6060f1SDimitry Andric cl::Hidden, cl::init(20)); 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric static cl::opt<unsigned> 106fe6060f1SDimitry Andric CostThreshold("dfa-cost-threshold", 107fe6060f1SDimitry Andric cl::desc("Maximum cost accepted for the transformation"), 108fe6060f1SDimitry Andric cl::Hidden, cl::init(50)); 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric namespace { 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric class SelectInstToUnfold { 113fe6060f1SDimitry Andric SelectInst *SI; 114fe6060f1SDimitry Andric PHINode *SIUse; 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric public: 117fe6060f1SDimitry Andric SelectInstToUnfold(SelectInst *SI, PHINode *SIUse) : SI(SI), SIUse(SIUse) {} 118fe6060f1SDimitry Andric 119fe6060f1SDimitry Andric SelectInst *getInst() { return SI; } 120fe6060f1SDimitry Andric PHINode *getUse() { return SIUse; } 121fe6060f1SDimitry Andric 122fe6060f1SDimitry Andric explicit operator bool() const { return SI && SIUse; } 123fe6060f1SDimitry Andric }; 124fe6060f1SDimitry Andric 125fe6060f1SDimitry Andric void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold, 126fe6060f1SDimitry Andric std::vector<SelectInstToUnfold> *NewSIsToUnfold, 127fe6060f1SDimitry Andric std::vector<BasicBlock *> *NewBBs); 128fe6060f1SDimitry Andric 129fe6060f1SDimitry Andric class DFAJumpThreading { 130fe6060f1SDimitry Andric public: 131fe6060f1SDimitry Andric DFAJumpThreading(AssumptionCache *AC, DominatorTree *DT, 132fe6060f1SDimitry Andric TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE) 133fe6060f1SDimitry Andric : AC(AC), DT(DT), TTI(TTI), ORE(ORE) {} 134fe6060f1SDimitry Andric 135fe6060f1SDimitry Andric bool run(Function &F); 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric private: 138fe6060f1SDimitry Andric void 139fe6060f1SDimitry Andric unfoldSelectInstrs(DominatorTree *DT, 140fe6060f1SDimitry Andric const SmallVector<SelectInstToUnfold, 4> &SelectInsts) { 141fe6060f1SDimitry Andric DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); 142fe6060f1SDimitry Andric SmallVector<SelectInstToUnfold, 4> Stack; 143fe6060f1SDimitry Andric for (SelectInstToUnfold SIToUnfold : SelectInsts) 144fe6060f1SDimitry Andric Stack.push_back(SIToUnfold); 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric while (!Stack.empty()) { 147349cc55cSDimitry Andric SelectInstToUnfold SIToUnfold = Stack.pop_back_val(); 148fe6060f1SDimitry Andric 149fe6060f1SDimitry Andric std::vector<SelectInstToUnfold> NewSIsToUnfold; 150fe6060f1SDimitry Andric std::vector<BasicBlock *> NewBBs; 151fe6060f1SDimitry Andric unfold(&DTU, SIToUnfold, &NewSIsToUnfold, &NewBBs); 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric // Put newly discovered select instructions into the work list. 154fe6060f1SDimitry Andric for (const SelectInstToUnfold &NewSIToUnfold : NewSIsToUnfold) 155fe6060f1SDimitry Andric Stack.push_back(NewSIToUnfold); 156fe6060f1SDimitry Andric } 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric AssumptionCache *AC; 160fe6060f1SDimitry Andric DominatorTree *DT; 161fe6060f1SDimitry Andric TargetTransformInfo *TTI; 162fe6060f1SDimitry Andric OptimizationRemarkEmitter *ORE; 163fe6060f1SDimitry Andric }; 164fe6060f1SDimitry Andric 165fe6060f1SDimitry Andric class DFAJumpThreadingLegacyPass : public FunctionPass { 166fe6060f1SDimitry Andric public: 167fe6060f1SDimitry Andric static char ID; // Pass identification 168fe6060f1SDimitry Andric DFAJumpThreadingLegacyPass() : FunctionPass(ID) {} 169fe6060f1SDimitry Andric 170fe6060f1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 171fe6060f1SDimitry Andric AU.addRequired<AssumptionCacheTracker>(); 172fe6060f1SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>(); 173349cc55cSDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 174fe6060f1SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 175fe6060f1SDimitry Andric AU.addRequired<OptimizationRemarkEmitterWrapperPass>(); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 178fe6060f1SDimitry Andric bool runOnFunction(Function &F) override { 179fe6060f1SDimitry Andric if (skipFunction(F)) 180fe6060f1SDimitry Andric return false; 181fe6060f1SDimitry Andric 182fe6060f1SDimitry Andric AssumptionCache *AC = 183fe6060f1SDimitry Andric &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F); 184fe6060f1SDimitry Andric DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 185fe6060f1SDimitry Andric TargetTransformInfo *TTI = 186fe6060f1SDimitry Andric &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 187fe6060f1SDimitry Andric OptimizationRemarkEmitter *ORE = 188fe6060f1SDimitry Andric &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(); 189fe6060f1SDimitry Andric 190fe6060f1SDimitry Andric return DFAJumpThreading(AC, DT, TTI, ORE).run(F); 191fe6060f1SDimitry Andric } 192fe6060f1SDimitry Andric }; 193fe6060f1SDimitry Andric } // end anonymous namespace 194fe6060f1SDimitry Andric 195fe6060f1SDimitry Andric char DFAJumpThreadingLegacyPass::ID = 0; 196fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(DFAJumpThreadingLegacyPass, "dfa-jump-threading", 197fe6060f1SDimitry Andric "DFA Jump Threading", false, false) 198fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) 199fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 200fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 201fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) 202fe6060f1SDimitry Andric INITIALIZE_PASS_END(DFAJumpThreadingLegacyPass, "dfa-jump-threading", 203fe6060f1SDimitry Andric "DFA Jump Threading", false, false) 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric // Public interface to the DFA Jump Threading pass 206fe6060f1SDimitry Andric FunctionPass *llvm::createDFAJumpThreadingPass() { 207fe6060f1SDimitry Andric return new DFAJumpThreadingLegacyPass(); 208fe6060f1SDimitry Andric } 209fe6060f1SDimitry Andric 210fe6060f1SDimitry Andric namespace { 211fe6060f1SDimitry Andric 212fe6060f1SDimitry Andric /// Create a new basic block and sink \p SIToSink into it. 213fe6060f1SDimitry Andric void createBasicBlockAndSinkSelectInst( 214fe6060f1SDimitry Andric DomTreeUpdater *DTU, SelectInst *SI, PHINode *SIUse, SelectInst *SIToSink, 215fe6060f1SDimitry Andric BasicBlock *EndBlock, StringRef NewBBName, BasicBlock **NewBlock, 216fe6060f1SDimitry Andric BranchInst **NewBranch, std::vector<SelectInstToUnfold> *NewSIsToUnfold, 217fe6060f1SDimitry Andric std::vector<BasicBlock *> *NewBBs) { 218fe6060f1SDimitry Andric assert(SIToSink->hasOneUse()); 219fe6060f1SDimitry Andric assert(NewBlock); 220fe6060f1SDimitry Andric assert(NewBranch); 221fe6060f1SDimitry Andric *NewBlock = BasicBlock::Create(SI->getContext(), NewBBName, 222fe6060f1SDimitry Andric EndBlock->getParent(), EndBlock); 223fe6060f1SDimitry Andric NewBBs->push_back(*NewBlock); 224fe6060f1SDimitry Andric *NewBranch = BranchInst::Create(EndBlock, *NewBlock); 225fe6060f1SDimitry Andric SIToSink->moveBefore(*NewBranch); 226fe6060f1SDimitry Andric NewSIsToUnfold->push_back(SelectInstToUnfold(SIToSink, SIUse)); 227fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Insert, *NewBlock, EndBlock}}); 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric /// Unfold the select instruction held in \p SIToUnfold by replacing it with 231fe6060f1SDimitry Andric /// control flow. 232fe6060f1SDimitry Andric /// 233fe6060f1SDimitry Andric /// Put newly discovered select instructions into \p NewSIsToUnfold. Put newly 234fe6060f1SDimitry Andric /// created basic blocks into \p NewBBs. 235fe6060f1SDimitry Andric /// 236fe6060f1SDimitry Andric /// TODO: merge it with CodeGenPrepare::optimizeSelectInst() if possible. 237fe6060f1SDimitry Andric void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold, 238fe6060f1SDimitry Andric std::vector<SelectInstToUnfold> *NewSIsToUnfold, 239fe6060f1SDimitry Andric std::vector<BasicBlock *> *NewBBs) { 240fe6060f1SDimitry Andric SelectInst *SI = SIToUnfold.getInst(); 241fe6060f1SDimitry Andric PHINode *SIUse = SIToUnfold.getUse(); 242fe6060f1SDimitry Andric BasicBlock *StartBlock = SI->getParent(); 243fe6060f1SDimitry Andric BasicBlock *EndBlock = SIUse->getParent(); 244fe6060f1SDimitry Andric BranchInst *StartBlockTerm = 245fe6060f1SDimitry Andric dyn_cast<BranchInst>(StartBlock->getTerminator()); 246fe6060f1SDimitry Andric 247fe6060f1SDimitry Andric assert(StartBlockTerm && StartBlockTerm->isUnconditional()); 248fe6060f1SDimitry Andric assert(SI->hasOneUse()); 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric // These are the new basic blocks for the conditional branch. 251fe6060f1SDimitry Andric // At least one will become an actual new basic block. 252fe6060f1SDimitry Andric BasicBlock *TrueBlock = nullptr; 253fe6060f1SDimitry Andric BasicBlock *FalseBlock = nullptr; 254fe6060f1SDimitry Andric BranchInst *TrueBranch = nullptr; 255fe6060f1SDimitry Andric BranchInst *FalseBranch = nullptr; 256fe6060f1SDimitry Andric 257fe6060f1SDimitry Andric // Sink select instructions to be able to unfold them later. 258fe6060f1SDimitry Andric if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getTrueValue())) { 259fe6060f1SDimitry Andric createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock, 260fe6060f1SDimitry Andric "si.unfold.true", &TrueBlock, &TrueBranch, 261fe6060f1SDimitry Andric NewSIsToUnfold, NewBBs); 262fe6060f1SDimitry Andric } 263fe6060f1SDimitry Andric if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getFalseValue())) { 264fe6060f1SDimitry Andric createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock, 265fe6060f1SDimitry Andric "si.unfold.false", &FalseBlock, 266fe6060f1SDimitry Andric &FalseBranch, NewSIsToUnfold, NewBBs); 267fe6060f1SDimitry Andric } 268fe6060f1SDimitry Andric 269fe6060f1SDimitry Andric // If there was nothing to sink, then arbitrarily choose the 'false' side 270fe6060f1SDimitry Andric // for a new input value to the PHI. 271fe6060f1SDimitry Andric if (!TrueBlock && !FalseBlock) { 272fe6060f1SDimitry Andric FalseBlock = BasicBlock::Create(SI->getContext(), "si.unfold.false", 273fe6060f1SDimitry Andric EndBlock->getParent(), EndBlock); 274fe6060f1SDimitry Andric NewBBs->push_back(FalseBlock); 275fe6060f1SDimitry Andric BranchInst::Create(EndBlock, FalseBlock); 276fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Insert, FalseBlock, EndBlock}}); 277fe6060f1SDimitry Andric } 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric // Insert the real conditional branch based on the original condition. 280fe6060f1SDimitry Andric // If we did not create a new block for one of the 'true' or 'false' paths 281fe6060f1SDimitry Andric // of the condition, it means that side of the branch goes to the end block 282fe6060f1SDimitry Andric // directly and the path originates from the start block from the point of 283fe6060f1SDimitry Andric // view of the new PHI. 284fe6060f1SDimitry Andric BasicBlock *TT = EndBlock; 285fe6060f1SDimitry Andric BasicBlock *FT = EndBlock; 286fe6060f1SDimitry Andric if (TrueBlock && FalseBlock) { 287fe6060f1SDimitry Andric // A diamond. 288fe6060f1SDimitry Andric TT = TrueBlock; 289fe6060f1SDimitry Andric FT = FalseBlock; 290fe6060f1SDimitry Andric 291fe6060f1SDimitry Andric // Update the phi node of SI. 292fe6060f1SDimitry Andric SIUse->removeIncomingValue(StartBlock, /* DeletePHIIfEmpty = */ false); 293fe6060f1SDimitry Andric SIUse->addIncoming(SI->getTrueValue(), TrueBlock); 294fe6060f1SDimitry Andric SIUse->addIncoming(SI->getFalseValue(), FalseBlock); 295fe6060f1SDimitry Andric 296fe6060f1SDimitry Andric // Update any other PHI nodes in EndBlock. 297fe6060f1SDimitry Andric for (PHINode &Phi : EndBlock->phis()) { 298fe6060f1SDimitry Andric if (&Phi != SIUse) { 299fe6060f1SDimitry Andric Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), TrueBlock); 300fe6060f1SDimitry Andric Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), FalseBlock); 301fe6060f1SDimitry Andric } 302fe6060f1SDimitry Andric } 303fe6060f1SDimitry Andric } else { 304fe6060f1SDimitry Andric BasicBlock *NewBlock = nullptr; 305fe6060f1SDimitry Andric Value *SIOp1 = SI->getTrueValue(); 306fe6060f1SDimitry Andric Value *SIOp2 = SI->getFalseValue(); 307fe6060f1SDimitry Andric 308fe6060f1SDimitry Andric // A triangle pointing right. 309fe6060f1SDimitry Andric if (!TrueBlock) { 310fe6060f1SDimitry Andric NewBlock = FalseBlock; 311fe6060f1SDimitry Andric FT = FalseBlock; 312fe6060f1SDimitry Andric } 313fe6060f1SDimitry Andric // A triangle pointing left. 314fe6060f1SDimitry Andric else { 315fe6060f1SDimitry Andric NewBlock = TrueBlock; 316fe6060f1SDimitry Andric TT = TrueBlock; 317fe6060f1SDimitry Andric std::swap(SIOp1, SIOp2); 318fe6060f1SDimitry Andric } 319fe6060f1SDimitry Andric 320fe6060f1SDimitry Andric // Update the phi node of SI. 321fe6060f1SDimitry Andric for (unsigned Idx = 0; Idx < SIUse->getNumIncomingValues(); ++Idx) { 322fe6060f1SDimitry Andric if (SIUse->getIncomingBlock(Idx) == StartBlock) 323fe6060f1SDimitry Andric SIUse->setIncomingValue(Idx, SIOp1); 324fe6060f1SDimitry Andric } 325fe6060f1SDimitry Andric SIUse->addIncoming(SIOp2, NewBlock); 326fe6060f1SDimitry Andric 327fe6060f1SDimitry Andric // Update any other PHI nodes in EndBlock. 328fe6060f1SDimitry Andric for (auto II = EndBlock->begin(); PHINode *Phi = dyn_cast<PHINode>(II); 329fe6060f1SDimitry Andric ++II) { 330fe6060f1SDimitry Andric if (Phi != SIUse) 331fe6060f1SDimitry Andric Phi->addIncoming(Phi->getIncomingValueForBlock(StartBlock), NewBlock); 332fe6060f1SDimitry Andric } 333fe6060f1SDimitry Andric } 334fe6060f1SDimitry Andric StartBlockTerm->eraseFromParent(); 335fe6060f1SDimitry Andric BranchInst::Create(TT, FT, SI->getCondition(), StartBlock); 336fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Insert, StartBlock, TT}, 337fe6060f1SDimitry Andric {DominatorTree::Insert, StartBlock, FT}}); 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric // The select is now dead. 340fe6060f1SDimitry Andric SI->eraseFromParent(); 341fe6060f1SDimitry Andric } 342fe6060f1SDimitry Andric 343fe6060f1SDimitry Andric struct ClonedBlock { 344fe6060f1SDimitry Andric BasicBlock *BB; 345fe6060f1SDimitry Andric uint64_t State; ///< \p State corresponds to the next value of a switch stmnt. 346fe6060f1SDimitry Andric }; 347fe6060f1SDimitry Andric 348fe6060f1SDimitry Andric typedef std::deque<BasicBlock *> PathType; 349fe6060f1SDimitry Andric typedef std::vector<PathType> PathsType; 350349cc55cSDimitry Andric typedef SmallPtrSet<const BasicBlock *, 8> VisitedBlocks; 351fe6060f1SDimitry Andric typedef std::vector<ClonedBlock> CloneList; 352fe6060f1SDimitry Andric 353fe6060f1SDimitry Andric // This data structure keeps track of all blocks that have been cloned. If two 354fe6060f1SDimitry Andric // different ThreadingPaths clone the same block for a certain state it should 355fe6060f1SDimitry Andric // be reused, and it can be looked up in this map. 356fe6060f1SDimitry Andric typedef DenseMap<BasicBlock *, CloneList> DuplicateBlockMap; 357fe6060f1SDimitry Andric 358fe6060f1SDimitry Andric // This map keeps track of all the new definitions for an instruction. This 359fe6060f1SDimitry Andric // information is needed when restoring SSA form after cloning blocks. 360fe6060f1SDimitry Andric typedef DenseMap<Instruction *, std::vector<Instruction *>> DefMap; 361fe6060f1SDimitry Andric 362fe6060f1SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const PathType &Path) { 363fe6060f1SDimitry Andric OS << "< "; 364fe6060f1SDimitry Andric for (const BasicBlock *BB : Path) { 365fe6060f1SDimitry Andric std::string BBName; 366fe6060f1SDimitry Andric if (BB->hasName()) 367fe6060f1SDimitry Andric raw_string_ostream(BBName) << BB->getName(); 368fe6060f1SDimitry Andric else 369fe6060f1SDimitry Andric raw_string_ostream(BBName) << BB; 370fe6060f1SDimitry Andric OS << BBName << " "; 371fe6060f1SDimitry Andric } 372fe6060f1SDimitry Andric OS << ">"; 373fe6060f1SDimitry Andric return OS; 374fe6060f1SDimitry Andric } 375fe6060f1SDimitry Andric 376fe6060f1SDimitry Andric /// ThreadingPath is a path in the control flow of a loop that can be threaded 377fe6060f1SDimitry Andric /// by cloning necessary basic blocks and replacing conditional branches with 378fe6060f1SDimitry Andric /// unconditional ones. A threading path includes a list of basic blocks, the 379fe6060f1SDimitry Andric /// exit state, and the block that determines the next state. 380fe6060f1SDimitry Andric struct ThreadingPath { 381fe6060f1SDimitry Andric /// Exit value is DFA's exit state for the given path. 382fe6060f1SDimitry Andric uint64_t getExitValue() const { return ExitVal; } 383fe6060f1SDimitry Andric void setExitValue(const ConstantInt *V) { 384fe6060f1SDimitry Andric ExitVal = V->getZExtValue(); 385fe6060f1SDimitry Andric IsExitValSet = true; 386fe6060f1SDimitry Andric } 387fe6060f1SDimitry Andric bool isExitValueSet() const { return IsExitValSet; } 388fe6060f1SDimitry Andric 389fe6060f1SDimitry Andric /// Determinator is the basic block that determines the next state of the DFA. 390fe6060f1SDimitry Andric const BasicBlock *getDeterminatorBB() const { return DBB; } 391fe6060f1SDimitry Andric void setDeterminator(const BasicBlock *BB) { DBB = BB; } 392fe6060f1SDimitry Andric 393fe6060f1SDimitry Andric /// Path is a list of basic blocks. 394fe6060f1SDimitry Andric const PathType &getPath() const { return Path; } 395fe6060f1SDimitry Andric void setPath(const PathType &NewPath) { Path = NewPath; } 396fe6060f1SDimitry Andric 397fe6060f1SDimitry Andric void print(raw_ostream &OS) const { 398fe6060f1SDimitry Andric OS << Path << " [ " << ExitVal << ", " << DBB->getName() << " ]"; 399fe6060f1SDimitry Andric } 400fe6060f1SDimitry Andric 401fe6060f1SDimitry Andric private: 402fe6060f1SDimitry Andric PathType Path; 403fe6060f1SDimitry Andric uint64_t ExitVal; 404fe6060f1SDimitry Andric const BasicBlock *DBB = nullptr; 405fe6060f1SDimitry Andric bool IsExitValSet = false; 406fe6060f1SDimitry Andric }; 407fe6060f1SDimitry Andric 408fe6060f1SDimitry Andric #ifndef NDEBUG 409fe6060f1SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const ThreadingPath &TPath) { 410fe6060f1SDimitry Andric TPath.print(OS); 411fe6060f1SDimitry Andric return OS; 412fe6060f1SDimitry Andric } 413fe6060f1SDimitry Andric #endif 414fe6060f1SDimitry Andric 415fe6060f1SDimitry Andric struct MainSwitch { 416fe6060f1SDimitry Andric MainSwitch(SwitchInst *SI, OptimizationRemarkEmitter *ORE) { 417fe6060f1SDimitry Andric if (isPredictable(SI)) { 418fe6060f1SDimitry Andric Instr = SI; 419fe6060f1SDimitry Andric } else { 420fe6060f1SDimitry Andric ORE->emit([&]() { 421fe6060f1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable", SI) 422fe6060f1SDimitry Andric << "Switch instruction is not predictable."; 423fe6060f1SDimitry Andric }); 424fe6060f1SDimitry Andric } 425fe6060f1SDimitry Andric } 426fe6060f1SDimitry Andric 427fe6060f1SDimitry Andric virtual ~MainSwitch() = default; 428fe6060f1SDimitry Andric 429fe6060f1SDimitry Andric SwitchInst *getInstr() const { return Instr; } 430fe6060f1SDimitry Andric const SmallVector<SelectInstToUnfold, 4> getSelectInsts() { 431fe6060f1SDimitry Andric return SelectInsts; 432fe6060f1SDimitry Andric } 433fe6060f1SDimitry Andric 434fe6060f1SDimitry Andric private: 435fe6060f1SDimitry Andric /// Do a use-def chain traversal. Make sure the value of the switch variable 436fe6060f1SDimitry Andric /// is always a known constant. This means that all conditional jumps based on 437fe6060f1SDimitry Andric /// switch variable can be converted to unconditional jumps. 438fe6060f1SDimitry Andric bool isPredictable(const SwitchInst *SI) { 439fe6060f1SDimitry Andric std::deque<Instruction *> Q; 440fe6060f1SDimitry Andric SmallSet<Value *, 16> SeenValues; 441fe6060f1SDimitry Andric SelectInsts.clear(); 442fe6060f1SDimitry Andric 443fe6060f1SDimitry Andric Value *FirstDef = SI->getOperand(0); 444fe6060f1SDimitry Andric auto *Inst = dyn_cast<Instruction>(FirstDef); 445fe6060f1SDimitry Andric 446fe6060f1SDimitry Andric // If this is a function argument or another non-instruction, then give up. 447fe6060f1SDimitry Andric // We are interested in loop local variables. 448fe6060f1SDimitry Andric if (!Inst) 449fe6060f1SDimitry Andric return false; 450fe6060f1SDimitry Andric 451fe6060f1SDimitry Andric // Require the first definition to be a PHINode 452fe6060f1SDimitry Andric if (!isa<PHINode>(Inst)) 453fe6060f1SDimitry Andric return false; 454fe6060f1SDimitry Andric 455fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\tisPredictable() FirstDef: " << *Inst << "\n"); 456fe6060f1SDimitry Andric 457fe6060f1SDimitry Andric Q.push_back(Inst); 458fe6060f1SDimitry Andric SeenValues.insert(FirstDef); 459fe6060f1SDimitry Andric 460fe6060f1SDimitry Andric while (!Q.empty()) { 461fe6060f1SDimitry Andric Instruction *Current = Q.front(); 462fe6060f1SDimitry Andric Q.pop_front(); 463fe6060f1SDimitry Andric 464fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(Current)) { 465fe6060f1SDimitry Andric for (Value *Incoming : Phi->incoming_values()) { 466fe6060f1SDimitry Andric if (!isPredictableValue(Incoming, SeenValues)) 467fe6060f1SDimitry Andric return false; 468fe6060f1SDimitry Andric addInstToQueue(Incoming, Q, SeenValues); 469fe6060f1SDimitry Andric } 470fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\tisPredictable() phi: " << *Phi << "\n"); 471fe6060f1SDimitry Andric } else if (SelectInst *SelI = dyn_cast<SelectInst>(Current)) { 472fe6060f1SDimitry Andric if (!isValidSelectInst(SelI)) 473fe6060f1SDimitry Andric return false; 474fe6060f1SDimitry Andric if (!isPredictableValue(SelI->getTrueValue(), SeenValues) || 475fe6060f1SDimitry Andric !isPredictableValue(SelI->getFalseValue(), SeenValues)) { 476fe6060f1SDimitry Andric return false; 477fe6060f1SDimitry Andric } 478fe6060f1SDimitry Andric addInstToQueue(SelI->getTrueValue(), Q, SeenValues); 479fe6060f1SDimitry Andric addInstToQueue(SelI->getFalseValue(), Q, SeenValues); 480fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\tisPredictable() select: " << *SelI << "\n"); 481fe6060f1SDimitry Andric if (auto *SelIUse = dyn_cast<PHINode>(SelI->user_back())) 482fe6060f1SDimitry Andric SelectInsts.push_back(SelectInstToUnfold(SelI, SelIUse)); 483fe6060f1SDimitry Andric } else { 484fe6060f1SDimitry Andric // If it is neither a phi nor a select, then we give up. 485fe6060f1SDimitry Andric return false; 486fe6060f1SDimitry Andric } 487fe6060f1SDimitry Andric } 488fe6060f1SDimitry Andric 489fe6060f1SDimitry Andric return true; 490fe6060f1SDimitry Andric } 491fe6060f1SDimitry Andric 492fe6060f1SDimitry Andric bool isPredictableValue(Value *InpVal, SmallSet<Value *, 16> &SeenValues) { 493349cc55cSDimitry Andric if (SeenValues.contains(InpVal)) 494fe6060f1SDimitry Andric return true; 495fe6060f1SDimitry Andric 496fe6060f1SDimitry Andric if (isa<ConstantInt>(InpVal)) 497fe6060f1SDimitry Andric return true; 498fe6060f1SDimitry Andric 499fe6060f1SDimitry Andric // If this is a function argument or another non-instruction, then give up. 500fe6060f1SDimitry Andric if (!isa<Instruction>(InpVal)) 501fe6060f1SDimitry Andric return false; 502fe6060f1SDimitry Andric 503fe6060f1SDimitry Andric return true; 504fe6060f1SDimitry Andric } 505fe6060f1SDimitry Andric 506fe6060f1SDimitry Andric void addInstToQueue(Value *Val, std::deque<Instruction *> &Q, 507fe6060f1SDimitry Andric SmallSet<Value *, 16> &SeenValues) { 508349cc55cSDimitry Andric if (SeenValues.contains(Val)) 509fe6060f1SDimitry Andric return; 510fe6060f1SDimitry Andric if (Instruction *I = dyn_cast<Instruction>(Val)) 511fe6060f1SDimitry Andric Q.push_back(I); 512fe6060f1SDimitry Andric SeenValues.insert(Val); 513fe6060f1SDimitry Andric } 514fe6060f1SDimitry Andric 515fe6060f1SDimitry Andric bool isValidSelectInst(SelectInst *SI) { 516fe6060f1SDimitry Andric if (!SI->hasOneUse()) 517fe6060f1SDimitry Andric return false; 518fe6060f1SDimitry Andric 519fe6060f1SDimitry Andric Instruction *SIUse = dyn_cast<Instruction>(SI->user_back()); 520fe6060f1SDimitry Andric // The use of the select inst should be either a phi or another select. 521fe6060f1SDimitry Andric if (!SIUse && !(isa<PHINode>(SIUse) || isa<SelectInst>(SIUse))) 522fe6060f1SDimitry Andric return false; 523fe6060f1SDimitry Andric 524fe6060f1SDimitry Andric BasicBlock *SIBB = SI->getParent(); 525fe6060f1SDimitry Andric 526fe6060f1SDimitry Andric // Currently, we can only expand select instructions in basic blocks with 527fe6060f1SDimitry Andric // one successor. 528fe6060f1SDimitry Andric BranchInst *SITerm = dyn_cast<BranchInst>(SIBB->getTerminator()); 529fe6060f1SDimitry Andric if (!SITerm || !SITerm->isUnconditional()) 530fe6060f1SDimitry Andric return false; 531fe6060f1SDimitry Andric 532fe6060f1SDimitry Andric if (isa<PHINode>(SIUse) && 533349cc55cSDimitry Andric SIBB->getSingleSuccessor() != cast<Instruction>(SIUse)->getParent()) 534fe6060f1SDimitry Andric return false; 535fe6060f1SDimitry Andric 536fe6060f1SDimitry Andric // If select will not be sunk during unfolding, and it is in the same basic 537fe6060f1SDimitry Andric // block as another state defining select, then cannot unfold both. 538fe6060f1SDimitry Andric for (SelectInstToUnfold SIToUnfold : SelectInsts) { 539fe6060f1SDimitry Andric SelectInst *PrevSI = SIToUnfold.getInst(); 540fe6060f1SDimitry Andric if (PrevSI->getTrueValue() != SI && PrevSI->getFalseValue() != SI && 541fe6060f1SDimitry Andric PrevSI->getParent() == SI->getParent()) 542fe6060f1SDimitry Andric return false; 543fe6060f1SDimitry Andric } 544fe6060f1SDimitry Andric 545fe6060f1SDimitry Andric return true; 546fe6060f1SDimitry Andric } 547fe6060f1SDimitry Andric 548fe6060f1SDimitry Andric SwitchInst *Instr = nullptr; 549fe6060f1SDimitry Andric SmallVector<SelectInstToUnfold, 4> SelectInsts; 550fe6060f1SDimitry Andric }; 551fe6060f1SDimitry Andric 552fe6060f1SDimitry Andric struct AllSwitchPaths { 553fe6060f1SDimitry Andric AllSwitchPaths(const MainSwitch *MSwitch, OptimizationRemarkEmitter *ORE) 554fe6060f1SDimitry Andric : Switch(MSwitch->getInstr()), SwitchBlock(Switch->getParent()), 555fe6060f1SDimitry Andric ORE(ORE) {} 556fe6060f1SDimitry Andric 557fe6060f1SDimitry Andric std::vector<ThreadingPath> &getThreadingPaths() { return TPaths; } 558fe6060f1SDimitry Andric unsigned getNumThreadingPaths() { return TPaths.size(); } 559fe6060f1SDimitry Andric SwitchInst *getSwitchInst() { return Switch; } 560fe6060f1SDimitry Andric BasicBlock *getSwitchBlock() { return SwitchBlock; } 561fe6060f1SDimitry Andric 562fe6060f1SDimitry Andric void run() { 563fe6060f1SDimitry Andric VisitedBlocks Visited; 564fe6060f1SDimitry Andric PathsType LoopPaths = paths(SwitchBlock, Visited, /* PathDepth = */ 1); 565fe6060f1SDimitry Andric StateDefMap StateDef = getStateDefMap(); 566fe6060f1SDimitry Andric 567fe6060f1SDimitry Andric for (PathType Path : LoopPaths) { 568fe6060f1SDimitry Andric ThreadingPath TPath; 569fe6060f1SDimitry Andric 570fe6060f1SDimitry Andric const BasicBlock *PrevBB = Path.back(); 571fe6060f1SDimitry Andric for (const BasicBlock *BB : Path) { 572fe6060f1SDimitry Andric if (StateDef.count(BB) != 0) { 573fe6060f1SDimitry Andric const PHINode *Phi = dyn_cast<PHINode>(StateDef[BB]); 574fe6060f1SDimitry Andric assert(Phi && "Expected a state-defining instr to be a phi node."); 575fe6060f1SDimitry Andric 576fe6060f1SDimitry Andric const Value *V = Phi->getIncomingValueForBlock(PrevBB); 577fe6060f1SDimitry Andric if (const ConstantInt *C = dyn_cast<const ConstantInt>(V)) { 578fe6060f1SDimitry Andric TPath.setExitValue(C); 579fe6060f1SDimitry Andric TPath.setDeterminator(BB); 580fe6060f1SDimitry Andric TPath.setPath(Path); 581fe6060f1SDimitry Andric } 582fe6060f1SDimitry Andric } 583fe6060f1SDimitry Andric 584fe6060f1SDimitry Andric // Switch block is the determinator, this is the final exit value. 585fe6060f1SDimitry Andric if (TPath.isExitValueSet() && BB == Path.front()) 586fe6060f1SDimitry Andric break; 587fe6060f1SDimitry Andric 588fe6060f1SDimitry Andric PrevBB = BB; 589fe6060f1SDimitry Andric } 590fe6060f1SDimitry Andric 591*0eae32dcSDimitry Andric if (TPath.isExitValueSet() && isSupported(TPath)) 592fe6060f1SDimitry Andric TPaths.push_back(TPath); 593fe6060f1SDimitry Andric } 594fe6060f1SDimitry Andric } 595fe6060f1SDimitry Andric 596fe6060f1SDimitry Andric private: 597fe6060f1SDimitry Andric // Value: an instruction that defines a switch state; 598fe6060f1SDimitry Andric // Key: the parent basic block of that instruction. 599fe6060f1SDimitry Andric typedef DenseMap<const BasicBlock *, const PHINode *> StateDefMap; 600fe6060f1SDimitry Andric 601fe6060f1SDimitry Andric PathsType paths(BasicBlock *BB, VisitedBlocks &Visited, 602fe6060f1SDimitry Andric unsigned PathDepth) const { 603fe6060f1SDimitry Andric PathsType Res; 604fe6060f1SDimitry Andric 605fe6060f1SDimitry Andric // Stop exploring paths after visiting MaxPathLength blocks 606fe6060f1SDimitry Andric if (PathDepth > MaxPathLength) { 607fe6060f1SDimitry Andric ORE->emit([&]() { 608fe6060f1SDimitry Andric return OptimizationRemarkAnalysis(DEBUG_TYPE, "MaxPathLengthReached", 609fe6060f1SDimitry Andric Switch) 610fe6060f1SDimitry Andric << "Exploration stopped after visiting MaxPathLength=" 611fe6060f1SDimitry Andric << ore::NV("MaxPathLength", MaxPathLength) << " blocks."; 612fe6060f1SDimitry Andric }); 613fe6060f1SDimitry Andric return Res; 614fe6060f1SDimitry Andric } 615fe6060f1SDimitry Andric 616fe6060f1SDimitry Andric Visited.insert(BB); 617fe6060f1SDimitry Andric 618fe6060f1SDimitry Andric // Some blocks have multiple edges to the same successor, and this set 619fe6060f1SDimitry Andric // is used to prevent a duplicate path from being generated 620fe6060f1SDimitry Andric SmallSet<BasicBlock *, 4> Successors; 621349cc55cSDimitry Andric for (BasicBlock *Succ : successors(BB)) { 622349cc55cSDimitry Andric if (!Successors.insert(Succ).second) 623fe6060f1SDimitry Andric continue; 624fe6060f1SDimitry Andric 625fe6060f1SDimitry Andric // Found a cycle through the SwitchBlock 626fe6060f1SDimitry Andric if (Succ == SwitchBlock) { 627fe6060f1SDimitry Andric Res.push_back({BB}); 628fe6060f1SDimitry Andric continue; 629fe6060f1SDimitry Andric } 630fe6060f1SDimitry Andric 631fe6060f1SDimitry Andric // We have encountered a cycle, do not get caught in it 632349cc55cSDimitry Andric if (Visited.contains(Succ)) 633fe6060f1SDimitry Andric continue; 634fe6060f1SDimitry Andric 635fe6060f1SDimitry Andric PathsType SuccPaths = paths(Succ, Visited, PathDepth + 1); 636fe6060f1SDimitry Andric for (PathType Path : SuccPaths) { 637fe6060f1SDimitry Andric PathType NewPath(Path); 638fe6060f1SDimitry Andric NewPath.push_front(BB); 639fe6060f1SDimitry Andric Res.push_back(NewPath); 640fe6060f1SDimitry Andric } 641fe6060f1SDimitry Andric } 642fe6060f1SDimitry Andric // This block could now be visited again from a different predecessor. Note 643fe6060f1SDimitry Andric // that this will result in exponential runtime. Subpaths could possibly be 644fe6060f1SDimitry Andric // cached but it takes a lot of memory to store them. 645fe6060f1SDimitry Andric Visited.erase(BB); 646fe6060f1SDimitry Andric return Res; 647fe6060f1SDimitry Andric } 648fe6060f1SDimitry Andric 649fe6060f1SDimitry Andric /// Walk the use-def chain and collect all the state-defining instructions. 650fe6060f1SDimitry Andric StateDefMap getStateDefMap() const { 651fe6060f1SDimitry Andric StateDefMap Res; 652fe6060f1SDimitry Andric 653fe6060f1SDimitry Andric Value *FirstDef = Switch->getOperand(0); 654fe6060f1SDimitry Andric 655fe6060f1SDimitry Andric assert(isa<PHINode>(FirstDef) && "After select unfolding, all state " 656fe6060f1SDimitry Andric "definitions are expected to be phi " 657fe6060f1SDimitry Andric "nodes."); 658fe6060f1SDimitry Andric 659fe6060f1SDimitry Andric SmallVector<PHINode *, 8> Stack; 660fe6060f1SDimitry Andric Stack.push_back(dyn_cast<PHINode>(FirstDef)); 661fe6060f1SDimitry Andric SmallSet<Value *, 16> SeenValues; 662fe6060f1SDimitry Andric 663fe6060f1SDimitry Andric while (!Stack.empty()) { 664349cc55cSDimitry Andric PHINode *CurPhi = Stack.pop_back_val(); 665fe6060f1SDimitry Andric 666fe6060f1SDimitry Andric Res[CurPhi->getParent()] = CurPhi; 667fe6060f1SDimitry Andric SeenValues.insert(CurPhi); 668fe6060f1SDimitry Andric 669fe6060f1SDimitry Andric for (Value *Incoming : CurPhi->incoming_values()) { 670fe6060f1SDimitry Andric if (Incoming == FirstDef || isa<ConstantInt>(Incoming) || 671349cc55cSDimitry Andric SeenValues.contains(Incoming)) { 672fe6060f1SDimitry Andric continue; 673fe6060f1SDimitry Andric } 674fe6060f1SDimitry Andric 675fe6060f1SDimitry Andric assert(isa<PHINode>(Incoming) && "After select unfolding, all state " 676fe6060f1SDimitry Andric "definitions are expected to be phi " 677fe6060f1SDimitry Andric "nodes."); 678fe6060f1SDimitry Andric 679fe6060f1SDimitry Andric Stack.push_back(cast<PHINode>(Incoming)); 680fe6060f1SDimitry Andric } 681fe6060f1SDimitry Andric } 682fe6060f1SDimitry Andric 683fe6060f1SDimitry Andric return Res; 684fe6060f1SDimitry Andric } 685fe6060f1SDimitry Andric 686*0eae32dcSDimitry Andric /// The determinator BB should precede the switch-defining BB. 687*0eae32dcSDimitry Andric /// 688*0eae32dcSDimitry Andric /// Otherwise, it is possible that the state defined in the determinator block 689*0eae32dcSDimitry Andric /// defines the state for the next iteration of the loop, rather than for the 690*0eae32dcSDimitry Andric /// current one. 691*0eae32dcSDimitry Andric /// 692*0eae32dcSDimitry Andric /// Currently supported paths: 693*0eae32dcSDimitry Andric /// \code 694*0eae32dcSDimitry Andric /// < switch bb1 determ def > [ 42, determ ] 695*0eae32dcSDimitry Andric /// < switch_and_def bb1 determ > [ 42, determ ] 696*0eae32dcSDimitry Andric /// < switch_and_def_and_determ bb1 > [ 42, switch_and_def_and_determ ] 697*0eae32dcSDimitry Andric /// \endcode 698*0eae32dcSDimitry Andric /// 699*0eae32dcSDimitry Andric /// Unsupported paths: 700*0eae32dcSDimitry Andric /// \code 701*0eae32dcSDimitry Andric /// < switch bb1 def determ > [ 43, determ ] 702*0eae32dcSDimitry Andric /// < switch_and_determ bb1 def > [ 43, switch_and_determ ] 703*0eae32dcSDimitry Andric /// \endcode 704*0eae32dcSDimitry Andric bool isSupported(const ThreadingPath &TPath) { 705*0eae32dcSDimitry Andric Instruction *SwitchCondI = dyn_cast<Instruction>(Switch->getCondition()); 706*0eae32dcSDimitry Andric assert(SwitchCondI); 707*0eae32dcSDimitry Andric if (!SwitchCondI) 708*0eae32dcSDimitry Andric return false; 709*0eae32dcSDimitry Andric 710*0eae32dcSDimitry Andric const BasicBlock *SwitchCondDefBB = SwitchCondI->getParent(); 711*0eae32dcSDimitry Andric const BasicBlock *SwitchCondUseBB = Switch->getParent(); 712*0eae32dcSDimitry Andric const BasicBlock *DeterminatorBB = TPath.getDeterminatorBB(); 713*0eae32dcSDimitry Andric 714*0eae32dcSDimitry Andric assert( 715*0eae32dcSDimitry Andric SwitchCondUseBB == TPath.getPath().front() && 716*0eae32dcSDimitry Andric "The first BB in a threading path should have the switch instruction"); 717*0eae32dcSDimitry Andric if (SwitchCondUseBB != TPath.getPath().front()) 718*0eae32dcSDimitry Andric return false; 719*0eae32dcSDimitry Andric 720*0eae32dcSDimitry Andric // Make DeterminatorBB the first element in Path. 721*0eae32dcSDimitry Andric PathType Path = TPath.getPath(); 722*0eae32dcSDimitry Andric auto ItDet = std::find(Path.begin(), Path.end(), DeterminatorBB); 723*0eae32dcSDimitry Andric std::rotate(Path.begin(), ItDet, Path.end()); 724*0eae32dcSDimitry Andric 725*0eae32dcSDimitry Andric bool IsDetBBSeen = false; 726*0eae32dcSDimitry Andric bool IsDefBBSeen = false; 727*0eae32dcSDimitry Andric bool IsUseBBSeen = false; 728*0eae32dcSDimitry Andric for (BasicBlock *BB : Path) { 729*0eae32dcSDimitry Andric if (BB == DeterminatorBB) 730*0eae32dcSDimitry Andric IsDetBBSeen = true; 731*0eae32dcSDimitry Andric if (BB == SwitchCondDefBB) 732*0eae32dcSDimitry Andric IsDefBBSeen = true; 733*0eae32dcSDimitry Andric if (BB == SwitchCondUseBB) 734*0eae32dcSDimitry Andric IsUseBBSeen = true; 735*0eae32dcSDimitry Andric if (IsDetBBSeen && IsUseBBSeen && !IsDefBBSeen) 736*0eae32dcSDimitry Andric return false; 737*0eae32dcSDimitry Andric } 738*0eae32dcSDimitry Andric 739*0eae32dcSDimitry Andric return true; 740*0eae32dcSDimitry Andric } 741*0eae32dcSDimitry Andric 742fe6060f1SDimitry Andric SwitchInst *Switch; 743fe6060f1SDimitry Andric BasicBlock *SwitchBlock; 744fe6060f1SDimitry Andric OptimizationRemarkEmitter *ORE; 745fe6060f1SDimitry Andric std::vector<ThreadingPath> TPaths; 746fe6060f1SDimitry Andric }; 747fe6060f1SDimitry Andric 748fe6060f1SDimitry Andric struct TransformDFA { 749fe6060f1SDimitry Andric TransformDFA(AllSwitchPaths *SwitchPaths, DominatorTree *DT, 750fe6060f1SDimitry Andric AssumptionCache *AC, TargetTransformInfo *TTI, 751fe6060f1SDimitry Andric OptimizationRemarkEmitter *ORE, 752fe6060f1SDimitry Andric SmallPtrSet<const Value *, 32> EphValues) 753fe6060f1SDimitry Andric : SwitchPaths(SwitchPaths), DT(DT), AC(AC), TTI(TTI), ORE(ORE), 754fe6060f1SDimitry Andric EphValues(EphValues) {} 755fe6060f1SDimitry Andric 756fe6060f1SDimitry Andric void run() { 757fe6060f1SDimitry Andric if (isLegalAndProfitableToTransform()) { 758fe6060f1SDimitry Andric createAllExitPaths(); 759fe6060f1SDimitry Andric NumTransforms++; 760fe6060f1SDimitry Andric } 761fe6060f1SDimitry Andric } 762fe6060f1SDimitry Andric 763fe6060f1SDimitry Andric private: 764fe6060f1SDimitry Andric /// This function performs both a legality check and profitability check at 765fe6060f1SDimitry Andric /// the same time since it is convenient to do so. It iterates through all 766fe6060f1SDimitry Andric /// blocks that will be cloned, and keeps track of the duplication cost. It 767fe6060f1SDimitry Andric /// also returns false if it is illegal to clone some required block. 768fe6060f1SDimitry Andric bool isLegalAndProfitableToTransform() { 769fe6060f1SDimitry Andric CodeMetrics Metrics; 770fe6060f1SDimitry Andric SwitchInst *Switch = SwitchPaths->getSwitchInst(); 771fe6060f1SDimitry Andric 772fe6060f1SDimitry Andric // Note that DuplicateBlockMap is not being used as intended here. It is 773fe6060f1SDimitry Andric // just being used to ensure (BB, State) pairs are only counted once. 774fe6060f1SDimitry Andric DuplicateBlockMap DuplicateMap; 775fe6060f1SDimitry Andric 776fe6060f1SDimitry Andric for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) { 777fe6060f1SDimitry Andric PathType PathBBs = TPath.getPath(); 778fe6060f1SDimitry Andric uint64_t NextState = TPath.getExitValue(); 779fe6060f1SDimitry Andric const BasicBlock *Determinator = TPath.getDeterminatorBB(); 780fe6060f1SDimitry Andric 781fe6060f1SDimitry Andric // Update Metrics for the Switch block, this is always cloned 782fe6060f1SDimitry Andric BasicBlock *BB = SwitchPaths->getSwitchBlock(); 783fe6060f1SDimitry Andric BasicBlock *VisitedBB = getClonedBB(BB, NextState, DuplicateMap); 784fe6060f1SDimitry Andric if (!VisitedBB) { 785fe6060f1SDimitry Andric Metrics.analyzeBasicBlock(BB, *TTI, EphValues); 786fe6060f1SDimitry Andric DuplicateMap[BB].push_back({BB, NextState}); 787fe6060f1SDimitry Andric } 788fe6060f1SDimitry Andric 789fe6060f1SDimitry Andric // If the Switch block is the Determinator, then we can continue since 790fe6060f1SDimitry Andric // this is the only block that is cloned and we already counted for it. 791fe6060f1SDimitry Andric if (PathBBs.front() == Determinator) 792fe6060f1SDimitry Andric continue; 793fe6060f1SDimitry Andric 794fe6060f1SDimitry Andric // Otherwise update Metrics for all blocks that will be cloned. If any 795fe6060f1SDimitry Andric // block is already cloned and would be reused, don't double count it. 796fe6060f1SDimitry Andric auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator); 797fe6060f1SDimitry Andric for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) { 798fe6060f1SDimitry Andric BB = *BBIt; 799fe6060f1SDimitry Andric VisitedBB = getClonedBB(BB, NextState, DuplicateMap); 800fe6060f1SDimitry Andric if (VisitedBB) 801fe6060f1SDimitry Andric continue; 802fe6060f1SDimitry Andric Metrics.analyzeBasicBlock(BB, *TTI, EphValues); 803fe6060f1SDimitry Andric DuplicateMap[BB].push_back({BB, NextState}); 804fe6060f1SDimitry Andric } 805fe6060f1SDimitry Andric 806fe6060f1SDimitry Andric if (Metrics.notDuplicatable) { 807fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains " 808fe6060f1SDimitry Andric << "non-duplicatable instructions.\n"); 809fe6060f1SDimitry Andric ORE->emit([&]() { 810fe6060f1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "NonDuplicatableInst", 811fe6060f1SDimitry Andric Switch) 812fe6060f1SDimitry Andric << "Contains non-duplicatable instructions."; 813fe6060f1SDimitry Andric }); 814fe6060f1SDimitry Andric return false; 815fe6060f1SDimitry Andric } 816fe6060f1SDimitry Andric 817fe6060f1SDimitry Andric if (Metrics.convergent) { 818fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains " 819fe6060f1SDimitry Andric << "convergent instructions.\n"); 820fe6060f1SDimitry Andric ORE->emit([&]() { 821fe6060f1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "ConvergentInst", Switch) 822fe6060f1SDimitry Andric << "Contains convergent instructions."; 823fe6060f1SDimitry Andric }); 824fe6060f1SDimitry Andric return false; 825fe6060f1SDimitry Andric } 826fe6060f1SDimitry Andric } 827fe6060f1SDimitry Andric 828fe6060f1SDimitry Andric unsigned DuplicationCost = 0; 829fe6060f1SDimitry Andric 830fe6060f1SDimitry Andric unsigned JumpTableSize = 0; 831fe6060f1SDimitry Andric TTI->getEstimatedNumberOfCaseClusters(*Switch, JumpTableSize, nullptr, 832fe6060f1SDimitry Andric nullptr); 833fe6060f1SDimitry Andric if (JumpTableSize == 0) { 834fe6060f1SDimitry Andric // Factor in the number of conditional branches reduced from jump 835fe6060f1SDimitry Andric // threading. Assume that lowering the switch block is implemented by 836fe6060f1SDimitry Andric // using binary search, hence the LogBase2(). 837fe6060f1SDimitry Andric unsigned CondBranches = 838fe6060f1SDimitry Andric APInt(32, Switch->getNumSuccessors()).ceilLogBase2(); 839fe6060f1SDimitry Andric DuplicationCost = Metrics.NumInsts / CondBranches; 840fe6060f1SDimitry Andric } else { 841fe6060f1SDimitry Andric // Compared with jump tables, the DFA optimizer removes an indirect branch 842fe6060f1SDimitry Andric // on each loop iteration, thus making branch prediction more precise. The 843fe6060f1SDimitry Andric // more branch targets there are, the more likely it is for the branch 844fe6060f1SDimitry Andric // predictor to make a mistake, and the more benefit there is in the DFA 845fe6060f1SDimitry Andric // optimizer. Thus, the more branch targets there are, the lower is the 846fe6060f1SDimitry Andric // cost of the DFA opt. 847fe6060f1SDimitry Andric DuplicationCost = Metrics.NumInsts / JumpTableSize; 848fe6060f1SDimitry Andric } 849fe6060f1SDimitry Andric 850fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\nDFA Jump Threading: Cost to jump thread block " 851fe6060f1SDimitry Andric << SwitchPaths->getSwitchBlock()->getName() 852fe6060f1SDimitry Andric << " is: " << DuplicationCost << "\n\n"); 853fe6060f1SDimitry Andric 854fe6060f1SDimitry Andric if (DuplicationCost > CostThreshold) { 855fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Not jump threading, duplication cost exceeds the " 856fe6060f1SDimitry Andric << "cost threshold.\n"); 857fe6060f1SDimitry Andric ORE->emit([&]() { 858fe6060f1SDimitry Andric return OptimizationRemarkMissed(DEBUG_TYPE, "NotProfitable", Switch) 859fe6060f1SDimitry Andric << "Duplication cost exceeds the cost threshold (cost=" 860fe6060f1SDimitry Andric << ore::NV("Cost", DuplicationCost) 861fe6060f1SDimitry Andric << ", threshold=" << ore::NV("Threshold", CostThreshold) << ")."; 862fe6060f1SDimitry Andric }); 863fe6060f1SDimitry Andric return false; 864fe6060f1SDimitry Andric } 865fe6060f1SDimitry Andric 866fe6060f1SDimitry Andric ORE->emit([&]() { 867fe6060f1SDimitry Andric return OptimizationRemark(DEBUG_TYPE, "JumpThreaded", Switch) 868fe6060f1SDimitry Andric << "Switch statement jump-threaded."; 869fe6060f1SDimitry Andric }); 870fe6060f1SDimitry Andric 871fe6060f1SDimitry Andric return true; 872fe6060f1SDimitry Andric } 873fe6060f1SDimitry Andric 874fe6060f1SDimitry Andric /// Transform each threading path to effectively jump thread the DFA. 875fe6060f1SDimitry Andric void createAllExitPaths() { 876fe6060f1SDimitry Andric DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager); 877fe6060f1SDimitry Andric 878fe6060f1SDimitry Andric // Move the switch block to the end of the path, since it will be duplicated 879fe6060f1SDimitry Andric BasicBlock *SwitchBlock = SwitchPaths->getSwitchBlock(); 880fe6060f1SDimitry Andric for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) { 881fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << TPath << "\n"); 882fe6060f1SDimitry Andric PathType NewPath(TPath.getPath()); 883fe6060f1SDimitry Andric NewPath.push_back(SwitchBlock); 884fe6060f1SDimitry Andric TPath.setPath(NewPath); 885fe6060f1SDimitry Andric } 886fe6060f1SDimitry Andric 887fe6060f1SDimitry Andric // Transform the ThreadingPaths and keep track of the cloned values 888fe6060f1SDimitry Andric DuplicateBlockMap DuplicateMap; 889fe6060f1SDimitry Andric DefMap NewDefs; 890fe6060f1SDimitry Andric 891fe6060f1SDimitry Andric SmallSet<BasicBlock *, 16> BlocksToClean; 892fe6060f1SDimitry Andric for (BasicBlock *BB : successors(SwitchBlock)) 893fe6060f1SDimitry Andric BlocksToClean.insert(BB); 894fe6060f1SDimitry Andric 895fe6060f1SDimitry Andric for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) { 896fe6060f1SDimitry Andric createExitPath(NewDefs, TPath, DuplicateMap, BlocksToClean, &DTU); 897fe6060f1SDimitry Andric NumPaths++; 898fe6060f1SDimitry Andric } 899fe6060f1SDimitry Andric 900fe6060f1SDimitry Andric // After all paths are cloned, now update the last successor of the cloned 901fe6060f1SDimitry Andric // path so it skips over the switch statement 902fe6060f1SDimitry Andric for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) 903fe6060f1SDimitry Andric updateLastSuccessor(TPath, DuplicateMap, &DTU); 904fe6060f1SDimitry Andric 905fe6060f1SDimitry Andric // For each instruction that was cloned and used outside, update its uses 906fe6060f1SDimitry Andric updateSSA(NewDefs); 907fe6060f1SDimitry Andric 908fe6060f1SDimitry Andric // Clean PHI Nodes for the newly created blocks 909fe6060f1SDimitry Andric for (BasicBlock *BB : BlocksToClean) 910fe6060f1SDimitry Andric cleanPhiNodes(BB); 911fe6060f1SDimitry Andric } 912fe6060f1SDimitry Andric 913fe6060f1SDimitry Andric /// For a specific ThreadingPath \p Path, create an exit path starting from 914fe6060f1SDimitry Andric /// the determinator block. 915fe6060f1SDimitry Andric /// 916fe6060f1SDimitry Andric /// To remember the correct destination, we have to duplicate blocks 917fe6060f1SDimitry Andric /// corresponding to each state. Also update the terminating instruction of 918fe6060f1SDimitry Andric /// the predecessors, and phis in the successor blocks. 919fe6060f1SDimitry Andric void createExitPath(DefMap &NewDefs, ThreadingPath &Path, 920fe6060f1SDimitry Andric DuplicateBlockMap &DuplicateMap, 921fe6060f1SDimitry Andric SmallSet<BasicBlock *, 16> &BlocksToClean, 922fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 923fe6060f1SDimitry Andric uint64_t NextState = Path.getExitValue(); 924fe6060f1SDimitry Andric const BasicBlock *Determinator = Path.getDeterminatorBB(); 925fe6060f1SDimitry Andric PathType PathBBs = Path.getPath(); 926fe6060f1SDimitry Andric 927fe6060f1SDimitry Andric // Don't select the placeholder block in front 928fe6060f1SDimitry Andric if (PathBBs.front() == Determinator) 929fe6060f1SDimitry Andric PathBBs.pop_front(); 930fe6060f1SDimitry Andric 931fe6060f1SDimitry Andric auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator); 932fe6060f1SDimitry Andric auto Prev = std::prev(DetIt); 933fe6060f1SDimitry Andric BasicBlock *PrevBB = *Prev; 934fe6060f1SDimitry Andric for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) { 935fe6060f1SDimitry Andric BasicBlock *BB = *BBIt; 936fe6060f1SDimitry Andric BlocksToClean.insert(BB); 937fe6060f1SDimitry Andric 938fe6060f1SDimitry Andric // We already cloned BB for this NextState, now just update the branch 939fe6060f1SDimitry Andric // and continue. 940fe6060f1SDimitry Andric BasicBlock *NextBB = getClonedBB(BB, NextState, DuplicateMap); 941fe6060f1SDimitry Andric if (NextBB) { 942fe6060f1SDimitry Andric updatePredecessor(PrevBB, BB, NextBB, DTU); 943fe6060f1SDimitry Andric PrevBB = NextBB; 944fe6060f1SDimitry Andric continue; 945fe6060f1SDimitry Andric } 946fe6060f1SDimitry Andric 947fe6060f1SDimitry Andric // Clone the BB and update the successor of Prev to jump to the new block 948fe6060f1SDimitry Andric BasicBlock *NewBB = cloneBlockAndUpdatePredecessor( 949fe6060f1SDimitry Andric BB, PrevBB, NextState, DuplicateMap, NewDefs, DTU); 950fe6060f1SDimitry Andric DuplicateMap[BB].push_back({NewBB, NextState}); 951fe6060f1SDimitry Andric BlocksToClean.insert(NewBB); 952fe6060f1SDimitry Andric PrevBB = NewBB; 953fe6060f1SDimitry Andric } 954fe6060f1SDimitry Andric } 955fe6060f1SDimitry Andric 956fe6060f1SDimitry Andric /// Restore SSA form after cloning blocks. 957fe6060f1SDimitry Andric /// 958fe6060f1SDimitry Andric /// Each cloned block creates new defs for a variable, and the uses need to be 959fe6060f1SDimitry Andric /// updated to reflect this. The uses may be replaced with a cloned value, or 960fe6060f1SDimitry Andric /// some derived phi instruction. Note that all uses of a value defined in the 961fe6060f1SDimitry Andric /// same block were already remapped when cloning the block. 962fe6060f1SDimitry Andric void updateSSA(DefMap &NewDefs) { 963fe6060f1SDimitry Andric SSAUpdaterBulk SSAUpdate; 964fe6060f1SDimitry Andric SmallVector<Use *, 16> UsesToRename; 965fe6060f1SDimitry Andric 966fe6060f1SDimitry Andric for (auto KV : NewDefs) { 967fe6060f1SDimitry Andric Instruction *I = KV.first; 968fe6060f1SDimitry Andric BasicBlock *BB = I->getParent(); 969fe6060f1SDimitry Andric std::vector<Instruction *> Cloned = KV.second; 970fe6060f1SDimitry Andric 971fe6060f1SDimitry Andric // Scan all uses of this instruction to see if it is used outside of its 972fe6060f1SDimitry Andric // block, and if so, record them in UsesToRename. 973fe6060f1SDimitry Andric for (Use &U : I->uses()) { 974fe6060f1SDimitry Andric Instruction *User = cast<Instruction>(U.getUser()); 975fe6060f1SDimitry Andric if (PHINode *UserPN = dyn_cast<PHINode>(User)) { 976fe6060f1SDimitry Andric if (UserPN->getIncomingBlock(U) == BB) 977fe6060f1SDimitry Andric continue; 978fe6060f1SDimitry Andric } else if (User->getParent() == BB) { 979fe6060f1SDimitry Andric continue; 980fe6060f1SDimitry Andric } 981fe6060f1SDimitry Andric 982fe6060f1SDimitry Andric UsesToRename.push_back(&U); 983fe6060f1SDimitry Andric } 984fe6060f1SDimitry Andric 985fe6060f1SDimitry Andric // If there are no uses outside the block, we're done with this 986fe6060f1SDimitry Andric // instruction. 987fe6060f1SDimitry Andric if (UsesToRename.empty()) 988fe6060f1SDimitry Andric continue; 989fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "DFA-JT: Renaming non-local uses of: " << *I 990fe6060f1SDimitry Andric << "\n"); 991fe6060f1SDimitry Andric 992fe6060f1SDimitry Andric // We found a use of I outside of BB. Rename all uses of I that are 993fe6060f1SDimitry Andric // outside its block to be uses of the appropriate PHI node etc. See 994fe6060f1SDimitry Andric // ValuesInBlocks with the values we know. 995fe6060f1SDimitry Andric unsigned VarNum = SSAUpdate.AddVariable(I->getName(), I->getType()); 996fe6060f1SDimitry Andric SSAUpdate.AddAvailableValue(VarNum, BB, I); 997fe6060f1SDimitry Andric for (Instruction *New : Cloned) 998fe6060f1SDimitry Andric SSAUpdate.AddAvailableValue(VarNum, New->getParent(), New); 999fe6060f1SDimitry Andric 1000fe6060f1SDimitry Andric while (!UsesToRename.empty()) 1001fe6060f1SDimitry Andric SSAUpdate.AddUse(VarNum, UsesToRename.pop_back_val()); 1002fe6060f1SDimitry Andric 1003fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 1004fe6060f1SDimitry Andric } 1005fe6060f1SDimitry Andric // SSAUpdater handles phi placement and renaming uses with the appropriate 1006fe6060f1SDimitry Andric // value. 1007fe6060f1SDimitry Andric SSAUpdate.RewriteAllUses(DT); 1008fe6060f1SDimitry Andric } 1009fe6060f1SDimitry Andric 1010fe6060f1SDimitry Andric /// Clones a basic block, and adds it to the CFG. 1011fe6060f1SDimitry Andric /// 1012fe6060f1SDimitry Andric /// This function also includes updating phi nodes in the successors of the 1013fe6060f1SDimitry Andric /// BB, and remapping uses that were defined locally in the cloned BB. 1014fe6060f1SDimitry Andric BasicBlock *cloneBlockAndUpdatePredecessor(BasicBlock *BB, BasicBlock *PrevBB, 1015fe6060f1SDimitry Andric uint64_t NextState, 1016fe6060f1SDimitry Andric DuplicateBlockMap &DuplicateMap, 1017fe6060f1SDimitry Andric DefMap &NewDefs, 1018fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 1019fe6060f1SDimitry Andric ValueToValueMapTy VMap; 1020fe6060f1SDimitry Andric BasicBlock *NewBB = CloneBasicBlock( 1021fe6060f1SDimitry Andric BB, VMap, ".jt" + std::to_string(NextState), BB->getParent()); 1022fe6060f1SDimitry Andric NewBB->moveAfter(BB); 1023fe6060f1SDimitry Andric NumCloned++; 1024fe6060f1SDimitry Andric 1025fe6060f1SDimitry Andric for (Instruction &I : *NewBB) { 1026fe6060f1SDimitry Andric // Do not remap operands of PHINode in case a definition in BB is an 1027fe6060f1SDimitry Andric // incoming value to a phi in the same block. This incoming value will 1028fe6060f1SDimitry Andric // be renamed later while restoring SSA. 1029fe6060f1SDimitry Andric if (isa<PHINode>(&I)) 1030fe6060f1SDimitry Andric continue; 1031fe6060f1SDimitry Andric RemapInstruction(&I, VMap, 1032fe6060f1SDimitry Andric RF_IgnoreMissingLocals | RF_NoModuleLevelChanges); 1033fe6060f1SDimitry Andric if (AssumeInst *II = dyn_cast<AssumeInst>(&I)) 1034fe6060f1SDimitry Andric AC->registerAssumption(II); 1035fe6060f1SDimitry Andric } 1036fe6060f1SDimitry Andric 1037fe6060f1SDimitry Andric updateSuccessorPhis(BB, NewBB, NextState, VMap, DuplicateMap); 1038fe6060f1SDimitry Andric updatePredecessor(PrevBB, BB, NewBB, DTU); 1039fe6060f1SDimitry Andric updateDefMap(NewDefs, VMap); 1040fe6060f1SDimitry Andric 1041fe6060f1SDimitry Andric // Add all successors to the DominatorTree 1042fe6060f1SDimitry Andric SmallPtrSet<BasicBlock *, 4> SuccSet; 1043fe6060f1SDimitry Andric for (auto *SuccBB : successors(NewBB)) { 1044fe6060f1SDimitry Andric if (SuccSet.insert(SuccBB).second) 1045fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB}}); 1046fe6060f1SDimitry Andric } 1047fe6060f1SDimitry Andric SuccSet.clear(); 1048fe6060f1SDimitry Andric return NewBB; 1049fe6060f1SDimitry Andric } 1050fe6060f1SDimitry Andric 1051fe6060f1SDimitry Andric /// Update the phi nodes in BB's successors. 1052fe6060f1SDimitry Andric /// 1053fe6060f1SDimitry Andric /// This means creating a new incoming value from NewBB with the new 1054fe6060f1SDimitry Andric /// instruction wherever there is an incoming value from BB. 1055fe6060f1SDimitry Andric void updateSuccessorPhis(BasicBlock *BB, BasicBlock *ClonedBB, 1056fe6060f1SDimitry Andric uint64_t NextState, ValueToValueMapTy &VMap, 1057fe6060f1SDimitry Andric DuplicateBlockMap &DuplicateMap) { 1058fe6060f1SDimitry Andric std::vector<BasicBlock *> BlocksToUpdate; 1059fe6060f1SDimitry Andric 1060fe6060f1SDimitry Andric // If BB is the last block in the path, we can simply update the one case 1061fe6060f1SDimitry Andric // successor that will be reached. 1062fe6060f1SDimitry Andric if (BB == SwitchPaths->getSwitchBlock()) { 1063fe6060f1SDimitry Andric SwitchInst *Switch = SwitchPaths->getSwitchInst(); 1064fe6060f1SDimitry Andric BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState); 1065fe6060f1SDimitry Andric BlocksToUpdate.push_back(NextCase); 1066fe6060f1SDimitry Andric BasicBlock *ClonedSucc = getClonedBB(NextCase, NextState, DuplicateMap); 1067fe6060f1SDimitry Andric if (ClonedSucc) 1068fe6060f1SDimitry Andric BlocksToUpdate.push_back(ClonedSucc); 1069fe6060f1SDimitry Andric } 1070fe6060f1SDimitry Andric // Otherwise update phis in all successors. 1071fe6060f1SDimitry Andric else { 1072fe6060f1SDimitry Andric for (BasicBlock *Succ : successors(BB)) { 1073fe6060f1SDimitry Andric BlocksToUpdate.push_back(Succ); 1074fe6060f1SDimitry Andric 1075fe6060f1SDimitry Andric // Check if a successor has already been cloned for the particular exit 1076fe6060f1SDimitry Andric // value. In this case if a successor was already cloned, the phi nodes 1077fe6060f1SDimitry Andric // in the cloned block should be updated directly. 1078fe6060f1SDimitry Andric BasicBlock *ClonedSucc = getClonedBB(Succ, NextState, DuplicateMap); 1079fe6060f1SDimitry Andric if (ClonedSucc) 1080fe6060f1SDimitry Andric BlocksToUpdate.push_back(ClonedSucc); 1081fe6060f1SDimitry Andric } 1082fe6060f1SDimitry Andric } 1083fe6060f1SDimitry Andric 1084fe6060f1SDimitry Andric // If there is a phi with an incoming value from BB, create a new incoming 1085fe6060f1SDimitry Andric // value for the new predecessor ClonedBB. The value will either be the same 1086fe6060f1SDimitry Andric // value from BB or a cloned value. 1087fe6060f1SDimitry Andric for (BasicBlock *Succ : BlocksToUpdate) { 1088fe6060f1SDimitry Andric for (auto II = Succ->begin(); PHINode *Phi = dyn_cast<PHINode>(II); 1089fe6060f1SDimitry Andric ++II) { 1090fe6060f1SDimitry Andric Value *Incoming = Phi->getIncomingValueForBlock(BB); 1091fe6060f1SDimitry Andric if (Incoming) { 1092fe6060f1SDimitry Andric if (isa<Constant>(Incoming)) { 1093fe6060f1SDimitry Andric Phi->addIncoming(Incoming, ClonedBB); 1094fe6060f1SDimitry Andric continue; 1095fe6060f1SDimitry Andric } 1096fe6060f1SDimitry Andric Value *ClonedVal = VMap[Incoming]; 1097fe6060f1SDimitry Andric if (ClonedVal) 1098fe6060f1SDimitry Andric Phi->addIncoming(ClonedVal, ClonedBB); 1099fe6060f1SDimitry Andric else 1100fe6060f1SDimitry Andric Phi->addIncoming(Incoming, ClonedBB); 1101fe6060f1SDimitry Andric } 1102fe6060f1SDimitry Andric } 1103fe6060f1SDimitry Andric } 1104fe6060f1SDimitry Andric } 1105fe6060f1SDimitry Andric 1106fe6060f1SDimitry Andric /// Sets the successor of PrevBB to be NewBB instead of OldBB. Note that all 1107fe6060f1SDimitry Andric /// other successors are kept as well. 1108fe6060f1SDimitry Andric void updatePredecessor(BasicBlock *PrevBB, BasicBlock *OldBB, 1109fe6060f1SDimitry Andric BasicBlock *NewBB, DomTreeUpdater *DTU) { 1110fe6060f1SDimitry Andric // When a path is reused, there is a chance that predecessors were already 1111fe6060f1SDimitry Andric // updated before. Check if the predecessor needs to be updated first. 1112fe6060f1SDimitry Andric if (!isPredecessor(OldBB, PrevBB)) 1113fe6060f1SDimitry Andric return; 1114fe6060f1SDimitry Andric 1115fe6060f1SDimitry Andric Instruction *PrevTerm = PrevBB->getTerminator(); 1116fe6060f1SDimitry Andric for (unsigned Idx = 0; Idx < PrevTerm->getNumSuccessors(); Idx++) { 1117fe6060f1SDimitry Andric if (PrevTerm->getSuccessor(Idx) == OldBB) { 1118fe6060f1SDimitry Andric OldBB->removePredecessor(PrevBB, /* KeepOneInputPHIs = */ true); 1119fe6060f1SDimitry Andric PrevTerm->setSuccessor(Idx, NewBB); 1120fe6060f1SDimitry Andric } 1121fe6060f1SDimitry Andric } 1122fe6060f1SDimitry Andric DTU->applyUpdates({{DominatorTree::Delete, PrevBB, OldBB}, 1123fe6060f1SDimitry Andric {DominatorTree::Insert, PrevBB, NewBB}}); 1124fe6060f1SDimitry Andric } 1125fe6060f1SDimitry Andric 1126fe6060f1SDimitry Andric /// Add new value mappings to the DefMap to keep track of all new definitions 1127fe6060f1SDimitry Andric /// for a particular instruction. These will be used while updating SSA form. 1128fe6060f1SDimitry Andric void updateDefMap(DefMap &NewDefs, ValueToValueMapTy &VMap) { 1129fe6060f1SDimitry Andric for (auto Entry : VMap) { 1130fe6060f1SDimitry Andric Instruction *Inst = 1131fe6060f1SDimitry Andric dyn_cast<Instruction>(const_cast<Value *>(Entry.first)); 1132fe6060f1SDimitry Andric if (!Inst || !Entry.second || isa<BranchInst>(Inst) || 1133fe6060f1SDimitry Andric isa<SwitchInst>(Inst)) { 1134fe6060f1SDimitry Andric continue; 1135fe6060f1SDimitry Andric } 1136fe6060f1SDimitry Andric 1137fe6060f1SDimitry Andric Instruction *Cloned = dyn_cast<Instruction>(Entry.second); 1138fe6060f1SDimitry Andric if (!Cloned) 1139fe6060f1SDimitry Andric continue; 1140fe6060f1SDimitry Andric 1141fe6060f1SDimitry Andric if (NewDefs.find(Inst) == NewDefs.end()) 1142fe6060f1SDimitry Andric NewDefs[Inst] = {Cloned}; 1143fe6060f1SDimitry Andric else 1144fe6060f1SDimitry Andric NewDefs[Inst].push_back(Cloned); 1145fe6060f1SDimitry Andric } 1146fe6060f1SDimitry Andric } 1147fe6060f1SDimitry Andric 1148fe6060f1SDimitry Andric /// Update the last branch of a particular cloned path to point to the correct 1149fe6060f1SDimitry Andric /// case successor. 1150fe6060f1SDimitry Andric /// 1151fe6060f1SDimitry Andric /// Note that this is an optional step and would have been done in later 1152fe6060f1SDimitry Andric /// optimizations, but it makes the CFG significantly easier to work with. 1153fe6060f1SDimitry Andric void updateLastSuccessor(ThreadingPath &TPath, 1154fe6060f1SDimitry Andric DuplicateBlockMap &DuplicateMap, 1155fe6060f1SDimitry Andric DomTreeUpdater *DTU) { 1156fe6060f1SDimitry Andric uint64_t NextState = TPath.getExitValue(); 1157fe6060f1SDimitry Andric BasicBlock *BB = TPath.getPath().back(); 1158fe6060f1SDimitry Andric BasicBlock *LastBlock = getClonedBB(BB, NextState, DuplicateMap); 1159fe6060f1SDimitry Andric 1160fe6060f1SDimitry Andric // Note multiple paths can end at the same block so check that it is not 1161fe6060f1SDimitry Andric // updated yet 1162fe6060f1SDimitry Andric if (!isa<SwitchInst>(LastBlock->getTerminator())) 1163fe6060f1SDimitry Andric return; 1164fe6060f1SDimitry Andric SwitchInst *Switch = cast<SwitchInst>(LastBlock->getTerminator()); 1165fe6060f1SDimitry Andric BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState); 1166fe6060f1SDimitry Andric 1167fe6060f1SDimitry Andric std::vector<DominatorTree::UpdateType> DTUpdates; 1168fe6060f1SDimitry Andric SmallPtrSet<BasicBlock *, 4> SuccSet; 1169fe6060f1SDimitry Andric for (BasicBlock *Succ : successors(LastBlock)) { 1170fe6060f1SDimitry Andric if (Succ != NextCase && SuccSet.insert(Succ).second) 1171fe6060f1SDimitry Andric DTUpdates.push_back({DominatorTree::Delete, LastBlock, Succ}); 1172fe6060f1SDimitry Andric } 1173fe6060f1SDimitry Andric 1174fe6060f1SDimitry Andric Switch->eraseFromParent(); 1175fe6060f1SDimitry Andric BranchInst::Create(NextCase, LastBlock); 1176fe6060f1SDimitry Andric 1177fe6060f1SDimitry Andric DTU->applyUpdates(DTUpdates); 1178fe6060f1SDimitry Andric } 1179fe6060f1SDimitry Andric 1180fe6060f1SDimitry Andric /// After cloning blocks, some of the phi nodes have extra incoming values 1181fe6060f1SDimitry Andric /// that are no longer used. This function removes them. 1182fe6060f1SDimitry Andric void cleanPhiNodes(BasicBlock *BB) { 1183fe6060f1SDimitry Andric // If BB is no longer reachable, remove any remaining phi nodes 1184fe6060f1SDimitry Andric if (pred_empty(BB)) { 1185fe6060f1SDimitry Andric std::vector<PHINode *> PhiToRemove; 1186fe6060f1SDimitry Andric for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) { 1187fe6060f1SDimitry Andric PhiToRemove.push_back(Phi); 1188fe6060f1SDimitry Andric } 1189fe6060f1SDimitry Andric for (PHINode *PN : PhiToRemove) { 1190fe6060f1SDimitry Andric PN->replaceAllUsesWith(UndefValue::get(PN->getType())); 1191fe6060f1SDimitry Andric PN->eraseFromParent(); 1192fe6060f1SDimitry Andric } 1193fe6060f1SDimitry Andric return; 1194fe6060f1SDimitry Andric } 1195fe6060f1SDimitry Andric 1196fe6060f1SDimitry Andric // Remove any incoming values that come from an invalid predecessor 1197fe6060f1SDimitry Andric for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) { 1198fe6060f1SDimitry Andric std::vector<BasicBlock *> BlocksToRemove; 1199fe6060f1SDimitry Andric for (BasicBlock *IncomingBB : Phi->blocks()) { 1200fe6060f1SDimitry Andric if (!isPredecessor(BB, IncomingBB)) 1201fe6060f1SDimitry Andric BlocksToRemove.push_back(IncomingBB); 1202fe6060f1SDimitry Andric } 1203fe6060f1SDimitry Andric for (BasicBlock *BB : BlocksToRemove) 1204fe6060f1SDimitry Andric Phi->removeIncomingValue(BB); 1205fe6060f1SDimitry Andric } 1206fe6060f1SDimitry Andric } 1207fe6060f1SDimitry Andric 1208fe6060f1SDimitry Andric /// Checks if BB was already cloned for a particular next state value. If it 1209fe6060f1SDimitry Andric /// was then it returns this cloned block, and otherwise null. 1210fe6060f1SDimitry Andric BasicBlock *getClonedBB(BasicBlock *BB, uint64_t NextState, 1211fe6060f1SDimitry Andric DuplicateBlockMap &DuplicateMap) { 1212fe6060f1SDimitry Andric CloneList ClonedBBs = DuplicateMap[BB]; 1213fe6060f1SDimitry Andric 1214fe6060f1SDimitry Andric // Find an entry in the CloneList with this NextState. If it exists then 1215fe6060f1SDimitry Andric // return the corresponding BB 1216fe6060f1SDimitry Andric auto It = llvm::find_if(ClonedBBs, [NextState](const ClonedBlock &C) { 1217fe6060f1SDimitry Andric return C.State == NextState; 1218fe6060f1SDimitry Andric }); 1219fe6060f1SDimitry Andric return It != ClonedBBs.end() ? (*It).BB : nullptr; 1220fe6060f1SDimitry Andric } 1221fe6060f1SDimitry Andric 1222fe6060f1SDimitry Andric /// Helper to get the successor corresponding to a particular case value for 1223fe6060f1SDimitry Andric /// a switch statement. 1224fe6060f1SDimitry Andric BasicBlock *getNextCaseSuccessor(SwitchInst *Switch, uint64_t NextState) { 1225fe6060f1SDimitry Andric BasicBlock *NextCase = nullptr; 1226fe6060f1SDimitry Andric for (auto Case : Switch->cases()) { 1227fe6060f1SDimitry Andric if (Case.getCaseValue()->getZExtValue() == NextState) { 1228fe6060f1SDimitry Andric NextCase = Case.getCaseSuccessor(); 1229fe6060f1SDimitry Andric break; 1230fe6060f1SDimitry Andric } 1231fe6060f1SDimitry Andric } 1232fe6060f1SDimitry Andric if (!NextCase) 1233fe6060f1SDimitry Andric NextCase = Switch->getDefaultDest(); 1234fe6060f1SDimitry Andric return NextCase; 1235fe6060f1SDimitry Andric } 1236fe6060f1SDimitry Andric 1237fe6060f1SDimitry Andric /// Returns true if IncomingBB is a predecessor of BB. 1238fe6060f1SDimitry Andric bool isPredecessor(BasicBlock *BB, BasicBlock *IncomingBB) { 1239fe6060f1SDimitry Andric return llvm::find(predecessors(BB), IncomingBB) != pred_end(BB); 1240fe6060f1SDimitry Andric } 1241fe6060f1SDimitry Andric 1242fe6060f1SDimitry Andric AllSwitchPaths *SwitchPaths; 1243fe6060f1SDimitry Andric DominatorTree *DT; 1244fe6060f1SDimitry Andric AssumptionCache *AC; 1245fe6060f1SDimitry Andric TargetTransformInfo *TTI; 1246fe6060f1SDimitry Andric OptimizationRemarkEmitter *ORE; 1247fe6060f1SDimitry Andric SmallPtrSet<const Value *, 32> EphValues; 1248fe6060f1SDimitry Andric std::vector<ThreadingPath> TPaths; 1249fe6060f1SDimitry Andric }; 1250fe6060f1SDimitry Andric 1251fe6060f1SDimitry Andric bool DFAJumpThreading::run(Function &F) { 1252fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\nDFA Jump threading: " << F.getName() << "\n"); 1253fe6060f1SDimitry Andric 1254fe6060f1SDimitry Andric if (F.hasOptSize()) { 1255fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Skipping due to the 'minsize' attribute\n"); 1256fe6060f1SDimitry Andric return false; 1257fe6060f1SDimitry Andric } 1258fe6060f1SDimitry Andric 1259fe6060f1SDimitry Andric if (ClViewCfgBefore) 1260fe6060f1SDimitry Andric F.viewCFG(); 1261fe6060f1SDimitry Andric 1262fe6060f1SDimitry Andric SmallVector<AllSwitchPaths, 2> ThreadableLoops; 1263fe6060f1SDimitry Andric bool MadeChanges = false; 1264fe6060f1SDimitry Andric 1265fe6060f1SDimitry Andric for (BasicBlock &BB : F) { 1266fe6060f1SDimitry Andric auto *SI = dyn_cast<SwitchInst>(BB.getTerminator()); 1267fe6060f1SDimitry Andric if (!SI) 1268fe6060f1SDimitry Andric continue; 1269fe6060f1SDimitry Andric 1270fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\nCheck if SwitchInst in BB " << BB.getName() 1271fe6060f1SDimitry Andric << " is predictable\n"); 1272fe6060f1SDimitry Andric MainSwitch Switch(SI, ORE); 1273fe6060f1SDimitry Andric 1274fe6060f1SDimitry Andric if (!Switch.getInstr()) 1275fe6060f1SDimitry Andric continue; 1276fe6060f1SDimitry Andric 1277fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\nSwitchInst in BB " << BB.getName() << " is a " 1278fe6060f1SDimitry Andric << "candidate for jump threading\n"); 1279fe6060f1SDimitry Andric LLVM_DEBUG(SI->dump()); 1280fe6060f1SDimitry Andric 1281fe6060f1SDimitry Andric unfoldSelectInstrs(DT, Switch.getSelectInsts()); 1282fe6060f1SDimitry Andric if (!Switch.getSelectInsts().empty()) 1283fe6060f1SDimitry Andric MadeChanges = true; 1284fe6060f1SDimitry Andric 1285fe6060f1SDimitry Andric AllSwitchPaths SwitchPaths(&Switch, ORE); 1286fe6060f1SDimitry Andric SwitchPaths.run(); 1287fe6060f1SDimitry Andric 1288fe6060f1SDimitry Andric if (SwitchPaths.getNumThreadingPaths() > 0) { 1289fe6060f1SDimitry Andric ThreadableLoops.push_back(SwitchPaths); 1290fe6060f1SDimitry Andric 1291fe6060f1SDimitry Andric // For the time being limit this optimization to occurring once in a 1292fe6060f1SDimitry Andric // function since it can change the CFG significantly. This is not a 1293fe6060f1SDimitry Andric // strict requirement but it can cause buggy behavior if there is an 1294fe6060f1SDimitry Andric // overlap of blocks in different opportunities. There is a lot of room to 1295fe6060f1SDimitry Andric // experiment with catching more opportunities here. 1296fe6060f1SDimitry Andric break; 1297fe6060f1SDimitry Andric } 1298fe6060f1SDimitry Andric } 1299fe6060f1SDimitry Andric 1300fe6060f1SDimitry Andric SmallPtrSet<const Value *, 32> EphValues; 1301fe6060f1SDimitry Andric if (ThreadableLoops.size() > 0) 1302fe6060f1SDimitry Andric CodeMetrics::collectEphemeralValues(&F, AC, EphValues); 1303fe6060f1SDimitry Andric 1304fe6060f1SDimitry Andric for (AllSwitchPaths SwitchPaths : ThreadableLoops) { 1305fe6060f1SDimitry Andric TransformDFA Transform(&SwitchPaths, DT, AC, TTI, ORE, EphValues); 1306fe6060f1SDimitry Andric Transform.run(); 1307fe6060f1SDimitry Andric MadeChanges = true; 1308fe6060f1SDimitry Andric } 1309fe6060f1SDimitry Andric 1310fe6060f1SDimitry Andric #ifdef EXPENSIVE_CHECKS 1311fe6060f1SDimitry Andric assert(DT->verify(DominatorTree::VerificationLevel::Full)); 1312fe6060f1SDimitry Andric verifyFunction(F, &dbgs()); 1313fe6060f1SDimitry Andric #endif 1314fe6060f1SDimitry Andric 1315fe6060f1SDimitry Andric return MadeChanges; 1316fe6060f1SDimitry Andric } 1317fe6060f1SDimitry Andric 1318fe6060f1SDimitry Andric } // end anonymous namespace 1319fe6060f1SDimitry Andric 1320fe6060f1SDimitry Andric /// Integrate with the new Pass Manager 1321fe6060f1SDimitry Andric PreservedAnalyses DFAJumpThreadingPass::run(Function &F, 1322fe6060f1SDimitry Andric FunctionAnalysisManager &AM) { 1323fe6060f1SDimitry Andric AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F); 1324fe6060f1SDimitry Andric DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F); 1325fe6060f1SDimitry Andric TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F); 1326fe6060f1SDimitry Andric OptimizationRemarkEmitter ORE(&F); 1327fe6060f1SDimitry Andric 1328fe6060f1SDimitry Andric if (!DFAJumpThreading(&AC, &DT, &TTI, &ORE).run(F)) 1329fe6060f1SDimitry Andric return PreservedAnalyses::all(); 1330fe6060f1SDimitry Andric 1331fe6060f1SDimitry Andric PreservedAnalyses PA; 1332fe6060f1SDimitry Andric PA.preserve<DominatorTreeAnalysis>(); 1333fe6060f1SDimitry Andric return PA; 1334fe6060f1SDimitry Andric } 1335