18#include "llvm/ADT/SetVector.h"
19#include "llvm/ADT/TypeSwitch.h"
20#include "llvm/IR/Intrinsics.h"
21#include "llvm/Support/Casting.h"
29 auto barg = mlir::dyn_cast<mlir::BlockArgument>(v);
35 mlir::dyn_cast<mlir::acc::ComputeRegionOp>(block->
getParentOp());
38 assert(block == computeReg.getBody() &&
39 "block must be the body of acc.compute_region");
40 return computeReg.getOperand(barg);
48 return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS>(def) ? def :
nullptr;
51template <
typename OpTy>
56 if (!region.
isAncestor(user->getParentRegion()))
58 return mlir::isa<OpTy>(user);
61 return llvm::all_of(val.
getUsers(), checkIfUsedOnlyByOpInside);
74std::optional<mlir::acc::ClauseDefaultValue>
76 std::optional<mlir::acc::ClauseDefaultValue> defaultAttr;
83 while (!defaultAttr.has_value() && currOp) {
86 std::optional<mlir::acc::ClauseDefaultValue>>(currOp)
87 .Case<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::DataOp>(
88 [&](
auto op) {
return op.getDefaultAttr(); })
89 .Default([&](
Operation *) {
return std::nullopt; });
97 mlir::acc::VariableTypeCategory typeCategory =
98 mlir::acc::VariableTypeCategory::uncategorized;
99 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(var.
getType()))
100 typeCategory = mappableTy.getTypeCategory(var);
101 else if (
auto pointerLikeTy =
102 dyn_cast<mlir::acc::PointerLikeType>(var.
getType()))
103 typeCategory = pointerLikeTy.getPointeeTypeCategory(
105 pointerLikeTy.getElementType());
110 return llvm::StringLiteral(
"<acc.varname.placeholder>");
120 return std::to_string(*constVal);
123 if (
auto varNameAttr =
125 return varNameAttr.getName().str();
128 if (isa<ACC_DATA_ENTRY_OPS>(definingOp))
133 if (
auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
134 current = viewOp.getViewSource();
146 assert(kind == mlir::acc::RecipeKind::private_recipe ||
147 kind == mlir::acc::RecipeKind::firstprivate_recipe ||
148 kind == mlir::acc::RecipeKind::reduction_recipe);
149 if (!llvm::isa<mlir::acc::PointerLikeType, mlir::acc::MappableType>(type))
152 std::string recipeName;
153 llvm::raw_string_ostream ss(recipeName);
154 ss << (kind == mlir::acc::RecipeKind::private_recipe ?
"privatization_"
155 : kind == mlir::acc::RecipeKind::firstprivate_recipe
156 ?
"firstprivatization_"
165 for (
char &c : recipeName) {
166 if (!std::isalnum(
static_cast<unsigned char>(c)) && c !=
'.' && c !=
'_') {
171 else if (c ==
'(' || c ==
')' || c ==
'[' || c ==
']' || c ==
'{' ||
172 c ==
'}' || c ==
'<' || c ==
'>')
183 if (
auto partialEntityAccessOp =
185 if (!partialEntityAccessOp.isCompleteView())
186 return partialEntityAccessOp.getBaseEntity();
193 mlir::SymbolRefAttr symbol,
204 *definingOpPtr = definingOp;
209 if (mlir::isa<mlir::acc::PrivateRecipeOp, mlir::acc::ReductionRecipeOp,
210 mlir::acc::FirstprivateRecipeOp>(definingOp))
216 mlir::dyn_cast<mlir::acc::GlobalVariableOpInterface>(definingOp))
217 if (globalVar.isDeviceData())
222 mlir::dyn_cast_if_present<mlir::FunctionOpInterface>(definingOp)) {
235 func.getFunctionBody().empty() &&
func.getName().starts_with(
"llvm.") &&
236 llvm::Intrinsic::lookupIntrinsicID(
func.getName()) !=
237 llvm::Intrinsic::not_intrinsic)
249 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(val.
getType()))
250 if (mappableTy.isDeviceData(val))
253 if (
auto pointerLikeTy = dyn_cast<mlir::acc::PointerLikeType>(val.
getType()))
254 if (pointerLikeTy.isDeviceData(val))
263 if (
auto declareAttr = defOp->
getAttrOfType<mlir::acc::DeclareAttr>(
265 if (declareAttr.getDataClause().getValue() ==
266 mlir::acc::DataClause::acc_deviceptr)
271 if (
auto partialAccess =
272 dyn_cast<mlir::acc::PartialEntityAccessOpInterface>(defOp)) {
273 if (
mlir::Value base = partialAccess.getBaseEntity())
278 if (
auto addrOfIface =
279 dyn_cast<mlir::acc::AddressOfGlobalOpInterface>(defOp)) {
280 auto symbol = addrOfIface.getSymbol();
282 mlir::acc::GlobalVariableOpInterface>(defOp, symbol))
283 return global.isDeviceData();
293 llvm::isa<mlir::VectorType>(type))
297 if (isa_and_nonnull<ACC_DATA_ENTRY_OPS>(val.
getDefiningOp()))
315 llvm::SmallSetVector<mlir::Value, 8> dominatingDataClauses;
318 .Case<mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp>(
320 for (
auto dataClause : op.getDataClauseOperands()) {
321 dominatingDataClauses.insert(dataClause);
328 while (currParentOp) {
329 if (mlir::isa<mlir::acc::DataOp>(currParentOp)) {
330 for (
auto dataClause : mlir::dyn_cast<mlir::acc::DataOp>(currParentOp)
331 .getDataClauseOperands()) {
332 dominatingDataClauses.insert(dataClause);
335 currParentOp = currParentOp->getParentOp();
342 return dominatingDataClauses.takeVector();
347 funcOp->walk([&](mlir::acc::DeclareEnterOp declareEnterOp) {
348 if (domInfo.
dominates(declareEnterOp.getOperation(), computeConstructOp)) {
351 for (
auto *user : declareEnterOp.getToken().getUsers())
352 if (
auto declareExit = mlir::dyn_cast<mlir::acc::DeclareExitOp>(user))
353 exits.push_back(declareExit);
357 if (!exits.empty() &&
358 llvm::all_of(exits, [&](mlir::acc::DeclareExitOp exitOp) {
359 return postDomInfo.postDominates(exitOp, computeConstructOp);
361 for (
auto dataClause : declareEnterOp.getDataClauseOperands())
362 dominatingDataClauses.insert(dataClause);
367 return dominatingDataClauses.takeVector();
372 const std::function<std::string()> &messageFn,
373 llvm::StringRef category) {
380 llvm::StringRef funcName;
381 if (
auto func = dyn_cast<mlir::FunctionOpInterface>(op))
382 funcName =
func.getName();
383 else if (
auto funcOp = op->
getParentOfType<mlir::FunctionOpInterface>())
384 funcName = funcOp.getName();
387 if (!funcName.empty())
388 opts = opts.function(funcName);
390 auto remark = engine->emitOptimizationRemark(loc, opts);
static bool isOnlyUsedByOpClauses(mlir::Value val, mlir::Region ®ion)
static std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
MLIRContext * getContext() const
Return the context this attribute belongs to.
Block represents an ordered list of Operations.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
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.
AttrClass getAttrOfType(StringAttr name)
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.
ParentT getParentOfType()
Find the first parent operation of the given type, or nullptr if there is no ancestor operation.
@ 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.
#define ACC_COMPUTE_CONSTRUCT_OPS
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.
mlir::Value getACCOperandForBlockArg(mlir::Value v)
If v is not a block argument of an acc.compute_region body, returns nullptr.
mlir::Operation * getACCDataClauseOpForBlockArg(mlir::Value v)
If v is not a block argument of an acc.compute_region body, returns nullptr.
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.
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::StringLiteral getVarNamePlaceholder()
Returns a placeholder string for use as an acc.var_name attribute value when the actual variable name...
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.
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.
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.