xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SpeculateAnalyses.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
1*8bcb0991SDimitry Andric //===-- SpeculateAnalyses.cpp  --*- C++ -*-===//
2*8bcb0991SDimitry Andric //
3*8bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*8bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8bcb0991SDimitry Andric //
7*8bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
8*8bcb0991SDimitry Andric 
9*8bcb0991SDimitry Andric #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h"
10*8bcb0991SDimitry Andric #include "llvm/ADT/ArrayRef.h"
11*8bcb0991SDimitry Andric #include "llvm/ADT/DenseMap.h"
12*8bcb0991SDimitry Andric #include "llvm/ADT/STLExtras.h"
13*8bcb0991SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
14*8bcb0991SDimitry Andric #include "llvm/ADT/SmallVector.h"
15*8bcb0991SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
16*8bcb0991SDimitry Andric #include "llvm/Analysis/BranchProbabilityInfo.h"
17*8bcb0991SDimitry Andric #include "llvm/Analysis/CFG.h"
18*8bcb0991SDimitry Andric #include "llvm/IR/PassManager.h"
19*8bcb0991SDimitry Andric #include "llvm/Passes/PassBuilder.h"
20*8bcb0991SDimitry Andric #include "llvm/Support/ErrorHandling.h"
21*8bcb0991SDimitry Andric 
22*8bcb0991SDimitry Andric #include <algorithm>
23*8bcb0991SDimitry Andric 
24*8bcb0991SDimitry Andric namespace {
25*8bcb0991SDimitry Andric using namespace llvm;
26*8bcb0991SDimitry Andric SmallVector<const BasicBlock *, 8> findBBwithCalls(const Function &F,
27*8bcb0991SDimitry Andric                                                    bool IndirectCall = false) {
28*8bcb0991SDimitry Andric   SmallVector<const BasicBlock *, 8> BBs;
29*8bcb0991SDimitry Andric 
30*8bcb0991SDimitry Andric   auto findCallInst = [&IndirectCall](const Instruction &I) {
31*8bcb0991SDimitry Andric     if (auto Call = dyn_cast<CallBase>(&I))
32*8bcb0991SDimitry Andric       return Call->isIndirectCall() ? IndirectCall : true;
33*8bcb0991SDimitry Andric     else
34*8bcb0991SDimitry Andric       return false;
35*8bcb0991SDimitry Andric   };
36*8bcb0991SDimitry Andric   for (auto &BB : F)
37*8bcb0991SDimitry Andric     if (findCallInst(*BB.getTerminator()) ||
38*8bcb0991SDimitry Andric         llvm::any_of(BB.instructionsWithoutDebug(), findCallInst))
39*8bcb0991SDimitry Andric       BBs.emplace_back(&BB);
40*8bcb0991SDimitry Andric 
41*8bcb0991SDimitry Andric   return BBs;
42*8bcb0991SDimitry Andric }
43*8bcb0991SDimitry Andric } // namespace
44*8bcb0991SDimitry Andric 
45*8bcb0991SDimitry Andric // Implementations of Queries shouldn't need to lock the resources
46*8bcb0991SDimitry Andric // such as LLVMContext, each argument (function) has a non-shared LLVMContext
47*8bcb0991SDimitry Andric // Plus, if Queries contain states necessary locking scheme should be provided.
48*8bcb0991SDimitry Andric namespace llvm {
49*8bcb0991SDimitry Andric namespace orc {
50*8bcb0991SDimitry Andric 
51*8bcb0991SDimitry Andric // Collect direct calls only
52*8bcb0991SDimitry Andric void SpeculateQuery::findCalles(const BasicBlock *BB,
53*8bcb0991SDimitry Andric                                 DenseSet<StringRef> &CallesNames) {
54*8bcb0991SDimitry Andric   assert(BB != nullptr && "Traversing Null BB to find calls?");
55*8bcb0991SDimitry Andric 
56*8bcb0991SDimitry Andric   auto getCalledFunction = [&CallesNames](const CallBase *Call) {
57*8bcb0991SDimitry Andric     auto CalledValue = Call->getCalledOperand()->stripPointerCasts();
58*8bcb0991SDimitry Andric     if (auto DirectCall = dyn_cast<Function>(CalledValue))
59*8bcb0991SDimitry Andric       CallesNames.insert(DirectCall->getName());
60*8bcb0991SDimitry Andric   };
61*8bcb0991SDimitry Andric   for (auto &I : BB->instructionsWithoutDebug())
62*8bcb0991SDimitry Andric     if (auto CI = dyn_cast<CallInst>(&I))
63*8bcb0991SDimitry Andric       getCalledFunction(CI);
64*8bcb0991SDimitry Andric 
65*8bcb0991SDimitry Andric   if (auto II = dyn_cast<InvokeInst>(BB->getTerminator()))
66*8bcb0991SDimitry Andric     getCalledFunction(II);
67*8bcb0991SDimitry Andric }
68*8bcb0991SDimitry Andric 
69*8bcb0991SDimitry Andric bool SpeculateQuery::isStraightLine(const Function &F) {
70*8bcb0991SDimitry Andric   return llvm::all_of(F.getBasicBlockList(), [](const BasicBlock &BB) {
71*8bcb0991SDimitry Andric     return BB.getSingleSuccessor() != nullptr;
72*8bcb0991SDimitry Andric   });
73*8bcb0991SDimitry Andric }
74*8bcb0991SDimitry Andric 
75*8bcb0991SDimitry Andric // BlockFreqQuery Implementations
76*8bcb0991SDimitry Andric 
77*8bcb0991SDimitry Andric size_t BlockFreqQuery::numBBToGet(size_t numBB) {
78*8bcb0991SDimitry Andric   // small CFG
79*8bcb0991SDimitry Andric   if (numBB < 4)
80*8bcb0991SDimitry Andric     return numBB;
81*8bcb0991SDimitry Andric   // mid-size CFG
82*8bcb0991SDimitry Andric   else if (numBB < 20)
83*8bcb0991SDimitry Andric     return (numBB / 2);
84*8bcb0991SDimitry Andric   else
85*8bcb0991SDimitry Andric     return (numBB / 2) + (numBB / 4);
86*8bcb0991SDimitry Andric }
87*8bcb0991SDimitry Andric 
88*8bcb0991SDimitry Andric BlockFreqQuery::ResultTy BlockFreqQuery::operator()(Function &F) {
89*8bcb0991SDimitry Andric   DenseMap<StringRef, DenseSet<StringRef>> CallerAndCalles;
90*8bcb0991SDimitry Andric   DenseSet<StringRef> Calles;
91*8bcb0991SDimitry Andric   SmallVector<std::pair<const BasicBlock *, uint64_t>, 8> BBFreqs;
92*8bcb0991SDimitry Andric 
93*8bcb0991SDimitry Andric   PassBuilder PB;
94*8bcb0991SDimitry Andric   FunctionAnalysisManager FAM;
95*8bcb0991SDimitry Andric   PB.registerFunctionAnalyses(FAM);
96*8bcb0991SDimitry Andric 
97*8bcb0991SDimitry Andric   auto IBBs = findBBwithCalls(F);
98*8bcb0991SDimitry Andric 
99*8bcb0991SDimitry Andric   if (IBBs.empty())
100*8bcb0991SDimitry Andric     return None;
101*8bcb0991SDimitry Andric 
102*8bcb0991SDimitry Andric   auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
103*8bcb0991SDimitry Andric 
104*8bcb0991SDimitry Andric   for (const auto I : IBBs)
105*8bcb0991SDimitry Andric     BBFreqs.push_back({I, BFI.getBlockFreq(I).getFrequency()});
106*8bcb0991SDimitry Andric 
107*8bcb0991SDimitry Andric   assert(IBBs.size() == BBFreqs.size() && "BB Count Mismatch");
108*8bcb0991SDimitry Andric 
109*8bcb0991SDimitry Andric   llvm::sort(BBFreqs.begin(), BBFreqs.end(),
110*8bcb0991SDimitry Andric              [](decltype(BBFreqs)::const_reference BBF,
111*8bcb0991SDimitry Andric                 decltype(BBFreqs)::const_reference BBS) {
112*8bcb0991SDimitry Andric                return BBF.second > BBS.second ? true : false;
113*8bcb0991SDimitry Andric              });
114*8bcb0991SDimitry Andric 
115*8bcb0991SDimitry Andric   // ignoring number of direct calls in a BB
116*8bcb0991SDimitry Andric   auto Topk = numBBToGet(BBFreqs.size());
117*8bcb0991SDimitry Andric 
118*8bcb0991SDimitry Andric   for (size_t i = 0; i < Topk; i++)
119*8bcb0991SDimitry Andric     findCalles(BBFreqs[i].first, Calles);
120*8bcb0991SDimitry Andric 
121*8bcb0991SDimitry Andric   assert(!Calles.empty() && "Running Analysis on Function with no calls?");
122*8bcb0991SDimitry Andric 
123*8bcb0991SDimitry Andric   CallerAndCalles.insert({F.getName(), std::move(Calles)});
124*8bcb0991SDimitry Andric 
125*8bcb0991SDimitry Andric   return CallerAndCalles;
126*8bcb0991SDimitry Andric }
127*8bcb0991SDimitry Andric 
128*8bcb0991SDimitry Andric // SequenceBBQuery Implementation
129*8bcb0991SDimitry Andric std::size_t SequenceBBQuery::getHottestBlocks(std::size_t TotalBlocks) {
130*8bcb0991SDimitry Andric   if (TotalBlocks == 1)
131*8bcb0991SDimitry Andric     return TotalBlocks;
132*8bcb0991SDimitry Andric   return TotalBlocks / 2;
133*8bcb0991SDimitry Andric }
134*8bcb0991SDimitry Andric 
135*8bcb0991SDimitry Andric // FIXME : find good implementation.
136*8bcb0991SDimitry Andric SequenceBBQuery::BlockListTy
137*8bcb0991SDimitry Andric SequenceBBQuery::rearrangeBB(const Function &F, const BlockListTy &BBList) {
138*8bcb0991SDimitry Andric   BlockListTy RearrangedBBSet;
139*8bcb0991SDimitry Andric 
140*8bcb0991SDimitry Andric   for (auto &Block : F.getBasicBlockList())
141*8bcb0991SDimitry Andric     if (llvm::is_contained(BBList, &Block))
142*8bcb0991SDimitry Andric       RearrangedBBSet.push_back(&Block);
143*8bcb0991SDimitry Andric 
144*8bcb0991SDimitry Andric   assert(RearrangedBBSet.size() == BBList.size() &&
145*8bcb0991SDimitry Andric          "BasicBlock missing while rearranging?");
146*8bcb0991SDimitry Andric   return RearrangedBBSet;
147*8bcb0991SDimitry Andric }
148*8bcb0991SDimitry Andric 
149*8bcb0991SDimitry Andric void SequenceBBQuery::traverseToEntryBlock(const BasicBlock *AtBB,
150*8bcb0991SDimitry Andric                                            const BlockListTy &CallerBlocks,
151*8bcb0991SDimitry Andric                                            const BackEdgesInfoTy &BackEdgesInfo,
152*8bcb0991SDimitry Andric                                            const BranchProbabilityInfo *BPI,
153*8bcb0991SDimitry Andric                                            VisitedBlocksInfoTy &VisitedBlocks) {
154*8bcb0991SDimitry Andric   auto Itr = VisitedBlocks.find(AtBB);
155*8bcb0991SDimitry Andric   if (Itr != VisitedBlocks.end()) { // already visited.
156*8bcb0991SDimitry Andric     if (!Itr->second.Upward)
157*8bcb0991SDimitry Andric       return;
158*8bcb0991SDimitry Andric     Itr->second.Upward = false;
159*8bcb0991SDimitry Andric   } else {
160*8bcb0991SDimitry Andric     // Create hint for newly discoverd blocks.
161*8bcb0991SDimitry Andric     WalkDirection BlockHint;
162*8bcb0991SDimitry Andric     BlockHint.Upward = false;
163*8bcb0991SDimitry Andric     // FIXME: Expensive Check
164*8bcb0991SDimitry Andric     if (llvm::is_contained(CallerBlocks, AtBB))
165*8bcb0991SDimitry Andric       BlockHint.CallerBlock = true;
166*8bcb0991SDimitry Andric     VisitedBlocks.insert(std::make_pair(AtBB, BlockHint));
167*8bcb0991SDimitry Andric   }
168*8bcb0991SDimitry Andric 
169*8bcb0991SDimitry Andric   const_pred_iterator PIt = pred_begin(AtBB), EIt = pred_end(AtBB);
170*8bcb0991SDimitry Andric   // Move this check to top, when we have code setup to launch speculative
171*8bcb0991SDimitry Andric   // compiles for function in entry BB, this triggers the speculative compiles
172*8bcb0991SDimitry Andric   // before running the program.
173*8bcb0991SDimitry Andric   if (PIt == EIt) // No Preds.
174*8bcb0991SDimitry Andric     return;
175*8bcb0991SDimitry Andric 
176*8bcb0991SDimitry Andric   DenseSet<const BasicBlock *> PredSkipNodes;
177*8bcb0991SDimitry Andric 
178*8bcb0991SDimitry Andric   // Since we are checking for predecessor's backedges, this Block
179*8bcb0991SDimitry Andric   // occurs in second position.
180*8bcb0991SDimitry Andric   for (auto &I : BackEdgesInfo)
181*8bcb0991SDimitry Andric     if (I.second == AtBB)
182*8bcb0991SDimitry Andric       PredSkipNodes.insert(I.first);
183*8bcb0991SDimitry Andric 
184*8bcb0991SDimitry Andric   // Skip predecessors which source of back-edges.
185*8bcb0991SDimitry Andric   for (; PIt != EIt; ++PIt)
186*8bcb0991SDimitry Andric     // checking EdgeHotness is cheaper
187*8bcb0991SDimitry Andric     if (BPI->isEdgeHot(*PIt, AtBB) && !PredSkipNodes.count(*PIt))
188*8bcb0991SDimitry Andric       traverseToEntryBlock(*PIt, CallerBlocks, BackEdgesInfo, BPI,
189*8bcb0991SDimitry Andric                            VisitedBlocks);
190*8bcb0991SDimitry Andric }
191*8bcb0991SDimitry Andric 
192*8bcb0991SDimitry Andric void SequenceBBQuery::traverseToExitBlock(const BasicBlock *AtBB,
193*8bcb0991SDimitry Andric                                           const BlockListTy &CallerBlocks,
194*8bcb0991SDimitry Andric                                           const BackEdgesInfoTy &BackEdgesInfo,
195*8bcb0991SDimitry Andric                                           const BranchProbabilityInfo *BPI,
196*8bcb0991SDimitry Andric                                           VisitedBlocksInfoTy &VisitedBlocks) {
197*8bcb0991SDimitry Andric   auto Itr = VisitedBlocks.find(AtBB);
198*8bcb0991SDimitry Andric   if (Itr != VisitedBlocks.end()) { // already visited.
199*8bcb0991SDimitry Andric     if (!Itr->second.Downward)
200*8bcb0991SDimitry Andric       return;
201*8bcb0991SDimitry Andric     Itr->second.Downward = false;
202*8bcb0991SDimitry Andric   } else {
203*8bcb0991SDimitry Andric     // Create hint for newly discoverd blocks.
204*8bcb0991SDimitry Andric     WalkDirection BlockHint;
205*8bcb0991SDimitry Andric     BlockHint.Downward = false;
206*8bcb0991SDimitry Andric     // FIXME: Expensive Check
207*8bcb0991SDimitry Andric     if (llvm::is_contained(CallerBlocks, AtBB))
208*8bcb0991SDimitry Andric       BlockHint.CallerBlock = true;
209*8bcb0991SDimitry Andric     VisitedBlocks.insert(std::make_pair(AtBB, BlockHint));
210*8bcb0991SDimitry Andric   }
211*8bcb0991SDimitry Andric 
212*8bcb0991SDimitry Andric   succ_const_iterator PIt = succ_begin(AtBB), EIt = succ_end(AtBB);
213*8bcb0991SDimitry Andric   if (PIt == EIt) // No succs.
214*8bcb0991SDimitry Andric     return;
215*8bcb0991SDimitry Andric 
216*8bcb0991SDimitry Andric   // If there are hot edges, then compute SuccSkipNodes.
217*8bcb0991SDimitry Andric   DenseSet<const BasicBlock *> SuccSkipNodes;
218*8bcb0991SDimitry Andric 
219*8bcb0991SDimitry Andric   // Since we are checking for successor's backedges, this Block
220*8bcb0991SDimitry Andric   // occurs in first position.
221*8bcb0991SDimitry Andric   for (auto &I : BackEdgesInfo)
222*8bcb0991SDimitry Andric     if (I.first == AtBB)
223*8bcb0991SDimitry Andric       SuccSkipNodes.insert(I.second);
224*8bcb0991SDimitry Andric 
225*8bcb0991SDimitry Andric   for (; PIt != EIt; ++PIt)
226*8bcb0991SDimitry Andric     if (BPI->isEdgeHot(AtBB, *PIt) && !SuccSkipNodes.count(*PIt))
227*8bcb0991SDimitry Andric       traverseToExitBlock(*PIt, CallerBlocks, BackEdgesInfo, BPI,
228*8bcb0991SDimitry Andric                           VisitedBlocks);
229*8bcb0991SDimitry Andric }
230*8bcb0991SDimitry Andric 
231*8bcb0991SDimitry Andric // Get Block frequencies for blocks and take most frquently executed block,
232*8bcb0991SDimitry Andric // walk towards the entry block from those blocks and discover the basic blocks
233*8bcb0991SDimitry Andric // with call.
234*8bcb0991SDimitry Andric SequenceBBQuery::BlockListTy
235*8bcb0991SDimitry Andric SequenceBBQuery::queryCFG(Function &F, const BlockListTy &CallerBlocks) {
236*8bcb0991SDimitry Andric 
237*8bcb0991SDimitry Andric   BlockFreqInfoTy BBFreqs;
238*8bcb0991SDimitry Andric   VisitedBlocksInfoTy VisitedBlocks;
239*8bcb0991SDimitry Andric   BackEdgesInfoTy BackEdgesInfo;
240*8bcb0991SDimitry Andric 
241*8bcb0991SDimitry Andric   PassBuilder PB;
242*8bcb0991SDimitry Andric   FunctionAnalysisManager FAM;
243*8bcb0991SDimitry Andric   PB.registerFunctionAnalyses(FAM);
244*8bcb0991SDimitry Andric 
245*8bcb0991SDimitry Andric   auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
246*8bcb0991SDimitry Andric 
247*8bcb0991SDimitry Andric   llvm::FindFunctionBackedges(F, BackEdgesInfo);
248*8bcb0991SDimitry Andric 
249*8bcb0991SDimitry Andric   for (const auto I : CallerBlocks)
250*8bcb0991SDimitry Andric     BBFreqs.push_back({I, BFI.getBlockFreq(I).getFrequency()});
251*8bcb0991SDimitry Andric 
252*8bcb0991SDimitry Andric   llvm::sort(BBFreqs, [](decltype(BBFreqs)::const_reference Bbf,
253*8bcb0991SDimitry Andric                          decltype(BBFreqs)::const_reference Bbs) {
254*8bcb0991SDimitry Andric     return Bbf.second > Bbs.second;
255*8bcb0991SDimitry Andric   });
256*8bcb0991SDimitry Andric 
257*8bcb0991SDimitry Andric   ArrayRef<std::pair<const BasicBlock *, uint64_t>> HotBlocksRef(BBFreqs);
258*8bcb0991SDimitry Andric   HotBlocksRef =
259*8bcb0991SDimitry Andric       HotBlocksRef.drop_back(BBFreqs.size() - getHottestBlocks(BBFreqs.size()));
260*8bcb0991SDimitry Andric 
261*8bcb0991SDimitry Andric   BranchProbabilityInfo *BPI =
262*8bcb0991SDimitry Andric       FAM.getCachedResult<BranchProbabilityAnalysis>(F);
263*8bcb0991SDimitry Andric 
264*8bcb0991SDimitry Andric   // visit NHotBlocks,
265*8bcb0991SDimitry Andric   // traverse upwards to entry
266*8bcb0991SDimitry Andric   // traverse downwards to end.
267*8bcb0991SDimitry Andric 
268*8bcb0991SDimitry Andric   for (auto I : HotBlocksRef) {
269*8bcb0991SDimitry Andric     traverseToEntryBlock(I.first, CallerBlocks, BackEdgesInfo, BPI,
270*8bcb0991SDimitry Andric                          VisitedBlocks);
271*8bcb0991SDimitry Andric     traverseToExitBlock(I.first, CallerBlocks, BackEdgesInfo, BPI,
272*8bcb0991SDimitry Andric                         VisitedBlocks);
273*8bcb0991SDimitry Andric   }
274*8bcb0991SDimitry Andric 
275*8bcb0991SDimitry Andric   BlockListTy MinCallerBlocks;
276*8bcb0991SDimitry Andric   for (auto &I : VisitedBlocks)
277*8bcb0991SDimitry Andric     if (I.second.CallerBlock)
278*8bcb0991SDimitry Andric       MinCallerBlocks.push_back(std::move(I.first));
279*8bcb0991SDimitry Andric 
280*8bcb0991SDimitry Andric   return rearrangeBB(F, MinCallerBlocks);
281*8bcb0991SDimitry Andric }
282*8bcb0991SDimitry Andric 
283*8bcb0991SDimitry Andric SpeculateQuery::ResultTy SequenceBBQuery::operator()(Function &F) {
284*8bcb0991SDimitry Andric   // reduce the number of lists!
285*8bcb0991SDimitry Andric   DenseMap<StringRef, DenseSet<StringRef>> CallerAndCalles;
286*8bcb0991SDimitry Andric   DenseSet<StringRef> Calles;
287*8bcb0991SDimitry Andric   BlockListTy SequencedBlocks;
288*8bcb0991SDimitry Andric   BlockListTy CallerBlocks;
289*8bcb0991SDimitry Andric 
290*8bcb0991SDimitry Andric   CallerBlocks = findBBwithCalls(F);
291*8bcb0991SDimitry Andric   if (CallerBlocks.empty())
292*8bcb0991SDimitry Andric     return None;
293*8bcb0991SDimitry Andric 
294*8bcb0991SDimitry Andric   if (isStraightLine(F))
295*8bcb0991SDimitry Andric     SequencedBlocks = rearrangeBB(F, CallerBlocks);
296*8bcb0991SDimitry Andric   else
297*8bcb0991SDimitry Andric     SequencedBlocks = queryCFG(F, CallerBlocks);
298*8bcb0991SDimitry Andric 
299*8bcb0991SDimitry Andric   for (auto BB : SequencedBlocks)
300*8bcb0991SDimitry Andric     findCalles(BB, Calles);
301*8bcb0991SDimitry Andric 
302*8bcb0991SDimitry Andric   CallerAndCalles.insert({F.getName(), std::move(Calles)});
303*8bcb0991SDimitry Andric   return CallerAndCalles;
304*8bcb0991SDimitry Andric }
305*8bcb0991SDimitry Andric 
306*8bcb0991SDimitry Andric } // namespace orc
307*8bcb0991SDimitry Andric } // namespace llvm
308