MLIR 23.0.0git
OneShotAnalysis.h
Go to the documentation of this file.
1//===- OneShotAnalysis.h - One-Shot (Single Pass) Analysis ------*- 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#ifndef MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTANALYSIS_H
10#define MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTANALYSIS_H
11
13#include "llvm/ADT/EquivalenceClasses.h"
14#include <string>
15
16namespace mlir {
17class DominanceInfo;
18
19namespace bufferization {
20
24
25/// Options for analysis-enabled bufferization.
33
35
36 /// Specifies whether returning newly allocated memrefs from loops should be
37 /// allowed. Otherwise, a pass failure is triggered.
39
40 /// Specifies whether the tensor IR should be annotated with alias sets.
41 bool dumpAliasSets = false;
42
43 /// The heuristic controls the order in which ops are traversed during the
44 /// analysis.
46
47 /// Specify the functions that should not be analyzed. copyBeforeWrite will be
48 /// set to true when bufferizing them.
50
51 /// Seed for the analysis fuzzer. Used only if the heuristic is set to
52 /// `AnalysisHeuristic::Fuzzer`. The fuzzer should be used only with
53 /// `testAnalysisOnly = true`.
54 unsigned analysisFuzzerSeed = 0;
55};
56
57/// State for analysis-enabled bufferization. This class keeps track of alias
58/// sets, equivalence sets, in-place OpOperands and other things.
59///
60/// Note: Modifying the IR generally invalidates the result of the analysis.
61/// Adding new operations is safe if they are analyzed subsequently.
63public:
66
68
69 ~OneShotAnalysisState() override = default;
70
71 static bool classof(const AnalysisState *base) {
72 return base->getType() == TypeID::get<OneShotAnalysisState>();
73 }
74
75 /// Return a reference to the BufferizationOptions.
77 return static_cast<const OneShotBufferizationOptions &>(
78 AnalysisState::getOptions());
79 }
80
81 /// Analyze the given op and its nested ops.
82 LogicalResult analyzeOp(Operation *op, const DominanceInfo &domInfo);
83
84 /// Analyze a single op (without nested ops).
85 LogicalResult analyzeSingleOp(Operation *op, const DominanceInfo &domInfo);
86
87 /// Apply `fun` to all the members of the equivalence class of `v`.
88 void applyOnEquivalenceClass(Value v, function_ref<void(Value)> fun) const;
89
90 /// Apply `fun` to all aliases of `v`.
91 void applyOnAliases(Value v, function_ref<void(Value)> fun) const;
92
93 /// Return true if `v1` and `v2` bufferize to equivalent buffers.
94 bool areEquivalentBufferizedValues(Value v1, Value v2) const override;
95
96 /// Return true if `v1` and `v2` may bufferize to aliasing buffers.
97 bool areAliasingBufferizedValues(Value v1, Value v2) const override;
98
99 /// Mark the given OpOperand as in-place and merge the results' and operand's
100 /// aliasing sets.
101 void bufferizeInPlace(OpOperand &operand);
102
103 /// Mark the given OpOperand as out-of-place.
104 void bufferizeOutOfPlace(OpOperand &operand);
105
106 /// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the
107 /// beginning the alias and equivalence sets only contain `v` itself.
109
110 /// Find all tensor values in the given operation that have undefined contents
111 /// and store them in `undefinedTensorUses`.
113
114 int64_t getStatNumTensorOutOfPlace() const { return statNumTensorOutOfPlace; }
115 int64_t getStatNumTensorInPlace() const { return statNumTensorInPlace; }
116
117 /// Return `true` if the given tensor has undefined contents.
118 bool hasUndefinedContents(OpOperand *opOperand) const override;
119
120 /// Return `true` if the given OpResult has been decided to bufferize inplace.
121 bool isInPlace(OpOperand &opOperand) const override;
122
123 /// Return true if the buffer of the given tensor value is written to. Must
124 /// not be called for values inside not yet analyzed functions.
125 bool isValueWritten(Value value) const;
126
127 /// Return true if the buffer of the given tensor value is writable.
128 bool isWritable(Value value) const;
129
130 /// Find the definitions of the given operand's value or
131 /// retrieve them from the cache.
133
134 /// Return whether `uRead` and `uConflictingWrite` are non-conflicting
135 /// subsets, with caching.
137 OpOperand *uConflictingWrite);
138
139 /// Reset cached data structures.
140 void resetCache() override;
141
142 /// Union the alias sets of `v1` and `v2`.
143 void unionAliasSets(Value v1, Value v2);
144
145 /// Union the equivalence classes of `v1` and `v2`.
147
148 /// Base class for OneShotAnalysisState extensions that allow
149 /// OneShotAnalysisState to contain user-specified information in the state
150 /// object. Clients are expected to derive this class, add the desired fields,
151 /// and make the derived class compatible with the MLIR TypeID mechanism.
152 ///
153 /// ```mlir
154 /// class MyExtension final : public OneShotAnalysisState::Extension {
155 /// public:
156 /// MyExtension(OneShotAnalysisState &state, int myData)
157 /// : Extension(state) {...}
158 /// private:
159 /// int mySupplementaryData;
160 /// };
161 /// ```
162 ///
163 /// Instances of this and derived classes are not expected to be created by
164 /// the user, instead they are directly constructed within a
165 /// OneShotAnalysisState. A OneShotAnalysisState can only contain one
166 /// extension with the given TypeID. Extensions can be obtained from a
167 /// OneShotAnalysisState instance.
168 ///
169 /// ```mlir
170 /// state.addExtension<MyExtension>(/*myData=*/42);
171 /// MyExtension *ext = state.getExtension<MyExtension>();
172 /// ext->doSomething();
173 /// ```
174 class Extension {
175 // Allow OneShotAnalysisState to allocate Extensions.
177
178 public:
179 /// Base virtual destructor.
180 // Out-of-line definition ensures symbols are emitted in a single object
181 // file.
182 virtual ~Extension();
183
184 protected:
185 /// Constructs an extension of the given state object.
186 Extension(OneShotAnalysisState &state) : state(state) {}
187
188 /// Provides read-only access to the parent OneShotAnalysisState object.
189 const OneShotAnalysisState &getAnalysisState() const { return state; }
190
191 private:
192 /// Back-reference to the state that is being extended.
194 };
195
196 /// Adds a new Extension of the type specified as template parameter,
197 /// constructing it with the arguments provided. The extension is owned by the
198 /// OneShotAnalysisState. It is expected that the state does not already have
199 /// an extension of the same type. Extension constructors are expected to take
200 /// a reference to OneShotAnalysisState as first argument, automatically
201 /// supplied by this call.
202 template <typename Ty, typename... Args>
203 Ty &addExtension(Args &&...args) {
204 static_assert(
205 std::is_base_of<Extension, Ty>::value,
206 "only a class derived from OneShotAnalysisState::Extension is allowed");
207 auto ptr = std::make_unique<Ty>(*this, std::forward<Args>(args)...);
208 auto result = extensions.try_emplace(TypeID::get<Ty>(), std::move(ptr));
209 assert(result.second && "extension already added");
210 return *static_cast<Ty *>(result.first->second.get());
211 }
212
213 /// Returns the extension of the specified type.
214 template <typename Ty>
216 static_assert(
217 std::is_base_of<Extension, Ty>::value,
218 "only a class derived from OneShotAnalysisState::Extension is allowed");
219 auto iter = extensions.find(TypeID::get<Ty>());
220 if (iter == extensions.end())
221 return nullptr;
222 return static_cast<Ty *>(iter->second.get());
223 }
224
225 /// Returns the extension of the specified type.
226 template <typename Ty>
227 const Ty *getExtension() const {
228 return const_cast<OneShotAnalysisState *>(this)->getExtension<Ty>();
229 }
230
231private:
232 using EquivalenceClassRangeType =
234 /// Check that aliasInfo for `v` exists and return a reference to it.
235 EquivalenceClassRangeType getAliases(Value v) const;
236
237 /// Cache definitions of tensor values.
238 DenseMap<Value, SetVector<Value>> cachedDefinitions;
239
240 /// Cache results of areNonConflictingSubsets checks. The bool value is `true`
241 /// if the operands are non-conflicting subsets, `false` if they are
242 /// conflicting. The absence of an entry means uncached.
243 DenseMap<std::pair<OpOperand *, OpOperand *>, bool> nonConflictingSubsetCache;
244
245 /// Set of all OpResults that were decided to bufferize in-place.
246 llvm::DenseSet<OpOperand *> inplaceBufferized;
247
248 /// Auxiliary structure to store all the values a given value may alias with.
249 /// Alias information is "may be" conservative: In the presence of branches, a
250 /// value may alias with one of multiple other values. The concrete aliasing
251 /// value may not even be known at compile time. All such values are
252 /// considered to be aliases.
253 llvm::EquivalenceClasses<Value> aliasInfo;
254
255 /// Auxiliary structure to store all the equivalent buffer classes. Equivalent
256 /// buffer information is "must be" conservative: Only if two values are
257 /// guaranteed to be equivalent at runtime, they said to be equivalent. It is
258 /// possible that, in the presence of branches, it cannot be determined
259 /// statically if two values are equivalent. In that case, the values are
260 /// considered to be not equivalent.
261 llvm::EquivalenceClasses<Value> equivalentInfo;
262
263 // Bufferization statistics.
264 int64_t statNumTensorOutOfPlace = 0;
265 int64_t statNumTensorInPlace = 0;
266
267 /// A set of uses of tensors that have undefined contents.
268 DenseSet<OpOperand *> undefinedTensorUses;
269
270 /// Extensions attached to the state, identified by the TypeID of their type.
271 /// Only one extension of any given type is allowed.
273};
274
275/// Analyze `op` and its nested ops. Bufferization decisions are stored in
276/// `state`.
277LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state,
278 BufferizationStatistics *statistics = nullptr);
279
280/// Run One-Shot Bufferize on the given op: Analysis + Bufferization
281LogicalResult
282runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options,
283 BufferizationState &state,
284 BufferizationStatistics *statistics = nullptr);
285
286} // namespace bufferization
287} // namespace mlir
288
290
291#endif // MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTANALYSIS_H
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DECLARE_EXPLICIT_TYPE_ID(CLASS_NAME)
Definition TypeID.h:321
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
A class for computing basic dominance information.
Definition Dominance.h:140
This class represents an operand of an operation.
Definition Value.h:254
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
static TypeID get()
Construct a type info object for the given type T.
Definition TypeID.h:245
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
virtual ~Extension()
Base virtual destructor.
Extension(OneShotAnalysisState &state)
Constructs an extension of the given state object.
const OneShotAnalysisState & getAnalysisState() const
Provides read-only access to the parent OneShotAnalysisState object.
State for analysis-enabled bufferization.
void bufferizeOutOfPlace(OpOperand &operand)
Mark the given OpOperand as out-of-place.
bool isWritable(Value value) const
Return true if the buffer of the given tensor value is writable.
const SetVector< Value > & findDefinitionsCached(OpOperand *opOperand)
Find the definitions of the given operand's value or retrieve them from the cache.
bool isInPlace(OpOperand &opOperand) const override
Return true if the given OpResult has been decided to bufferize inplace.
LogicalResult analyzeOp(Operation *op, const DominanceInfo &domInfo)
Analyze the given op and its nested ops.
bool isValueWritten(Value value) const
Return true if the buffer of the given tensor value is written to.
void unionEquivalenceClasses(Value v1, Value v2)
Union the equivalence classes of v1 and v2.
OneShotAnalysisState(const OneShotAnalysisState &)=delete
void gatherUndefinedTensorUses(Operation *op)
Find all tensor values in the given operation that have undefined contents and store them in undefine...
void resetCache() override
Reset cached data structures.
Ty & addExtension(Args &&...args)
Adds a new Extension of the type specified as template parameter, constructing it with the arguments ...
const OneShotBufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
Ty * getExtension()
Returns the extension of the specified type.
LogicalResult analyzeSingleOp(Operation *op, const DominanceInfo &domInfo)
Analyze a single op (without nested ops).
const Ty * getExtension() const
Returns the extension of the specified type.
void applyOnEquivalenceClass(Value v, function_ref< void(Value)> fun) const
Apply fun to all the members of the equivalence class of v.
bool hasUndefinedContents(OpOperand *opOperand) const override
Return true if the given tensor has undefined contents.
bool areNonConflictingSubsetsCached(OpOperand *uRead, OpOperand *uConflictingWrite)
Return whether uRead and uConflictingWrite are non-conflicting subsets, with caching.
static bool classof(const AnalysisState *base)
void bufferizeInPlace(OpOperand &operand)
Mark the given OpOperand as in-place and merge the results' and operand's aliasing sets.
void applyOnAliases(Value v, function_ref< void(Value)> fun) const
Apply fun to all aliases of v.
bool areEquivalentBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 bufferize to equivalent buffers.
OneShotAnalysisState(Operation *op, const OneShotBufferizationOptions &options)
bool areAliasingBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 may bufferize to aliasing buffers.
void unionAliasSets(Value v1, Value v2)
Union the alias sets of v1 and v2.
void createAliasInfoEntry(Value v)
Add a new entry for v in the aliasInfo and equivalentInfo.
LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state, BufferizationStatistics *statistics=nullptr)
Analyze op and its nested ops.
LogicalResult runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options, BufferizationState &state, BufferizationStatistics *statistics=nullptr)
Run One-Shot Bufferize on the given op: Analysis + Bufferization.
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
Definition LLVM.h:122
llvm::SetVector< T, Vector, Set, N > SetVector
Definition LLVM.h:125
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
Bufferization statistics for debugging.
Definition Bufferize.h:35
Options for analysis-enabled bufferization.
unsigned analysisFuzzerSeed
Seed for the analysis fuzzer.
bool dumpAliasSets
Specifies whether the tensor IR should be annotated with alias sets.
bool allowReturnAllocsFromLoops
Specifies whether returning newly allocated memrefs from loops should be allowed.
AnalysisHeuristic analysisHeuristic
The heuristic controls the order in which ops are traversed during the analysis.
llvm::ArrayRef< std::string > noAnalysisFuncFilter
Specify the functions that should not be analyzed.