MLIR 24.0.0git
OpenACCSupport.h
Go to the documentation of this file.
1//===- OpenACCSupport.h - OpenACC Support Interface -------------*- 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// This file defines the OpenACCSupport analysis interface, which provides
10// extensible support for OpenACC passes. Custom implementations
11// can be registered to provide pipeline and dialect-specific information
12// that cannot be adequately expressed through type or operation interfaces
13// alone.
14//
15// Usage Pattern:
16// ==============
17//
18// A pass that needs this functionality should call
19// getAnalysis<OpenACCSupport>(), which will provide either:
20// - A cached version if previously initialized, OR
21// - A default implementation if not previously initialized
22//
23// This analysis is never invalidated (isInvalidated returns false), so it only
24// needs to be initialized once and will persist throughout the pass pipeline.
25//
26// Registering a Custom Implementation:
27// =====================================
28//
29// If a custom implementation is needed, create a pass that runs BEFORE the pass
30// that needs the analysis. In this setup pass, use
31// getAnalysis<OpenACCSupport>() followed by setImplementation() to register
32// your custom implementation. The custom implementation will need to provide
33// implementation for all methods defined in the `OpenACCSupportTraits::Concept`
34// class.
35//
36// Example:
37// void MySetupPass::runOnOperation() {
38// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
39// support.setImplementation(MyCustomImpl());
40// }
41//
42// void MyAnalysisConsumerPass::runOnOperation() {
43// OpenACCSupport &support = getAnalysis<OpenACCSupport>();
44// std::string name = support.getVariableName(someValue);
45// // ... use the analysis results
46// }
47//
48//===----------------------------------------------------------------------===//
49
50#ifndef MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
51#define MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
52
57#include "mlir/IR/BuiltinOps.h"
58#include "mlir/IR/Remarks.h"
59#include "mlir/IR/Value.h"
61#include "llvm/ADT/StringRef.h"
62#include <functional>
63#include <memory>
64#include <optional>
65#include <string>
66
67namespace mlir {
68namespace acc {
69
70namespace detail {
71/// This class contains internal trait classes used by OpenACCSupport.
72/// It follows the Concept-Model pattern used throughout MLIR (e.g., in
73/// AliasAnalysis and interface definitions).
75 class Concept {
76 public:
77 virtual ~Concept() = default;
78
79 /// Get the variable name for a given MLIR value.
80 virtual std::string getVariableName(Value v) = 0;
81
82 /// Get the recipe name for a given kind, type and value.
83 virtual std::string getRecipeName(RecipeKind kind, Type type,
84 Value var) = 0;
85
86 // Used to report a case that is not supported by the implementation.
87 virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
88
89 // Used to emit an OpenACC remark. The category is optional and is used to
90 // either capture the pass name or pipeline phase when the remark is
91 // emitted. When not provided, in the default implementation, the category
92 // is "openacc".
94 emitRemark(Operation *op, std::function<std::string()> messageFn,
95 llvm::StringRef category) = 0;
96
97 /// Check if a symbol use is valid for use in an OpenACC region.
98 virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
99 Operation **definingOpPtr) = 0;
100
101 /// Check if a value use is legal in an OpenACC region.
102 virtual bool isValidValueUse(Value v, mlir::Region &region) = 0;
103
104 /// Get or optionally create a GPU module in the given module.
105 virtual std::optional<gpu::GPUModuleOp>
106 getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name) = 0;
107
108 /// Returns the size and ABI alignment in bytes for \p ty.
109 virtual std::optional<TypeSizeAndAlignment>
110 getTypeSizeAndAlignment(Type ty, ModuleOp module,
111 OpenACCSupport &support) = 0;
112 };
113
114 /// SFINAE helpers to detect if implementation has optional methods
115 template <typename ImplT, typename... Args>
117 decltype(std::declval<ImplT>().isValidSymbolUse(std::declval<Args>()...));
118
119 template <typename ImplT>
121 llvm::is_detected<isValidSymbolUse_t, ImplT, Operation *, SymbolRefAttr,
122 Operation **>;
123
124 template <typename ImplT, typename... Args>
125
127 decltype(std::declval<ImplT>().isValidValueUse(std::declval<Args>()...));
128
129 template <typename ImplT>
131 llvm::is_detected<isValidValueUse_t, ImplT, Value, Region &>;
132
133 template <typename ImplT, typename... Args>
135 decltype(std::declval<ImplT>().emitRemark(std::declval<Args>()...));
136
137 template <typename ImplT>
139 llvm::is_detected<emitRemark_t, ImplT, Operation *,
140 std::function<std::string()>, llvm::StringRef>;
141
142 template <typename ImplT, typename... Args>
144 decltype(std::declval<ImplT>().getOrCreateGPUModule(
145 std::declval<Args>()...));
146
147 template <typename ImplT>
149 llvm::is_detected<getOrCreateGPUModule_t, ImplT, ModuleOp, bool,
150 llvm::StringRef>;
151
152 template <typename ImplT, typename... Args>
154 decltype(std::declval<ImplT>().getTypeSizeAndAlignment(
155 std::declval<Args>()...));
156
157 template <typename ImplT>
159 llvm::is_detected<getTypeSizeAndAlignment_t, ImplT, Type, ModuleOp,
161
162 /// This class wraps a concrete OpenACCSupport implementation and forwards
163 /// interface calls to it. This provides type erasure, allowing different
164 /// implementation types to be used interchangeably without inheritance.
165 /// Methods can be optionally implemented; if not present, default behavior
166 /// is used.
167 template <typename ImplT>
168 class Model final : public Concept {
169 public:
170 explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
171 ~Model() override = default;
172
173 std::string getVariableName(Value v) final {
174 return impl.getVariableName(v);
175 }
176
177 std::string getRecipeName(RecipeKind kind, Type type, Value var) final {
178 return impl.getRecipeName(kind, type, var);
179 }
180
181 InFlightDiagnostic emitNYI(Location loc, const Twine &message) final {
182 return impl.emitNYI(loc, message);
183 }
184
186 emitRemark(Operation *op, std::function<std::string()> messageFn,
187 llvm::StringRef category) final {
188 if constexpr (has_emitRemark<ImplT>::value)
189 return impl.emitRemark(op, std::move(messageFn), category);
190 else
191 return acc::emitRemark(op, messageFn(), category);
192 }
193
194 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
195 Operation **definingOpPtr) final {
197 return impl.isValidSymbolUse(user, symbol, definingOpPtr);
198 else
199 return acc::isValidSymbolUse(user, symbol, definingOpPtr);
200 }
201
202 bool isValidValueUse(Value v, Region &region) final {
204 return impl.isValidValueUse(v, region);
205 else
206 return acc::isValidValueUse(v, region);
207 }
208
209 std::optional<gpu::GPUModuleOp>
210 getOrCreateGPUModule(ModuleOp mod, bool create,
211 llvm::StringRef name) final {
213 return impl.getOrCreateGPUModule(mod, create, name);
214 else
215 return acc::getOrCreateGPUModule(mod, create, name);
216 }
217
218 std::optional<TypeSizeAndAlignment>
219 getTypeSizeAndAlignment(Type ty, ModuleOp module,
220 OpenACCSupport &support) final {
222 return impl.getTypeSizeAndAlignment(ty, module, support);
223 else
224 return acc::getTypeSizeAndAlignment(ty, module, &support);
225 }
226
227 private:
228 ImplT impl;
229 };
230};
231} // namespace detail
232
233//===----------------------------------------------------------------------===//
234// OpenACCSupport
235//===----------------------------------------------------------------------===//
236
239 template <typename ImplT>
241
242public:
243 OpenACCSupport() = default;
245
246 /// Register a custom OpenACCSupport implementation. Only one implementation
247 /// can be registered at a time; calling this replaces any existing
248 /// implementation.
249 template <typename AnalysisT>
250 void setImplementation(AnalysisT &&analysis) {
251 impl =
252 std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis));
253 }
254
255 /// Get the variable name for a given value.
256 ///
257 /// \param v The MLIR value to get the variable name for.
258 /// \return The variable name, or an empty string if unavailable.
259 std::string getVariableName(Value v);
260
261 /// Get the recipe name for a given type and value.
262 ///
263 /// \param kind The kind of recipe to get the name for.
264 /// \param type The type to get the recipe name for. Can be null if the
265 /// var is provided instead.
266 /// \param var The MLIR value to get the recipe name for. Can be null if
267 /// the type is provided instead.
268 /// \return The recipe name, or an empty string if not available.
269 std::string getRecipeName(RecipeKind kind, Type type, Value var);
270
271 /// Report a case that is not yet supported by the implementation.
272 ///
273 /// \param loc The location to report the unsupported case at.
274 /// \param message The message to report.
275 /// \return An in-flight diagnostic object that can be used to report the
276 /// unsupported case.
277 InFlightDiagnostic emitNYI(Location loc, const Twine &message) {
278 if (impl)
279 return impl->emitNYI(loc, message);
280 return mlir::emitError(loc, "not yet implemented: " + message);
281 }
282
283 /// Emit an OpenACC remark with lazy message generation.
284 ///
285 /// The messageFn is only invoked if remarks are enabled for the given
286 /// operation, allowing callers to avoid constructing expensive messages
287 /// when remarks are disabled.
288 ///
289 /// \param op The operation to emit the remark for.
290 /// \param messageFn A callable that returns the remark message.
291 /// \param category Optional category for the remark. Defaults to "openacc".
292 /// \return An in-flight remark object that can be used to append
293 /// additional information to the remark.
295 emitRemark(Operation *op, std::function<std::string()> messageFn,
296 llvm::StringRef category = "openacc");
297
298 /// Emit an OpenACC remark.
299 ///
300 /// \param op The operation to emit the remark for.
301 /// \param message The remark message.
302 /// \param category Optional category for the remark. Defaults to "openacc".
303 /// \return An in-flight remark object that can be used to append
304 /// additional information to the remark.
306 emitRemark(Operation *op, const Twine &message,
307 llvm::StringRef category = "openacc") {
308 return emitRemark(op, std::function<std::string()>([msg = message.str()]() {
309 return msg;
310 }),
311 category);
312 }
313
314 /// Check if a symbol use is valid for use in an OpenACC region.
315 ///
316 /// \param user The operation using the symbol.
317 /// \param symbol The symbol reference being used.
318 /// \param definingOpPtr Optional output parameter to receive the defining op.
319 /// \return true if the symbol use is valid, false otherwise.
320 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
321 Operation **definingOpPtr = nullptr);
322
323 /// Check if a value use is legal in an OpenACC region.
324 ///
325 /// \param v The MLIR value to check for legality.
326 /// \param region The MLIR region in which the legality is checked.
327 bool isValidValueUse(Value v, Region &region);
328
329 /// Get or optionally create a GPU module in the given module.
330 ///
331 /// \param mod The module to search or create the GPU module in.
332 /// \param create If true (default), create the GPU module if it doesn't
333 /// exist.
334 /// \param name The name for the GPU module. If empty, implementation uses its
335 /// default name.
336 /// \return The GPU module if found or created, std::nullopt otherwise.
337 std::optional<gpu::GPUModuleOp>
338 getOrCreateGPUModule(ModuleOp mod, bool create = true,
339 llvm::StringRef name = "");
340
341 /// Returns the size and ABI alignment in bytes for \p ty.
342 std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(Type ty,
343 ModuleOp module) {
344 if (impl)
345 if (auto result = impl->getTypeSizeAndAlignment(ty, module, *this))
346 return result;
347 return acc::getTypeSizeAndAlignment(ty, module, this);
348 }
349
350 /// Signal that this analysis should always be preserved so that
351 /// underlying implementation registration is not lost.
353 return false;
354 }
355
356private:
357 /// The registered custom implementation (if any).
358 std::unique_ptr<Concept> impl;
359};
360
361} // namespace acc
362} // namespace mlir
363
364#endif // MLIR_DIALECT_OPENACC_ANALYSIS_OPENACCSUPPORT_H
detail::PreservedAnalyses PreservedAnalyses
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
remark::detail::InFlightRemark emitRemark(Operation *op, std::function< std::string()> messageFn, llvm::StringRef category="openacc")
Emit an OpenACC remark with lazy message generation.
remark::detail::InFlightRemark emitRemark(Operation *op, const Twine &message, llvm::StringRef category="openacc")
Emit an OpenACC remark.
void setImplementation(AnalysisT &&analysis)
Register a custom OpenACCSupport implementation.
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
bool isValidValueUse(Value v, Region &region)
Check if a value use is legal in an OpenACC region.
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol, Operation **definingOpPtr=nullptr)
Check if a symbol use is valid for use in an OpenACC region.
bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa)
Signal that this analysis should always be preserved so that underlying implementation registration i...
std::optional< gpu::GPUModuleOp > getOrCreateGPUModule(ModuleOp mod, bool create=true, llvm::StringRef name="")
Get or optionally create a GPU module in the given module.
std::string getVariableName(Value v)
Get the variable name for a given value.
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module)
Returns the size and ABI alignment in bytes for ty.
std::string getRecipeName(RecipeKind kind, Type type, Value var)
Get the recipe name for a given type and value.
virtual std::string getRecipeName(RecipeKind kind, Type type, Value var)=0
Get the recipe name for a given kind, type and value.
virtual std::string getVariableName(Value v)=0
Get the variable name for a given MLIR value.
virtual std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, OpenACCSupport &support)=0
Returns the size and ABI alignment in bytes for ty.
virtual bool isValidValueUse(Value v, mlir::Region &region)=0
Check if a value use is legal in an OpenACC region.
virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message)=0
virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol, Operation **definingOpPtr)=0
Check if a symbol use is valid for use in an OpenACC region.
virtual remark::detail::InFlightRemark emitRemark(Operation *op, std::function< std::string()> messageFn, llvm::StringRef category)=0
virtual std::optional< gpu::GPUModuleOp > getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name)=0
Get or optionally create a GPU module in the given module.
This class wraps a concrete OpenACCSupport implementation and forwards interface calls to it.
remark::detail::InFlightRemark emitRemark(Operation *op, std::function< std::string()> messageFn, llvm::StringRef category) final
bool isValidValueUse(Value v, Region &region) final
Check if a value use is legal in an OpenACC region.
std::optional< gpu::GPUModuleOp > getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name) final
Get or optionally create a GPU module in the given module.
InFlightDiagnostic emitNYI(Location loc, const Twine &message) final
std::string getRecipeName(RecipeKind kind, Type type, Value var) final
Get the recipe name for a given kind, type and value.
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol, Operation **definingOpPtr) final
Check if a symbol use is valid for use in an OpenACC region.
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, OpenACCSupport &support) final
Returns the size and ABI alignment in bytes for ty.
std::string getVariableName(Value v) final
Get the variable name for a given MLIR value.
A wrapper for linking remarks by query - searches the engine's registry at stream time and links to a...
Definition Remarks.h:402
bool isValidSymbolUse(mlir::Operation *user, mlir::SymbolRefAttr symbol, mlir::Operation **definingOpPtr=nullptr)
Check if a symbol use is valid for use in an OpenACC region.
std::optional< gpu::GPUModuleOp > getOrCreateGPUModule(ModuleOp mod, bool create=true, llvm::StringRef name=kDefaultGPUModuleName)
Get or create a GPU module in the given module.
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl, OpenACCSupport *support=nullptr)
Returns the size and ABI alignment in bytes.
bool isValidValueUse(mlir::Value val, mlir::Region &region)
Check if a value use is valid in an OpenACC region.
remark::detail::InFlightRemark emitRemark(mlir::Operation *op, const std::function< std::string()> &messageFn, llvm::StringRef category="openacc")
Emit an OpenACC remark with lazy message generation.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
This class contains internal trait classes used by OpenACCSupport.
llvm::is_detected< getOrCreateGPUModule_t, ImplT, ModuleOp, bool, llvm::StringRef > has_getOrCreateGPUModule
decltype(std::declval< ImplT >().getTypeSizeAndAlignment( std::declval< Args >()...)) getTypeSizeAndAlignment_t
llvm::is_detected< emitRemark_t, ImplT, Operation *, std::function< std::string()>, llvm::StringRef > has_emitRemark
decltype(std::declval< ImplT >().isValidValueUse(std::declval< Args >()...)) isValidValueUse_t
llvm::is_detected< isValidValueUse_t, ImplT, Value, Region & > has_isValidValueUse
llvm::is_detected< isValidSymbolUse_t, ImplT, Operation *, SymbolRefAttr, Operation ** > has_isValidSymbolUse
decltype(std::declval< ImplT >().emitRemark(std::declval< Args >()...)) emitRemark_t
decltype(std::declval< ImplT >().getOrCreateGPUModule( std::declval< Args >()...)) getOrCreateGPUModule_t
decltype(std::declval< ImplT >().isValidSymbolUse(std::declval< Args >()...)) isValidSymbolUse_t
SFINAE helpers to detect if implementation has optional methods.
llvm::is_detected< getTypeSizeAndAlignment_t, ImplT, Type, ModuleOp, OpenACCSupport & > has_getTypeSizeAndAlignment