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
227ActiveParDimsAttr getActiveParDimsAttr(Operation *op) {
228 return op->getAttrOfType<ActiveParDimsAttr>(ActiveParDimsAttr::name);
229}
230
232 return getActiveParDimsAttr(op) != nullptr;
233}
234
235void setActiveParDimsAttr(Operation *op, ActiveParDimsAttr attr) {
236 op->setAttr(ActiveParDimsAttr::name, attr);
237}
238
240 setActiveParDimsAttr(op, ActiveParDimsAttr::get(op->getContext(), dims));
241}
242
244 assert(alignment > 0 && llvm::isPowerOf2_64(alignment) &&
245 "alignment must be a power of two");
246 return (offset + alignment - 1) & ~(alignment - 1);
247}
248
250 int64_t aligned = alignOffset(bytesUsed_, alignment);
251 if (aligned + bytes > maxTotalBytes_) {
252 return false;
253 }
254 bytesUsed_ = aligned + bytes;
255 return true;
256}
257
259 int64_t total = 0;
260 region.walk([&](GPUSharedMemoryOp op) {
261 int64_t upperBound = op.getStaticUpperBoundBytes();
262 total = SharedMemoryBudget::alignOffset(total) + upperBound;
263 });
264 return total;
265}
266
267PrivatizeOp getPrivatizeOp(PrivateLocalOp privateLocal,
268 ComputeRegionOp computeRegion) {
269 Value value = privateLocal.getPrivatized();
270 if (BlockArgument blockArg = dyn_cast<BlockArgument>(value)) {
271 auto owner = dyn_cast<ComputeRegionOp>(blockArg.getOwner()->getParentOp());
272 value = (owner ? owner : computeRegion).getOperand(blockArg);
273 }
274 PrivatizeOp privatizeOp = value.getDefiningOp<PrivatizeOp>();
275 assert(privatizeOp && "expected privatize op to be the defining op");
276 return privatizeOp;
277}
278
279static bool isThreadXPrivatize(PrivatizeOp privatize) {
280 if (GPUParallelDimsAttr parDimsAttr = privatize.getParDimsAttr())
281 return llvm::any_of(parDimsAttr.getArray(),
282 [](GPUParallelDimAttr d) { return d.isThreadX(); });
283 return false;
284}
285
286MemRefType getPrivateBaseMemRefType(Type baseTy, ModuleOp module) {
287 auto memrefTy = cast<PointerLikeType>(baseTy).getAsMemRefType(module);
288 assert(memrefTy && "private base type must be convertible to memref");
289 return memrefTy;
290}
291
293collectPrivateLocalParDims(PrivateLocalOp privateLocal,
294 ComputeRegionOp computeRegion) {
296 // Walk the enclosing scf.parallel loops, but stop at the compute region
297 // boundary: loops outside the compute region do not contribute parallel
298 // dimensions to this privatization.
299 auto parentLoop = privateLocal->getParentOfType<scf::ParallelOp>();
300 while (parentLoop && computeRegion->isProperAncestor(parentLoop)) {
301 if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(parentLoop))
302 for (GPUParallelDimAttr parDim : parDimsAttr.getArray())
303 insertParDim(parDims, parDim);
304 parentLoop = parentLoop->getParentOfType<scf::ParallelOp>();
305 }
306 if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(computeRegion))
307 for (GPUParallelDimAttr parDim : parDimsAttr.getArray())
308 insertParDim(parDims, parDim);
309 if (parDims.empty()) {
310 for (GPUParallelDimAttr parDim : computeRegion.getLaunchParDims()) {
311 if (parDim.isAnyBlock())
312 insertParDim(parDims, parDim);
313 }
314 }
315
316 for (Operation *user : privateLocal.getResult().getUsers()) {
317 if (auto accumulateOp = dyn_cast<ReductionAccumulateOp>(user)) {
318 if (accumulateOp.getMemref() == privateLocal.getResult())
319 for (GPUParallelDimAttr parDim : accumulateOp.getParDims().getArray())
320 insertParDim(parDims, parDim);
321 }
322 if (auto combineOp = dyn_cast<ReductionCombineOp>(user)) {
323 if (combineOp.getSrcMemref() == privateLocal.getResult())
324 for (GPUParallelDimAttr parDim : getReductionCombineParDims(combineOp))
325 insertParDim(parDims, parDim);
326 }
327 if (auto combineRegionOp = dyn_cast<ReductionCombineRegionOp>(user)) {
328 if (combineRegionOp.getSrcVar() == privateLocal.getResult())
329 for (GPUParallelDimAttr parDim :
330 getReductionCombineParDims(combineRegionOp))
331 insertParDim(parDims, parDim);
332 }
333 }
334 return parDims;
335}
336
337static FailureOr<std::optional<int64_t>> getWorkerPrivateSharedMemoryNumCopies(
338 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion,
339 bool isWorkerPrivate, OpenACCSupport *support) {
340 if (!isWorkerPrivate)
341 return std::optional<int64_t>(1);
342
343 GPUParallelDimAttr threadY =
344 GPUParallelDimAttr::threadYDim(privateLocal.getContext());
345 std::optional<Value> workerArg = computeRegion.getKnownLaunchArg(threadY);
346 if (!workerArg)
347 return std::optional<int64_t>();
348
349 auto workerArgConst = workerArg->getDefiningOp<arith::ConstantIndexOp>();
350 if (workerArgConst)
351 return std::optional<int64_t>(workerArgConst.value());
352
353 FailureOr<int64_t> workerArgBound =
355 *workerArg);
356 if (succeeded(workerArgBound))
357 return std::optional<int64_t>(*workerArgBound);
358
359 if (support) {
360 (void)support->emitNYI(privateLocal.getLoc(),
361 "worker-private variables in shared memory "
362 "require compile-time constant num_workers");
363 return failure();
364 }
365 return std::optional<int64_t>();
366}
367
369 auto funcOp = op->getParentOfType<FunctionOpInterface>();
370 return funcOp && isSpecializedAccRoutine(funcOp);
371}
372
374 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module,
375 const ACCToGPUMappingPolicy &policy, OpenACCSupport *support) {
376 if (isInsideACCSpecializedRoutine(computeRegion))
377 return false;
378
379 if (isThreadXPrivatize(getPrivatizeOp(privateLocal, computeRegion)))
380 return false;
381
382 bool isReductionAccumulator =
383 llvm::any_of(privateLocal.getResult().getUsers(), [](Operation *user) {
384 return isa<ReductionAccumulateOp>(user);
385 });
386
388 collectPrivateLocalParDims(privateLocal, computeRegion);
389 bool isGangPrivate =
390 llvm::any_of(parDims, [&](auto parDim) { return policy.isGang(parDim); });
391 bool isWorkerPrivate = llvm::any_of(
392 parDims, [&](auto parDim) { return policy.isWorker(parDim); });
393 bool isVectorPrivate = llvm::any_of(
394 parDims, [&](auto parDim) { return policy.isVector(parDim); });
395
396 auto baseTy = getPrivateBaseMemRefType(
397 cast<PrivateType>(privateLocal.getPrivatized().getType()).getBaseTy(),
398 module);
399
400 bool isBlockLevelPrivate =
401 !isVectorPrivate &&
402 (isGangPrivate ||
403 (isWorkerPrivate && baseTy.getRank() > 0 && !isReductionAccumulator));
404 if (!isBlockLevelPrivate)
405 return false;
406
407 for (int64_t dim : baseTy.getShape())
408 if (dim == ShapedType::kDynamic)
409 return false;
410
411 auto resultMemRefTy = dyn_cast<MemRefType>(privateLocal.getType());
412 if (!resultMemRefTy || !resultMemRefTy.getLayout().isIdentity() ||
413 resultMemRefTy.getMemorySpace())
414 return false;
415
416 if (isGangPrivate && isWorkerPrivate && !isReductionAccumulator)
417 return false;
418
419 FailureOr<std::optional<int64_t>> numCopies =
420 getWorkerPrivateSharedMemoryNumCopies(privateLocal, computeRegion,
421 isWorkerPrivate, support);
422 if (failed(numCopies))
423 return failure();
424 return numCopies->has_value();
425}
426
428 PrivateLocalOp privateLocal, ComputeRegionOp computeRegion, ModuleOp module,
429 const ACCToGPUMappingPolicy &policy, OpenACCSupport *support) {
430 FailureOr<bool> isCandidate = isPrivateLocalSharedMemoryCandidate(
431 privateLocal, computeRegion, module, policy);
432 if (failed(isCandidate) || !*isCandidate)
433 return std::nullopt;
434
436 collectPrivateLocalParDims(privateLocal, computeRegion);
437 bool isWorkerPrivate = llvm::any_of(
438 parDims, [&](auto parDim) { return policy.isWorker(parDim); });
439
440 FailureOr<std::optional<int64_t>> numCopies =
442 privateLocal, computeRegion, isWorkerPrivate, /*support=*/nullptr);
443 if (failed(numCopies) || !numCopies->has_value())
444 return std::nullopt;
445
446 auto baseTy = getPrivateBaseMemRefType(
447 cast<PrivateType>(privateLocal.getPrivatized().getType()).getBaseTy(),
448 module);
449 std::optional<TypeSizeAndAlignment> elementSizeAndAlignment =
450 getTypeSizeAndAlignment(baseTy.getElementType(), module, support);
451 if (!elementSizeAndAlignment)
452 return std::nullopt;
453
454 int64_t numElements = 1;
455 for (int64_t dim : baseTy.getShape())
456 numElements *= dim;
457 return elementSizeAndAlignment->first.getFixedValue() * numElements *
458 numCopies->value();
459}
460
461} // namespace acc
462} // 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
AttrClass getAttrOfType(StringAttr name)
Definition Operation.h:575
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 setActiveParDimsAttr(Operation *op, ActiveParDimsAttr attr)
Set active parallel dimensions on op.
void insertParDim(llvm::SmallVector< GPUParallelDimAttr > &parDims, GPUParallelDimAttr parDim)
Insert parDim into parDims while preserving dimension ordering.
bool hasActiveParDimsAttr(Operation *op)
Return whether op carries active parallel dimensions.
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.
ActiveParDimsAttr getActiveParDimsAttr(Operation *op)
Obtain the active parallel dimensions carried by op, if any.
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.