MLIR 23.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
56#include "mlir/IR/Remarks.h"
57#include "mlir/IR/Value.h"
59#include "llvm/ADT/StringRef.h"
60#include <functional>
61#include <memory>
62#include <string>
63
64namespace mlir {
65namespace acc {
66
67namespace detail {
68/// This class contains internal trait classes used by OpenACCSupport.
69/// It follows the Concept-Model pattern used throughout MLIR (e.g., in
70/// AliasAnalysis and interface definitions).
72 class Concept {
73 public:
74 virtual ~Concept() = default;
75
76 /// Get the variable name for a given MLIR value.
77 virtual std::string getVariableName(Value v) = 0;
78
79 /// Get the recipe name for a given kind, type and value.
80 virtual std::string getRecipeName(RecipeKind kind, Type type,
81 Value var) = 0;
82
83 // Used to report a case that is not supported by the implementation.
84 virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
85
86 // Used to emit an OpenACC remark. The category is optional and is used to
87 // either capture the pass name or pipeline phase when the remark is
88 // emitted. When not provided, in the default implementation, the category
89 // is "openacc".
91 emitRemark(Operation *op, std::function<std::string()> messageFn,
92 llvm::StringRef category) = 0;
93
94 /// Check if a symbol use is valid for use in an OpenACC region.
95 virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
96 Operation **definingOpPtr) = 0;
97
98 /// Check if a value use is legal in an OpenACC region.
99 virtual bool isValidValueUse(Value v, mlir::Region &region) = 0;
100
101 /// Get or optionally create a GPU module in the given module.
102 virtual std::optional<gpu::GPUModuleOp>
103 getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name) = 0;
104 };
105
106 /// SFINAE helpers to detect if implementation has optional methods
107 template <typename ImplT, typename... Args>
109 decltype(std::declval<ImplT>().isValidSymbolUse(std::declval<Args>()...));
110
111 template <typename ImplT>
113 llvm::is_detected<isValidSymbolUse_t, ImplT, Operation *, SymbolRefAttr,
114 Operation **>;
115
116 template <typename ImplT, typename... Args>
117
119 decltype(std::declval<ImplT>().isValidValueUse(std::declval<Args>()...));
120
121 template <typename ImplT>
123 llvm::is_detected<isValidValueUse_t, ImplT, Value, Region &>;
124
125 template <typename ImplT, typename... Args>
127 decltype(std::declval<ImplT>().emitRemark(std::declval<Args>()...));
128
129 template <typename ImplT>
131 llvm::is_detected<emitRemark_t, ImplT, Operation *,
132 std::function<std::string()>, llvm::StringRef>;
133
134 template <typename ImplT, typename... Args>
136 decltype(std::declval<ImplT>().getOrCreateGPUModule(
137 std::declval<Args>()...));
138
139 template <typename ImplT>
141 llvm::is_detected<getOrCreateGPUModule_t, ImplT, ModuleOp, bool,
142 llvm::StringRef>;
143
144 /// This class wraps a concrete OpenACCSupport implementation and forwards
145 /// interface calls to it. This provides type erasure, allowing different
146 /// implementation types to be used interchangeably without inheritance.
147 /// Methods can be optionally implemented; if not present, default behavior
148 /// is used.
149 template <typename ImplT>
150 class Model final : public Concept {
151 public:
152 explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
153 ~Model() override = default;
154
155 std::string getVariableName(Value v) final {
156 return impl.getVariableName(v);
157 }
158
159 std::string getRecipeName(RecipeKind kind, Type type, Value var) final {
160 return impl.getRecipeName(kind, type, var);
161 }
162
163 InFlightDiagnostic emitNYI(Location loc, const Twine &message) final {
164 return impl.emitNYI(loc, message);
165 }
166
168 emitRemark(Operation *op, std::function<std::string()> messageFn,
169 llvm::StringRef category) final {
170 if constexpr (has_emitRemark<ImplT>::value)
171 return impl.emitRemark(op, std::move(messageFn), category);
172 else
173 return acc::emitRemark(op, messageFn(), category);
174 }
175
176 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
177 Operation **definingOpPtr) final {
179 return impl.isValidSymbolUse(user, symbol, definingOpPtr);
180 else
181 return acc::isValidSymbolUse(user, symbol, definingOpPtr);
182 }
183
184 bool isValidValueUse(Value v, Region &region) final {
186 return impl.isValidValueUse(v, region);
187 else
188 return acc::isValidValueUse(v, region);
189 }
190
191 std::optional<gpu::GPUModuleOp>
192 getOrCreateGPUModule(ModuleOp mod, bool create,
193 llvm::StringRef name) final {
195 return impl.getOrCreateGPUModule(mod, create, name);
196 else
197 return acc::getOrCreateGPUModule(mod, create, name);
198 }
199
200 private:
201 ImplT impl;
202 };
203};
204} // namespace detail
205
206//===----------------------------------------------------------------------===//
207// OpenACCSupport
208//===----------------------------------------------------------------------===//
209
212 template <typename ImplT>
214
215public:
216 OpenACCSupport() = default;
218
219 /// Register a custom OpenACCSupport implementation. Only one implementation
220 /// can be registered at a time; calling this replaces any existing
221 /// implementation.
222 template <typename AnalysisT>
223 void setImplementation(AnalysisT &&analysis) {
224 impl =
225 std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis));
226 }
227
228 /// Get the variable name for a given value.
229 ///
230 /// \param v The MLIR value to get the variable name for.
231 /// \return The variable name, or an empty string if unavailable.
232 std::string getVariableName(Value v);
233
234 /// Get the recipe name for a given type and value.
235 ///
236 /// \param kind The kind of recipe to get the name for.
237 /// \param type The type to get the recipe name for. Can be null if the
238 /// var is provided instead.
239 /// \param var The MLIR value to get the recipe name for. Can be null if
240 /// the type is provided instead.
241 /// \return The recipe name, or an empty string if not available.
242 std::string getRecipeName(RecipeKind kind, Type type, Value var);
243
244 /// Report a case that is not yet supported by the implementation.
245 ///
246 /// \param loc The location to report the unsupported case at.
247 /// \param message The message to report.
248 /// \return An in-flight diagnostic object that can be used to report the
249 /// unsupported case.
250 InFlightDiagnostic emitNYI(Location loc, const Twine &message);
251
252 /// Emit an OpenACC remark with lazy message generation.
253 ///
254 /// The messageFn is only invoked if remarks are enabled for the given
255 /// operation, allowing callers to avoid constructing expensive messages
256 /// when remarks are disabled.
257 ///
258 /// \param op The operation to emit the remark for.
259 /// \param messageFn A callable that returns the remark message.
260 /// \param category Optional category for the remark. Defaults to "openacc".
261 /// \return An in-flight remark object that can be used to append
262 /// additional information to the remark.
264 emitRemark(Operation *op, std::function<std::string()> messageFn,
265 llvm::StringRef category = "openacc");
266
267 /// Emit an OpenACC remark.
268 ///
269 /// \param op The operation to emit the remark for.
270 /// \param message The remark message.
271 /// \param category Optional category for the remark. Defaults to "openacc".
272 /// \return An in-flight remark object that can be used to append
273 /// additional information to the remark.
275 emitRemark(Operation *op, const Twine &message,
276 llvm::StringRef category = "openacc") {
277 return emitRemark(op, std::function<std::string()>([msg = message.str()]() {
278 return msg;
279 }),
280 category);
281 }
282
283 /// Check if a symbol use is valid for use in an OpenACC region.
284 ///
285 /// \param user The operation using the symbol.
286 /// \param symbol The symbol reference being used.
287 /// \param definingOpPtr Optional output parameter to receive the defining op.
288 /// \return true if the symbol use is valid, false otherwise.
289 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
290 Operation **definingOpPtr = nullptr);
291
292 /// Check if a value use is legal in an OpenACC region.
293 ///
294 /// \param v The MLIR value to check for legality.
295 /// \param region The MLIR region in which the legality is checked.
296 bool isValidValueUse(Value v, Region &region);
297
298 /// Get or optionally create a GPU module in the given module.
299 ///
300 /// \param mod The module to search or create the GPU module in.
301 /// \param create If true (default), create the GPU module if it doesn't
302 /// exist.
303 /// \param name The name for the GPU module. If empty, implementation uses its
304 /// default name.
305 /// \return The GPU module if found or created, std::nullopt otherwise.
306 std::optional<gpu::GPUModuleOp>
307 getOrCreateGPUModule(ModuleOp mod, bool create = true,
308 llvm::StringRef name = "");
309
310 /// Signal that this analysis should always be preserved so that
311 /// underlying implementation registration is not lost.
313 return false;
314 }
315
316private:
317 /// The registered custom implementation (if any).
318 std::unique_ptr<Concept> impl;
319};
320
321} // namespace acc
322} // namespace mlir
323
324#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:88
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::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 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::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.
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.
This class contains internal trait classes used by OpenACCSupport.
llvm::is_detected< getOrCreateGPUModule_t, ImplT, ModuleOp, bool, llvm::StringRef > has_getOrCreateGPUModule
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.