18bcb0991SDimitry Andric //===-- SpeculateAnalyses.cpp --*- C++ -*-===// 28bcb0991SDimitry Andric // 38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric 98bcb0991SDimitry Andric #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h" 108bcb0991SDimitry Andric #include "llvm/ADT/ArrayRef.h" 118bcb0991SDimitry Andric #include "llvm/ADT/DenseMap.h" 128bcb0991SDimitry Andric #include "llvm/ADT/STLExtras.h" 138bcb0991SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 148bcb0991SDimitry Andric #include "llvm/ADT/SmallVector.h" 158bcb0991SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h" 168bcb0991SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h" 178bcb0991SDimitry Andric #include "llvm/Analysis/CFG.h" 188bcb0991SDimitry Andric #include "llvm/IR/PassManager.h" 198bcb0991SDimitry Andric #include "llvm/Passes/PassBuilder.h" 208bcb0991SDimitry Andric #include "llvm/Support/ErrorHandling.h" 218bcb0991SDimitry Andric 228bcb0991SDimitry Andric #include <algorithm> 238bcb0991SDimitry Andric 248bcb0991SDimitry Andric namespace { 258bcb0991SDimitry Andric using namespace llvm; 268bcb0991SDimitry Andric SmallVector<const BasicBlock *, 8> findBBwithCalls(const Function &F, 278bcb0991SDimitry Andric bool IndirectCall = false) { 288bcb0991SDimitry Andric SmallVector<const BasicBlock *, 8> BBs; 298bcb0991SDimitry Andric 308bcb0991SDimitry Andric auto findCallInst = [&IndirectCall](const Instruction &I) { 318bcb0991SDimitry Andric if (auto Call = dyn_cast<CallBase>(&I)) 328bcb0991SDimitry Andric return Call->isIndirectCall() ? IndirectCall : true; 338bcb0991SDimitry Andric else 348bcb0991SDimitry Andric return false; 358bcb0991SDimitry Andric }; 368bcb0991SDimitry Andric for (auto &BB : F) 378bcb0991SDimitry Andric if (findCallInst(*BB.getTerminator()) || 388bcb0991SDimitry Andric llvm::any_of(BB.instructionsWithoutDebug(), findCallInst)) 398bcb0991SDimitry Andric BBs.emplace_back(&BB); 408bcb0991SDimitry Andric 418bcb0991SDimitry Andric return BBs; 428bcb0991SDimitry Andric } 438bcb0991SDimitry Andric } // namespace 448bcb0991SDimitry Andric 458bcb0991SDimitry Andric // Implementations of Queries shouldn't need to lock the resources 468bcb0991SDimitry Andric // such as LLVMContext, each argument (function) has a non-shared LLVMContext 478bcb0991SDimitry Andric // Plus, if Queries contain states necessary locking scheme should be provided. 488bcb0991SDimitry Andric namespace llvm { 498bcb0991SDimitry Andric namespace orc { 508bcb0991SDimitry Andric 518bcb0991SDimitry Andric // Collect direct calls only 528bcb0991SDimitry Andric void SpeculateQuery::findCalles(const BasicBlock *BB, 538bcb0991SDimitry Andric DenseSet<StringRef> &CallesNames) { 548bcb0991SDimitry Andric assert(BB != nullptr && "Traversing Null BB to find calls?"); 558bcb0991SDimitry Andric 568bcb0991SDimitry Andric auto getCalledFunction = [&CallesNames](const CallBase *Call) { 578bcb0991SDimitry Andric auto CalledValue = Call->getCalledOperand()->stripPointerCasts(); 588bcb0991SDimitry Andric if (auto DirectCall = dyn_cast<Function>(CalledValue)) 598bcb0991SDimitry Andric CallesNames.insert(DirectCall->getName()); 608bcb0991SDimitry Andric }; 618bcb0991SDimitry Andric for (auto &I : BB->instructionsWithoutDebug()) 628bcb0991SDimitry Andric if (auto CI = dyn_cast<CallInst>(&I)) 638bcb0991SDimitry Andric getCalledFunction(CI); 648bcb0991SDimitry Andric 658bcb0991SDimitry Andric if (auto II = dyn_cast<InvokeInst>(BB->getTerminator())) 668bcb0991SDimitry Andric getCalledFunction(II); 678bcb0991SDimitry Andric } 688bcb0991SDimitry Andric 698bcb0991SDimitry Andric bool SpeculateQuery::isStraightLine(const Function &F) { 708bcb0991SDimitry Andric return llvm::all_of(F.getBasicBlockList(), [](const BasicBlock &BB) { 718bcb0991SDimitry Andric return BB.getSingleSuccessor() != nullptr; 728bcb0991SDimitry Andric }); 738bcb0991SDimitry Andric } 748bcb0991SDimitry Andric 758bcb0991SDimitry Andric // BlockFreqQuery Implementations 768bcb0991SDimitry Andric 778bcb0991SDimitry Andric size_t BlockFreqQuery::numBBToGet(size_t numBB) { 788bcb0991SDimitry Andric // small CFG 798bcb0991SDimitry Andric if (numBB < 4) 808bcb0991SDimitry Andric return numBB; 818bcb0991SDimitry Andric // mid-size CFG 828bcb0991SDimitry Andric else if (numBB < 20) 838bcb0991SDimitry Andric return (numBB / 2); 848bcb0991SDimitry Andric else 858bcb0991SDimitry Andric return (numBB / 2) + (numBB / 4); 868bcb0991SDimitry Andric } 878bcb0991SDimitry Andric 888bcb0991SDimitry Andric BlockFreqQuery::ResultTy BlockFreqQuery::operator()(Function &F) { 898bcb0991SDimitry Andric DenseMap<StringRef, DenseSet<StringRef>> CallerAndCalles; 908bcb0991SDimitry Andric DenseSet<StringRef> Calles; 918bcb0991SDimitry Andric SmallVector<std::pair<const BasicBlock *, uint64_t>, 8> BBFreqs; 928bcb0991SDimitry Andric 938bcb0991SDimitry Andric PassBuilder PB; 948bcb0991SDimitry Andric FunctionAnalysisManager FAM; 958bcb0991SDimitry Andric PB.registerFunctionAnalyses(FAM); 968bcb0991SDimitry Andric 978bcb0991SDimitry Andric auto IBBs = findBBwithCalls(F); 988bcb0991SDimitry Andric 998bcb0991SDimitry Andric if (IBBs.empty()) 1008bcb0991SDimitry Andric return None; 1018bcb0991SDimitry Andric 1028bcb0991SDimitry Andric auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F); 1038bcb0991SDimitry Andric 1048bcb0991SDimitry Andric for (const auto I : IBBs) 1058bcb0991SDimitry Andric BBFreqs.push_back({I, BFI.getBlockFreq(I).getFrequency()}); 1068bcb0991SDimitry Andric 1078bcb0991SDimitry Andric assert(IBBs.size() == BBFreqs.size() && "BB Count Mismatch"); 1088bcb0991SDimitry Andric 109*e8d8bef9SDimitry Andric llvm::sort(BBFreqs, [](decltype(BBFreqs)::const_reference BBF, 1108bcb0991SDimitry Andric decltype(BBFreqs)::const_reference BBS) { 1118bcb0991SDimitry Andric return BBF.second > BBS.second ? true : false; 1128bcb0991SDimitry Andric }); 1138bcb0991SDimitry Andric 1148bcb0991SDimitry Andric // ignoring number of direct calls in a BB 1158bcb0991SDimitry Andric auto Topk = numBBToGet(BBFreqs.size()); 1168bcb0991SDimitry Andric 1178bcb0991SDimitry Andric for (size_t i = 0; i < Topk; i++) 1188bcb0991SDimitry Andric findCalles(BBFreqs[i].first, Calles); 1198bcb0991SDimitry Andric 1208bcb0991SDimitry Andric assert(!Calles.empty() && "Running Analysis on Function with no calls?"); 1218bcb0991SDimitry Andric 1228bcb0991SDimitry Andric CallerAndCalles.insert({F.getName(), std::move(Calles)}); 1238bcb0991SDimitry Andric 1248bcb0991SDimitry Andric return CallerAndCalles; 1258bcb0991SDimitry Andric } 1268bcb0991SDimitry Andric 1278bcb0991SDimitry Andric // SequenceBBQuery Implementation 1288bcb0991SDimitry Andric std::size_t SequenceBBQuery::getHottestBlocks(std::size_t TotalBlocks) { 1298bcb0991SDimitry Andric if (TotalBlocks == 1) 1308bcb0991SDimitry Andric return TotalBlocks; 1318bcb0991SDimitry Andric return TotalBlocks / 2; 1328bcb0991SDimitry Andric } 1338bcb0991SDimitry Andric 1348bcb0991SDimitry Andric // FIXME : find good implementation. 1358bcb0991SDimitry Andric SequenceBBQuery::BlockListTy 1368bcb0991SDimitry Andric SequenceBBQuery::rearrangeBB(const Function &F, const BlockListTy &BBList) { 1378bcb0991SDimitry Andric BlockListTy RearrangedBBSet; 1388bcb0991SDimitry Andric 1398bcb0991SDimitry Andric for (auto &Block : F.getBasicBlockList()) 1408bcb0991SDimitry Andric if (llvm::is_contained(BBList, &Block)) 1418bcb0991SDimitry Andric RearrangedBBSet.push_back(&Block); 1428bcb0991SDimitry Andric 1438bcb0991SDimitry Andric assert(RearrangedBBSet.size() == BBList.size() && 1448bcb0991SDimitry Andric "BasicBlock missing while rearranging?"); 1458bcb0991SDimitry Andric return RearrangedBBSet; 1468bcb0991SDimitry Andric } 1478bcb0991SDimitry Andric 1488bcb0991SDimitry Andric void SequenceBBQuery::traverseToEntryBlock(const BasicBlock *AtBB, 1498bcb0991SDimitry Andric const BlockListTy &CallerBlocks, 1508bcb0991SDimitry Andric const BackEdgesInfoTy &BackEdgesInfo, 1518bcb0991SDimitry Andric const BranchProbabilityInfo *BPI, 1528bcb0991SDimitry Andric VisitedBlocksInfoTy &VisitedBlocks) { 1538bcb0991SDimitry Andric auto Itr = VisitedBlocks.find(AtBB); 1548bcb0991SDimitry Andric if (Itr != VisitedBlocks.end()) { // already visited. 1558bcb0991SDimitry Andric if (!Itr->second.Upward) 1568bcb0991SDimitry Andric return; 1578bcb0991SDimitry Andric Itr->second.Upward = false; 1588bcb0991SDimitry Andric } else { 1598bcb0991SDimitry Andric // Create hint for newly discoverd blocks. 1608bcb0991SDimitry Andric WalkDirection BlockHint; 1618bcb0991SDimitry Andric BlockHint.Upward = false; 1628bcb0991SDimitry Andric // FIXME: Expensive Check 1638bcb0991SDimitry Andric if (llvm::is_contained(CallerBlocks, AtBB)) 1648bcb0991SDimitry Andric BlockHint.CallerBlock = true; 1658bcb0991SDimitry Andric VisitedBlocks.insert(std::make_pair(AtBB, BlockHint)); 1668bcb0991SDimitry Andric } 1678bcb0991SDimitry Andric 1688bcb0991SDimitry Andric const_pred_iterator PIt = pred_begin(AtBB), EIt = pred_end(AtBB); 1698bcb0991SDimitry Andric // Move this check to top, when we have code setup to launch speculative 1708bcb0991SDimitry Andric // compiles for function in entry BB, this triggers the speculative compiles 1718bcb0991SDimitry Andric // before running the program. 1728bcb0991SDimitry Andric if (PIt == EIt) // No Preds. 1738bcb0991SDimitry Andric return; 1748bcb0991SDimitry Andric 1758bcb0991SDimitry Andric DenseSet<const BasicBlock *> PredSkipNodes; 1768bcb0991SDimitry Andric 1778bcb0991SDimitry Andric // Since we are checking for predecessor's backedges, this Block 1788bcb0991SDimitry Andric // occurs in second position. 1798bcb0991SDimitry Andric for (auto &I : BackEdgesInfo) 1808bcb0991SDimitry Andric if (I.second == AtBB) 1818bcb0991SDimitry Andric PredSkipNodes.insert(I.first); 1828bcb0991SDimitry Andric 1838bcb0991SDimitry Andric // Skip predecessors which source of back-edges. 1848bcb0991SDimitry Andric for (; PIt != EIt; ++PIt) 1858bcb0991SDimitry Andric // checking EdgeHotness is cheaper 1868bcb0991SDimitry Andric if (BPI->isEdgeHot(*PIt, AtBB) && !PredSkipNodes.count(*PIt)) 1878bcb0991SDimitry Andric traverseToEntryBlock(*PIt, CallerBlocks, BackEdgesInfo, BPI, 1888bcb0991SDimitry Andric VisitedBlocks); 1898bcb0991SDimitry Andric } 1908bcb0991SDimitry Andric 1918bcb0991SDimitry Andric void SequenceBBQuery::traverseToExitBlock(const BasicBlock *AtBB, 1928bcb0991SDimitry Andric const BlockListTy &CallerBlocks, 1938bcb0991SDimitry Andric const BackEdgesInfoTy &BackEdgesInfo, 1948bcb0991SDimitry Andric const BranchProbabilityInfo *BPI, 1958bcb0991SDimitry Andric VisitedBlocksInfoTy &VisitedBlocks) { 1968bcb0991SDimitry Andric auto Itr = VisitedBlocks.find(AtBB); 1978bcb0991SDimitry Andric if (Itr != VisitedBlocks.end()) { // already visited. 1988bcb0991SDimitry Andric if (!Itr->second.Downward) 1998bcb0991SDimitry Andric return; 2008bcb0991SDimitry Andric Itr->second.Downward = false; 2018bcb0991SDimitry Andric } else { 2028bcb0991SDimitry Andric // Create hint for newly discoverd blocks. 2038bcb0991SDimitry Andric WalkDirection BlockHint; 2048bcb0991SDimitry Andric BlockHint.Downward = false; 2058bcb0991SDimitry Andric // FIXME: Expensive Check 2068bcb0991SDimitry Andric if (llvm::is_contained(CallerBlocks, AtBB)) 2078bcb0991SDimitry Andric BlockHint.CallerBlock = true; 2088bcb0991SDimitry Andric VisitedBlocks.insert(std::make_pair(AtBB, BlockHint)); 2098bcb0991SDimitry Andric } 2108bcb0991SDimitry Andric 2115ffd83dbSDimitry Andric const_succ_iterator PIt = succ_begin(AtBB), EIt = succ_end(AtBB); 2128bcb0991SDimitry Andric if (PIt == EIt) // No succs. 2138bcb0991SDimitry Andric return; 2148bcb0991SDimitry Andric 2158bcb0991SDimitry Andric // If there are hot edges, then compute SuccSkipNodes. 2168bcb0991SDimitry Andric DenseSet<const BasicBlock *> SuccSkipNodes; 2178bcb0991SDimitry Andric 2188bcb0991SDimitry Andric // Since we are checking for successor's backedges, this Block 2198bcb0991SDimitry Andric // occurs in first position. 2208bcb0991SDimitry Andric for (auto &I : BackEdgesInfo) 2218bcb0991SDimitry Andric if (I.first == AtBB) 2228bcb0991SDimitry Andric SuccSkipNodes.insert(I.second); 2238bcb0991SDimitry Andric 2248bcb0991SDimitry Andric for (; PIt != EIt; ++PIt) 2258bcb0991SDimitry Andric if (BPI->isEdgeHot(AtBB, *PIt) && !SuccSkipNodes.count(*PIt)) 2268bcb0991SDimitry Andric traverseToExitBlock(*PIt, CallerBlocks, BackEdgesInfo, BPI, 2278bcb0991SDimitry Andric VisitedBlocks); 2288bcb0991SDimitry Andric } 2298bcb0991SDimitry Andric 2308bcb0991SDimitry Andric // Get Block frequencies for blocks and take most frquently executed block, 2318bcb0991SDimitry Andric // walk towards the entry block from those blocks and discover the basic blocks 2328bcb0991SDimitry Andric // with call. 2338bcb0991SDimitry Andric SequenceBBQuery::BlockListTy 2348bcb0991SDimitry Andric SequenceBBQuery::queryCFG(Function &F, const BlockListTy &CallerBlocks) { 2358bcb0991SDimitry Andric 2368bcb0991SDimitry Andric BlockFreqInfoTy BBFreqs; 2378bcb0991SDimitry Andric VisitedBlocksInfoTy VisitedBlocks; 2388bcb0991SDimitry Andric BackEdgesInfoTy BackEdgesInfo; 2398bcb0991SDimitry Andric 2408bcb0991SDimitry Andric PassBuilder PB; 2418bcb0991SDimitry Andric FunctionAnalysisManager FAM; 2428bcb0991SDimitry Andric PB.registerFunctionAnalyses(FAM); 2438bcb0991SDimitry Andric 2448bcb0991SDimitry Andric auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F); 2458bcb0991SDimitry Andric 2468bcb0991SDimitry Andric llvm::FindFunctionBackedges(F, BackEdgesInfo); 2478bcb0991SDimitry Andric 2488bcb0991SDimitry Andric for (const auto I : CallerBlocks) 2498bcb0991SDimitry Andric BBFreqs.push_back({I, BFI.getBlockFreq(I).getFrequency()}); 2508bcb0991SDimitry Andric 2518bcb0991SDimitry Andric llvm::sort(BBFreqs, [](decltype(BBFreqs)::const_reference Bbf, 2528bcb0991SDimitry Andric decltype(BBFreqs)::const_reference Bbs) { 2538bcb0991SDimitry Andric return Bbf.second > Bbs.second; 2548bcb0991SDimitry Andric }); 2558bcb0991SDimitry Andric 2568bcb0991SDimitry Andric ArrayRef<std::pair<const BasicBlock *, uint64_t>> HotBlocksRef(BBFreqs); 2578bcb0991SDimitry Andric HotBlocksRef = 2588bcb0991SDimitry Andric HotBlocksRef.drop_back(BBFreqs.size() - getHottestBlocks(BBFreqs.size())); 2598bcb0991SDimitry Andric 2608bcb0991SDimitry Andric BranchProbabilityInfo *BPI = 2618bcb0991SDimitry Andric FAM.getCachedResult<BranchProbabilityAnalysis>(F); 2628bcb0991SDimitry Andric 2638bcb0991SDimitry Andric // visit NHotBlocks, 2648bcb0991SDimitry Andric // traverse upwards to entry 2658bcb0991SDimitry Andric // traverse downwards to end. 2668bcb0991SDimitry Andric 2678bcb0991SDimitry Andric for (auto I : HotBlocksRef) { 2688bcb0991SDimitry Andric traverseToEntryBlock(I.first, CallerBlocks, BackEdgesInfo, BPI, 2698bcb0991SDimitry Andric VisitedBlocks); 2708bcb0991SDimitry Andric traverseToExitBlock(I.first, CallerBlocks, BackEdgesInfo, BPI, 2718bcb0991SDimitry Andric VisitedBlocks); 2728bcb0991SDimitry Andric } 2738bcb0991SDimitry Andric 2748bcb0991SDimitry Andric BlockListTy MinCallerBlocks; 2758bcb0991SDimitry Andric for (auto &I : VisitedBlocks) 2768bcb0991SDimitry Andric if (I.second.CallerBlock) 2778bcb0991SDimitry Andric MinCallerBlocks.push_back(std::move(I.first)); 2788bcb0991SDimitry Andric 2798bcb0991SDimitry Andric return rearrangeBB(F, MinCallerBlocks); 2808bcb0991SDimitry Andric } 2818bcb0991SDimitry Andric 2828bcb0991SDimitry Andric SpeculateQuery::ResultTy SequenceBBQuery::operator()(Function &F) { 2838bcb0991SDimitry Andric // reduce the number of lists! 2848bcb0991SDimitry Andric DenseMap<StringRef, DenseSet<StringRef>> CallerAndCalles; 2858bcb0991SDimitry Andric DenseSet<StringRef> Calles; 2868bcb0991SDimitry Andric BlockListTy SequencedBlocks; 2878bcb0991SDimitry Andric BlockListTy CallerBlocks; 2888bcb0991SDimitry Andric 2898bcb0991SDimitry Andric CallerBlocks = findBBwithCalls(F); 2908bcb0991SDimitry Andric if (CallerBlocks.empty()) 2918bcb0991SDimitry Andric return None; 2928bcb0991SDimitry Andric 2938bcb0991SDimitry Andric if (isStraightLine(F)) 2948bcb0991SDimitry Andric SequencedBlocks = rearrangeBB(F, CallerBlocks); 2958bcb0991SDimitry Andric else 2968bcb0991SDimitry Andric SequencedBlocks = queryCFG(F, CallerBlocks); 2978bcb0991SDimitry Andric 2988bcb0991SDimitry Andric for (auto BB : SequencedBlocks) 2998bcb0991SDimitry Andric findCalles(BB, Calles); 3008bcb0991SDimitry Andric 3018bcb0991SDimitry Andric CallerAndCalles.insert({F.getName(), std::move(Calles)}); 3028bcb0991SDimitry Andric return CallerAndCalles; 3038bcb0991SDimitry Andric } 3048bcb0991SDimitry Andric 3058bcb0991SDimitry Andric } // namespace orc 3068bcb0991SDimitry Andric } // namespace llvm 307