28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallVector.h"
56struct RemoveEmptyKernelEnvironment
58 using OpRewritePattern<acc::KernelEnvironmentOp>::OpRewritePattern;
60 LogicalResult matchAndRewrite(acc::KernelEnvironmentOp op,
61 PatternRewriter &rewriter)
const override {
62 assert(op->getNumRegions() == 1 &&
"expected op to have one region");
64 Block &block = op.getRegion().front();
70 if (!op.getWaitOperands().empty() || op.getWaitOnlyAttr())
72 op, op.getWaitOperands(), Value(),
73 op.getWaitDevnum(),
nullptr, Value());
81static void updateComputeRegionInputOperandSegments(ComputeRegionOp op,
84 const size_t numLaunch = op.getLaunchArgs().size();
85 op->setAttr(ComputeRegionOp::getOperandSegmentSizeAttr(),
87 static_cast<int32_t>(numInput),
88 op.getStream() ? 1 : 0}));
91struct ComputeRegionRemoveDuplicateArgs
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();
101 "region args mismatch");
103 bool mergedAny =
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)))
111 unsigned keepIdx =
static_cast<unsigned>(numLaunch + i);
112 unsigned dropIdx =
static_cast<unsigned>(numLaunch + j);
116 op->eraseOperand(dropIdx);
129 updateComputeRegionInputOperandSegments(op, rewriter, numInput);
134struct ComputeRegionRemoveUnusedArgs
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();
144 "region args mismatch");
146 bool changed =
false;
147 for (
size_t k = numLaunch; k < numLaunch + numInput;) {
153 op->eraseOperand(
static_cast<unsigned>(k));
160 updateComputeRegionInputOperandSegments(op, rewriter, numInput);
165template <
typename EffectTy>
170 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
171 effects.emplace_back(EffectTy::get(), &operand[i]);
174template <
typename EffectTy>
179 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
182static int64_t gpuProcessorIndex(gpu::Processor p) {
184 case gpu::Processor::Sequential:
186 case gpu::Processor::ThreadX:
188 case gpu::Processor::ThreadY:
190 case gpu::Processor::ThreadZ:
192 case gpu::Processor::BlockX:
194 case gpu::Processor::BlockY:
196 case gpu::Processor::BlockZ:
199 llvm_unreachable(
"unhandled gpu::Processor");
202static gpu::Processor indexToGpuProcessor(
int64_t idx) {
205 return gpu::Processor::Sequential;
207 return gpu::Processor::ThreadX;
209 return gpu::Processor::ThreadY;
211 return gpu::Processor::ThreadZ;
213 return gpu::Processor::BlockX;
215 return gpu::Processor::BlockY;
217 return gpu::Processor::BlockZ;
219 return gpu::Processor::Sequential;
224 return GPUParallelDimAttr::get(
225 context, IntegerAttr::get(IndexType::get(context), dimInt));
228static GPUParallelDimAttr processorParDim(
MLIRContext *context,
229 gpu::Processor proc) {
230 return GPUParallelDimAttr::get(
232 IntegerAttr::get(IndexType::get(context), gpuProcessorIndex(proc)));
235static ParseResult parseProcessorValue(
AsmParser &parser,
236 GPUParallelDimAttr &dim) {
241 auto maybeProcessor = gpu::symbolizeProcessor(keyword);
244 <<
"expected one of ::mlir::gpu::Processor enum names";
245 dim = intToParDim(parser.
getContext(), gpuProcessorIndex(*maybeProcessor));
249static void printProcessorValue(
AsmPrinter &printer,
250 const GPUParallelDimAttr &attr) {
251 gpu::Processor processor = indexToGpuProcessor(attr.getValue().getInt());
252 printer << gpu::stringifyProcessor(processor);
261void KernelEnvironmentOp::getSuccessorRegions(
271void KernelEnvironmentOp::getCanonicalizationPatterns(
273 results.
add<RemoveEmptyKernelEnvironment>(context);
277template <
typename ComputeConstructT>
281 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly) {
282 if (computeConstruct.hasAsyncOnly(clauseDeviceType)) {
283 asyncOnly = UnitAttr::get(context);
286 if (
Value asyncValue = computeConstruct.getAsyncValue(clauseDeviceType)) {
287 asyncOperand = asyncValue;
294template <
typename ComputeConstructT>
297 std::optional<Value> &waitDevnum,
299 UnitAttr &waitOnly) {
300 if (computeConstruct.hasWaitOnly(clauseDeviceType)) {
301 waitOnly = UnitAttr::get(context);
304 Value devnum = computeConstruct.getWaitDevnum(clauseDeviceType);
305 auto waitValues = computeConstruct.getWaitValues(clauseDeviceType);
306 if (!devnum && waitValues.empty())
310 waitOperands.append(waitValues.begin(), waitValues.end());
314template <
typename ComputeConstructT>
316 ComputeConstructT computeConstruct, DeviceType deviceType,
317 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly,
319 UnitAttr &waitOnly) {
320 MLIRContext *context = computeConstruct->getContext();
325 if (deviceType != DeviceType::None)
327 asyncOperand, asyncOnly);
331 waitOperands, waitOnly)) {
332 if (deviceType != DeviceType::None)
334 waitOperands, waitOnly);
338template <
typename ComputeConstructT>
340KernelEnvironmentOp::createAndPopulate(ComputeConstructT computeConstruct,
341 DeviceType deviceType,
343 std::optional<Value> asyncOperand;
344 UnitAttr asyncOnly =
nullptr;
345 std::optional<Value> waitDevnum;
347 UnitAttr waitOnly =
nullptr;
349 asyncOnly, waitDevnum, waitOperands,
352 auto kernelEnvironment = KernelEnvironmentOp::create(
353 builder, computeConstruct->getLoc(),
354 computeConstruct.getDataClauseOperands(), asyncOperand.value_or(
Value()),
355 asyncOnly, waitDevnum.value_or(
Value()), waitOperands, waitOnly);
356 Block &block = kernelEnvironment.getRegion().emplaceBlock();
358 return kernelEnvironment;
361template KernelEnvironmentOp
362KernelEnvironmentOp::createAndPopulate<ParallelOp>(ParallelOp, DeviceType,
364template KernelEnvironmentOp
365KernelEnvironmentOp::createAndPopulate<KernelsOp>(KernelsOp, DeviceType,
367template KernelEnvironmentOp
368KernelEnvironmentOp::createAndPopulate<SerialOp>(SerialOp, DeviceType,
371LogicalResult KernelEnvironmentOp::verify() {
373 return emitError(
"async-only cannot appear with async operand");
374 if (getWaitOnly() && (!getWaitOperands().empty() || getWaitDevnum()))
375 return emitError(
"wait-only cannot appear with wait operands or devnum");
383LogicalResult FirstprivateMapInitialOp::verify() {
385 return emitError(
"data clause associated with firstprivate operation must "
388 return emitError(
"must have var operand");
389 if (!mlir::isa<mlir::acc::PointerLikeType>(
getVar().
getType()) &&
391 return emitError(
"var must be mappable or pointer-like");
392 if (mlir::isa<mlir::acc::PointerLikeType>(
getVar().
getType()) &&
394 return emitError(
"varType must capture the element type of var");
395 if (getModifiers() != acc::DataClauseModifier::none)
396 return emitError(
"no data clause modifiers are allowed");
400void FirstprivateMapInitialOp::getEffects(
413void ReductionInitOp::getSuccessorRegions(
419void ReductionInitOp::getRegionInvocationBounds(
422 invocationBounds.emplace_back(1, 1);
429LogicalResult ReductionInitOp::verify() {
431 if (
auto yieldOp = dyn_cast<acc::YieldOp>(block.
getTerminator())) {
432 if (yieldOp.getNumOperands() != 1)
434 "region must yield exactly one value (private storage)");
436 return emitOpError(
"yielded value type must match var type");
445void ReductionCombineRegionOp::getSuccessorRegions(
451void ReductionCombineRegionOp::getRegionInvocationBounds(
454 invocationBounds.emplace_back(1, 1);
458ReductionCombineRegionOp::getSuccessorInputs(
RegionSuccessor successor) {
462LogicalResult ReductionCombineRegionOp::verify() {
464 if (
auto yieldOp = dyn_cast<acc::YieldOp>(block.
getTerminator())) {
465 if (yieldOp.getNumOperands() != 0)
466 return emitOpError(
"region must be terminated by acc.yield with no "
476LogicalResult ReductionAccumulateOp::verify() {
477 Type valueType = getValue().getType();
478 auto ptrLikeTy = cast<PointerLikeType>(getMemref().
getType());
479 Type elementType = ptrLikeTy.getElementType();
481 return emitOpError(
"pointer-like destination must have an element type");
482 if (elementType != valueType)
483 return emitOpError(
"pointer-like element type must match value type");
484 if (getParDims().getArray().empty())
485 return emitOpError(
"par_dims must specify at least one parallel dimension");
493LogicalResult ReductionAccumulateArrayOp::verify() {
494 if (getParDims().getArray().empty())
495 return emitOpError(
"par_dims must specify at least one parallel dimension");
503void ReductionCombineOp::getEffects(
519 GPUParallelDimAttr parDim) {
520 for (
auto launchArg : op.getLaunchArgs()) {
521 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
524 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
525 if (launchArgDim == parDim)
531std::optional<Value> ComputeRegionOp::getLaunchArg(GPUParallelDimAttr parDim) {
533 return parWidthOp.getResult();
538ComputeRegionOp::getKnownLaunchArg(GPUParallelDimAttr parDim) {
540 if (parWidthOp.getLaunchArg())
541 return parWidthOp.getLaunchArg();
545std::optional<uint64_t>
546ComputeRegionOp::getKnownConstantLaunchArg(GPUParallelDimAttr parDim) {
547 auto knownParWidth = getKnownLaunchArg(parDim);
548 if (knownParWidth.has_value())
554 getInputArgsMutable().append(value);
555 return getBody()->addArgument(value.
getType(), getLoc());
558std::optional<BlockArgument>
559ComputeRegionOp::wireHoistedValueThroughIns(
Value value) {
560 Region ®ion = getRegion();
562 auto useIsInRegion = [&](
OpOperand &use) ->
bool {
563 return region.
isAncestor(use.getOwner()->getParentRegion());
567 !llvm::any_of(value.
getUses(), useIsInRegion))
575bool ComputeRegionOp::isEffectivelySerial() {
578 if (getLaunchArg(GPUParallelDimAttr::seqDim(ctx)))
581 auto checkDim = [&](GPUParallelDimAttr dim) ->
bool {
582 auto val = getKnownConstantLaunchArg(dim);
583 return val && *val == 1;
586 return checkDim(GPUParallelDimAttr::threadXDim(ctx)) &&
587 checkDim(GPUParallelDimAttr::threadYDim(ctx)) &&
588 checkDim(GPUParallelDimAttr::threadZDim(ctx)) &&
589 checkDim(GPUParallelDimAttr::blockXDim(ctx)) &&
590 checkDim(GPUParallelDimAttr::blockYDim(ctx)) &&
591 checkDim(GPUParallelDimAttr::blockZDim(ctx));
594BlockArgument ComputeRegionOp::parDimToWidth(GPUParallelDimAttr parDim) {
595 for (
auto [pos, launchArg] : llvm::enumerate(getLaunchArgs())) {
596 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
598 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
599 if (launchArgDim == parDim) {
600 assert(pos < getRegion().front().getNumArguments() &&
601 "launch arg position out of range");
602 return getRegion().front().getArgument(pos);
605 llvm_unreachable(
"attempting to get unspecified parDim");
610 for (
auto launchArg : getLaunchArgs()) {
611 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
612 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
613 int64_t dimInt = launchArgDim.getValue().getInt();
614 parDims.push_back(intToParDim(
getContext(), dimInt));
620 Block *body = getBody();
624 unsigned numLaunchArgs = getLaunchArgs().size();
625 unsigned numInputArgs = getInputArgs().size();
626 if (argNumber >= numLaunchArgs + numInputArgs)
628 if (argNumber < numLaunchArgs)
629 return getLaunchArgs()[argNumber];
630 return getInputArgs()[argNumber - numLaunchArgs];
633std::optional<BlockArgument> ComputeRegionOp::getBlockArg(
Value value) {
634 Block *body = getBody();
635 for (
auto [idx, launchVal] : llvm::enumerate(getLaunchArgs())) {
636 if (launchVal == value)
639 unsigned numLaunch = getLaunchArgs().size();
640 for (
auto [idx, inputVal] : llvm::enumerate(getInputArgs())) {
641 if (inputVal == value)
649 results.
add<ComputeRegionRemoveDuplicateArgs, ComputeRegionRemoveUnusedArgs>(
653BlockArgument ComputeRegionOp::gpuParWidth(gpu::Processor processor) {
654 return parDimToWidth(GPUParallelDimAttr::get(
getContext(), processor));
657LogicalResult ComputeRegionOp::verify() {
658 for (
auto op : getLaunchArgs())
659 if (!op.getDefiningOp<acc::ParWidthOp>())
661 "launch arguments must be results of acc.par_width operations");
663 unsigned expectedBlockArgs = getLaunchArgs().size() + getInputArgs().size();
664 unsigned actualBlockArgs = getRegion().front().getNumArguments();
665 if (expectedBlockArgs != actualBlockArgs)
667 << expectedBlockArgs <<
" block arguments (launch + input), got "
674 ValueRange regionArgs = getBody()->getArguments();
678 assert(regionArgs.size() == (launchArgs.size() + inputArgs.size()) &&
679 "region args mismatch");
682 p <<
" stream(" << getStream() <<
" : " << getStream().getType() <<
")";
685 if (!launchArgs.empty()) {
687 for (
size_t j = 0;
j < launchArgs.size(); ++
j, ++i) {
688 p << regionArgs[i] <<
" = " << launchArgs[
j];
689 if (
j < launchArgs.size() - 1)
694 if (!inputArgs.empty()) {
696 for (
size_t j = 0;
j < inputArgs.size(); ++
j, ++i) {
697 p << regionArgs[i] <<
" = " << inputArgs[
j];
698 if (
j < inputArgs.size() - 1)
702 for (
size_t j = 0;
j < inputArgs.size(); ++
j) {
703 p << inputArgs[
j].getType();
704 if (
j < inputArgs.size() - 1)
713 getOperandSegmentSizeAttr());
716ParseResult ComputeRegionOp::parse(
OpAsmParser &parser,
727 bool hasStream =
false;
740 for (
size_t i = 0; i < regionArgs.size(); ++i)
741 types.push_back(indexType);
754 for (
auto [iterArg, type] : llvm::zip_equal(regionArgs, types))
760 ComputeRegionOp::ensureTerminator(*body, parser.
getBuilder(),
763 const size_t numLaunchOperands = launchOperands.size();
764 const size_t numInputOperands = inputOperands.size();
765 assert(numLaunchOperands + numInputOperands == regionArgs.size() &&
766 "compute region args mismatch");
769 ComputeRegionOp::getOperandSegmentSizeAttr(),
771 static_cast<int32_t>(numInputOperands),
772 hasStream ? 1 : 0}));
774 for (
size_t i = 0; i < numLaunchOperands; ++i) {
779 for (
size_t i = numLaunchOperands; i < regionArgs.size(); ++i) {
780 if (parser.
resolveOperand(inputOperands[i - numLaunchOperands], types[i],
800LogicalResult GPUSharedMemoryOp::verify() {
801 if (getNumCopies() <= 0)
803 if (getStaticUpperBoundBytes() <= 0)
804 return emitOpError(
"static_upper_bound_bytes must be positive");
806 bool hasScaling =
static_cast<bool>(getDynamicSharedMemoryScalingBytes());
807 bool hasFixed =
static_cast<bool>(getDynamicSharedMemoryFixedBytes());
808 if (hasScaling != hasFixed)
810 "dynamic_shared_memory_scaling_bytes and "
811 "dynamic_shared_memory_fixed_bytes must both be present or both be "
813 if (
auto scalingAttr = getDynamicSharedMemoryScalingBytesAttr())
814 if (scalingAttr.getValue().isNegative())
815 return emitOpError(
"dynamic_shared_memory_scaling_bytes must be "
817 if (
auto fixedAttr = getDynamicSharedMemoryFixedBytesAttr())
818 if (fixedAttr.getValue().isNegative())
819 return emitOpError(
"dynamic_shared_memory_fixed_bytes must be "
822 auto resultTy = cast<MemRefType>(getResult().
getType());
824 dyn_cast_if_present<gpu::AddressSpaceAttr>(resultTy.getMemorySpace());
826 addrSpace.getValue() != gpu::GPUDialect::getWorkgroupAddressSpace())
827 return emitOpError(
"result memref must use #gpu.address_space<workgroup>");
836LogicalResult PredicateRegionOp::verify() {
837 if (getRegion().empty())
838 return emitOpError(
"region needs to have at least one block");
839 if (getRegion().front().getNumArguments() > 0)
840 return emitOpError(
"region cannot have any arguments");
841 if (!getOperation()->getParentOfType<ComputeRegionOp>())
842 return emitOpError(
"must be nested within an acc.compute_region operation");
850GPUParallelDimAttr GPUParallelDimAttr::get(
MLIRContext *context,
851 gpu::Processor proc) {
852 return processorParDim(context, proc);
855GPUParallelDimAttr GPUParallelDimAttr::seqDim(
MLIRContext *context) {
856 return processorParDim(context, gpu::Processor::Sequential);
859GPUParallelDimAttr GPUParallelDimAttr::threadXDim(
MLIRContext *context) {
860 return processorParDim(context, gpu::Processor::ThreadX);
863GPUParallelDimAttr GPUParallelDimAttr::threadYDim(
MLIRContext *context) {
864 return processorParDim(context, gpu::Processor::ThreadY);
867GPUParallelDimAttr GPUParallelDimAttr::threadZDim(
MLIRContext *context) {
868 return processorParDim(context, gpu::Processor::ThreadZ);
871GPUParallelDimAttr GPUParallelDimAttr::blockXDim(
MLIRContext *context) {
872 return processorParDim(context, gpu::Processor::BlockX);
875GPUParallelDimAttr GPUParallelDimAttr::blockYDim(
MLIRContext *context) {
876 return processorParDim(context, gpu::Processor::BlockY);
879GPUParallelDimAttr GPUParallelDimAttr::blockZDim(
MLIRContext *context) {
880 return processorParDim(context, gpu::Processor::BlockZ);
884 GPUParallelDimAttr dim;
885 if (parser.
parseLess() || parseProcessorValue(parser, dim) ||
888 "expected format `<` processor_name `>`");
894void GPUParallelDimAttr::print(
AsmPrinter &printer)
const {
896 printProcessorValue(printer, *
this);
900GPUParallelDimAttr GPUParallelDimAttr::threadDim(
MLIRContext *context,
902 assert(
index <= 2 &&
"thread dimension index must be 0, 1, or 2");
905 return threadXDim(context);
907 return threadYDim(context);
909 return threadZDim(context);
911 llvm_unreachable(
"validated thread dimension index");
914GPUParallelDimAttr GPUParallelDimAttr::blockDim(
MLIRContext *context,
916 assert(
index <= 2 &&
"block dimension index must be 0, 1, or 2");
919 return blockXDim(context);
921 return blockYDim(context);
923 return blockZDim(context);
925 llvm_unreachable(
"validated block dimension index");
928gpu::Processor GPUParallelDimAttr::getProcessor()
const {
929 return indexToGpuProcessor(getValue().getInt());
932int GPUParallelDimAttr::getOrder()
const {
933 return gpuProcessorIndex(getProcessor());
936GPUParallelDimAttr GPUParallelDimAttr::getOneHigher()
const {
937 int order = getOrder();
943GPUParallelDimAttr GPUParallelDimAttr::getOneLower()
const {
944 int order = getOrder();
950bool GPUParallelDimAttr::isSeq()
const {
951 return getProcessor() == gpu::Processor::Sequential;
953bool GPUParallelDimAttr::isThreadX()
const {
954 return getProcessor() == gpu::Processor::ThreadX;
956bool GPUParallelDimAttr::isThreadY()
const {
957 return getProcessor() == gpu::Processor::ThreadY;
959bool GPUParallelDimAttr::isThreadZ()
const {
960 return getProcessor() == gpu::Processor::ThreadZ;
962bool GPUParallelDimAttr::isBlockX()
const {
963 return getProcessor() == gpu::Processor::BlockX;
965bool GPUParallelDimAttr::isBlockY()
const {
966 return getProcessor() == gpu::Processor::BlockY;
968bool GPUParallelDimAttr::isBlockZ()
const {
969 return getProcessor() == gpu::Processor::BlockZ;
971bool GPUParallelDimAttr::isAnyThread()
const {
972 return isThreadX() || isThreadY() || isThreadZ();
974bool GPUParallelDimAttr::isAnyBlock()
const {
975 return isBlockX() || isBlockY() || isBlockZ();
982GPUParallelDimsAttr GPUParallelDimsAttr::seq(
MLIRContext *ctx) {
983 return GPUParallelDimsAttr::get(ctx, {GPUParallelDimAttr::seqDim(ctx)});
986bool GPUParallelDimsAttr::isSeq()
const {
987 assert(!getArray().empty() &&
"no par_dims found");
988 if (getArray().size() == 1) {
989 auto parDim = dyn_cast<GPUParallelDimAttr>(getArray()[0]);
990 assert(parDim &&
"expected GPUParallelDimAttr");
991 return parDim.isSeq();
996bool GPUParallelDimsAttr::isParallel()
const {
return !isSeq(); }
998bool GPUParallelDimsAttr::isMultiDim()
const {
return getArray().size() > 1; }
1000bool GPUParallelDimsAttr::hasAnyBlockLevel()
const {
1001 return llvm::any_of(
1002 getArray(), [](
const GPUParallelDimAttr &p) {
return p.isAnyBlock(); });
1005bool GPUParallelDimsAttr::hasOnlyBlockLevel()
const {
1006 return !getArray().empty() &&
1007 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1008 return p.isAnyBlock();
1012bool GPUParallelDimsAttr::hasOnlyThreadYLevel()
const {
1013 return !getArray().empty() &&
1014 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1015 return p.isThreadY();
1019bool GPUParallelDimsAttr::hasOnlyThreadXLevel()
const {
1020 return !getArray().empty() &&
1021 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1022 return p.isThreadX();
1029 auto parseParDim = [&]() -> ParseResult {
1030 GPUParallelDimAttr dim;
1031 if (parseProcessorValue(parser, dim))
1033 parDims.push_back(dim);
1037 "list of OpenACC GPU parallel dimensions"))
1039 return GPUParallelDimsAttr::get(parser.
getContext(), parDims);
1042void GPUParallelDimsAttr::print(
AsmPrinter &printer)
const {
1044 llvm::interleaveComma(getArray(), printer,
1045 [&printer](
const GPUParallelDimAttr &p) {
1046 printProcessorValue(printer, p);
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.
static void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
static void getSingleRegionOpSuccessorRegions(Operation *op, Region ®ion, RegionBranchPoint point, SmallVectorImpl< RegionSuccessor > ®ions)
Generic helper for single-region OpenACC ops that execute their body once and then continue after the...
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
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.
This class represents an argument of a Block.
unsigned getArgNumber() const
Returns the number of this argument.
Block * getOwner() const
Returns the block that owns this argument.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
void eraseArgument(unsigned index)
Erase the argument at 'index' and remove it from the argument list.
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
MLIRContext is the top-level object for a collection of MLIR operations.
This class provides a mutable adaptor for a range of operands.
unsigned size() const
Returns the current size of the range.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region ®ion, 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.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
This class represents an operand of an operation.
Operation is the basic unit of execution within MLIR.
result_range getResults()
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.
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
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.
static DerivedEffect * get()
static CurrentDeviceIdResource * get()
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
Type getType() const
Return the type of this value.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
mlir::ArrayAttr getAsyncOnly(mlir::Operation *accDataClauseOp)
Returns an array of acc:DeviceTypeAttr attributes attached to an acc data clause operation,...
mlir::Type getVarType(mlir::Operation *accDataClauseOp)
Used to obtains the varType from a data clause operation which records the type of variable.
Include the generated interface declarations.
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region ®ion)
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.
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.
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.