1 //===- PassManagerImpl.h - Pass management infrastructure -------*- 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 //===----------------------------------------------------------------------===//
8 ///
9 /// Provides implementations for PassManager and AnalysisManager template
10 /// methods. These classes should be explicitly instantiated for any IR unit,
11 /// and files doing the explicit instantiation should include this header.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_IR_PASSMANAGERIMPL_H
16 #define LLVM_IR_PASSMANAGERIMPL_H
17
18 #include "llvm/IR/PassManager.h"
19
20 namespace llvm {
21
22 template <typename IRUnitT, typename... ExtraArgTs>
AnalysisManager(bool DebugLogging)23 inline AnalysisManager<IRUnitT, ExtraArgTs...>::AnalysisManager(
24 bool DebugLogging)
25 : DebugLogging(DebugLogging) {}
26
27 template <typename IRUnitT, typename... ExtraArgTs>
28 inline AnalysisManager<IRUnitT, ExtraArgTs...>::AnalysisManager(
29 AnalysisManager &&) = default;
30
31 template <typename IRUnitT, typename... ExtraArgTs>
32 inline AnalysisManager<IRUnitT, ExtraArgTs...> &
33 AnalysisManager<IRUnitT, ExtraArgTs...>::operator=(AnalysisManager &&) =
34 default;
35
36 template <typename IRUnitT, typename... ExtraArgTs>
37 inline void
clear(IRUnitT & IR,llvm::StringRef Name)38 AnalysisManager<IRUnitT, ExtraArgTs...>::clear(IRUnitT &IR,
39 llvm::StringRef Name) {
40 if (DebugLogging)
41 dbgs() << "Clearing all analysis results for: " << Name << "\n";
42
43 auto ResultsListI = AnalysisResultLists.find(&IR);
44 if (ResultsListI == AnalysisResultLists.end())
45 return;
46 // Delete the map entries that point into the results list.
47 for (auto &IDAndResult : ResultsListI->second)
48 AnalysisResults.erase({IDAndResult.first, &IR});
49
50 // And actually destroy and erase the results associated with this IR.
51 AnalysisResultLists.erase(ResultsListI);
52 }
53
54 template <typename IRUnitT, typename... ExtraArgTs>
55 inline typename AnalysisManager<IRUnitT, ExtraArgTs...>::ResultConceptT &
getResultImpl(AnalysisKey * ID,IRUnitT & IR,ExtraArgTs...ExtraArgs)56 AnalysisManager<IRUnitT, ExtraArgTs...>::getResultImpl(
57 AnalysisKey *ID, IRUnitT &IR, ExtraArgTs... ExtraArgs) {
58 typename AnalysisResultMapT::iterator RI;
59 bool Inserted;
60 std::tie(RI, Inserted) = AnalysisResults.insert(std::make_pair(
61 std::make_pair(ID, &IR), typename AnalysisResultListT::iterator()));
62
63 // If we don't have a cached result for this function, look up the pass and
64 // run it to produce a result, which we then add to the cache.
65 if (Inserted) {
66 auto &P = this->lookUpPass(ID);
67
68 PassInstrumentation PI;
69 if (ID != PassInstrumentationAnalysis::ID()) {
70 PI = getResult<PassInstrumentationAnalysis>(IR, ExtraArgs...);
71 PI.runBeforeAnalysis(P, IR);
72 }
73
74 AnalysisResultListT &ResultList = AnalysisResultLists[&IR];
75 ResultList.emplace_back(ID, P.run(IR, *this, ExtraArgs...));
76
77 PI.runAfterAnalysis(P, IR);
78
79 // P.run may have inserted elements into AnalysisResults and invalidated
80 // RI.
81 RI = AnalysisResults.find({ID, &IR});
82 assert(RI != AnalysisResults.end() && "we just inserted it!");
83
84 RI->second = std::prev(ResultList.end());
85 }
86
87 return *RI->second->second;
88 }
89
90 template <typename IRUnitT, typename... ExtraArgTs>
invalidate(IRUnitT & IR,const PreservedAnalyses & PA)91 inline void AnalysisManager<IRUnitT, ExtraArgTs...>::invalidate(
92 IRUnitT &IR, const PreservedAnalyses &PA) {
93 // We're done if all analyses on this IR unit are preserved.
94 if (PA.allAnalysesInSetPreserved<AllAnalysesOn<IRUnitT>>())
95 return;
96
97 // Track whether each analysis's result is invalidated in
98 // IsResultInvalidated.
99 SmallDenseMap<AnalysisKey *, bool, 8> IsResultInvalidated;
100 Invalidator Inv(IsResultInvalidated, AnalysisResults);
101 AnalysisResultListT &ResultsList = AnalysisResultLists[&IR];
102 for (auto &AnalysisResultPair : ResultsList) {
103 // This is basically the same thing as Invalidator::invalidate, but we
104 // can't call it here because we're operating on the type-erased result.
105 // Moreover if we instead called invalidate() directly, it would do an
106 // unnecessary look up in ResultsList.
107 AnalysisKey *ID = AnalysisResultPair.first;
108 auto &Result = *AnalysisResultPair.second;
109
110 auto IMapI = IsResultInvalidated.find(ID);
111 if (IMapI != IsResultInvalidated.end())
112 // This result was already handled via the Invalidator.
113 continue;
114
115 // Try to invalidate the result, giving it the Invalidator so it can
116 // recursively query for any dependencies it has and record the result.
117 // Note that we cannot reuse 'IMapI' here or pre-insert the ID, as
118 // Result.invalidate may insert things into the map, invalidating our
119 // iterator.
120 bool Inserted =
121 IsResultInvalidated.insert({ID, Result.invalidate(IR, PA, Inv)}).second;
122 (void)Inserted;
123 assert(Inserted && "Should never have already inserted this ID, likely "
124 "indicates a cycle!");
125 }
126
127 // Now erase the results that were marked above as invalidated.
128 if (!IsResultInvalidated.empty()) {
129 for (auto I = ResultsList.begin(), E = ResultsList.end(); I != E;) {
130 AnalysisKey *ID = I->first;
131 if (!IsResultInvalidated.lookup(ID)) {
132 ++I;
133 continue;
134 }
135
136 if (DebugLogging)
137 dbgs() << "Invalidating analysis: " << this->lookUpPass(ID).name()
138 << " on " << IR.getName() << "\n";
139
140 I = ResultsList.erase(I);
141 AnalysisResults.erase({ID, &IR});
142 }
143 }
144
145 if (ResultsList.empty())
146 AnalysisResultLists.erase(&IR);
147 }
148 } // end namespace llvm
149
150 #endif // LLVM_IR_PASSMANAGERIMPL_H
151