diff options
Diffstat (limited to 'llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp')
| -rw-r--r-- | llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp | 518 |
1 files changed, 282 insertions, 236 deletions
diff --git a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp index 4371b821eae6..8a5c506eed69 100644 --- a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp @@ -76,7 +76,6 @@ #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/SSAUpdaterBulk.h" #include "llvm/Transforms/Utils/ValueMapper.h" -#include <algorithm> #include <deque> #ifdef EXPENSIVE_CHECKS @@ -106,6 +105,12 @@ static cl::opt<unsigned> MaxPathLength( cl::desc("Max number of blocks searched to find a threading path"), cl::Hidden, cl::init(20)); +static cl::opt<unsigned> MaxNumVisitiedPaths( + "dfa-max-num-visited-paths", + cl::desc( + "Max number of blocks visited while enumerating paths around a switch"), + cl::Hidden, cl::init(2500)); + static cl::opt<unsigned> MaxNumPaths("dfa-max-num-paths", cl::desc("Max number of paths enumerated around a switch"), @@ -149,9 +154,7 @@ private: unfoldSelectInstrs(DominatorTree *DT, const SmallVector<SelectInstToUnfold, 4> &SelectInsts) { DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); - SmallVector<SelectInstToUnfold, 4> Stack; - for (SelectInstToUnfold SIToUnfold : SelectInsts) - Stack.push_back(SIToUnfold); + SmallVector<SelectInstToUnfold, 4> Stack(SelectInsts); while (!Stack.empty()) { SelectInstToUnfold SIToUnfold = Stack.pop_back_val(); @@ -177,24 +180,6 @@ private: namespace { -/// Create a new basic block and sink \p SIToSink into it. -void 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) { - assert(SIToSink->hasOneUse()); - assert(NewBlock); - assert(NewBranch); - *NewBlock = BasicBlock::Create(SI->getContext(), NewBBName, - EndBlock->getParent(), EndBlock); - NewBBs->push_back(*NewBlock); - *NewBranch = BranchInst::Create(EndBlock, *NewBlock); - SIToSink->moveBefore(*NewBranch); - NewSIsToUnfold->push_back(SelectInstToUnfold(SIToSink, SIUse)); - DTU->applyUpdates({{DominatorTree::Insert, *NewBlock, EndBlock}}); -} - /// Unfold the select instruction held in \p SIToUnfold by replacing it with /// control flow. /// @@ -208,105 +193,145 @@ void unfold(DomTreeUpdater *DTU, LoopInfo *LI, SelectInstToUnfold SIToUnfold, SelectInst *SI = SIToUnfold.getInst(); PHINode *SIUse = SIToUnfold.getUse(); BasicBlock *StartBlock = SI->getParent(); - BasicBlock *EndBlock = SIUse->getParent(); BranchInst *StartBlockTerm = dyn_cast<BranchInst>(StartBlock->getTerminator()); - assert(StartBlockTerm && StartBlockTerm->isUnconditional()); + assert(StartBlockTerm); assert(SI->hasOneUse()); - // These are the new basic blocks for the conditional branch. - // At least one will become an actual new basic block. - BasicBlock *TrueBlock = nullptr; - BasicBlock *FalseBlock = nullptr; - BranchInst *TrueBranch = nullptr; - BranchInst *FalseBranch = nullptr; - - // Sink select instructions to be able to unfold them later. - if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getTrueValue())) { - createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock, - "si.unfold.true", &TrueBlock, &TrueBranch, - NewSIsToUnfold, NewBBs); - } - if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getFalseValue())) { - createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock, - "si.unfold.false", &FalseBlock, - &FalseBranch, NewSIsToUnfold, NewBBs); - } - - // If there was nothing to sink, then arbitrarily choose the 'false' side - // for a new input value to the PHI. - if (!TrueBlock && !FalseBlock) { - FalseBlock = BasicBlock::Create(SI->getContext(), "si.unfold.false", - EndBlock->getParent(), EndBlock); - NewBBs->push_back(FalseBlock); - BranchInst::Create(EndBlock, FalseBlock); - DTU->applyUpdates({{DominatorTree::Insert, FalseBlock, EndBlock}}); - } + if (StartBlockTerm->isUnconditional()) { + BasicBlock *EndBlock = StartBlock->getUniqueSuccessor(); + // Arbitrarily choose the 'false' side for a new input value to the PHI. + BasicBlock *NewBlock = BasicBlock::Create( + SI->getContext(), Twine(SI->getName(), ".si.unfold.false"), + EndBlock->getParent(), EndBlock); + NewBBs->push_back(NewBlock); + BranchInst::Create(EndBlock, NewBlock); + DTU->applyUpdates({{DominatorTree::Insert, NewBlock, EndBlock}}); + + // StartBlock + // | \ + // | NewBlock + // | / + // EndBlock + Value *SIOp1 = SI->getTrueValue(); + Value *SIOp2 = SI->getFalseValue(); - // Insert the real conditional branch based on the original condition. - // If we did not create a new block for one of the 'true' or 'false' paths - // of the condition, it means that side of the branch goes to the end block - // directly and the path originates from the start block from the point of - // view of the new PHI. - BasicBlock *TT = EndBlock; - BasicBlock *FT = EndBlock; - if (TrueBlock && FalseBlock) { - // A diamond. - TT = TrueBlock; - FT = FalseBlock; - - // Update the phi node of SI. - SIUse->addIncoming(SI->getTrueValue(), TrueBlock); - SIUse->addIncoming(SI->getFalseValue(), FalseBlock); + PHINode *NewPhi = PHINode::Create(SIUse->getType(), 1, + Twine(SIOp2->getName(), ".si.unfold.phi"), + NewBlock->getFirstInsertionPt()); + NewPhi->addIncoming(SIOp2, StartBlock); // Update any other PHI nodes in EndBlock. for (PHINode &Phi : EndBlock->phis()) { - if (&Phi != SIUse) { - Value *OrigValue = Phi.getIncomingValueForBlock(StartBlock); - Phi.addIncoming(OrigValue, TrueBlock); - Phi.addIncoming(OrigValue, FalseBlock); + if (SIUse == &Phi) + continue; + Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), NewBlock); + } + + // Update the phi node of SI, which is its only use. + if (EndBlock == SIUse->getParent()) { + SIUse->addIncoming(NewPhi, NewBlock); + SIUse->replaceUsesOfWith(SI, SIOp1); + } else { + PHINode *EndPhi = PHINode::Create(SIUse->getType(), pred_size(EndBlock), + Twine(SI->getName(), ".si.unfold.phi"), + EndBlock->getFirstInsertionPt()); + for (BasicBlock *Pred : predecessors(EndBlock)) { + if (Pred != StartBlock && Pred != NewBlock) + EndPhi->addIncoming(EndPhi, Pred); } - // Remove incoming place of original StartBlock, which comes in a indirect - // way (through TrueBlock and FalseBlock) now. - Phi.removeIncomingValue(StartBlock, /* DeletePHIIfEmpty = */ false); + EndPhi->addIncoming(SIOp1, StartBlock); + EndPhi->addIncoming(NewPhi, NewBlock); + SIUse->replaceUsesOfWith(SI, EndPhi); + SIUse = EndPhi; } - } else { - BasicBlock *NewBlock = nullptr; - Value *SIOp1 = SI->getTrueValue(); - Value *SIOp2 = SI->getFalseValue(); - // A triangle pointing right. - if (!TrueBlock) { - NewBlock = FalseBlock; - FT = FalseBlock; - } - // A triangle pointing left. - else { - NewBlock = TrueBlock; - TT = TrueBlock; - std::swap(SIOp1, SIOp2); - } + if (auto *OpSi = dyn_cast<SelectInst>(SIOp1)) + NewSIsToUnfold->push_back(SelectInstToUnfold(OpSi, SIUse)); + if (auto *OpSi = dyn_cast<SelectInst>(SIOp2)) + NewSIsToUnfold->push_back(SelectInstToUnfold(OpSi, NewPhi)); - // Update the phi node of SI. - for (unsigned Idx = 0; Idx < SIUse->getNumIncomingValues(); ++Idx) { - if (SIUse->getIncomingBlock(Idx) == StartBlock) - SIUse->setIncomingValue(Idx, SIOp1); - } - SIUse->addIncoming(SIOp2, NewBlock); + // Insert the real conditional branch based on the original condition. + StartBlockTerm->eraseFromParent(); + BranchInst::Create(EndBlock, NewBlock, SI->getCondition(), StartBlock); + DTU->applyUpdates({{DominatorTree::Insert, StartBlock, EndBlock}, + {DominatorTree::Insert, StartBlock, NewBlock}}); + } else { + BasicBlock *EndBlock = SIUse->getParent(); + BasicBlock *NewBlockT = BasicBlock::Create( + SI->getContext(), Twine(SI->getName(), ".si.unfold.true"), + EndBlock->getParent(), EndBlock); + BasicBlock *NewBlockF = BasicBlock::Create( + SI->getContext(), Twine(SI->getName(), ".si.unfold.false"), + EndBlock->getParent(), EndBlock); + + NewBBs->push_back(NewBlockT); + NewBBs->push_back(NewBlockF); + + // Def only has one use in EndBlock. + // Before transformation: + // StartBlock(Def) + // | \ + // EndBlock OtherBlock + // (Use) + // + // After transformation: + // StartBlock(Def) + // | \ + // | OtherBlock + // NewBlockT + // | \ + // | NewBlockF + // | / + // | / + // EndBlock + // (Use) + BranchInst::Create(EndBlock, NewBlockF); + // Insert the real conditional branch based on the original condition. + BranchInst::Create(EndBlock, NewBlockF, SI->getCondition(), NewBlockT); + DTU->applyUpdates({{DominatorTree::Insert, NewBlockT, NewBlockF}, + {DominatorTree::Insert, NewBlockT, EndBlock}, + {DominatorTree::Insert, NewBlockF, EndBlock}}); + + Value *TrueVal = SI->getTrueValue(); + Value *FalseVal = SI->getFalseValue(); + + PHINode *NewPhiT = PHINode::Create( + SIUse->getType(), 1, Twine(TrueVal->getName(), ".si.unfold.phi"), + NewBlockT->getFirstInsertionPt()); + PHINode *NewPhiF = PHINode::Create( + SIUse->getType(), 1, Twine(FalseVal->getName(), ".si.unfold.phi"), + NewBlockF->getFirstInsertionPt()); + NewPhiT->addIncoming(TrueVal, StartBlock); + NewPhiF->addIncoming(FalseVal, NewBlockT); + + if (auto *TrueSI = dyn_cast<SelectInst>(TrueVal)) + NewSIsToUnfold->push_back(SelectInstToUnfold(TrueSI, NewPhiT)); + if (auto *FalseSi = dyn_cast<SelectInst>(FalseVal)) + NewSIsToUnfold->push_back(SelectInstToUnfold(FalseSi, NewPhiF)); + + SIUse->addIncoming(NewPhiT, NewBlockT); + SIUse->addIncoming(NewPhiF, NewBlockF); + SIUse->removeIncomingValue(StartBlock); // Update any other PHI nodes in EndBlock. - for (auto II = EndBlock->begin(); PHINode *Phi = dyn_cast<PHINode>(II); - ++II) { - if (Phi != SIUse) - Phi->addIncoming(Phi->getIncomingValueForBlock(StartBlock), NewBlock); + for (PHINode &Phi : EndBlock->phis()) { + if (SIUse == &Phi) + continue; + Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), NewBlockT); + Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), NewBlockF); + Phi.removeIncomingValue(StartBlock); } + + // Update the appropriate successor of the start block to point to the new + // unfolded block. + unsigned SuccNum = StartBlockTerm->getSuccessor(1) == EndBlock ? 1 : 0; + StartBlockTerm->setSuccessor(SuccNum, NewBlockT); + DTU->applyUpdates({{DominatorTree::Delete, StartBlock, EndBlock}, + {DominatorTree::Insert, StartBlock, NewBlockT}}); } - StartBlockTerm->eraseFromParent(); - BranchInst::Create(TT, FT, SI->getCondition(), StartBlock); - DTU->applyUpdates({{DominatorTree::Insert, StartBlock, TT}, - {DominatorTree::Insert, StartBlock, FT}}); // Preserve loop info if (Loop *L = LI->getLoopFor(SI->getParent())) { @@ -372,6 +397,11 @@ struct ThreadingPath { /// Path is a list of basic blocks. const PathType &getPath() const { return Path; } void setPath(const PathType &NewPath) { Path = NewPath; } + void push_back(BasicBlock *BB) { Path.push_back(BB); } + void push_front(BasicBlock *BB) { Path.push_front(BB); } + void appendExcludingFirst(const PathType &OtherPath) { + Path.insert(Path.end(), OtherPath.begin() + 1, OtherPath.end()); + } void print(raw_ostream &OS) const { OS << Path << " [ " << ExitVal << ", " << DBB->getName() << " ]"; @@ -483,10 +513,8 @@ private: void addToQueue(Value *Val, BasicBlock *BB, std::deque<std::pair<Value *, BasicBlock *>> &Q, SmallSet<Value *, 16> &SeenValues) { - if (SeenValues.contains(Val)) - return; - Q.push_back({Val, BB}); - SeenValues.insert(Val); + if (SeenValues.insert(Val).second) + Q.push_back({Val, BB}); } bool isValidSelectInst(SelectInst *SI) { @@ -530,9 +558,9 @@ private: struct AllSwitchPaths { AllSwitchPaths(const MainSwitch *MSwitch, OptimizationRemarkEmitter *ORE, - LoopInfo *LI) + LoopInfo *LI, Loop *L) : Switch(MSwitch->getInstr()), SwitchBlock(Switch->getParent()), ORE(ORE), - LI(LI) {} + LI(LI), SwitchOuterLoop(L) {} std::vector<ThreadingPath> &getThreadingPaths() { return TPaths; } unsigned getNumThreadingPaths() { return TPaths.size(); } @@ -540,10 +568,7 @@ struct AllSwitchPaths { BasicBlock *getSwitchBlock() { return SwitchBlock; } void run() { - VisitedBlocks Visited; - PathsType LoopPaths = paths(SwitchBlock, Visited, /* PathDepth = */ 1); - StateDefMap StateDef = getStateDefMap(LoopPaths); - + StateDefMap StateDef = getStateDefMap(); if (StateDef.empty()) { ORE->emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable", @@ -553,42 +578,118 @@ struct AllSwitchPaths { return; } - for (const PathType &Path : LoopPaths) { - ThreadingPath TPath; - - const BasicBlock *PrevBB = Path.back(); - for (const BasicBlock *BB : Path) { - if (StateDef.contains(BB)) { - const PHINode *Phi = dyn_cast<PHINode>(StateDef[BB]); - assert(Phi && "Expected a state-defining instr to be a phi node."); - - const Value *V = Phi->getIncomingValueForBlock(PrevBB); - if (const ConstantInt *C = dyn_cast<const ConstantInt>(V)) { - TPath.setExitValue(C); - TPath.setDeterminator(BB); - TPath.setPath(Path); - } - } + auto *SwitchPhi = cast<PHINode>(Switch->getOperand(0)); + auto *SwitchPhiDefBB = SwitchPhi->getParent(); + VisitedBlocks VB; + // Get paths from the determinator BBs to SwitchPhiDefBB + std::vector<ThreadingPath> PathsToPhiDef = + getPathsFromStateDefMap(StateDef, SwitchPhi, VB); + if (SwitchPhiDefBB == SwitchBlock) { + TPaths = std::move(PathsToPhiDef); + return; + } - // Switch block is the determinator, this is the final exit value. - if (TPath.isExitValueSet() && BB == Path.front()) - break; + // Find and append paths from SwitchPhiDefBB to SwitchBlock. + PathsType PathsToSwitchBB = + paths(SwitchPhiDefBB, SwitchBlock, VB, /* PathDepth = */ 1); + if (PathsToSwitchBB.empty()) + return; - PrevBB = BB; + std::vector<ThreadingPath> TempList; + for (const ThreadingPath &Path : PathsToPhiDef) { + for (const PathType &PathToSw : PathsToSwitchBB) { + ThreadingPath PathCopy(Path); + PathCopy.appendExcludingFirst(PathToSw); + TempList.push_back(PathCopy); } - - if (TPath.isExitValueSet() && isSupported(TPath)) - TPaths.push_back(TPath); } + TPaths = std::move(TempList); } private: // Value: an instruction that defines a switch state; // Key: the parent basic block of that instruction. typedef DenseMap<const BasicBlock *, const PHINode *> StateDefMap; + std::vector<ThreadingPath> getPathsFromStateDefMap(StateDefMap &StateDef, + PHINode *Phi, + VisitedBlocks &VB) { + std::vector<ThreadingPath> Res; + auto *PhiBB = Phi->getParent(); + VB.insert(PhiBB); + + VisitedBlocks UniqueBlocks; + for (auto *IncomingBB : Phi->blocks()) { + if (!UniqueBlocks.insert(IncomingBB).second) + continue; + if (!SwitchOuterLoop->contains(IncomingBB)) + continue; + + Value *IncomingValue = Phi->getIncomingValueForBlock(IncomingBB); + // We found the determinator. This is the start of our path. + if (auto *C = dyn_cast<ConstantInt>(IncomingValue)) { + // SwitchBlock is the determinator, unsupported unless its also the def. + if (PhiBB == SwitchBlock && + SwitchBlock != cast<PHINode>(Switch->getOperand(0))->getParent()) + continue; + ThreadingPath NewPath; + NewPath.setDeterminator(PhiBB); + NewPath.setExitValue(C); + // Don't add SwitchBlock at the start, this is handled later. + if (IncomingBB != SwitchBlock) + NewPath.push_back(IncomingBB); + NewPath.push_back(PhiBB); + Res.push_back(NewPath); + continue; + } + // Don't get into a cycle. + if (VB.contains(IncomingBB) || IncomingBB == SwitchBlock) + continue; + // Recurse up the PHI chain. + auto *IncomingPhi = dyn_cast<PHINode>(IncomingValue); + if (!IncomingPhi) + continue; + auto *IncomingPhiDefBB = IncomingPhi->getParent(); + if (!StateDef.contains(IncomingPhiDefBB)) + continue; + + // Direct predecessor, just add to the path. + if (IncomingPhiDefBB == IncomingBB) { + std::vector<ThreadingPath> PredPaths = + getPathsFromStateDefMap(StateDef, IncomingPhi, VB); + for (ThreadingPath &Path : PredPaths) { + Path.push_back(PhiBB); + Res.push_back(std::move(Path)); + } + continue; + } + // Not a direct predecessor, find intermediate paths to append to the + // existing path. + if (VB.contains(IncomingPhiDefBB)) + continue; + + PathsType IntermediatePaths; + IntermediatePaths = + paths(IncomingPhiDefBB, IncomingBB, VB, /* PathDepth = */ 1); + if (IntermediatePaths.empty()) + continue; + + std::vector<ThreadingPath> PredPaths = + getPathsFromStateDefMap(StateDef, IncomingPhi, VB); + for (const ThreadingPath &Path : PredPaths) { + for (const PathType &IPath : IntermediatePaths) { + ThreadingPath NewPath(Path); + NewPath.appendExcludingFirst(IPath); + NewPath.push_back(PhiBB); + Res.push_back(NewPath); + } + } + } + VB.erase(PhiBB); + return Res; + } - PathsType paths(BasicBlock *BB, VisitedBlocks &Visited, - unsigned PathDepth) const { + PathsType paths(BasicBlock *BB, BasicBlock *ToBB, VisitedBlocks &Visited, + unsigned PathDepth) { PathsType Res; // Stop exploring paths after visiting MaxPathLength blocks @@ -603,11 +704,12 @@ private: } Visited.insert(BB); + if (++NumVisited > MaxNumVisitiedPaths) + return Res; // Stop if we have reached the BB out of loop, since its successors have no // impact on the DFA. - // TODO: Do we need to stop exploring if BB is the outer loop of the switch? - if (!LI->getLoopFor(BB)) + if (!SwitchOuterLoop->contains(BB)) return Res; // Some blocks have multiple edges to the same successor, and this set @@ -617,9 +719,9 @@ private: if (!Successors.insert(Succ).second) continue; - // Found a cycle through the SwitchBlock - if (Succ == SwitchBlock) { - Res.push_back({BB}); + // Found a cycle through the final block. + if (Succ == ToBB) { + Res.push_back({BB, ToBB}); continue; } @@ -627,11 +729,19 @@ private: if (Visited.contains(Succ)) continue; - PathsType SuccPaths = paths(Succ, Visited, PathDepth + 1); - for (const PathType &Path : SuccPaths) { - PathType NewPath(Path); - NewPath.push_front(BB); - Res.push_back(NewPath); + auto *CurrLoop = LI->getLoopFor(BB); + // Unlikely to be beneficial. + if (Succ == CurrLoop->getHeader()) + continue; + // Skip for now, revisit this condition later to see the impact on + // coverage and compile time. + if (LI->getLoopFor(Succ) != CurrLoop) + continue; + + PathsType SuccPaths = paths(Succ, ToBB, Visited, PathDepth + 1); + for (PathType &Path : SuccPaths) { + Path.push_front(BB); + Res.push_back(Path); if (Res.size() >= MaxNumPaths) { return Res; } @@ -644,26 +754,15 @@ private: return Res; } - /// Walk the use-def chain and collect all the state-defining instructions. - /// - /// Return an empty map if unpredictable values encountered inside the basic - /// blocks of \p LoopPaths. - StateDefMap getStateDefMap(const PathsType &LoopPaths) const { + /// Walk the use-def chain and collect all the state-defining blocks and the + /// PHI nodes in those blocks that define the state. + StateDefMap getStateDefMap() const { StateDefMap Res; - - // Basic blocks belonging to any of the loops around the switch statement. - SmallPtrSet<BasicBlock *, 16> LoopBBs; - for (const PathType &Path : LoopPaths) { - for (BasicBlock *BB : Path) - LoopBBs.insert(BB); - } - - Value *FirstDef = Switch->getOperand(0); - - assert(isa<PHINode>(FirstDef) && "The first definition must be a phi."); + PHINode *FirstDef = dyn_cast<PHINode>(Switch->getOperand(0)); + assert(FirstDef && "The first definition must be a phi."); SmallVector<PHINode *, 8> Stack; - Stack.push_back(dyn_cast<PHINode>(FirstDef)); + Stack.push_back(FirstDef); SmallSet<Value *, 16> SeenValues; while (!Stack.empty()) { @@ -673,85 +772,28 @@ private: SeenValues.insert(CurPhi); for (BasicBlock *IncomingBB : CurPhi->blocks()) { - Value *Incoming = CurPhi->getIncomingValueForBlock(IncomingBB); - bool IsOutsideLoops = LoopBBs.count(IncomingBB) == 0; - if (Incoming == FirstDef || isa<ConstantInt>(Incoming) || - SeenValues.contains(Incoming) || IsOutsideLoops) { + PHINode *IncomingPhi = + dyn_cast<PHINode>(CurPhi->getIncomingValueForBlock(IncomingBB)); + if (!IncomingPhi) + continue; + bool IsOutsideLoops = !SwitchOuterLoop->contains(IncomingBB); + if (SeenValues.contains(IncomingPhi) || IsOutsideLoops) continue; - } - - // Any unpredictable value inside the loops means we must bail out. - if (!isa<PHINode>(Incoming)) - return StateDefMap(); - Stack.push_back(cast<PHINode>(Incoming)); + Stack.push_back(IncomingPhi); } } return Res; } - /// The determinator BB should precede the switch-defining BB. - /// - /// Otherwise, it is possible that the state defined in the determinator block - /// defines the state for the next iteration of the loop, rather than for the - /// current one. - /// - /// Currently supported paths: - /// \code - /// < switch bb1 determ def > [ 42, determ ] - /// < switch_and_def bb1 determ > [ 42, determ ] - /// < switch_and_def_and_determ bb1 > [ 42, switch_and_def_and_determ ] - /// \endcode - /// - /// Unsupported paths: - /// \code - /// < switch bb1 def determ > [ 43, determ ] - /// < switch_and_determ bb1 def > [ 43, switch_and_determ ] - /// \endcode - bool isSupported(const ThreadingPath &TPath) { - Instruction *SwitchCondI = dyn_cast<Instruction>(Switch->getCondition()); - assert(SwitchCondI); - if (!SwitchCondI) - return false; - - const BasicBlock *SwitchCondDefBB = SwitchCondI->getParent(); - const BasicBlock *SwitchCondUseBB = Switch->getParent(); - const BasicBlock *DeterminatorBB = TPath.getDeterminatorBB(); - - assert( - SwitchCondUseBB == TPath.getPath().front() && - "The first BB in a threading path should have the switch instruction"); - if (SwitchCondUseBB != TPath.getPath().front()) - return false; - - // Make DeterminatorBB the first element in Path. - PathType Path = TPath.getPath(); - auto ItDet = llvm::find(Path, DeterminatorBB); - std::rotate(Path.begin(), ItDet, Path.end()); - - bool IsDetBBSeen = false; - bool IsDefBBSeen = false; - bool IsUseBBSeen = false; - for (BasicBlock *BB : Path) { - if (BB == DeterminatorBB) - IsDetBBSeen = true; - if (BB == SwitchCondDefBB) - IsDefBBSeen = true; - if (BB == SwitchCondUseBB) - IsUseBBSeen = true; - if (IsDetBBSeen && IsUseBBSeen && !IsDefBBSeen) - return false; - } - - return true; - } - + unsigned NumVisited = 0; SwitchInst *Switch; BasicBlock *SwitchBlock; OptimizationRemarkEmitter *ORE; std::vector<ThreadingPath> TPaths; LoopInfo *LI; + Loop *SwitchOuterLoop; }; struct TransformDFA { @@ -905,9 +947,9 @@ private: BasicBlock *SwitchBlock = SwitchPaths->getSwitchBlock(); for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) { LLVM_DEBUG(dbgs() << TPath << "\n"); - PathType NewPath(TPath.getPath()); - NewPath.push_back(SwitchBlock); - TPath.setPath(NewPath); + // TODO: Fix exit path creation logic so that we dont need this + // placeholder. + TPath.push_front(SwitchBlock); } // Transform the ThreadingPaths and keep track of the cloned values @@ -1310,8 +1352,11 @@ bool DFAJumpThreading::run(Function &F) { << " is a candidate\n"); MainSwitch Switch(SI, LI, ORE); - if (!Switch.getInstr()) + if (!Switch.getInstr()) { + LLVM_DEBUG(dbgs() << "\nSwitchInst in BB " << BB.getName() << " is not a " + << "candidate for jump threading\n"); continue; + } LLVM_DEBUG(dbgs() << "\nSwitchInst in BB " << BB.getName() << " is a " << "candidate for jump threading\n"); @@ -1321,7 +1366,8 @@ bool DFAJumpThreading::run(Function &F) { if (!Switch.getSelectInsts().empty()) MadeChanges = true; - AllSwitchPaths SwitchPaths(&Switch, ORE, LI); + AllSwitchPaths SwitchPaths(&Switch, ORE, LI, + LI->getLoopFor(&BB)->getOutermostLoop()); SwitchPaths.run(); if (SwitchPaths.getNumThreadingPaths() > 0) { |
