[InstCombine] Signed saturation patterns
[llvm-core.git] / lib / ExecutionEngine / Orc / SpeculateAnalyses.cpp
blobf22acf50419d47e91ebbc1b6b9df2f8ce50d612e
1 //===-- SpeculateAnalyses.cpp --*- C++ -*-===//
2 //
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
6 //
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"
22 #include <algorithm>
24 namespace {
25 using namespace llvm;
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;
33 else
34 return false;
36 for (auto &BB : F)
37 if (findCallInst(*BB.getTerminator()) ||
38 llvm::any_of(BB.instructionsWithoutDebug(), findCallInst))
39 BBs.emplace_back(&BB);
41 return BBs;
43 } // namespace
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.
48 namespace llvm {
49 namespace orc {
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;
72 });
75 // BlockFreqQuery Implementations
77 size_t BlockFreqQuery::numBBToGet(size_t numBB) {
78 // small CFG
79 if (numBB < 4)
80 return numBB;
81 // mid-size CFG
82 else if (numBB < 20)
83 return (numBB / 2);
84 else
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;
93 PassBuilder PB;
94 FunctionAnalysisManager FAM;
95 PB.registerFunctionAnalyses(FAM);
97 auto IBBs = findBBwithCalls(F);
99 if (IBBs.empty())
100 return None;
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)
131 return TotalBlocks;
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)
157 return;
158 Itr->second.Upward = false;
159 } else {
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.
174 return;
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,
189 VisitedBlocks);
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)
200 return;
201 Itr->second.Downward = false;
202 } else {
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.
214 return;
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)
222 if (I.first == AtBB)
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,
228 VisitedBlocks);
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
233 // with call.
234 SequenceBBQuery::BlockListTy
235 SequenceBBQuery::queryCFG(Function &F, const BlockListTy &CallerBlocks) {
237 BlockFreqInfoTy BBFreqs;
238 VisitedBlocksInfoTy VisitedBlocks;
239 BackEdgesInfoTy BackEdgesInfo;
241 PassBuilder PB;
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);
258 HotBlocksRef =
259 HotBlocksRef.drop_back(BBFreqs.size() - getHottestBlocks(BBFreqs.size()));
261 BranchProbabilityInfo *BPI =
262 FAM.getCachedResult<BranchProbabilityAnalysis>(F);
264 // visit NHotBlocks,
265 // traverse upwards to entry
266 // traverse downwards to end.
268 for (auto I : HotBlocksRef) {
269 traverseToEntryBlock(I.first, CallerBlocks, BackEdgesInfo, BPI,
270 VisitedBlocks);
271 traverseToExitBlock(I.first, CallerBlocks, BackEdgesInfo, BPI,
272 VisitedBlocks);
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())
292 return None;
294 if (isStraightLine(F))
295 SequencedBlocks = rearrangeBB(F, CallerBlocks);
296 else
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;
306 } // namespace orc
307 } // namespace llvm