Skip to content

Commit ec1d9c4

Browse files
aeubanksagozillon
authored andcommitted
[NFC][PassManager] Remove PreservedAnalysesT template parameter (llvm#80324)
This is always PreservedAnalyses. Perhaps in the past there was the idea to make some types of passes return more invalidation information, but that hasn't happened. Requires splitting out some analysis classes into a header so PassManagerInternal.h can see the definition of PreservedAnalyses.
1 parent 5e06bff commit ec1d9c4

File tree

6 files changed

+377
-377
lines changed

6 files changed

+377
-377
lines changed

llvm/include/llvm/Analysis/CGSCCPassManager.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,9 @@ class ModuleToPostOrderCGSCCPassAdaptor
371371
template <typename CGSCCPassT>
372372
ModuleToPostOrderCGSCCPassAdaptor
373373
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT &&Pass) {
374-
using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT,
375-
PreservedAnalyses, CGSCCAnalysisManager,
376-
LazyCallGraph &, CGSCCUpdateResult &>;
374+
using PassModelT =
375+
detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager,
376+
LazyCallGraph &, CGSCCUpdateResult &>;
377377
// Do not use make_unique, it causes too many template instantiations,
378378
// causing terrible compile times.
379379
return ModuleToPostOrderCGSCCPassAdaptor(
@@ -518,8 +518,7 @@ createCGSCCToFunctionPassAdaptor(FunctionPassT &&Pass,
518518
bool EagerlyInvalidate = false,
519519
bool NoRerun = false) {
520520
using PassModelT =
521-
detail::PassModel<Function, FunctionPassT, PreservedAnalyses,
522-
FunctionAnalysisManager>;
521+
detail::PassModel<Function, FunctionPassT, FunctionAnalysisManager>;
523522
// Do not use make_unique, it causes too many template instantiations,
524523
// causing terrible compile times.
525524
return CGSCCToFunctionPassAdaptor(
@@ -588,9 +587,9 @@ class DevirtSCCRepeatedPass : public PassInfoMixin<DevirtSCCRepeatedPass> {
588587
template <typename CGSCCPassT>
589588
DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT &&Pass,
590589
int MaxIterations) {
591-
using PassModelT = detail::PassModel<LazyCallGraph::SCC, CGSCCPassT,
592-
PreservedAnalyses, CGSCCAnalysisManager,
593-
LazyCallGraph &, CGSCCUpdateResult &>;
590+
using PassModelT =
591+
detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager,
592+
LazyCallGraph &, CGSCCUpdateResult &>;
594593
// Do not use make_unique, it causes too many template instantiations,
595594
// causing terrible compile times.
596595
return DevirtSCCRepeatedPass(

llvm/include/llvm/CodeGen/MachinePassManager.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,8 @@ class MachineFunctionPassManager
183183
template <typename PassT>
184184
std::enable_if_t<is_detected<has_init_t, PassT>::value>
185185
addDoInitialization(PassConceptT *Pass) {
186-
using PassModelT =
187-
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
188-
MachineFunctionAnalysisManager>;
186+
using PassModelT = detail::PassModel<MachineFunction, PassT,
187+
MachineFunctionAnalysisManager>;
189188
auto *P = static_cast<PassModelT *>(Pass);
190189
InitializationFuncs.emplace_back(
191190
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
@@ -205,9 +204,8 @@ class MachineFunctionPassManager
205204
template <typename PassT>
206205
std::enable_if_t<is_detected<has_fini_t, PassT>::value>
207206
addDoFinalization(PassConceptT *Pass) {
208-
using PassModelT =
209-
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
210-
MachineFunctionAnalysisManager>;
207+
using PassModelT = detail::PassModel<MachineFunction, PassT,
208+
MachineFunctionAnalysisManager>;
211209
auto *P = static_cast<PassModelT *>(Pass);
212210
FinalizationFuncs.emplace_back(
213211
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
@@ -236,9 +234,8 @@ class MachineFunctionPassManager
236234
"machine module pass needs to define machine function pass "
237235
"api. sorry.");
238236

239-
using PassModelT =
240-
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
241-
MachineFunctionAnalysisManager>;
237+
using PassModelT = detail::PassModel<MachineFunction, PassT,
238+
MachineFunctionAnalysisManager>;
242239
auto *P = static_cast<PassModelT *>(Pass);
243240
MachineModulePasses.emplace(
244241
Passes.size() - 1,

llvm/include/llvm/IR/Analysis.h

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
//===- Analysis.h --------------------------------------------*- 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+
/// \file
9+
/// Pass manager infrastructure for declaring and invalidating analyses.
10+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef LLVM_IR_ANALYSIS_H
13+
#define LLVM_IR_ANALYSIS_H
14+
15+
#include "llvm/ADT/SmallPtrSet.h"
16+
#include "llvm/IR/Function.h"
17+
#include "llvm/IR/Module.h"
18+
19+
namespace llvm {
20+
/// A special type used by analysis passes to provide an address that
21+
/// identifies that particular analysis pass type.
22+
///
23+
/// Analysis passes should have a static data member of this type and derive
24+
/// from the \c AnalysisInfoMixin to get a static ID method used to identify
25+
/// the analysis in the pass management infrastructure.
26+
struct alignas(8) AnalysisKey {};
27+
28+
/// A special type used to provide an address that identifies a set of related
29+
/// analyses. These sets are primarily used below to mark sets of analyses as
30+
/// preserved.
31+
///
32+
/// For example, a transformation can indicate that it preserves the CFG of a
33+
/// function by preserving the appropriate AnalysisSetKey. An analysis that
34+
/// depends only on the CFG can then check if that AnalysisSetKey is preserved;
35+
/// if it is, the analysis knows that it itself is preserved.
36+
struct alignas(8) AnalysisSetKey {};
37+
38+
/// This templated class represents "all analyses that operate over \<a
39+
/// particular IR unit\>" (e.g. a Function or a Module) in instances of
40+
/// PreservedAnalysis.
41+
///
42+
/// This lets a transformation say e.g. "I preserved all function analyses".
43+
///
44+
/// Note that you must provide an explicit instantiation declaration and
45+
/// definition for this template in order to get the correct behavior on
46+
/// Windows. Otherwise, the address of SetKey will not be stable.
47+
template <typename IRUnitT> class AllAnalysesOn {
48+
public:
49+
static AnalysisSetKey *ID() { return &SetKey; }
50+
51+
private:
52+
static AnalysisSetKey SetKey;
53+
};
54+
55+
template <typename IRUnitT> AnalysisSetKey AllAnalysesOn<IRUnitT>::SetKey;
56+
57+
extern template class AllAnalysesOn<Module>;
58+
extern template class AllAnalysesOn<Function>;
59+
60+
/// Represents analyses that only rely on functions' control flow.
61+
///
62+
/// This can be used with \c PreservedAnalyses to mark the CFG as preserved and
63+
/// to query whether it has been preserved.
64+
///
65+
/// The CFG of a function is defined as the set of basic blocks and the edges
66+
/// between them. Changing the set of basic blocks in a function is enough to
67+
/// mutate the CFG. Mutating the condition of a branch or argument of an
68+
/// invoked function does not mutate the CFG, but changing the successor labels
69+
/// of those instructions does.
70+
class CFGAnalyses {
71+
public:
72+
static AnalysisSetKey *ID() { return &SetKey; }
73+
74+
private:
75+
static AnalysisSetKey SetKey;
76+
};
77+
78+
/// A set of analyses that are preserved following a run of a transformation
79+
/// pass.
80+
///
81+
/// Transformation passes build and return these objects to communicate which
82+
/// analyses are still valid after the transformation. For most passes this is
83+
/// fairly simple: if they don't change anything all analyses are preserved,
84+
/// otherwise only a short list of analyses that have been explicitly updated
85+
/// are preserved.
86+
///
87+
/// This class also lets transformation passes mark abstract *sets* of analyses
88+
/// as preserved. A transformation that (say) does not alter the CFG can
89+
/// indicate such by marking a particular AnalysisSetKey as preserved, and
90+
/// then analyses can query whether that AnalysisSetKey is preserved.
91+
///
92+
/// Finally, this class can represent an "abandoned" analysis, which is
93+
/// not preserved even if it would be covered by some abstract set of analyses.
94+
///
95+
/// Given a `PreservedAnalyses` object, an analysis will typically want to
96+
/// figure out whether it is preserved. In the example below, MyAnalysisType is
97+
/// preserved if it's not abandoned, and (a) it's explicitly marked as
98+
/// preserved, (b), the set AllAnalysesOn<MyIRUnit> is preserved, or (c) both
99+
/// AnalysisSetA and AnalysisSetB are preserved.
100+
///
101+
/// ```
102+
/// auto PAC = PA.getChecker<MyAnalysisType>();
103+
/// if (PAC.preserved() || PAC.preservedSet<AllAnalysesOn<MyIRUnit>>() ||
104+
/// (PAC.preservedSet<AnalysisSetA>() &&
105+
/// PAC.preservedSet<AnalysisSetB>())) {
106+
/// // The analysis has been successfully preserved ...
107+
/// }
108+
/// ```
109+
class PreservedAnalyses {
110+
public:
111+
/// Convenience factory function for the empty preserved set.
112+
static PreservedAnalyses none() { return PreservedAnalyses(); }
113+
114+
/// Construct a special preserved set that preserves all passes.
115+
static PreservedAnalyses all() {
116+
PreservedAnalyses PA;
117+
PA.PreservedIDs.insert(&AllAnalysesKey);
118+
return PA;
119+
}
120+
121+
/// Construct a preserved analyses object with a single preserved set.
122+
template <typename AnalysisSetT> static PreservedAnalyses allInSet() {
123+
PreservedAnalyses PA;
124+
PA.preserveSet<AnalysisSetT>();
125+
return PA;
126+
}
127+
128+
/// Mark an analysis as preserved.
129+
template <typename AnalysisT> void preserve() { preserve(AnalysisT::ID()); }
130+
131+
/// Given an analysis's ID, mark the analysis as preserved, adding it
132+
/// to the set.
133+
void preserve(AnalysisKey *ID) {
134+
// Clear this ID from the explicit not-preserved set if present.
135+
NotPreservedAnalysisIDs.erase(ID);
136+
137+
// If we're not already preserving all analyses (other than those in
138+
// NotPreservedAnalysisIDs).
139+
if (!areAllPreserved())
140+
PreservedIDs.insert(ID);
141+
}
142+
143+
/// Mark an analysis set as preserved.
144+
template <typename AnalysisSetT> void preserveSet() {
145+
preserveSet(AnalysisSetT::ID());
146+
}
147+
148+
/// Mark an analysis set as preserved using its ID.
149+
void preserveSet(AnalysisSetKey *ID) {
150+
// If we're not already in the saturated 'all' state, add this set.
151+
if (!areAllPreserved())
152+
PreservedIDs.insert(ID);
153+
}
154+
155+
/// Mark an analysis as abandoned.
156+
///
157+
/// An abandoned analysis is not preserved, even if it is nominally covered
158+
/// by some other set or was previously explicitly marked as preserved.
159+
///
160+
/// Note that you can only abandon a specific analysis, not a *set* of
161+
/// analyses.
162+
template <typename AnalysisT> void abandon() { abandon(AnalysisT::ID()); }
163+
164+
/// Mark an analysis as abandoned using its ID.
165+
///
166+
/// An abandoned analysis is not preserved, even if it is nominally covered
167+
/// by some other set or was previously explicitly marked as preserved.
168+
///
169+
/// Note that you can only abandon a specific analysis, not a *set* of
170+
/// analyses.
171+
void abandon(AnalysisKey *ID) {
172+
PreservedIDs.erase(ID);
173+
NotPreservedAnalysisIDs.insert(ID);
174+
}
175+
176+
/// Intersect this set with another in place.
177+
///
178+
/// This is a mutating operation on this preserved set, removing all
179+
/// preserved passes which are not also preserved in the argument.
180+
void intersect(const PreservedAnalyses &Arg) {
181+
if (Arg.areAllPreserved())
182+
return;
183+
if (areAllPreserved()) {
184+
*this = Arg;
185+
return;
186+
}
187+
// The intersection requires the *union* of the explicitly not-preserved
188+
// IDs and the *intersection* of the preserved IDs.
189+
for (auto *ID : Arg.NotPreservedAnalysisIDs) {
190+
PreservedIDs.erase(ID);
191+
NotPreservedAnalysisIDs.insert(ID);
192+
}
193+
for (auto *ID : PreservedIDs)
194+
if (!Arg.PreservedIDs.count(ID))
195+
PreservedIDs.erase(ID);
196+
}
197+
198+
/// Intersect this set with a temporary other set in place.
199+
///
200+
/// This is a mutating operation on this preserved set, removing all
201+
/// preserved passes which are not also preserved in the argument.
202+
void intersect(PreservedAnalyses &&Arg) {
203+
if (Arg.areAllPreserved())
204+
return;
205+
if (areAllPreserved()) {
206+
*this = std::move(Arg);
207+
return;
208+
}
209+
// The intersection requires the *union* of the explicitly not-preserved
210+
// IDs and the *intersection* of the preserved IDs.
211+
for (auto *ID : Arg.NotPreservedAnalysisIDs) {
212+
PreservedIDs.erase(ID);
213+
NotPreservedAnalysisIDs.insert(ID);
214+
}
215+
for (auto *ID : PreservedIDs)
216+
if (!Arg.PreservedIDs.count(ID))
217+
PreservedIDs.erase(ID);
218+
}
219+
220+
/// A checker object that makes it easy to query for whether an analysis or
221+
/// some set covering it is preserved.
222+
class PreservedAnalysisChecker {
223+
friend class PreservedAnalyses;
224+
225+
const PreservedAnalyses &PA;
226+
AnalysisKey *const ID;
227+
const bool IsAbandoned;
228+
229+
/// A PreservedAnalysisChecker is tied to a particular Analysis because
230+
/// `preserved()` and `preservedSet()` both return false if the Analysis
231+
/// was abandoned.
232+
PreservedAnalysisChecker(const PreservedAnalyses &PA, AnalysisKey *ID)
233+
: PA(PA), ID(ID), IsAbandoned(PA.NotPreservedAnalysisIDs.count(ID)) {}
234+
235+
public:
236+
/// Returns true if the checker's analysis was not abandoned and either
237+
/// - the analysis is explicitly preserved or
238+
/// - all analyses are preserved.
239+
bool preserved() {
240+
return !IsAbandoned && (PA.PreservedIDs.count(&AllAnalysesKey) ||
241+
PA.PreservedIDs.count(ID));
242+
}
243+
244+
/// Return true if the checker's analysis was not abandoned, i.e. it was not
245+
/// explicitly invalidated. Even if the analysis is not explicitly
246+
/// preserved, if the analysis is known stateless, then it is preserved.
247+
bool preservedWhenStateless() { return !IsAbandoned; }
248+
249+
/// Returns true if the checker's analysis was not abandoned and either
250+
/// - \p AnalysisSetT is explicitly preserved or
251+
/// - all analyses are preserved.
252+
template <typename AnalysisSetT> bool preservedSet() {
253+
AnalysisSetKey *SetID = AnalysisSetT::ID();
254+
return !IsAbandoned && (PA.PreservedIDs.count(&AllAnalysesKey) ||
255+
PA.PreservedIDs.count(SetID));
256+
}
257+
};
258+
259+
/// Build a checker for this `PreservedAnalyses` and the specified analysis
260+
/// type.
261+
///
262+
/// You can use the returned object to query whether an analysis was
263+
/// preserved. See the example in the comment on `PreservedAnalysis`.
264+
template <typename AnalysisT> PreservedAnalysisChecker getChecker() const {
265+
return PreservedAnalysisChecker(*this, AnalysisT::ID());
266+
}
267+
268+
/// Build a checker for this `PreservedAnalyses` and the specified analysis
269+
/// ID.
270+
///
271+
/// You can use the returned object to query whether an analysis was
272+
/// preserved. See the example in the comment on `PreservedAnalysis`.
273+
PreservedAnalysisChecker getChecker(AnalysisKey *ID) const {
274+
return PreservedAnalysisChecker(*this, ID);
275+
}
276+
277+
/// Test whether all analyses are preserved (and none are abandoned).
278+
///
279+
/// This is used primarily to optimize for the common case of a transformation
280+
/// which makes no changes to the IR.
281+
bool areAllPreserved() const {
282+
return NotPreservedAnalysisIDs.empty() &&
283+
PreservedIDs.count(&AllAnalysesKey);
284+
}
285+
286+
/// Directly test whether a set of analyses is preserved.
287+
///
288+
/// This is only true when no analyses have been explicitly abandoned.
289+
template <typename AnalysisSetT> bool allAnalysesInSetPreserved() const {
290+
return allAnalysesInSetPreserved(AnalysisSetT::ID());
291+
}
292+
293+
/// Directly test whether a set of analyses is preserved.
294+
///
295+
/// This is only true when no analyses have been explicitly abandoned.
296+
bool allAnalysesInSetPreserved(AnalysisSetKey *SetID) const {
297+
return NotPreservedAnalysisIDs.empty() &&
298+
(PreservedIDs.count(&AllAnalysesKey) || PreservedIDs.count(SetID));
299+
}
300+
301+
private:
302+
/// A special key used to indicate all analyses.
303+
static AnalysisSetKey AllAnalysesKey;
304+
305+
/// The IDs of analyses and analysis sets that are preserved.
306+
SmallPtrSet<void *, 2> PreservedIDs;
307+
308+
/// The IDs of explicitly not-preserved analyses.
309+
///
310+
/// If an analysis in this set is covered by a set in `PreservedIDs`, we
311+
/// consider it not-preserved. That is, `NotPreservedAnalysisIDs` always
312+
/// "wins" over analysis sets in `PreservedIDs`.
313+
///
314+
/// Also, a given ID should never occur both here and in `PreservedIDs`.
315+
SmallPtrSet<AnalysisKey *, 2> NotPreservedAnalysisIDs;
316+
};
317+
} // namespace llvm
318+
319+
#endif

0 commit comments

Comments
 (0)