MLIR 24.0.0git
OpenACCUtilsCG.cpp
Go to the documentation of this file.
1//===- OpenACCUtilsCG.cpp - OpenACC Code Generation Utilities -------------===//
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//
9// This file implements utility functions for OpenACC code generation.
10//
11//===----------------------------------------------------------------------===//
12
14
22#include "mlir/IR/BuiltinOps.h"
23#include "mlir/IR/IRMapping.h"
26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/TypeSwitch.h"
29#include "llvm/Support/MathExtras.h"
30
31namespace mlir {
32namespace acc {
33
34std::optional<DataLayout> getDataLayout(Operation *op, bool allowDefault) {
35 if (!op)
36 return std::nullopt;
37
38 // Walk up the parent chain to find the nearest operation with an explicit
39 // data layout spec. Check ModuleOp explicitly since it does not actually
40 // implement DataLayoutOpInterface as a trait (it just has the same methods).
41 Operation *current = op;
42 while (current) {
43 // Check for ModuleOp with explicit data layout spec
44 if (auto mod = llvm::dyn_cast<ModuleOp>(current)) {
45 if (mod.getDataLayoutSpec())
46 return DataLayout(mod);
47 } else if (auto dataLayoutOp =
48 llvm::dyn_cast<DataLayoutOpInterface>(current)) {
49 // Check other DataLayoutOpInterface implementations
50 if (dataLayoutOp.getDataLayoutSpec())
51 return DataLayout(dataLayoutOp);
52 }
53 current = current->getParentOp();
54 }
55
56 // No explicit data layout found; return default if allowed
57 if (allowDefault) {
58 // Check if op itself is a ModuleOp
59 if (auto mod = llvm::dyn_cast<ModuleOp>(op))
60 return DataLayout(mod);
61 // Otherwise check parents
62 if (auto mod = op->getParentOfType<ModuleOp>())
63 return DataLayout(mod);
64 }
65
66 return std::nullopt;
67}
68
69ComputeRegionOp buildComputeRegion(Location loc, ValueRange launchArgs,
70 ValueRange inputArgs, llvm::StringRef origin,
71 Region &regionToClone,
72 RewriterBase &rewriter, IRMapping &mapping,
73 ValueRange output,
74 FlatSymbolRefAttr kernelFuncName,
75 FlatSymbolRefAttr kernelModuleName,
76 Value stream, ValueRange inputArgsToMap) {
77 SmallVector<Type> resultTypes;
78 for (auto val : output)
79 resultTypes.push_back(val.getType());
80 auto computeRegion =
81 ComputeRegionOp::create(rewriter, loc, resultTypes, launchArgs, inputArgs,
82 stream, origin, kernelFuncName, kernelModuleName);
83
84 assert(!regionToClone.getBlocks().empty() &&
85 "empty region for acc.compute_region");
86 OpBuilder::InsertionGuard guard(rewriter);
87
88 ValueRange mapKeys = inputArgsToMap.empty() ? inputArgs : inputArgsToMap;
89 assert(mapKeys.size() == inputArgs.size() &&
90 "inputArgsToMap must have same size as inputArgs when provided");
91
92 Type indexType = rewriter.getIndexType();
93 Block *entryBlock = rewriter.createBlock(&computeRegion.getRegion());
94 for (size_t i = 0; i < launchArgs.size(); ++i)
95 entryBlock->addArgument(indexType, loc);
96 for (Value input : inputArgs)
97 entryBlock->addArgument(input.getType(), loc);
98 for (size_t i = 0; i < inputArgs.size(); ++i)
99 mapping.map(mapKeys[i], entryBlock->getArgument(launchArgs.size() + i));
100 rewriter.setInsertionPointToStart(entryBlock);
101 if (regionToClone.getBlocks().size() == 1) {
102 for (auto &op : regionToClone.front().getOperations()) {
103 if (op.hasTrait<OpTrait::IsTerminator>())
104 break;
105 rewriter.clone(op, mapping);
106 }
107 SmallVector<Value> yieldOperands;
108 for (auto val : output)
109 yieldOperands.push_back(mapping.lookup(val));
110 rewriter.setInsertionPointToEnd(entryBlock);
111 YieldOp::create(rewriter, loc, yieldOperands);
112 } else {
114 regionToClone, mapping, loc, rewriter);
115 if (!exeRegion) {
116 rewriter.eraseOp(computeRegion);
117 return nullptr;
118 }
120 llvm::to_vector(exeRegion.getOps<scf::YieldOp>()));
121 assert(!yieldOps.empty() &&
122 "multi-block region must contain at least one scf.yield");
123 assert(llvm::all_of(yieldOps,
124 [&output](scf::YieldOp yieldOp) {
125 return yieldOp.getNumOperands() ==
126 static_cast<int64_t>(output.size()) &&
127 llvm::all_of(
128 llvm::zip(yieldOp.getOperands(), output),
129 [](auto pair) {
130 return std::get<0>(pair).getType() ==
131 std::get<1>(pair).getType();
132 });
133 }) &&
134 "each scf.yield operand count and types must match output");
135 rewriter.setInsertionPointToEnd(entryBlock);
136 YieldOp::create(rewriter, loc, exeRegion.getResults());
137 }
138
139 return computeRegion;
140}
141
144 GPUParallelDimAttr parDim) {
145 return llvm::lower_bound(
146 parDims, parDim,
147 [](const GPUParallelDimAttr &lhs, const GPUParallelDimAttr &rhs) {
148 return lhs.getOrder() > rhs.getOrder();
149 });
150}
151
153 GPUParallelDimAttr parDim) {
155 if (lb == parDims.end() || *lb != parDim)
156 parDims.insert(lb, parDim);
157}
158
160 GPUParallelDimAttr parDim) {
162 if (lb != parDims.end() && *lb == parDim)
163 parDims.erase(lb);
164}
165
166#define ACC_OP_WITH_PAR_DIMS_LIST \
167 PrivatizeOp, ReductionAccumulateOp, ReductionAccumulateArrayOp
168
169GPUParallelDimsAttr getParDimsAttr(Operation *op) {
172 [](auto parOp) { return parOp.getParDimsAttr(); })
173 .Default([](Operation *op) -> GPUParallelDimsAttr {
174 if (Attribute attr = op->getAttr(GPUParallelDimsAttr::name)) {
175 GPUParallelDimsAttr parDimsAttr = dyn_cast<GPUParallelDimsAttr>(attr);
176 assert(parDimsAttr && "acc.par_dims must be a GPUParallelDimsAttr");
177 return parDimsAttr;
178 }
179 return nullptr;
180 });
181}
182
183bool hasParDimsAttr(Operation *op) { return getParDimsAttr(op) != nullptr; }
184
186 if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(op))
187 return parDimsAttr.isSeq();
188 return false;
189}
190
191void setParDimsAttr(Operation *op, GPUParallelDimsAttr attr) {
192 assert(!hasParDimsAttr(op) && "parallel dimensions attribute is already set");
195 [&](auto parOp) { parOp.setParDimsAttr(attr); })
196 .Default(
197 [&](Operation *op) { op->setAttr(GPUParallelDimsAttr::name, attr); });
198}
199
200void updateParDimsAttr(Operation *op, GPUParallelDimsAttr attr) {
201 assert(hasParDimsAttr(op) &&
202 "expected parallel dimensions attribute to already be set");
205 [&](auto parOp) { parOp.setParDimsAttr(attr); })
206 .Default(
207 [&](Operation *op) { op->setAttr(GPUParallelDimsAttr::name, attr); });
208}
209
210#undef ACC_OP_WITH_PAR_DIMS_LIST
211
213 return op->hasAttrOfType<GPUBlockRedundantAttr>(GPUBlockRedundantAttr::name);
214}
215
217 op->setAttr(GPUBlockRedundantAttr::name,
218 GPUBlockRedundantAttr::get(op->getContext()));
219}
220
222 assert(hasParDimsAttr(from) &&
223 "expected parallel dimensions attribute to already be set");
225}
226
228 assert(alignment > 0 && llvm::isPowerOf2_64(alignment) &&
229 "alignment must be a power of two");
230 return (offset + alignment - 1) & ~(alignment - 1);
231}
232
234 int64_t aligned = alignOffset(bytesUsed_, alignment);
235 if (aligned + bytes > maxTotalBytes_) {
236 return false;
237 }
238 bytesUsed_ = aligned + bytes;
239 return true;
240}
241
243 int64_t total = 0;
244 region.walk([&](GPUSharedMemoryOp op) {
245 int64_t upperBound = op.getStaticUpperBoundBytes();
246 total = SharedMemoryBudget::alignOffset(total) + upperBound;
247 });
248 return total;
249}
250
251PrivatizeOp getPrivatizeOp(PrivateLocalOp privateLocal,
252 ComputeRegionOp computeRegion) {
253 Value value = privateLocal.getPrivatized();
254 if (BlockArgument blockArg = dyn_cast<BlockArgument>(value)) {
255 auto owner = dyn_cast<ComputeRegionOp>(blockArg.getOwner()->getParentOp());
256 value = (owner ? owner : computeRegion).getOperand(blockArg);
257 }
258 PrivatizeOp privatizeOp = value.getDefiningOp<PrivatizeOp>();
259 assert(privatizeOp && "expected privatize op to be the defining op");
260 return privatizeOp;
261}
262
263static bool isThreadXPrivatize(PrivatizeOp privatize) {
264 if (GPUParallelDimsAttr parDimsAttr = privatize.getParDimsAttr())
265 return llvm::any_of(parDimsAttr.getArray(),
266 [](GPUParallelDimAttr d) { return d.isThreadX(); });
267 return false;
268}
269
270MemRefType getPrivateBaseMemRefType(Type baseTy, ModuleOp module) {
271 auto memrefTy = cast<PointerLikeType>(baseTy).getAsMemRefType(module);
272 assert(memrefTy && "private base type must be convertible to memref");
273 return memrefTy;
274}
275
277collectPrivateLocalParDims(PrivateLocalOp privateLocal,
278 ComputeRegionOp computeRegion) {
280 // Walk the enclosing scf.parallel loops, but stop at the compute region
281 // boundary: loops outside the compute region do not contribute parallel
282 // dimensions to this privatization.
283 auto parentLoop = privateLocal->getParentOfType<scf::ParallelOp>();
284 while (parentLoop && computeRegion->isProperAncestor(parentLoop)) {
285 if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(parentLoop))
286 for (GPUParallelDimAttr parDim : parDimsAttr.getArray())
287 insertParDim(parDims, parDim);
288 parentLoop = parentLoop->getParentOfType<scf::ParallelOp>();
289 }
290 if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(computeRegion))
291 for (GPUParallelDimAttr parDim : parDimsAttr.getArray())
292 insertParDim(parDims, parDim);
293 if (parDims.empty()) {
294 for (GPUParallelDimAttr parDim : computeRegion.getLaunchParDims()) {
295 if (parDim.isAnyBlock())
296 insertParDim(parDims, parDim);
297 }
298 }
299
300 for (Operation *user : privateLocal.getResult().getUsers()) {
301 if (auto accumulateOp = dyn_cast<ReductionAccumulateOp>(user)) {
302 if (accumulateOp.getMemref() == privateLocal.getResult())
303 for (GPUParallelDimAttr parDim : accumulateOp.getParDims().getArray())
304 insertParDim(parDims, parDim);
305 }
306 if (auto combineOp = dyn_cast<ReductionCombineOp>(user)) {
307 if (combineOp.getSrcMemref() == privateLocal.getResult())
308 for (GPUParallelDimAttr parDim : getReductionCombineParDims(combineOp))
309 insertParDim(parDims, parDim);
310 }
311 if (auto combineRegionOp = dyn_cast<ReductionCombineRegionOp>(user)) {
312 if (combineRegionOp.getSrcVar() == privateLocal.getResult())
313 for (GPUParallelDimAttr parDim :
314 getReductionCombineParDims(combineRegionOp))
315 insertParDim(parDims, parDim);
316 }
317 }
318 return parDims;
319}
320
321static FailureOr<std::optional<int64_t>> getWorkerPrivateSharedMemoryNumCopies(
322 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion,
323 bool isWorkerPrivate, OpenACCSupport *support) {
324 if (!isWorkerPrivate)
325 return std::optional<int64_t>(1);
326
327 GPUParallelDimAttr threadY =
328 GPUParallelDimAttr::threadYDim(privateLocal.getContext());
329 std::optional<Value> workerArg = computeRegion.getKnownLaunchArg(threadY);
330 if (!workerArg)
331 return std::optional<int64_t>();
332
333 auto workerArgConst = workerArg->getDefiningOp<arith::ConstantIndexOp>();
334 if (workerArgConst)
335 return std::optional<int64_t>(workerArgConst.value());
336
337 FailureOr<int64_t> workerArgBound =
339 *workerArg);
340 if (succeeded(workerArgBound))
341 return std::optional<int64_t>(*workerArgBound);
342
343 if (support) {
344 (void)support->emitNYI(privateLocal.getLoc(),
345 "worker-private variables in shared memory "
346 "require compile-time constant num_workers");
347 return failure();
348 }
349 return std::optional<int64_t>();
350}
351
353 auto funcOp = op->getParentOfType<FunctionOpInterface>();
354 return funcOp && isSpecializedAccRoutine(funcOp);
355}
356
358 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module,
359 const ACCToGPUMappingPolicy &policy, OpenACCSupport *support) {
360 if (isInsideACCSpecializedRoutine(computeRegion))
361 return false;
362
363 if (isThreadXPrivatize(getPrivatizeOp(privateLocal, computeRegion)))
364 return false;
365
366 bool isReductionAccumulator =
367 llvm::any_of(privateLocal.getResult().getUsers(), [](Operation *user) {
368 return isa<ReductionAccumulateOp>(user);
369 });
370
372 collectPrivateLocalParDims(privateLocal, computeRegion);
373 bool isGangPrivate =
374 llvm::any_of(parDims, [&](auto parDim) { return policy.isGang(parDim); });
375 bool isWorkerPrivate = llvm::any_of(
376 parDims, [&](auto parDim) { return policy.isWorker(parDim); });
377 bool isVectorPrivate = llvm::any_of(
378 parDims, [&](auto parDim) { return policy.isVector(parDim); });
379
380 auto baseTy = getPrivateBaseMemRefType(
381 cast<PrivateType>(privateLocal.getPrivatized().getType()).getBaseTy(),
382 module);
383
384 bool isBlockLevelPrivate =
385 !isVectorPrivate &&
386 (isGangPrivate ||
387 (isWorkerPrivate && baseTy.getRank() > 0 && !isReductionAccumulator));
388 if (!isBlockLevelPrivate)
389 return false;
390
391 for (int64_t dim : baseTy.getShape())
392 if (dim == ShapedType::kDynamic)
393 return false;
394
395 auto resultMemRefTy = dyn_cast<MemRefType>(privateLocal.getType());
396 if (!resultMemRefTy || !resultMemRefTy.getLayout().isIdentity() ||
397 resultMemRefTy.getMemorySpace())
398 return false;
399
400 if (isGangPrivate && isWorkerPrivate && !isReductionAccumulator)
401 return false;
402
403 FailureOr<std::optional<int64_t>> numCopies =
404 getWorkerPrivateSharedMemoryNumCopies(privateLocal, computeRegion,
405 isWorkerPrivate, support);
406 if (failed(numCopies))
407 return failure();
408 return numCopies->has_value();
409}
410
412 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module,
413 const ACCToGPUMappingPolicy &policy, OpenACCSupport *support) {
414 FailureOr<bool> isCandidate = isPrivateLocalSharedMemoryCandidate(
415 privateLocal, computeRegion, module, policy);
416 if (failed(isCandidate) || !*isCandidate)
417 return std::nullopt;
418
420 collectPrivateLocalParDims(privateLocal, computeRegion);
421 bool isWorkerPrivate = llvm::any_of(
422 parDims, [&](auto parDim) { return policy.isWorker(parDim); });
423
424 FailureOr<std::optional<int64_t>> numCopies =
426 privateLocal, computeRegion, isWorkerPrivate, /*support=*/nullptr);
427 if (failed(numCopies) || !numCopies->has_value())
428 return std::nullopt;
429
430 auto baseTy = getPrivateBaseMemRefType(
431 cast<PrivateType>(privateLocal.getPrivatized().getType()).getBaseTy(),
432 module);
433 std::optional<TypeSizeAndAlignment> elementSizeAndAlignment =
434 getTypeSizeAndAlignment(baseTy.getElementType(), module, support);
435 if (!elementSizeAndAlignment)
436 return std::nullopt;
437
438 int64_t numElements = 1;
439 for (int64_t dim : baseTy.getShape())
440 numElements *= dim;
441 return elementSizeAndAlignment->first.getFixedValue() * numElements *
442 numCopies->value();
443}
444
445} // namespace acc
446} // namespace mlir
lhs
#define ACC_OP_WITH_PAR_DIMS_LIST
Attributes are known-constant values of operations.
Definition Attributes.h:25
This class represents an argument of a Block.
Definition Value.h:306
Block represents an ordered list of Operations.
Definition Block.h:33
BlockArgument getArgument(unsigned i)
Definition Block.h:153
OpListType & getOperations()
Definition Block.h:161
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition Block.cpp:158
IndexType getIndexType()
Definition Builders.cpp:59
The main mechanism for performing data layout queries.
A symbol reference with a reference path containing a single element.
This is a utility class for mapping one set of IR entities to another.
Definition IRMapping.h:26
auto lookup(T from) const
Lookup a mapped value within the map.
Definition IRMapping.h:72
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
Definition IRMapping.h:30
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
RAII guard to reset the insertion point of the builder when destroyed.
Definition Builders.h:351
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Definition Builders.cpp:439
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
Definition Builders.cpp:571
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Definition Builders.h:439
This class provides the API for ops that are known to be terminators.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Definition Operation.h:559
bool hasAttrOfType(NameT &&name)
Definition Operation.h:600
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition Operation.h:251
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
Definition Operation.h:607
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
Block & front()
Definition Region.h:65
BlockListType & getBlocks()
Definition Region.h:45
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
Definition Region.h:312
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, const Variable &var, const StopConditionFn &stopCondition=nullptr, ValueBoundsOptions options={})
Compute a constant bound for the given variable.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
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
virtual bool isWorker(ParDimAttrT attr) const =0
Check if the attribute represents worker parallelism.
virtual bool isVector(ParDimAttrT attr) const =0
Check if the attribute represents vector parallelism.
virtual bool isGang(ParDimAttrT attr) const =0
Check if the attribute represents gang parallelism (any gang dimension).
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
bool tryAllocate(int64_t bytes, int64_t alignment=kDefaultAlignmentBytes)
Reserve bytes, rounding the current offset up to alignment first.
static int64_t alignOffset(int64_t offset, int64_t alignment=kDefaultAlignmentBytes)
Round offset up to the next multiple of alignment, which must be a power of two.
Specialization of arith.constant op that returns an integer of index type.
Definition Arith.h:114
GPUParallelDimsAttr getParDimsAttr(Operation *op)
Obtain the parallel dimensions carried by op, if any.
std::optional< DataLayout > getDataLayout(Operation *op, bool allowDefault=true)
Get the data layout for an operation.
MemRefType getPrivateBaseMemRefType(Type baseTy, ModuleOp module)
Returns the ranked MemRef type used to allocate privatized storage.
SmallVector< GPUParallelDimAttr > getReductionCombineParDims(ReductionCombineOp op)
Returns the parallel dimensions that participate in op's combine step.
void insertParDim(llvm::SmallVector< GPUParallelDimAttr > &parDims, GPUParallelDimAttr parDim)
Insert parDim into parDims while preserving dimension ordering.
bool hasParDimsAttr(Operation *op)
Return whether op carries parallel dimensions.
ComputeRegionOp buildComputeRegion(Location loc, ValueRange launchArgs, ValueRange inputArgs, llvm::StringRef origin, Region &regionToClone, RewriterBase &rewriter, IRMapping &mapping, ValueRange output={}, FlatSymbolRefAttr kernelFuncName={}, FlatSymbolRefAttr kernelModuleName={}, Value stream={}, ValueRange inputArgsToMap={})
Build an acc.compute_region operation by cloning a source region.
void setGPUBlockRedundantAttr(Operation *op)
Mark op with the acc.gpu_block_redundant attribute.
static FailureOr< std::optional< int64_t > > getWorkerPrivateSharedMemoryNumCopies(PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, bool isWorkerPrivate, OpenACCSupport *support)
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
Definition OpenACC.h:201
static bool isInsideACCSpecializedRoutine(Operation *op)
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl, OpenACCSupport *support=nullptr)
Returns the size and ABI alignment in bytes.
FailureOr< bool > isPrivateLocalSharedMemoryCandidate(PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module, const ACCToGPUMappingPolicy &policy, OpenACCSupport *support=nullptr)
True when privateLocal may be placed in shared memory.
int64_t sumExistingSharedMemoryBytes(Region &region)
Sum aligned static_upper_bound_bytes for all acc.gpu_shared_memory in region.
scf::ExecuteRegionOp wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping, Location loc, RewriterBase &rewriter)
Wrap a multi-block region in an scf.execute_region.
void updateParDimsAttr(Operation *op, GPUParallelDimsAttr attr)
Update parallel dimensions on op.
PrivatizeOp getPrivatizeOp(PrivateLocalOp privateLocal, ComputeRegionOp computeRegion)
Resolve the acc.privatize operation associated with a private local.
bool hasSeqParDims(Operation *op)
Return whether op carries sequential parallel dimensions.
void copyParDimsAttr(Operation *from, Operation *to)
Copy parallel dimensions from from to to.
bool hasGPUBlockRedundantAttr(Operation *op)
Return whether op is marked with the acc.gpu_block_redundant attribute, i.e.
void removeParDim(llvm::SmallVector< GPUParallelDimAttr > &parDims, GPUParallelDimAttr parDim)
Remove parDim from parDims if present.
void setParDimsAttr(Operation *op, GPUParallelDimsAttr attr)
Set parallel dimensions on op.
std::optional< int64_t > getPrivateLocalSharedMemoryUpperBoundBytes(PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module, const ACCToGPUMappingPolicy &policy, OpenACCSupport *support=nullptr)
Upper-bound byte size for a shared-memory private_local candidate, or std::nullopt when not eligible ...
static bool isThreadXPrivatize(PrivatizeOp privatize)
static SmallVector< GPUParallelDimAttr >::iterator findParDim(SmallVector< GPUParallelDimAttr > &parDims, GPUParallelDimAttr parDim)
SmallVector< GPUParallelDimAttr > collectPrivateLocalParDims(PrivateLocalOp privateLocal, ComputeRegionOp computeRegion)
Collect parallel dimensions that govern privatization of privateLocal.
ACCParMappingPolicy< mlir::acc::GPUParallelDimAttr > ACCToGPUMappingPolicy
Type alias for the GPU-specific mapping policy.
Include the generated interface declarations.