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 insertParDim(parDims, policy.gangDim(ctx, ParLevel::gang_dim1));
231 }
232 return parDims;
233}
234
235/// Build `acc.compute_region` launch operands: one sequential `acc.par_width`
236/// for `acc.serial`, for `acc.parallel` / `acc.kernels` when every num_gangs
237/// operand and num_workers / vector_length are the constant 1, and otherwise
238/// `acc.par_width` from gang/worker/vector (device-type operands first, then
239/// default DeviceType::None).
240template <typename ComputeConstructT>
241static SmallVector<Value> assignKnownLaunchArgs(
242 ComputeConstructT computeOp, DeviceType deviceType, RewriterBase &rewriter,
243 const ACCToGPUMappingPolicy &policy, const SizedLevelMap &sizedLevelMap) {
244 auto *ctx = rewriter.getContext();
245 auto loc = computeOp->getLoc();
246
247 if constexpr (std::is_same_v<ComputeConstructT, SerialOp>) {
248 return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
249 } else if constexpr (llvm::is_one_of<ComputeConstructT, ParallelOp,
250 KernelsOp>::value) {
251 if (computeOp.isEffectivelySerial())
252 return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
253
254 deviceType = getParDimsDeviceType(computeOp, deviceType);
255
256 SmallVector<Value> values;
257 auto indexTy = rewriter.getIndexType();
258
259 auto numGangs = computeOp.getNumGangsValues(deviceType);
260 for (auto [gangDimIdx, gangSize] : llvm::enumerate(numGangs)) {
261 auto gangLevel = getGangParLevel(gangDimIdx + 1);
262 values.push_back(ParWidthOp::create(
263 rewriter, loc,
264 getValueOrCreateCastToIndexLike(rewriter, gangSize.getLoc(), indexTy,
265 gangSize),
266 policy.gangDim(ctx, gangLevel)));
267 }
268
269 Value numWorkers = computeOp.getNumWorkersValue(deviceType);
270 if (numWorkers) {
271 values.push_back(ParWidthOp::create(
272 rewriter, loc,
273 getValueOrCreateCastToIndexLike(rewriter, numWorkers.getLoc(),
274 indexTy, numWorkers),
275 policy.workerDim(ctx)));
278 Value vectorLength = computeOp.getVectorLengthValue(deviceType);
279 if (vectorLength) {
280 values.push_back(ParWidthOp::create(
281 rewriter, loc,
282 getValueOrCreateCastToIndexLike(rewriter, vectorLength.getLoc(),
283 indexTy, vectorLength),
284 policy.vectorDim(ctx)));
286
287 // Loop-level sized clauses. Skip a dim already set on the construct.
288 // Rematerialize the constant here so it dominates the compute region.
289 auto sizedLevels = sizedLevelMap.find(computeOp.getOperation());
290 if (sizedLevels != sizedLevelMap.end()) {
291 for (const SizedLevel &sizedLevel : sizedLevels->second) {
292 GPUParallelDimAttr dim = policy.map(ctx, sizedLevel.level);
293 bool exists = llvm::any_of(values, [&](Value v) {
294 auto parWidth = v.getDefiningOp<ParWidthOp>();
295 return parWidth && parWidth.getParDim() == dim;
296 });
297 if (exists)
298 continue;
299 Value sizeVal =
300 arith::ConstantIndexOp::create(rewriter, loc, sizedLevel.size);
301 values.push_back(ParWidthOp::create(rewriter, loc, sizeVal, dim));
302 }
303 }
304 return values;
305 } else {
306 llvm_unreachable("assignKnownLaunchArgs: expected parallel, kernels, or "
307 "serial");
308 }
309}
310
311//===----------------------------------------------------------------------===//
312// Loop conversion pattern
313//===----------------------------------------------------------------------===//
314
315class ACCLoopConversion : public OpRewritePattern<LoopOp> {
316public:
317 ACCLoopConversion(MLIRContext *ctx, const ACCToGPUMappingPolicy &policy,
318 DeviceType deviceType)
319 : OpRewritePattern<LoopOp>(ctx), policy(policy), deviceType(deviceType) {}
321 LogicalResult matchAndRewrite(LoopOp loopOp,
322 PatternRewriter &rewriter) const override {
323 if (loopOp.getUnstructured()) {
324 auto executeRegion =
326 if (!executeRegion)
327 return failure();
328 rewriter.replaceOp(loopOp, executeRegion);
329 return success();
330 }
331
332 LoopParMode parMode = loopOp.getDefaultOrDeviceTypeParallelism(deviceType);
334 if (parMode == LoopParMode::loop_seq || isOpInSerialRegion(loopOp)) {
335 // Use scf.for with sequential loops, because the loop's parallelism is
336 // already determined.
337 auto forOp =
338 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/true);
339 if (!forOp)
340 return failure();
341 setParDimsAttr(forOp, GPUParallelDimsAttr::seq(loopOp->getContext()));
342 rewriter.replaceOp(loopOp, forOp);
343 } else if (parMode == LoopParMode::loop_auto) {
344 // All loops in serial regions should have already been handled.
345 assert(!isOpInSerialRegion(loopOp) &&
346 "Expected loop to be in non-serial region");
347 // Mark as scf.for to allow auto-parallelization analysis later.
348 auto forOp =
349 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/true);
350 if (!forOp)
351 return failure();
353 getParallelDimensions(loopOp, policy, deviceType);
354 if (!parDims.empty()) {
355 auto parDimsAttr =
356 GPUParallelDimsAttr::get(loopOp->getContext(), parDims);
357 setParDimsAttr(forOp, parDimsAttr);
358 }
359 rewriter.replaceOp(loopOp, forOp);
360 } else if (!isOpInComputeRegion(loopOp) &&
362 loopOp->getParentOfType<FunctionOpInterface>())) {
363 // This loop is an orphan `acc loop` but it is not in any sort
364 // of compute region. Thus it is just a sequential non-accelerator loop.
365 auto forOp =
366 convertACCLoopToSCFFor(loopOp, rewriter, /*enableCollapse=*/false);
367 if (!forOp)
368 return failure();
369 rewriter.replaceOp(loopOp, forOp);
370 } else {
371 assert(parMode == LoopParMode::loop_independent &&
372 "Expected loop to be independent");
373 auto parallelOp = convertACCLoopToSCFParallel(loopOp, rewriter);
374 if (!parallelOp)
375 return failure();
376
377 SmallVector<GPUParallelDimAttr> parDims =
378 getParallelDimensions(loopOp, policy, deviceType);
379 if (!parDims.empty()) {
380 auto parDimsAttr =
381 GPUParallelDimsAttr::get(loopOp->getContext(), parDims);
382 setParDimsAttr(parallelOp, parDimsAttr);
383 }
384
385 rewriter.replaceOp(loopOp, parallelOp);
386 }
387 return success();
388 }
389
390private:
391 const ACCToGPUMappingPolicy &policy;
392 DeviceType deviceType;
393};
394
395//===----------------------------------------------------------------------===//
396// Compute construct conversion pattern
397//===----------------------------------------------------------------------===//
398
399template <typename ComputeConstructT>
400class ComputeOpConversion : public OpRewritePattern<ComputeConstructT> {
401public:
402 ComputeOpConversion(MLIRContext *ctx, const ACCToGPUMappingPolicy &policy,
403 DeviceType deviceType, const SizedLevelMap &sizedLevelMap)
404 : OpRewritePattern<ComputeConstructT>(ctx), policy(policy),
405 deviceType(deviceType), sizedLevelMap(sizedLevelMap) {}
406
407 LogicalResult matchAndRewrite(ComputeConstructT computeOp,
408 PatternRewriter &rewriter) const override {
409 rewriter.setInsertionPoint(computeOp);
410 auto kernelEnv =
411 KernelEnvironmentOp::createAndPopulate(computeOp, deviceType, rewriter);
412 auto launchArgs = assignKnownLaunchArgs(computeOp, deviceType, rewriter,
413 policy, sizedLevelMap);
414 Region &region = computeOp.getRegion();
415 SetVector<Value> liveInValues;
416 getUsedValuesDefinedAbove(region, region, liveInValues);
417 materializeConstantLiveInsIntoRegion(region, liveInValues, rewriter);
418 IRMapping mapping;
419 auto computeRegion = buildComputeRegion(
420 computeOp->getLoc(), launchArgs, liveInValues.getArrayRef(),
421 ComputeConstructT::getOperationName(), region, rewriter, mapping);
422 if (!computeRegion) {
423 rewriter.eraseOp(kernelEnv);
424 return failure();
425 }
426 rewriter.eraseOp(computeOp);
427 return success();
428 }
429
430private:
431 const ACCToGPUMappingPolicy &policy;
432 DeviceType deviceType;
433 const SizedLevelMap &sizedLevelMap;
434};
435
436//===----------------------------------------------------------------------===//
437// Pass implementation
438//===----------------------------------------------------------------------===//
439
440class ACCComputeLowering
441 : public acc::impl::ACCComputeLoweringBase<ACCComputeLowering> {
442public:
443 using ACCComputeLoweringBase::ACCComputeLoweringBase;
444
445 void runOnOperation() override {
446 auto op = getOperation();
447 auto *context = op.getContext();
448
449 DefaultACCToGPUMappingPolicy policy;
450 // Collect loop sized levels before loops are rewritten away.
451 SizedLevelMap sizedLevelMap;
452 OpenACCSupport &accSupport = getAnalysis<OpenACCSupport>();
453 if (failed(fillSizedLevelMap(op, deviceType, sizedLevelMap, accSupport)))
454 return signalPassFailure();
455
456 // Part 1: Convert acc.loop to scf.parallel/scf.for while the parent
457 // compute construct is still present (needed to determine conversion
458 // strategy).
459 RewritePatternSet loopPatterns(context);
460 loopPatterns.insert<ACCLoopConversion>(context, policy, deviceType);
461 if (failed(applyPatternsGreedily(op, std::move(loopPatterns))))
462 return signalPassFailure();
463
464 // Part 2: Convert acc.parallel, acc.kernels, and acc.serial to
465 // acc.kernel_environment { acc.compute_region { ... } }.
466 RewritePatternSet computePatterns(context);
467 computePatterns
468 .insert<ComputeOpConversion<ParallelOp>, ComputeOpConversion<KernelsOp>,
469 ComputeOpConversion<SerialOp>>(context, policy, deviceType,
470 sizedLevelMap);
471 if (failed(applyPatternsGreedily(op, std::move(computePatterns))))
472 return signalPassFailure();
473 }
474};
475
476} // 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:189
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.
bool isSpecializedAccRoutine(mlir::Operation *op)
Used to check whether this is a specialized accelerator version of acc routine function.
Definition OpenACC.h:201
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:732
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...