Skip to content

Commit afd1ffb

Browse files
[mlir][acc] Check legality of symbols in acc regions (#167957)
This PR adds a new utility function to check whether symbols used in OpenACC regions are legal for offloading. Functions must be marked with `acc routine` or be built-in intrinsics. Global symbols must be marked with `acc declare`. The utility is designed to be extensible, and the OpenACCSupport analysis has been updated to allow handling of additional symbols that do not necessarily use OpenACC attributes but are marked in a way that still guarantees the symbol will be available when offloading. For example, in the Flang implementation, CUF attributes can be validated as legal symbols.
1 parent dbd97c8 commit afd1ffb

File tree

5 files changed

+342
-1
lines changed

5 files changed

+342
-1
lines changed

mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@
5858
namespace mlir {
5959
namespace acc {
6060

61-
// Forward declaration for RecipeKind enum
61+
// Forward declarations
6262
enum class RecipeKind : uint32_t;
63+
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
64+
Operation **definingOpPtr);
6365

6466
namespace detail {
6567
/// This class contains internal trait classes used by OpenACCSupport.
@@ -79,11 +81,27 @@ struct OpenACCSupportTraits {
7981

8082
// Used to report a case that is not supported by the implementation.
8183
virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
84+
85+
/// Check if a symbol use is valid for use in an OpenACC region.
86+
virtual bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
87+
Operation **definingOpPtr) = 0;
8288
};
8389

90+
/// SFINAE helpers to detect if implementation has optional methods
91+
template <typename ImplT, typename... Args>
92+
using isValidSymbolUse_t =
93+
decltype(std::declval<ImplT>().isValidSymbolUse(std::declval<Args>()...));
94+
95+
template <typename ImplT>
96+
using has_isValidSymbolUse =
97+
llvm::is_detected<isValidSymbolUse_t, ImplT, Operation *, SymbolRefAttr,
98+
Operation **>;
99+
84100
/// This class wraps a concrete OpenACCSupport implementation and forwards
85101
/// interface calls to it. This provides type erasure, allowing different
86102
/// implementation types to be used interchangeably without inheritance.
103+
/// Methods can be optionally implemented; if not present, default behavior
104+
/// is used.
87105
template <typename ImplT>
88106
class Model final : public Concept {
89107
public:
@@ -102,6 +120,14 @@ struct OpenACCSupportTraits {
102120
return impl.emitNYI(loc, message);
103121
}
104122

123+
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
124+
Operation **definingOpPtr) final {
125+
if constexpr (has_isValidSymbolUse<ImplT>::value)
126+
return impl.isValidSymbolUse(user, symbol, definingOpPtr);
127+
else
128+
return acc::isValidSymbolUse(user, symbol, definingOpPtr);
129+
}
130+
105131
private:
106132
ImplT impl;
107133
};
@@ -154,6 +180,15 @@ class OpenACCSupport {
154180
/// unsupported case.
155181
InFlightDiagnostic emitNYI(Location loc, const Twine &message);
156182

183+
/// Check if a symbol use is valid for use in an OpenACC region.
184+
///
185+
/// \param user The operation using the symbol.
186+
/// \param symbol The symbol reference being used.
187+
/// \param definingOpPtr Optional output parameter to receive the defining op.
188+
/// \return true if the symbol use is valid, false otherwise.
189+
bool isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
190+
Operation **definingOpPtr = nullptr);
191+
157192
/// Signal that this analysis should always be preserved so that
158193
/// underlying implementation registration is not lost.
159194
bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {

mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type);
5252
// base `array` from an operation that only accesses a subarray.
5353
mlir::Value getBaseEntity(mlir::Value val);
5454

55+
/// Check if a symbol use is valid for use in an OpenACC region.
56+
/// This includes looking for various attributes such as `acc.routine_info`
57+
/// and `acc.declare` attributes.
58+
/// \param user The operation using the symbol
59+
/// \param symbol The symbol reference being used
60+
/// \param definingOpPtr Optional output parameter to receive the defining op
61+
/// \return true if the symbol use is valid, false otherwise
62+
bool isValidSymbolUse(mlir::Operation *user, mlir::SymbolRefAttr symbol,
63+
mlir::Operation **definingOpPtr = nullptr);
64+
5565
} // namespace acc
5666
} // namespace mlir
5767

mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,12 @@ InFlightDiagnostic OpenACCSupport::emitNYI(Location loc, const Twine &message) {
4141
return mlir::emitError(loc, "not yet implemented: " + message);
4242
}
4343

44+
bool OpenACCSupport::isValidSymbolUse(Operation *user, SymbolRefAttr symbol,
45+
Operation **definingOpPtr) {
46+
if (impl)
47+
return impl->isValidSymbolUse(user, symbol, definingOpPtr);
48+
return acc::isValidSymbolUse(user, symbol, definingOpPtr);
49+
}
50+
4451
} // namespace acc
4552
} // namespace mlir

mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
1010

1111
#include "mlir/Dialect/OpenACC/OpenACC.h"
12+
#include "mlir/IR/SymbolTable.h"
13+
#include "mlir/Interfaces/FunctionInterfaces.h"
1214
#include "mlir/Interfaces/ViewLikeInterface.h"
1315
#include "llvm/ADT/TypeSwitch.h"
16+
#include "llvm/IR/Intrinsics.h"
1417
#include "llvm/Support/Casting.h"
1518

1619
mlir::Operation *mlir::acc::getEnclosingComputeOp(mlir::Region &region) {
@@ -155,3 +158,50 @@ mlir::Value mlir::acc::getBaseEntity(mlir::Value val) {
155158

156159
return val;
157160
}
161+
162+
bool mlir::acc::isValidSymbolUse(mlir::Operation *user,
163+
mlir::SymbolRefAttr symbol,
164+
mlir::Operation **definingOpPtr) {
165+
mlir::Operation *definingOp =
166+
mlir::SymbolTable::lookupNearestSymbolFrom(user, symbol);
167+
168+
// If there are no defining ops, we have no way to ensure validity because
169+
// we cannot check for any attributes.
170+
if (!definingOp)
171+
return false;
172+
173+
if (definingOpPtr)
174+
*definingOpPtr = definingOp;
175+
176+
// Check if the defining op is a recipe (private, reduction, firstprivate).
177+
// Recipes are valid as they get materialized before being offloaded to
178+
// device. They are only instructions for how to materialize.
179+
if (mlir::isa<mlir::acc::PrivateRecipeOp, mlir::acc::ReductionRecipeOp,
180+
mlir::acc::FirstprivateRecipeOp>(definingOp))
181+
return true;
182+
183+
// Check if the defining op is a function
184+
if (auto func =
185+
mlir::dyn_cast_if_present<mlir::FunctionOpInterface>(definingOp)) {
186+
// If this symbol is actually an acc routine - then it is expected for it
187+
// to be offloaded - therefore it is valid.
188+
if (func->hasAttr(mlir::acc::getRoutineInfoAttrName()))
189+
return true;
190+
191+
// If this symbol is a call to an LLVM intrinsic, then it is likely valid.
192+
// Check the following:
193+
// 1. The function is private
194+
// 2. The function has no body
195+
// 3. Name starts with "llvm."
196+
// 4. The function's name is a valid LLVM intrinsic name
197+
if (func.getVisibility() == mlir::SymbolTable::Visibility::Private &&
198+
func.getFunctionBody().empty() && func.getName().starts_with("llvm.") &&
199+
llvm::Intrinsic::lookupIntrinsicID(func.getName()) !=
200+
llvm::Intrinsic::not_intrinsic)
201+
return true;
202+
}
203+
204+
// A declare attribute is needed for symbol references.
205+
bool hasDeclare = definingOp->hasAttr(mlir::acc::getDeclareAttrName());
206+
return hasDeclare;
207+
}

0 commit comments

Comments
 (0)