20 #include "llvm/ADT/SmallSet.h"
21 #include "llvm/ADT/TypeSwitch.h"
22 #include "llvm/Support/LogicalResult.h"
27 #include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
28 #include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
29 #include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
30 #include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
31 #include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
34 struct MemRefPointerLikeModel
35 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
38 return llvm::cast<MemRefType>(pointer).getElementType();
42 struct LLVMPointerPointerLikeModel
43 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
44 LLVM::LLVMPointerType> {
53 void OpenACCDialect::initialize() {
56 #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
59 #define GET_ATTRDEF_LIST
60 #include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
63 #define GET_TYPEDEF_LIST
64 #include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
70 MemRefType::attachInterface<MemRefPointerLikeModel>(*
getContext());
71 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
80 if (arrayAttr && *arrayAttr && arrayAttr->size() > 0)
86 mlir::acc::DeviceType deviceType) {
90 for (
auto attr : *arrayAttr) {
91 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
92 if (deviceTypeAttr.getValue() == deviceType)
100 std::optional<mlir::ArrayAttr> deviceTypes) {
105 llvm::interleaveComma(*deviceTypes, p,
111 mlir::acc::DeviceType deviceType) {
112 unsigned segmentIdx = 0;
113 for (
auto attr : segments) {
114 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
115 if (deviceTypeAttr.getValue() == deviceType)
116 return std::make_optional(segmentIdx);
126 mlir::acc::DeviceType deviceType) {
128 return range.take_front(0);
129 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
130 int32_t nbOperandsBefore = 0;
131 for (
unsigned i = 0; i < *pos; ++i)
132 nbOperandsBefore += (*segments)[i];
133 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
135 return range.take_front(0);
142 std::optional<mlir::ArrayAttr> hasWaitDevnum,
143 mlir::acc::DeviceType deviceType) {
146 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType))
147 if (hasWaitDevnum->getValue()[*pos])
158 std::optional<mlir::ArrayAttr> hasWaitDevnum,
159 mlir::acc::DeviceType deviceType) {
164 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
165 if (hasWaitDevnum && *hasWaitDevnum) {
166 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
167 if (boolAttr.getValue())
168 return range.drop_front(1);
174 template <
typename Op>
176 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
178 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
183 op.hasAsyncOnly(dtype))
184 return op.
emitError(
"async attribute cannot appear with asyncOperand");
189 op.hasWaitOnly(dtype))
190 return op.
emitError(
"wait attribute cannot appear with waitOperands");
197 mlir::TypeAttr &varTypeAttr) {
198 if (failed(parser.
parseType(varPtrType)))
215 mlir::cast<mlir::acc::PointerLikeType>(varPtrType).
getElementType());
222 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
229 if (mlir::cast<mlir::acc::PointerLikeType>(varPtrType).
getElementType() !=
241 auto extent = getExtent();
242 auto upperbound = getUpperbound();
243 if (!extent && !upperbound)
244 return emitError(
"expected extent or upperbound.");
254 "data clause associated with private operation must match its intent");
263 return emitError(
"data clause associated with firstprivate operation must "
273 return emitError(
"data clause associated with reduction operation must "
283 return emitError(
"data clause associated with deviceptr operation must "
294 "data clause associated with present operation must match its intent");
303 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
308 "data clause associated with copyin operation must match its intent"
309 " or specify original clause this operation was decomposed from");
313 bool acc::CopyinOp::isCopyinReadonly() {
314 return getDataClause() == acc::DataClause::acc_copyin_readonly;
327 "data clause associated with create operation must match its intent"
328 " or specify original clause this operation was decomposed from");
332 bool acc::CreateOp::isCreateZero() {
334 return getDataClause() == acc::DataClause::acc_create_zero ||
343 return emitError(
"data clause associated with no_create operation must "
354 "data clause associated with attach operation must match its intent");
363 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
364 return emitError(
"data clause associated with device_resident operation "
365 "must match its intent");
376 "data clause associated with link operation must match its intent");
390 "data clause associated with copyout operation must match its intent"
391 " or specify original clause this operation was decomposed from");
393 return emitError(
"must have both host and device pointers");
397 bool acc::CopyoutOp::isCopyoutZero() {
412 getDataClause() != acc::DataClause::acc_declare_device_resident &&
415 "data clause associated with delete operation must match its intent"
416 " or specify original clause this operation was decomposed from");
418 return emitError(
"must have device pointer");
430 "data clause associated with detach operation must match its intent"
431 " or specify original clause this operation was decomposed from");
433 return emitError(
"must have device pointer");
445 "data clause associated with host operation must match its intent"
446 " or specify original clause this operation was decomposed from");
448 return emitError(
"must have both host and device pointers");
459 "data clause associated with device operation must match its intent"
460 " or specify original clause this operation was decomposed from");
471 "data clause associated with use_device operation must match its intent"
472 " or specify original clause this operation was decomposed from");
484 "data clause associated with cache operation must match its intent"
485 " or specify original clause this operation was decomposed from");
489 template <
typename StructureOp>
491 unsigned nRegions = 1) {
494 for (
unsigned i = 0; i < nRegions; ++i)
495 regions.push_back(state.addRegion());
497 for (
Region *region : regions)
505 return isa<acc::ParallelOp, acc::LoopOp>(op);
512 template <
typename OpTy>
516 LogicalResult matchAndRewrite(OpTy op,
519 Value ifCond = op.getIfCond();
523 IntegerAttr constAttr;
526 if (constAttr.getInt())
527 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
539 assert(llvm::hasSingleElement(region) &&
"expected single-region block");
551 template <
typename OpTy>
552 struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
555 LogicalResult matchAndRewrite(OpTy op,
558 Value ifCond = op.getIfCond();
562 IntegerAttr constAttr;
565 if (constAttr.getInt())
566 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
581 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
583 if (optional && region.
empty())
587 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
591 return op->
emitOpError() <<
"expects " << regionName
594 << regionType <<
" type";
597 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
598 if (yieldOp.getOperands().size() != 1 ||
599 yieldOp.getOperands().getTypes()[0] != type)
600 return op->
emitOpError() <<
"expects " << regionName
602 "yield a value of the "
603 << regionType <<
" type";
609 LogicalResult acc::PrivateRecipeOp::verifyRegions() {
611 "privatization",
"init",
getType(),
615 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
625 LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
627 "privatization",
"init",
getType(),
631 if (getCopyRegion().empty())
632 return emitOpError() <<
"expects non-empty copy region";
637 return emitOpError() <<
"expects copy region with two arguments of the "
638 "privatization type";
640 if (getDestroyRegion().empty())
644 "privatization",
"destroy",
655 LogicalResult acc::ReductionRecipeOp::verifyRegions() {
661 if (getCombinerRegion().empty())
662 return emitOpError() <<
"expects non-empty combiner region";
664 Block &reductionBlock = getCombinerRegion().
front();
668 return emitOpError() <<
"expects combiner region with the first two "
669 <<
"arguments of the reduction type";
671 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
672 if (yieldOp.getOperands().size() != 1 ||
673 yieldOp.getOperands().getTypes()[0] !=
getType())
674 return emitOpError() <<
"expects combiner region to yield a value "
675 "of the reduction type";
691 if (parser.parseAttribute(attributes.emplace_back()) ||
692 parser.parseArrow() ||
693 parser.parseOperand(operands.emplace_back()) ||
694 parser.parseColonType(types.emplace_back()))
708 std::optional<mlir::ArrayAttr> attributes) {
709 llvm::interleaveComma(llvm::zip(*attributes, operands), p, [&](
auto it) {
710 p << std::get<0>(it) <<
" -> " << std::get<1>(it) <<
" : "
711 << std::get<1>(it).getType();
720 template <
typename Op>
724 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
725 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
726 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
727 operand.getDefiningOp()))
729 "expect data entry/exit operation or acc.getdeviceptr "
734 template <
typename Op>
738 llvm::StringRef symbolName,
bool checkOperandType =
true) {
739 if (!operands.empty()) {
740 if (!attributes || attributes->size() != operands.size())
742 <<
"expected as many " << symbolName <<
" symbol reference as "
743 << operandName <<
" operands";
747 <<
"unexpected " << symbolName <<
" symbol reference";
752 for (
auto args : llvm::zip(operands, *attributes)) {
755 if (!set.insert(operand).second)
757 << operandName <<
" operand appears more than once";
760 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
761 auto decl = SymbolTable::lookupNearestSymbolFrom<Op>(op, symbolRef);
764 <<
"expected symbol reference " << symbolRef <<
" to point to a "
765 << operandName <<
" declaration";
767 if (checkOperandType && decl.getType() && decl.getType() != varType)
768 return op->
emitOpError() <<
"expected " << operandName <<
" (" << varType
769 <<
") to be the same type as " << operandName
770 <<
" declaration (" << decl.getType() <<
")";
776 unsigned ParallelOp::getNumDataOperands() {
777 return getReductionOperands().size() + getPrivateOperands().size() +
778 getFirstprivateOperands().size() + getDataClauseOperands().size();
781 Value ParallelOp::getDataOperand(
unsigned i) {
783 numOptional += getNumGangs().size();
784 numOptional += getNumWorkers().size();
785 numOptional += getVectorLength().size();
786 numOptional += getIfCond() ? 1 : 0;
787 numOptional += getSelfCond() ? 1 : 0;
788 return getOperand(getWaitOperands().size() + numOptional + i);
791 template <
typename Op>
793 ArrayAttr deviceTypes,
794 llvm::StringRef keyword) {
795 if (!operands.empty() && deviceTypes.getValue().size() != operands.size())
796 return op.
emitOpError() << keyword <<
" operands count must match "
797 << keyword <<
" device_type count";
801 template <
typename Op>
804 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
805 std::size_t numOperandsInSegments = 0;
806 std::size_t nbOfSegments = 0;
810 if (maxInSegment != 0 && segCount > maxInSegment)
811 return op.
emitOpError() << keyword <<
" expects a maximum of "
812 << maxInSegment <<
" values per segment";
813 numOperandsInSegments += segCount;
818 if ((numOperandsInSegments != operands.size()) ||
819 (!deviceTypes && !operands.empty()))
821 << keyword <<
" operand count does not match count in segments";
822 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
824 << keyword <<
" segment count does not match device_type count";
829 if (failed(checkSymOperandList<mlir::acc::PrivateRecipeOp>(
830 *
this, getPrivatizations(), getPrivateOperands(),
"private",
831 "privatizations",
false)))
833 if (failed(checkSymOperandList<mlir::acc::FirstprivateRecipeOp>(
834 *
this, getFirstprivatizations(), getFirstprivateOperands(),
835 "firstprivate",
"firstprivatizations",
false)))
837 if (failed(checkSymOperandList<mlir::acc::ReductionRecipeOp>(
838 *
this, getReductionRecipes(), getReductionOperands(),
"reduction",
839 "reductions",
false)))
843 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
844 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
848 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
849 getWaitOperandsDeviceTypeAttr(),
"wait")))
853 getNumWorkersDeviceTypeAttr(),
858 getVectorLengthDeviceTypeAttr(),
863 getAsyncOperandsDeviceTypeAttr(),
867 if (failed(checkWaitAndAsyncConflict<acc::ParallelOp>(*
this)))
870 return checkDataOperands<acc::ParallelOp>(*
this, getDataClauseOperands());
876 mlir::acc::DeviceType deviceType) {
879 if (
auto pos =
findSegment(*arrayAttr, deviceType))
884 bool acc::ParallelOp::hasAsyncOnly() {
888 bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
896 mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
901 mlir::Value acc::ParallelOp::getNumWorkersValue() {
906 acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
911 mlir::Value acc::ParallelOp::getVectorLengthValue() {
916 acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
918 getVectorLength(), deviceType);
926 ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
928 getNumGangsSegments(), deviceType);
931 bool acc::ParallelOp::hasWaitOnly() {
935 bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
944 ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
946 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
947 getHasWaitDevnum(), deviceType);
954 mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
956 getWaitOperandsSegments(), getHasWaitDevnum(),
972 odsBuilder, odsState, asyncOperands,
nullptr,
973 nullptr, waitOperands,
nullptr,
975 nullptr, numGangs,
nullptr,
977 nullptr, vectorLength,
978 nullptr, ifCond, selfCond,
979 nullptr, reductionOperands,
nullptr,
980 gangPrivateOperands,
nullptr, gangFirstPrivateOperands,
981 nullptr, dataClauseOperands,
997 int32_t crtOperandsSize = operands.size();
1000 if (parser.parseOperand(operands.emplace_back()) ||
1001 parser.parseColonType(types.emplace_back()))
1006 seg.push_back(operands.size() - crtOperandsSize);
1030 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
1032 p <<
" [" << attr <<
"]";
1037 std::optional<mlir::ArrayAttr> deviceTypes,
1038 std::optional<mlir::DenseI32ArrayAttr> segments) {
1040 llvm::interleaveComma(
llvm::enumerate(*deviceTypes), p, [&](
auto it) {
1042 llvm::interleaveComma(
1043 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
1044 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
1064 int32_t crtOperandsSize = operands.size();
1068 if (parser.parseOperand(operands.emplace_back()) ||
1069 parser.parseColonType(types.emplace_back()))
1075 seg.push_back(operands.size() - crtOperandsSize);
1101 std::optional<mlir::DenseI32ArrayAttr> segments) {
1103 llvm::interleaveComma(
llvm::enumerate(*deviceTypes), p, [&](
auto it) {
1105 llvm::interleaveComma(
1106 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
1107 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
1120 mlir::ArrayAttr &keywordOnly) {
1124 bool needCommaBeforeOperands =
false;
1137 if (parser.parseAttribute(keywordAttrs.emplace_back()))
1144 needCommaBeforeOperands =
true;
1147 if (needCommaBeforeOperands && failed(parser.
parseComma()))
1154 int32_t crtOperandsSize = operands.size();
1166 if (parser.parseOperand(operands.emplace_back()) ||
1167 parser.parseColonType(types.emplace_back()))
1173 seg.push_back(operands.size() - crtOperandsSize);
1202 if (attrs->size() != 1)
1204 if (
auto deviceTypeAttr =
1205 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
1212 std::optional<mlir::ArrayAttr> deviceTypes,
1213 std::optional<mlir::DenseI32ArrayAttr> segments,
1214 std::optional<mlir::ArrayAttr> hasDevNum,
1215 std::optional<mlir::ArrayAttr> keywordOnly) {
1227 llvm::interleaveComma(
llvm::enumerate(*deviceTypes), p, [&](
auto it) {
1229 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
1230 if (boolAttr && boolAttr.getValue())
1232 llvm::interleaveComma(
1233 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
1234 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
1250 if (parser.parseOperand(operands.emplace_back()) ||
1251 parser.parseColonType(types.emplace_back()))
1253 if (succeeded(parser.parseOptionalLSquare())) {
1254 if (parser.parseAttribute(attributes.emplace_back()) ||
1255 parser.parseRSquare())
1258 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
1259 parser.getContext(), mlir::acc::DeviceType::None));
1273 std::optional<mlir::ArrayAttr> deviceTypes) {
1276 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
1277 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
1286 mlir::ArrayAttr &keywordOnlyDeviceType) {
1289 bool needCommaBeforeOperands =
false;
1295 keywordOnlyDeviceType =
1304 if (parser.parseAttribute(
1305 keywordOnlyDeviceTypeAttributes.emplace_back()))
1312 needCommaBeforeOperands =
true;
1315 if (needCommaBeforeOperands && failed(parser.
parseComma()))
1320 if (parser.parseOperand(operands.emplace_back()) ||
1321 parser.parseColonType(types.emplace_back()))
1323 if (succeeded(parser.parseOptionalLSquare())) {
1324 if (parser.parseAttribute(attributes.emplace_back()) ||
1325 parser.parseRSquare())
1328 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
1329 parser.getContext(), mlir::acc::DeviceType::None));
1335 if (failed(parser.parseRParen()))
1347 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
1349 if (operands.begin() == operands.end() &&
1365 mlir::acc::CombinedConstructsTypeAttr &attr) {
1371 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
1374 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
1377 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
1380 "expected compute construct name");
1391 mlir::acc::CombinedConstructsTypeAttr attr) {
1393 switch (attr.getValue()) {
1394 case mlir::acc::CombinedConstructsType::KernelsLoop:
1395 p <<
"combined(kernels)";
1397 case mlir::acc::CombinedConstructsType::ParallelLoop:
1398 p <<
"combined(parallel)";
1400 case mlir::acc::CombinedConstructsType::SerialLoop:
1401 p <<
"combined(serial)";
1411 unsigned SerialOp::getNumDataOperands() {
1412 return getReductionOperands().size() + getPrivateOperands().size() +
1413 getFirstprivateOperands().size() + getDataClauseOperands().size();
1416 Value SerialOp::getDataOperand(
unsigned i) {
1418 numOptional += getIfCond() ? 1 : 0;
1419 numOptional += getSelfCond() ? 1 : 0;
1420 return getOperand(getWaitOperands().size() + numOptional + i);
1423 bool acc::SerialOp::hasAsyncOnly() {
1427 bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
1435 mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
1440 bool acc::SerialOp::hasWaitOnly() {
1444 bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
1453 SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
1455 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
1456 getHasWaitDevnum(), deviceType);
1463 mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
1465 getWaitOperandsSegments(), getHasWaitDevnum(),
1470 if (failed(checkSymOperandList<mlir::acc::PrivateRecipeOp>(
1471 *
this, getPrivatizations(), getPrivateOperands(),
"private",
1472 "privatizations",
false)))
1474 if (failed(checkSymOperandList<mlir::acc::FirstprivateRecipeOp>(
1475 *
this, getFirstprivatizations(), getFirstprivateOperands(),
1476 "firstprivate",
"firstprivatizations",
false)))
1478 if (failed(checkSymOperandList<mlir::acc::ReductionRecipeOp>(
1479 *
this, getReductionRecipes(), getReductionOperands(),
"reduction",
1480 "reductions",
false)))
1484 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
1485 getWaitOperandsDeviceTypeAttr(),
"wait")))
1489 getAsyncOperandsDeviceTypeAttr(),
1493 if (failed(checkWaitAndAsyncConflict<acc::SerialOp>(*
this)))
1496 return checkDataOperands<acc::SerialOp>(*
this, getDataClauseOperands());
1503 unsigned KernelsOp::getNumDataOperands() {
1504 return getDataClauseOperands().size();
1507 Value KernelsOp::getDataOperand(
unsigned i) {
1509 numOptional += getWaitOperands().size();
1510 numOptional += getNumGangs().size();
1511 numOptional += getNumWorkers().size();
1512 numOptional += getVectorLength().size();
1513 numOptional += getIfCond() ? 1 : 0;
1514 numOptional += getSelfCond() ? 1 : 0;
1515 return getOperand(numOptional + i);
1518 bool acc::KernelsOp::hasAsyncOnly() {
1522 bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
1530 mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
1535 mlir::Value acc::KernelsOp::getNumWorkersValue() {
1540 acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
1545 mlir::Value acc::KernelsOp::getVectorLengthValue() {
1550 acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
1552 getVectorLength(), deviceType);
1560 KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
1562 getNumGangsSegments(), deviceType);
1565 bool acc::KernelsOp::hasWaitOnly() {
1569 bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
1578 KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
1580 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
1581 getHasWaitDevnum(), deviceType);
1588 mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
1590 getWaitOperandsSegments(), getHasWaitDevnum(),
1596 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
1597 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
1601 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
1602 getWaitOperandsDeviceTypeAttr(),
"wait")))
1606 getNumWorkersDeviceTypeAttr(),
1611 getVectorLengthDeviceTypeAttr(),
1616 getAsyncOperandsDeviceTypeAttr(),
1620 if (failed(checkWaitAndAsyncConflict<acc::KernelsOp>(*
this)))
1623 return checkDataOperands<acc::KernelsOp>(*
this, getDataClauseOperands());
1631 if (getDataClauseOperands().empty())
1632 return emitError(
"at least one operand must appear on the host_data "
1635 for (
mlir::Value operand : getDataClauseOperands())
1636 if (!mlir::isa<acc::UseDeviceOp>(operand.getDefiningOp()))
1637 return emitError(
"expect data entry operation as defining op");
1643 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
1655 bool &needCommaBetweenValues,
bool &newValue) {
1662 attributes.push_back(gangArgType);
1663 needCommaBetweenValues =
true;
1674 mlir::ArrayAttr &gangOnlyDeviceType) {
1679 bool needCommaBetweenValues =
false;
1680 bool needCommaBeforeOperands =
false;
1686 gangOnlyDeviceType =
1695 if (parser.parseAttribute(
1696 gangOnlyDeviceTypeAttributes.emplace_back()))
1703 needCommaBeforeOperands =
true;
1707 mlir::acc::GangArgType::Num);
1709 mlir::acc::GangArgType::Dim);
1711 parser.
getContext(), mlir::acc::GangArgType::Static);
1714 if (needCommaBeforeOperands) {
1715 needCommaBeforeOperands =
false;
1722 int32_t crtOperandsSize = gangOperands.size();
1724 bool newValue =
false;
1725 bool needValue =
false;
1726 if (needCommaBetweenValues) {
1734 gangOperands, gangOperandsType,
1735 gangArgTypeAttributes, argNum,
1736 needCommaBetweenValues, newValue)))
1739 gangOperands, gangOperandsType,
1740 gangArgTypeAttributes, argDim,
1741 needCommaBetweenValues, newValue)))
1743 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
1744 gangOperands, gangOperandsType,
1745 gangArgTypeAttributes, argStatic,
1746 needCommaBetweenValues, newValue)))
1749 if (!newValue && needValue) {
1751 "new value expected after comma");
1759 if (gangOperands.empty())
1762 "expect at least one of num, dim or static values");
1768 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
1776 seg.push_back(gangOperands.size() - crtOperandsSize);
1784 gangArgTypeAttributes.end());
1789 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
1798 std::optional<mlir::ArrayAttr> gangArgTypes,
1799 std::optional<mlir::ArrayAttr> deviceTypes,
1800 std::optional<mlir::DenseI32ArrayAttr> segments,
1801 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
1803 if (operands.begin() == operands.end() &&
1818 llvm::interleaveComma(
llvm::enumerate(*deviceTypes), p, [&](
auto it) {
1820 llvm::interleaveComma(
1821 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
1822 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
1823 (*gangArgTypes)[opIdx]);
1824 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
1825 p << LoopOp::getGangNumKeyword();
1826 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
1827 p << LoopOp::getGangDimKeyword();
1828 else if (gangArgTypeAttr.getValue() ==
1829 mlir::acc::GangArgType::Static)
1830 p << LoopOp::getGangStaticKeyword();
1831 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
1842 std::optional<mlir::ArrayAttr> segments,
1843 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
1846 for (
auto attr : *segments) {
1847 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
1848 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
1856 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
1859 for (
auto attr : deviceTypes) {
1860 auto deviceTypeAttr =
1861 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
1862 if (!deviceTypeAttr)
1864 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
1871 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
1872 (getUpperbound().size() != getInclusiveUpperbound()->size()))
1873 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
1874 <<
" as upperbound size";
1877 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
1878 return emitOpError() <<
"collapse device_type attr must be define when"
1879 <<
" collapse attr is present";
1881 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
1882 getCollapseAttr().getValue().size() !=
1883 getCollapseDeviceTypeAttr().getValue().size())
1884 return emitOpError() <<
"collapse attribute count must match collapse"
1885 <<
" device_type count";
1887 return emitOpError()
1888 <<
"duplicate device_type found in collapseDeviceType attribute";
1891 if (!getGangOperands().empty()) {
1892 if (!getGangOperandsArgType())
1893 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
1894 <<
" when gang operands are present";
1896 if (getGangOperands().size() !=
1897 getGangOperandsArgTypeAttr().getValue().size())
1898 return emitOpError() <<
"gangOperandsArgType attribute count must match"
1899 <<
" gangOperands count";
1902 return emitOpError() <<
"duplicate device_type found in gang attribute";
1905 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
1906 getGangOperandsDeviceTypeAttr(),
"gang")))
1911 return emitOpError() <<
"duplicate device_type found in worker attribute";
1913 return emitOpError() <<
"duplicate device_type found in "
1914 "workerNumOperandsDeviceType attribute";
1916 getWorkerNumOperandsDeviceTypeAttr(),
1922 return emitOpError() <<
"duplicate device_type found in vector attribute";
1924 return emitOpError() <<
"duplicate device_type found in "
1925 "vectorOperandsDeviceType attribute";
1927 getVectorOperandsDeviceTypeAttr(),
1932 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
1933 getTileOperandsDeviceTypeAttr(),
"tile")))
1937 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
1941 return emitError() <<
"only one of \"" << acc::LoopOp::getAutoAttrStrName()
1942 <<
"\", " << getIndependentAttrName() <<
", "
1944 <<
" can be present at the same time";
1949 for (
auto attr : getSeqAttr()) {
1950 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
1951 if (hasVector(deviceTypeAttr.getValue()) ||
1952 getVectorValue(deviceTypeAttr.getValue()) ||
1953 hasWorker(deviceTypeAttr.getValue()) ||
1954 getWorkerValue(deviceTypeAttr.getValue()) ||
1955 hasGang(deviceTypeAttr.getValue()) ||
1956 getGangValue(mlir::acc::GangArgType::Num,
1957 deviceTypeAttr.getValue()) ||
1958 getGangValue(mlir::acc::GangArgType::Dim,
1959 deviceTypeAttr.getValue()) ||
1960 getGangValue(mlir::acc::GangArgType::Static,
1961 deviceTypeAttr.getValue()))
1963 <<
"gang, worker or vector cannot appear with the seq attr";
1967 if (failed(checkSymOperandList<mlir::acc::PrivateRecipeOp>(
1968 *
this, getPrivatizations(), getPrivateOperands(),
"private",
1969 "privatizations",
false)))
1972 if (failed(checkSymOperandList<mlir::acc::ReductionRecipeOp>(
1973 *
this, getReductionRecipes(), getReductionOperands(),
"reduction",
1974 "reductions",
false)))
1977 if (getCombined().has_value() &&
1978 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
1979 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
1980 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
1981 return emitError(
"unexpected combined constructs attribute");
1985 if (getRegion().empty())
1986 return emitError(
"expected non-empty body.");
1991 unsigned LoopOp::getNumDataOperands() {
1992 return getReductionOperands().size() + getPrivateOperands().size();
1995 Value LoopOp::getDataOperand(
unsigned i) {
1996 unsigned numOptional =
1997 getLowerbound().size() + getUpperbound().size() + getStep().size();
1998 numOptional += getGangOperands().size();
1999 numOptional += getVectorOperands().size();
2000 numOptional += getWorkerNumOperands().size();
2001 numOptional += getTileOperands().size();
2002 numOptional += getCacheOperands().size();
2003 return getOperand(numOptional + i);
2008 bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
2012 bool LoopOp::hasIndependent() {
2016 bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
2022 bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
2030 mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
2032 getVectorOperands(), deviceType);
2037 bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
2045 mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
2047 getWorkerNumOperands(), deviceType);
2052 bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
2061 LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
2063 getTileOperandsSegments(), deviceType);
2066 std::optional<int64_t> LoopOp::getCollapseValue() {
2070 std::optional<int64_t>
2071 LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
2072 if (!getCollapseAttr())
2073 return std::nullopt;
2074 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
2076 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
2077 return intAttr.getValue().getZExtValue();
2079 return std::nullopt;
2082 mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
2086 mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
2087 mlir::acc::DeviceType deviceType) {
2088 if (getGangOperands().empty())
2090 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
2091 int32_t nbOperandsBefore = 0;
2092 for (
unsigned i = 0; i < *pos; ++i)
2093 nbOperandsBefore += (*getGangOperandsSegments())[i];
2096 .drop_front(nbOperandsBefore)
2097 .take_front((*getGangOperandsSegments())[*pos]);
2099 int32_t argTypeIdx = nbOperandsBefore;
2100 for (
auto value : values) {
2101 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
2102 (*getGangOperandsArgType())[argTypeIdx]);
2103 if (gangArgTypeAttr.getValue() == gangArgType)
2113 bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
2118 return {&getRegion()};
2162 if (!regionArgs.empty()) {
2163 p << acc::LoopOp::getControlKeyword() <<
"(";
2164 llvm::interleaveComma(regionArgs, p,
2166 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
2167 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
2168 <<
" : " << stepType <<
") ";
2181 if (getOperands().empty() && !getDefaultAttr())
2182 return emitError(
"at least one operand or the default attribute "
2183 "must appear on the data operation");
2185 for (
mlir::Value operand : getDataClauseOperands())
2186 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2187 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2188 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
2189 operand.getDefiningOp()))
2190 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
2193 if (failed(checkWaitAndAsyncConflict<acc::DataOp>(*
this)))
2199 unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
2201 Value DataOp::getDataOperand(
unsigned i) {
2202 unsigned numOptional = getIfCond() ? 1 : 0;
2204 numOptional += getWaitOperands().size();
2205 return getOperand(numOptional + i);
2208 bool acc::DataOp::hasAsyncOnly() {
2212 bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2220 mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2227 bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2236 DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2238 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2239 getHasWaitDevnum(), deviceType);
2246 mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2248 getWaitOperandsSegments(), getHasWaitDevnum(),
2260 if (getDataClauseOperands().empty())
2261 return emitError(
"at least one operand must be present in dataOperands on "
2262 "the exit data operation");
2266 if (getAsyncOperand() && getAsync())
2267 return emitError(
"async attribute cannot appear with asyncOperand");
2271 if (!getWaitOperands().empty() && getWait())
2272 return emitError(
"wait attribute cannot appear with waitOperands");
2274 if (getWaitDevnum() && getWaitOperands().empty())
2275 return emitError(
"wait_devnum cannot appear without waitOperands");
2280 unsigned ExitDataOp::getNumDataOperands() {
2281 return getDataClauseOperands().size();
2284 Value ExitDataOp::getDataOperand(
unsigned i) {
2285 unsigned numOptional = getIfCond() ? 1 : 0;
2286 numOptional += getAsyncOperand() ? 1 : 0;
2287 numOptional += getWaitDevnum() ? 1 : 0;
2288 return getOperand(getWaitOperands().size() + numOptional + i);
2293 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
2304 if (getDataClauseOperands().empty())
2305 return emitError(
"at least one operand must be present in dataOperands on "
2306 "the enter data operation");
2310 if (getAsyncOperand() && getAsync())
2311 return emitError(
"async attribute cannot appear with asyncOperand");
2315 if (!getWaitOperands().empty() && getWait())
2316 return emitError(
"wait attribute cannot appear with waitOperands");
2318 if (getWaitDevnum() && getWaitOperands().empty())
2319 return emitError(
"wait_devnum cannot appear without waitOperands");
2321 for (
mlir::Value operand : getDataClauseOperands())
2322 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp>(
2323 operand.getDefiningOp()))
2324 return emitError(
"expect data entry operation as defining op");
2329 unsigned EnterDataOp::getNumDataOperands() {
2330 return getDataClauseOperands().size();
2333 Value EnterDataOp::getDataOperand(
unsigned i) {
2334 unsigned numOptional = getIfCond() ? 1 : 0;
2335 numOptional += getAsyncOperand() ? 1 : 0;
2336 numOptional += getWaitDevnum() ? 1 : 0;
2337 return getOperand(getWaitOperands().size() + numOptional + i);
2342 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
2361 LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
2368 if (
Value writeVal = op.getWriteOpVal()) {
2378 LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
2384 AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
2385 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
2387 return dyn_cast<AtomicReadOp>(getSecondOp());
2390 AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
2391 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
2393 return dyn_cast<AtomicWriteOp>(getSecondOp());
2396 AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
2397 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
2399 return dyn_cast<AtomicUpdateOp>(getSecondOp());
2402 LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
2408 template <
typename Op>
2409 static LogicalResult
2411 bool requireAtLeastOneOperand =
true) {
2412 if (operands.empty() && requireAtLeastOneOperand)
2415 "at least one operand must appear on the declare operation");
2418 if (!mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2419 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
2420 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp>(
2421 operand.getDefiningOp()))
2423 "expect valid declare data entry operation or acc.getdeviceptr "
2427 assert(varPtr &&
"declare operands can only be data entry operations which "
2428 "must have varPtr");
2429 std::optional<mlir::acc::DataClause> dataClauseOptional{
2431 assert(dataClauseOptional.has_value() &&
2432 "declare operands can only be data entry operations which must have "
2436 if (!varPtr.getDefiningOp())
2440 auto declareAttribute{
2442 if (!declareAttribute)
2444 "expect declare attribute on variable in declare operation");
2446 auto declAttr = mlir::cast<mlir::acc::DeclareAttr>(declareAttribute);
2447 if (declAttr.getDataClause().getValue() != dataClauseOptional.value())
2449 "expect matching declare attribute on variable in declare operation");
2456 if (declAttr.getImplicit() &&
2459 "implicitness must match between declare op and flag on variable");
2493 acc::DeviceType dtype) {
2494 unsigned parallelism = 0;
2495 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
2496 parallelism += op.hasWorker(dtype) ? 1 : 0;
2497 parallelism += op.hasVector(dtype) ? 1 : 0;
2498 parallelism += op.hasSeq(dtype) ? 1 : 0;
2503 unsigned baseParallelism =
2506 if (baseParallelism > 1)
2507 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
2508 "be present at the same time";
2510 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
2512 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
2517 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
2518 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
2519 "be present at the same time";
2526 mlir::ArrayAttr &deviceTypes) {
2531 if (parser.parseAttribute(bindNameAttrs.emplace_back()))
2533 if (failed(parser.parseOptionalLSquare())) {
2534 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2535 parser.getContext(), mlir::acc::DeviceType::None));
2537 if (parser.parseAttribute(deviceTypeAttrs.emplace_back()) ||
2538 parser.parseRSquare())
2546 deviceTypes =
ArrayAttr::get(parser.getContext(), deviceTypeAttrs);
2552 std::optional<mlir::ArrayAttr> bindName,
2553 std::optional<mlir::ArrayAttr> deviceTypes) {
2554 llvm::interleaveComma(llvm::zip(*bindName, *deviceTypes), p,
2555 [&](
const auto &pair) {
2556 p << std::get<0>(pair);
2562 mlir::ArrayAttr &gang,
2563 mlir::ArrayAttr &gangDim,
2564 mlir::ArrayAttr &gangDimDeviceTypes) {
2567 gangDimDeviceTypeAttrs;
2568 bool needCommaBeforeOperands =
false;
2581 if (parser.parseAttribute(gangAttrs.emplace_back()))
2588 needCommaBeforeOperands =
true;
2591 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2595 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
2596 parser.parseColon() ||
2597 parser.parseAttribute(gangDimAttrs.emplace_back()))
2599 if (succeeded(parser.parseOptionalLSquare())) {
2600 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
2601 parser.parseRSquare())
2604 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2605 parser.getContext(), mlir::acc::DeviceType::None));
2611 if (failed(parser.parseRParen()))
2616 gangDimDeviceTypes =
2623 std::optional<mlir::ArrayAttr> gang,
2624 std::optional<mlir::ArrayAttr> gangDim,
2625 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
2628 gang->size() == 1) {
2629 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
2642 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
2643 [&](
const auto &pair) {
2644 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
2645 p << std::get<0>(pair);
2653 mlir::ArrayAttr &deviceTypes) {
2666 if (parser.parseAttribute(attributes.emplace_back()))
2680 std::optional<mlir::ArrayAttr> deviceTypes) {
2683 auto deviceTypeAttr =
2684 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
2694 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2702 bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
2708 bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
2714 bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
2718 std::optional<llvm::StringRef> RoutineOp::getBindNameValue() {
2722 std::optional<llvm::StringRef>
2723 RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
2725 return std::nullopt;
2726 if (
auto pos =
findSegment(*getBindNameDeviceType(), deviceType)) {
2727 auto attr = (*getBindName())[*pos];
2728 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
2729 return stringAttr.getValue();
2731 return std::nullopt;
2736 bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
2740 std::optional<int64_t> RoutineOp::getGangDimValue() {
2744 std::optional<int64_t>
2745 RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
2747 return std::nullopt;
2748 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
2749 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
2750 return intAttr.getInt();
2752 return std::nullopt;
2763 return emitOpError(
"cannot be nested in a compute operation");
2775 return emitOpError(
"cannot be nested in a compute operation");
2787 return emitOpError(
"cannot be nested in a compute operation");
2788 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
2789 return emitOpError(
"at least one default_async, device_num, or device_type "
2790 "operand must appear");
2800 if (getDataClauseOperands().empty())
2801 return emitError(
"at least one value must be present in dataOperands");
2804 getAsyncOperandsDeviceTypeAttr(),
2809 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2810 getWaitOperandsDeviceTypeAttr(),
"wait")))
2813 if (failed(checkWaitAndAsyncConflict<acc::UpdateOp>(*
this)))
2816 for (
mlir::Value operand : getDataClauseOperands())
2817 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp>(
2818 operand.getDefiningOp()))
2819 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
2825 unsigned UpdateOp::getNumDataOperands() {
2826 return getDataClauseOperands().size();
2829 Value UpdateOp::getDataOperand(
unsigned i) {
2831 numOptional += getIfCond() ? 1 : 0;
2832 return getOperand(getWaitOperands().size() + numOptional + i);
2837 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
2840 bool UpdateOp::hasAsyncOnly() {
2844 bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2852 mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2862 bool UpdateOp::hasWaitOnly() {
2866 bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2875 UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2877 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2878 getHasWaitDevnum(), deviceType);
2885 mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2887 getWaitOperandsSegments(), getHasWaitDevnum(),
2898 if (getAsyncOperand() && getAsync())
2899 return emitError(
"async attribute cannot appear with asyncOperand");
2901 if (getWaitDevnum() && getWaitOperands().empty())
2902 return emitError(
"wait_devnum cannot appear without waitOperands");
2907 #define GET_OP_CLASSES
2908 #include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
2910 #define GET_ATTRDEF_CLASSES
2911 #include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
2913 #define GET_TYPEDEF_CLASSES
2914 #include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
2923 [&](
auto entry) {
return entry.getVarPtr(); })
2924 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
2925 [&](
auto exit) {
return exit.getVarPtr(); })
2933 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
2942 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
2952 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
2954 dataClause.getBounds().begin(), dataClause.getBounds().end());
2966 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
2968 dataClause.getAsyncOperands().begin(),
2969 dataClause.getAsyncOperands().end());
2980 return dataClause.getAsyncOperandsDeviceTypeAttr();
2988 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
2995 .Case<ACC_DATA_ENTRY_OPS>([&](
auto entry) {
return entry.getName(); })
3002 std::optional<mlir::acc::DataClause>
3007 .Case<ACC_DATA_ENTRY_OPS>(
3008 [&](
auto entry) {
return entry.getDataClause(); })
3016 [&](
auto entry) {
return entry.getImplicit(); })
3025 [&](
auto entry) {
return entry.getDataClauseOperands(); })
3027 return dataOperands;
3035 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
3037 return dataOperands;
static void replaceOpWithRegion(PatternRewriter &rewriter, Operation *op, Region ®ion, ValueRange blockArgs={})
Replaces the given op with the contents of the given single-block region, using the operands of the b...
static MLIRContext * getContext(OpFoldResult val)
static LogicalResult verifyYield(linalg::YieldOp op, LinalgOp linalgOp)
void printRoutineGangClause(OpAsmPrinter &p, Operation *op, std::optional< mlir::ArrayAttr > gang, std::optional< mlir::ArrayAttr > gangDim, std::optional< mlir::ArrayAttr > gangDimDeviceTypes)
static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, unsigned nRegions=1)
bool hasDuplicateDeviceTypes(std::optional< mlir::ArrayAttr > segments, llvm::SmallSet< mlir::acc::DeviceType, 3 > &deviceTypes)
static LogicalResult verifyDeviceTypeCountMatch(Op op, OperandRange operands, ArrayAttr deviceTypes, llvm::StringRef keyword)
LogicalResult checkDeviceTypes(mlir::ArrayAttr deviceTypes)
Check for duplicates in the DeviceType array attribute.
static bool isComputeOperation(Operation *op)
static bool hasOnlyDeviceTypeNone(std::optional< mlir::ArrayAttr > attrs)
static ParseResult parseBindName(OpAsmParser &parser, mlir::ArrayAttr &bindName, mlir::ArrayAttr &deviceTypes)
static void printWaitClause(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments, std::optional< mlir::ArrayAttr > hasDevNum, std::optional< mlir::ArrayAttr > keywordOnly)
static ParseResult parseWaitClause(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments, mlir::ArrayAttr &hasDevNum, mlir::ArrayAttr &keywordOnly)
static bool hasDeviceTypeValues(std::optional< mlir::ArrayAttr > arrayAttr)
static void printDeviceTypeArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > deviceTypes)
static ParseResult parseGangValue(OpAsmParser &parser, llvm::StringRef keyword, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, llvm::SmallVector< GangArgTypeAttr > &attributes, GangArgTypeAttr gangArgType, bool &needCommaBetweenValues, bool &newValue)
static ParseResult parseCombinedConstructsLoop(mlir::OpAsmParser &parser, mlir::acc::CombinedConstructsTypeAttr &attr)
static LogicalResult checkDeclareOperands(Op &op, const mlir::ValueRange &operands, bool requireAtLeastOneOperand=true)
static void printDeviceTypes(mlir::OpAsmPrinter &p, std::optional< mlir::ArrayAttr > deviceTypes)
ParseResult parseLoopControl(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &lowerbound, SmallVectorImpl< Type > &lowerboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &upperbound, SmallVectorImpl< Type > &upperboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &step, SmallVectorImpl< Type > &stepType)
loop-control ::= control ( ssa-id-and-type-list ) = ( ssa-id-and-type-list ) to ( ssa-id-and-type-lis...
static LogicalResult checkDataOperands(Op op, const mlir::ValueRange &operands)
Check dataOperands for acc.parallel, acc.serial and acc.kernels.
static ParseResult parseDeviceTypeOperands(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes)
static mlir::Value getValueInDeviceTypeSegment(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, mlir::acc::DeviceType deviceType)
static mlir::Operation::operand_range getValuesFromSegments(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, std::optional< llvm::ArrayRef< int32_t >> segments, mlir::acc::DeviceType deviceType)
static ParseResult parseNumGangs(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
void printLoopControl(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lowerbound, TypeRange lowerboundType, ValueRange upperbound, TypeRange upperboundType, ValueRange steps, TypeRange stepType)
static ParseResult parseDeviceTypeArrayAttr(OpAsmParser &parser, mlir::ArrayAttr &deviceTypes)
static ParseResult parseRoutineGangClause(OpAsmParser &parser, mlir::ArrayAttr &gang, mlir::ArrayAttr &gangDim, mlir::ArrayAttr &gangDimDeviceTypes)
static void printDeviceTypeOperandsWithSegment(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments)
static void printDeviceTypeOperands(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes)
static void printBindName(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > bindName, std::optional< mlir::ArrayAttr > deviceTypes)
static ParseResult parseDeviceTypeOperandsWithSegment(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
static void printSymOperandList(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > attributes)
static mlir::Operation::operand_range getWaitValuesWithoutDevnum(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t >> segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static void printVarPtrType(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Type varPtrType, mlir::TypeAttr varTypeAttr)
static ParseResult parseGangClause(OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &gangOperands, llvm::SmallVectorImpl< Type > &gangOperandsType, mlir::ArrayAttr &gangArgType, mlir::ArrayAttr &deviceType, mlir::DenseI32ArrayAttr &segments, mlir::ArrayAttr &gangOnlyDeviceType)
static LogicalResult verifyInitLikeSingleArgRegion(Operation *op, Region ®ion, StringRef regionType, StringRef regionName, Type type, bool verifyYield, bool optional=false)
static void printSingleDeviceType(mlir::OpAsmPrinter &p, mlir::Attribute attr)
static std::optional< unsigned > findSegment(ArrayAttr segments, mlir::acc::DeviceType deviceType)
static LogicalResult checkSymOperandList(Operation *op, std::optional< mlir::ArrayAttr > attributes, mlir::OperandRange operands, llvm::StringRef operandName, llvm::StringRef symbolName, bool checkOperandType=true)
static void printDeviceTypeOperandsWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::ArrayAttr > keywordOnlyDeviceTypes)
static bool hasDeviceType(std::optional< mlir::ArrayAttr > arrayAttr, mlir::acc::DeviceType deviceType)
void printGangClause(OpAsmPrinter &p, Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > gangArgTypes, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments, std::optional< mlir::ArrayAttr > gangOnlyDeviceTypes)
static mlir::Value getWaitDevnumValue(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t >> segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static ParseResult parseDeviceTypeOperandsWithKeywordOnly(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::ArrayAttr &keywordOnlyDeviceType)
static ParseResult parseVarPtrType(mlir::OpAsmParser &parser, mlir::Type &varPtrType, mlir::TypeAttr &varTypeAttr)
static LogicalResult checkWaitAndAsyncConflict(Op op)
static LogicalResult verifyDeviceTypeAndSegmentCountMatch(Op op, OperandRange operands, DenseI32ArrayAttr segments, ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment=0)
static unsigned getParallelismForDeviceType(acc::RoutineOp op, acc::DeviceType dtype)
static void printNumGangs(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments)
static void printCombinedConstructsLoop(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::acc::CombinedConstructsTypeAttr attr)
static ParseResult parseSymOperandList(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &symbols)
#define ACC_COMPUTE_AND_DATA_CONSTRUCT_OPS
#define ACC_DATA_ENTRY_OPS
#define ACC_DATA_EXIT_OPS
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
virtual ParseResult parseLBrace()=0
Parse a { token.
@ None
Zero or more operands with no delimiters.
virtual ParseResult parseColonTypeList(SmallVectorImpl< Type > &result)=0
Parse a colon followed by a type list, which must have at least one type.
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 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.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseRBrace()=0
Parse a } token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printType(Type type)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
static BoolAttr get(MLIRContext *context, bool value)
MLIRContext is the top-level object for a collection of MLIR operations.
This class provides a mutable adaptor for a range of operands.
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.
virtual ParseResult parseArgumentList(SmallVectorImpl< Argument > &result, Delimiter delimiter=Delimiter::None, bool allowType=false, bool allowAttrs=false)=0
Parse zero or more arguments with a specified surrounding delimiter.
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.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
This class helps build Operations.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
operand_range getOperands()
Returns an iterator on the underlying Value's.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
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 replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues=std::nullopt)
Inline the operations of block 'source' into block 'dest' before the given position.
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 provides an abstraction over the various different ranges of value types.
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...
Type getType() const
Return the type of this value.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Builder from ArrayRef<T>.
ArrayRef< T > asArrayRef() const
mlir::Value getVarPtr(mlir::Operation *accDataClauseOp)
Used to obtain the varPtr 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::MutableOperandRange getMutableDataOperands(mlir::Operation *accOp)
Used to get a mutable range iterating over the data operands.
mlir::SmallVector< mlir::Value > getBounds(mlir::Operation *accDataClauseOp)
Used to obtain bounds from an acc data clause operation.
mlir::ValueRange getDataOperands(mlir::Operation *accOp)
Used to get an immutable range iterating over the data operands.
std::optional< llvm::StringRef > getVarName(mlir::Operation *accOp)
Used to obtain the name from an acc operation.
bool getImplicitFlag(mlir::Operation *accDataEntryOp)
Used to find out whether data operation is implicit.
mlir::SmallVector< mlir::Value > getAsyncOperands(mlir::Operation *accDataClauseOp)
Used to obtain async operands from an acc data clause operation.
mlir::Value getVarPtrPtr(mlir::Operation *accDataClauseOp)
Used to obtain the varPtrPtr from a data clause operation.
mlir::Value getAccPtr(mlir::Operation *accDataClauseOp)
Used to obtain the accPtr from a data clause operation.
mlir::ArrayAttr getAsyncOnly(mlir::Operation *accDataClauseOp)
Returns an array of acc:DeviceTypeAttr attributes attached to an acc data clause operation,...
static constexpr StringLiteral getDeclareAttrName()
Used to obtain the attribute name for declare.
mlir::ArrayAttr getAsyncOperandsDeviceType(mlir::Operation *accDataClauseOp)
Returns an array of acc:DeviceTypeAttr attributes attached to an acc data clause operation,...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
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...
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.