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);
255static FailureOr<SmallVector<GPUParallelDimAttr>>
256parseGPUParallelDimList(
AsmParser &parser) {
258 auto parseParDim = [&]() -> ParseResult {
259 GPUParallelDimAttr dim;
260 if (parseProcessorValue(parser, dim))
262 parDims.push_back(dim);
266 "list of OpenACC GPU parallel dimensions"))
271static void printGPUParallelDimList(
AsmPrinter &printer,
274 llvm::interleaveComma(dims, printer, [&printer](
const GPUParallelDimAttr &p) {
275 printProcessorValue(printer, p);
286void KernelEnvironmentOp::getSuccessorRegions(
296void KernelEnvironmentOp::getCanonicalizationPatterns(
298 results.
add<RemoveEmptyKernelEnvironment>(context);
302template <
typename ComputeConstructT>
306 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly) {
307 if (computeConstruct.hasAsyncOnly(clauseDeviceType)) {
308 asyncOnly = UnitAttr::get(context);
311 if (
Value asyncValue = computeConstruct.getAsyncValue(clauseDeviceType)) {
312 asyncOperand = asyncValue;
319template <
typename ComputeConstructT>
322 std::optional<Value> &waitDevnum,
324 UnitAttr &waitOnly) {
325 if (computeConstruct.hasWaitOnly(clauseDeviceType)) {
326 waitOnly = UnitAttr::get(context);
329 Value devnum = computeConstruct.getWaitDevnum(clauseDeviceType);
330 auto waitValues = computeConstruct.getWaitValues(clauseDeviceType);
331 if (!devnum && waitValues.empty())
335 waitOperands.append(waitValues.begin(), waitValues.end());
339template <
typename ComputeConstructT>
341 ComputeConstructT computeConstruct, DeviceType deviceType,
342 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly,
344 UnitAttr &waitOnly) {
345 MLIRContext *context = computeConstruct->getContext();
350 if (deviceType != DeviceType::None)
352 asyncOperand, asyncOnly);
356 waitOperands, waitOnly)) {
357 if (deviceType != DeviceType::None)
359 waitOperands, waitOnly);
363template <
typename ComputeConstructT>
365KernelEnvironmentOp::createAndPopulate(ComputeConstructT computeConstruct,
366 DeviceType deviceType,
368 std::optional<Value> asyncOperand;
369 UnitAttr asyncOnly =
nullptr;
370 std::optional<Value> waitDevnum;
372 UnitAttr waitOnly =
nullptr;
374 asyncOnly, waitDevnum, waitOperands,
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();
383 return kernelEnvironment;
386template KernelEnvironmentOp
387KernelEnvironmentOp::createAndPopulate<ParallelOp>(ParallelOp, DeviceType,
389template KernelEnvironmentOp
390KernelEnvironmentOp::createAndPopulate<KernelsOp>(KernelsOp, DeviceType,
392template KernelEnvironmentOp
393KernelEnvironmentOp::createAndPopulate<SerialOp>(SerialOp, DeviceType,
396LogicalResult KernelEnvironmentOp::verify() {
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");
408LogicalResult FirstprivateMapInitialOp::verify() {
410 return emitError(
"data clause associated with firstprivate operation must "
413 return emitError(
"must have var operand");
414 if (!mlir::isa<mlir::acc::PointerLikeType>(
getVar().
getType()) &&
416 return emitError(
"var must be mappable or pointer-like");
417 if (mlir::isa<mlir::acc::PointerLikeType>(
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");
425void FirstprivateMapInitialOp::getEffects(
438void ReductionInitOp::getSuccessorRegions(
444void ReductionInitOp::getRegionInvocationBounds(
447 invocationBounds.emplace_back(1, 1);
454LogicalResult ReductionInitOp::verify() {
456 if (
auto yieldOp = dyn_cast<acc::YieldOp>(block.
getTerminator())) {
457 if (yieldOp.getNumOperands() != 1)
459 "region must yield exactly one value (private storage)");
461 return emitOpError(
"yielded value type must match var type");
470void ReductionCombineRegionOp::getSuccessorRegions(
476void ReductionCombineRegionOp::getRegionInvocationBounds(
479 invocationBounds.emplace_back(1, 1);
483ReductionCombineRegionOp::getSuccessorInputs(
RegionSuccessor successor) {
487LogicalResult ReductionCombineRegionOp::verify() {
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 "
501LogicalResult ReductionAccumulateOp::verify() {
502 Type valueType = getValue().getType();
503 auto ptrLikeTy = cast<PointerLikeType>(getMemref().
getType());
504 Type elementType = ptrLikeTy.getElementType();
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");
518LogicalResult ReductionAccumulateArrayOp::verify() {
519 if (getParDims().getArray().empty())
520 return emitOpError(
"par_dims must specify at least one parallel dimension");
528void ReductionCombineOp::getEffects(
544 GPUParallelDimAttr parDim) {
545 for (
auto launchArg : op.getLaunchArgs()) {
546 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
549 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
550 if (launchArgDim == parDim)
556std::optional<Value> ComputeRegionOp::getLaunchArg(GPUParallelDimAttr parDim) {
558 return parWidthOp.getResult();
563ComputeRegionOp::getKnownLaunchArg(GPUParallelDimAttr parDim) {
565 if (parWidthOp.getLaunchArg())
566 return parWidthOp.getLaunchArg();
570std::optional<uint64_t>
571ComputeRegionOp::getKnownConstantLaunchArg(GPUParallelDimAttr parDim) {
572 auto knownParWidth = getKnownLaunchArg(parDim);
573 if (knownParWidth.has_value())
579 getInputArgsMutable().append(value);
580 return getBody()->addArgument(value.
getType(), getLoc());
583std::optional<BlockArgument>
584ComputeRegionOp::wireHoistedValueThroughIns(
Value value) {
585 Region ®ion = getRegion();
587 auto useIsInRegion = [&](
OpOperand &use) ->
bool {
588 return region.
isAncestor(use.getOwner()->getParentRegion());
592 !llvm::any_of(value.
getUses(), useIsInRegion))
600bool ComputeRegionOp::isEffectivelySerial() {
603 if (getLaunchArg(GPUParallelDimAttr::seqDim(ctx)))
606 auto checkDim = [&](GPUParallelDimAttr dim) ->
bool {
607 auto val = getKnownConstantLaunchArg(dim);
608 return val && *val == 1;
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));
619BlockArgument ComputeRegionOp::parDimToWidth(GPUParallelDimAttr parDim) {
620 for (
auto [pos, launchArg] : llvm::enumerate(getLaunchArgs())) {
621 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
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);
630 llvm_unreachable(
"attempting to get unspecified parDim");
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));
645 Block *body = getBody();
649 unsigned numLaunchArgs = getLaunchArgs().size();
650 unsigned numInputArgs = getInputArgs().size();
651 if (argNumber >= numLaunchArgs + numInputArgs)
653 if (argNumber < numLaunchArgs)
654 return getLaunchArgs()[argNumber];
655 return getInputArgs()[argNumber - numLaunchArgs];
658std::optional<BlockArgument> ComputeRegionOp::getBlockArg(
Value value) {
659 Block *body = getBody();
660 for (
auto [idx, launchVal] : llvm::enumerate(getLaunchArgs())) {
661 if (launchVal == value)
664 unsigned numLaunch = getLaunchArgs().size();
665 for (
auto [idx, inputVal] : llvm::enumerate(getInputArgs())) {
666 if (inputVal == value)
674 results.
add<ComputeRegionRemoveDuplicateArgs, ComputeRegionRemoveUnusedArgs>(
678BlockArgument ComputeRegionOp::gpuParWidth(gpu::Processor processor) {
679 return parDimToWidth(GPUParallelDimAttr::get(
getContext(), processor));
682LogicalResult ComputeRegionOp::verify() {
683 for (
auto op : getLaunchArgs())
684 if (!op.getDefiningOp<acc::ParWidthOp>())
686 "launch arguments must be results of acc.par_width operations");
688 unsigned expectedBlockArgs = getLaunchArgs().size() + getInputArgs().size();
689 unsigned actualBlockArgs = getRegion().front().getNumArguments();
690 if (expectedBlockArgs != actualBlockArgs)
692 << expectedBlockArgs <<
" block arguments (launch + input), got "
699 ValueRange regionArgs = getBody()->getArguments();
703 assert(regionArgs.size() == (launchArgs.size() + inputArgs.size()) &&
704 "region args mismatch");
707 p <<
" stream(" << getStream() <<
" : " << getStream().getType() <<
")";
710 if (!launchArgs.empty()) {
712 for (
size_t j = 0;
j < launchArgs.size(); ++
j, ++i) {
713 p << regionArgs[i] <<
" = " << launchArgs[
j];
714 if (
j < launchArgs.size() - 1)
719 if (!inputArgs.empty()) {
721 for (
size_t j = 0;
j < inputArgs.size(); ++
j, ++i) {
722 p << regionArgs[i] <<
" = " << inputArgs[
j];
723 if (
j < inputArgs.size() - 1)
727 for (
size_t j = 0;
j < inputArgs.size(); ++
j) {
728 p << inputArgs[
j].getType();
729 if (
j < inputArgs.size() - 1)
738 getOperandSegmentSizeAttr());
741ParseResult ComputeRegionOp::parse(
OpAsmParser &parser,
752 bool hasStream =
false;
765 for (
size_t i = 0; i < regionArgs.size(); ++i)
766 types.push_back(indexType);
779 for (
auto [iterArg, type] : llvm::zip_equal(regionArgs, types))
785 ComputeRegionOp::ensureTerminator(*body, parser.
getBuilder(),
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");
794 ComputeRegionOp::getOperandSegmentSizeAttr(),
796 static_cast<int32_t>(numInputOperands),
797 hasStream ? 1 : 0}));
799 for (
size_t i = 0; i < numLaunchOperands; ++i) {
804 for (
size_t i = numLaunchOperands; i < regionArgs.size(); ++i) {
805 if (parser.
resolveOperand(inputOperands[i - numLaunchOperands], types[i],
825LogicalResult GPUSharedMemoryOp::verify() {
826 if (getNumCopies() <= 0)
828 if (getStaticUpperBoundBytes() <= 0)
829 return emitOpError(
"static_upper_bound_bytes must be positive");
831 bool hasScaling =
static_cast<bool>(getDynamicSharedMemoryScalingBytes());
832 bool hasFixed =
static_cast<bool>(getDynamicSharedMemoryFixedBytes());
833 if (hasScaling != hasFixed)
835 "dynamic_shared_memory_scaling_bytes and "
836 "dynamic_shared_memory_fixed_bytes must both be present or both be "
838 if (
auto scalingAttr = getDynamicSharedMemoryScalingBytesAttr())
839 if (scalingAttr.getValue().isNegative())
840 return emitOpError(
"dynamic_shared_memory_scaling_bytes must be "
842 if (
auto fixedAttr = getDynamicSharedMemoryFixedBytesAttr())
843 if (fixedAttr.getValue().isNegative())
844 return emitOpError(
"dynamic_shared_memory_fixed_bytes must be "
847 auto resultTy = cast<MemRefType>(getResult().
getType());
849 dyn_cast_if_present<gpu::AddressSpaceAttr>(resultTy.getMemorySpace());
851 addrSpace.getValue() != gpu::GPUDialect::getWorkgroupAddressSpace())
852 return emitOpError(
"result memref must use #gpu.address_space<workgroup>");
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");
875GPUParallelDimAttr GPUParallelDimAttr::get(
MLIRContext *context,
876 gpu::Processor proc) {
877 return processorParDim(context, proc);
880GPUParallelDimAttr GPUParallelDimAttr::seqDim(
MLIRContext *context) {
881 return processorParDim(context, gpu::Processor::Sequential);
884GPUParallelDimAttr GPUParallelDimAttr::threadXDim(
MLIRContext *context) {
885 return processorParDim(context, gpu::Processor::ThreadX);
888GPUParallelDimAttr GPUParallelDimAttr::threadYDim(
MLIRContext *context) {
889 return processorParDim(context, gpu::Processor::ThreadY);
892GPUParallelDimAttr GPUParallelDimAttr::threadZDim(
MLIRContext *context) {
893 return processorParDim(context, gpu::Processor::ThreadZ);
896GPUParallelDimAttr GPUParallelDimAttr::blockXDim(
MLIRContext *context) {
897 return processorParDim(context, gpu::Processor::BlockX);
900GPUParallelDimAttr GPUParallelDimAttr::blockYDim(
MLIRContext *context) {
901 return processorParDim(context, gpu::Processor::BlockY);
904GPUParallelDimAttr GPUParallelDimAttr::blockZDim(
MLIRContext *context) {
905 return processorParDim(context, gpu::Processor::BlockZ);
909 GPUParallelDimAttr dim;
910 if (parser.
parseLess() || parseProcessorValue(parser, dim) ||
913 "expected format `<` processor_name `>`");
919void GPUParallelDimAttr::print(
AsmPrinter &printer)
const {
921 printProcessorValue(printer, *
this);
925GPUParallelDimAttr GPUParallelDimAttr::threadDim(
MLIRContext *context,
927 assert(
index <= 2 &&
"thread dimension index must be 0, 1, or 2");
930 return threadXDim(context);
932 return threadYDim(context);
934 return threadZDim(context);
936 llvm_unreachable(
"validated thread dimension index");
939GPUParallelDimAttr GPUParallelDimAttr::blockDim(
MLIRContext *context,
941 assert(
index <= 2 &&
"block dimension index must be 0, 1, or 2");
944 return blockXDim(context);
946 return blockYDim(context);
948 return blockZDim(context);
950 llvm_unreachable(
"validated block dimension index");
953gpu::Processor GPUParallelDimAttr::getProcessor()
const {
954 return indexToGpuProcessor(getValue().getInt());
957int GPUParallelDimAttr::getOrder()
const {
958 return gpuProcessorIndex(getProcessor());
961GPUParallelDimAttr GPUParallelDimAttr::getOneHigher()
const {
962 int order = getOrder();
968GPUParallelDimAttr GPUParallelDimAttr::getOneLower()
const {
969 int order = getOrder();
975bool GPUParallelDimAttr::isSeq()
const {
976 return getProcessor() == gpu::Processor::Sequential;
978bool GPUParallelDimAttr::isThreadX()
const {
979 return getProcessor() == gpu::Processor::ThreadX;
981bool GPUParallelDimAttr::isThreadY()
const {
982 return getProcessor() == gpu::Processor::ThreadY;
984bool GPUParallelDimAttr::isThreadZ()
const {
985 return getProcessor() == gpu::Processor::ThreadZ;
987bool GPUParallelDimAttr::isBlockX()
const {
988 return getProcessor() == gpu::Processor::BlockX;
990bool GPUParallelDimAttr::isBlockY()
const {
991 return getProcessor() == gpu::Processor::BlockY;
993bool GPUParallelDimAttr::isBlockZ()
const {
994 return getProcessor() == gpu::Processor::BlockZ;
996bool GPUParallelDimAttr::isAnyThread()
const {
997 return isThreadX() || isThreadY() || isThreadZ();
999bool GPUParallelDimAttr::isAnyBlock()
const {
1000 return isBlockX() || isBlockY() || isBlockZ();
1007GPUParallelDimsAttr GPUParallelDimsAttr::seq(
MLIRContext *ctx) {
1008 return GPUParallelDimsAttr::get(ctx, {GPUParallelDimAttr::seqDim(ctx)});
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();
1021bool GPUParallelDimsAttr::isParallel()
const {
return !isSeq(); }
1023bool GPUParallelDimsAttr::isMultiDim()
const {
return getArray().size() > 1; }
1025bool GPUParallelDimsAttr::hasAnyBlockLevel()
const {
1026 return llvm::any_of(
1027 getArray(), [](
const GPUParallelDimAttr &p) {
return p.isAnyBlock(); });
1030bool GPUParallelDimsAttr::hasOnlyBlockLevel()
const {
1031 return !getArray().empty() &&
1032 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1033 return p.isAnyBlock();
1037bool GPUParallelDimsAttr::hasOnlyThreadYLevel()
const {
1038 return !getArray().empty() &&
1039 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1040 return p.isThreadY();
1044bool GPUParallelDimsAttr::hasOnlyThreadXLevel()
const {
1045 return !getArray().empty() &&
1046 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1047 return p.isThreadX();
1052 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1053 parseGPUParallelDimList(parser);
1056 return GPUParallelDimsAttr::get(parser.
getContext(), *parDims);
1059void GPUParallelDimsAttr::print(
AsmPrinter &printer)
const {
1060 printGPUParallelDimList(printer, getArray());
1068 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1069 parseGPUParallelDimList(parser);
1072 return ActiveParDimsAttr::get(parser.
getContext(), *parDims);
1075void ActiveParDimsAttr::print(
AsmPrinter &printer)
const {
1076 printGPUParallelDimList(printer, getArray());
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.