MLIR 24.0.0git
OpenACCCG.cpp
Go to the documentation of this file.
1//===- OpenACCCG.cpp - OpenACC codegen ops, attributes, and types ---------===//
2//
3// Part of the MLIR 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// Implementation for OpenACC codegen operations, attributes, and types.
10// These correspond to the definitions in OpenACCCG*.td tablegen files
11// and are kept in a separate file because they do not represent direct mappings
12// of OpenACC language constructs; they are intermediate representations used
13// when decomposing and lowering primary `acc` dialect operations.
14//
15//===----------------------------------------------------------------------===//
16
24#include "mlir/IR/Region.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallVector.h"
30
31using namespace mlir;
32using namespace acc;
33
34namespace {
35
36/// Generic helper for single-region OpenACC ops that execute their body once
37/// and then continue after the operation with their results (if any).
38static void
42 if (point.isParent()) {
43 regions.push_back(RegionSuccessor(&region));
44 return;
45 }
46 regions.push_back(RegionSuccessor(op));
47}
48
50 RegionSuccessor successor) {
51 return successor.isOperation() ? ValueRange(op->getResults()) : ValueRange();
52}
53
54/// Remove empty acc.kernel_environment operations. If the operation has wait
55/// operands, create a acc.wait operation to preserve synchronization.
56struct RemoveEmptyKernelEnvironment
57 : public OpRewritePattern<acc::KernelEnvironmentOp> {
58 using OpRewritePattern<acc::KernelEnvironmentOp>::OpRewritePattern;
59
60 LogicalResult matchAndRewrite(acc::KernelEnvironmentOp op,
61 PatternRewriter &rewriter) const override {
62 assert(op->getNumRegions() == 1 && "expected op to have one region");
63
64 Block &block = op.getRegion().front();
65 if (!block.empty())
66 return failure();
67
68 // Remove empty kernel environment.
69 // Preserve synchronization by creating acc.wait operation if needed.
70 if (!op.getWaitOperands().empty() || op.getWaitOnlyAttr())
71 rewriter.replaceOpWithNewOp<acc::WaitOp>(
72 op, op.getWaitOperands(), /*asyncOperand=*/Value(),
73 op.getWaitDevnum(), /*async=*/nullptr, /*ifCond=*/Value());
74 else
75 rewriter.eraseOp(op);
76
77 return success();
78 }
79};
80
81static void updateComputeRegionInputOperandSegments(ComputeRegionOp op,
82 PatternRewriter &rewriter,
83 size_t numInput) {
84 const size_t numLaunch = op.getLaunchArgs().size();
85 op->setAttr(ComputeRegionOp::getOperandSegmentSizeAttr(),
86 rewriter.getDenseI32ArrayAttr({static_cast<int32_t>(numLaunch),
87 static_cast<int32_t>(numInput),
88 op.getStream() ? 1 : 0}));
89}
90
91struct ComputeRegionRemoveDuplicateArgs
92 : public OpRewritePattern<ComputeRegionOp> {
94
95 LogicalResult matchAndRewrite(ComputeRegionOp op,
96 PatternRewriter &rewriter) const override {
97 Block *body = op.getBody();
98 const size_t numLaunch = op.getLaunchArgs().size();
99 size_t numInput = op.getInputArgs().size();
100 assert(body->getNumArguments() == numLaunch + numInput &&
101 "region args mismatch");
102
103 bool mergedAny = false;
104 while (true) {
105 bool merged = false;
106 for (size_t j = 1; j < numInput && !merged; ++j) {
107 for (size_t i = 0; i < j; ++i) {
108 if (op->getOperand(static_cast<unsigned>(numLaunch + i)) !=
109 op->getOperand(static_cast<unsigned>(numLaunch + j)))
110 continue;
111 unsigned keepIdx = static_cast<unsigned>(numLaunch + i);
112 unsigned dropIdx = static_cast<unsigned>(numLaunch + j);
113 rewriter.replaceAllUsesWith(body->getArgument(dropIdx),
114 body->getArgument(keepIdx));
115 body->eraseArgument(dropIdx);
116 op->eraseOperand(dropIdx);
117 --numInput;
118 merged = true;
119 mergedAny = true;
120 break;
121 }
122 }
123 if (!merged)
124 break;
125 }
126
127 if (!mergedAny)
128 return failure();
129 updateComputeRegionInputOperandSegments(op, rewriter, numInput);
130 return success();
131 }
132};
133
134struct ComputeRegionRemoveUnusedArgs
135 : public OpRewritePattern<ComputeRegionOp> {
137
138 LogicalResult matchAndRewrite(ComputeRegionOp op,
139 PatternRewriter &rewriter) const override {
140 Block *body = op.getBody();
141 const size_t numLaunch = op.getLaunchArgs().size();
142 size_t numInput = op.getInputArgs().size();
143 assert(body->getNumArguments() == numLaunch + numInput &&
144 "region args mismatch");
145
146 bool changed = false;
147 for (size_t k = numLaunch; k < numLaunch + numInput;) {
148 if (!body->getArgument(static_cast<unsigned>(k)).use_empty()) {
149 ++k;
150 continue;
151 }
152 body->eraseArgument(static_cast<unsigned>(k));
153 op->eraseOperand(static_cast<unsigned>(k));
154 --numInput;
155 changed = true;
156 }
157
158 if (!changed)
159 return failure();
160 updateComputeRegionInputOperandSegments(op, rewriter, numInput);
161 return success();
162 }
163};
164
165template <typename EffectTy>
166static void addOperandEffect(
168 &effects,
169 const MutableOperandRange &operand) {
170 for (unsigned i = 0, e = operand.size(); i < e; ++i)
171 effects.emplace_back(EffectTy::get(), &operand[i]);
172}
173
174template <typename EffectTy>
175static void addResultEffect(
177 &effects,
178 Value result) {
179 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(result));
180}
181
182static int64_t gpuProcessorIndex(gpu::Processor p) {
183 switch (p) {
184 case gpu::Processor::Sequential:
185 return 0;
186 case gpu::Processor::ThreadX:
187 return 1;
188 case gpu::Processor::ThreadY:
189 return 2;
190 case gpu::Processor::ThreadZ:
191 return 3;
192 case gpu::Processor::BlockX:
193 return 4;
194 case gpu::Processor::BlockY:
195 return 5;
196 case gpu::Processor::BlockZ:
197 return 6;
198 }
199 llvm_unreachable("unhandled gpu::Processor");
200}
201
202static gpu::Processor indexToGpuProcessor(int64_t idx) {
203 switch (idx) {
204 case 0:
205 return gpu::Processor::Sequential;
206 case 1:
207 return gpu::Processor::ThreadX;
208 case 2:
209 return gpu::Processor::ThreadY;
210 case 3:
211 return gpu::Processor::ThreadZ;
212 case 4:
213 return gpu::Processor::BlockX;
214 case 5:
215 return gpu::Processor::BlockY;
216 case 6:
217 return gpu::Processor::BlockZ;
218 default:
219 return gpu::Processor::Sequential;
220 }
221}
222
223static GPUParallelDimAttr intToParDim(MLIRContext *context, int64_t dimInt) {
224 return GPUParallelDimAttr::get(
225 context, IntegerAttr::get(IndexType::get(context), dimInt));
226}
227
228static GPUParallelDimAttr processorParDim(MLIRContext *context,
229 gpu::Processor proc) {
230 return GPUParallelDimAttr::get(
231 context,
232 IntegerAttr::get(IndexType::get(context), gpuProcessorIndex(proc)));
233}
234
235static ParseResult parseProcessorValue(AsmParser &parser,
236 GPUParallelDimAttr &dim) {
237 std::string keyword;
238 llvm::SMLoc loc = parser.getCurrentLocation();
239 if (failed(parser.parseKeywordOrString(&keyword)))
240 return failure();
241 auto maybeProcessor = gpu::symbolizeProcessor(keyword);
242 if (!maybeProcessor)
243 return parser.emitError(loc)
244 << "expected one of ::mlir::gpu::Processor enum names";
245 dim = intToParDim(parser.getContext(), gpuProcessorIndex(*maybeProcessor));
246 return success();
247}
248
249static void printProcessorValue(AsmPrinter &printer,
250 const GPUParallelDimAttr &attr) {
251 gpu::Processor processor = indexToGpuProcessor(attr.getValue().getInt());
252 printer << gpu::stringifyProcessor(processor);
253}
254
255static FailureOr<SmallVector<GPUParallelDimAttr>>
256parseGPUParallelDimList(AsmParser &parser) {
258 auto parseParDim = [&]() -> ParseResult {
259 GPUParallelDimAttr dim;
260 if (parseProcessorValue(parser, dim))
261 return failure();
262 parDims.push_back(dim);
263 return success();
264 };
266 "list of OpenACC GPU parallel dimensions"))
267 return failure();
268 return parDims;
269}
270
271static void printGPUParallelDimList(AsmPrinter &printer,
273 printer << "[";
274 llvm::interleaveComma(dims, printer, [&printer](const GPUParallelDimAttr &p) {
275 printProcessorValue(printer, p);
276 });
277 printer << "]";
278}
279
280} // namespace
281
282//===----------------------------------------------------------------------===//
283// KernelEnvironmentOp
284//===----------------------------------------------------------------------===//
285
286void KernelEnvironmentOp::getSuccessorRegions(
288 getSingleRegionOpSuccessorRegions(getOperation(), getRegion(), point,
289 regions);
290}
291
292ValueRange KernelEnvironmentOp::getSuccessorInputs(RegionSuccessor successor) {
293 return getSingleRegionSuccessorInputs(getOperation(), successor);
294}
295
296void KernelEnvironmentOp::getCanonicalizationPatterns(
297 RewritePatternSet &results, MLIRContext *context) {
298 results.add<RemoveEmptyKernelEnvironment>(context);
299}
300
301/// Extract async for `clauseDeviceType`. Returns true if a clause was found.
302template <typename ComputeConstructT>
303static bool
304extractAsyncClause(ComputeConstructT computeConstruct,
305 DeviceType clauseDeviceType, MLIRContext *context,
306 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly) {
307 if (computeConstruct.hasAsyncOnly(clauseDeviceType)) {
308 asyncOnly = UnitAttr::get(context);
309 return true;
310 }
311 if (Value asyncValue = computeConstruct.getAsyncValue(clauseDeviceType)) {
312 asyncOperand = asyncValue;
313 return true;
314 }
315 return false;
316}
317
318/// Extract wait for `clauseDeviceType`. Returns true if a clause was found.
319template <typename ComputeConstructT>
320static bool extractWaitClause(ComputeConstructT computeConstruct,
321 DeviceType clauseDeviceType, MLIRContext *context,
322 std::optional<Value> &waitDevnum,
323 SmallVectorImpl<Value> &waitOperands,
324 UnitAttr &waitOnly) {
325 if (computeConstruct.hasWaitOnly(clauseDeviceType)) {
326 waitOnly = UnitAttr::get(context);
327 return true;
328 }
329 Value devnum = computeConstruct.getWaitDevnum(clauseDeviceType);
330 auto waitValues = computeConstruct.getWaitValues(clauseDeviceType);
331 if (!devnum && waitValues.empty())
332 return false;
333 if (devnum)
334 waitDevnum = devnum;
335 waitOperands.append(waitValues.begin(), waitValues.end());
336 return true;
337}
338
339template <typename ComputeConstructT>
341 ComputeConstructT computeConstruct, DeviceType deviceType,
342 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly,
343 std::optional<Value> &waitDevnum, SmallVectorImpl<Value> &waitOperands,
344 UnitAttr &waitOnly) {
345 MLIRContext *context = computeConstruct->getContext();
346
347 // Prefer device_type-specific clauses, then default ones.
348 if (!extractAsyncClause(computeConstruct, deviceType, context, asyncOperand,
349 asyncOnly)) {
350 if (deviceType != DeviceType::None)
351 extractAsyncClause(computeConstruct, DeviceType::None, context,
352 asyncOperand, asyncOnly);
353 }
354
355 if (!extractWaitClause(computeConstruct, deviceType, context, waitDevnum,
356 waitOperands, waitOnly)) {
357 if (deviceType != DeviceType::None)
358 extractWaitClause(computeConstruct, DeviceType::None, context, waitDevnum,
359 waitOperands, waitOnly);
360 }
361}
362
363template <typename ComputeConstructT>
364KernelEnvironmentOp
365KernelEnvironmentOp::createAndPopulate(ComputeConstructT computeConstruct,
366 DeviceType deviceType,
367 OpBuilder &builder) {
368 std::optional<Value> asyncOperand;
369 UnitAttr asyncOnly = nullptr;
370 std::optional<Value> waitDevnum;
371 SmallVector<Value> waitOperands;
372 UnitAttr waitOnly = nullptr;
373 populateKernelEnvironmentAsyncWait(computeConstruct, deviceType, asyncOperand,
374 asyncOnly, waitDevnum, waitOperands,
375 waitOnly);
376
377 auto kernelEnvironment = KernelEnvironmentOp::create(
378 builder, computeConstruct->getLoc(),
379 computeConstruct.getDataClauseOperands(), asyncOperand.value_or(Value()),
380 asyncOnly, waitDevnum.value_or(Value()), waitOperands, waitOnly);
381 Block &block = kernelEnvironment.getRegion().emplaceBlock();
382 builder.setInsertionPointToStart(&block);
383 return kernelEnvironment;
384}
385
386template KernelEnvironmentOp
387KernelEnvironmentOp::createAndPopulate<ParallelOp>(ParallelOp, DeviceType,
388 OpBuilder &);
389template KernelEnvironmentOp
390KernelEnvironmentOp::createAndPopulate<KernelsOp>(KernelsOp, DeviceType,
391 OpBuilder &);
392template KernelEnvironmentOp
393KernelEnvironmentOp::createAndPopulate<SerialOp>(SerialOp, DeviceType,
394 OpBuilder &);
395
396LogicalResult KernelEnvironmentOp::verify() {
397 if (getAsyncOnly() && getAsyncOperand())
398 return emitError("async-only cannot appear with async operand");
399 if (getWaitOnly() && (!getWaitOperands().empty() || getWaitDevnum()))
400 return emitError("wait-only cannot appear with wait operands or devnum");
401 return success();
402}
403
404//===----------------------------------------------------------------------===//
405// FirstprivateMapInitialOp
406//===----------------------------------------------------------------------===//
407
408LogicalResult FirstprivateMapInitialOp::verify() {
409 if (getDataClause() != acc::DataClause::acc_firstprivate)
410 return emitError("data clause associated with firstprivate operation must "
411 "match its intent");
412 if (!getVar())
413 return emitError("must have var operand");
414 if (!mlir::isa<mlir::acc::PointerLikeType>(getVar().getType()) &&
415 !mlir::isa<mlir::acc::MappableType>(getVar().getType()))
416 return emitError("var must be mappable or pointer-like");
417 if (mlir::isa<mlir::acc::PointerLikeType>(getVar().getType()) &&
418 getVarType() == getVar().getType())
419 return emitError("varType must capture the element type of var");
420 if (getModifiers() != acc::DataClauseModifier::none)
421 return emitError("no data clause modifiers are allowed");
422 return success();
423}
424
425void FirstprivateMapInitialOp::getEffects(
427 &effects) {
428 effects.emplace_back(MemoryEffects::Read::get(),
430 addOperandEffect<MemoryEffects::Read>(effects, getVarMutable());
432}
433
434//===----------------------------------------------------------------------===//
435// ReductionInitOp
436//===----------------------------------------------------------------------===//
437
438void ReductionInitOp::getSuccessorRegions(
440 getSingleRegionOpSuccessorRegions(getOperation(), getRegion(), point,
441 regions);
442}
443
444void ReductionInitOp::getRegionInvocationBounds(
445 ArrayRef<Attribute> operands,
446 SmallVectorImpl<InvocationBounds> &invocationBounds) {
447 invocationBounds.emplace_back(1, 1);
448}
449
450ValueRange ReductionInitOp::getSuccessorInputs(RegionSuccessor successor) {
451 return getSingleRegionSuccessorInputs(getOperation(), successor);
452}
453
454LogicalResult ReductionInitOp::verify() {
455 Block &block = getRegion().front();
456 if (auto yieldOp = dyn_cast<acc::YieldOp>(block.getTerminator())) {
457 if (yieldOp.getNumOperands() != 1)
458 return emitOpError(
459 "region must yield exactly one value (private storage)");
460 if (yieldOp.getOperand(0).getType() != getVar().getType())
461 return emitOpError("yielded value type must match var type");
462 }
463 return success();
464}
465
466//===----------------------------------------------------------------------===//
467// ReductionCombineRegionOp
468//===----------------------------------------------------------------------===//
469
470void ReductionCombineRegionOp::getSuccessorRegions(
472 getSingleRegionOpSuccessorRegions(getOperation(), getRegion(), point,
473 regions);
474}
475
476void ReductionCombineRegionOp::getRegionInvocationBounds(
477 ArrayRef<Attribute> operands,
478 SmallVectorImpl<InvocationBounds> &invocationBounds) {
479 invocationBounds.emplace_back(1, 1);
480}
481
483ReductionCombineRegionOp::getSuccessorInputs(RegionSuccessor successor) {
484 return getSingleRegionSuccessorInputs(getOperation(), successor);
485}
486
487LogicalResult ReductionCombineRegionOp::verify() {
488 Block &block = getRegion().front();
489 if (auto yieldOp = dyn_cast<acc::YieldOp>(block.getTerminator())) {
490 if (yieldOp.getNumOperands() != 0)
491 return emitOpError("region must be terminated by acc.yield with no "
492 "operands");
493 }
494 return success();
495}
496
497//===----------------------------------------------------------------------===//
498// ReductionAccumulateOp
499//===----------------------------------------------------------------------===//
500
501LogicalResult ReductionAccumulateOp::verify() {
502 Type valueType = getValue().getType();
503 auto ptrLikeTy = cast<PointerLikeType>(getMemref().getType());
504 Type elementType = ptrLikeTy.getElementType();
505 if (!elementType)
506 return emitOpError("pointer-like destination must have an element type");
507 if (elementType != valueType)
508 return emitOpError("pointer-like element type must match value type");
509 if (getParDims().getArray().empty())
510 return emitOpError("par_dims must specify at least one parallel dimension");
511 return success();
512}
513
514//===----------------------------------------------------------------------===//
515// ReductionAccumulateArrayOp
516//===----------------------------------------------------------------------===//
517
518LogicalResult ReductionAccumulateArrayOp::verify() {
519 if (getParDims().getArray().empty())
520 return emitOpError("par_dims must specify at least one parallel dimension");
521 return success();
522}
523
524//===----------------------------------------------------------------------===//
525// ReductionCombineOp
526//===----------------------------------------------------------------------===//
527
528void ReductionCombineOp::getEffects(
530 &effects) {
531 effects.emplace_back(MemoryEffects::Read::get(), &getSrcMemrefMutable(),
533 effects.emplace_back(MemoryEffects::Read::get(), &getDestMemrefMutable(),
535 effects.emplace_back(MemoryEffects::Write::get(), &getDestMemrefMutable(),
537}
538
539//===----------------------------------------------------------------------===//
540// ComputeRegionOp
541//===----------------------------------------------------------------------===//
542
543static ParWidthOp getParWidthOpForLaunchArg(ComputeRegionOp op,
544 GPUParallelDimAttr parDim) {
545 for (auto launchArg : op.getLaunchArgs()) {
546 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
547 if (!parOp)
548 continue;
549 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
550 if (launchArgDim == parDim)
551 return parOp;
552 }
553 return nullptr;
554}
555
556std::optional<Value> ComputeRegionOp::getLaunchArg(GPUParallelDimAttr parDim) {
557 if (auto parWidthOp = getParWidthOpForLaunchArg(*this, parDim))
558 return parWidthOp.getResult();
559 return {};
560}
561
562std::optional<Value>
563ComputeRegionOp::getKnownLaunchArg(GPUParallelDimAttr parDim) {
564 if (auto parWidthOp = getParWidthOpForLaunchArg(*this, parDim))
565 if (parWidthOp.getLaunchArg())
566 return parWidthOp.getLaunchArg();
567 return {};
568}
569
570std::optional<uint64_t>
571ComputeRegionOp::getKnownConstantLaunchArg(GPUParallelDimAttr parDim) {
572 auto knownParWidth = getKnownLaunchArg(parDim);
573 if (knownParWidth.has_value())
574 return getConstantIntValue(knownParWidth.value());
575 return {};
576}
577
578BlockArgument ComputeRegionOp::appendInputArg(Value value) {
579 getInputArgsMutable().append(value);
580 return getBody()->addArgument(value.getType(), getLoc());
581}
582
583std::optional<BlockArgument>
584ComputeRegionOp::wireHoistedValueThroughIns(Value value) {
585 Region &region = getRegion();
586
587 auto useIsInRegion = [&](OpOperand &use) -> bool {
588 return region.isAncestor(use.getOwner()->getParentRegion());
589 };
590
591 if (!areValuesDefinedAbove(ValueRange(value), region) ||
592 !llvm::any_of(value.getUses(), useIsInRegion))
593 return std::nullopt;
594
595 BlockArgument arg = appendInputArg(value);
596 replaceAllUsesInRegionWith(value, arg, region);
597 return arg;
598}
599
600bool ComputeRegionOp::isEffectivelySerial() {
601 auto *ctx = getContext();
602
603 if (getLaunchArg(GPUParallelDimAttr::seqDim(ctx)))
604 return true;
605
606 auto checkDim = [&](GPUParallelDimAttr dim) -> bool {
607 auto val = getKnownConstantLaunchArg(dim);
608 return val && *val == 1;
609 };
610
611 return checkDim(GPUParallelDimAttr::threadXDim(ctx)) &&
612 checkDim(GPUParallelDimAttr::threadYDim(ctx)) &&
613 checkDim(GPUParallelDimAttr::threadZDim(ctx)) &&
614 checkDim(GPUParallelDimAttr::blockXDim(ctx)) &&
615 checkDim(GPUParallelDimAttr::blockYDim(ctx)) &&
616 checkDim(GPUParallelDimAttr::blockZDim(ctx));
617}
618
619BlockArgument ComputeRegionOp::parDimToWidth(GPUParallelDimAttr parDim) {
620 for (auto [pos, launchArg] : llvm::enumerate(getLaunchArgs())) {
621 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
622 assert(parOp);
623 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
624 if (launchArgDim == parDim) {
625 assert(pos < getRegion().front().getNumArguments() &&
626 "launch arg position out of range");
627 return getRegion().front().getArgument(pos);
628 }
629 }
630 llvm_unreachable("attempting to get unspecified parDim");
631}
632
633SmallVector<GPUParallelDimAttr> ComputeRegionOp::getLaunchParDims() {
635 for (auto launchArg : getLaunchArgs()) {
636 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
637 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
638 int64_t dimInt = launchArgDim.getValue().getInt();
639 parDims.push_back(intToParDim(getContext(), dimInt));
640 }
641 return parDims;
642}
643
644Value ComputeRegionOp::getOperand(BlockArgument blockArg) {
645 Block *body = getBody();
646 if (blockArg.getOwner() != body)
647 return Value();
648 unsigned argNumber = blockArg.getArgNumber();
649 unsigned numLaunchArgs = getLaunchArgs().size();
650 unsigned numInputArgs = getInputArgs().size();
651 if (argNumber >= numLaunchArgs + numInputArgs)
652 return Value();
653 if (argNumber < numLaunchArgs)
654 return getLaunchArgs()[argNumber];
655 return getInputArgs()[argNumber - numLaunchArgs];
656}
657
658std::optional<BlockArgument> ComputeRegionOp::getBlockArg(Value value) {
659 Block *body = getBody();
660 for (auto [idx, launchVal] : llvm::enumerate(getLaunchArgs())) {
661 if (launchVal == value)
662 return body->getArgument(idx);
663 }
664 unsigned numLaunch = getLaunchArgs().size();
665 for (auto [idx, inputVal] : llvm::enumerate(getInputArgs())) {
666 if (inputVal == value)
667 return body->getArgument(numLaunch + idx);
668 }
669 return std::nullopt;
670}
671
672void ComputeRegionOp::getCanonicalizationPatterns(RewritePatternSet &results,
673 MLIRContext *context) {
674 results.add<ComputeRegionRemoveDuplicateArgs, ComputeRegionRemoveUnusedArgs>(
675 context);
676}
677
678BlockArgument ComputeRegionOp::gpuParWidth(gpu::Processor processor) {
679 return parDimToWidth(GPUParallelDimAttr::get(getContext(), processor));
680}
681
682LogicalResult ComputeRegionOp::verify() {
683 for (auto op : getLaunchArgs())
684 if (!op.getDefiningOp<acc::ParWidthOp>())
685 return emitOpError(
686 "launch arguments must be results of acc.par_width operations");
687
688 unsigned expectedBlockArgs = getLaunchArgs().size() + getInputArgs().size();
689 unsigned actualBlockArgs = getRegion().front().getNumArguments();
690 if (expectedBlockArgs != actualBlockArgs)
691 return emitOpError("expected ")
692 << expectedBlockArgs << " block arguments (launch + input), got "
693 << actualBlockArgs;
694
695 return success();
696}
697
698void ComputeRegionOp::print(OpAsmPrinter &p) {
699 ValueRange regionArgs = getBody()->getArguments();
700 ValueRange launchArgs = getLaunchArgs();
701 ValueRange inputArgs = getInputArgs();
702
703 assert(regionArgs.size() == (launchArgs.size() + inputArgs.size()) &&
704 "region args mismatch");
705
706 if (getStream())
707 p << " stream(" << getStream() << " : " << getStream().getType() << ")";
708
709 size_t i = 0;
710 if (!launchArgs.empty()) {
711 p << " launch(";
712 for (size_t j = 0; j < launchArgs.size(); ++j, ++i) {
713 p << regionArgs[i] << " = " << launchArgs[j];
714 if (j < launchArgs.size() - 1)
715 p << ", ";
716 }
717 p << ")";
718 }
719 if (!inputArgs.empty()) {
720 p << " ins(";
721 for (size_t j = 0; j < inputArgs.size(); ++j, ++i) {
722 p << regionArgs[i] << " = " << inputArgs[j];
723 if (j < inputArgs.size() - 1)
724 p << ", ";
725 }
726 p << ") : (";
727 for (size_t j = 0; j < inputArgs.size(); ++j) {
728 p << inputArgs[j].getType();
729 if (j < inputArgs.size() - 1)
730 p << ", ";
731 }
732 p << ")";
733 }
734 p.printOptionalArrowTypeList(getResultTypes());
735 p << " ";
736 p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);
737 p.printOptionalAttrDict((*this)->getAttrs(),
738 /*elidedAttrs=*/getOperandSegmentSizeAttr());
739}
740
741ParseResult ComputeRegionOp::parse(OpAsmParser &parser,
743 auto &builder = parser.getBuilder();
744
746 OpAsmParser::UnresolvedOperand streamOperand;
747 Type streamType;
750 SmallVector<Type> types;
751
752 bool hasStream = false;
753 if (succeeded(parser.parseOptionalKeyword("stream"))) {
754 hasStream = true;
755 if (parser.parseLParen() || parser.parseOperand(streamOperand) ||
756 parser.parseColon() || parser.parseType(streamType) ||
757 parser.parseRParen())
758 return failure();
759 }
760
761 if (succeeded(parser.parseOptionalKeyword("launch"))) {
762 if (parser.parseAssignmentList(regionArgs, launchOperands))
763 return failure();
764 Type indexType = builder.getIndexType();
765 for (size_t i = 0; i < regionArgs.size(); ++i)
766 types.push_back(indexType);
767 }
768
769 if (succeeded(parser.parseOptionalKeyword("ins"))) {
770 if (parser.parseAssignmentList(regionArgs, inputOperands) ||
771 parser.parseColon() || parser.parseLParen() ||
772 parser.parseTypeList(types) || parser.parseRParen())
773 return failure();
774 }
775
776 if (parser.parseOptionalArrowTypeList(result.types))
777 return failure();
778
779 for (auto [iterArg, type] : llvm::zip_equal(regionArgs, types))
780 iterArg.type = type;
781
782 Region *body = result.addRegion();
783 if (parser.parseRegion(*body, regionArgs))
784 return failure();
785 ComputeRegionOp::ensureTerminator(*body, parser.getBuilder(),
786 result.location);
787
788 const size_t numLaunchOperands = launchOperands.size();
789 const size_t numInputOperands = inputOperands.size();
790 assert(numLaunchOperands + numInputOperands == regionArgs.size() &&
791 "compute region args mismatch");
792
793 result.addAttribute(
794 ComputeRegionOp::getOperandSegmentSizeAttr(),
795 builder.getDenseI32ArrayAttr({static_cast<int32_t>(numLaunchOperands),
796 static_cast<int32_t>(numInputOperands),
797 hasStream ? 1 : 0}));
798
799 for (size_t i = 0; i < numLaunchOperands; ++i) {
800 if (parser.resolveOperand(launchOperands[i], types[i], result.operands))
801 return failure();
802 }
803
804 for (size_t i = numLaunchOperands; i < regionArgs.size(); ++i) {
805 if (parser.resolveOperand(inputOperands[i - numLaunchOperands], types[i],
806 result.operands))
807 return failure();
808 }
809
810 if (hasStream) {
811 if (parser.resolveOperand(streamOperand, streamType, result.operands))
812 return failure();
813 }
814
815 if (parser.parseOptionalAttrDict(result.attributes))
816 return failure();
817
818 return success();
819}
820
821//===----------------------------------------------------------------------===//
822// GPUSharedMemoryOp
823//===----------------------------------------------------------------------===//
824
825LogicalResult GPUSharedMemoryOp::verify() {
826 if (getNumCopies() <= 0)
827 return emitOpError("num_copies must be positive");
828 if (getStaticUpperBoundBytes() <= 0)
829 return emitOpError("static_upper_bound_bytes must be positive");
830
831 bool hasScaling = static_cast<bool>(getDynamicSharedMemoryScalingBytes());
832 bool hasFixed = static_cast<bool>(getDynamicSharedMemoryFixedBytes());
833 if (hasScaling != hasFixed)
834 return emitOpError(
835 "dynamic_shared_memory_scaling_bytes and "
836 "dynamic_shared_memory_fixed_bytes must both be present or both be "
837 "absent");
838 if (auto scalingAttr = getDynamicSharedMemoryScalingBytesAttr())
839 if (scalingAttr.getValue().isNegative())
840 return emitOpError("dynamic_shared_memory_scaling_bytes must be "
841 "non-negative");
842 if (auto fixedAttr = getDynamicSharedMemoryFixedBytesAttr())
843 if (fixedAttr.getValue().isNegative())
844 return emitOpError("dynamic_shared_memory_fixed_bytes must be "
845 "non-negative");
846
847 auto resultTy = cast<MemRefType>(getResult().getType());
848 auto addrSpace =
849 dyn_cast_if_present<gpu::AddressSpaceAttr>(resultTy.getMemorySpace());
850 if (!addrSpace ||
851 addrSpace.getValue() != gpu::GPUDialect::getWorkgroupAddressSpace())
852 return emitOpError("result memref must use #gpu.address_space<workgroup>");
853
854 return success();
855}
856
857//===----------------------------------------------------------------------===//
858// PredicateRegionOp
859//===----------------------------------------------------------------------===//
860
861LogicalResult PredicateRegionOp::verify() {
862 if (getRegion().empty())
863 return emitOpError("region needs to have at least one block");
864 if (getRegion().front().getNumArguments() > 0)
865 return emitOpError("region cannot have any arguments");
866 if (!getOperation()->getParentOfType<ComputeRegionOp>())
867 return emitOpError("must be nested within an acc.compute_region operation");
868 return success();
869}
870
871//===----------------------------------------------------------------------===//
872// GPUParallelDimAttr
873//===----------------------------------------------------------------------===//
874
875GPUParallelDimAttr GPUParallelDimAttr::get(MLIRContext *context,
876 gpu::Processor proc) {
877 return processorParDim(context, proc);
878}
879
880GPUParallelDimAttr GPUParallelDimAttr::seqDim(MLIRContext *context) {
881 return processorParDim(context, gpu::Processor::Sequential);
882}
883
884GPUParallelDimAttr GPUParallelDimAttr::threadXDim(MLIRContext *context) {
885 return processorParDim(context, gpu::Processor::ThreadX);
886}
887
888GPUParallelDimAttr GPUParallelDimAttr::threadYDim(MLIRContext *context) {
889 return processorParDim(context, gpu::Processor::ThreadY);
890}
891
892GPUParallelDimAttr GPUParallelDimAttr::threadZDim(MLIRContext *context) {
893 return processorParDim(context, gpu::Processor::ThreadZ);
894}
895
896GPUParallelDimAttr GPUParallelDimAttr::blockXDim(MLIRContext *context) {
897 return processorParDim(context, gpu::Processor::BlockX);
898}
899
900GPUParallelDimAttr GPUParallelDimAttr::blockYDim(MLIRContext *context) {
901 return processorParDim(context, gpu::Processor::BlockY);
902}
903
904GPUParallelDimAttr GPUParallelDimAttr::blockZDim(MLIRContext *context) {
905 return processorParDim(context, gpu::Processor::BlockZ);
906}
907
908Attribute GPUParallelDimAttr::parse(AsmParser &parser, Type type) {
909 GPUParallelDimAttr dim;
910 if (parser.parseLess() || parseProcessorValue(parser, dim) ||
911 parser.parseGreater()) {
912 parser.emitError(parser.getCurrentLocation(),
913 "expected format `<` processor_name `>`");
914 return {};
915 }
916 return dim;
917}
918
919void GPUParallelDimAttr::print(AsmPrinter &printer) const {
920 printer << "<";
921 printProcessorValue(printer, *this);
922 printer << ">";
923}
924
925GPUParallelDimAttr GPUParallelDimAttr::threadDim(MLIRContext *context,
926 unsigned index) {
927 assert(index <= 2 && "thread dimension index must be 0, 1, or 2");
928 switch (index) {
929 case 0:
930 return threadXDim(context);
931 case 1:
932 return threadYDim(context);
933 case 2:
934 return threadZDim(context);
935 }
936 llvm_unreachable("validated thread dimension index");
937}
938
939GPUParallelDimAttr GPUParallelDimAttr::blockDim(MLIRContext *context,
940 unsigned index) {
941 assert(index <= 2 && "block dimension index must be 0, 1, or 2");
942 switch (index) {
943 case 0:
944 return blockXDim(context);
945 case 1:
946 return blockYDim(context);
947 case 2:
948 return blockZDim(context);
949 }
950 llvm_unreachable("validated block dimension index");
951}
952
953gpu::Processor GPUParallelDimAttr::getProcessor() const {
954 return indexToGpuProcessor(getValue().getInt());
955}
956
957int GPUParallelDimAttr::getOrder() const {
958 return gpuProcessorIndex(getProcessor());
959}
960
961GPUParallelDimAttr GPUParallelDimAttr::getOneHigher() const {
962 int order = getOrder();
963 if (order >= 6) // BlockZ is the highest
964 return *this;
965 return get(getContext(), indexToGpuProcessor(order + 1));
966}
967
968GPUParallelDimAttr GPUParallelDimAttr::getOneLower() const {
969 int order = getOrder();
970 if (order <= 0) // Sequential is the lowest
971 return *this;
972 return get(getContext(), indexToGpuProcessor(order - 1));
973}
974
975bool GPUParallelDimAttr::isSeq() const {
976 return getProcessor() == gpu::Processor::Sequential;
977}
978bool GPUParallelDimAttr::isThreadX() const {
979 return getProcessor() == gpu::Processor::ThreadX;
980}
981bool GPUParallelDimAttr::isThreadY() const {
982 return getProcessor() == gpu::Processor::ThreadY;
983}
984bool GPUParallelDimAttr::isThreadZ() const {
985 return getProcessor() == gpu::Processor::ThreadZ;
986}
987bool GPUParallelDimAttr::isBlockX() const {
988 return getProcessor() == gpu::Processor::BlockX;
989}
990bool GPUParallelDimAttr::isBlockY() const {
991 return getProcessor() == gpu::Processor::BlockY;
992}
993bool GPUParallelDimAttr::isBlockZ() const {
994 return getProcessor() == gpu::Processor::BlockZ;
995}
996bool GPUParallelDimAttr::isAnyThread() const {
997 return isThreadX() || isThreadY() || isThreadZ();
998}
999bool GPUParallelDimAttr::isAnyBlock() const {
1000 return isBlockX() || isBlockY() || isBlockZ();
1001}
1002
1003//===----------------------------------------------------------------------===//
1004// GPUParallelDimsAttr
1005//===----------------------------------------------------------------------===//
1006
1007GPUParallelDimsAttr GPUParallelDimsAttr::seq(MLIRContext *ctx) {
1008 return GPUParallelDimsAttr::get(ctx, {GPUParallelDimAttr::seqDim(ctx)});
1009}
1010
1011bool GPUParallelDimsAttr::isSeq() const {
1012 assert(!getArray().empty() && "no par_dims found");
1013 if (getArray().size() == 1) {
1014 auto parDim = dyn_cast<GPUParallelDimAttr>(getArray()[0]);
1015 assert(parDim && "expected GPUParallelDimAttr");
1016 return parDim.isSeq();
1017 }
1018 return false;
1019}
1020
1021bool GPUParallelDimsAttr::isParallel() const { return !isSeq(); }
1022
1023bool GPUParallelDimsAttr::isMultiDim() const { return getArray().size() > 1; }
1024
1025bool GPUParallelDimsAttr::hasAnyBlockLevel() const {
1026 return llvm::any_of(
1027 getArray(), [](const GPUParallelDimAttr &p) { return p.isAnyBlock(); });
1028}
1029
1030bool GPUParallelDimsAttr::hasOnlyBlockLevel() const {
1031 return !getArray().empty() &&
1032 llvm::all_of(getArray(), [](const GPUParallelDimAttr &p) {
1033 return p.isAnyBlock();
1034 });
1035}
1036
1037bool GPUParallelDimsAttr::hasOnlyThreadYLevel() const {
1038 return !getArray().empty() &&
1039 llvm::all_of(getArray(), [](const GPUParallelDimAttr &p) {
1040 return p.isThreadY();
1041 });
1042}
1043
1044bool GPUParallelDimsAttr::hasOnlyThreadXLevel() const {
1045 return !getArray().empty() &&
1046 llvm::all_of(getArray(), [](const GPUParallelDimAttr &p) {
1047 return p.isThreadX();
1048 });
1049}
1050
1051Attribute GPUParallelDimsAttr::parse(AsmParser &parser, Type type) {
1052 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1053 parseGPUParallelDimList(parser);
1054 if (failed(parDims))
1055 return {};
1056 return GPUParallelDimsAttr::get(parser.getContext(), *parDims);
1057}
1058
1059void GPUParallelDimsAttr::print(AsmPrinter &printer) const {
1060 printGPUParallelDimList(printer, getArray());
1061}
1062
1063//===----------------------------------------------------------------------===//
1064// ActiveParDimsAttr
1065//===----------------------------------------------------------------------===//
1066
1067Attribute ActiveParDimsAttr::parse(AsmParser &parser, Type type) {
1068 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1069 parseGPUParallelDimList(parser);
1070 if (failed(parDims))
1071 return {};
1072 return ActiveParDimsAttr::get(parser.getContext(), *parDims);
1073}
1074
1075void ActiveParDimsAttr::print(AsmPrinter &printer) const {
1076 printGPUParallelDimList(printer, getArray());
1077}
return success()
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static void addOperandEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, MutableOperandRange operand)
Helper to add an effect on an operand, referenced by its mutable range.
Definition OpenACC.cpp:1356
static void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
Definition OpenACC.cpp:1366
static void getSingleRegionOpSuccessorRegions(Operation *op, Region &region, RegionBranchPoint point, SmallVectorImpl< RegionSuccessor > &regions)
Generic helper for single-region OpenACC ops that execute their body once and then continue after the...
Definition OpenACC.cpp:530
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
Definition OpenACC.cpp:541
b getContext())
static ParWidthOp getParWidthOpForLaunchArg(ComputeRegionOp op, GPUParallelDimAttr parDim)
static bool extractWaitClause(ComputeConstructT computeConstruct, DeviceType clauseDeviceType, MLIRContext *context, std::optional< Value > &waitDevnum, SmallVectorImpl< Value > &waitOperands, UnitAttr &waitOnly)
Extract wait for clauseDeviceType. Returns true if a clause was found.
static bool extractAsyncClause(ComputeConstructT computeConstruct, DeviceType clauseDeviceType, MLIRContext *context, std::optional< Value > &asyncOperand, UnitAttr &asyncOnly)
Extract async for clauseDeviceType. Returns true if a clause was found.
static void populateKernelEnvironmentAsyncWait(ComputeConstructT computeConstruct, DeviceType deviceType, std::optional< Value > &asyncOperand, UnitAttr &asyncOnly, std::optional< Value > &waitDevnum, SmallVectorImpl< Value > &waitOperands, UnitAttr &waitOnly)
This base class exposes generic asm parser hooks, usable across the various derived parsers.
@ Square
Square brackets surrounding zero or more operands.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
ParseResult parseKeywordOrString(std::string *result)
Parse a keyword or a quoted string.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseOptionalArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an optional arrow followed by a type list.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
This base class exposes generic asm printer hooks, usable across the various derived printers.
void printOptionalArrowTypeList(TypeRange &&types)
Print an optional arrow followed by a type list.
Attributes are known-constant values of operations.
Definition Attributes.h:25
This class represents an argument of a Block.
Definition Value.h:306
unsigned getArgNumber() const
Returns the number of this argument.
Definition Value.h:318
Block * getOwner() const
Returns the block that owns this argument.
Definition Value.h:315
Block represents an ordered list of Operations.
Definition Block.h:33
bool empty()
Definition Block.h:172
BlockArgument getArgument(unsigned i)
Definition Block.h:153
unsigned getNumArguments()
Definition Block.h:152
Operation & front()
Definition Block.h:177
Operation * getTerminator()
Get the terminator operation of this block.
Definition Block.cpp:249
void eraseArgument(unsigned index)
Erase the argument at 'index' and remove it from the argument list.
Definition Block.cpp:198
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
Definition Builders.cpp:171
IndexType getIndexType()
Definition Builders.cpp:59
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class provides a mutable adaptor for a range of operands.
Definition ValueRange.h:119
unsigned size() const
Returns the current size of the range.
Definition ValueRange.h:157
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region &region, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
ParseResult parseAssignmentList(SmallVectorImpl< Argument > &lhs, SmallVectorImpl< UnresolvedOperand > &rhs)
Parse a list of assignments of the form (x1 = y1, x2 = y2, ...)
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class helps build Operations.
Definition Builders.h:210
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
Definition Builders.h:434
This class represents an operand of an operation.
Definition Value.h:254
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
result_range getResults()
Definition Operation.h:440
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
This class represents a successor of a region.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
Definition Region.h:249
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class represents a specific instance of an effect.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
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
bool use_empty() const
Returns true if this value has no uses.
Definition Value.h:208
Type getType() const
Return the type of this value.
Definition Value.h:105
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
Definition Value.h:188
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
Definition OpenACC.cpp:5287
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
Definition OpenACC.cpp:5256
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
Definition OpenACC.cpp:5360
mlir::ArrayAttr getAsyncOnly(mlir::Operation *accDataClauseOp)
Returns an array of acc:DeviceTypeAttr attributes attached to an acc data clause operation,...
Definition OpenACC.cpp:5342
mlir::Type getVarType(mlir::Operation *accDataClauseOp)
Used to obtains the varType from a data clause operation which records the type of variable.
Definition OpenACC.cpp:5264
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
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.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:307
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
bool areValuesDefinedAbove(Range values, Region &limit)
Check if all values in the provided range are defined above the limit region.
Definition RegionUtils.h:26
This is the representation of an operand reference.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
Patterns must specify the root operation name they match against, and can also specify the benefit of...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.