1 //===-- SpeculateAnalyses.cpp --*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/DenseMap.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/SmallPtrSet.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/Analysis/BlockFrequencyInfo.h"
16 #include "llvm/Analysis/BranchProbabilityInfo.h"
17 #include "llvm/Analysis/CFG.h"
18 #include "llvm/IR/PassManager.h"
19 #include "llvm/Passes/PassBuilder.h"
20 #include "llvm/Support/ErrorHandling.h"
26 SmallVector
<const BasicBlock
*, 8> findBBwithCalls(const Function
&F
,
27 bool IndirectCall
= false) {
28 SmallVector
<const BasicBlock
*, 8> BBs
;
30 auto findCallInst
= [&IndirectCall
](const Instruction
&I
) {
31 if (auto Call
= dyn_cast
<CallBase
>(&I
))
32 return Call
->isIndirectCall() ? IndirectCall
: true;
37 if (findCallInst(*BB
.getTerminator()) ||
38 llvm::any_of(BB
.instructionsWithoutDebug(), findCallInst
))
39 BBs
.emplace_back(&BB
);
45 // Implementations of Queries shouldn't need to lock the resources
46 // such as LLVMContext, each argument (function) has a non-shared LLVMContext
47 // Plus, if Queries contain states necessary locking scheme should be provided.
51 // Collect direct calls only
52 void SpeculateQuery::findCalles(const BasicBlock
*BB
,
53 DenseSet
<StringRef
> &CallesNames
) {
54 assert(BB
!= nullptr && "Traversing Null BB to find calls?");
56 auto getCalledFunction
= [&CallesNames
](const CallBase
*Call
) {
57 auto CalledValue
= Call
->getCalledOperand()->stripPointerCasts();
58 if (auto DirectCall
= dyn_cast
<Function
>(CalledValue
))
59 CallesNames
.insert(DirectCall
->getName());
61 for (auto &I
: BB
->instructionsWithoutDebug())
62 if (auto CI
= dyn_cast
<CallInst
>(&I
))
63 getCalledFunction(CI
);
65 if (auto II
= dyn_cast
<InvokeInst
>(BB
->getTerminator()))
66 getCalledFunction(II
);
69 bool SpeculateQuery::isStraightLine(const Function
&F
) {
70 return llvm::all_of(F
, [](const BasicBlock
&BB
) {
71 return BB
.getSingleSuccessor() != nullptr;
75 // BlockFreqQuery Implementations
77 size_t BlockFreqQuery::numBBToGet(size_t numBB
) {
85 return (numBB
/ 2) + (numBB
/ 4);
88 BlockFreqQuery::ResultTy
BlockFreqQuery::operator()(Function
&F
) {
89 DenseMap
<StringRef
, DenseSet
<StringRef
>> CallerAndCalles
;
90 DenseSet
<StringRef
> Calles
;
91 SmallVector
<std::pair
<const BasicBlock
*, uint64_t>, 8> BBFreqs
;
94 FunctionAnalysisManager FAM
;
95 PB
.registerFunctionAnalyses(FAM
);
97 auto IBBs
= findBBwithCalls(F
);
102 auto &BFI
= FAM
.getResult
<BlockFrequencyAnalysis
>(F
);
104 for (const auto I
: IBBs
)
105 BBFreqs
.push_back({I
, BFI
.getBlockFreq(I
).getFrequency()});
107 assert(IBBs
.size() == BBFreqs
.size() && "BB Count Mismatch");
109 llvm::sort(BBFreqs
, [](decltype(BBFreqs
)::const_reference BBF
,
110 decltype(BBFreqs
)::const_reference BBS
) {
111 return BBF
.second
> BBS
.second
? true : false;
114 // ignoring number of direct calls in a BB
115 auto Topk
= numBBToGet(BBFreqs
.size());
117 for (size_t i
= 0; i
< Topk
; i
++)
118 findCalles(BBFreqs
[i
].first
, Calles
);
120 assert(!Calles
.empty() && "Running Analysis on Function with no calls?");
122 CallerAndCalles
.insert({F
.getName(), std::move(Calles
)});
124 return CallerAndCalles
;
127 // SequenceBBQuery Implementation
128 std::size_t SequenceBBQuery::getHottestBlocks(std::size_t TotalBlocks
) {
129 if (TotalBlocks
== 1)
131 return TotalBlocks
/ 2;
134 // FIXME : find good implementation.
135 SequenceBBQuery::BlockListTy
136 SequenceBBQuery::rearrangeBB(const Function
&F
, const BlockListTy
&BBList
) {
137 BlockListTy RearrangedBBSet
;
139 for (auto &Block
: F
)
140 if (llvm::is_contained(BBList
, &Block
))
141 RearrangedBBSet
.push_back(&Block
);
143 assert(RearrangedBBSet
.size() == BBList
.size() &&
144 "BasicBlock missing while rearranging?");
145 return RearrangedBBSet
;
148 void SequenceBBQuery::traverseToEntryBlock(const BasicBlock
*AtBB
,
149 const BlockListTy
&CallerBlocks
,
150 const BackEdgesInfoTy
&BackEdgesInfo
,
151 const BranchProbabilityInfo
*BPI
,
152 VisitedBlocksInfoTy
&VisitedBlocks
) {
153 auto Itr
= VisitedBlocks
.find(AtBB
);
154 if (Itr
!= VisitedBlocks
.end()) { // already visited.
155 if (!Itr
->second
.Upward
)
157 Itr
->second
.Upward
= false;
159 // Create hint for newly discoverd blocks.
160 WalkDirection BlockHint
;
161 BlockHint
.Upward
= false;
162 // FIXME: Expensive Check
163 if (llvm::is_contained(CallerBlocks
, AtBB
))
164 BlockHint
.CallerBlock
= true;
165 VisitedBlocks
.insert(std::make_pair(AtBB
, BlockHint
));
168 const_pred_iterator PIt
= pred_begin(AtBB
), EIt
= pred_end(AtBB
);
169 // Move this check to top, when we have code setup to launch speculative
170 // compiles for function in entry BB, this triggers the speculative compiles
171 // before running the program.
172 if (PIt
== EIt
) // No Preds.
175 DenseSet
<const BasicBlock
*> PredSkipNodes
;
177 // Since we are checking for predecessor's backedges, this Block
178 // occurs in second position.
179 for (auto &I
: BackEdgesInfo
)
180 if (I
.second
== AtBB
)
181 PredSkipNodes
.insert(I
.first
);
183 // Skip predecessors which source of back-edges.
184 for (; PIt
!= EIt
; ++PIt
)
185 // checking EdgeHotness is cheaper
186 if (BPI
->isEdgeHot(*PIt
, AtBB
) && !PredSkipNodes
.count(*PIt
))
187 traverseToEntryBlock(*PIt
, CallerBlocks
, BackEdgesInfo
, BPI
,
191 void SequenceBBQuery::traverseToExitBlock(const BasicBlock
*AtBB
,
192 const BlockListTy
&CallerBlocks
,
193 const BackEdgesInfoTy
&BackEdgesInfo
,
194 const BranchProbabilityInfo
*BPI
,
195 VisitedBlocksInfoTy
&VisitedBlocks
) {
196 auto Itr
= VisitedBlocks
.find(AtBB
);
197 if (Itr
!= VisitedBlocks
.end()) { // already visited.
198 if (!Itr
->second
.Downward
)
200 Itr
->second
.Downward
= false;
202 // Create hint for newly discoverd blocks.
203 WalkDirection BlockHint
;
204 BlockHint
.Downward
= false;
205 // FIXME: Expensive Check
206 if (llvm::is_contained(CallerBlocks
, AtBB
))
207 BlockHint
.CallerBlock
= true;
208 VisitedBlocks
.insert(std::make_pair(AtBB
, BlockHint
));
211 const_succ_iterator PIt
= succ_begin(AtBB
), EIt
= succ_end(AtBB
);
212 if (PIt
== EIt
) // No succs.
215 // If there are hot edges, then compute SuccSkipNodes.
216 DenseSet
<const BasicBlock
*> SuccSkipNodes
;
218 // Since we are checking for successor's backedges, this Block
219 // occurs in first position.
220 for (auto &I
: BackEdgesInfo
)
222 SuccSkipNodes
.insert(I
.second
);
224 for (; PIt
!= EIt
; ++PIt
)
225 if (BPI
->isEdgeHot(AtBB
, *PIt
) && !SuccSkipNodes
.count(*PIt
))
226 traverseToExitBlock(*PIt
, CallerBlocks
, BackEdgesInfo
, BPI
,
230 // Get Block frequencies for blocks and take most frequently executed block,
231 // walk towards the entry block from those blocks and discover the basic blocks
233 SequenceBBQuery::BlockListTy
234 SequenceBBQuery::queryCFG(Function
&F
, const BlockListTy
&CallerBlocks
) {
236 BlockFreqInfoTy BBFreqs
;
237 VisitedBlocksInfoTy VisitedBlocks
;
238 BackEdgesInfoTy BackEdgesInfo
;
241 FunctionAnalysisManager FAM
;
242 PB
.registerFunctionAnalyses(FAM
);
244 auto &BFI
= FAM
.getResult
<BlockFrequencyAnalysis
>(F
);
246 llvm::FindFunctionBackedges(F
, BackEdgesInfo
);
248 for (const auto I
: CallerBlocks
)
249 BBFreqs
.push_back({I
, BFI
.getBlockFreq(I
).getFrequency()});
251 llvm::sort(BBFreqs
, [](decltype(BBFreqs
)::const_reference Bbf
,
252 decltype(BBFreqs
)::const_reference Bbs
) {
253 return Bbf
.second
> Bbs
.second
;
256 ArrayRef
<std::pair
<const BasicBlock
*, uint64_t>> HotBlocksRef(BBFreqs
);
258 HotBlocksRef
.drop_back(BBFreqs
.size() - getHottestBlocks(BBFreqs
.size()));
260 BranchProbabilityInfo
*BPI
=
261 FAM
.getCachedResult
<BranchProbabilityAnalysis
>(F
);
264 // traverse upwards to entry
265 // traverse downwards to end.
267 for (auto I
: HotBlocksRef
) {
268 traverseToEntryBlock(I
.first
, CallerBlocks
, BackEdgesInfo
, BPI
,
270 traverseToExitBlock(I
.first
, CallerBlocks
, BackEdgesInfo
, BPI
,
274 BlockListTy MinCallerBlocks
;
275 for (auto &I
: VisitedBlocks
)
276 if (I
.second
.CallerBlock
)
277 MinCallerBlocks
.push_back(std::move(I
.first
));
279 return rearrangeBB(F
, MinCallerBlocks
);
282 SpeculateQuery::ResultTy
SequenceBBQuery::operator()(Function
&F
) {
283 // reduce the number of lists!
284 DenseMap
<StringRef
, DenseSet
<StringRef
>> CallerAndCalles
;
285 DenseSet
<StringRef
> Calles
;
286 BlockListTy SequencedBlocks
;
287 BlockListTy CallerBlocks
;
289 CallerBlocks
= findBBwithCalls(F
);
290 if (CallerBlocks
.empty())
293 if (isStraightLine(F
))
294 SequencedBlocks
= rearrangeBB(F
, CallerBlocks
);
296 SequencedBlocks
= queryCFG(F
, CallerBlocks
);
298 for (const auto *BB
: SequencedBlocks
)
299 findCalles(BB
, Calles
);
301 CallerAndCalles
.insert({F
.getName(), std::move(Calles
)});
302 return CallerAndCalles
;