diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LazyValueInfo.h" @@ -28,6 +29,7 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" @@ -9652,6 +9654,97 @@ BlockStatus.clear(); } + // Propagate across blocks. + BranchProbabilityInfo *BPInfo = + A.getInfoCache() + .getAnalysisResultForFunction( + *getAssociatedFunction()); + + SmallPtrSet Visited; + + SmallVector ExitPoints; + SmallVector Worklist; + Worklist.push_back(&getAssociatedFunction()->getEntryBlock()); + + SmallVector ExitBlocks; + + auto Propagate = [&](BasicBlock *Pred, BasicBlock *Block, + Optional &CurrentStatus) { + if (!BlockStatus.count(Pred)) + return true; + Optional PredStatus = BlockStatus[Pred]; + if (!PredStatus.hasValue()) + return true; + if (PredStatus.getValue()) { + // One of our predecessors are hot. + // If the edge is hot also we can assume that this block is hot. + if (BPInfo->isEdgeHot(Pred, Block)) { + CurrentStatus = true; + // We are done. + return false; + } + return true; + } + // Block is marked as either Cold or None. + CurrentStatus = false; + return true; + }; + // Propagate forwards. + while (!Worklist.empty()) { + BasicBlock *Block = Worklist.pop_back_val(); + + if (!Visited.insert(Block).second) + continue; + + bool IsExit = true; + for (BasicBlock *Succ : successors(Block)) { + Worklist.push_back(Succ); + IsExit = false; + } + // Collect exit blocks, we will uses this for backwards propagation. + if (IsExit) + ExitPoints.push_back(Block); + + // If the block already has information, skip this block. + if (BlockStatus.count(Block)) + continue; + + Optional &CurrentStatus = BlockStatus[Block]; + Optional OldStatus = CurrentStatus; + for (BasicBlock *Pred : predecessors(Block)) { + if (!Propagate(Pred, Block, CurrentStatus)) + break; + } + + // Track changes. + Change |= CurrentStatus == OldStatus ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + // Propagate backwards. + Visited.clear(); + Worklist.swap(ExitPoints); + + while (!Worklist.empty()) { + BasicBlock *Block = Worklist.pop_back_val(); + if (!Visited.insert(Block).second) + continue; + + Worklist.append(pred_begin(Block), pred_end(Block)); + + if (BlockStatus.count(Block)) + continue; + + Optional &CurrentStatus = BlockStatus[Block]; + Optional OldStatus = CurrentStatus; + for (BasicBlock *Succ : successors(Block)) { + if (!Propagate(Block, Succ, CurrentStatus)) + break; + } + Change |= CurrentStatus == OldStatus ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + return Change; }