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