17#include "llvm/ADT/SetVector.h"
18#include "llvm/ADT/TypeSwitch.h"
19#include "llvm/IR/Intrinsics.h"
20#include "llvm/Support/Casting.h"
25 if (mlir::isa<ACC_COMPUTE_CONSTRUCT_OPS>(parentOp))
32template <
typename OpTy>
37 if (!region.
isAncestor(user->getParentRegion()))
39 return mlir::isa<OpTy>(user);
42 return llvm::all_of(val.
getUsers(), checkIfUsedOnlyByOpInside);
55std::optional<mlir::acc::ClauseDefaultValue>
57 std::optional<mlir::acc::ClauseDefaultValue> defaultAttr;
64 while (!defaultAttr.has_value() && currOp) {
67 std::optional<mlir::acc::ClauseDefaultValue>>(currOp)
68 .Case<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::DataOp>(
69 [&](
auto op) {
return op.getDefaultAttr(); })
70 .Default([&](
Operation *) {
return std::nullopt; });
78 mlir::acc::VariableTypeCategory typeCategory =
79 mlir::acc::VariableTypeCategory::uncategorized;
80 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(var.
getType()))
81 typeCategory = mappableTy.getTypeCategory(var);
82 else if (
auto pointerLikeTy =
83 dyn_cast<mlir::acc::PointerLikeType>(var.
getType()))
84 typeCategory = pointerLikeTy.getPointeeTypeCategory(
86 pointerLikeTy.getElementType());
96 if (
auto varNameAttr =
98 return varNameAttr.getName().str();
101 if (isa<ACC_DATA_ENTRY_OPS>(definingOp))
106 if (
auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
107 current = viewOp.getViewSource();
119 assert(kind == mlir::acc::RecipeKind::private_recipe ||
120 kind == mlir::acc::RecipeKind::firstprivate_recipe ||
121 kind == mlir::acc::RecipeKind::reduction_recipe);
122 if (!llvm::isa<mlir::acc::PointerLikeType, mlir::acc::MappableType>(type))
125 std::string recipeName;
126 llvm::raw_string_ostream ss(recipeName);
127 ss << (kind == mlir::acc::RecipeKind::private_recipe ?
"privatization_"
128 : kind == mlir::acc::RecipeKind::firstprivate_recipe
129 ?
"firstprivatization_"
138 for (
char &c : recipeName) {
139 if (!std::isalnum(
static_cast<unsigned char>(c)) && c !=
'.' && c !=
'_') {
144 else if (c ==
'(' || c ==
')' || c ==
'[' || c ==
']' || c ==
'{' ||
145 c ==
'}' || c ==
'<' || c ==
'>')
156 if (
auto partialEntityAccessOp =
158 if (!partialEntityAccessOp.isCompleteView())
159 return partialEntityAccessOp.getBaseEntity();
166 mlir::SymbolRefAttr symbol,
177 *definingOpPtr = definingOp;
182 if (mlir::isa<mlir::acc::PrivateRecipeOp, mlir::acc::ReductionRecipeOp,
183 mlir::acc::FirstprivateRecipeOp>(definingOp))
189 mlir::dyn_cast<mlir::acc::GlobalVariableOpInterface>(definingOp))
190 if (globalVar.isDeviceData())
195 mlir::dyn_cast_if_present<mlir::FunctionOpInterface>(definingOp)) {
208 func.getFunctionBody().empty() &&
func.getName().starts_with(
"llvm.") &&
209 llvm::Intrinsic::lookupIntrinsicID(
func.getName()) !=
210 llvm::Intrinsic::not_intrinsic)
222 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(val.
getType()))
223 if (mappableTy.isDeviceData(val))
226 if (
auto pointerLikeTy = dyn_cast<mlir::acc::PointerLikeType>(val.
getType()))
227 if (pointerLikeTy.isDeviceData(val))
233 if (
auto partialAccess =
234 dyn_cast<mlir::acc::PartialEntityAccessOpInterface>(defOp)) {
235 if (
mlir::Value base = partialAccess.getBaseEntity())
240 if (
auto addrOfIface =
241 dyn_cast<mlir::acc::AddressOfGlobalOpInterface>(defOp)) {
242 auto symbol = addrOfIface.getSymbol();
244 mlir::acc::GlobalVariableOpInterface>(defOp, symbol))
245 return global.isDeviceData();
256 llvm::isa<mlir::VectorType>(type))
260 if (isa_and_nonnull<ACC_DATA_ENTRY_OPS>(val.
getDefiningOp()))
278 llvm::SmallSetVector<mlir::Value, 8> dominatingDataClauses;
281 .Case<mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp>(
283 for (
auto dataClause : op.getDataClauseOperands()) {
284 dominatingDataClauses.insert(dataClause);
291 while (currParentOp) {
292 if (mlir::isa<mlir::acc::DataOp>(currParentOp)) {
293 for (
auto dataClause : mlir::dyn_cast<mlir::acc::DataOp>(currParentOp)
294 .getDataClauseOperands()) {
295 dominatingDataClauses.insert(dataClause);
298 currParentOp = currParentOp->getParentOp();
305 return dominatingDataClauses.takeVector();
310 funcOp->walk([&](mlir::acc::DeclareEnterOp declareEnterOp) {
311 if (domInfo.
dominates(declareEnterOp.getOperation(), computeConstructOp)) {
314 for (
auto *user : declareEnterOp.getToken().getUsers())
315 if (
auto declareExit = mlir::dyn_cast<mlir::acc::DeclareExitOp>(user))
316 exits.push_back(declareExit);
320 if (!exits.empty() &&
321 llvm::all_of(exits, [&](mlir::acc::DeclareExitOp exitOp) {
322 return postDomInfo.postDominates(exitOp, computeConstructOp);
324 for (
auto dataClause : declareEnterOp.getDataClauseOperands())
325 dominatingDataClauses.insert(dataClause);
330 return dominatingDataClauses.takeVector();
335 llvm::StringRef category) {
342 llvm::StringRef funcName;
343 if (
auto func = dyn_cast<mlir::FunctionOpInterface>(op))
344 funcName =
func.getName();
345 else if (
auto funcOp = op->
getParentOfType<mlir::FunctionOpInterface>())
346 funcName = funcOp.getName();
349 if (!funcName.empty())
350 opts = opts.function(funcName);
352 auto remark = engine->emitOptimizationRemark(loc, opts);
static bool isOnlyUsedByOpClauses(mlir::Value val, mlir::Region ®ion)
MLIRContext * getContext() const
Return the context this attribute belongs to.
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
remark::detail::RemarkEngine * getRemarkEngine()
Returns the remark engine for this context, or nullptr if none has been set.
Operation is the basic unit of execution within MLIR.
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
A class for computing basic postdominance information.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
Operation * getParentOp()
Return the parent operation this region is attached to.
@ Private
The symbol is private and may only be referenced by SymbolRefAttrs local to the operations within the...
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
void print(raw_ostream &os) const
Print the current type.
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
user_range getUsers() const
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Value var)
Get the type category of an OpenACC variable.
std::string getVariableName(mlir::Value v)
Attempts to extract the variable name from a value by walking through view-like operations until an a...
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< ClauseDefaultValue > getDefaultAttr(mlir::Operation *op)
Looks for an OpenACC default attribute on the current operation op or in a parent operation which enc...
bool isOnlyUsedByReductionClauses(mlir::Value val, mlir::Region ®ion)
Returns true if this value is only used by acc.reduction operations in the region.
remark::detail::InFlightRemark emitRemark(mlir::Operation *op, const llvm::Twine &message, llvm::StringRef category="openacc")
Emit an OpenACC remark for the given operation with the given message.
std::optional< llvm::StringRef > getVarName(mlir::Operation *accOp)
Used to obtain the name from an acc operation.
static constexpr StringLiteral getRoutineInfoAttrName()
bool isValidValueUse(mlir::Value val, mlir::Region ®ion)
Check if a value use is valid in an OpenACC region.
mlir::Operation * getEnclosingComputeOp(mlir::Region ®ion)
Used to obtain the enclosing compute construct operation that contains the provided region.
llvm::SmallVector< mlir::Value > getDominatingDataClauses(mlir::Operation *computeConstructOp, mlir::DominanceInfo &domInfo, mlir::PostDominanceInfo &postDomInfo)
Collects all data clauses that dominate the compute construct.
static constexpr StringLiteral getVarNameAttrName()
std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type)
Get the recipe name for a given recipe kind and type.
static constexpr StringLiteral getDeclareAttrName()
Used to obtain the attribute name for declare.
bool isDeviceValue(mlir::Value val)
Check if a value represents device data.
mlir::Value getBaseEntity(mlir::Value val)
bool isOnlyUsedByPrivateClauses(mlir::Value val, mlir::Region ®ion)
Returns true if this value is only used by acc.private operations in the region.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.