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
70/// How the name of a variable is to be rendered.
72 /// Render the name the source language spells, which is the name a message
73 /// to the user states. When false, the name the variable is emitted under is
74 /// rendered instead - for a global the symbol it is addressed through -
75 /// which is the name it is resolved against the symbols of a binary by. Only
76 /// a language that uniques or mangles the names of its variables spells the
77 /// two differently.
79};
80
81namespace detail {
82/// This class contains internal trait classes used by OpenACCSupport.
83/// It follows the Concept-Model pattern used throughout MLIR (e.g., in
84/// AliasAnalysis and interface definitions).
86 class Concept {
87 public:
88 virtual ~Concept() = default;
89
90 /// Get the variable name for a given MLIR value.
91 virtual std::string getVariableName(Value v, VariableNameConfig config) = 0;
92
93 /// Get the recipe name for a given kind, type and value.
94 virtual std::string getRecipeName(RecipeKind kind, Type type,
95 Value var) = 0;
96
97 // Used to report a case that is not supported by the implementation.
98 virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
99
100 // Used to emit an OpenACC remark. The category is optional and is used to
101 // either capture the pass name or pipeline phase when the remark is
102 // emitted. When not provided, in the default implementation, the category
103 // is "openacc".
105 emitRemark(Operation *op, std::function<std::string()> messageFn,
106 llvm::StringRef category) = 0;
107
108 /// Check if a symbol use is valid for use in an OpenACC region.
109 virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
110 Operation **definingOpPtr) = 0;
111
112 /// Check if a value use is legal in an OpenACC region.
113 virtual bool isValidValueUse(Value v, mlir::Region &region) = 0;
114
115 /// Get or optionally create a GPU module in the given module.
116 virtual std::optional<gpu::GPUModuleOp>
117 getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name) = 0;
118
119 /// Returns the size and ABI alignment in bytes for \p ty.
120 virtual std::optional<TypeSizeAndAlignment>
121 getTypeSizeAndAlignment(Type ty, ModuleOp module,
122 OpenACCSupport &support) = 0;
123 };
124
125 /// SFINAE helpers to detect if implementation has optional methods
126 template <typename ImplT, typename... Args>
128 decltype(std::declval<ImplT>().isValidSymbolUse(std::declval<Args>()...));
129
130 template <typename ImplT>
132 llvm::is_detected<isValidSymbolUse_t, ImplT, Operation *, SymbolRefAttr,
133 Operation **>;
134
135 template <typename ImplT, typename... Args>
136
138 decltype(std::declval<ImplT>().isValidValueUse(std::declval<Args>()...));
139
140 template <typename ImplT>
142 llvm::is_detected<isValidValueUse_t, ImplT, Value, Region &>;
143
144 template <typename ImplT, typename... Args>
146 decltype(std::declval<ImplT>().emitRemark(std::declval<Args>()...));
147
148 template <typename ImplT>
150 llvm::is_detected<emitRemark_t, ImplT, Operation *,
151 std::function<std::string()>, llvm::StringRef>;
152
153 template <typename ImplT, typename... Args>
155 decltype(std::declval<ImplT>().getOrCreateGPUModule(
156 std::declval<Args>()...));
157
158 template <typename ImplT>
160 llvm::is_detected<getOrCreateGPUModule_t, ImplT, ModuleOp, bool,
161 llvm::StringRef>;
162
163 template <typename ImplT, typename... Args>
165 decltype(std::declval<ImplT>().getTypeSizeAndAlignment(
166 std::declval<Args>()...));
167
168 template <typename ImplT>
170 llvm::is_detected<getTypeSizeAndAlignment_t, ImplT, Type, ModuleOp,
172
173 /// This class wraps a concrete OpenACCSupport implementation and forwards
174 /// interface calls to it. This provides type erasure, allowing different
175 /// implementation types to be used interchangeably without inheritance.
176 /// Methods can be optionally implemented; if not present, default behavior
177 /// is used.
178 template <typename ImplT>
179 class Model final : public Concept {
180 public:
181 explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
182 ~Model() override = default;
183
184 std::string getVariableName(Value v, VariableNameConfig config) final {
185 return impl.getVariableName(v, config);
186 }
187
188 std::string getRecipeName(RecipeKind kind, Type type, Value var) final {
189 return impl.getRecipeName(kind, type, var);
190 }
191
192 InFlightDiagnostic emitNYI(Location loc, const Twine &message) final {
193 return impl.emitNYI(loc, message);
194 }
195
197 emitRemark(Operation *op, std::function<std::string()> messageFn,
198 llvm::StringRef category) final {
199 if constexpr (has_emitRemark<ImplT>::value)
200 return impl.emitRemark(op, std::move(messageFn), category);
201 else
202 return acc::emitRemark(op, messageFn(), category);
203 }
204
205 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
206 Operation **definingOpPtr) final {
208 return impl.isValidSymbolUse(user, symbol, definingOpPtr);
209 else
210 return acc::isValidSymbolUse(user, symbol, definingOpPtr);
211 }
212
213 bool isValidValueUse(Value v, Region &region) final {
215 return impl.isValidValueUse(v, region);
216 else
217 return acc::isValidValueUse(v, region);
218 }
219
220 std::optional<gpu::GPUModuleOp>
221 getOrCreateGPUModule(ModuleOp mod, bool create,
222 llvm::StringRef name) final {
224 return impl.getOrCreateGPUModule(mod, create, name);
225 else
226 return acc::getOrCreateGPUModule(mod, create, name);
227 }
228
229 std::optional<TypeSizeAndAlignment>
230 getTypeSizeAndAlignment(Type ty, ModuleOp module,
231 OpenACCSupport &support) final {
233 return impl.getTypeSizeAndAlignment(ty, module, support);
234 else
235 return acc::getTypeSizeAndAlignment(ty, module, &support);
236 }
237
238 private:
239 ImplT impl;
240 };
241};
242} // namespace detail
243
244//===----------------------------------------------------------------------===//
245// OpenACCSupport
246//===----------------------------------------------------------------------===//
247
250 template <typename ImplT>
252
253public:
254 OpenACCSupport() = default;
256
257 /// Register a custom OpenACCSupport implementation. Only one implementation
258 /// can be registered at a time; calling this replaces any existing
259 /// implementation.
260 template <typename AnalysisT>
261 void setImplementation(AnalysisT &&analysis) {
262 impl =
263 std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis));
264 }
265
266 /// Get the variable name for a given value. Which of the names a variable
267 /// goes by is a question only an implementation that knows the source
268 /// language can answer, so the default implementation returns the one name
269 /// the IR states regardless of \p config.
270 ///
271 /// \param v The MLIR value to get the variable name for.
272 /// \param config Which of the names of the variable to return.
273 /// \return The variable name, or an empty string if unavailable.
274 std::string getVariableName(Value v, VariableNameConfig config = {});
275
276 /// Get the recipe name for a given type and value.
277 ///
278 /// \param kind The kind of recipe to get the name for.
279 /// \param type The type to get the recipe name for. Can be null if the
280 /// var is provided instead.
281 /// \param var The MLIR value to get the recipe name for. Can be null if
282 /// the type is provided instead.
283 /// \return The recipe name, or an empty string if not available.
284 std::string getRecipeName(RecipeKind kind, Type type, Value var);
285
286 /// Report a case that is not yet supported by the implementation.
287 ///
288 /// \param loc The location to report the unsupported case at.
289 /// \param message The message to report.
290 /// \return An in-flight diagnostic object that can be used to report the
291 /// unsupported case.
292 InFlightDiagnostic emitNYI(Location loc, const Twine &message) {
293 if (impl)
294 return impl->emitNYI(loc, message);
295 return mlir::emitError(loc, "not yet implemented: " + message);
296 }
297
298 /// Emit an OpenACC remark with lazy message generation.
299 ///
300 /// The messageFn is only invoked if remarks are enabled for the given
301 /// operation, allowing callers to avoid constructing expensive messages
302 /// when remarks are disabled.
303 ///
304 /// \param op The operation to emit the remark for.
305 /// \param messageFn A callable that returns the remark message.
306 /// \param category Optional category for the remark. Defaults to "openacc".
307 /// \return An in-flight remark object that can be used to append
308 /// additional information to the remark.
310 emitRemark(Operation *op, std::function<std::string()> messageFn,
311 llvm::StringRef category = "openacc");
312
313 /// Emit an OpenACC remark.
314 ///
315 /// \param op The operation to emit the remark for.
316 /// \param message The remark message.
317 /// \param category Optional category for the remark. Defaults to "openacc".
318 /// \return An in-flight remark object that can be used to append
319 /// additional information to the remark.
321 emitRemark(Operation *op, const Twine &message,
322 llvm::StringRef category = "openacc") {
323 return emitRemark(op, std::function<std::string()>([msg = message.str()]() {
324 return msg;
325 }),
326 category);
327 }
328
329 /// Check if a symbol use is valid for use in an OpenACC region.
330 ///
331 /// \param user The operation using the symbol.
332 /// \param symbol The symbol reference being used.
333 /// \param definingOpPtr Optional output parameter to receive the defining op.
334 /// \return true if the symbol use is valid, false otherwise.
335 bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
336 Operation **definingOpPtr = nullptr);
337
338 /// Check if a value use is legal in an OpenACC region.
339 ///
340 /// \param v The MLIR value to check for legality.
341 /// \param region The MLIR region in which the legality is checked.
342 bool isValidValueUse(Value v, Region &region);
343
344 /// Get or optionally create a GPU module in the given module.
345 ///
346 /// \param mod The module to search or create the GPU module in.
347 /// \param create If true (default), create the GPU module if it doesn't
348 /// exist.
349 /// \param name The name for the GPU module. If empty, implementation uses its
350 /// default name.
351 /// \return The GPU module if found or created, std::nullopt otherwise.
352 std::optional<gpu::GPUModuleOp>
353 getOrCreateGPUModule(ModuleOp mod, bool create = true,
354 llvm::StringRef name = "");
355
356 /// Returns the size and ABI alignment in bytes for \p ty.
357 std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(Type ty,
358 ModuleOp module) {
359 if (impl)
360 if (auto result = impl->getTypeSizeAndAlignment(ty, module, *this))
361 return result;
362 return acc::getTypeSizeAndAlignment(ty, module, this);
363 }
364
365 /// Signal that this analysis should always be preserved so that
366 /// underlying implementation registration is not lost.
368 return false;
369 }
370
371private:
372 /// The registered custom implementation (if any).
373 std::unique_ptr<Concept> impl;
374};
375
376} // namespace acc
377} // namespace mlir
378
379#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.
std::string getVariableName(Value v, VariableNameConfig config={})
Get the variable name for a given value.
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::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::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, OpenACCSupport &support)=0
Returns the size and ABI alignment in bytes for ty.
virtual std::string getVariableName(Value v, VariableNameConfig config)=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.
std::string getVariableName(Value v, VariableNameConfig config) final
Get the variable name for a given MLIR value.
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.
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.
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl, OpenACCSupport *support=nullptr, Value var={})
Returns the size and ABI alignment in bytes.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
How the name of a variable is to be rendered.
bool preferDemangledName
Render the name the source language spells, which is the name a message to the user states.
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