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());
83static void setComputeRegionInputOperandSegments(ComputeRegionOp op,
87 const size_t numLaunch = op.getLaunchArgs().size();
89 rewriter.
getStringAttr(ComputeRegionOp::getOperandSegmentSizeAttr()),
91 static_cast<int32_t>(numInput),
95struct ComputeRegionRemoveDuplicateArgs
99 LogicalResult matchAndRewrite(ComputeRegionOp op,
100 PatternRewriter &rewriter)
const override {
101 Block *body = op.getBody();
102 const size_t numLaunch = op.getLaunchArgs().size();
103 size_t numInput = op.getInputArgs().size();
105 "region args mismatch");
107 bool hasDuplicate =
false;
108 for (
size_t j = 1; j < numInput && !hasDuplicate; ++j)
109 for (
size_t i = 0; i < j; ++i)
110 if (op->getOperand(
static_cast<unsigned>(numLaunch + i)) ==
111 op->getOperand(
static_cast<unsigned>(numLaunch + j))) {
118 const bool hasStream =
static_cast<bool>(op.getStream());
122 for (
size_t j = 1; j < numInput && !merged; ++j) {
123 for (
size_t i = 0; i < j; ++i) {
124 if (op->getOperand(
static_cast<unsigned>(numLaunch + i)) !=
125 op->getOperand(
static_cast<unsigned>(numLaunch + j)))
127 unsigned keepIdx =
static_cast<unsigned>(numLaunch + i);
128 unsigned dropIdx =
static_cast<unsigned>(numLaunch + j);
132 op->eraseOperand(dropIdx);
141 setComputeRegionInputOperandSegments(op, rewriter, numInput, hasStream);
147struct ComputeRegionRemoveUnusedArgs
151 LogicalResult matchAndRewrite(ComputeRegionOp op,
152 PatternRewriter &rewriter)
const override {
153 Block *body = op.getBody();
154 const size_t numLaunch = op.getLaunchArgs().size();
155 size_t numInput = op.getInputArgs().size();
157 "region args mismatch");
159 bool hasUnused =
false;
160 for (
size_t k = numLaunch; k < numLaunch + numInput; ++k)
168 const bool hasStream =
static_cast<bool>(op.getStream());
170 for (
size_t k = numLaunch; k < numLaunch + numInput;) {
176 op->eraseOperand(
static_cast<unsigned>(k));
179 setComputeRegionInputOperandSegments(op, rewriter, numInput, hasStream);
185template <
typename EffectTy>
190 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
191 effects.emplace_back(EffectTy::get(), &operand[i]);
194template <
typename EffectTy>
199 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
202static int64_t gpuProcessorIndex(gpu::Processor p) {
204 case gpu::Processor::Sequential:
206 case gpu::Processor::ThreadX:
208 case gpu::Processor::ThreadY:
210 case gpu::Processor::ThreadZ:
212 case gpu::Processor::BlockX:
214 case gpu::Processor::BlockY:
216 case gpu::Processor::BlockZ:
219 llvm_unreachable(
"unhandled gpu::Processor");
222static gpu::Processor indexToGpuProcessor(
int64_t idx) {
225 return gpu::Processor::Sequential;
227 return gpu::Processor::ThreadX;
229 return gpu::Processor::ThreadY;
231 return gpu::Processor::ThreadZ;
233 return gpu::Processor::BlockX;
235 return gpu::Processor::BlockY;
237 return gpu::Processor::BlockZ;
239 return gpu::Processor::Sequential;
244 return GPUParallelDimAttr::get(
245 context, IntegerAttr::get(IndexType::get(context), dimInt));
248static GPUParallelDimAttr processorParDim(
MLIRContext *context,
249 gpu::Processor proc) {
250 return GPUParallelDimAttr::get(
252 IntegerAttr::get(IndexType::get(context), gpuProcessorIndex(proc)));
255static ParseResult parseProcessorValue(
AsmParser &parser,
256 GPUParallelDimAttr &dim) {
261 auto maybeProcessor = gpu::symbolizeProcessor(keyword);
264 <<
"expected one of ::mlir::gpu::Processor enum names";
265 dim = intToParDim(parser.
getContext(), gpuProcessorIndex(*maybeProcessor));
269static void printProcessorValue(
AsmPrinter &printer,
270 const GPUParallelDimAttr &attr) {
271 gpu::Processor processor = indexToGpuProcessor(attr.getValue().getInt());
272 printer << gpu::stringifyProcessor(processor);
275static FailureOr<SmallVector<GPUParallelDimAttr>>
276parseGPUParallelDimList(
AsmParser &parser) {
278 auto parseParDim = [&]() -> ParseResult {
279 GPUParallelDimAttr dim;
280 if (parseProcessorValue(parser, dim))
282 parDims.push_back(dim);
286 "list of OpenACC GPU parallel dimensions"))
291static void printGPUParallelDimList(
AsmPrinter &printer,
294 llvm::interleaveComma(dims, printer, [&printer](
const GPUParallelDimAttr &p) {
295 printProcessorValue(printer, p);
306void KernelEnvironmentOp::getSuccessorRegions(
316void KernelEnvironmentOp::getCanonicalizationPatterns(
318 results.
add<RemoveEmptyKernelEnvironment>(context);
322template <
typename ComputeConstructT>
326 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly) {
327 if (computeConstruct.hasAsyncOnly(clauseDeviceType)) {
328 asyncOnly = UnitAttr::get(context);
331 if (
Value asyncValue = computeConstruct.getAsyncValue(clauseDeviceType)) {
332 asyncOperand = asyncValue;
339template <
typename ComputeConstructT>
342 std::optional<Value> &waitDevnum,
344 UnitAttr &waitOnly) {
345 if (computeConstruct.hasWaitOnly(clauseDeviceType)) {
346 waitOnly = UnitAttr::get(context);
349 Value devnum = computeConstruct.getWaitDevnum(clauseDeviceType);
350 auto waitValues = computeConstruct.getWaitValues(clauseDeviceType);
351 if (!devnum && waitValues.empty())
355 waitOperands.append(waitValues.begin(), waitValues.end());
359template <
typename ComputeConstructT>
361 ComputeConstructT computeConstruct, DeviceType deviceType,
362 std::optional<Value> &asyncOperand, UnitAttr &asyncOnly,
364 UnitAttr &waitOnly) {
365 MLIRContext *context = computeConstruct->getContext();
370 if (deviceType != DeviceType::None)
372 asyncOperand, asyncOnly);
376 waitOperands, waitOnly)) {
377 if (deviceType != DeviceType::None)
379 waitOperands, waitOnly);
383template <
typename ComputeConstructT>
385KernelEnvironmentOp::createAndPopulate(ComputeConstructT computeConstruct,
386 DeviceType deviceType,
388 std::optional<Value> asyncOperand;
389 UnitAttr asyncOnly =
nullptr;
390 std::optional<Value> waitDevnum;
392 UnitAttr waitOnly =
nullptr;
394 asyncOnly, waitDevnum, waitOperands,
397 auto kernelEnvironment = KernelEnvironmentOp::create(
398 builder, computeConstruct->getLoc(),
399 computeConstruct.getDataClauseOperands(), asyncOperand.value_or(
Value()),
400 asyncOnly, waitDevnum.value_or(
Value()), waitOperands, waitOnly);
401 Block &block = kernelEnvironment.getRegion().emplaceBlock();
403 return kernelEnvironment;
406template KernelEnvironmentOp
407KernelEnvironmentOp::createAndPopulate<ParallelOp>(ParallelOp, DeviceType,
409template KernelEnvironmentOp
410KernelEnvironmentOp::createAndPopulate<KernelsOp>(KernelsOp, DeviceType,
412template KernelEnvironmentOp
413KernelEnvironmentOp::createAndPopulate<SerialOp>(SerialOp, DeviceType,
416LogicalResult KernelEnvironmentOp::verify() {
418 return emitError(
"async-only cannot appear with async operand");
419 if (getWaitOnly() && (!getWaitOperands().empty() || getWaitDevnum()))
420 return emitError(
"wait-only cannot appear with wait operands or devnum");
428LogicalResult FirstprivateMapInitialOp::verify() {
430 return emitError(
"data clause associated with firstprivate operation must "
433 return emitError(
"must have var operand");
434 if (!mlir::isa<mlir::acc::PointerLikeType>(
getVar().
getType()) &&
436 return emitError(
"var must be mappable or pointer-like");
437 if (mlir::isa<mlir::acc::PointerLikeType>(
getVar().
getType()) &&
439 return emitError(
"varType must capture the element type of var");
440 if (getModifiers() != acc::DataClauseModifier::none)
441 return emitError(
"no data clause modifiers are allowed");
445void FirstprivateMapInitialOp::getEffects(
458void ReductionInitOp::getSuccessorRegions(
464void ReductionInitOp::getRegionInvocationBounds(
467 invocationBounds.emplace_back(1, 1);
474LogicalResult ReductionInitOp::verify() {
476 if (
auto yieldOp = dyn_cast<acc::YieldOp>(block.
getTerminator())) {
477 if (yieldOp.getNumOperands() != 1)
479 "region must yield exactly one value (private storage)");
481 return emitOpError(
"yielded value type must match var type");
490void ReductionCombineRegionOp::getSuccessorRegions(
496void ReductionCombineRegionOp::getRegionInvocationBounds(
499 invocationBounds.emplace_back(1, 1);
503ReductionCombineRegionOp::getSuccessorInputs(
RegionSuccessor successor) {
507LogicalResult ReductionCombineRegionOp::verify() {
509 if (
auto yieldOp = dyn_cast<acc::YieldOp>(block.
getTerminator())) {
510 if (yieldOp.getNumOperands() != 0)
511 return emitOpError(
"region must be terminated by acc.yield with no "
521LogicalResult ReductionAccumulateOp::verify() {
522 Type valueType = getValue().getType();
523 auto ptrLikeTy = cast<PointerLikeType>(getMemref().
getType());
524 Type elementType = ptrLikeTy.getElementType();
526 return emitOpError(
"pointer-like destination must have an element type");
527 if (elementType != valueType)
528 return emitOpError(
"pointer-like element type must match value type");
529 if (getParDims().getArray().empty())
530 return emitOpError(
"par_dims must specify at least one parallel dimension");
538LogicalResult ReductionAccumulateArrayOp::verify() {
539 if (getParDims().getArray().empty())
540 return emitOpError(
"par_dims must specify at least one parallel dimension");
548void ReductionCombineOp::getEffects(
564 GPUParallelDimAttr parDim) {
565 for (
auto launchArg : op.getLaunchArgs()) {
566 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
569 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
570 if (launchArgDim == parDim)
576std::optional<Value> ComputeRegionOp::getLaunchArg(GPUParallelDimAttr parDim) {
578 return parWidthOp.getResult();
583ComputeRegionOp::getKnownLaunchArg(GPUParallelDimAttr parDim) {
585 if (parWidthOp.getLaunchArg())
586 return parWidthOp.getLaunchArg();
590std::optional<uint64_t>
591ComputeRegionOp::getKnownConstantLaunchArg(GPUParallelDimAttr parDim) {
592 auto knownParWidth = getKnownLaunchArg(parDim);
593 if (knownParWidth.has_value())
599 getInputArgsMutable().append(value);
600 return getBody()->addArgument(value.
getType(), getLoc());
603std::optional<BlockArgument>
604ComputeRegionOp::wireHoistedValueThroughIns(
Value value) {
605 Region ®ion = getRegion();
607 auto useIsInRegion = [&](
OpOperand &use) ->
bool {
608 return region.
isAncestor(use.getOwner()->getParentRegion());
612 !llvm::any_of(value.
getUses(), useIsInRegion))
620bool ComputeRegionOp::isEffectivelySerial() {
623 if (getLaunchArg(GPUParallelDimAttr::seqDim(ctx)))
626 auto checkDim = [&](GPUParallelDimAttr dim) ->
bool {
627 auto val = getKnownConstantLaunchArg(dim);
628 return val && *val == 1;
631 return checkDim(GPUParallelDimAttr::threadXDim(ctx)) &&
632 checkDim(GPUParallelDimAttr::threadYDim(ctx)) &&
633 checkDim(GPUParallelDimAttr::threadZDim(ctx)) &&
634 checkDim(GPUParallelDimAttr::blockXDim(ctx)) &&
635 checkDim(GPUParallelDimAttr::blockYDim(ctx)) &&
636 checkDim(GPUParallelDimAttr::blockZDim(ctx));
639BlockArgument ComputeRegionOp::parDimToWidth(GPUParallelDimAttr parDim) {
640 for (
auto [pos, launchArg] : llvm::enumerate(getLaunchArgs())) {
641 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
643 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
644 if (launchArgDim == parDim) {
645 assert(pos < getRegion().front().getNumArguments() &&
646 "launch arg position out of range");
647 return getRegion().front().getArgument(pos);
650 llvm_unreachable(
"attempting to get unspecified parDim");
655 for (
auto launchArg : getLaunchArgs()) {
656 auto parOp = launchArg.getDefiningOp<ParWidthOp>();
657 auto launchArgDim = cast<GPUParallelDimAttr>(parOp.getParDim());
658 int64_t dimInt = launchArgDim.getValue().getInt();
659 parDims.push_back(intToParDim(
getContext(), dimInt));
665 Block *body = getBody();
669 unsigned numLaunchArgs = getLaunchArgs().size();
670 unsigned numInputArgs = getInputArgs().size();
671 if (argNumber >= numLaunchArgs + numInputArgs)
673 if (argNumber < numLaunchArgs)
674 return getLaunchArgs()[argNumber];
675 return getInputArgs()[argNumber - numLaunchArgs];
678std::optional<BlockArgument> ComputeRegionOp::getBlockArg(
Value value) {
679 Block *body = getBody();
680 for (
auto [idx, launchVal] : llvm::enumerate(getLaunchArgs())) {
681 if (launchVal == value)
684 unsigned numLaunch = getLaunchArgs().size();
685 for (
auto [idx, inputVal] : llvm::enumerate(getInputArgs())) {
686 if (inputVal == value)
694 results.
add<ComputeRegionRemoveDuplicateArgs, ComputeRegionRemoveUnusedArgs>(
698BlockArgument ComputeRegionOp::gpuParWidth(gpu::Processor processor) {
699 return parDimToWidth(GPUParallelDimAttr::get(
getContext(), processor));
702LogicalResult ComputeRegionOp::verify() {
703 for (
auto op : getLaunchArgs())
704 if (!op.getDefiningOp<acc::ParWidthOp>())
706 "launch arguments must be results of acc.par_width operations");
708 unsigned expectedBlockArgs = getLaunchArgs().size() + getInputArgs().size();
709 unsigned actualBlockArgs = getRegion().front().getNumArguments();
710 if (expectedBlockArgs != actualBlockArgs)
711 return emitOpError(
"expected ")
712 << expectedBlockArgs <<
" block arguments (launch + input), got "
719 ValueRange regionArgs = getBody()->getArguments();
723 assert(regionArgs.size() == (launchArgs.size() + inputArgs.size()) &&
724 "region args mismatch");
727 p <<
" stream(" << getStream() <<
" : " << getStream().getType() <<
")";
730 if (!launchArgs.empty()) {
732 for (
size_t j = 0;
j < launchArgs.size(); ++
j, ++i) {
733 p << regionArgs[i] <<
" = " << launchArgs[
j];
734 if (
j < launchArgs.size() - 1)
739 if (!inputArgs.empty()) {
741 for (
size_t j = 0;
j < inputArgs.size(); ++
j, ++i) {
742 p << regionArgs[i] <<
" = " << inputArgs[
j];
743 if (
j < inputArgs.size() - 1)
747 for (
size_t j = 0;
j < inputArgs.size(); ++
j) {
748 p << inputArgs[
j].getType();
749 if (
j < inputArgs.size() - 1)
757 ComputeRegionOp::printProperties(
getContext(), p, getProperties(),
758 getOperandSegmentSizeAttr());
762ParseResult ComputeRegionOp::parse(
OpAsmParser &parser,
773 bool hasStream =
false;
786 for (
size_t i = 0; i < regionArgs.size(); ++i)
787 types.push_back(indexType);
800 for (
auto [iterArg, type] : llvm::zip_equal(regionArgs, types))
806 ComputeRegionOp::ensureTerminator(*body, parser.
getBuilder(),
809 const size_t numLaunchOperands = launchOperands.size();
810 const size_t numInputOperands = inputOperands.size();
811 assert(numLaunchOperands + numInputOperands == regionArgs.size() &&
812 "compute region args mismatch");
815 {
static_cast<int32_t
>(numLaunchOperands),
816 static_cast<int32_t
>(numInputOperands), hasStream ? 1 : 0});
818 for (
size_t i = 0; i < numLaunchOperands; ++i) {
823 for (
size_t i = numLaunchOperands; i < regionArgs.size(); ++i) {
824 if (parser.
resolveOperand(inputOperands[i - numLaunchOperands], types[i],
835 if (ComputeRegionOp::genericParseProperties(parser, parsedProperties))
837 auto propertyDictionary = dyn_cast_or_null<DictionaryAttr>(parsedProperties);
838 if (parsedProperties && !propertyDictionary)
840 "expected properties dictionary");
842 NamedAttrList properties(propertyDictionary ? propertyDictionary
844 properties.set(ComputeRegionOp::getOperandSegmentSizeAttr(),
845 operandSegmentSizes);
846 propertyDictionary = properties.getDictionary(builder.
getContext());
849 << propertyDictionary <<
" for op " <<
result.name.getStringRef()
852 if (
failed(ComputeRegionOp::setPropertiesFromParsedAttr(
853 result.getOrAddProperties<Properties>(), propertyDictionary,
860 for (StringRef attrName : ComputeRegionOp::getAttributeNames()) {
861 if (
result.attributes.get(attrName))
863 <<
"inherent attribute '" << attrName
864 <<
"' cannot be parsed from attr-dict when strict properties in "
865 "assembly format is enabled";
875LogicalResult GPUSharedMemoryOp::verify() {
876 if (getNumCopies() <= 0)
877 return emitOpError(
"num_copies must be positive");
878 if (getStaticUpperBoundBytes() <= 0)
879 return emitOpError(
"static_upper_bound_bytes must be positive");
881 bool hasScaling =
static_cast<bool>(getDynamicSharedMemoryScalingBytes());
882 bool hasFixed =
static_cast<bool>(getDynamicSharedMemoryFixedBytes());
883 if (hasScaling != hasFixed)
885 "dynamic_shared_memory_scaling_bytes and "
886 "dynamic_shared_memory_fixed_bytes must both be present or both be "
888 if (
auto scalingAttr = getDynamicSharedMemoryScalingBytesAttr())
889 if (scalingAttr.getValue().isNegative())
890 return emitOpError(
"dynamic_shared_memory_scaling_bytes must be "
892 if (
auto fixedAttr = getDynamicSharedMemoryFixedBytesAttr())
893 if (fixedAttr.getValue().isNegative())
894 return emitOpError(
"dynamic_shared_memory_fixed_bytes must be "
897 auto resultTy = cast<MemRefType>(getResult().
getType());
899 dyn_cast_if_present<gpu::AddressSpaceAttr>(resultTy.getMemorySpace());
901 addrSpace.getValue() != gpu::GPUDialect::getWorkgroupAddressSpace())
902 return emitOpError(
"result memref must use #gpu.address_space<workgroup>");
911LogicalResult PredicateRegionOp::verify() {
912 if (getRegion().empty())
913 return emitOpError(
"region needs to have at least one block");
914 if (getRegion().front().getNumArguments() > 0)
915 return emitOpError(
"region cannot have any arguments");
916 if (!getOperation()->getParentOfType<ComputeRegionOp>())
917 return emitOpError(
"must be nested within an acc.compute_region operation");
925LogicalResult MapInfoOp::verify() {
930 return emitOpError(
"varType must capture the element type of var");
934 if (
getDesc() && getDescKind() == DataDescKind::none)
935 return emitOpError(
"desc requires a descKind other than none");
940 !acc::bitEnumContainsAny(getDescKind(), DataDescKind::openacc))
941 return emitOpError(
"bounds require descKind openacc");
947 if (constantSize && *constantSize < -1)
948 return emitOpError(
"size must be -1, 0, or a positive byte count");
958GPUParallelDimAttr GPUParallelDimAttr::get(
MLIRContext *context,
959 gpu::Processor proc) {
960 return processorParDim(context, proc);
963GPUParallelDimAttr GPUParallelDimAttr::seqDim(
MLIRContext *context) {
964 return processorParDim(context, gpu::Processor::Sequential);
967GPUParallelDimAttr GPUParallelDimAttr::threadXDim(
MLIRContext *context) {
968 return processorParDim(context, gpu::Processor::ThreadX);
971GPUParallelDimAttr GPUParallelDimAttr::threadYDim(
MLIRContext *context) {
972 return processorParDim(context, gpu::Processor::ThreadY);
975GPUParallelDimAttr GPUParallelDimAttr::threadZDim(
MLIRContext *context) {
976 return processorParDim(context, gpu::Processor::ThreadZ);
979GPUParallelDimAttr GPUParallelDimAttr::blockXDim(
MLIRContext *context) {
980 return processorParDim(context, gpu::Processor::BlockX);
983GPUParallelDimAttr GPUParallelDimAttr::blockYDim(
MLIRContext *context) {
984 return processorParDim(context, gpu::Processor::BlockY);
987GPUParallelDimAttr GPUParallelDimAttr::blockZDim(
MLIRContext *context) {
988 return processorParDim(context, gpu::Processor::BlockZ);
992 GPUParallelDimAttr dim;
993 if (parser.
parseLess() || parseProcessorValue(parser, dim) ||
996 "expected format `<` processor_name `>`");
1002void GPUParallelDimAttr::print(
AsmPrinter &printer)
const {
1004 printProcessorValue(printer, *
this);
1008GPUParallelDimAttr GPUParallelDimAttr::threadDim(
MLIRContext *context,
1010 assert(
index <= 2 &&
"thread dimension index must be 0, 1, or 2");
1013 return threadXDim(context);
1015 return threadYDim(context);
1017 return threadZDim(context);
1019 llvm_unreachable(
"validated thread dimension index");
1022GPUParallelDimAttr GPUParallelDimAttr::blockDim(
MLIRContext *context,
1024 assert(
index <= 2 &&
"block dimension index must be 0, 1, or 2");
1027 return blockXDim(context);
1029 return blockYDim(context);
1031 return blockZDim(context);
1033 llvm_unreachable(
"validated block dimension index");
1036gpu::Processor GPUParallelDimAttr::getProcessor()
const {
1037 return indexToGpuProcessor(getValue().getInt());
1040int GPUParallelDimAttr::getOrder()
const {
1041 return gpuProcessorIndex(getProcessor());
1044GPUParallelDimAttr GPUParallelDimAttr::getOneHigher()
const {
1045 int order = getOrder();
1051GPUParallelDimAttr GPUParallelDimAttr::getOneLower()
const {
1052 int order = getOrder();
1058bool GPUParallelDimAttr::isSeq()
const {
1059 return getProcessor() == gpu::Processor::Sequential;
1061bool GPUParallelDimAttr::isThreadX()
const {
1062 return getProcessor() == gpu::Processor::ThreadX;
1064bool GPUParallelDimAttr::isThreadY()
const {
1065 return getProcessor() == gpu::Processor::ThreadY;
1067bool GPUParallelDimAttr::isThreadZ()
const {
1068 return getProcessor() == gpu::Processor::ThreadZ;
1070bool GPUParallelDimAttr::isBlockX()
const {
1071 return getProcessor() == gpu::Processor::BlockX;
1073bool GPUParallelDimAttr::isBlockY()
const {
1074 return getProcessor() == gpu::Processor::BlockY;
1076bool GPUParallelDimAttr::isBlockZ()
const {
1077 return getProcessor() == gpu::Processor::BlockZ;
1079bool GPUParallelDimAttr::isAnyThread()
const {
1080 return isThreadX() || isThreadY() || isThreadZ();
1082bool GPUParallelDimAttr::isAnyBlock()
const {
1083 return isBlockX() || isBlockY() || isBlockZ();
1090GPUParallelDimsAttr GPUParallelDimsAttr::seq(
MLIRContext *ctx) {
1091 return GPUParallelDimsAttr::get(ctx, {GPUParallelDimAttr::seqDim(ctx)});
1094bool GPUParallelDimsAttr::isSeq()
const {
1095 assert(!getArray().empty() &&
"no par_dims found");
1096 if (getArray().size() == 1) {
1097 auto parDim = dyn_cast<GPUParallelDimAttr>(getArray()[0]);
1098 assert(parDim &&
"expected GPUParallelDimAttr");
1099 return parDim.isSeq();
1104bool GPUParallelDimsAttr::isParallel()
const {
return !isSeq(); }
1106bool GPUParallelDimsAttr::isMultiDim()
const {
return getArray().size() > 1; }
1108bool GPUParallelDimsAttr::hasAnyBlockLevel()
const {
1109 return llvm::any_of(
1110 getArray(), [](
const GPUParallelDimAttr &p) {
return p.isAnyBlock(); });
1113bool GPUParallelDimsAttr::hasOnlyBlockLevel()
const {
1114 return !getArray().empty() &&
1115 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1116 return p.isAnyBlock();
1120bool GPUParallelDimsAttr::hasOnlyThreadYLevel()
const {
1121 return !getArray().empty() &&
1122 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1123 return p.isThreadY();
1127bool GPUParallelDimsAttr::hasOnlyThreadXLevel()
const {
1128 return !getArray().empty() &&
1129 llvm::all_of(getArray(), [](
const GPUParallelDimAttr &p) {
1130 return p.isThreadX();
1135 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1136 parseGPUParallelDimList(parser);
1139 return GPUParallelDimsAttr::get(parser.
getContext(), *parDims);
1142void GPUParallelDimsAttr::print(
AsmPrinter &printer)
const {
1143 printGPUParallelDimList(printer, getArray());
1151 FailureOr<SmallVector<GPUParallelDimAttr>> parDims =
1152 parseGPUParallelDimList(parser);
1155 return ActiveParDimsAttr::get(parser.
getContext(), *parDims);
1158void ActiveParDimsAttr::print(
AsmPrinter &printer)
const {
1159 printGPUParallelDimList(printer, getArray());
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 SMLoc getNameLoc() const =0
Return the location of the original name 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)
StringAttr getStringAttr(const Twine &bytes)
MLIRContext * getContext() const
DictionaryAttr getDictionaryAttr(ArrayRef< NamedAttribute > value)
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.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
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.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
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::SmallVector< mlir::Value > getBounds(mlir::Operation *accDataClauseOp)
Used to obtain bounds from an acc data clause operation.
Value getDesc(Operation *mapEntryOp)
Returns descriptor value from acc.map_info.
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.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
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.