102077da7SAlexey Zhikhartsev //===- DFAJumpThreading.cpp - Threads a switch statement inside a loop ----===//
202077da7SAlexey Zhikhartsev //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
602077da7SAlexey Zhikhartsev //
702077da7SAlexey Zhikhartsev //===----------------------------------------------------------------------===//
802077da7SAlexey Zhikhartsev //
902077da7SAlexey Zhikhartsev // Transform each threading path to effectively jump thread the DFA. For
1002077da7SAlexey Zhikhartsev // example, the CFG below could be transformed as follows, where the cloned
1102077da7SAlexey Zhikhartsev // blocks unconditionally branch to the next correct case based on what is
1202077da7SAlexey Zhikhartsev // identified in the analysis.
1302077da7SAlexey Zhikhartsev //
1402077da7SAlexey Zhikhartsev //          sw.bb                        sw.bb
1502077da7SAlexey Zhikhartsev //        /   |   \                    /   |   \
1602077da7SAlexey Zhikhartsev //   case1  case2  case3          case1  case2  case3
1702077da7SAlexey Zhikhartsev //        \   |   /                 |      |      |
1802077da7SAlexey Zhikhartsev //       determinator            det.2   det.3  det.1
1902077da7SAlexey Zhikhartsev //        br sw.bb                /        |        \
2002077da7SAlexey Zhikhartsev //                          sw.bb.2     sw.bb.3     sw.bb.1
2102077da7SAlexey Zhikhartsev //                           br case2    br case3    br case1§
2202077da7SAlexey Zhikhartsev //
2302077da7SAlexey Zhikhartsev // Definitions and Terminology:
2402077da7SAlexey Zhikhartsev //
2502077da7SAlexey Zhikhartsev // * Threading path:
2602077da7SAlexey Zhikhartsev //   a list of basic blocks, the exit state, and the block that determines
2702077da7SAlexey Zhikhartsev //   the next state, for which the following notation will be used:
2802077da7SAlexey Zhikhartsev //   < path of BBs that form a cycle > [ state, determinator ]
2902077da7SAlexey Zhikhartsev //
3002077da7SAlexey Zhikhartsev // * Predictable switch:
3102077da7SAlexey Zhikhartsev //   The switch variable is always a known constant so that all conditional
3202077da7SAlexey Zhikhartsev //   jumps based on switch variable can be converted to unconditional jump.
3302077da7SAlexey Zhikhartsev //
3402077da7SAlexey Zhikhartsev // * Determinator:
3502077da7SAlexey Zhikhartsev //   The basic block that determines the next state of the DFA.
3602077da7SAlexey Zhikhartsev //
3702077da7SAlexey Zhikhartsev // Representing the optimization in C-like pseudocode: the code pattern on the
3802077da7SAlexey Zhikhartsev // left could functionally be transformed to the right pattern if the switch
3902077da7SAlexey Zhikhartsev // condition is predictable.
4002077da7SAlexey Zhikhartsev //
4102077da7SAlexey Zhikhartsev //  X = A                       goto A
4202077da7SAlexey Zhikhartsev //  for (...)                   A:
4302077da7SAlexey Zhikhartsev //    switch (X)                  ...
4402077da7SAlexey Zhikhartsev //      case A                    goto B
4502077da7SAlexey Zhikhartsev //        X = B                 B:
4602077da7SAlexey Zhikhartsev //      case B                    ...
4702077da7SAlexey Zhikhartsev //        X = C                   goto C
4802077da7SAlexey Zhikhartsev //
4902077da7SAlexey Zhikhartsev // The pass first checks that switch variable X is decided by the control flow
5002077da7SAlexey Zhikhartsev // path taken in the loop; for example, in case B, the next value of X is
5102077da7SAlexey Zhikhartsev // decided to be C. It then enumerates through all paths in the loop and labels
5202077da7SAlexey Zhikhartsev // the basic blocks where the next state is decided.
5302077da7SAlexey Zhikhartsev //
5402077da7SAlexey Zhikhartsev // Using this information it creates new paths that unconditionally branch to
5502077da7SAlexey Zhikhartsev // the next case. This involves cloning code, so it only gets triggered if the
5602077da7SAlexey Zhikhartsev // amount of code duplicated is below a threshold.
5702077da7SAlexey Zhikhartsev //
5802077da7SAlexey Zhikhartsev //===----------------------------------------------------------------------===//
5902077da7SAlexey Zhikhartsev 
6002077da7SAlexey Zhikhartsev #include "llvm/Transforms/Scalar/DFAJumpThreading.h"
6102077da7SAlexey Zhikhartsev #include "llvm/ADT/APInt.h"
6202077da7SAlexey Zhikhartsev #include "llvm/ADT/DenseMap.h"
6302077da7SAlexey Zhikhartsev #include "llvm/ADT/SmallSet.h"
6402077da7SAlexey Zhikhartsev #include "llvm/ADT/Statistic.h"
6502077da7SAlexey Zhikhartsev #include "llvm/Analysis/AssumptionCache.h"
6602077da7SAlexey Zhikhartsev #include "llvm/Analysis/CodeMetrics.h"
67a494ae43Sserge-sans-paille #include "llvm/Analysis/DomTreeUpdater.h"
6802077da7SAlexey Zhikhartsev #include "llvm/Analysis/OptimizationRemarkEmitter.h"
6902077da7SAlexey Zhikhartsev #include "llvm/Analysis/TargetTransformInfo.h"
7002077da7SAlexey Zhikhartsev #include "llvm/IR/CFG.h"
7102077da7SAlexey Zhikhartsev #include "llvm/IR/Constants.h"
7202077da7SAlexey Zhikhartsev #include "llvm/IR/IntrinsicInst.h"
7302077da7SAlexey Zhikhartsev #include "llvm/InitializePasses.h"
7402077da7SAlexey Zhikhartsev #include "llvm/Pass.h"
7502077da7SAlexey Zhikhartsev #include "llvm/Support/CommandLine.h"
7602077da7SAlexey Zhikhartsev #include "llvm/Support/Debug.h"
7702077da7SAlexey Zhikhartsev #include "llvm/Transforms/Scalar.h"
7802077da7SAlexey Zhikhartsev #include "llvm/Transforms/Utils/Cloning.h"
7902077da7SAlexey Zhikhartsev #include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
8002077da7SAlexey Zhikhartsev #include "llvm/Transforms/Utils/ValueMapper.h"
8102077da7SAlexey Zhikhartsev #include <algorithm>
8202077da7SAlexey Zhikhartsev #include <deque>
8302077da7SAlexey Zhikhartsev 
84f90a66a5Sserge-sans-paille #ifdef EXPENSIVE_CHECKS
85f90a66a5Sserge-sans-paille #include "llvm/IR/Verifier.h"
86f90a66a5Sserge-sans-paille #endif
87f90a66a5Sserge-sans-paille 
8802077da7SAlexey Zhikhartsev using namespace llvm;
8902077da7SAlexey Zhikhartsev 
9002077da7SAlexey Zhikhartsev #define DEBUG_TYPE "dfa-jump-threading"
9102077da7SAlexey Zhikhartsev 
9202077da7SAlexey Zhikhartsev STATISTIC(NumTransforms, "Number of transformations done");
9302077da7SAlexey Zhikhartsev STATISTIC(NumCloned, "Number of blocks cloned");
9402077da7SAlexey Zhikhartsev STATISTIC(NumPaths, "Number of individual paths threaded");
9502077da7SAlexey Zhikhartsev 
9602077da7SAlexey Zhikhartsev static cl::opt<bool>
9702077da7SAlexey Zhikhartsev     ClViewCfgBefore("dfa-jump-view-cfg-before",
9802077da7SAlexey Zhikhartsev                     cl::desc("View the CFG before DFA Jump Threading"),
9902077da7SAlexey Zhikhartsev                     cl::Hidden, cl::init(false));
10002077da7SAlexey Zhikhartsev 
10102077da7SAlexey Zhikhartsev static cl::opt<unsigned> MaxPathLength(
10202077da7SAlexey Zhikhartsev     "dfa-max-path-length",
10302077da7SAlexey Zhikhartsev     cl::desc("Max number of blocks searched to find a threading path"),
10402077da7SAlexey Zhikhartsev     cl::Hidden, cl::init(20));
10502077da7SAlexey Zhikhartsev 
1068b0d7634SAlex Zhikhartsev static cl::opt<unsigned> MaxNumPaths(
1078b0d7634SAlex Zhikhartsev     "dfa-max-num-paths",
1088b0d7634SAlex Zhikhartsev     cl::desc("Max number of paths enumerated around a switch"),
1098b0d7634SAlex Zhikhartsev     cl::Hidden, cl::init(200));
1108b0d7634SAlex Zhikhartsev 
11102077da7SAlexey Zhikhartsev static cl::opt<unsigned>
11202077da7SAlexey Zhikhartsev     CostThreshold("dfa-cost-threshold",
11302077da7SAlexey Zhikhartsev                   cl::desc("Maximum cost accepted for the transformation"),
11402077da7SAlexey Zhikhartsev                   cl::Hidden, cl::init(50));
11502077da7SAlexey Zhikhartsev 
11602077da7SAlexey Zhikhartsev namespace {
11702077da7SAlexey Zhikhartsev 
11802077da7SAlexey Zhikhartsev class SelectInstToUnfold {
11902077da7SAlexey Zhikhartsev   SelectInst *SI;
12002077da7SAlexey Zhikhartsev   PHINode *SIUse;
12102077da7SAlexey Zhikhartsev 
12202077da7SAlexey Zhikhartsev public:
SelectInstToUnfold(SelectInst * SI,PHINode * SIUse)12302077da7SAlexey Zhikhartsev   SelectInstToUnfold(SelectInst *SI, PHINode *SIUse) : SI(SI), SIUse(SIUse) {}
12402077da7SAlexey Zhikhartsev 
getInst()12502077da7SAlexey Zhikhartsev   SelectInst *getInst() { return SI; }
getUse()12602077da7SAlexey Zhikhartsev   PHINode *getUse() { return SIUse; }
12702077da7SAlexey Zhikhartsev 
operator bool() const12802077da7SAlexey Zhikhartsev   explicit operator bool() const { return SI && SIUse; }
12902077da7SAlexey Zhikhartsev };
13002077da7SAlexey Zhikhartsev 
13102077da7SAlexey Zhikhartsev void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold,
13202077da7SAlexey Zhikhartsev             std::vector<SelectInstToUnfold> *NewSIsToUnfold,
13302077da7SAlexey Zhikhartsev             std::vector<BasicBlock *> *NewBBs);
13402077da7SAlexey Zhikhartsev 
13502077da7SAlexey Zhikhartsev class DFAJumpThreading {
13602077da7SAlexey Zhikhartsev public:
DFAJumpThreading(AssumptionCache * AC,DominatorTree * DT,TargetTransformInfo * TTI,OptimizationRemarkEmitter * ORE)13702077da7SAlexey Zhikhartsev   DFAJumpThreading(AssumptionCache *AC, DominatorTree *DT,
13802077da7SAlexey Zhikhartsev                    TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE)
13902077da7SAlexey Zhikhartsev       : AC(AC), DT(DT), TTI(TTI), ORE(ORE) {}
14002077da7SAlexey Zhikhartsev 
14102077da7SAlexey Zhikhartsev   bool run(Function &F);
14202077da7SAlexey Zhikhartsev 
14302077da7SAlexey Zhikhartsev private:
14402077da7SAlexey Zhikhartsev   void
unfoldSelectInstrs(DominatorTree * DT,const SmallVector<SelectInstToUnfold,4> & SelectInsts)14502077da7SAlexey Zhikhartsev   unfoldSelectInstrs(DominatorTree *DT,
14602077da7SAlexey Zhikhartsev                      const SmallVector<SelectInstToUnfold, 4> &SelectInsts) {
14702077da7SAlexey Zhikhartsev     DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
14802077da7SAlexey Zhikhartsev     SmallVector<SelectInstToUnfold, 4> Stack;
14902077da7SAlexey Zhikhartsev     for (SelectInstToUnfold SIToUnfold : SelectInsts)
15002077da7SAlexey Zhikhartsev       Stack.push_back(SIToUnfold);
15102077da7SAlexey Zhikhartsev 
15202077da7SAlexey Zhikhartsev     while (!Stack.empty()) {
15384b07c9bSKazu Hirata       SelectInstToUnfold SIToUnfold = Stack.pop_back_val();
15402077da7SAlexey Zhikhartsev 
15502077da7SAlexey Zhikhartsev       std::vector<SelectInstToUnfold> NewSIsToUnfold;
15602077da7SAlexey Zhikhartsev       std::vector<BasicBlock *> NewBBs;
15702077da7SAlexey Zhikhartsev       unfold(&DTU, SIToUnfold, &NewSIsToUnfold, &NewBBs);
15802077da7SAlexey Zhikhartsev 
15902077da7SAlexey Zhikhartsev       // Put newly discovered select instructions into the work list.
16002077da7SAlexey Zhikhartsev       for (const SelectInstToUnfold &NewSIToUnfold : NewSIsToUnfold)
16102077da7SAlexey Zhikhartsev         Stack.push_back(NewSIToUnfold);
16202077da7SAlexey Zhikhartsev     }
16302077da7SAlexey Zhikhartsev   }
16402077da7SAlexey Zhikhartsev 
16502077da7SAlexey Zhikhartsev   AssumptionCache *AC;
16602077da7SAlexey Zhikhartsev   DominatorTree *DT;
16702077da7SAlexey Zhikhartsev   TargetTransformInfo *TTI;
16802077da7SAlexey Zhikhartsev   OptimizationRemarkEmitter *ORE;
16902077da7SAlexey Zhikhartsev };
17002077da7SAlexey Zhikhartsev 
17102077da7SAlexey Zhikhartsev class DFAJumpThreadingLegacyPass : public FunctionPass {
17202077da7SAlexey Zhikhartsev public:
17302077da7SAlexey Zhikhartsev   static char ID; // Pass identification
DFAJumpThreadingLegacyPass()17402077da7SAlexey Zhikhartsev   DFAJumpThreadingLegacyPass() : FunctionPass(ID) {}
17502077da7SAlexey Zhikhartsev 
getAnalysisUsage(AnalysisUsage & AU) const17602077da7SAlexey Zhikhartsev   void getAnalysisUsage(AnalysisUsage &AU) const override {
17702077da7SAlexey Zhikhartsev     AU.addRequired<AssumptionCacheTracker>();
17802077da7SAlexey Zhikhartsev     AU.addRequired<DominatorTreeWrapperPass>();
179e97524cbSNikita Popov     AU.addPreserved<DominatorTreeWrapperPass>();
18002077da7SAlexey Zhikhartsev     AU.addRequired<TargetTransformInfoWrapperPass>();
18102077da7SAlexey Zhikhartsev     AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
18202077da7SAlexey Zhikhartsev   }
18302077da7SAlexey Zhikhartsev 
runOnFunction(Function & F)18402077da7SAlexey Zhikhartsev   bool runOnFunction(Function &F) override {
18502077da7SAlexey Zhikhartsev     if (skipFunction(F))
18602077da7SAlexey Zhikhartsev       return false;
18702077da7SAlexey Zhikhartsev 
18802077da7SAlexey Zhikhartsev     AssumptionCache *AC =
18902077da7SAlexey Zhikhartsev         &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
19002077da7SAlexey Zhikhartsev     DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
19102077da7SAlexey Zhikhartsev     TargetTransformInfo *TTI =
19202077da7SAlexey Zhikhartsev         &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
19302077da7SAlexey Zhikhartsev     OptimizationRemarkEmitter *ORE =
19402077da7SAlexey Zhikhartsev         &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
19502077da7SAlexey Zhikhartsev 
19602077da7SAlexey Zhikhartsev     return DFAJumpThreading(AC, DT, TTI, ORE).run(F);
19702077da7SAlexey Zhikhartsev   }
19802077da7SAlexey Zhikhartsev };
19902077da7SAlexey Zhikhartsev } // end anonymous namespace
20002077da7SAlexey Zhikhartsev 
20102077da7SAlexey Zhikhartsev char DFAJumpThreadingLegacyPass::ID = 0;
20202077da7SAlexey Zhikhartsev INITIALIZE_PASS_BEGIN(DFAJumpThreadingLegacyPass, "dfa-jump-threading",
20302077da7SAlexey Zhikhartsev                       "DFA Jump Threading", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)20402077da7SAlexey Zhikhartsev INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
20502077da7SAlexey Zhikhartsev INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
20602077da7SAlexey Zhikhartsev INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
20702077da7SAlexey Zhikhartsev INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
20802077da7SAlexey Zhikhartsev INITIALIZE_PASS_END(DFAJumpThreadingLegacyPass, "dfa-jump-threading",
20902077da7SAlexey Zhikhartsev                     "DFA Jump Threading", false, false)
21002077da7SAlexey Zhikhartsev 
21102077da7SAlexey Zhikhartsev // Public interface to the DFA Jump Threading pass
21202077da7SAlexey Zhikhartsev FunctionPass *llvm::createDFAJumpThreadingPass() {
21302077da7SAlexey Zhikhartsev   return new DFAJumpThreadingLegacyPass();
21402077da7SAlexey Zhikhartsev }
21502077da7SAlexey Zhikhartsev 
21602077da7SAlexey Zhikhartsev namespace {
21702077da7SAlexey Zhikhartsev 
21802077da7SAlexey Zhikhartsev /// Create a new basic block and sink \p SIToSink into it.
createBasicBlockAndSinkSelectInst(DomTreeUpdater * DTU,SelectInst * SI,PHINode * SIUse,SelectInst * SIToSink,BasicBlock * EndBlock,StringRef NewBBName,BasicBlock ** NewBlock,BranchInst ** NewBranch,std::vector<SelectInstToUnfold> * NewSIsToUnfold,std::vector<BasicBlock * > * NewBBs)21902077da7SAlexey Zhikhartsev void createBasicBlockAndSinkSelectInst(
22002077da7SAlexey Zhikhartsev     DomTreeUpdater *DTU, SelectInst *SI, PHINode *SIUse, SelectInst *SIToSink,
22102077da7SAlexey Zhikhartsev     BasicBlock *EndBlock, StringRef NewBBName, BasicBlock **NewBlock,
22202077da7SAlexey Zhikhartsev     BranchInst **NewBranch, std::vector<SelectInstToUnfold> *NewSIsToUnfold,
22302077da7SAlexey Zhikhartsev     std::vector<BasicBlock *> *NewBBs) {
22402077da7SAlexey Zhikhartsev   assert(SIToSink->hasOneUse());
22502077da7SAlexey Zhikhartsev   assert(NewBlock);
22602077da7SAlexey Zhikhartsev   assert(NewBranch);
22702077da7SAlexey Zhikhartsev   *NewBlock = BasicBlock::Create(SI->getContext(), NewBBName,
22802077da7SAlexey Zhikhartsev                                  EndBlock->getParent(), EndBlock);
22902077da7SAlexey Zhikhartsev   NewBBs->push_back(*NewBlock);
23002077da7SAlexey Zhikhartsev   *NewBranch = BranchInst::Create(EndBlock, *NewBlock);
23102077da7SAlexey Zhikhartsev   SIToSink->moveBefore(*NewBranch);
23202077da7SAlexey Zhikhartsev   NewSIsToUnfold->push_back(SelectInstToUnfold(SIToSink, SIUse));
23302077da7SAlexey Zhikhartsev   DTU->applyUpdates({{DominatorTree::Insert, *NewBlock, EndBlock}});
23402077da7SAlexey Zhikhartsev }
23502077da7SAlexey Zhikhartsev 
23602077da7SAlexey Zhikhartsev /// Unfold the select instruction held in \p SIToUnfold by replacing it with
23702077da7SAlexey Zhikhartsev /// control flow.
23802077da7SAlexey Zhikhartsev ///
23902077da7SAlexey Zhikhartsev /// Put newly discovered select instructions into \p NewSIsToUnfold. Put newly
24002077da7SAlexey Zhikhartsev /// created basic blocks into \p NewBBs.
24102077da7SAlexey Zhikhartsev ///
24202077da7SAlexey Zhikhartsev /// TODO: merge it with CodeGenPrepare::optimizeSelectInst() if possible.
unfold(DomTreeUpdater * DTU,SelectInstToUnfold SIToUnfold,std::vector<SelectInstToUnfold> * NewSIsToUnfold,std::vector<BasicBlock * > * NewBBs)24302077da7SAlexey Zhikhartsev void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold,
24402077da7SAlexey Zhikhartsev             std::vector<SelectInstToUnfold> *NewSIsToUnfold,
24502077da7SAlexey Zhikhartsev             std::vector<BasicBlock *> *NewBBs) {
24602077da7SAlexey Zhikhartsev   SelectInst *SI = SIToUnfold.getInst();
24702077da7SAlexey Zhikhartsev   PHINode *SIUse = SIToUnfold.getUse();
24802077da7SAlexey Zhikhartsev   BasicBlock *StartBlock = SI->getParent();
24902077da7SAlexey Zhikhartsev   BasicBlock *EndBlock = SIUse->getParent();
25002077da7SAlexey Zhikhartsev   BranchInst *StartBlockTerm =
25102077da7SAlexey Zhikhartsev       dyn_cast<BranchInst>(StartBlock->getTerminator());
25202077da7SAlexey Zhikhartsev 
25302077da7SAlexey Zhikhartsev   assert(StartBlockTerm && StartBlockTerm->isUnconditional());
25402077da7SAlexey Zhikhartsev   assert(SI->hasOneUse());
25502077da7SAlexey Zhikhartsev 
25602077da7SAlexey Zhikhartsev   // These are the new basic blocks for the conditional branch.
25702077da7SAlexey Zhikhartsev   // At least one will become an actual new basic block.
25802077da7SAlexey Zhikhartsev   BasicBlock *TrueBlock = nullptr;
25902077da7SAlexey Zhikhartsev   BasicBlock *FalseBlock = nullptr;
26002077da7SAlexey Zhikhartsev   BranchInst *TrueBranch = nullptr;
26102077da7SAlexey Zhikhartsev   BranchInst *FalseBranch = nullptr;
26202077da7SAlexey Zhikhartsev 
26302077da7SAlexey Zhikhartsev   // Sink select instructions to be able to unfold them later.
26402077da7SAlexey Zhikhartsev   if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getTrueValue())) {
26502077da7SAlexey Zhikhartsev     createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock,
26602077da7SAlexey Zhikhartsev                                       "si.unfold.true", &TrueBlock, &TrueBranch,
26702077da7SAlexey Zhikhartsev                                       NewSIsToUnfold, NewBBs);
26802077da7SAlexey Zhikhartsev   }
26902077da7SAlexey Zhikhartsev   if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getFalseValue())) {
27002077da7SAlexey Zhikhartsev     createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock,
27102077da7SAlexey Zhikhartsev                                       "si.unfold.false", &FalseBlock,
27202077da7SAlexey Zhikhartsev                                       &FalseBranch, NewSIsToUnfold, NewBBs);
27302077da7SAlexey Zhikhartsev   }
27402077da7SAlexey Zhikhartsev 
27502077da7SAlexey Zhikhartsev   // If there was nothing to sink, then arbitrarily choose the 'false' side
27602077da7SAlexey Zhikhartsev   // for a new input value to the PHI.
27702077da7SAlexey Zhikhartsev   if (!TrueBlock && !FalseBlock) {
27802077da7SAlexey Zhikhartsev     FalseBlock = BasicBlock::Create(SI->getContext(), "si.unfold.false",
27902077da7SAlexey Zhikhartsev                                     EndBlock->getParent(), EndBlock);
28002077da7SAlexey Zhikhartsev     NewBBs->push_back(FalseBlock);
28102077da7SAlexey Zhikhartsev     BranchInst::Create(EndBlock, FalseBlock);
28202077da7SAlexey Zhikhartsev     DTU->applyUpdates({{DominatorTree::Insert, FalseBlock, EndBlock}});
28302077da7SAlexey Zhikhartsev   }
28402077da7SAlexey Zhikhartsev 
28502077da7SAlexey Zhikhartsev   // Insert the real conditional branch based on the original condition.
28602077da7SAlexey Zhikhartsev   // If we did not create a new block for one of the 'true' or 'false' paths
28702077da7SAlexey Zhikhartsev   // of the condition, it means that side of the branch goes to the end block
28802077da7SAlexey Zhikhartsev   // directly and the path originates from the start block from the point of
28902077da7SAlexey Zhikhartsev   // view of the new PHI.
29002077da7SAlexey Zhikhartsev   BasicBlock *TT = EndBlock;
29102077da7SAlexey Zhikhartsev   BasicBlock *FT = EndBlock;
29202077da7SAlexey Zhikhartsev   if (TrueBlock && FalseBlock) {
29302077da7SAlexey Zhikhartsev     // A diamond.
29402077da7SAlexey Zhikhartsev     TT = TrueBlock;
29502077da7SAlexey Zhikhartsev     FT = FalseBlock;
29602077da7SAlexey Zhikhartsev 
29702077da7SAlexey Zhikhartsev     // Update the phi node of SI.
29802077da7SAlexey Zhikhartsev     SIUse->removeIncomingValue(StartBlock, /* DeletePHIIfEmpty = */ false);
29902077da7SAlexey Zhikhartsev     SIUse->addIncoming(SI->getTrueValue(), TrueBlock);
30002077da7SAlexey Zhikhartsev     SIUse->addIncoming(SI->getFalseValue(), FalseBlock);
30102077da7SAlexey Zhikhartsev 
30202077da7SAlexey Zhikhartsev     // Update any other PHI nodes in EndBlock.
30302077da7SAlexey Zhikhartsev     for (PHINode &Phi : EndBlock->phis()) {
30402077da7SAlexey Zhikhartsev       if (&Phi != SIUse) {
30502077da7SAlexey Zhikhartsev         Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), TrueBlock);
30602077da7SAlexey Zhikhartsev         Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), FalseBlock);
30702077da7SAlexey Zhikhartsev       }
30802077da7SAlexey Zhikhartsev     }
30902077da7SAlexey Zhikhartsev   } else {
31002077da7SAlexey Zhikhartsev     BasicBlock *NewBlock = nullptr;
31102077da7SAlexey Zhikhartsev     Value *SIOp1 = SI->getTrueValue();
31202077da7SAlexey Zhikhartsev     Value *SIOp2 = SI->getFalseValue();
31302077da7SAlexey Zhikhartsev 
31402077da7SAlexey Zhikhartsev     // A triangle pointing right.
31502077da7SAlexey Zhikhartsev     if (!TrueBlock) {
31602077da7SAlexey Zhikhartsev       NewBlock = FalseBlock;
31702077da7SAlexey Zhikhartsev       FT = FalseBlock;
31802077da7SAlexey Zhikhartsev     }
31902077da7SAlexey Zhikhartsev     // A triangle pointing left.
32002077da7SAlexey Zhikhartsev     else {
32102077da7SAlexey Zhikhartsev       NewBlock = TrueBlock;
32202077da7SAlexey Zhikhartsev       TT = TrueBlock;
32302077da7SAlexey Zhikhartsev       std::swap(SIOp1, SIOp2);
32402077da7SAlexey Zhikhartsev     }
32502077da7SAlexey Zhikhartsev 
32602077da7SAlexey Zhikhartsev     // Update the phi node of SI.
32702077da7SAlexey Zhikhartsev     for (unsigned Idx = 0; Idx < SIUse->getNumIncomingValues(); ++Idx) {
32802077da7SAlexey Zhikhartsev       if (SIUse->getIncomingBlock(Idx) == StartBlock)
32902077da7SAlexey Zhikhartsev         SIUse->setIncomingValue(Idx, SIOp1);
33002077da7SAlexey Zhikhartsev     }
33102077da7SAlexey Zhikhartsev     SIUse->addIncoming(SIOp2, NewBlock);
33202077da7SAlexey Zhikhartsev 
33302077da7SAlexey Zhikhartsev     // Update any other PHI nodes in EndBlock.
33402077da7SAlexey Zhikhartsev     for (auto II = EndBlock->begin(); PHINode *Phi = dyn_cast<PHINode>(II);
33502077da7SAlexey Zhikhartsev          ++II) {
33602077da7SAlexey Zhikhartsev       if (Phi != SIUse)
33702077da7SAlexey Zhikhartsev         Phi->addIncoming(Phi->getIncomingValueForBlock(StartBlock), NewBlock);
33802077da7SAlexey Zhikhartsev     }
33902077da7SAlexey Zhikhartsev   }
34002077da7SAlexey Zhikhartsev   StartBlockTerm->eraseFromParent();
34102077da7SAlexey Zhikhartsev   BranchInst::Create(TT, FT, SI->getCondition(), StartBlock);
34202077da7SAlexey Zhikhartsev   DTU->applyUpdates({{DominatorTree::Insert, StartBlock, TT},
34302077da7SAlexey Zhikhartsev                      {DominatorTree::Insert, StartBlock, FT}});
34402077da7SAlexey Zhikhartsev 
34502077da7SAlexey Zhikhartsev   // The select is now dead.
34602077da7SAlexey Zhikhartsev   SI->eraseFromParent();
34702077da7SAlexey Zhikhartsev }
34802077da7SAlexey Zhikhartsev 
34902077da7SAlexey Zhikhartsev struct ClonedBlock {
35002077da7SAlexey Zhikhartsev   BasicBlock *BB;
35102077da7SAlexey Zhikhartsev   uint64_t State; ///< \p State corresponds to the next value of a switch stmnt.
35202077da7SAlexey Zhikhartsev };
35302077da7SAlexey Zhikhartsev 
35402077da7SAlexey Zhikhartsev typedef std::deque<BasicBlock *> PathType;
35502077da7SAlexey Zhikhartsev typedef std::vector<PathType> PathsType;
356380b8a60SNikita Popov typedef SmallPtrSet<const BasicBlock *, 8> VisitedBlocks;
35702077da7SAlexey Zhikhartsev typedef std::vector<ClonedBlock> CloneList;
35802077da7SAlexey Zhikhartsev 
35902077da7SAlexey Zhikhartsev // This data structure keeps track of all blocks that have been cloned.  If two
36002077da7SAlexey Zhikhartsev // different ThreadingPaths clone the same block for a certain state it should
36102077da7SAlexey Zhikhartsev // be reused, and it can be looked up in this map.
36202077da7SAlexey Zhikhartsev typedef DenseMap<BasicBlock *, CloneList> DuplicateBlockMap;
36302077da7SAlexey Zhikhartsev 
36402077da7SAlexey Zhikhartsev // This map keeps track of all the new definitions for an instruction. This
36502077da7SAlexey Zhikhartsev // information is needed when restoring SSA form after cloning blocks.
3669d555b4aSOlle Fredriksson typedef MapVector<Instruction *, std::vector<Instruction *>> DefMap;
36702077da7SAlexey Zhikhartsev 
operator <<(raw_ostream & OS,const PathType & Path)36802077da7SAlexey Zhikhartsev inline raw_ostream &operator<<(raw_ostream &OS, const PathType &Path) {
36902077da7SAlexey Zhikhartsev   OS << "< ";
37002077da7SAlexey Zhikhartsev   for (const BasicBlock *BB : Path) {
37102077da7SAlexey Zhikhartsev     std::string BBName;
37202077da7SAlexey Zhikhartsev     if (BB->hasName())
37302077da7SAlexey Zhikhartsev       raw_string_ostream(BBName) << BB->getName();
37402077da7SAlexey Zhikhartsev     else
37502077da7SAlexey Zhikhartsev       raw_string_ostream(BBName) << BB;
37602077da7SAlexey Zhikhartsev     OS << BBName << " ";
37702077da7SAlexey Zhikhartsev   }
37802077da7SAlexey Zhikhartsev   OS << ">";
37902077da7SAlexey Zhikhartsev   return OS;
38002077da7SAlexey Zhikhartsev }
38102077da7SAlexey Zhikhartsev 
38202077da7SAlexey Zhikhartsev /// ThreadingPath is a path in the control flow of a loop that can be threaded
38302077da7SAlexey Zhikhartsev /// by cloning necessary basic blocks and replacing conditional branches with
38402077da7SAlexey Zhikhartsev /// unconditional ones. A threading path includes a list of basic blocks, the
38502077da7SAlexey Zhikhartsev /// exit state, and the block that determines the next state.
38602077da7SAlexey Zhikhartsev struct ThreadingPath {
38702077da7SAlexey Zhikhartsev   /// Exit value is DFA's exit state for the given path.
getExitValue__anon91a52f600211::ThreadingPath38802077da7SAlexey Zhikhartsev   uint64_t getExitValue() const { return ExitVal; }
setExitValue__anon91a52f600211::ThreadingPath38902077da7SAlexey Zhikhartsev   void setExitValue(const ConstantInt *V) {
39002077da7SAlexey Zhikhartsev     ExitVal = V->getZExtValue();
39102077da7SAlexey Zhikhartsev     IsExitValSet = true;
39202077da7SAlexey Zhikhartsev   }
isExitValueSet__anon91a52f600211::ThreadingPath39302077da7SAlexey Zhikhartsev   bool isExitValueSet() const { return IsExitValSet; }
39402077da7SAlexey Zhikhartsev 
39502077da7SAlexey Zhikhartsev   /// Determinator is the basic block that determines the next state of the DFA.
getDeterminatorBB__anon91a52f600211::ThreadingPath39602077da7SAlexey Zhikhartsev   const BasicBlock *getDeterminatorBB() const { return DBB; }
setDeterminator__anon91a52f600211::ThreadingPath39702077da7SAlexey Zhikhartsev   void setDeterminator(const BasicBlock *BB) { DBB = BB; }
39802077da7SAlexey Zhikhartsev 
39902077da7SAlexey Zhikhartsev   /// Path is a list of basic blocks.
getPath__anon91a52f600211::ThreadingPath40002077da7SAlexey Zhikhartsev   const PathType &getPath() const { return Path; }
setPath__anon91a52f600211::ThreadingPath40102077da7SAlexey Zhikhartsev   void setPath(const PathType &NewPath) { Path = NewPath; }
40202077da7SAlexey Zhikhartsev 
print__anon91a52f600211::ThreadingPath40302077da7SAlexey Zhikhartsev   void print(raw_ostream &OS) const {
40402077da7SAlexey Zhikhartsev     OS << Path << " [ " << ExitVal << ", " << DBB->getName() << " ]";
40502077da7SAlexey Zhikhartsev   }
40602077da7SAlexey Zhikhartsev 
40702077da7SAlexey Zhikhartsev private:
40802077da7SAlexey Zhikhartsev   PathType Path;
40902077da7SAlexey Zhikhartsev   uint64_t ExitVal;
41002077da7SAlexey Zhikhartsev   const BasicBlock *DBB = nullptr;
41102077da7SAlexey Zhikhartsev   bool IsExitValSet = false;
41202077da7SAlexey Zhikhartsev };
41302077da7SAlexey Zhikhartsev 
41402077da7SAlexey Zhikhartsev #ifndef NDEBUG
operator <<(raw_ostream & OS,const ThreadingPath & TPath)41502077da7SAlexey Zhikhartsev inline raw_ostream &operator<<(raw_ostream &OS, const ThreadingPath &TPath) {
41602077da7SAlexey Zhikhartsev   TPath.print(OS);
41702077da7SAlexey Zhikhartsev   return OS;
41802077da7SAlexey Zhikhartsev }
41902077da7SAlexey Zhikhartsev #endif
42002077da7SAlexey Zhikhartsev 
42102077da7SAlexey Zhikhartsev struct MainSwitch {
MainSwitch__anon91a52f600211::MainSwitch42202077da7SAlexey Zhikhartsev   MainSwitch(SwitchInst *SI, OptimizationRemarkEmitter *ORE) {
4238b0d7634SAlex Zhikhartsev     if (isCandidate(SI)) {
42402077da7SAlexey Zhikhartsev       Instr = SI;
42502077da7SAlexey Zhikhartsev     } else {
42602077da7SAlexey Zhikhartsev       ORE->emit([&]() {
42702077da7SAlexey Zhikhartsev         return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable", SI)
42802077da7SAlexey Zhikhartsev                << "Switch instruction is not predictable.";
42902077da7SAlexey Zhikhartsev       });
43002077da7SAlexey Zhikhartsev     }
43102077da7SAlexey Zhikhartsev   }
43202077da7SAlexey Zhikhartsev 
43302077da7SAlexey Zhikhartsev   virtual ~MainSwitch() = default;
43402077da7SAlexey Zhikhartsev 
getInstr__anon91a52f600211::MainSwitch43502077da7SAlexey Zhikhartsev   SwitchInst *getInstr() const { return Instr; }
getSelectInsts__anon91a52f600211::MainSwitch43602077da7SAlexey Zhikhartsev   const SmallVector<SelectInstToUnfold, 4> getSelectInsts() {
43702077da7SAlexey Zhikhartsev     return SelectInsts;
43802077da7SAlexey Zhikhartsev   }
43902077da7SAlexey Zhikhartsev 
44002077da7SAlexey Zhikhartsev private:
4418b0d7634SAlex Zhikhartsev   /// Do a use-def chain traversal starting from the switch condition to see if
4428b0d7634SAlex Zhikhartsev   /// \p SI is a potential condidate.
4438b0d7634SAlex Zhikhartsev   ///
4448b0d7634SAlex Zhikhartsev   /// Also, collect select instructions to unfold.
isCandidate__anon91a52f600211::MainSwitch4458b0d7634SAlex Zhikhartsev   bool isCandidate(const SwitchInst *SI) {
4468b0d7634SAlex Zhikhartsev     std::deque<Value *> Q;
44702077da7SAlexey Zhikhartsev     SmallSet<Value *, 16> SeenValues;
44802077da7SAlexey Zhikhartsev     SelectInsts.clear();
44902077da7SAlexey Zhikhartsev 
4508b0d7634SAlex Zhikhartsev     Value *SICond = SI->getCondition();
4518b0d7634SAlex Zhikhartsev     LLVM_DEBUG(dbgs() << "\tSICond: " << *SICond << "\n");
4528b0d7634SAlex Zhikhartsev     if (!isa<PHINode>(SICond))
45302077da7SAlexey Zhikhartsev       return false;
45402077da7SAlexey Zhikhartsev 
4558b0d7634SAlex Zhikhartsev     addToQueue(SICond, Q, SeenValues);
45602077da7SAlexey Zhikhartsev 
45702077da7SAlexey Zhikhartsev     while (!Q.empty()) {
4588b0d7634SAlex Zhikhartsev       Value *Current = Q.front();
45902077da7SAlexey Zhikhartsev       Q.pop_front();
46002077da7SAlexey Zhikhartsev 
46102077da7SAlexey Zhikhartsev       if (auto *Phi = dyn_cast<PHINode>(Current)) {
46202077da7SAlexey Zhikhartsev         for (Value *Incoming : Phi->incoming_values()) {
4638b0d7634SAlex Zhikhartsev           addToQueue(Incoming, Q, SeenValues);
46402077da7SAlexey Zhikhartsev         }
4658b0d7634SAlex Zhikhartsev         LLVM_DEBUG(dbgs() << "\tphi: " << *Phi << "\n");
46602077da7SAlexey Zhikhartsev       } else if (SelectInst *SelI = dyn_cast<SelectInst>(Current)) {
46702077da7SAlexey Zhikhartsev         if (!isValidSelectInst(SelI))
46802077da7SAlexey Zhikhartsev           return false;
4698b0d7634SAlex Zhikhartsev         addToQueue(SelI->getTrueValue(), Q, SeenValues);
4708b0d7634SAlex Zhikhartsev         addToQueue(SelI->getFalseValue(), Q, SeenValues);
4718b0d7634SAlex Zhikhartsev         LLVM_DEBUG(dbgs() << "\tselect: " << *SelI << "\n");
47202077da7SAlexey Zhikhartsev         if (auto *SelIUse = dyn_cast<PHINode>(SelI->user_back()))
47302077da7SAlexey Zhikhartsev           SelectInsts.push_back(SelectInstToUnfold(SelI, SelIUse));
4748b0d7634SAlex Zhikhartsev       } else if (isa<Constant>(Current)) {
4758b0d7634SAlex Zhikhartsev         LLVM_DEBUG(dbgs() << "\tconst: " << *Current << "\n");
4768b0d7634SAlex Zhikhartsev         continue;
47702077da7SAlexey Zhikhartsev       } else {
4788b0d7634SAlex Zhikhartsev         LLVM_DEBUG(dbgs() << "\tother: " << *Current << "\n");
4798b0d7634SAlex Zhikhartsev         // Allow unpredictable values. The hope is that those will be the
4808b0d7634SAlex Zhikhartsev         // initial switch values that can be ignored (they will hit the
4818b0d7634SAlex Zhikhartsev         // unthreaded switch) but this assumption will get checked later after
4828b0d7634SAlex Zhikhartsev         // paths have been enumerated (in function getStateDefMap).
4838b0d7634SAlex Zhikhartsev         continue;
48402077da7SAlexey Zhikhartsev       }
48502077da7SAlexey Zhikhartsev     }
48602077da7SAlexey Zhikhartsev 
48702077da7SAlexey Zhikhartsev     return true;
48802077da7SAlexey Zhikhartsev   }
48902077da7SAlexey Zhikhartsev 
addToQueue__anon91a52f600211::MainSwitch4908b0d7634SAlex Zhikhartsev   void addToQueue(Value *Val, std::deque<Value *> &Q,
49102077da7SAlexey Zhikhartsev                   SmallSet<Value *, 16> &SeenValues) {
492972d4133SKazu Hirata     if (SeenValues.contains(Val))
49302077da7SAlexey Zhikhartsev       return;
4948b0d7634SAlex Zhikhartsev     Q.push_back(Val);
49502077da7SAlexey Zhikhartsev     SeenValues.insert(Val);
49602077da7SAlexey Zhikhartsev   }
49702077da7SAlexey Zhikhartsev 
isValidSelectInst__anon91a52f600211::MainSwitch49802077da7SAlexey Zhikhartsev   bool isValidSelectInst(SelectInst *SI) {
49902077da7SAlexey Zhikhartsev     if (!SI->hasOneUse())
50002077da7SAlexey Zhikhartsev       return false;
50102077da7SAlexey Zhikhartsev 
50202077da7SAlexey Zhikhartsev     Instruction *SIUse = dyn_cast<Instruction>(SI->user_back());
50302077da7SAlexey Zhikhartsev     // The use of the select inst should be either a phi or another select.
50402077da7SAlexey Zhikhartsev     if (!SIUse && !(isa<PHINode>(SIUse) || isa<SelectInst>(SIUse)))
50502077da7SAlexey Zhikhartsev       return false;
50602077da7SAlexey Zhikhartsev 
50702077da7SAlexey Zhikhartsev     BasicBlock *SIBB = SI->getParent();
50802077da7SAlexey Zhikhartsev 
50902077da7SAlexey Zhikhartsev     // Currently, we can only expand select instructions in basic blocks with
51002077da7SAlexey Zhikhartsev     // one successor.
51102077da7SAlexey Zhikhartsev     BranchInst *SITerm = dyn_cast<BranchInst>(SIBB->getTerminator());
51202077da7SAlexey Zhikhartsev     if (!SITerm || !SITerm->isUnconditional())
51302077da7SAlexey Zhikhartsev       return false;
51402077da7SAlexey Zhikhartsev 
51502077da7SAlexey Zhikhartsev     if (isa<PHINode>(SIUse) &&
516c1f3bab2SSimon Pilgrim         SIBB->getSingleSuccessor() != cast<Instruction>(SIUse)->getParent())
51702077da7SAlexey Zhikhartsev       return false;
51802077da7SAlexey Zhikhartsev 
51902077da7SAlexey Zhikhartsev     // If select will not be sunk during unfolding, and it is in the same basic
52002077da7SAlexey Zhikhartsev     // block as another state defining select, then cannot unfold both.
52102077da7SAlexey Zhikhartsev     for (SelectInstToUnfold SIToUnfold : SelectInsts) {
52202077da7SAlexey Zhikhartsev       SelectInst *PrevSI = SIToUnfold.getInst();
52302077da7SAlexey Zhikhartsev       if (PrevSI->getTrueValue() != SI && PrevSI->getFalseValue() != SI &&
52402077da7SAlexey Zhikhartsev           PrevSI->getParent() == SI->getParent())
52502077da7SAlexey Zhikhartsev         return false;
52602077da7SAlexey Zhikhartsev     }
52702077da7SAlexey Zhikhartsev 
52802077da7SAlexey Zhikhartsev     return true;
52902077da7SAlexey Zhikhartsev   }
53002077da7SAlexey Zhikhartsev 
53102077da7SAlexey Zhikhartsev   SwitchInst *Instr = nullptr;
53202077da7SAlexey Zhikhartsev   SmallVector<SelectInstToUnfold, 4> SelectInsts;
53302077da7SAlexey Zhikhartsev };
53402077da7SAlexey Zhikhartsev 
53502077da7SAlexey Zhikhartsev struct AllSwitchPaths {
AllSwitchPaths__anon91a52f600211::AllSwitchPaths53602077da7SAlexey Zhikhartsev   AllSwitchPaths(const MainSwitch *MSwitch, OptimizationRemarkEmitter *ORE)
53702077da7SAlexey Zhikhartsev       : Switch(MSwitch->getInstr()), SwitchBlock(Switch->getParent()),
53802077da7SAlexey Zhikhartsev         ORE(ORE) {}
53902077da7SAlexey Zhikhartsev 
getThreadingPaths__anon91a52f600211::AllSwitchPaths54002077da7SAlexey Zhikhartsev   std::vector<ThreadingPath> &getThreadingPaths() { return TPaths; }
getNumThreadingPaths__anon91a52f600211::AllSwitchPaths54102077da7SAlexey Zhikhartsev   unsigned getNumThreadingPaths() { return TPaths.size(); }
getSwitchInst__anon91a52f600211::AllSwitchPaths54202077da7SAlexey Zhikhartsev   SwitchInst *getSwitchInst() { return Switch; }
getSwitchBlock__anon91a52f600211::AllSwitchPaths54302077da7SAlexey Zhikhartsev   BasicBlock *getSwitchBlock() { return SwitchBlock; }
54402077da7SAlexey Zhikhartsev 
run__anon91a52f600211::AllSwitchPaths54502077da7SAlexey Zhikhartsev   void run() {
54602077da7SAlexey Zhikhartsev     VisitedBlocks Visited;
54702077da7SAlexey Zhikhartsev     PathsType LoopPaths = paths(SwitchBlock, Visited, /* PathDepth = */ 1);
5488b0d7634SAlex Zhikhartsev     StateDefMap StateDef = getStateDefMap(LoopPaths);
5498b0d7634SAlex Zhikhartsev 
5508b0d7634SAlex Zhikhartsev     if (StateDef.empty()) {
5518b0d7634SAlex Zhikhartsev       ORE->emit([&]() {
5528b0d7634SAlex Zhikhartsev         return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable",
5538b0d7634SAlex Zhikhartsev                                         Switch)
5548b0d7634SAlex Zhikhartsev                << "Switch instruction is not predictable.";
5558b0d7634SAlex Zhikhartsev       });
5568b0d7634SAlex Zhikhartsev       return;
5578b0d7634SAlex Zhikhartsev     }
55802077da7SAlexey Zhikhartsev 
55902077da7SAlexey Zhikhartsev     for (PathType Path : LoopPaths) {
56002077da7SAlexey Zhikhartsev       ThreadingPath TPath;
56102077da7SAlexey Zhikhartsev 
56202077da7SAlexey Zhikhartsev       const BasicBlock *PrevBB = Path.back();
56302077da7SAlexey Zhikhartsev       for (const BasicBlock *BB : Path) {
56402077da7SAlexey Zhikhartsev         if (StateDef.count(BB) != 0) {
56502077da7SAlexey Zhikhartsev           const PHINode *Phi = dyn_cast<PHINode>(StateDef[BB]);
56602077da7SAlexey Zhikhartsev           assert(Phi && "Expected a state-defining instr to be a phi node.");
56702077da7SAlexey Zhikhartsev 
56802077da7SAlexey Zhikhartsev           const Value *V = Phi->getIncomingValueForBlock(PrevBB);
56902077da7SAlexey Zhikhartsev           if (const ConstantInt *C = dyn_cast<const ConstantInt>(V)) {
57002077da7SAlexey Zhikhartsev             TPath.setExitValue(C);
57102077da7SAlexey Zhikhartsev             TPath.setDeterminator(BB);
57202077da7SAlexey Zhikhartsev             TPath.setPath(Path);
57302077da7SAlexey Zhikhartsev           }
57402077da7SAlexey Zhikhartsev         }
57502077da7SAlexey Zhikhartsev 
57602077da7SAlexey Zhikhartsev         // Switch block is the determinator, this is the final exit value.
57702077da7SAlexey Zhikhartsev         if (TPath.isExitValueSet() && BB == Path.front())
57802077da7SAlexey Zhikhartsev           break;
57902077da7SAlexey Zhikhartsev 
58002077da7SAlexey Zhikhartsev         PrevBB = BB;
58102077da7SAlexey Zhikhartsev       }
58202077da7SAlexey Zhikhartsev 
583d5dc3964SAlexey Zhikhartsev       if (TPath.isExitValueSet() && isSupported(TPath))
58402077da7SAlexey Zhikhartsev         TPaths.push_back(TPath);
58502077da7SAlexey Zhikhartsev     }
58602077da7SAlexey Zhikhartsev   }
58702077da7SAlexey Zhikhartsev 
58802077da7SAlexey Zhikhartsev private:
58902077da7SAlexey Zhikhartsev   // Value: an instruction that defines a switch state;
59002077da7SAlexey Zhikhartsev   // Key: the parent basic block of that instruction.
59102077da7SAlexey Zhikhartsev   typedef DenseMap<const BasicBlock *, const PHINode *> StateDefMap;
59202077da7SAlexey Zhikhartsev 
paths__anon91a52f600211::AllSwitchPaths59302077da7SAlexey Zhikhartsev   PathsType paths(BasicBlock *BB, VisitedBlocks &Visited,
59402077da7SAlexey Zhikhartsev                   unsigned PathDepth) const {
59502077da7SAlexey Zhikhartsev     PathsType Res;
59602077da7SAlexey Zhikhartsev 
59702077da7SAlexey Zhikhartsev     // Stop exploring paths after visiting MaxPathLength blocks
59802077da7SAlexey Zhikhartsev     if (PathDepth > MaxPathLength) {
59902077da7SAlexey Zhikhartsev       ORE->emit([&]() {
60002077da7SAlexey Zhikhartsev         return OptimizationRemarkAnalysis(DEBUG_TYPE, "MaxPathLengthReached",
60102077da7SAlexey Zhikhartsev                                           Switch)
60202077da7SAlexey Zhikhartsev                << "Exploration stopped after visiting MaxPathLength="
60302077da7SAlexey Zhikhartsev                << ore::NV("MaxPathLength", MaxPathLength) << " blocks.";
60402077da7SAlexey Zhikhartsev       });
60502077da7SAlexey Zhikhartsev       return Res;
60602077da7SAlexey Zhikhartsev     }
60702077da7SAlexey Zhikhartsev 
60802077da7SAlexey Zhikhartsev     Visited.insert(BB);
60902077da7SAlexey Zhikhartsev 
61002077da7SAlexey Zhikhartsev     // Some blocks have multiple edges to the same successor, and this set
61102077da7SAlexey Zhikhartsev     // is used to prevent a duplicate path from being generated
61202077da7SAlexey Zhikhartsev     SmallSet<BasicBlock *, 4> Successors;
6133f7aea1aSNikita Popov     for (BasicBlock *Succ : successors(BB)) {
6143f7aea1aSNikita Popov       if (!Successors.insert(Succ).second)
61502077da7SAlexey Zhikhartsev         continue;
61602077da7SAlexey Zhikhartsev 
61702077da7SAlexey Zhikhartsev       // Found a cycle through the SwitchBlock
61802077da7SAlexey Zhikhartsev       if (Succ == SwitchBlock) {
61902077da7SAlexey Zhikhartsev         Res.push_back({BB});
62002077da7SAlexey Zhikhartsev         continue;
62102077da7SAlexey Zhikhartsev       }
62202077da7SAlexey Zhikhartsev 
62302077da7SAlexey Zhikhartsev       // We have encountered a cycle, do not get caught in it
624380b8a60SNikita Popov       if (Visited.contains(Succ))
62502077da7SAlexey Zhikhartsev         continue;
62602077da7SAlexey Zhikhartsev 
62702077da7SAlexey Zhikhartsev       PathsType SuccPaths = paths(Succ, Visited, PathDepth + 1);
62802077da7SAlexey Zhikhartsev       for (PathType Path : SuccPaths) {
62902077da7SAlexey Zhikhartsev         PathType NewPath(Path);
63002077da7SAlexey Zhikhartsev         NewPath.push_front(BB);
63102077da7SAlexey Zhikhartsev         Res.push_back(NewPath);
6328b0d7634SAlex Zhikhartsev         if (Res.size() >= MaxNumPaths) {
6338b0d7634SAlex Zhikhartsev           return Res;
6348b0d7634SAlex Zhikhartsev         }
63502077da7SAlexey Zhikhartsev       }
63602077da7SAlexey Zhikhartsev     }
63702077da7SAlexey Zhikhartsev     // This block could now be visited again from a different predecessor. Note
63802077da7SAlexey Zhikhartsev     // that this will result in exponential runtime. Subpaths could possibly be
63902077da7SAlexey Zhikhartsev     // cached but it takes a lot of memory to store them.
64002077da7SAlexey Zhikhartsev     Visited.erase(BB);
64102077da7SAlexey Zhikhartsev     return Res;
64202077da7SAlexey Zhikhartsev   }
64302077da7SAlexey Zhikhartsev 
64402077da7SAlexey Zhikhartsev   /// Walk the use-def chain and collect all the state-defining instructions.
6458b0d7634SAlex Zhikhartsev   ///
6468b0d7634SAlex Zhikhartsev   /// Return an empty map if unpredictable values encountered inside the basic
6478b0d7634SAlex Zhikhartsev   /// blocks of \p LoopPaths.
getStateDefMap__anon91a52f600211::AllSwitchPaths6488b0d7634SAlex Zhikhartsev   StateDefMap getStateDefMap(const PathsType &LoopPaths) const {
64902077da7SAlexey Zhikhartsev     StateDefMap Res;
65002077da7SAlexey Zhikhartsev 
6518b0d7634SAlex Zhikhartsev     // Basic blocks belonging to any of the loops around the switch statement.
6528b0d7634SAlex Zhikhartsev     SmallPtrSet<BasicBlock *, 16> LoopBBs;
6538b0d7634SAlex Zhikhartsev     for (const PathType &Path : LoopPaths) {
6548b0d7634SAlex Zhikhartsev       for (BasicBlock *BB : Path)
6558b0d7634SAlex Zhikhartsev         LoopBBs.insert(BB);
6568b0d7634SAlex Zhikhartsev     }
6578b0d7634SAlex Zhikhartsev 
65802077da7SAlexey Zhikhartsev     Value *FirstDef = Switch->getOperand(0);
65902077da7SAlexey Zhikhartsev 
6608b0d7634SAlex Zhikhartsev     assert(isa<PHINode>(FirstDef) && "The first definition must be a phi.");
66102077da7SAlexey Zhikhartsev 
66202077da7SAlexey Zhikhartsev     SmallVector<PHINode *, 8> Stack;
66302077da7SAlexey Zhikhartsev     Stack.push_back(dyn_cast<PHINode>(FirstDef));
66402077da7SAlexey Zhikhartsev     SmallSet<Value *, 16> SeenValues;
66502077da7SAlexey Zhikhartsev 
66602077da7SAlexey Zhikhartsev     while (!Stack.empty()) {
66784b07c9bSKazu Hirata       PHINode *CurPhi = Stack.pop_back_val();
66802077da7SAlexey Zhikhartsev 
66902077da7SAlexey Zhikhartsev       Res[CurPhi->getParent()] = CurPhi;
67002077da7SAlexey Zhikhartsev       SeenValues.insert(CurPhi);
67102077da7SAlexey Zhikhartsev 
6728b0d7634SAlex Zhikhartsev       for (BasicBlock *IncomingBB : CurPhi->blocks()) {
6738b0d7634SAlex Zhikhartsev         Value *Incoming = CurPhi->getIncomingValueForBlock(IncomingBB);
6748b0d7634SAlex Zhikhartsev         bool IsOutsideLoops = LoopBBs.count(IncomingBB) == 0;
67502077da7SAlexey Zhikhartsev         if (Incoming == FirstDef || isa<ConstantInt>(Incoming) ||
6768b0d7634SAlex Zhikhartsev             SeenValues.contains(Incoming) || IsOutsideLoops) {
67702077da7SAlexey Zhikhartsev           continue;
67802077da7SAlexey Zhikhartsev         }
67902077da7SAlexey Zhikhartsev 
6808b0d7634SAlex Zhikhartsev         // Any unpredictable value inside the loops means we must bail out.
6818b0d7634SAlex Zhikhartsev         if (!isa<PHINode>(Incoming))
6828b0d7634SAlex Zhikhartsev           return StateDefMap();
68302077da7SAlexey Zhikhartsev 
68402077da7SAlexey Zhikhartsev         Stack.push_back(cast<PHINode>(Incoming));
68502077da7SAlexey Zhikhartsev       }
68602077da7SAlexey Zhikhartsev     }
68702077da7SAlexey Zhikhartsev 
68802077da7SAlexey Zhikhartsev     return Res;
68902077da7SAlexey Zhikhartsev   }
69002077da7SAlexey Zhikhartsev 
691d5dc3964SAlexey Zhikhartsev   /// The determinator BB should precede the switch-defining BB.
692d5dc3964SAlexey Zhikhartsev   ///
693d5dc3964SAlexey Zhikhartsev   /// Otherwise, it is possible that the state defined in the determinator block
694d5dc3964SAlexey Zhikhartsev   /// defines the state for the next iteration of the loop, rather than for the
695d5dc3964SAlexey Zhikhartsev   /// current one.
696d5dc3964SAlexey Zhikhartsev   ///
697d5dc3964SAlexey Zhikhartsev   /// Currently supported paths:
698d5dc3964SAlexey Zhikhartsev   /// \code
699d5dc3964SAlexey Zhikhartsev   /// < switch bb1 determ def > [ 42, determ ]
700d5dc3964SAlexey Zhikhartsev   /// < switch_and_def bb1 determ > [ 42, determ ]
701d5dc3964SAlexey Zhikhartsev   /// < switch_and_def_and_determ bb1 > [ 42, switch_and_def_and_determ ]
702d5dc3964SAlexey Zhikhartsev   /// \endcode
703d5dc3964SAlexey Zhikhartsev   ///
704d5dc3964SAlexey Zhikhartsev   /// Unsupported paths:
705d5dc3964SAlexey Zhikhartsev   /// \code
706d5dc3964SAlexey Zhikhartsev   /// < switch bb1 def determ > [ 43, determ ]
707d5dc3964SAlexey Zhikhartsev   /// < switch_and_determ bb1 def > [ 43, switch_and_determ ]
708d5dc3964SAlexey Zhikhartsev   /// \endcode
isSupported__anon91a52f600211::AllSwitchPaths709d5dc3964SAlexey Zhikhartsev   bool isSupported(const ThreadingPath &TPath) {
710d5dc3964SAlexey Zhikhartsev     Instruction *SwitchCondI = dyn_cast<Instruction>(Switch->getCondition());
711d5dc3964SAlexey Zhikhartsev     assert(SwitchCondI);
712d5dc3964SAlexey Zhikhartsev     if (!SwitchCondI)
713d5dc3964SAlexey Zhikhartsev       return false;
714d5dc3964SAlexey Zhikhartsev 
715d5dc3964SAlexey Zhikhartsev     const BasicBlock *SwitchCondDefBB = SwitchCondI->getParent();
716d5dc3964SAlexey Zhikhartsev     const BasicBlock *SwitchCondUseBB = Switch->getParent();
717d5dc3964SAlexey Zhikhartsev     const BasicBlock *DeterminatorBB = TPath.getDeterminatorBB();
718d5dc3964SAlexey Zhikhartsev 
719d5dc3964SAlexey Zhikhartsev     assert(
720d5dc3964SAlexey Zhikhartsev         SwitchCondUseBB == TPath.getPath().front() &&
721d5dc3964SAlexey Zhikhartsev         "The first BB in a threading path should have the switch instruction");
722d5dc3964SAlexey Zhikhartsev     if (SwitchCondUseBB != TPath.getPath().front())
723d5dc3964SAlexey Zhikhartsev       return false;
724d5dc3964SAlexey Zhikhartsev 
725d5dc3964SAlexey Zhikhartsev     // Make DeterminatorBB the first element in Path.
726d5dc3964SAlexey Zhikhartsev     PathType Path = TPath.getPath();
727d5dc3964SAlexey Zhikhartsev     auto ItDet = std::find(Path.begin(), Path.end(), DeterminatorBB);
728d5dc3964SAlexey Zhikhartsev     std::rotate(Path.begin(), ItDet, Path.end());
729d5dc3964SAlexey Zhikhartsev 
730d5dc3964SAlexey Zhikhartsev     bool IsDetBBSeen = false;
731d5dc3964SAlexey Zhikhartsev     bool IsDefBBSeen = false;
732d5dc3964SAlexey Zhikhartsev     bool IsUseBBSeen = false;
733d5dc3964SAlexey Zhikhartsev     for (BasicBlock *BB : Path) {
734d5dc3964SAlexey Zhikhartsev       if (BB == DeterminatorBB)
735d5dc3964SAlexey Zhikhartsev         IsDetBBSeen = true;
736d5dc3964SAlexey Zhikhartsev       if (BB == SwitchCondDefBB)
737d5dc3964SAlexey Zhikhartsev         IsDefBBSeen = true;
738d5dc3964SAlexey Zhikhartsev       if (BB == SwitchCondUseBB)
739d5dc3964SAlexey Zhikhartsev         IsUseBBSeen = true;
740d5dc3964SAlexey Zhikhartsev       if (IsDetBBSeen && IsUseBBSeen && !IsDefBBSeen)
741d5dc3964SAlexey Zhikhartsev         return false;
742d5dc3964SAlexey Zhikhartsev     }
743d5dc3964SAlexey Zhikhartsev 
744d5dc3964SAlexey Zhikhartsev     return true;
745d5dc3964SAlexey Zhikhartsev   }
746d5dc3964SAlexey Zhikhartsev 
74702077da7SAlexey Zhikhartsev   SwitchInst *Switch;
74802077da7SAlexey Zhikhartsev   BasicBlock *SwitchBlock;
74902077da7SAlexey Zhikhartsev   OptimizationRemarkEmitter *ORE;
75002077da7SAlexey Zhikhartsev   std::vector<ThreadingPath> TPaths;
75102077da7SAlexey Zhikhartsev };
75202077da7SAlexey Zhikhartsev 
75302077da7SAlexey Zhikhartsev struct TransformDFA {
TransformDFA__anon91a52f600211::TransformDFA75402077da7SAlexey Zhikhartsev   TransformDFA(AllSwitchPaths *SwitchPaths, DominatorTree *DT,
75502077da7SAlexey Zhikhartsev                AssumptionCache *AC, TargetTransformInfo *TTI,
75602077da7SAlexey Zhikhartsev                OptimizationRemarkEmitter *ORE,
75702077da7SAlexey Zhikhartsev                SmallPtrSet<const Value *, 32> EphValues)
75802077da7SAlexey Zhikhartsev       : SwitchPaths(SwitchPaths), DT(DT), AC(AC), TTI(TTI), ORE(ORE),
75902077da7SAlexey Zhikhartsev         EphValues(EphValues) {}
76002077da7SAlexey Zhikhartsev 
run__anon91a52f600211::TransformDFA76102077da7SAlexey Zhikhartsev   void run() {
76202077da7SAlexey Zhikhartsev     if (isLegalAndProfitableToTransform()) {
76302077da7SAlexey Zhikhartsev       createAllExitPaths();
76402077da7SAlexey Zhikhartsev       NumTransforms++;
76502077da7SAlexey Zhikhartsev     }
76602077da7SAlexey Zhikhartsev   }
76702077da7SAlexey Zhikhartsev 
76802077da7SAlexey Zhikhartsev private:
76902077da7SAlexey Zhikhartsev   /// This function performs both a legality check and profitability check at
77002077da7SAlexey Zhikhartsev   /// the same time since it is convenient to do so. It iterates through all
77102077da7SAlexey Zhikhartsev   /// blocks that will be cloned, and keeps track of the duplication cost. It
77202077da7SAlexey Zhikhartsev   /// also returns false if it is illegal to clone some required block.
isLegalAndProfitableToTransform__anon91a52f600211::TransformDFA77302077da7SAlexey Zhikhartsev   bool isLegalAndProfitableToTransform() {
77402077da7SAlexey Zhikhartsev     CodeMetrics Metrics;
77502077da7SAlexey Zhikhartsev     SwitchInst *Switch = SwitchPaths->getSwitchInst();
77602077da7SAlexey Zhikhartsev 
77702077da7SAlexey Zhikhartsev     // Note that DuplicateBlockMap is not being used as intended here. It is
77802077da7SAlexey Zhikhartsev     // just being used to ensure (BB, State) pairs are only counted once.
77902077da7SAlexey Zhikhartsev     DuplicateBlockMap DuplicateMap;
78002077da7SAlexey Zhikhartsev 
78102077da7SAlexey Zhikhartsev     for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
78202077da7SAlexey Zhikhartsev       PathType PathBBs = TPath.getPath();
78302077da7SAlexey Zhikhartsev       uint64_t NextState = TPath.getExitValue();
78402077da7SAlexey Zhikhartsev       const BasicBlock *Determinator = TPath.getDeterminatorBB();
78502077da7SAlexey Zhikhartsev 
78602077da7SAlexey Zhikhartsev       // Update Metrics for the Switch block, this is always cloned
78702077da7SAlexey Zhikhartsev       BasicBlock *BB = SwitchPaths->getSwitchBlock();
78802077da7SAlexey Zhikhartsev       BasicBlock *VisitedBB = getClonedBB(BB, NextState, DuplicateMap);
78902077da7SAlexey Zhikhartsev       if (!VisitedBB) {
79002077da7SAlexey Zhikhartsev         Metrics.analyzeBasicBlock(BB, *TTI, EphValues);
79102077da7SAlexey Zhikhartsev         DuplicateMap[BB].push_back({BB, NextState});
79202077da7SAlexey Zhikhartsev       }
79302077da7SAlexey Zhikhartsev 
79402077da7SAlexey Zhikhartsev       // If the Switch block is the Determinator, then we can continue since
79502077da7SAlexey Zhikhartsev       // this is the only block that is cloned and we already counted for it.
79602077da7SAlexey Zhikhartsev       if (PathBBs.front() == Determinator)
79702077da7SAlexey Zhikhartsev         continue;
79802077da7SAlexey Zhikhartsev 
79902077da7SAlexey Zhikhartsev       // Otherwise update Metrics for all blocks that will be cloned. If any
80002077da7SAlexey Zhikhartsev       // block is already cloned and would be reused, don't double count it.
80102077da7SAlexey Zhikhartsev       auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator);
80202077da7SAlexey Zhikhartsev       for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) {
80302077da7SAlexey Zhikhartsev         BB = *BBIt;
80402077da7SAlexey Zhikhartsev         VisitedBB = getClonedBB(BB, NextState, DuplicateMap);
80502077da7SAlexey Zhikhartsev         if (VisitedBB)
80602077da7SAlexey Zhikhartsev           continue;
80702077da7SAlexey Zhikhartsev         Metrics.analyzeBasicBlock(BB, *TTI, EphValues);
80802077da7SAlexey Zhikhartsev         DuplicateMap[BB].push_back({BB, NextState});
80902077da7SAlexey Zhikhartsev       }
81002077da7SAlexey Zhikhartsev 
81102077da7SAlexey Zhikhartsev       if (Metrics.notDuplicatable) {
81202077da7SAlexey Zhikhartsev         LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains "
81302077da7SAlexey Zhikhartsev                           << "non-duplicatable instructions.\n");
81402077da7SAlexey Zhikhartsev         ORE->emit([&]() {
81502077da7SAlexey Zhikhartsev           return OptimizationRemarkMissed(DEBUG_TYPE, "NonDuplicatableInst",
81602077da7SAlexey Zhikhartsev                                           Switch)
81702077da7SAlexey Zhikhartsev                  << "Contains non-duplicatable instructions.";
81802077da7SAlexey Zhikhartsev         });
81902077da7SAlexey Zhikhartsev         return false;
82002077da7SAlexey Zhikhartsev       }
82102077da7SAlexey Zhikhartsev 
82202077da7SAlexey Zhikhartsev       if (Metrics.convergent) {
82302077da7SAlexey Zhikhartsev         LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains "
82402077da7SAlexey Zhikhartsev                           << "convergent instructions.\n");
82502077da7SAlexey Zhikhartsev         ORE->emit([&]() {
82602077da7SAlexey Zhikhartsev           return OptimizationRemarkMissed(DEBUG_TYPE, "ConvergentInst", Switch)
82702077da7SAlexey Zhikhartsev                  << "Contains convergent instructions.";
82802077da7SAlexey Zhikhartsev         });
82902077da7SAlexey Zhikhartsev         return false;
83002077da7SAlexey Zhikhartsev       }
831f85c5079SPhilip Reames 
832f85c5079SPhilip Reames       if (!Metrics.NumInsts.isValid()) {
833f85c5079SPhilip Reames         LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains "
834f85c5079SPhilip Reames                           << "instructions with invalid cost.\n");
835f85c5079SPhilip Reames         ORE->emit([&]() {
836f85c5079SPhilip Reames           return OptimizationRemarkMissed(DEBUG_TYPE, "ConvergentInst", Switch)
837f85c5079SPhilip Reames                  << "Contains instructions with invalid cost.";
838f85c5079SPhilip Reames         });
839f85c5079SPhilip Reames         return false;
840f85c5079SPhilip Reames       }
84102077da7SAlexey Zhikhartsev     }
84202077da7SAlexey Zhikhartsev 
84302077da7SAlexey Zhikhartsev     unsigned DuplicationCost = 0;
84402077da7SAlexey Zhikhartsev 
84502077da7SAlexey Zhikhartsev     unsigned JumpTableSize = 0;
84602077da7SAlexey Zhikhartsev     TTI->getEstimatedNumberOfCaseClusters(*Switch, JumpTableSize, nullptr,
84702077da7SAlexey Zhikhartsev                                           nullptr);
84802077da7SAlexey Zhikhartsev     if (JumpTableSize == 0) {
84902077da7SAlexey Zhikhartsev       // Factor in the number of conditional branches reduced from jump
85002077da7SAlexey Zhikhartsev       // threading. Assume that lowering the switch block is implemented by
85102077da7SAlexey Zhikhartsev       // using binary search, hence the LogBase2().
85202077da7SAlexey Zhikhartsev       unsigned CondBranches =
85302077da7SAlexey Zhikhartsev           APInt(32, Switch->getNumSuccessors()).ceilLogBase2();
854f85c5079SPhilip Reames       DuplicationCost = *Metrics.NumInsts.getValue() / CondBranches;
85502077da7SAlexey Zhikhartsev     } else {
85602077da7SAlexey Zhikhartsev       // Compared with jump tables, the DFA optimizer removes an indirect branch
85702077da7SAlexey Zhikhartsev       // on each loop iteration, thus making branch prediction more precise. The
85802077da7SAlexey Zhikhartsev       // more branch targets there are, the more likely it is for the branch
85902077da7SAlexey Zhikhartsev       // predictor to make a mistake, and the more benefit there is in the DFA
86002077da7SAlexey Zhikhartsev       // optimizer. Thus, the more branch targets there are, the lower is the
86102077da7SAlexey Zhikhartsev       // cost of the DFA opt.
862f85c5079SPhilip Reames       DuplicationCost = *Metrics.NumInsts.getValue() / JumpTableSize;
86302077da7SAlexey Zhikhartsev     }
86402077da7SAlexey Zhikhartsev 
86502077da7SAlexey Zhikhartsev     LLVM_DEBUG(dbgs() << "\nDFA Jump Threading: Cost to jump thread block "
86602077da7SAlexey Zhikhartsev                       << SwitchPaths->getSwitchBlock()->getName()
86702077da7SAlexey Zhikhartsev                       << " is: " << DuplicationCost << "\n\n");
86802077da7SAlexey Zhikhartsev 
86902077da7SAlexey Zhikhartsev     if (DuplicationCost > CostThreshold) {
87002077da7SAlexey Zhikhartsev       LLVM_DEBUG(dbgs() << "Not jump threading, duplication cost exceeds the "
87102077da7SAlexey Zhikhartsev                         << "cost threshold.\n");
87202077da7SAlexey Zhikhartsev       ORE->emit([&]() {
87302077da7SAlexey Zhikhartsev         return OptimizationRemarkMissed(DEBUG_TYPE, "NotProfitable", Switch)
87402077da7SAlexey Zhikhartsev                << "Duplication cost exceeds the cost threshold (cost="
87502077da7SAlexey Zhikhartsev                << ore::NV("Cost", DuplicationCost)
87602077da7SAlexey Zhikhartsev                << ", threshold=" << ore::NV("Threshold", CostThreshold) << ").";
87702077da7SAlexey Zhikhartsev       });
87802077da7SAlexey Zhikhartsev       return false;
87902077da7SAlexey Zhikhartsev     }
88002077da7SAlexey Zhikhartsev 
88102077da7SAlexey Zhikhartsev     ORE->emit([&]() {
88202077da7SAlexey Zhikhartsev       return OptimizationRemark(DEBUG_TYPE, "JumpThreaded", Switch)
88302077da7SAlexey Zhikhartsev              << "Switch statement jump-threaded.";
88402077da7SAlexey Zhikhartsev     });
88502077da7SAlexey Zhikhartsev 
88602077da7SAlexey Zhikhartsev     return true;
88702077da7SAlexey Zhikhartsev   }
88802077da7SAlexey Zhikhartsev 
88902077da7SAlexey Zhikhartsev   /// Transform each threading path to effectively jump thread the DFA.
createAllExitPaths__anon91a52f600211::TransformDFA89002077da7SAlexey Zhikhartsev   void createAllExitPaths() {
89102077da7SAlexey Zhikhartsev     DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);
89202077da7SAlexey Zhikhartsev 
89302077da7SAlexey Zhikhartsev     // Move the switch block to the end of the path, since it will be duplicated
89402077da7SAlexey Zhikhartsev     BasicBlock *SwitchBlock = SwitchPaths->getSwitchBlock();
89502077da7SAlexey Zhikhartsev     for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
89602077da7SAlexey Zhikhartsev       LLVM_DEBUG(dbgs() << TPath << "\n");
89702077da7SAlexey Zhikhartsev       PathType NewPath(TPath.getPath());
89802077da7SAlexey Zhikhartsev       NewPath.push_back(SwitchBlock);
89902077da7SAlexey Zhikhartsev       TPath.setPath(NewPath);
90002077da7SAlexey Zhikhartsev     }
90102077da7SAlexey Zhikhartsev 
90202077da7SAlexey Zhikhartsev     // Transform the ThreadingPaths and keep track of the cloned values
90302077da7SAlexey Zhikhartsev     DuplicateBlockMap DuplicateMap;
90402077da7SAlexey Zhikhartsev     DefMap NewDefs;
90502077da7SAlexey Zhikhartsev 
90602077da7SAlexey Zhikhartsev     SmallSet<BasicBlock *, 16> BlocksToClean;
90702077da7SAlexey Zhikhartsev     for (BasicBlock *BB : successors(SwitchBlock))
90802077da7SAlexey Zhikhartsev       BlocksToClean.insert(BB);
90902077da7SAlexey Zhikhartsev 
91002077da7SAlexey Zhikhartsev     for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
91102077da7SAlexey Zhikhartsev       createExitPath(NewDefs, TPath, DuplicateMap, BlocksToClean, &DTU);
91202077da7SAlexey Zhikhartsev       NumPaths++;
91302077da7SAlexey Zhikhartsev     }
91402077da7SAlexey Zhikhartsev 
91502077da7SAlexey Zhikhartsev     // After all paths are cloned, now update the last successor of the cloned
91602077da7SAlexey Zhikhartsev     // path so it skips over the switch statement
91702077da7SAlexey Zhikhartsev     for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths())
91802077da7SAlexey Zhikhartsev       updateLastSuccessor(TPath, DuplicateMap, &DTU);
91902077da7SAlexey Zhikhartsev 
92002077da7SAlexey Zhikhartsev     // For each instruction that was cloned and used outside, update its uses
92102077da7SAlexey Zhikhartsev     updateSSA(NewDefs);
92202077da7SAlexey Zhikhartsev 
92302077da7SAlexey Zhikhartsev     // Clean PHI Nodes for the newly created blocks
92402077da7SAlexey Zhikhartsev     for (BasicBlock *BB : BlocksToClean)
92502077da7SAlexey Zhikhartsev       cleanPhiNodes(BB);
92602077da7SAlexey Zhikhartsev   }
92702077da7SAlexey Zhikhartsev 
92802077da7SAlexey Zhikhartsev   /// For a specific ThreadingPath \p Path, create an exit path starting from
92902077da7SAlexey Zhikhartsev   /// the determinator block.
93002077da7SAlexey Zhikhartsev   ///
93102077da7SAlexey Zhikhartsev   /// To remember the correct destination, we have to duplicate blocks
93202077da7SAlexey Zhikhartsev   /// corresponding to each state. Also update the terminating instruction of
93302077da7SAlexey Zhikhartsev   /// the predecessors, and phis in the successor blocks.
createExitPath__anon91a52f600211::TransformDFA93402077da7SAlexey Zhikhartsev   void createExitPath(DefMap &NewDefs, ThreadingPath &Path,
93502077da7SAlexey Zhikhartsev                       DuplicateBlockMap &DuplicateMap,
93602077da7SAlexey Zhikhartsev                       SmallSet<BasicBlock *, 16> &BlocksToClean,
93702077da7SAlexey Zhikhartsev                       DomTreeUpdater *DTU) {
93802077da7SAlexey Zhikhartsev     uint64_t NextState = Path.getExitValue();
93902077da7SAlexey Zhikhartsev     const BasicBlock *Determinator = Path.getDeterminatorBB();
94002077da7SAlexey Zhikhartsev     PathType PathBBs = Path.getPath();
94102077da7SAlexey Zhikhartsev 
94202077da7SAlexey Zhikhartsev     // Don't select the placeholder block in front
94302077da7SAlexey Zhikhartsev     if (PathBBs.front() == Determinator)
94402077da7SAlexey Zhikhartsev       PathBBs.pop_front();
94502077da7SAlexey Zhikhartsev 
94602077da7SAlexey Zhikhartsev     auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator);
94702077da7SAlexey Zhikhartsev     auto Prev = std::prev(DetIt);
94802077da7SAlexey Zhikhartsev     BasicBlock *PrevBB = *Prev;
94902077da7SAlexey Zhikhartsev     for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) {
95002077da7SAlexey Zhikhartsev       BasicBlock *BB = *BBIt;
95102077da7SAlexey Zhikhartsev       BlocksToClean.insert(BB);
95202077da7SAlexey Zhikhartsev 
95302077da7SAlexey Zhikhartsev       // We already cloned BB for this NextState, now just update the branch
95402077da7SAlexey Zhikhartsev       // and continue.
95502077da7SAlexey Zhikhartsev       BasicBlock *NextBB = getClonedBB(BB, NextState, DuplicateMap);
95602077da7SAlexey Zhikhartsev       if (NextBB) {
95702077da7SAlexey Zhikhartsev         updatePredecessor(PrevBB, BB, NextBB, DTU);
95802077da7SAlexey Zhikhartsev         PrevBB = NextBB;
95902077da7SAlexey Zhikhartsev         continue;
96002077da7SAlexey Zhikhartsev       }
96102077da7SAlexey Zhikhartsev 
96202077da7SAlexey Zhikhartsev       // Clone the BB and update the successor of Prev to jump to the new block
96302077da7SAlexey Zhikhartsev       BasicBlock *NewBB = cloneBlockAndUpdatePredecessor(
96402077da7SAlexey Zhikhartsev           BB, PrevBB, NextState, DuplicateMap, NewDefs, DTU);
96502077da7SAlexey Zhikhartsev       DuplicateMap[BB].push_back({NewBB, NextState});
96602077da7SAlexey Zhikhartsev       BlocksToClean.insert(NewBB);
96702077da7SAlexey Zhikhartsev       PrevBB = NewBB;
96802077da7SAlexey Zhikhartsev     }
96902077da7SAlexey Zhikhartsev   }
97002077da7SAlexey Zhikhartsev 
97102077da7SAlexey Zhikhartsev   /// Restore SSA form after cloning blocks.
97202077da7SAlexey Zhikhartsev   ///
97302077da7SAlexey Zhikhartsev   /// Each cloned block creates new defs for a variable, and the uses need to be
97402077da7SAlexey Zhikhartsev   /// updated to reflect this. The uses may be replaced with a cloned value, or
97502077da7SAlexey Zhikhartsev   /// some derived phi instruction. Note that all uses of a value defined in the
97602077da7SAlexey Zhikhartsev   /// same block were already remapped when cloning the block.
updateSSA__anon91a52f600211::TransformDFA97702077da7SAlexey Zhikhartsev   void updateSSA(DefMap &NewDefs) {
97802077da7SAlexey Zhikhartsev     SSAUpdaterBulk SSAUpdate;
97902077da7SAlexey Zhikhartsev     SmallVector<Use *, 16> UsesToRename;
98002077da7SAlexey Zhikhartsev 
98102077da7SAlexey Zhikhartsev     for (auto KV : NewDefs) {
98202077da7SAlexey Zhikhartsev       Instruction *I = KV.first;
98302077da7SAlexey Zhikhartsev       BasicBlock *BB = I->getParent();
98402077da7SAlexey Zhikhartsev       std::vector<Instruction *> Cloned = KV.second;
98502077da7SAlexey Zhikhartsev 
98602077da7SAlexey Zhikhartsev       // Scan all uses of this instruction to see if it is used outside of its
98702077da7SAlexey Zhikhartsev       // block, and if so, record them in UsesToRename.
98802077da7SAlexey Zhikhartsev       for (Use &U : I->uses()) {
98902077da7SAlexey Zhikhartsev         Instruction *User = cast<Instruction>(U.getUser());
99002077da7SAlexey Zhikhartsev         if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
99102077da7SAlexey Zhikhartsev           if (UserPN->getIncomingBlock(U) == BB)
99202077da7SAlexey Zhikhartsev             continue;
99302077da7SAlexey Zhikhartsev         } else if (User->getParent() == BB) {
99402077da7SAlexey Zhikhartsev           continue;
99502077da7SAlexey Zhikhartsev         }
99602077da7SAlexey Zhikhartsev 
99702077da7SAlexey Zhikhartsev         UsesToRename.push_back(&U);
99802077da7SAlexey Zhikhartsev       }
99902077da7SAlexey Zhikhartsev 
100002077da7SAlexey Zhikhartsev       // If there are no uses outside the block, we're done with this
100102077da7SAlexey Zhikhartsev       // instruction.
100202077da7SAlexey Zhikhartsev       if (UsesToRename.empty())
100302077da7SAlexey Zhikhartsev         continue;
100402077da7SAlexey Zhikhartsev       LLVM_DEBUG(dbgs() << "DFA-JT: Renaming non-local uses of: " << *I
100502077da7SAlexey Zhikhartsev                         << "\n");
100602077da7SAlexey Zhikhartsev 
100702077da7SAlexey Zhikhartsev       // We found a use of I outside of BB.  Rename all uses of I that are
100802077da7SAlexey Zhikhartsev       // outside its block to be uses of the appropriate PHI node etc.  See
100902077da7SAlexey Zhikhartsev       // ValuesInBlocks with the values we know.
101002077da7SAlexey Zhikhartsev       unsigned VarNum = SSAUpdate.AddVariable(I->getName(), I->getType());
101102077da7SAlexey Zhikhartsev       SSAUpdate.AddAvailableValue(VarNum, BB, I);
101202077da7SAlexey Zhikhartsev       for (Instruction *New : Cloned)
101302077da7SAlexey Zhikhartsev         SSAUpdate.AddAvailableValue(VarNum, New->getParent(), New);
101402077da7SAlexey Zhikhartsev 
101502077da7SAlexey Zhikhartsev       while (!UsesToRename.empty())
101602077da7SAlexey Zhikhartsev         SSAUpdate.AddUse(VarNum, UsesToRename.pop_back_val());
101702077da7SAlexey Zhikhartsev 
101802077da7SAlexey Zhikhartsev       LLVM_DEBUG(dbgs() << "\n");
101902077da7SAlexey Zhikhartsev     }
102002077da7SAlexey Zhikhartsev     // SSAUpdater handles phi placement and renaming uses with the appropriate
102102077da7SAlexey Zhikhartsev     // value.
102202077da7SAlexey Zhikhartsev     SSAUpdate.RewriteAllUses(DT);
102302077da7SAlexey Zhikhartsev   }
102402077da7SAlexey Zhikhartsev 
102502077da7SAlexey Zhikhartsev   /// Clones a basic block, and adds it to the CFG.
102602077da7SAlexey Zhikhartsev   ///
102702077da7SAlexey Zhikhartsev   /// This function also includes updating phi nodes in the successors of the
102802077da7SAlexey Zhikhartsev   /// BB, and remapping uses that were defined locally in the cloned BB.
cloneBlockAndUpdatePredecessor__anon91a52f600211::TransformDFA102902077da7SAlexey Zhikhartsev   BasicBlock *cloneBlockAndUpdatePredecessor(BasicBlock *BB, BasicBlock *PrevBB,
103002077da7SAlexey Zhikhartsev                                              uint64_t NextState,
103102077da7SAlexey Zhikhartsev                                              DuplicateBlockMap &DuplicateMap,
103202077da7SAlexey Zhikhartsev                                              DefMap &NewDefs,
103302077da7SAlexey Zhikhartsev                                              DomTreeUpdater *DTU) {
103402077da7SAlexey Zhikhartsev     ValueToValueMapTy VMap;
103502077da7SAlexey Zhikhartsev     BasicBlock *NewBB = CloneBasicBlock(
103602077da7SAlexey Zhikhartsev         BB, VMap, ".jt" + std::to_string(NextState), BB->getParent());
103702077da7SAlexey Zhikhartsev     NewBB->moveAfter(BB);
103802077da7SAlexey Zhikhartsev     NumCloned++;
103902077da7SAlexey Zhikhartsev 
104002077da7SAlexey Zhikhartsev     for (Instruction &I : *NewBB) {
104102077da7SAlexey Zhikhartsev       // Do not remap operands of PHINode in case a definition in BB is an
104202077da7SAlexey Zhikhartsev       // incoming value to a phi in the same block. This incoming value will
104302077da7SAlexey Zhikhartsev       // be renamed later while restoring SSA.
104402077da7SAlexey Zhikhartsev       if (isa<PHINode>(&I))
104502077da7SAlexey Zhikhartsev         continue;
104602077da7SAlexey Zhikhartsev       RemapInstruction(&I, VMap,
104702077da7SAlexey Zhikhartsev                        RF_IgnoreMissingLocals | RF_NoModuleLevelChanges);
104802077da7SAlexey Zhikhartsev       if (AssumeInst *II = dyn_cast<AssumeInst>(&I))
104902077da7SAlexey Zhikhartsev         AC->registerAssumption(II);
105002077da7SAlexey Zhikhartsev     }
105102077da7SAlexey Zhikhartsev 
105202077da7SAlexey Zhikhartsev     updateSuccessorPhis(BB, NewBB, NextState, VMap, DuplicateMap);
105302077da7SAlexey Zhikhartsev     updatePredecessor(PrevBB, BB, NewBB, DTU);
105402077da7SAlexey Zhikhartsev     updateDefMap(NewDefs, VMap);
105502077da7SAlexey Zhikhartsev 
105602077da7SAlexey Zhikhartsev     // Add all successors to the DominatorTree
105702077da7SAlexey Zhikhartsev     SmallPtrSet<BasicBlock *, 4> SuccSet;
105802077da7SAlexey Zhikhartsev     for (auto *SuccBB : successors(NewBB)) {
105902077da7SAlexey Zhikhartsev       if (SuccSet.insert(SuccBB).second)
106002077da7SAlexey Zhikhartsev         DTU->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB}});
106102077da7SAlexey Zhikhartsev     }
106202077da7SAlexey Zhikhartsev     SuccSet.clear();
106302077da7SAlexey Zhikhartsev     return NewBB;
106402077da7SAlexey Zhikhartsev   }
106502077da7SAlexey Zhikhartsev 
106602077da7SAlexey Zhikhartsev   /// Update the phi nodes in BB's successors.
106702077da7SAlexey Zhikhartsev   ///
106802077da7SAlexey Zhikhartsev   /// This means creating a new incoming value from NewBB with the new
106902077da7SAlexey Zhikhartsev   /// instruction wherever there is an incoming value from BB.
updateSuccessorPhis__anon91a52f600211::TransformDFA107002077da7SAlexey Zhikhartsev   void updateSuccessorPhis(BasicBlock *BB, BasicBlock *ClonedBB,
107102077da7SAlexey Zhikhartsev                            uint64_t NextState, ValueToValueMapTy &VMap,
107202077da7SAlexey Zhikhartsev                            DuplicateBlockMap &DuplicateMap) {
107302077da7SAlexey Zhikhartsev     std::vector<BasicBlock *> BlocksToUpdate;
107402077da7SAlexey Zhikhartsev 
107502077da7SAlexey Zhikhartsev     // If BB is the last block in the path, we can simply update the one case
107602077da7SAlexey Zhikhartsev     // successor that will be reached.
107702077da7SAlexey Zhikhartsev     if (BB == SwitchPaths->getSwitchBlock()) {
107802077da7SAlexey Zhikhartsev       SwitchInst *Switch = SwitchPaths->getSwitchInst();
107902077da7SAlexey Zhikhartsev       BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState);
108002077da7SAlexey Zhikhartsev       BlocksToUpdate.push_back(NextCase);
108102077da7SAlexey Zhikhartsev       BasicBlock *ClonedSucc = getClonedBB(NextCase, NextState, DuplicateMap);
108202077da7SAlexey Zhikhartsev       if (ClonedSucc)
108302077da7SAlexey Zhikhartsev         BlocksToUpdate.push_back(ClonedSucc);
108402077da7SAlexey Zhikhartsev     }
108502077da7SAlexey Zhikhartsev     // Otherwise update phis in all successors.
108602077da7SAlexey Zhikhartsev     else {
108702077da7SAlexey Zhikhartsev       for (BasicBlock *Succ : successors(BB)) {
108802077da7SAlexey Zhikhartsev         BlocksToUpdate.push_back(Succ);
108902077da7SAlexey Zhikhartsev 
109002077da7SAlexey Zhikhartsev         // Check if a successor has already been cloned for the particular exit
109102077da7SAlexey Zhikhartsev         // value. In this case if a successor was already cloned, the phi nodes
109202077da7SAlexey Zhikhartsev         // in the cloned block should be updated directly.
109302077da7SAlexey Zhikhartsev         BasicBlock *ClonedSucc = getClonedBB(Succ, NextState, DuplicateMap);
109402077da7SAlexey Zhikhartsev         if (ClonedSucc)
109502077da7SAlexey Zhikhartsev           BlocksToUpdate.push_back(ClonedSucc);
109602077da7SAlexey Zhikhartsev       }
109702077da7SAlexey Zhikhartsev     }
109802077da7SAlexey Zhikhartsev 
109902077da7SAlexey Zhikhartsev     // If there is a phi with an incoming value from BB, create a new incoming
110002077da7SAlexey Zhikhartsev     // value for the new predecessor ClonedBB. The value will either be the same
110102077da7SAlexey Zhikhartsev     // value from BB or a cloned value.
110202077da7SAlexey Zhikhartsev     for (BasicBlock *Succ : BlocksToUpdate) {
110302077da7SAlexey Zhikhartsev       for (auto II = Succ->begin(); PHINode *Phi = dyn_cast<PHINode>(II);
110402077da7SAlexey Zhikhartsev            ++II) {
110502077da7SAlexey Zhikhartsev         Value *Incoming = Phi->getIncomingValueForBlock(BB);
110602077da7SAlexey Zhikhartsev         if (Incoming) {
110702077da7SAlexey Zhikhartsev           if (isa<Constant>(Incoming)) {
110802077da7SAlexey Zhikhartsev             Phi->addIncoming(Incoming, ClonedBB);
110902077da7SAlexey Zhikhartsev             continue;
111002077da7SAlexey Zhikhartsev           }
111102077da7SAlexey Zhikhartsev           Value *ClonedVal = VMap[Incoming];
111202077da7SAlexey Zhikhartsev           if (ClonedVal)
111302077da7SAlexey Zhikhartsev             Phi->addIncoming(ClonedVal, ClonedBB);
111402077da7SAlexey Zhikhartsev           else
111502077da7SAlexey Zhikhartsev             Phi->addIncoming(Incoming, ClonedBB);
111602077da7SAlexey Zhikhartsev         }
111702077da7SAlexey Zhikhartsev       }
111802077da7SAlexey Zhikhartsev     }
111902077da7SAlexey Zhikhartsev   }
112002077da7SAlexey Zhikhartsev 
112102077da7SAlexey Zhikhartsev   /// Sets the successor of PrevBB to be NewBB instead of OldBB. Note that all
112202077da7SAlexey Zhikhartsev   /// other successors are kept as well.
updatePredecessor__anon91a52f600211::TransformDFA112302077da7SAlexey Zhikhartsev   void updatePredecessor(BasicBlock *PrevBB, BasicBlock *OldBB,
112402077da7SAlexey Zhikhartsev                          BasicBlock *NewBB, DomTreeUpdater *DTU) {
112502077da7SAlexey Zhikhartsev     // When a path is reused, there is a chance that predecessors were already
112602077da7SAlexey Zhikhartsev     // updated before. Check if the predecessor needs to be updated first.
112702077da7SAlexey Zhikhartsev     if (!isPredecessor(OldBB, PrevBB))
112802077da7SAlexey Zhikhartsev       return;
112902077da7SAlexey Zhikhartsev 
113002077da7SAlexey Zhikhartsev     Instruction *PrevTerm = PrevBB->getTerminator();
113102077da7SAlexey Zhikhartsev     for (unsigned Idx = 0; Idx < PrevTerm->getNumSuccessors(); Idx++) {
113202077da7SAlexey Zhikhartsev       if (PrevTerm->getSuccessor(Idx) == OldBB) {
113302077da7SAlexey Zhikhartsev         OldBB->removePredecessor(PrevBB, /* KeepOneInputPHIs = */ true);
113402077da7SAlexey Zhikhartsev         PrevTerm->setSuccessor(Idx, NewBB);
113502077da7SAlexey Zhikhartsev       }
113602077da7SAlexey Zhikhartsev     }
113702077da7SAlexey Zhikhartsev     DTU->applyUpdates({{DominatorTree::Delete, PrevBB, OldBB},
113802077da7SAlexey Zhikhartsev                        {DominatorTree::Insert, PrevBB, NewBB}});
113902077da7SAlexey Zhikhartsev   }
114002077da7SAlexey Zhikhartsev 
114102077da7SAlexey Zhikhartsev   /// Add new value mappings to the DefMap to keep track of all new definitions
114202077da7SAlexey Zhikhartsev   /// for a particular instruction. These will be used while updating SSA form.
updateDefMap__anon91a52f600211::TransformDFA114302077da7SAlexey Zhikhartsev   void updateDefMap(DefMap &NewDefs, ValueToValueMapTy &VMap) {
11449d555b4aSOlle Fredriksson     SmallVector<std::pair<Instruction *, Instruction *>> NewDefsVector;
11459d555b4aSOlle Fredriksson     NewDefsVector.reserve(VMap.size());
11469d555b4aSOlle Fredriksson 
114702077da7SAlexey Zhikhartsev     for (auto Entry : VMap) {
114802077da7SAlexey Zhikhartsev       Instruction *Inst =
114902077da7SAlexey Zhikhartsev           dyn_cast<Instruction>(const_cast<Value *>(Entry.first));
115002077da7SAlexey Zhikhartsev       if (!Inst || !Entry.second || isa<BranchInst>(Inst) ||
115102077da7SAlexey Zhikhartsev           isa<SwitchInst>(Inst)) {
115202077da7SAlexey Zhikhartsev         continue;
115302077da7SAlexey Zhikhartsev       }
115402077da7SAlexey Zhikhartsev 
115502077da7SAlexey Zhikhartsev       Instruction *Cloned = dyn_cast<Instruction>(Entry.second);
115602077da7SAlexey Zhikhartsev       if (!Cloned)
115702077da7SAlexey Zhikhartsev         continue;
115802077da7SAlexey Zhikhartsev 
11599d555b4aSOlle Fredriksson       NewDefsVector.push_back({Inst, Cloned});
116002077da7SAlexey Zhikhartsev     }
11619d555b4aSOlle Fredriksson 
11629d555b4aSOlle Fredriksson     // Sort the defs to get deterministic insertion order into NewDefs.
11639d555b4aSOlle Fredriksson     sort(NewDefsVector, [](const auto &LHS, const auto &RHS) {
11649d555b4aSOlle Fredriksson       if (LHS.first == RHS.first)
11659d555b4aSOlle Fredriksson         return LHS.second->comesBefore(RHS.second);
11669d555b4aSOlle Fredriksson       return LHS.first->comesBefore(RHS.first);
11679d555b4aSOlle Fredriksson     });
11689d555b4aSOlle Fredriksson 
11699d555b4aSOlle Fredriksson     for (const auto &KV : NewDefsVector)
11709d555b4aSOlle Fredriksson       NewDefs[KV.first].push_back(KV.second);
117102077da7SAlexey Zhikhartsev   }
117202077da7SAlexey Zhikhartsev 
117302077da7SAlexey Zhikhartsev   /// Update the last branch of a particular cloned path to point to the correct
117402077da7SAlexey Zhikhartsev   /// case successor.
117502077da7SAlexey Zhikhartsev   ///
117602077da7SAlexey Zhikhartsev   /// Note that this is an optional step and would have been done in later
117702077da7SAlexey Zhikhartsev   /// optimizations, but it makes the CFG significantly easier to work with.
updateLastSuccessor__anon91a52f600211::TransformDFA117802077da7SAlexey Zhikhartsev   void updateLastSuccessor(ThreadingPath &TPath,
117902077da7SAlexey Zhikhartsev                            DuplicateBlockMap &DuplicateMap,
118002077da7SAlexey Zhikhartsev                            DomTreeUpdater *DTU) {
118102077da7SAlexey Zhikhartsev     uint64_t NextState = TPath.getExitValue();
118202077da7SAlexey Zhikhartsev     BasicBlock *BB = TPath.getPath().back();
118302077da7SAlexey Zhikhartsev     BasicBlock *LastBlock = getClonedBB(BB, NextState, DuplicateMap);
118402077da7SAlexey Zhikhartsev 
118502077da7SAlexey Zhikhartsev     // Note multiple paths can end at the same block so check that it is not
118602077da7SAlexey Zhikhartsev     // updated yet
118702077da7SAlexey Zhikhartsev     if (!isa<SwitchInst>(LastBlock->getTerminator()))
118802077da7SAlexey Zhikhartsev       return;
118902077da7SAlexey Zhikhartsev     SwitchInst *Switch = cast<SwitchInst>(LastBlock->getTerminator());
119002077da7SAlexey Zhikhartsev     BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState);
119102077da7SAlexey Zhikhartsev 
119202077da7SAlexey Zhikhartsev     std::vector<DominatorTree::UpdateType> DTUpdates;
119302077da7SAlexey Zhikhartsev     SmallPtrSet<BasicBlock *, 4> SuccSet;
119402077da7SAlexey Zhikhartsev     for (BasicBlock *Succ : successors(LastBlock)) {
119502077da7SAlexey Zhikhartsev       if (Succ != NextCase && SuccSet.insert(Succ).second)
119602077da7SAlexey Zhikhartsev         DTUpdates.push_back({DominatorTree::Delete, LastBlock, Succ});
119702077da7SAlexey Zhikhartsev     }
119802077da7SAlexey Zhikhartsev 
119902077da7SAlexey Zhikhartsev     Switch->eraseFromParent();
120002077da7SAlexey Zhikhartsev     BranchInst::Create(NextCase, LastBlock);
120102077da7SAlexey Zhikhartsev 
120202077da7SAlexey Zhikhartsev     DTU->applyUpdates(DTUpdates);
120302077da7SAlexey Zhikhartsev   }
120402077da7SAlexey Zhikhartsev 
120502077da7SAlexey Zhikhartsev   /// After cloning blocks, some of the phi nodes have extra incoming values
120602077da7SAlexey Zhikhartsev   /// that are no longer used. This function removes them.
cleanPhiNodes__anon91a52f600211::TransformDFA120702077da7SAlexey Zhikhartsev   void cleanPhiNodes(BasicBlock *BB) {
120802077da7SAlexey Zhikhartsev     // If BB is no longer reachable, remove any remaining phi nodes
120902077da7SAlexey Zhikhartsev     if (pred_empty(BB)) {
121002077da7SAlexey Zhikhartsev       std::vector<PHINode *> PhiToRemove;
121102077da7SAlexey Zhikhartsev       for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) {
121202077da7SAlexey Zhikhartsev         PhiToRemove.push_back(Phi);
121302077da7SAlexey Zhikhartsev       }
121402077da7SAlexey Zhikhartsev       for (PHINode *PN : PhiToRemove) {
1215*53dc0f10SNuno Lopes         PN->replaceAllUsesWith(PoisonValue::get(PN->getType()));
121602077da7SAlexey Zhikhartsev         PN->eraseFromParent();
121702077da7SAlexey Zhikhartsev       }
121802077da7SAlexey Zhikhartsev       return;
121902077da7SAlexey Zhikhartsev     }
122002077da7SAlexey Zhikhartsev 
122102077da7SAlexey Zhikhartsev     // Remove any incoming values that come from an invalid predecessor
122202077da7SAlexey Zhikhartsev     for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) {
122302077da7SAlexey Zhikhartsev       std::vector<BasicBlock *> BlocksToRemove;
122402077da7SAlexey Zhikhartsev       for (BasicBlock *IncomingBB : Phi->blocks()) {
122502077da7SAlexey Zhikhartsev         if (!isPredecessor(BB, IncomingBB))
122602077da7SAlexey Zhikhartsev           BlocksToRemove.push_back(IncomingBB);
122702077da7SAlexey Zhikhartsev       }
122802077da7SAlexey Zhikhartsev       for (BasicBlock *BB : BlocksToRemove)
122902077da7SAlexey Zhikhartsev         Phi->removeIncomingValue(BB);
123002077da7SAlexey Zhikhartsev     }
123102077da7SAlexey Zhikhartsev   }
123202077da7SAlexey Zhikhartsev 
123302077da7SAlexey Zhikhartsev   /// Checks if BB was already cloned for a particular next state value. If it
123402077da7SAlexey Zhikhartsev   /// was then it returns this cloned block, and otherwise null.
getClonedBB__anon91a52f600211::TransformDFA123502077da7SAlexey Zhikhartsev   BasicBlock *getClonedBB(BasicBlock *BB, uint64_t NextState,
123602077da7SAlexey Zhikhartsev                           DuplicateBlockMap &DuplicateMap) {
123702077da7SAlexey Zhikhartsev     CloneList ClonedBBs = DuplicateMap[BB];
123802077da7SAlexey Zhikhartsev 
123902077da7SAlexey Zhikhartsev     // Find an entry in the CloneList with this NextState. If it exists then
124002077da7SAlexey Zhikhartsev     // return the corresponding BB
124102077da7SAlexey Zhikhartsev     auto It = llvm::find_if(ClonedBBs, [NextState](const ClonedBlock &C) {
124202077da7SAlexey Zhikhartsev       return C.State == NextState;
124302077da7SAlexey Zhikhartsev     });
124402077da7SAlexey Zhikhartsev     return It != ClonedBBs.end() ? (*It).BB : nullptr;
124502077da7SAlexey Zhikhartsev   }
124602077da7SAlexey Zhikhartsev 
124702077da7SAlexey Zhikhartsev   /// Helper to get the successor corresponding to a particular case value for
124802077da7SAlexey Zhikhartsev   /// a switch statement.
getNextCaseSuccessor__anon91a52f600211::TransformDFA124902077da7SAlexey Zhikhartsev   BasicBlock *getNextCaseSuccessor(SwitchInst *Switch, uint64_t NextState) {
125002077da7SAlexey Zhikhartsev     BasicBlock *NextCase = nullptr;
125102077da7SAlexey Zhikhartsev     for (auto Case : Switch->cases()) {
125202077da7SAlexey Zhikhartsev       if (Case.getCaseValue()->getZExtValue() == NextState) {
125302077da7SAlexey Zhikhartsev         NextCase = Case.getCaseSuccessor();
125402077da7SAlexey Zhikhartsev         break;
125502077da7SAlexey Zhikhartsev       }
125602077da7SAlexey Zhikhartsev     }
125702077da7SAlexey Zhikhartsev     if (!NextCase)
125802077da7SAlexey Zhikhartsev       NextCase = Switch->getDefaultDest();
125902077da7SAlexey Zhikhartsev     return NextCase;
126002077da7SAlexey Zhikhartsev   }
126102077da7SAlexey Zhikhartsev 
126202077da7SAlexey Zhikhartsev   /// Returns true if IncomingBB is a predecessor of BB.
isPredecessor__anon91a52f600211::TransformDFA126302077da7SAlexey Zhikhartsev   bool isPredecessor(BasicBlock *BB, BasicBlock *IncomingBB) {
1264f83a88a1SKazu Hirata     return llvm::is_contained(predecessors(BB), IncomingBB);
126502077da7SAlexey Zhikhartsev   }
126602077da7SAlexey Zhikhartsev 
126702077da7SAlexey Zhikhartsev   AllSwitchPaths *SwitchPaths;
126802077da7SAlexey Zhikhartsev   DominatorTree *DT;
126902077da7SAlexey Zhikhartsev   AssumptionCache *AC;
127002077da7SAlexey Zhikhartsev   TargetTransformInfo *TTI;
127102077da7SAlexey Zhikhartsev   OptimizationRemarkEmitter *ORE;
127202077da7SAlexey Zhikhartsev   SmallPtrSet<const Value *, 32> EphValues;
127302077da7SAlexey Zhikhartsev   std::vector<ThreadingPath> TPaths;
127402077da7SAlexey Zhikhartsev };
127502077da7SAlexey Zhikhartsev 
run(Function & F)127602077da7SAlexey Zhikhartsev bool DFAJumpThreading::run(Function &F) {
127702077da7SAlexey Zhikhartsev   LLVM_DEBUG(dbgs() << "\nDFA Jump threading: " << F.getName() << "\n");
127802077da7SAlexey Zhikhartsev 
127902077da7SAlexey Zhikhartsev   if (F.hasOptSize()) {
128002077da7SAlexey Zhikhartsev     LLVM_DEBUG(dbgs() << "Skipping due to the 'minsize' attribute\n");
128102077da7SAlexey Zhikhartsev     return false;
128202077da7SAlexey Zhikhartsev   }
128302077da7SAlexey Zhikhartsev 
128402077da7SAlexey Zhikhartsev   if (ClViewCfgBefore)
128502077da7SAlexey Zhikhartsev     F.viewCFG();
128602077da7SAlexey Zhikhartsev 
128702077da7SAlexey Zhikhartsev   SmallVector<AllSwitchPaths, 2> ThreadableLoops;
128802077da7SAlexey Zhikhartsev   bool MadeChanges = false;
128902077da7SAlexey Zhikhartsev 
129002077da7SAlexey Zhikhartsev   for (BasicBlock &BB : F) {
129102077da7SAlexey Zhikhartsev     auto *SI = dyn_cast<SwitchInst>(BB.getTerminator());
129202077da7SAlexey Zhikhartsev     if (!SI)
129302077da7SAlexey Zhikhartsev       continue;
129402077da7SAlexey Zhikhartsev 
129502077da7SAlexey Zhikhartsev     LLVM_DEBUG(dbgs() << "\nCheck if SwitchInst in BB " << BB.getName()
12968b0d7634SAlex Zhikhartsev                       << " is a candidate\n");
129702077da7SAlexey Zhikhartsev     MainSwitch Switch(SI, ORE);
129802077da7SAlexey Zhikhartsev 
129902077da7SAlexey Zhikhartsev     if (!Switch.getInstr())
130002077da7SAlexey Zhikhartsev       continue;
130102077da7SAlexey Zhikhartsev 
130202077da7SAlexey Zhikhartsev     LLVM_DEBUG(dbgs() << "\nSwitchInst in BB " << BB.getName() << " is a "
130302077da7SAlexey Zhikhartsev                       << "candidate for jump threading\n");
130402077da7SAlexey Zhikhartsev     LLVM_DEBUG(SI->dump());
130502077da7SAlexey Zhikhartsev 
130602077da7SAlexey Zhikhartsev     unfoldSelectInstrs(DT, Switch.getSelectInsts());
130702077da7SAlexey Zhikhartsev     if (!Switch.getSelectInsts().empty())
130802077da7SAlexey Zhikhartsev       MadeChanges = true;
130902077da7SAlexey Zhikhartsev 
131002077da7SAlexey Zhikhartsev     AllSwitchPaths SwitchPaths(&Switch, ORE);
131102077da7SAlexey Zhikhartsev     SwitchPaths.run();
131202077da7SAlexey Zhikhartsev 
131302077da7SAlexey Zhikhartsev     if (SwitchPaths.getNumThreadingPaths() > 0) {
131402077da7SAlexey Zhikhartsev       ThreadableLoops.push_back(SwitchPaths);
131502077da7SAlexey Zhikhartsev 
131602077da7SAlexey Zhikhartsev       // For the time being limit this optimization to occurring once in a
131702077da7SAlexey Zhikhartsev       // function since it can change the CFG significantly. This is not a
131802077da7SAlexey Zhikhartsev       // strict requirement but it can cause buggy behavior if there is an
131902077da7SAlexey Zhikhartsev       // overlap of blocks in different opportunities. There is a lot of room to
132002077da7SAlexey Zhikhartsev       // experiment with catching more opportunities here.
132102077da7SAlexey Zhikhartsev       break;
132202077da7SAlexey Zhikhartsev     }
132302077da7SAlexey Zhikhartsev   }
132402077da7SAlexey Zhikhartsev 
132502077da7SAlexey Zhikhartsev   SmallPtrSet<const Value *, 32> EphValues;
132602077da7SAlexey Zhikhartsev   if (ThreadableLoops.size() > 0)
132702077da7SAlexey Zhikhartsev     CodeMetrics::collectEphemeralValues(&F, AC, EphValues);
132802077da7SAlexey Zhikhartsev 
132902077da7SAlexey Zhikhartsev   for (AllSwitchPaths SwitchPaths : ThreadableLoops) {
133002077da7SAlexey Zhikhartsev     TransformDFA Transform(&SwitchPaths, DT, AC, TTI, ORE, EphValues);
133102077da7SAlexey Zhikhartsev     Transform.run();
133202077da7SAlexey Zhikhartsev     MadeChanges = true;
133302077da7SAlexey Zhikhartsev   }
133402077da7SAlexey Zhikhartsev 
133502077da7SAlexey Zhikhartsev #ifdef EXPENSIVE_CHECKS
133602077da7SAlexey Zhikhartsev   assert(DT->verify(DominatorTree::VerificationLevel::Full));
133702077da7SAlexey Zhikhartsev   verifyFunction(F, &dbgs());
133802077da7SAlexey Zhikhartsev #endif
133902077da7SAlexey Zhikhartsev 
134002077da7SAlexey Zhikhartsev   return MadeChanges;
134102077da7SAlexey Zhikhartsev }
134202077da7SAlexey Zhikhartsev 
134302077da7SAlexey Zhikhartsev } // end anonymous namespace
134402077da7SAlexey Zhikhartsev 
134502077da7SAlexey Zhikhartsev /// Integrate with the new Pass Manager
run(Function & F,FunctionAnalysisManager & AM)134602077da7SAlexey Zhikhartsev PreservedAnalyses DFAJumpThreadingPass::run(Function &F,
134702077da7SAlexey Zhikhartsev                                             FunctionAnalysisManager &AM) {
134802077da7SAlexey Zhikhartsev   AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
134902077da7SAlexey Zhikhartsev   DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
135002077da7SAlexey Zhikhartsev   TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
135102077da7SAlexey Zhikhartsev   OptimizationRemarkEmitter ORE(&F);
135202077da7SAlexey Zhikhartsev 
135302077da7SAlexey Zhikhartsev   if (!DFAJumpThreading(&AC, &DT, &TTI, &ORE).run(F))
135402077da7SAlexey Zhikhartsev     return PreservedAnalyses::all();
135502077da7SAlexey Zhikhartsev 
135602077da7SAlexey Zhikhartsev   PreservedAnalyses PA;
135702077da7SAlexey Zhikhartsev   PA.preserve<DominatorTreeAnalysis>();
135802077da7SAlexey Zhikhartsev   return PA;
135902077da7SAlexey Zhikhartsev }
1360