MLIR 24.0.0git
ACCComputeLowering.cpp
Go to the documentation of this file.
1//===- ACCComputeLowering.cpp - Lower ACC compute to compute_region -------===//
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 pass decomposes OpenACC compute constructs into a representation that
10// separates the data environment from the compute portion and prepares for
11// parallelism assignment and privatization at the appropriate level.
12//
13// Overview:
14// ---------
15// Each compute construct (`acc.parallel`, `acc.serial`, `acc.kernels`) is
16// lowered to (1) `acc.kernel_environment`, which captures the data environment
17// and (2) `acc.compute_region`, which holds the compute body. Inside the
18// compute region, acc.loop is converted to SCF loops (`scf.parallel` or
19// `scf.for`) with any predetermined parallelism expressed as `par_dims`. This
20// decomposition allows later phases to assign parallelism and handle
21// privatization at the right granularity.
22//
23// Transformations:
24// ----------------
25// 1. Compute constructs: acc.parallel, acc.serial, and acc.kernels are
26// replaced by acc.kernel_environment containing a single acc.compute_region.
27// For acc.parallel / acc.kernels, launch arguments (num_gangs, num_workers,
28// vector_length) become acc.par_width ops (each result is `index`) and are
29// passed as compute_region launch operands. Compute regions with
30// num_gangs(1), num_workers(1), and vector_length(1) and acc serial use a
31// single sequential acc.par_width launch operand.
32//
33// 2. acc.loop: Converted according to context and attributes:
34// - Unstructured: body wrapped in scf.execute_region.
35// - Sequential (serial region, seq clause, or compute region with
36// num_gangs(1), num_workers(1), and vector_length(1)):
37// scf.parallel with par_dims = sequential.
38// - Auto (in parallel/kernels): scf.for with collapse when
39// multi-dimensional.
40// - Orphan (not inside a compute construct): scf.for, no collapse.
41// - Independent (in parallel/kernels): scf.parallel with par_dims from
42// gang/worker/vector mapping (e.g. block_x).
43//
44//===----------------------------------------------------------------------===//
45
47
57#include "mlir/IR/IRMapping.h"
58#include "mlir/IR/Matchers.h"
62#include "llvm/ADT/DenseMap.h"
63#include "llvm/ADT/STLExtras.h"
64
65namespace mlir {
66namespace acc {
67#define GEN_PASS_DEF_ACCCOMPUTELOWERING
68#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
69} // namespace acc
70} // namespace mlir
71
72#define DEBUG_TYPE "acc-compute-lowering"
73
74using namespace mlir;
75using namespace mlir::acc;
76
77namespace {
78
79//===----------------------------------------------------------------------===//
80// Helper functions
81//===----------------------------------------------------------------------===//
82
83static bool isOpInComputeRegion(Operation *op) {
84 Region *region = op->getBlock()->getParent();
85 return getEnclosingComputeOp(*region) != nullptr;
86}
87
88static bool isOpInSerialRegion(Operation *op) {
89 if (auto parallelOp = op->getParentOfType<ParallelOp>())
90 return parallelOp.isEffectivelySerial();
91 if (auto kernelsOp = op->getParentOfType<KernelsOp>())
92 return kernelsOp.isEffectivelySerial();
93 if (op->getParentOfType<SerialOp>())
94 return true;
95 if (auto computeRegion = op->getParentOfType<ComputeRegionOp>())
96 return computeRegion.isEffectivelySerial();
97 if (auto funcOp = op->getParentOfType<FunctionOpInterface>()) {
98 if (isSpecializedAccRoutine(funcOp)) {
99 auto attr = funcOp->getDiscardableAttrOfType<SpecializedRoutineAttr>(
101 if (attr && attr.getLevel().getValue() == ParLevel::seq)
102 return true;
103 }
104 }
105 return false;
106}
107
108/// Clone defining ops of constant live-in values into `region`, rewrite uses
109/// inside the region to the clones, and remove those values from
110/// `liveInValues` so they are not threaded through `acc.compute_region` ins.
111static void materializeConstantLiveInsIntoRegion(Region &region,
112 SetVector<Value> &liveInValues,
113 RewriterBase &rewriter) {
114 SmallVector<Value> constantLiveIns;
115 for (Value v : liveInValues) {
116 Operation *defOp = v.getDefiningOp();
117 if (defOp && matchPattern(defOp, m_Constant())) {
118 // As per the definition of ConstantLike trait, constants must have a
119 // single result.
120 assert(defOp->getNumResults() == 1 &&
121 "constants must have a single result");
122 constantLiveIns.push_back(v);
123 }
124 }
125 if (constantLiveIns.empty())
126 return;
127
128 OpBuilder::InsertionGuard guard(rewriter);
129 rewriter.setInsertionPointToStart(&region.front());
130
131 for (Value v : constantLiveIns) {
132 Value newV = rewriter.clone(*v.getDefiningOp())->getResult(0);
133 replaceAllUsesInRegionWith(v, newV, region);
134 liveInValues.remove(v);
135 }
136}
137
138/// Return the device type from which gang/worker/vector clauses should be read.
139/// If the requested device type has any such clauses, use that exclusively;
140/// otherwise fall back to the default (DeviceType::None).
141static DeviceType getGangWorkerVectorDeviceType(LoopOp loopOp,
142 DeviceType deviceType) {
143 if (deviceType != DeviceType::None &&
144 loopOp.hasAnyGangWorkerVector(deviceType))
145 return deviceType;
146 return DeviceType::None;
147}
148
149template <typename ComputeConstructT>
150static DeviceType getParDimsDeviceType(ComputeConstructT computeOp,
151 DeviceType deviceType) {
152 if (deviceType != DeviceType::None &&
153 computeOp.hasAnyGangWorkerVector(deviceType))
154 return deviceType;
155 return DeviceType::None;
156}
157
158/// Constant sized gang/worker/vector clauses collected per compute construct.
159struct SizedLevel {
160 ParLevel level;
161 int64_t size;
162};
164
165/// Record a sized clause if `size` is a constant; NYI otherwise.
166static LogicalResult tryAddSizedLevel(SizedLevelMap &sizedLevelMap,
167 Operation *computeOp, LoopOp loopOp,
168 ParLevel level, Value size,
169 OpenACCSupport &accSupport) {
170 if (!size)
171 return success();
172 std::optional<int64_t> constSize = getConstantIntValue(size);
173 if (!constSize) {
174 accSupport.emitNYI(loopOp.getLoc(),
175 "non-constant sized parallelism clause");
176 return failure();
177 }
178 sizedLevelMap[computeOp].push_back({level, *constSize});
179 return success();
180}
181
182/// Collect constant sized levels from loops in `acc.kernels` regions.
183static LogicalResult fillSizedLevelMap(Operation *op, DeviceType deviceType,
184 SizedLevelMap &sizedLevelMap,
185 OpenACCSupport &accSupport) {
186 WalkResult result = op->walk([&](LoopOp loopOp) {
187 Operation *computeOp =
188 getEnclosingComputeOp(*loopOp->getBlock()->getParent());
189 if (!computeOp || !isa<KernelsOp>(computeOp))
190 return WalkResult::advance();
191 DeviceType loopDeviceType =
192 getGangWorkerVectorDeviceType(loopOp, deviceType);
193 if (failed(tryAddSizedLevel(
194 sizedLevelMap, computeOp, loopOp, ParLevel::vector,
195 loopOp.getVectorValue(loopDeviceType), accSupport)) ||
196 failed(tryAddSizedLevel(
197 sizedLevelMap, computeOp, loopOp, ParLevel::worker,
198 loopOp.getWorkerValue(loopDeviceType), accSupport)) ||
199 failed(tryAddSizedLevel(
200 sizedLevelMap, computeOp, loopOp, ParLevel::gang_dim1,
201 loopOp.getGangValue(GangArgType::Num, loopDeviceType), accSupport)))
202 return WalkResult::interrupt();
203 return WalkResult::advance();
204 });
205 return failure(result.wasInterrupted());
206}
207
208/// Map loop parallelism clauses (gang/worker/vector) to GPU parallel
209/// dimensions using the given mapping policy. Sized clauses (e.g. vector(n))
210/// count as the corresponding level.
212getParallelDimensions(LoopOp loopOp, const ACCToGPUMappingPolicy &policy,
213 DeviceType deviceType) {
214 deviceType = getGangWorkerVectorDeviceType(loopOp, deviceType);
216 auto *ctx = loopOp->getContext();
217
218 if (loopOp.hasVector(deviceType) || loopOp.getVectorValue(deviceType))
219 insertParDim(parDims, policy.vectorDim(ctx));
220 if (loopOp.hasWorker(deviceType) || loopOp.getWorkerValue(deviceType))
221 insertParDim(parDims, policy.workerDim(ctx));
222 if (auto gangDimValue = loopOp.getGangValue(GangArgType::Dim, deviceType)) {
223 if (auto gangDimDefOp =
224 gangDimValue.getDefiningOp<arith::ConstantIntOp>()) {
225 auto gangLevel = getGangParLevel(gangDimDefOp.value());
226 insertParDim(parDims, policy.gangDim(ctx, gangLevel));
227 }
228 } else if (loopOp.hasGang(deviceType) ||
229 loopOp.getGangValue(GangArgType::Num, deviceType) ||
230 loopOp.getGangValue(GangArgType::Static, deviceType)) {
231 insertParDim(parDims, policy.gangDim(ctx, ParLevel::gang_dim1));
232 }
233 return parDims;
234}
235
236/// If \p loopOp has a `gang(static:)` value, return the corresponding
237/// `acc.chunk_size` attribute. A constant size is stored directly; a
238/// non-constant size is recorded as -1, the same encoding as `static:*`.
239/// Returns a null attribute when the clause is absent.
240static ChunkSizeAttr getChunkSizeFromStatic(LoopOp loopOp,
241 DeviceType deviceType) {
242 DeviceType loopDeviceType = getGangWorkerVectorDeviceType(loopOp, deviceType);
243 Value gangStatic = loopOp.getGangValue(GangArgType::Static, loopDeviceType);
244 if (!gangStatic)
245 return {};
246 std::optional<int64_t> chunkSize = getConstantIntValue(gangStatic);
247 // Non-constant static is treated like `static:*` (implementation-chosen).
248 return ChunkSizeAttr::get(loopOp->getContext(), chunkSize.value_or(-1));
249}
250
251/// Build `acc.compute_region` launch operands: one sequential `acc.par_width`
252/// for `acc.serial`, for `acc.parallel` / `acc.kernels` when every num_gangs
253/// operand and num_workers / vector_length are the constant 1, and otherwise
254/// `acc.par_width` from gang/worker/vector (device-type operands first, then
255/// default DeviceType::None).
256template <typename ComputeConstructT>
257static SmallVector<Value> assignKnownLaunchArgs(
258 ComputeConstructT computeOp, DeviceType deviceType, RewriterBase &rewriter,
259 const ACCToGPUMappingPolicy &policy, const SizedLevelMap &sizedLevelMap) {
260 auto *ctx = rewriter.getContext();
261 auto loc = computeOp->getLoc();
262
263 if constexpr (std::is_same_v<ComputeConstructT, SerialOp>) {
264 return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
265 } else if constexpr (llvm::is_one_of<ComputeConstructT, ParallelOp,
266 KernelsOp>::value) {
267 if (computeOp.isEffectivelySerial())
268 return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
269
270 deviceType = getParDimsDeviceType(computeOp, deviceType);
272 SmallVector<Value> values;
273 auto indexTy = rewriter.getIndexType();
274
275 auto numGangs = computeOp.getNumGangsValues(deviceType);
276 for (auto [gangDimIdx, gangSize] : llvm::enumerate(numGangs)) {
277 auto gangLevel = getGangParLevel(gangDimIdx + 1);
278 values.push_back(ParWidthOp::create(
279 rewriter, loc,
280 getValueOrCreateCastToIndexLike(rewriter, gangSize.getLoc(), indexTy,
281 gangSize),
282 policy.gangDim(ctx, gangLevel)));
284
285 Value numWorkers = computeOp.getNumWorkersValue(deviceType);
286 if (numWorkers) {
287 values.push_back(ParWidthOp::create(
288 rewriter, loc,
289 getValueOrCreateCastToIndexLike(rewriter, numWorkers.getLoc(),
290 indexTy, numWorkers),
291 policy.workerDim(ctx)));
292 }
293
294 Value vectorLength = computeOp.getVectorLengthValue(deviceType);
295 if (vectorLength) {
296 values.push_back(ParWidthOp::create(
297 rewriter, loc,
298 getValueOrCreateCastToIndexLike(rewriter, vectorLength.getLoc(),
299 indexTy, vectorLength),
300 policy.vectorDim(ctx)));
301 }
303 // Loop-level sized clauses. Skip a dim already set on the construct.
304 // Rematerialize the constant here so it dominates the compute region.
305 auto sizedLevels = sizedLevelMap.find(computeOp.getOperation());
306 if (sizedLevels != sizedLevelMap.end()) {
307 for (const SizedLevel &sizedLevel : sizedLevels->second) {
308 GPUParallelDimAttr dim = policy.map(ctx, sizedLevel.level);
309 bool exists = llvm::any_of(values, [&](Value v) {
310 auto parWidth = v.getDefiningOp<ParWidthOp>();
311 return parWidth && parWidth.getParDim() == dim;
312 });
313 if (exists)
314 continue;
315 Value sizeVal =
316 arith::ConstantIndexOp::create(rewriter, loc, sizedLevel.size);
317 values.push_back(ParWidthOp::create(rewriter, loc, sizeVal, dim));
318 }
319 }
320 return values;
321 } else {
322 llvm_unreachable("assignKnownLaunchArgs: expected parallel, kernels, or "
323 "serial");
324 }
325}
326
327//===----------------------------------------------------------------------===//
328// Loop conversion pattern
329//===----------------------------------------------------------------------===//
331class ACCLoopConversion : public OpRewritePattern<LoopOp> {
332public:
333 ACCLoopConversion(MLIRContext *ctx, const ACCToGPUMappingPolicy &policy,
334 DeviceType deviceType)
335 : OpRewritePattern<LoopOp>(ctx), policy(policy), deviceType(deviceType) {}
336
337 LogicalResult matchAndRewrite(LoopOp loopOp,
338 PatternRewriter &rewriter) const override {
339 if (loopOp.getUnstructured()) {
340 auto executeRegion =
342 if (!executeRegion)
343 return failure();
344 rewriter.replaceOp(loopOp, executeRegion);
345 return success();
346 }
347
348 LoopParMode parMode = loopOp.getDefaultOrDeviceTypeParallelism(deviceType);
349
350 if (parMode == LoopParMode::loop_seq || isOpInSerialRegion(loopOp)) {
351 // Use scf.for with sequential loops, because the loop's parallelism is
352 // already determined.
353 auto forOp =
354 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/true);
355 if (!forOp)
356 return failure();
357 setParDimsAttr(forOp, GPUParallelDimsAttr::seq(loopOp->getContext()));
358 rewriter.replaceOp(loopOp, forOp);
359 } else if (parMode == LoopParMode::loop_auto) {
360 // All loops in serial regions should have already been handled.
361 assert(!isOpInSerialRegion(loopOp) &&
362 "Expected loop to be in non-serial region");
363 // Mark as scf.for to allow auto-parallelization analysis later.
364 auto forOp =
365 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/true);
366 if (!forOp)
367 return failure();
369 getParallelDimensions(loopOp, policy, deviceType);
370 if (!parDims.empty()) {
371 auto parDimsAttr =
372 GPUParallelDimsAttr::get(loopOp->getContext(), parDims);
373 setParDimsAttr(forOp, parDimsAttr);
374 if (ChunkSizeAttr chunkSize =
375 getChunkSizeFromStatic(loopOp, deviceType))
376 setChunkSizeAttr(forOp, chunkSize);
377 }
378 rewriter.replaceOp(loopOp, forOp);
379 } else if (!isOpInComputeRegion(loopOp) &&
381 loopOp->getParentOfType<FunctionOpInterface>())) {
382 // This loop is an orphan `acc loop` but it is not in any sort
383 // of compute region. Thus it is just a sequential non-accelerator loop.
384 auto forOp =
385 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/false);
386 if (!forOp)
387 return failure();
388 rewriter.replaceOp(loopOp, forOp);
389 } else {
390 assert(parMode == LoopParMode::loop_independent &&
391 "Expected loop to be independent");
392 auto parallelOp = convertACCLoopToSCFParallel(loopOp, rewriter);
393 if (!parallelOp)
394 return failure();
395
396 SmallVector<GPUParallelDimAttr> parDims =
397 getParallelDimensions(loopOp, policy, deviceType);
398 if (!parDims.empty()) {
399 auto parDimsAttr =
400 GPUParallelDimsAttr::get(loopOp->getContext(), parDims);
401 setParDimsAttr(parallelOp, parDimsAttr);
402 if (ChunkSizeAttr chunkSize =
403 getChunkSizeFromStatic(loopOp, deviceType))
404 setChunkSizeAttr(parallelOp, chunkSize);
405 }
406 rewriter.replaceOp(loopOp, parallelOp);
407 }
408 return success();
409 }
410
411private:
412 const ACCToGPUMappingPolicy &policy;
413 DeviceType deviceType;
414};
415
416//===----------------------------------------------------------------------===//
417// Compute construct conversion pattern
418//===----------------------------------------------------------------------===//
419
420template <typename ComputeConstructT>
421class ComputeOpConversion : public OpRewritePattern<ComputeConstructT> {
422public:
423 ComputeOpConversion(MLIRContext *ctx, const ACCToGPUMappingPolicy &policy,
424 DeviceType deviceType, const SizedLevelMap &sizedLevelMap)
425 : OpRewritePattern<ComputeConstructT>(ctx), policy(policy),
426 deviceType(deviceType), sizedLevelMap(sizedLevelMap) {}
427
428 LogicalResult matchAndRewrite(ComputeConstructT computeOp,
429 PatternRewriter &rewriter) const override {
430 rewriter.setInsertionPoint(computeOp);
431 auto kernelEnv =
432 KernelEnvironmentOp::createAndPopulate(computeOp, deviceType, rewriter);
433 auto launchArgs = assignKnownLaunchArgs(computeOp, deviceType, rewriter,
434 policy, sizedLevelMap);
435 Region &region = computeOp.getRegion();
436 SetVector<Value> liveInValues;
437 getUsedValuesDefinedAbove(region, region, liveInValues);
438 materializeConstantLiveInsIntoRegion(region, liveInValues, rewriter);
439 IRMapping mapping;
440 auto computeRegion = buildComputeRegion(
441 computeOp->getLoc(), launchArgs, liveInValues.getArrayRef(),
442 ComputeConstructT::getOperationName(), region, rewriter, mapping);
443 if (!computeRegion) {
444 rewriter.eraseOp(kernelEnv);
445 return failure();
446 }
447 rewriter.eraseOp(computeOp);
448 return success();
449 }
450
451private:
452 const ACCToGPUMappingPolicy &policy;
453 DeviceType deviceType;
454 const SizedLevelMap &sizedLevelMap;
455};
456
457//===----------------------------------------------------------------------===//
458// Pass implementation
459//===----------------------------------------------------------------------===//
460
461class ACCComputeLowering
462 : public acc::impl::ACCComputeLoweringBase<ACCComputeLowering> {
463public:
464 using ACCComputeLoweringBase::ACCComputeLoweringBase;
465
466 void runOnOperation() override {
467 auto op = getOperation();
468 auto *context = op.getContext();
469
470 DefaultACCToGPUMappingPolicy policy;
471 // Collect loop sized levels before loops are rewritten away.
472 SizedLevelMap sizedLevelMap;
473 OpenACCSupport &accSupport = getAnalysis<OpenACCSupport>();
474 if (failed(fillSizedLevelMap(op, deviceType, sizedLevelMap, accSupport)))
475 return signalPassFailure();
476
477 // Part 1: Convert acc.loop to scf.parallel/scf.for while the parent
478 // compute construct is still present (needed to determine conversion
479 // strategy).
480 RewritePatternSet loopPatterns(context);
481 loopPatterns.insert<ACCLoopConversion>(context, policy, deviceType);
482 if (failed(applyPatternsGreedily(op, std::move(loopPatterns))))
483 return signalPassFailure();
484
485 // Part 2: Convert acc.parallel, acc.kernels, and acc.serial to
486 // acc.kernel_environment { acc.compute_region { ... } }.
487 RewritePatternSet computePatterns(context);
488 computePatterns
489 .insert<ComputeOpConversion<ParallelOp>, ComputeOpConversion<KernelsOp>,
490 ComputeOpConversion<SerialOp>>(context, policy, deviceType,
491 sizedLevelMap);
492 if (failed(applyPatternsGreedily(op, std::move(computePatterns))))
493 return signalPassFailure();
494 }
495};
496
497} // namespace
return success()
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Definition Block.cpp:27
MLIRContext * getContext() const
Definition Builders.h:56
IndexType getIndexType()
Definition Builders.cpp:59
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
RAII guard to reset the insertion point of the builder when destroyed.
Definition Builders.h:351
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:581
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition Builders.h:401
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Block * getBlock()
Returns the operation block that contains this operation.
Definition Operation.h:230
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition Operation.h:255
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
Definition Operation.h:849
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
unsigned getNumResults()
Return the number of results held by this operation.
Definition Operation.h:429
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Location getLoc() const
Return the location of this value.
Definition Value.cpp:24
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
A utility result that is used to signal how to proceed with an ongoing walk:
Definition WalkResult.h:29
static WalkResult advance()
Definition WalkResult.h:47
static WalkResult interrupt()
Definition WalkResult.h:46
ParDimAttrT seqDim(MLIRContext *ctx) const
virtual ParDimAttrT map(MLIRContext *ctx, ParLevel level) const =0
Map an OpenACC parallelism level to target dimension.
ParDimAttrT vectorDim(MLIRContext *ctx) const
ParDimAttrT workerDim(MLIRContext *ctx) const
ParDimAttrT gangDim(MLIRContext *ctx, ParLevel level) const
Convenience methods for specific parallelism levels.
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
::mlir::Pass::Option< mlir::acc::DeviceType > deviceType
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Definition ArithOps.cpp:398
Specialization of arith.constant op that returns an integer value.
Definition Arith.h:34
ParLevel getGangParLevel(int64_t gangDimValue)
Convert a gang dimension value (1, 2, or 3) to the corresponding ParLevel.
void insertParDim(llvm::SmallVector< GPUParallelDimAttr > &parDims, GPUParallelDimAttr parDim)
Insert parDim into parDims while preserving dimension ordering.
static constexpr StringLiteral getSpecializedRoutineAttrName()
Definition OpenACC.h:197
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 setChunkSizeAttr(Operation *op, ChunkSizeAttr attr)
Set the acc.chunk_size attribute on op.
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
Definition OpenACC.h:209
scf::ParallelOp convertACCLoopToSCFParallel(LoopOp loopOp, RewriterBase &rewriter)
Convert acc.loop to scf.parallel.
mlir::Operation * getEnclosingComputeOp(mlir::Region &region)
Used to obtain the enclosing compute construct operation that contains the provided region.
scf::ExecuteRegionOp convertUnstructuredACCLoopToSCFExecuteRegion(LoopOp loopOp, RewriterBase &rewriter)
Convert an unstructured acc.loop to scf.execute_region.
void setParDimsAttr(Operation *op, GPUParallelDimsAttr attr)
Set parallel dimensions on op.
scf::ForOp convertACCLoopToSCFFor(LoopOp loopOp, RewriterBase &rewriter, bool enableCollapse)
Convert a structured acc.loop to scf.for.
ACCParMappingPolicy< mlir::acc::GPUParallelDimAttr > ACCToGPUMappingPolicy
Type alias for the GPU-specific mapping policy.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:734
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
Definition Matchers.h:490
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region &region)
Replace all uses of orig within the given region with replacement.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
LogicalResult applyPatternsGreedily(Region &region, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
llvm::SetVector< T, Vector, Set, N > SetVector
Definition LLVM.h:125
Value getValueOrCreateCastToIndexLike(OpBuilder &b, Location loc, Type targetType, Value value)
Create a cast from an index-like value (index or integer) to another index-like value.
Definition Utils.cpp:122
void getUsedValuesDefinedAbove(Region &region, Region &limit, SetVector< Value > &values)
Fill values with a list of values defined at the ancestors of the limit region and used within region...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Definition Matchers.h:369
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...