MLIR 24.0.0git
OpenACCUtils.cpp
Go to the documentation of this file.
1//===- OpenACCUtils.cpp ---------------------------------------------------===//
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
10
15#include "mlir/IR/BuiltinOps.h"
17#include "mlir/IR/Dominance.h"
18#include "mlir/IR/SymbolTable.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SetVector.h"
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/Support/Casting.h"
26
28 return region
29 .getParentOfType<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::ComputeRegionOp>();
30}
31
33 auto barg = mlir::dyn_cast<mlir::BlockArgument>(v);
34 if (!barg)
35 return nullptr;
36
37 mlir::Block *block = barg.getOwner();
38 auto computeReg =
39 mlir::dyn_cast<mlir::acc::ComputeRegionOp>(block->getParentOp());
40 if (!computeReg)
41 return nullptr;
42 assert(block == computeReg.getBody() &&
43 "block must be the body of acc.compute_region");
44 return computeReg.getOperand(barg);
45}
46
49 if (!orig)
50 return nullptr;
51 mlir::Operation *def = orig.getDefiningOp();
52 return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS>(def) ? def : nullptr;
53}
54
55template <typename OpTy>
57 auto checkIfUsedOnlyByOpInside = [&](mlir::Operation *user) {
58 // For any users which are not in the current acc region, we can ignore.
59 // Return true so that it can be used in a `all_of` check.
60 if (!region.isAncestor(user->getParentRegion()))
61 return true;
62 return mlir::isa<OpTy>(user);
63 };
64
65 return llvm::all_of(val.getUsers(), checkIfUsedOnlyByOpInside);
66}
67
72
77
78std::optional<mlir::acc::ClauseDefaultValue>
80 std::optional<mlir::acc::ClauseDefaultValue> defaultAttr;
81 Operation *currOp = op;
82
83 // Iterate outwards until a default clause is found (since OpenACC
84 // specification notes that a visible default clause is the nearest default
85 // clause appearing on the compute construct or a lexically containing data
86 // construct.
87 while (!defaultAttr.has_value() && currOp) {
88 defaultAttr =
90 std::optional<mlir::acc::ClauseDefaultValue>>(currOp)
91 .Case<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::DataOp>(
92 [&](auto op) { return op.getDefaultAttr(); })
93 .Default([&](Operation *) { return std::nullopt; });
94 currOp = currOp->getParentOp();
95 }
96
97 return defaultAttr;
98}
99
100mlir::acc::VariableTypeCategory mlir::acc::getTypeCategory(mlir::Value var) {
101 mlir::acc::VariableTypeCategory typeCategory =
102 mlir::acc::VariableTypeCategory::uncategorized;
103 if (auto mappableTy = dyn_cast<mlir::acc::MappableType>(var.getType()))
104 typeCategory = mappableTy.getTypeCategory(var);
105 else if (auto pointerLikeTy =
106 dyn_cast<mlir::acc::PointerLikeType>(var.getType()))
107 typeCategory = pointerLikeTy.getPointeeTypeCategory(
109 pointerLikeTy.getElementType());
110 return typeCategory;
111}
112
113llvm::StringLiteral mlir::acc::getVarNamePlaceholder() {
114 return llvm::StringLiteral("<acc.varname.placeholder>");
115}
116
118 Value current = v;
119
120 // Walk through view operations until a name is found or can't go further
121 while (Operation *definingOp = current.getDefiningOp()) {
122 // For integer constants, return their value as a string.
123 if (std::optional<int64_t> constVal = getConstantIntValue(current))
124 return std::to_string(*constVal);
125
126 // Check for `acc.var_name` attribute
127 if (auto varNameAttr = definingOp->getDiscardableAttrOfType<VarNameAttr>(
129 return varNameAttr.getName().str();
130
131 // If it is a data entry operation, get name via getVarName
132 if (isa<ACC_DATA_ENTRY_OPS, MapInfoOp>(definingOp))
133 if (auto name = acc::getVarName(definingOp))
134 return name->str();
135
136 // A global goes by the symbol it is addressed through.
137 if (auto addressOf = dyn_cast<AddressOfGlobalOpInterface>(definingOp))
138 return addressOf.getSymbol().getLeafReference().str();
139
140 // If it's a view operation, continue to the source
141 if (auto viewOp = dyn_cast<ViewLikeOpInterface>(definingOp)) {
142 current = viewOp.getViewSource();
143 continue;
144 }
145
146 break;
147 }
148
149 return "";
150}
151
152std::string mlir::acc::getRecipeName(mlir::acc::RecipeKind kind,
153 mlir::Type type) {
154 assert(kind == mlir::acc::RecipeKind::private_recipe ||
155 kind == mlir::acc::RecipeKind::firstprivate_recipe ||
156 kind == mlir::acc::RecipeKind::reduction_recipe);
157 if (!llvm::isa<mlir::acc::PointerLikeType, mlir::acc::MappableType>(type))
158 return "";
159
160 std::string recipeName;
161 llvm::raw_string_ostream ss(recipeName);
162 ss << (kind == mlir::acc::RecipeKind::private_recipe ? "privatization_"
163 : kind == mlir::acc::RecipeKind::firstprivate_recipe
164 ? "firstprivatization_"
165 : "reduction_");
166
167 // Print the type using its dialect-defined textual format.
168 type.print(ss);
169 ss.flush();
170
171 // Replace invalid characters (anything that's not a letter, number, or
172 // period) since this needs to be a valid MLIR identifier.
173 for (char &c : recipeName) {
174 if (!std::isalnum(static_cast<unsigned char>(c)) && c != '.' && c != '_') {
175 if (c == '?')
176 c = 'U';
177 else if (c == '*')
178 c = 'Z';
179 else if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' ||
180 c == '}' || c == '<' || c == '>')
181 c = '_';
182 else
183 c = 'X';
184 }
185 }
186
187 return recipeName;
188}
189
191 if (auto partialEntityAccessOp =
192 val.getDefiningOp<PartialEntityAccessOpInterface>()) {
193 if (!partialEntityAccessOp.isCompleteView())
194 return partialEntityAccessOp.getBaseEntity();
195 }
196
197 return val;
198}
199
200/// Look up `symbol` in the `gpu.module`s of the enclosing module. A
201/// `gpu.module` is its own symbol table, so `lookupNearestSymbolFrom` from a
202/// user outside of it does not find definitions placed inside.
204 mlir::SymbolRefAttr symbol) {
205 auto moduleOp = user->getParentOfType<mlir::ModuleOp>();
206 if (!moduleOp)
207 return nullptr;
208 for (auto gpuModule : moduleOp.getOps<mlir::gpu::GPUModuleOp>()) {
210 gpuModule, symbol.getRootReference()))
211 return op;
212 }
213 return nullptr;
214}
215
217 mlir::SymbolRefAttr symbol,
218 mlir::Operation **definingOpPtr) {
219 // A pass may prepare the device-side definition of a symbol inside a
220 // `gpu.module` while the use is still a reference from host IR. Such a
221 // symbol is meant to be used on device, so the use is valid.
222 if (mlir::Operation *gpuOp = lookupSymbolInGPUModules(user, symbol)) {
223 if (definingOpPtr)
224 *definingOpPtr = gpuOp;
225 return true;
226 }
227
228 mlir::Operation *definingOp =
230
231 // If there are no defining ops, we have no way to ensure validity because
232 // we cannot check for any attributes.
233 if (!definingOp)
234 return false;
235
236 if (definingOpPtr)
237 *definingOpPtr = definingOp;
238
239 // Check if the defining op is a recipe.
240 // Recipes are valid as they get materialized before being offloaded to
241 // device. They are only instructions for how to materialize.
242 if (mlir::isa<mlir::accomp::RecipeInterface>(definingOp))
243 return true;
244
245 // Check if the defining op is a global variable that is device data.
246 // Device data is already resident on the device and does not need mapping.
247 if (auto globalVar =
248 mlir::dyn_cast<mlir::acc::GlobalVariableOpInterface>(definingOp))
249 if (globalVar.isDeviceAccessible())
250 return true;
251
252 // Check if the defining op is a function
253 if (auto func =
254 mlir::dyn_cast_if_present<mlir::FunctionOpInterface>(definingOp)) {
255 // If this symbol is actually an acc routine or a specialized acc routine -
256 // then it is expected for it to be offloaded - therefore it is valid.
257 if (func->hasDiscardableAttr(mlir::acc::getRoutineInfoAttrName()) ||
258 func->hasDiscardableAttr(mlir::acc::getSpecializedRoutineAttrName()))
259 return true;
260
261 // If this symbol is a call to an LLVM intrinsic, then it is likely valid.
262 // Check the following:
263 // 1. The function is private
264 // 2. The function has no body
265 // 3. Name starts with "llvm."
266 // 4. The function's name is a valid LLVM intrinsic name
267 if (func.getVisibility() == mlir::SymbolTable::Visibility::Private &&
268 func.getFunctionBody().empty() && func.getName().starts_with("llvm.") &&
269 llvm::Intrinsic::lookupIntrinsicID(func.getName()) !=
270 llvm::Intrinsic::not_intrinsic)
271 return true;
272 }
273
274 // A declare attribute is needed for symbol references.
275 bool hasDeclare =
277 return hasDeclare;
278}
279
280/// Finds the global variable that `addrOf` refers to, through `symbolTables`
281/// when provided (cached lookup) and by scanning the nearest symbol table
282/// otherwise.
283static mlir::acc::GlobalVariableOpInterface
284lookupGlobalVariable(mlir::Operation *addrOf, mlir::SymbolRefAttr symbol,
285 mlir::SymbolTableCollection *symbolTables) {
286 if (symbolTables)
287 return symbolTables
288 ->lookupNearestSymbolFrom<mlir::acc::GlobalVariableOpInterface>(addrOf,
289 symbol);
291 mlir::acc::GlobalVariableOpInterface>(addrOf, symbol);
292}
293
295 mlir::Value val, mlir::SymbolTableCollection *symbolTables) {
296 // Check if the value is device data via type interfaces.
297 // Device data is already resident on the device and does not need mapping.
298 if (auto mappableTy = dyn_cast<mlir::acc::MappableType>(val.getType()))
299 if (mappableTy.isDeviceAccessible(val, symbolTables))
300 return true;
301
302 if (auto pointerLikeTy = dyn_cast<mlir::acc::PointerLikeType>(val.getType()))
303 if (pointerLikeTy.isDeviceAccessible(val, symbolTables))
304 return true;
305
306 mlir::Operation *defOp = val.getDefiningOp();
307 if (!defOp)
308 return false;
309
310 // `acc.declare` with deviceptr marks data that is already associated with
311 // the device.
312 if (auto declareAttr =
313 defOp->getDiscardableAttrOfType<mlir::acc::DeclareAttr>(
315 if (declareAttr.getDataClause().getValue() ==
316 mlir::acc::DataClause::acc_deviceptr)
317 return true;
318
319 // Handle operations that access a partial entity - check if the base entity
320 // is device data.
321 if (auto partialAccess =
322 dyn_cast<mlir::acc::PartialEntityAccessOpInterface>(defOp)) {
323 if (mlir::Value base = partialAccess.getBaseEntity())
324 return isDeviceAccessibleValue(base, symbolTables);
325 }
326
327 // Handle address_of - check if the referenced global is device data.
328 if (auto addrOfIface =
329 dyn_cast<mlir::acc::AddressOfGlobalOpInterface>(defOp)) {
330 auto symbol = addrOfIface.getSymbol();
331 if (auto global = lookupGlobalVariable(defOp, symbol, symbolTables))
332 return global.isDeviceAccessible();
333 }
334
335 return false;
336}
337
339 mlir::Value val, mlir::SymbolTableCollection *symbolTables) {
340 // In-device-memory data is a subset of device-accessible data: it must be
341 // accessible and its storage must physically reside in device memory.
342 if (auto mappableTy = dyn_cast<mlir::acc::MappableType>(val.getType()))
343 if (mappableTy.isInDeviceMemory(val, symbolTables))
344 return true;
345
346 if (auto pointerLikeTy = dyn_cast<mlir::acc::PointerLikeType>(val.getType()))
347 if (pointerLikeTy.isInDeviceMemory(val, symbolTables))
348 return true;
349
350 mlir::Operation *defOp = val.getDefiningOp();
351 if (!defOp)
352 return false;
353
354 // `acc.declare` with deviceptr marks data whose storage is already in device
355 // memory.
356 if (auto declareAttr =
357 defOp->getDiscardableAttrOfType<mlir::acc::DeclareAttr>(
359 if (declareAttr.getDataClause().getValue() ==
360 mlir::acc::DataClause::acc_deviceptr)
361 return true;
362
363 // Handle operations that access a partial entity - check if the base entity
364 // is in device memory.
365 if (auto partialAccess =
366 dyn_cast<mlir::acc::PartialEntityAccessOpInterface>(defOp)) {
367 if (mlir::Value base = partialAccess.getBaseEntity())
368 return isInDeviceMemoryValue(base, symbolTables);
369 }
370
371 // Handle address_of - check if the referenced global is in device memory.
372 if (auto addrOfIface =
373 dyn_cast<mlir::acc::AddressOfGlobalOpInterface>(defOp)) {
374 auto symbol = addrOfIface.getSymbol();
375 if (auto global = lookupGlobalVariable(defOp, symbol, symbolTables))
376 return global.isInDeviceMemory();
377 }
378
379 return false;
380}
381
383 mlir::SymbolTableCollection *symbolTables) {
384 // Types that can be passed by value are legal.
385 Type type = val.getType();
386 if (type.isIntOrIndexOrFloat() || isa<mlir::ComplexType>(type) ||
387 llvm::isa<mlir::VectorType>(type))
388 return true;
389
390 // If this is produced by an ACC data entry operation, it is valid.
391 if (isa_and_nonnull<ACC_DATA_ENTRY_OPS>(val.getDefiningOp()))
392 return true;
393
394 // If the value is only used by private clauses, it is not a live-in.
395 if (isOnlyUsedByPrivateClauses(val, region))
396 return true;
397
398 // If this is device data, it is valid.
399 if (isDeviceAccessibleValue(val, symbolTables))
400 return true;
401
402 // Arguments of an enclosing acc routine are already on the device.
403 if (mlir::Operation *parent = region.getParentOp()) {
404 if (auto func = parent->getParentOfType<mlir::FunctionOpInterface>()) {
407 llvm::is_contained(func.getArguments(), val))
408 return true;
409 }
410 }
411
412 return false;
413}
414
417 mlir::DominanceInfo &domInfo,
418 mlir::PostDominanceInfo &postDomInfo) {
419 llvm::SmallSetVector<mlir::Value, 8> dominatingDataClauses;
420
421 llvm::TypeSwitch<mlir::Operation *>(computeConstructOp)
422 .Case<mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp>(
423 [&](auto op) {
424 for (auto dataClause : op.getDataClauseOperands()) {
425 dominatingDataClauses.insert(dataClause);
426 }
427 })
428 .Default([](mlir::Operation *) {});
429
430 // Collect the data clauses from enclosing data constructs.
431 mlir::Operation *currParentOp = computeConstructOp->getParentOp();
432 while (currParentOp) {
433 if (mlir::isa<mlir::acc::DataOp>(currParentOp)) {
434 for (auto dataClause : mlir::dyn_cast<mlir::acc::DataOp>(currParentOp)
435 .getDataClauseOperands()) {
436 dominatingDataClauses.insert(dataClause);
437 }
438 }
439 currParentOp = currParentOp->getParentOp();
440 }
441
442 // Find the enclosing function/subroutine
443 auto funcOp =
444 computeConstructOp->getParentOfType<mlir::FunctionOpInterface>();
445 if (!funcOp)
446 return dominatingDataClauses.takeVector();
447
448 // Walk the function to find `acc.declare_enter`/`acc.declare_exit` pairs that
449 // dominate and post-dominate the compute construct and add their data
450 // clauses to the list.
451 funcOp->walk([&](mlir::acc::DeclareEnterOp declareEnterOp) {
452 if (domInfo.dominates(declareEnterOp.getOperation(), computeConstructOp)) {
453 // Collect all `acc.declare_exit` ops for this token.
455 for (auto *user : declareEnterOp.getToken().getUsers())
456 if (auto declareExit = mlir::dyn_cast<mlir::acc::DeclareExitOp>(user))
457 exits.push_back(declareExit);
458
459 // Only add clauses if every `acc.declare_exit` op post-dominates the
460 // compute construct.
461 if (!exits.empty() &&
462 llvm::all_of(exits, [&](mlir::acc::DeclareExitOp exitOp) {
463 return postDomInfo.postDominates(exitOp, computeConstructOp);
464 })) {
465 for (auto dataClause : declareEnterOp.getDataClauseOperands())
466 dominatingDataClauses.insert(dataClause);
467 }
468 }
469 });
470
471 return dominatingDataClauses.takeVector();
472}
473
475 if (auto ifOp = mlir::dyn_cast<mlir::scf::IfOp>(op))
476 return ifOp.getCondition();
477
478 if (!mlir::isa<mlir::RegionBranchOpInterface>(op) ||
479 mlir::isa<mlir::LoopLikeOpInterface>(op))
480 return {};
481 if (op->getNumOperands() != 1 || op->getNumRegions() != 2 ||
483 return {};
484 return op->getOperand(0);
485}
486
488 llvm::ArrayRef<int64_t> deviceTypes) {
489 // No device type is known to be true, so no branch can be classified.
490 if (deviceTypes.empty())
491 return false;
492
493 for (mlir::Operation *parent = op->getParentOp();
494 parent &&
495 !mlir::isa<ACC_COMPUTE_CONSTRUCT_OPS, mlir::acc::ComputeRegionOp,
496 mlir::FunctionOpInterface>(parent);
497 parent = parent->getParentOp()) {
498 mlir::Value condition = getIfCondition(parent);
499 if (!condition)
500 continue;
501
502 // The condition must be the `acc.on_device` result itself.
503 auto onDeviceOp = condition.getDefiningOp<mlir::acc::OnDeviceOp>();
504 if (!onDeviceOp)
505 continue;
506
507 std::optional<int64_t> deviceTypeValue =
508 mlir::getConstantIntValue(onDeviceOp.getDeviceType());
509 if (!deviceTypeValue)
510 continue;
511
512 bool onTarget = llvm::is_contained(deviceTypes, *deviceTypeValue);
513 bool inThen = parent->getRegion(0).isAncestor(op->getParentRegion());
514 bool inElse = parent->getRegion(1).isAncestor(op->getParentRegion());
515 // Off the target: the then of a device type outside `deviceTypes`, or
516 // the else of a device type in `deviceTypes`.
517 if ((!onTarget && inThen) || (onTarget && inElse))
518 return true;
519 }
520 return false;
521}
522
525 const std::function<std::string()> &messageFn,
526 llvm::StringRef category) {
527 using namespace mlir::remark;
528 mlir::Location loc = op->getLoc();
529 auto *engine = loc->getContext()->getRemarkEngine();
530 if (!engine)
532
533 llvm::StringRef funcName;
534 if (auto func = dyn_cast<mlir::FunctionOpInterface>(op))
535 funcName = func.getName();
536 else if (auto funcOp = op->getParentOfType<mlir::FunctionOpInterface>())
537 funcName = funcOp.getName();
538
539 auto opts = RemarkOpts::name("openacc").category(category);
540 if (!funcName.empty())
541 opts = opts.function(funcName);
542
543 auto remark = engine->emitOptimizationRemark(loc, opts);
544 if (remark)
545 remark << messageFn();
546 return remark;
547}
static bool isOnlyUsedByOpClauses(mlir::Value val, mlir::Region &region)
static mlir::Value getIfCondition(mlir::Operation *op)
static mlir::Operation * lookupSymbolInGPUModules(mlir::Operation *user, mlir::SymbolRefAttr symbol)
Look up symbol in the gpu.modules of the enclosing module.
static mlir::acc::GlobalVariableOpInterface lookupGlobalVariable(mlir::Operation *addrOf, mlir::SymbolRefAttr symbol, mlir::SymbolTableCollection *symbolTables)
Finds the global variable that addrOf refers to, through symbolTables when provided (cached lookup) a...
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.
Definition Block.h:34
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
Definition Block.cpp:31
A class for computing basic dominance information.
Definition Dominance.h:143
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
Definition Dominance.h:161
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
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.
Definition Operation.h:87
Value getOperand(unsigned idx)
Definition Operation.h:377
unsigned getNumRegions()
Returns the number of regions held by this operation.
Definition Operation.h:728
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
unsigned getNumOperands()
Definition Operation.h:373
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
bool hasDiscardableAttr(StringRef name)
Return true if this operation has a discardable attribute with the provided name.
Definition Operation.h:505
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
Definition Operation.h:495
Region * getParentRegion()
Returns the region to which the instruction belongs.
Definition Operation.h:247
A class for computing basic postdominance information.
Definition Dominance.h:207
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
Definition Region.h:234
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition Region.h:198
ParentT getParentOfType()
Find the first parent operation of the given type, or nullptr if there is no ancestor operation.
Definition Region.h:206
This class represents a collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
@ Private
The symbol is private and may only be referenced by SymbolRefAttrs local to the operations within the...
Definition SymbolTable.h:92
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...
Definition Types.h:74
void print(raw_ostream &os) const
Print the current type.
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition Types.cpp:66
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
Definition Types.cpp:122
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
user_range getUsers() const
Definition Value.h:218
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
A wrapper for linking remarks by query - searches the engine's registry at stream time and links to a...
Definition Remarks.h:412
#define ACC_COMPUTE_CONSTRUCT_OPS
Definition OpenACC.h:62
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.
Definition OpenACC.h:211
static constexpr StringLiteral getSpecializedRoutineAttrName()
Definition OpenACC.h:205
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.
Definition OpenACC.h:217
bool isOnlyUsedByReductionClauses(mlir::Value val, mlir::Region &region)
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.
Definition OpenACC.cpp:5160
static constexpr StringLiteral getRoutineInfoAttrName()
Definition OpenACC.h:201
mlir::Operation * getEnclosingComputeOp(mlir::Region &region)
Used to obtain the enclosing compute construct operation that contains the provided region.
bool isValidValueUse(mlir::Value val, mlir::Region &region, mlir::SymbolTableCollection *symbolTables=nullptr)
Check if a value use is valid in an OpenACC 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.
bool isInDeviceMemoryValue(mlir::Value val, mlir::SymbolTableCollection *symbolTables=nullptr)
Check if a value is backed by memory that is residing in the current device, and therefore requires n...
static constexpr StringLiteral getVarNameAttrName()
Definition OpenACC.h:246
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.
Definition OpenACC.h:193
bool isDeviceAccessibleValue(mlir::Value val, mlir::SymbolTableCollection *symbolTables=nullptr)
Check if a value represents device data.
bool isInOffTargetBranch(mlir::Operation *op, llvm::ArrayRef< int64_t > deviceTypes)
Returns true if op is in a branch that does not execute on the target.
mlir::Value getBaseEntity(mlir::Value val)
bool isOnlyUsedByPrivateClauses(mlir::Value val, mlir::Region &region)
Returns true if this value is only used by acc.private operations in the region.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
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.
Definition Value.h:496
static RemarkOpts name(StringRef n)
Definition Remarks.h:108