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
.getBasicBlockList(), [](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
.begin(), BBFreqs
.end(),
110 [](decltype(BBFreqs
)::const_reference BBF
,
111 decltype(BBFreqs
)::const_reference BBS
) {
112 return BBF
.second
> BBS
.second
? true : false;
115 // ignoring number of direct calls in a BB
116 auto Topk
= numBBToGet(BBFreqs
.size());
118 for (size_t i
= 0; i
< Topk
; i
++)
119 findCalles(BBFreqs
[i
].first
, Calles
);
121 assert(!Calles
.empty() && "Running Analysis on Function with no calls?");
123 CallerAndCalles
.insert({F
.getName(), std::move(Calles
)});
125 return CallerAndCalles
;
128 // SequenceBBQuery Implementation
129 std::size_t SequenceBBQuery::getHottestBlocks(std::size_t TotalBlocks
) {
130 if (TotalBlocks
== 1)
132 return TotalBlocks
/ 2;
135 // FIXME : find good implementation.
136 SequenceBBQuery::BlockListTy
137 SequenceBBQuery::rearrangeBB(const Function
&F
, const BlockListTy
&BBList
) {
138 BlockListTy RearrangedBBSet
;
140 for (auto &Block
: F
.getBasicBlockList())
141 if (llvm::is_contained(BBList
, &Block
))
142 RearrangedBBSet
.push_back(&Block
);
144 assert(RearrangedBBSet
.size() == BBList
.size() &&
145 "BasicBlock missing while rearranging?");
146 return RearrangedBBSet
;
149 void SequenceBBQuery::traverseToEntryBlock(const BasicBlock
*AtBB
,
150 const BlockListTy
&CallerBlocks
,
151 const BackEdgesInfoTy
&BackEdgesInfo
,
152 const BranchProbabilityInfo
*BPI
,
153 VisitedBlocksInfoTy
&VisitedBlocks
) {
154 auto Itr
= VisitedBlocks
.find(AtBB
);
155 if (Itr
!= VisitedBlocks
.end()) { // already visited.
156 if (!Itr
->second
.Upward
)
158 Itr
->second
.Upward
= false;
160 // Create hint for newly discoverd blocks.
161 WalkDirection BlockHint
;
162 BlockHint
.Upward
= false;
163 // FIXME: Expensive Check
164 if (llvm::is_contained(CallerBlocks
, AtBB
))
165 BlockHint
.CallerBlock
= true;
166 VisitedBlocks
.insert(std::make_pair(AtBB
, BlockHint
));
169 const_pred_iterator PIt
= pred_begin(AtBB
), EIt
= pred_end(AtBB
);
170 // Move this check to top, when we have code setup to launch speculative
171 // compiles for function in entry BB, this triggers the speculative compiles
172 // before running the program.
173 if (PIt
== EIt
) // No Preds.
176 DenseSet
<const BasicBlock
*> PredSkipNodes
;
178 // Since we are checking for predecessor's backedges, this Block
179 // occurs in second position.
180 for (auto &I
: BackEdgesInfo
)
181 if (I
.second
== AtBB
)
182 PredSkipNodes
.insert(I
.first
);
184 // Skip predecessors which source of back-edges.
185 for (; PIt
!= EIt
; ++PIt
)
186 // checking EdgeHotness is cheaper
187 if (BPI
->isEdgeHot(*PIt
, AtBB
) && !PredSkipNodes
.count(*PIt
))
188 traverseToEntryBlock(*PIt
, CallerBlocks
, BackEdgesInfo
, BPI
,
192 void SequenceBBQuery::traverseToExitBlock(const BasicBlock
*AtBB
,
193 const BlockListTy
&CallerBlocks
,
194 const BackEdgesInfoTy
&BackEdgesInfo
,
195 const BranchProbabilityInfo
*BPI
,
196 VisitedBlocksInfoTy
&VisitedBlocks
) {
197 auto Itr
= VisitedBlocks
.find(AtBB
);
198 if (Itr
!= VisitedBlocks
.end()) { // already visited.
199 if (!Itr
->second
.Downward
)
201 Itr
->second
.Downward
= false;
203 // Create hint for newly discoverd blocks.
204 WalkDirection BlockHint
;
205 BlockHint
.Downward
= false;
206 // FIXME: Expensive Check
207 if (llvm::is_contained(CallerBlocks
, AtBB
))
208 BlockHint
.CallerBlock
= true;
209 VisitedBlocks
.insert(std::make_pair(AtBB
, BlockHint
));
212 succ_const_iterator PIt
= succ_begin(AtBB
), EIt
= succ_end(AtBB
);
213 if (PIt
== EIt
) // No succs.
216 // If there are hot edges, then compute SuccSkipNodes.
217 DenseSet
<const BasicBlock
*> SuccSkipNodes
;
219 // Since we are checking for successor's backedges, this Block
220 // occurs in first position.
221 for (auto &I
: BackEdgesInfo
)
223 SuccSkipNodes
.insert(I
.second
);
225 for (; PIt
!= EIt
; ++PIt
)
226 if (BPI
->isEdgeHot(AtBB
, *PIt
) && !SuccSkipNodes
.count(*PIt
))
227 traverseToExitBlock(*PIt
, CallerBlocks
, BackEdgesInfo
, BPI
,
231 // Get Block frequencies for blocks and take most frquently executed block,
232 // walk towards the entry block from those blocks and discover the basic blocks
234 SequenceBBQuery::BlockListTy
235 SequenceBBQuery::queryCFG(Function
&F
, const BlockListTy
&CallerBlocks
) {
237 BlockFreqInfoTy BBFreqs
;
238 VisitedBlocksInfoTy VisitedBlocks
;
239 BackEdgesInfoTy BackEdgesInfo
;
242 FunctionAnalysisManager FAM
;
243 PB
.registerFunctionAnalyses(FAM
);
245 auto &BFI
= FAM
.getResult
<BlockFrequencyAnalysis
>(F
);
247 llvm::FindFunctionBackedges(F
, BackEdgesInfo
);
249 for (const auto I
: CallerBlocks
)
250 BBFreqs
.push_back({I
, BFI
.getBlockFreq(I
).getFrequency()});
252 llvm::sort(BBFreqs
, [](decltype(BBFreqs
)::const_reference Bbf
,
253 decltype(BBFreqs
)::const_reference Bbs
) {
254 return Bbf
.second
> Bbs
.second
;
257 ArrayRef
<std::pair
<const BasicBlock
*, uint64_t>> HotBlocksRef(BBFreqs
);
259 HotBlocksRef
.drop_back(BBFreqs
.size() - getHottestBlocks(BBFreqs
.size()));
261 BranchProbabilityInfo
*BPI
=
262 FAM
.getCachedResult
<BranchProbabilityAnalysis
>(F
);
265 // traverse upwards to entry
266 // traverse downwards to end.
268 for (auto I
: HotBlocksRef
) {
269 traverseToEntryBlock(I
.first
, CallerBlocks
, BackEdgesInfo
, BPI
,
271 traverseToExitBlock(I
.first
, CallerBlocks
, BackEdgesInfo
, BPI
,
275 BlockListTy MinCallerBlocks
;
276 for (auto &I
: VisitedBlocks
)
277 if (I
.second
.CallerBlock
)
278 MinCallerBlocks
.push_back(std::move(I
.first
));
280 return rearrangeBB(F
, MinCallerBlocks
);
283 SpeculateQuery::ResultTy
SequenceBBQuery::operator()(Function
&F
) {
284 // reduce the number of lists!
285 DenseMap
<StringRef
, DenseSet
<StringRef
>> CallerAndCalles
;
286 DenseSet
<StringRef
> Calles
;
287 BlockListTy SequencedBlocks
;
288 BlockListTy CallerBlocks
;
290 CallerBlocks
= findBBwithCalls(F
);
291 if (CallerBlocks
.empty())
294 if (isStraightLine(F
))
295 SequencedBlocks
= rearrangeBB(F
, CallerBlocks
);
297 SequencedBlocks
= queryCFG(F
, CallerBlocks
);
299 for (auto BB
: SequencedBlocks
)
300 findCalles(BB
, Calles
);
302 CallerAndCalles
.insert({F
.getName(), std::move(Calles
)});
303 return CallerAndCalles
;