MLIR 24.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 "llvm/ADT/SmallPtrSet.h"
15#include <memory>
16#include <optional>
17#include <string>
18
19namespace mlir {
20class DominanceInfo;
21
22namespace bufferization {
23
27
28/// Options for analysis-enabled bufferization.
36
38
39 /// Specifies whether returning newly allocated memrefs from loops should be
40 /// allowed. Otherwise, a pass failure is triggered.
42
43 /// Specifies whether the tensor IR should be annotated with alias sets.
44 bool dumpAliasSets = false;
45
46 /// The heuristic controls the order in which ops are traversed during the
47 /// analysis.
49
50 /// Specify the functions that should not be analyzed. copyBeforeWrite will be
51 /// set to true when bufferizing them.
53
54 /// Seed for the analysis fuzzer. Used only if the heuristic is set to
55 /// `AnalysisHeuristic::Fuzzer`. The fuzzer should be used only with
56 /// `testAnalysisOnly = true`.
57 unsigned analysisFuzzerSeed = 0;
58
59 /// Whether the IR contains a region with more than one block. When unset,
60 /// the analysis walks the IR to compute it.
61 /// Note: If the IR contains unstructured control flow, but this flag is set
62 /// to "false", the bufferization may produce incorrect IR.
63 std::optional<bool> mayHaveUnstructuredControlFlow = std::nullopt;
64};
65
66/// State for analysis-enabled bufferization. This class keeps track of alias
67/// sets, equivalence sets, in-place OpOperands and other things.
68///
69/// Note: Modifying the IR generally invalidates the result of the analysis.
70/// Adding new operations is safe if they are analyzed subsequently.
72public:
75
77
79
80 static bool classof(const AnalysisState *base) {
81 return base->getType() == TypeID::get<OneShotAnalysisState>();
82 }
83
84 /// Return a reference to the BufferizationOptions.
86 return static_cast<const OneShotBufferizationOptions &>(
87 AnalysisState::getOptions());
88 }
89
90 /// True if any region in the analyzed IR has more than one block. Taken from
91 /// the options when set; otherwise computed by walking the IR.
92 bool mayHaveUnstructuredControlFlow() const { return mayHaveUnstructuredCF; }
93
94 /// True if the analyzed IR may contain a parallel region. Taken from the
95 /// options when set; otherwise computed by walking the IR.
96 bool mayHaveParallelRegions() const { return mayHaveParallelRegionsFlag; }
97
98 /// Analyze the given op and its nested ops.
99 LogicalResult analyzeOp(Operation *op, const DominanceInfo &domInfo);
100
101 /// Analyze a single op (without nested ops).
102 LogicalResult analyzeSingleOp(Operation *op, const DominanceInfo &domInfo);
103
104 /// Apply `fun` to all the members of the equivalence class of `v`.
105 void applyOnEquivalenceClass(Value v, function_ref<void(Value)> fun) const;
106
107 /// Apply `fun` to all aliases of `v`.
108 void applyOnAliases(Value v, function_ref<void(Value)> fun) const;
109
110 /// Return true if `v1` and `v2` bufferize to equivalent buffers.
111 bool areEquivalentBufferizedValues(Value v1, Value v2) const override;
112
113 /// Return true if `v1` and `v2` may bufferize to aliasing buffers.
114 bool areAliasingBufferizedValues(Value v1, Value v2) const override;
115
116 /// Mark the given OpOperand as in-place and merge the results' and operand's
117 /// aliasing sets.
118 void bufferizeInPlace(OpOperand &operand);
119
120 /// Mark the given OpOperand as out-of-place.
121 void bufferizeOutOfPlace(OpOperand &operand);
122
123 /// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the
124 /// beginning the alias and equivalence sets only contain `v` itself.
126
127 /// Find all tensor values in the given operation that have undefined contents
128 /// and store them in `undefinedTensorUses`.
130
131 int64_t getStatNumTensorOutOfPlace() const { return statNumTensorOutOfPlace; }
132 int64_t getStatNumTensorInPlace() const { return statNumTensorInPlace; }
133
134 /// Return `true` if the given tensor has undefined contents.
135 bool hasUndefinedContents(OpOperand *opOperand) const override;
136
137 /// Return `true` if the given OpResult has been decided to bufferize inplace.
138 bool isInPlace(OpOperand &opOperand) const override;
139
140 /// Return true if the buffer of the given tensor value is written to. Must
141 /// not be called for values inside not yet analyzed functions.
142 bool isValueWritten(Value value) const;
143
144 /// Return true if the buffer of the given tensor value is writable.
145 bool isWritable(Value value) const;
146
147 /// Find the definitions of the given operand's value or
148 /// retrieve them from the cache.
150
151 /// Return true if `to` is reachable from `from` without crossing `barriers`.
152 /// Results are cached; the cache is cleared by `resetCache`.
153 bool
154 isReachableCached(Block *from, Block *to,
155 const llvm::SmallPtrSetImpl<Block *> *barriers = nullptr);
156
157 /// Cached `canUseOpDominanceDueToBlocks`. The result depends only on the
158 /// blocks that contain the read, the write, and the definitions, not on the
159 /// ops themselves. `defBlocks` must be sorted and unique. `compute` runs
160 /// only on a cache miss. Cleared by `resetCache`.
161 bool canUseOpDominanceDueToBlocksCached(Block *readBlock, Block *writeBlock,
162 llvm::ArrayRef<Block *> defBlocks,
163 function_ref<bool()> compute);
164
165 /// Return whether `uRead` and `uConflictingWrite` are non-conflicting
166 /// subsets, with caching.
168 OpOperand *uConflictingWrite);
169
170 /// Reset cached data structures.
171 void resetCache() override;
172
173 /// Union the alias sets of `v1` and `v2`.
174 void unionAliasSets(Value v1, Value v2);
175
176 /// Union the equivalence classes of `v1` and `v2`.
178
179 /// Base class for OneShotAnalysisState extensions that allow
180 /// OneShotAnalysisState to contain user-specified information in the state
181 /// object. Clients are expected to derive this class, add the desired fields,
182 /// and make the derived class compatible with the MLIR TypeID mechanism.
183 ///
184 /// ```mlir
185 /// class MyExtension final : public OneShotAnalysisState::Extension {
186 /// public:
187 /// MyExtension(OneShotAnalysisState &state, int myData)
188 /// : Extension(state) {...}
189 /// private:
190 /// int mySupplementaryData;
191 /// };
192 /// ```
193 ///
194 /// Instances of this and derived classes are not expected to be created by
195 /// the user, instead they are directly constructed within a
196 /// OneShotAnalysisState. A OneShotAnalysisState can only contain one
197 /// extension with the given TypeID. Extensions can be obtained from a
198 /// OneShotAnalysisState instance.
199 ///
200 /// ```mlir
201 /// state.addExtension<MyExtension>(/*myData=*/42);
202 /// MyExtension *ext = state.getExtension<MyExtension>();
203 /// ext->doSomething();
204 /// ```
205 class Extension {
206 // Allow OneShotAnalysisState to allocate Extensions.
208
209 public:
210 /// Base virtual destructor.
211 // Out-of-line definition ensures symbols are emitted in a single object
212 // file.
213 virtual ~Extension();
214
215 protected:
216 /// Constructs an extension of the given state object.
217 Extension(OneShotAnalysisState &state) : state(state) {}
218
219 /// Provides read-only access to the parent OneShotAnalysisState object.
220 const OneShotAnalysisState &getAnalysisState() const { return state; }
221
222 private:
223 /// Back-reference to the state that is being extended.
225 };
226
227 /// Adds a new Extension of the type specified as template parameter,
228 /// constructing it with the arguments provided. The extension is owned by the
229 /// OneShotAnalysisState. It is expected that the state does not already have
230 /// an extension of the same type. Extension constructors are expected to take
231 /// a reference to OneShotAnalysisState as first argument, automatically
232 /// supplied by this call.
233 template <typename Ty, typename... Args>
234 Ty &addExtension(Args &&...args) {
235 static_assert(
236 std::is_base_of<Extension, Ty>::value,
237 "only a class derived from OneShotAnalysisState::Extension is allowed");
238 auto ptr = std::make_unique<Ty>(*this, std::forward<Args>(args)...);
239 auto result = extensions.try_emplace(TypeID::get<Ty>(), std::move(ptr));
240 assert(result.second && "extension already added");
241 return *static_cast<Ty *>(result.first->second.get());
242 }
243
244 /// Returns the extension of the specified type.
245 template <typename Ty>
247 static_assert(
248 std::is_base_of<Extension, Ty>::value,
249 "only a class derived from OneShotAnalysisState::Extension is allowed");
250 auto iter = extensions.find(TypeID::get<Ty>());
251 if (iter == extensions.end())
252 return nullptr;
253 return static_cast<Ty *>(iter->second.get());
254 }
255
256 /// Returns the extension of the specified type.
257 template <typename Ty>
258 const Ty *getExtension() const {
259 return const_cast<OneShotAnalysisState *>(this)->getExtension<Ty>();
260 }
261
262private:
263 using EquivalenceClassRangeType =
265 /// Check that aliasInfo for `v` exists and return a reference to it.
266 EquivalenceClassRangeType getAliases(Value v) const;
267
268 /// Cache definitions of tensor values.
269 DenseMap<Value, SetVector<Value>> cachedDefinitions;
270
271 /// True if any region has more than one block.
272 bool mayHaveUnstructuredCF = false;
273
274 /// True if the analyzed IR may contain a parallel region.
275 bool mayHaveParallelRegionsFlag = false;
276
277 /// Cached CFG reachability. Defined out-of-line to keep BitVector out of
278 /// this header.
279 class CFGReachabilityCache;
280 std::unique_ptr<CFGReachabilityCache> cfgReachabilityCache;
281
282 /// Cached block-granularity op-dominance decisions. Defined out-of-line.
283 class OpDominanceBlockCache;
284 std::unique_ptr<OpDominanceBlockCache> opDominanceBlockCache;
285
286 /// Cache results of areNonConflictingSubsets checks. The bool value is `true`
287 /// if the operands are non-conflicting subsets, `false` if they are
288 /// conflicting. The absence of an entry means uncached.
289 DenseMap<std::pair<OpOperand *, OpOperand *>, bool> nonConflictingSubsetCache;
290
291 /// Set of all OpResults that were decided to bufferize in-place.
292 llvm::DenseSet<OpOperand *> inplaceBufferized;
293
294 /// Auxiliary structure to store all the values a given value may alias with.
295 /// Alias information is "may be" conservative: In the presence of branches, a
296 /// value may alias with one of multiple other values. The concrete aliasing
297 /// value may not even be known at compile time. All such values are
298 /// considered to be aliases.
299 llvm::EquivalenceClasses<Value> aliasInfo;
300
301 /// Auxiliary structure to store all the equivalent buffer classes. Equivalent
302 /// buffer information is "must be" conservative: Only if two values are
303 /// guaranteed to be equivalent at runtime, they said to be equivalent. It is
304 /// possible that, in the presence of branches, it cannot be determined
305 /// statically if two values are equivalent. In that case, the values are
306 /// considered to be not equivalent.
307 llvm::EquivalenceClasses<Value> equivalentInfo;
308
309 // Bufferization statistics.
310 int64_t statNumTensorOutOfPlace = 0;
311 int64_t statNumTensorInPlace = 0;
312
313 /// A set of uses of tensors that have undefined contents.
314 DenseSet<OpOperand *> undefinedTensorUses;
315
316 /// Extensions attached to the state, identified by the TypeID of their type.
317 /// Only one extension of any given type is allowed.
319};
320
321/// Perform various checks on the input IR to see if it contains IR constructs
322/// that are unsupported by One-Shot Bufferize.
324 const DominanceInfo &domInfo,
325 OneShotAnalysisState &state);
326
327/// Analyze `op` and its nested ops. Bufferization decisions are stored in
328/// `state`.
329LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state,
330 BufferizationStatistics *statistics = nullptr);
331
332/// Run One-Shot Bufferize on the given op: Analysis + Bufferization
333LogicalResult
334runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options,
335 BufferizationState &state,
336 BufferizationStatistics *statistics = nullptr);
337
338} // namespace bufferization
339} // namespace mlir
340
342
343#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.
Block represents an ordered list of Operations.
Definition Block.h:34
A class for computing basic dominance information.
Definition Dominance.h:143
This class represents an operand of an operation.
Definition Value.h:254
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
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 isReachableCached(Block *from, Block *to, const llvm::SmallPtrSetImpl< Block * > *barriers=nullptr)
Return true if to is reachable from from without crossing barriers.
bool isInPlace(OpOperand &opOperand) const override
Return true if the given OpResult has been decided to bufferize inplace.
bool canUseOpDominanceDueToBlocksCached(Block *readBlock, Block *writeBlock, llvm::ArrayRef< Block * > defBlocks, function_ref< bool()> compute)
Cached canUseOpDominanceDueToBlocks.
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 mayHaveUnstructuredControlFlow() const
True if any region in the analyzed IR has more than one block.
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)
bool mayHaveParallelRegions() const
True if the analyzed IR may contain a parallel region.
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.
LogicalResult checkPreBufferizationAssumptions(Operation *op, const DominanceInfo &domInfo, OneShotAnalysisState &state)
Perform various checks on the input IR to see if it contains IR constructs that are unsupported by On...
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.
std::optional< bool > mayHaveUnstructuredControlFlow
Whether the IR contains a region with more than one block.
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.