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