20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SetVector.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include "llvm/IR/Intrinsics.h"
24#include "llvm/Support/Casting.h"
32 auto barg = mlir::dyn_cast<mlir::BlockArgument>(v);
38 mlir::dyn_cast<mlir::acc::ComputeRegionOp>(block->
getParentOp());
41 assert(block == computeReg.getBody() &&
42 "block must be the body of acc.compute_region");
43 return computeReg.getOperand(barg);
51 return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS>(def) ? def :
nullptr;
54template <
typename OpTy>
59 if (!region.
isAncestor(user->getParentRegion()))
61 return mlir::isa<OpTy>(user);
64 return llvm::all_of(val.
getUsers(), checkIfUsedOnlyByOpInside);
77std::optional<mlir::acc::ClauseDefaultValue>
79 std::optional<mlir::acc::ClauseDefaultValue> defaultAttr;
86 while (!defaultAttr.has_value() && currOp) {
89 std::optional<mlir::acc::ClauseDefaultValue>>(currOp)
90 .Case<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::DataOp>(
91 [&](
auto op) {
return op.getDefaultAttr(); })
92 .Default([&](
Operation *) {
return std::nullopt; });
100 mlir::acc::VariableTypeCategory typeCategory =
101 mlir::acc::VariableTypeCategory::uncategorized;
102 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(var.
getType()))
103 typeCategory = mappableTy.getTypeCategory(var);
104 else if (
auto pointerLikeTy =
105 dyn_cast<mlir::acc::PointerLikeType>(var.
getType()))
106 typeCategory = pointerLikeTy.getPointeeTypeCategory(
108 pointerLikeTy.getElementType());
113 return llvm::StringLiteral(
"<acc.varname.placeholder>");
123 return std::to_string(*constVal);
126 if (
auto varNameAttr = definingOp->getDiscardableAttrOfType<VarNameAttr>(
128 return varNameAttr.getName().str();
131 if (isa<ACC_DATA_ENTRY_OPS, MapInfoOp>(definingOp))
136 if (
auto addressOf = dyn_cast<AddressOfGlobalOpInterface>(definingOp))
137 return addressOf.getSymbol().getLeafReference().str();
140 if (
auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
141 current = viewOp.getViewSource();
153 assert(kind == mlir::acc::RecipeKind::private_recipe ||
154 kind == mlir::acc::RecipeKind::firstprivate_recipe ||
155 kind == mlir::acc::RecipeKind::reduction_recipe);
156 if (!llvm::isa<mlir::acc::PointerLikeType, mlir::acc::MappableType>(type))
159 std::string recipeName;
160 llvm::raw_string_ostream ss(recipeName);
161 ss << (kind == mlir::acc::RecipeKind::private_recipe ?
"privatization_"
162 : kind == mlir::acc::RecipeKind::firstprivate_recipe
163 ?
"firstprivatization_"
172 for (
char &c : recipeName) {
173 if (!std::isalnum(
static_cast<unsigned char>(c)) && c !=
'.' && c !=
'_') {
178 else if (c ==
'(' || c ==
')' || c ==
'[' || c ==
']' || c ==
'{' ||
179 c ==
'}' || c ==
'<' || c ==
'>')
190 if (
auto partialEntityAccessOp =
192 if (!partialEntityAccessOp.isCompleteView())
193 return partialEntityAccessOp.getBaseEntity();
203 mlir::SymbolRefAttr symbol) {
207 for (
auto gpuModule : moduleOp.getOps<mlir::gpu::GPUModuleOp>()) {
209 gpuModule, symbol.getRootReference()))
216 mlir::SymbolRefAttr symbol,
223 *definingOpPtr = gpuOp;
236 *definingOpPtr = definingOp;
241 if (mlir::isa<mlir::accomp::RecipeInterface>(definingOp))
247 mlir::dyn_cast<mlir::acc::GlobalVariableOpInterface>(definingOp))
248 if (globalVar.isDeviceData())
253 mlir::dyn_cast_if_present<mlir::FunctionOpInterface>(definingOp)) {
267 func.getFunctionBody().empty() &&
func.getName().starts_with(
"llvm.") &&
268 llvm::Intrinsic::lookupIntrinsicID(
func.getName()) !=
269 llvm::Intrinsic::not_intrinsic)
282 if (
auto mappableTy = dyn_cast<mlir::acc::MappableType>(val.
getType()))
283 if (mappableTy.isDeviceData(val))
286 if (
auto pointerLikeTy = dyn_cast<mlir::acc::PointerLikeType>(val.
getType()))
287 if (pointerLikeTy.isDeviceData(val))
296 if (
auto declareAttr =
299 if (declareAttr.getDataClause().getValue() ==
300 mlir::acc::DataClause::acc_deviceptr)
305 if (
auto partialAccess =
306 dyn_cast<mlir::acc::PartialEntityAccessOpInterface>(defOp)) {
307 if (
mlir::Value base = partialAccess.getBaseEntity())
312 if (
auto addrOfIface =
313 dyn_cast<mlir::acc::AddressOfGlobalOpInterface>(defOp)) {
314 auto symbol = addrOfIface.getSymbol();
316 mlir::acc::GlobalVariableOpInterface>(defOp, symbol))
317 return global.isDeviceData();
327 llvm::isa<mlir::VectorType>(type))
331 if (isa_and_nonnull<ACC_DATA_ENTRY_OPS>(val.
getDefiningOp()))
344 if (
auto func = parent->getParentOfType<mlir::FunctionOpInterface>()) {
347 llvm::is_contained(
func.getArguments(), val))
359 llvm::SmallSetVector<mlir::Value, 8> dominatingDataClauses;
362 .Case<mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp>(
364 for (
auto dataClause : op.getDataClauseOperands()) {
365 dominatingDataClauses.insert(dataClause);
372 while (currParentOp) {
373 if (mlir::isa<mlir::acc::DataOp>(currParentOp)) {
374 for (
auto dataClause : mlir::dyn_cast<mlir::acc::DataOp>(currParentOp)
375 .getDataClauseOperands()) {
376 dominatingDataClauses.insert(dataClause);
379 currParentOp = currParentOp->getParentOp();
386 return dominatingDataClauses.takeVector();
391 funcOp->walk([&](mlir::acc::DeclareEnterOp declareEnterOp) {
392 if (domInfo.
dominates(declareEnterOp.getOperation(), computeConstructOp)) {
395 for (
auto *user : declareEnterOp.getToken().getUsers())
396 if (
auto declareExit = mlir::dyn_cast<mlir::acc::DeclareExitOp>(user))
397 exits.push_back(declareExit);
401 if (!exits.empty() &&
402 llvm::all_of(exits, [&](mlir::acc::DeclareExitOp exitOp) {
403 return postDomInfo.postDominates(exitOp, computeConstructOp);
405 for (
auto dataClause : declareEnterOp.getDataClauseOperands())
406 dominatingDataClauses.insert(dataClause);
411 return dominatingDataClauses.takeVector();
416 const std::function<std::string()> &messageFn,
417 llvm::StringRef category) {
424 llvm::StringRef funcName;
425 if (
auto func = dyn_cast<mlir::FunctionOpInterface>(op))
426 funcName =
func.getName();
427 else if (
auto funcOp = op->
getParentOfType<mlir::FunctionOpInterface>())
428 funcName = funcOp.getName();
431 if (!funcName.empty())
432 opts = opts.function(funcName);
434 auto remark = engine->emitOptimizationRemark(loc, opts);
static bool isOnlyUsedByOpClauses(mlir::Value val, mlir::Region ®ion)
static mlir::Operation * lookupSymbolInGPUModules(mlir::Operation *user, mlir::SymbolRefAttr symbol)
Look up symbol in the gpu.modules of the enclosing module.
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.
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'.
bool hasDiscardableAttr(StringRef name)
Return true if this operation has a discardable attribute with the provided name.
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
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.
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 * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
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.
bool isAccRoutine(mlir::Operation *op)
Used to check whether the current operation is marked with acc routine.
static constexpr StringLiteral getSpecializedRoutineAttrName()
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 isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
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.