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
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
279 /// Emit an OpenACC remark with lazy message generation.
280 ///
281 /// The messageFn is only invoked if remarks are enabled for the given
282 /// operation, allowing callers to avoid constructing expensive messages
283 /// when remarks are disabled.
284 ///
285 /// \param op The operation to emit the remark for.
286 /// \param messageFn A callable that returns the remark message.
287 /// \param category Optional category for the remark. Defaults to "openacc".
288 /// \return An in-flight remark object that can be used to append
289 /// additional information to the remark.
291 emitRemark(Operation *op, std::function<std::string()> messageFn,
292 llvm::StringRef category = "openacc");
293
294 /// Emit an OpenACC remark.
295 ///
296 /// \param op The operation to emit the remark for.
297 /// \param message The remark message.
298 /// \param category Optional category for the remark. Defaults to "openacc".
299 /// \return An in-flight remark object that can be used to append
300 /// additional information to the remark.
302 emitRemark(Operation *op, const Twine &message,
303 llvm::StringRef category = "openacc") {
304 return emitRemark(op, std::function<std::string()>([msg = message.str()]() {
305 return msg;
306 }),
307 category);
308 }
309
310 /// Check if a symbol use is valid for use in an OpenACC region.
311 ///
312 /// \param user The operation using the symbol.
313 /// \param symbol The symbol reference being used.
314 /// \param definingOpPtr Optional output parameter to receive the defining op.
315 /// \return true if the symbol use is valid, false otherwise.
316 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
317 Operation **definingOpPtr = nullptr);
318
319 /// Check if a value use is legal in an OpenACC region.
320 ///
321 /// \param v The MLIR value to check for legality.
322 /// \param region The MLIR region in which the legality is checked.
323 bool isValidValueUse(Value v, Region &region);
324
325 /// Get or optionally create a GPU module in the given module.
326 ///
327 /// \param mod The module to search or create the GPU module in.
328 /// \param create If true (default), create the GPU module if it doesn't
329 /// exist.
330 /// \param name The name for the GPU module. If empty, implementation uses its
331 /// default name.
332 /// \return The GPU module if found or created, std::nullopt otherwise.
333 std::optional<gpu::GPUModuleOp>
334 getOrCreateGPUModule(ModuleOp mod, bool create = true,
335 llvm::StringRef name = "");
336
337 /// Returns the size and ABI alignment in bytes for \p ty.
338 std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(Type ty,
339 ModuleOp module) {
340 if (impl)
341 if (auto result = impl->getTypeSizeAndAlignment(ty, module, *this))
342 return result;
343 return acc::getTypeSizeAndAlignment(ty, module, this);
344 }
345
346 /// Signal that this analysis should always be preserved so that
347 /// underlying implementation registration is not lost.
349 return false;
350 }
351
352private:
353 /// The registered custom implementation (if any).
354 std::unique_ptr<Concept> impl;
355};
356
357} // namespace acc
358} // namespace mlir
359
360#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.
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