22#include "llvm/ADT/SmallSet.h"
23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/LogicalResult.h"
30#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
31#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
32#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
33#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
34#include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
37struct PrivateTypePointerLikeModel
38 :
public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
41 return cast<PrivateType>(type).getBaseTy();
44 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
45 Type resultType)
const {
46 if (value.
getType() == resultType)
48 if (!isa<PointerLikeType>(resultType))
50 return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
53 MemRefType getAsMemRefType(Type type, ModuleOp module)
const {
54 Type baseTy = cast<PrivateType>(type).getBaseTy();
55 if (
auto memrefTy = dyn_cast<MemRefType>(baseTy))
57 if (
auto ptrLikeTy = dyn_cast<PointerLikeType>(baseTy))
58 return ptrLikeTy.getAsMemRefType(module);
67mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
68 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
71 if (existingDeviceTypes)
72 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
74 if (newDeviceTypes.empty())
75 deviceTypes.push_back(
76 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
78 for (DeviceType dt : newDeviceTypes)
79 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
81 return mlir::ArrayAttr::get(context, deviceTypes);
90mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
91 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
96 if (existingDeviceTypes)
97 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
99 if (newDeviceTypes.empty()) {
100 argCollection.
append(arguments);
101 segments.push_back(arguments.size());
102 deviceTypes.push_back(
103 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
106 for (DeviceType dt : newDeviceTypes) {
107 argCollection.
append(arguments);
108 segments.push_back(arguments.size());
109 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
112 return mlir::ArrayAttr::get(context, deviceTypes);
116mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
117 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
121 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
122 newDeviceTypes, arguments,
123 argCollection, segments);
131void OpenACCDialect::initialize() {
134#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
137#define GET_ATTRDEF_LIST
138#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
141#define GET_TYPEDEF_LIST
142#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
145 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
182void ParallelOp::getSuccessorRegions(
212void HostDataOp::getSuccessorRegions(
240 if (loopOp.isContainerLike())
250 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
257 if (!lb || !
ub || !step || *step == 0) {
266 std::optional<ArrayRef<bool>> inclusiveUbs =
267 loopOp.getInclusiveUpperbound();
268 bool inclusiveUb = inclusiveUbs && (*inclusiveUbs)[i];
269 assert(*step != 0 &&
"zero step should have been filtered out");
270 bool runsOnce = *step > 0 ? (inclusiveUb ? *lb <= *
ub : *lb < *
ub)
271 : (inclusiveUb ? *lb >= *
ub : *lb > *
ub);
289 if (getUnstructured()) {
336 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
340 mlir::acc::DeviceType deviceType) {
344 for (
auto attr : *arrayAttr) {
345 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
346 if (deviceTypeAttr.getValue() == deviceType)
354 std::optional<mlir::ArrayAttr> deviceTypes) {
359 llvm::interleaveComma(*deviceTypes, p,
365 mlir::acc::DeviceType deviceType) {
366 unsigned segmentIdx = 0;
367 for (
auto attr : segments) {
368 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
369 if (deviceTypeAttr.getValue() == deviceType)
370 return std::make_optional(segmentIdx);
380 mlir::acc::DeviceType deviceType) {
382 return range.take_front(0);
383 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
384 int32_t nbOperandsBefore = 0;
385 for (
unsigned i = 0; i < *pos; ++i)
386 nbOperandsBefore += (*segments)[i];
387 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
389 return range.take_front(0);
397 mlir::acc::DeviceType deviceType) {
400 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
402 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
403 if (boolAttr && boolAttr.getValue())
417 mlir::acc::DeviceType deviceType) {
422 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
424 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
425 if (boolAttr.getValue())
426 return range.drop_front(1);
432template <
typename Op>
434 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
436 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
441 op.hasAsyncOnly(dtype))
443 "asyncOnly attribute cannot appear with asyncOperand");
448 op.hasWaitOnly(dtype))
449 return op.
emitError(
"wait attribute cannot appear with waitOperands");
454template <
typename Op>
457 return op.
emitError(
"must have var operand");
460 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
461 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
462 return op.
emitError(
"var must be mappable or pointer-like");
465 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
466 op.getVarType() == op.getVar().getType())
467 return op.
emitError(
"varType must capture the element type of var");
472template <
typename Op>
474 if (op.getVar().getType() != op.getAccVar().getType())
475 return op.
emitError(
"input and output types must match");
480template <
typename Op>
482 if (op.getModifiers() != acc::DataClauseModifier::none)
483 return op.
emitError(
"no data clause modifiers are allowed");
487template <
typename Op>
490 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
492 "invalid data clause modifiers: " +
493 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
498template <
typename OpT,
typename RecipeOpT>
499static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
504 !std::is_same_v<OpT, acc::ReductionOp>)
507 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
509 return op->emitOpError() <<
"recipe expected for " << operandName;
514 return op->emitOpError()
515 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
516 << operandName <<
" declaration";
537 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
558 if (failed(parser.
parseType(accVarType)))
568 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
580 mlir::TypeAttr &varTypeAttr) {
581 if (failed(parser.
parseType(varPtrType)))
592 varTypeAttr = mlir::TypeAttr::get(varType);
597 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
598 Type elementType = ptrTy.getElementType();
601 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
603 varTypeAttr = mlir::TypeAttr::get(varPtrType);
611 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
619 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
620 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
624 if (!typeToCheckAgainst)
625 typeToCheckAgainst = varPtrType;
626 if (typeToCheckAgainst != varType) {
642 locAttr = mlir::dyn_cast<mlir::LocationAttr>(attr);
644 return parser.
emitError(attrLoc,
"expected location attribute");
654 mlir::SymbolRefAttr &recipeAttr) {
661 mlir::SymbolRefAttr recipeAttr) {
676 mlir::ArrayAttr &attr) {
681 mlir::ArrayAttr attr) {
688LogicalResult acc::DataBoundsOp::verify() {
689 auto extent = getExtent();
690 auto upperbound = getUpperbound();
691 if (!extent && !upperbound)
692 return emitError(
"expected extent or upperbound.");
699LogicalResult acc::PrivateOp::verify() {
702 "data clause associated with private operation must match its intent");
716LogicalResult acc::FirstprivateOp::verify() {
718 return emitError(
"data clause associated with firstprivate operation must "
725 *
this,
"firstprivate")))
733LogicalResult acc::ReductionOp::verify() {
735 return emitError(
"data clause associated with reduction operation must "
742 *
this,
"reduction")))
750LogicalResult acc::DevicePtrOp::verify() {
752 return emitError(
"data clause associated with deviceptr operation must "
766LogicalResult acc::PresentOp::verify() {
769 "data clause associated with present operation must match its intent");
782LogicalResult acc::CopyinOp::verify() {
784 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
789 "data clause associated with copyin operation must match its intent"
790 " or specify original clause this operation was decomposed from");
796 acc::DataClauseModifier::always |
797 acc::DataClauseModifier::capture)))
802bool acc::CopyinOp::isCopyinReadonly() {
803 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
804 acc::bitEnumContainsAny(getModifiers(),
805 acc::DataClauseModifier::readonly);
811LogicalResult acc::CreateOp::verify() {
818 "data clause associated with create operation must match its intent"
819 " or specify original clause this operation was decomposed from");
827 acc::DataClauseModifier::always |
828 acc::DataClauseModifier::capture)))
833bool acc::CreateOp::isCreateZero() {
835 return getDataClause() == acc::DataClause::acc_create_zero ||
837 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
843LogicalResult acc::NoCreateOp::verify() {
845 return emitError(
"data clause associated with no_create operation must "
859LogicalResult acc::AttachOp::verify() {
862 "data clause associated with attach operation must match its intent");
876LogicalResult acc::DeclareDeviceResidentOp::verify() {
877 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
878 return emitError(
"data clause associated with device_resident operation "
879 "must match its intent");
893LogicalResult acc::DeclareLinkOp::verify() {
896 "data clause associated with link operation must match its intent");
909LogicalResult acc::CopyoutOp::verify() {
916 "data clause associated with copyout operation must match its intent"
917 " or specify original clause this operation was decomposed from");
919 return emitError(
"must have both host and device pointers");
925 acc::DataClauseModifier::always |
926 acc::DataClauseModifier::capture)))
931bool acc::CopyoutOp::isCopyoutZero() {
932 return getDataClause() == acc::DataClause::acc_copyout_zero ||
933 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
939LogicalResult acc::DeleteOp::verify() {
948 getDataClause() != acc::DataClause::acc_declare_device_resident &&
951 "data clause associated with delete operation must match its intent"
952 " or specify original clause this operation was decomposed from");
954 return emitError(
"must have device pointer");
958 acc::DataClauseModifier::readonly |
959 acc::DataClauseModifier::always |
960 acc::DataClauseModifier::capture)))
968LogicalResult acc::DetachOp::verify() {
973 "data clause associated with detach operation must match its intent"
974 " or specify original clause this operation was decomposed from");
976 return emitError(
"must have device pointer");
985LogicalResult acc::UpdateHostOp::verify() {
990 "data clause associated with host operation must match its intent"
991 " or specify original clause this operation was decomposed from");
993 return emitError(
"must have both host and device pointers");
1006LogicalResult acc::UpdateDeviceOp::verify() {
1010 "data clause associated with device operation must match its intent"
1011 " or specify original clause this operation was decomposed from");
1024LogicalResult acc::UseDeviceOp::verify() {
1028 "data clause associated with use_device operation must match its intent"
1029 " or specify original clause this operation was decomposed from");
1042LogicalResult acc::CacheOp::verify() {
1047 "data clause associated with cache operation must match its intent"
1048 " or specify original clause this operation was decomposed from");
1058bool acc::CacheOp::isCacheReadonly() {
1059 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1060 acc::bitEnumContainsAny(getModifiers(),
1061 acc::DataClauseModifier::readonly);
1077template <
typename EffectTy>
1082 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1083 effects.emplace_back(EffectTy::get(), &operand[i]);
1087template <
typename EffectTy>
1092 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1096void acc::PrivateOp::getEffects(
1110void acc::FirstprivateOp::getEffects(
1124void acc::ReductionOp::getEffects(
1138void acc::DevicePtrOp::getEffects(
1147void acc::PresentOp::getEffects(
1158void acc::CopyinOp::getEffects(
1171void acc::CreateOp::getEffects(
1184void acc::NoCreateOp::getEffects(
1195void acc::AttachOp::getEffects(
1208void acc::GetDevicePtrOp::getEffects(
1217void acc::UpdateDeviceOp::getEffects(
1227void acc::UseDeviceOp::getEffects(
1236void acc::DeclareDeviceResidentOp::getEffects(
1247void acc::DeclareLinkOp::getEffects(
1258void acc::CacheOp::getEffects(
1263void acc::CopyoutOp::getEffects(
1276void acc::DeleteOp::getEffects(
1288void acc::DetachOp::getEffects(
1300void acc::UpdateHostOp::getEffects(
1316template <
typename OpTy>
1318 using OpRewritePattern<OpTy>::OpRewritePattern;
1320 LogicalResult matchAndRewrite(OpTy op,
1321 PatternRewriter &rewriter)
const override {
1323 Value ifCond = op.getIfCond();
1327 IntegerAttr constAttr;
1330 if (constAttr.getInt())
1331 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1343 assert(region.
hasOneBlock() &&
"expected single-block region");
1355template <
typename OpTy>
1356struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1357 using OpRewritePattern<OpTy>::OpRewritePattern;
1359 LogicalResult matchAndRewrite(OpTy op,
1360 PatternRewriter &rewriter)
const override {
1362 Value ifCond = op.getIfCond();
1366 IntegerAttr constAttr;
1369 if (constAttr.getInt()) {
1370 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1377 Region ®ion = op.getRegion();
1378 if (region.
empty()) {
1379 if (op->getNumResults() != 0)
1413 for (
Value bound : bounds) {
1414 argTypes.push_back(bound.getType());
1415 argLocs.push_back(loc);
1422 Value privatizedValue;
1428 if (isa<MappableType>(varType)) {
1429 auto mappableTy = cast<MappableType>(varType);
1430 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1431 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1432 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1434 mappableTy.generatePrivateInit(builder, loc, typedVar, varName, bounds,
1435 {}, varInfo, needsFree, destroyValues);
1436 if (!privatizedValue)
1439 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1440 auto pointerLikeTy = cast<PointerLikeType>(varType);
1442 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1443 blockArgVar, needsFree);
1444 if (!privatizedValue)
1450 initResults.append(destroyValues);
1451 acc::YieldOp::create(builder, loc, initResults);
1468 for (
Value bound : bounds) {
1469 copyArgTypes.push_back(bound.getType());
1470 copyArgLocs.push_back(loc);
1480 if (isa<MappableType>(varType)) {
1481 auto mappableTy = cast<MappableType>(varType);
1484 if (!mappableTy.generateCopy(
1489 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1490 auto pointerLikeTy = cast<PointerLikeType>(varType);
1491 if (!pointerLikeTy.genCopy(
1498 acc::TerminatorOp::create(builder, loc);
1515 for (
Value destroyValue : destroyValues) {
1516 destroyArgTypes.push_back(destroyValue.getType());
1517 destroyArgLocs.push_back(loc);
1519 for (
Value bound : bounds) {
1520 destroyArgTypes.push_back(bound.getType());
1521 destroyArgLocs.push_back(loc);
1525 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1529 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1530 if (isa<MappableType>(varType)) {
1531 auto mappableTy = cast<MappableType>(varType);
1533 destroyBlock->
getArguments().slice(2, destroyValues.size());
1535 destroyBlock->
getArguments().drop_front(2 + destroyValues.size());
1536 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, destroyArgs,
1537 destroyBounds, varInfo))
1540 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1541 auto pointerLikeTy = cast<PointerLikeType>(varType);
1542 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1546 acc::TerminatorOp::create(builder, loc);
1556 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1558 if (optional && region.
empty())
1562 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1566 return op->
emitOpError() <<
"expects " << regionName
1569 << regionType <<
" type";
1572 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1573 if (yieldOp.getOperands().size() != 1 ||
1574 yieldOp.getOperands().getTypes()[0] != type)
1575 return op->
emitOpError() <<
"expects " << regionName
1577 "yield a value of the "
1578 << regionType <<
" type";
1584LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1586 "privatization",
"init",
getType(),
1590 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1596std::optional<PrivateRecipeOp>
1598 StringRef recipeName,
Value hostVar,
1603 bool isMappable = isa<MappableType>(varType);
1604 bool isPointerLike = isa<PointerLikeType>(varType);
1607 if (!isMappable && !isPointerLike)
1608 return std::nullopt;
1613 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1617 bool needsFree =
false;
1620 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1621 varName, bounds, needsFree, varInfo,
1624 return std::nullopt;
1631 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1632 Value allocRes = yieldOp.getOperand(0);
1634 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1635 varType, allocRes, destroyValues, bounds,
1638 return std::nullopt;
1645std::optional<PrivateRecipeOp>
1647 StringRef recipeName,
1648 FirstprivateRecipeOp firstprivRecipe) {
1651 auto varType = firstprivRecipe.getType();
1652 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1657 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
1660 if (!firstprivRecipe.getDestroyRegion().empty()) {
1662 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
1672LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
1674 "privatization",
"init",
getType(),
1678 if (getCopyRegion().empty())
1679 return emitOpError() <<
"expects non-empty copy region";
1684 return emitOpError() <<
"expects copy region with two arguments of the "
1685 "privatization type";
1687 if (getDestroyRegion().empty())
1691 "privatization",
"destroy",
1698std::optional<FirstprivateRecipeOp>
1700 StringRef recipeName,
Value hostVar,
1705 bool isMappable = isa<MappableType>(varType);
1706 bool isPointerLike = isa<PointerLikeType>(varType);
1709 if (!isMappable && !isPointerLike)
1710 return std::nullopt;
1715 auto recipe = FirstprivateRecipeOp::create(
1716 builder, loc, recipeName,
nullptr, varType);
1719 bool needsFree =
false;
1725 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1726 varName, bounds, needsFree, varInfo,
1729 return std::nullopt;
1733 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
1734 bounds, varInfo))) {
1736 return std::nullopt;
1743 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1744 Value allocRes = yieldOp.getOperand(0);
1746 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1747 varType, allocRes, destroyValues, bounds,
1750 return std::nullopt;
1761LogicalResult acc::ReductionRecipeOp::verifyRegions() {
1767 if (getCombinerRegion().empty())
1768 return emitOpError() <<
"expects non-empty combiner region";
1770 Block &reductionBlock = getCombinerRegion().
front();
1774 return emitOpError() <<
"expects combiner region with the first two "
1775 <<
"arguments of the reduction type";
1777 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
1778 if (yieldOp.getOperands().size() != 1 ||
1779 yieldOp.getOperands().getTypes()[0] !=
getType())
1780 return emitOpError() <<
"expects combiner region to yield a value "
1781 "of the reduction type";
1792template <
typename Op>
1796 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
1797 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
1798 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
1799 acc::MapInfoOp>(operand.getDefiningOp()))
1801 "expect data entry/exit operation or acc.getdeviceptr "
1806template <
typename OpT,
typename RecipeOpT>
1809 llvm::StringRef operandName) {
1812 if (!mlir::isa<OpT>(operand.getDefiningOp()))
1814 <<
"expected " << operandName <<
" as defining op";
1815 if (!set.insert(operand).second)
1817 << operandName <<
" operand appears more than once";
1822unsigned ParallelOp::getNumDataOperands() {
1823 return getReductionOperands().size() + getPrivateOperands().size() +
1824 getFirstprivateOperands().size() + getDataClauseOperands().size();
1827Value ParallelOp::getDataOperand(
unsigned i) {
1829 numOptional += getNumGangs().size();
1830 numOptional += getNumWorkers().size();
1831 numOptional += getVectorLength().size();
1832 numOptional += getIfCond() ? 1 : 0;
1833 numOptional += getSelfCond() ? 1 : 0;
1834 return getOperand(getWaitOperands().size() + numOptional + i);
1837template <
typename Op>
1840 llvm::StringRef keyword) {
1841 if (!operands.empty() &&
1842 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
1843 return op.
emitOpError() << keyword <<
" operands count must match "
1844 << keyword <<
" device_type count";
1848template <
typename Op>
1851 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
1852 std::size_t numOperandsInSegments = 0;
1853 std::size_t nbOfSegments = 0;
1856 for (
auto segCount : segments.
asArrayRef()) {
1857 if (maxInSegment != 0 && segCount > maxInSegment)
1858 return op.
emitOpError() << keyword <<
" expects a maximum of "
1859 << maxInSegment <<
" values per segment";
1860 numOperandsInSegments += segCount;
1865 if ((numOperandsInSegments != operands.size()) ||
1866 (!deviceTypes && !operands.empty()))
1868 << keyword <<
" operand count does not match count in segments";
1869 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
1871 << keyword <<
" segment count does not match device_type count";
1875LogicalResult acc::ParallelOp::verify() {
1877 mlir::acc::PrivateRecipeOp>(
1878 *
this, getPrivateOperands(),
"private")))
1881 mlir::acc::FirstprivateRecipeOp>(
1882 *
this, getFirstprivateOperands(),
"firstprivate")))
1885 mlir::acc::ReductionRecipeOp>(
1886 *
this, getReductionOperands(),
"reduction")))
1890 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
1891 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
1895 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
1896 getWaitOperandsDeviceTypeAttr(),
"wait")))
1900 getNumWorkersDeviceTypeAttr(),
1905 getVectorLengthDeviceTypeAttr(),
1910 getAsyncOperandsDeviceTypeAttr(),
1923 mlir::acc::DeviceType deviceType) {
1926 if (
auto pos =
findSegment(*arrayAttr, deviceType))
1931bool acc::ParallelOp::hasAsyncOnly() {
1932 return hasAsyncOnly(mlir::acc::DeviceType::None);
1935bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
1940 return getAsyncValue(mlir::acc::DeviceType::None);
1943mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
1948mlir::Value acc::ParallelOp::getNumWorkersValue() {
1949 return getNumWorkersValue(mlir::acc::DeviceType::None);
1953acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
1958mlir::Value acc::ParallelOp::getVectorLengthValue() {
1959 return getVectorLengthValue(mlir::acc::DeviceType::None);
1963acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
1965 getVectorLength(), deviceType);
1969 return getNumGangsValues(mlir::acc::DeviceType::None);
1973ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
1975 getNumGangsSegments(), deviceType);
1979 std::optional<mlir::ArrayAttr> numGangsDeviceType,
1982 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
1984 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
1986 mlir::acc::DeviceType deviceType) {
1996bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
1998 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
1999 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2000 getVectorLength(), deviceType);
2003bool acc::ParallelOp::isEffectivelySerial() {
2007bool acc::ParallelOp::hasWaitOnly() {
2008 return hasWaitOnly(mlir::acc::DeviceType::None);
2011bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2016 return getWaitValues(mlir::acc::DeviceType::None);
2020ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2022 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2023 getHasWaitDevnum(), deviceType);
2027 return getWaitDevnum(mlir::acc::DeviceType::None);
2030mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2032 getWaitOperandsSegments(), getHasWaitDevnum(),
2047 odsBuilder, odsState, asyncOperands,
nullptr,
2048 nullptr, waitOperands,
nullptr,
2050 nullptr, numGangs,
nullptr,
2051 nullptr, numWorkers,
2052 nullptr, vectorLength,
2053 nullptr, ifCond, selfCond,
2054 false, reductionOperands, gangPrivateOperands,
2055 gangFirstPrivateOperands, dataClauseOperands,
2059void acc::ParallelOp::addNumWorkersOperand(
2062 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2063 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2064 getNumWorkersMutable()));
2066void acc::ParallelOp::addVectorLengthOperand(
2069 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2070 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2071 getVectorLengthMutable()));
2074void acc::ParallelOp::addAsyncOnly(
2076 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2077 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2080void acc::ParallelOp::addAsyncOperand(
2083 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2084 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2085 getAsyncOperandsMutable()));
2088void acc::ParallelOp::addNumGangsOperands(
2092 if (getNumGangsSegments())
2093 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2095 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2096 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2097 getNumGangsMutable(), segments));
2099 setNumGangsSegments(segments);
2101void acc::ParallelOp::addWaitOnly(
2103 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2104 effectiveDeviceTypes));
2106void acc::ParallelOp::addWaitOperands(
2111 if (getWaitOperandsSegments())
2112 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2114 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2115 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2116 getWaitOperandsMutable(), segments));
2117 setWaitOperandsSegments(segments);
2120 if (getHasWaitDevnumAttr())
2121 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2124 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2126 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2129void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2130 mlir::acc::PrivateOp op,
2131 mlir::acc::PrivateRecipeOp recipe) {
2132 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2133 getPrivateOperandsMutable().append(op.getResult());
2136void acc::ParallelOp::addFirstPrivatization(
2137 MLIRContext *context, mlir::acc::FirstprivateOp op,
2138 mlir::acc::FirstprivateRecipeOp recipe) {
2139 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2140 getFirstprivateOperandsMutable().append(op.getResult());
2143void acc::ParallelOp::addReduction(
MLIRContext *context,
2144 mlir::acc::ReductionOp op,
2145 mlir::acc::ReductionRecipeOp recipe) {
2146 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2147 getReductionOperandsMutable().append(op.getResult());
2162 int32_t crtOperandsSize = operands.size();
2165 if (parser.parseOperand(operands.emplace_back()) ||
2166 parser.parseColonType(types.emplace_back()))
2171 seg.push_back(operands.size() - crtOperandsSize);
2181 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2182 parser.
getContext(), mlir::acc::DeviceType::None));
2188 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2195 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2196 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2197 p <<
" [" << attr <<
"]";
2202 std::optional<mlir::ArrayAttr> deviceTypes,
2203 std::optional<mlir::DenseI32ArrayAttr> segments) {
2205 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2207 llvm::interleaveComma(
2208 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2209 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2229 int32_t crtOperandsSize = operands.size();
2233 if (parser.parseOperand(operands.emplace_back()) ||
2234 parser.parseColonType(types.emplace_back()))
2240 seg.push_back(operands.size() - crtOperandsSize);
2250 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2251 parser.
getContext(), mlir::acc::DeviceType::None));
2257 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2266 std::optional<mlir::DenseI32ArrayAttr> segments) {
2268 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2270 llvm::interleaveComma(
2271 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2272 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2285 mlir::ArrayAttr &keywordOnly) {
2289 bool needCommaBeforeOperands =
false;
2293 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2294 parser.
getContext(), mlir::acc::DeviceType::None));
2295 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2302 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2309 needCommaBeforeOperands =
true;
2312 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2319 int32_t crtOperandsSize = operands.size();
2331 if (parser.parseOperand(operands.emplace_back()) ||
2332 parser.parseColonType(types.emplace_back()))
2338 seg.push_back(operands.size() - crtOperandsSize);
2348 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2349 parser.
getContext(), mlir::acc::DeviceType::None));
2356 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2357 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2359 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2367 if (attrs->size() != 1)
2369 if (
auto deviceTypeAttr =
2370 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2371 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2377 std::optional<mlir::ArrayAttr> deviceTypes,
2378 std::optional<mlir::DenseI32ArrayAttr> segments,
2379 std::optional<mlir::ArrayAttr> hasDevNum,
2380 std::optional<mlir::ArrayAttr> keywordOnly) {
2393 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2395 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2396 if (boolAttr && boolAttr.getValue())
2398 llvm::interleaveComma(
2399 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2400 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2417 if (parser.parseOperand(operands.emplace_back()) ||
2418 parser.parseColonType(types.emplace_back()))
2420 if (succeeded(parser.parseOptionalLSquare())) {
2421 if (parser.parseAttribute(attributes.emplace_back()) ||
2422 parser.parseRSquare())
2425 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2426 parser.getContext(), mlir::acc::DeviceType::None));
2433 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2440 std::optional<mlir::ArrayAttr> deviceTypes) {
2443 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2444 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2453 mlir::ArrayAttr &keywordOnlyDeviceType) {
2456 bool needCommaBeforeOperands =
false;
2460 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2461 parser.
getContext(), mlir::acc::DeviceType::None));
2462 keywordOnlyDeviceType =
2463 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2471 if (parser.parseAttribute(
2472 keywordOnlyDeviceTypeAttributes.emplace_back()))
2479 keywordOnlyDeviceType =
2480 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2481 needCommaBeforeOperands =
true;
2484 if (needCommaBeforeOperands) {
2493 if (parser.parseOperand(operands.emplace_back()) ||
2494 parser.parseColonType(types.emplace_back()))
2496 if (succeeded(parser.parseOptionalLSquare())) {
2497 if (parser.parseAttribute(attributes.emplace_back()) ||
2498 parser.parseRSquare())
2501 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2502 parser.getContext(), mlir::acc::DeviceType::None));
2508 if (
failed(parser.parseRParen()))
2513 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2520 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2522 if (operands.begin() == operands.end() &&
2538 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2539 mlir::Type &operandType, mlir::UnitAttr &attr) {
2542 attr = mlir::UnitAttr::get(parser.
getContext());
2552 if (failed(parser.
parseType(operandType)))
2562 std::optional<mlir::Value> operand,
2564 mlir::UnitAttr attr) {
2581 attr = mlir::UnitAttr::get(parser.
getContext());
2586 if (parser.parseOperand(operands.emplace_back()))
2594 if (parser.parseType(types.emplace_back()))
2609 mlir::UnitAttr attr) {
2614 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2616 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2622 mlir::acc::CombinedConstructsTypeAttr &attr) {
2624 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2625 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2627 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2628 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2630 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2631 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2634 "expected compute construct name");
2642 mlir::acc::CombinedConstructsTypeAttr attr) {
2644 switch (attr.getValue()) {
2645 case mlir::acc::CombinedConstructsType::KernelsLoop:
2648 case mlir::acc::CombinedConstructsType::ParallelLoop:
2651 case mlir::acc::CombinedConstructsType::SerialLoop:
2662unsigned SerialOp::getNumDataOperands() {
2663 return getReductionOperands().size() + getPrivateOperands().size() +
2664 getFirstprivateOperands().size() + getDataClauseOperands().size();
2667Value SerialOp::getDataOperand(
unsigned i) {
2669 numOptional += getIfCond() ? 1 : 0;
2670 numOptional += getSelfCond() ? 1 : 0;
2671 return getOperand(getWaitOperands().size() + numOptional + i);
2674bool acc::SerialOp::hasAsyncOnly() {
2675 return hasAsyncOnly(mlir::acc::DeviceType::None);
2678bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2683 return getAsyncValue(mlir::acc::DeviceType::None);
2686mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2691bool acc::SerialOp::hasWaitOnly() {
2692 return hasWaitOnly(mlir::acc::DeviceType::None);
2695bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2700 return getWaitValues(mlir::acc::DeviceType::None);
2704SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2706 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2707 getHasWaitDevnum(), deviceType);
2711 return getWaitDevnum(mlir::acc::DeviceType::None);
2714mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2716 getWaitOperandsSegments(), getHasWaitDevnum(),
2720LogicalResult acc::SerialOp::verify() {
2722 mlir::acc::PrivateRecipeOp>(
2723 *
this, getPrivateOperands(),
"private")))
2726 mlir::acc::FirstprivateRecipeOp>(
2727 *
this, getFirstprivateOperands(),
"firstprivate")))
2730 mlir::acc::ReductionRecipeOp>(
2731 *
this, getReductionOperands(),
"reduction")))
2735 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2736 getWaitOperandsDeviceTypeAttr(),
"wait")))
2740 getAsyncOperandsDeviceTypeAttr(),
2750void acc::SerialOp::addAsyncOnly(
2752 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2753 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2756void acc::SerialOp::addAsyncOperand(
2759 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2760 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2761 getAsyncOperandsMutable()));
2764void acc::SerialOp::addWaitOnly(
2766 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2767 effectiveDeviceTypes));
2769void acc::SerialOp::addWaitOperands(
2774 if (getWaitOperandsSegments())
2775 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2777 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2778 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2779 getWaitOperandsMutable(), segments));
2780 setWaitOperandsSegments(segments);
2783 if (getHasWaitDevnumAttr())
2784 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2787 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2789 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2792void acc::SerialOp::addPrivatization(
MLIRContext *context,
2793 mlir::acc::PrivateOp op,
2794 mlir::acc::PrivateRecipeOp recipe) {
2795 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2796 getPrivateOperandsMutable().append(op.getResult());
2799void acc::SerialOp::addFirstPrivatization(
2800 MLIRContext *context, mlir::acc::FirstprivateOp op,
2801 mlir::acc::FirstprivateRecipeOp recipe) {
2802 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2803 getFirstprivateOperandsMutable().append(op.getResult());
2806void acc::SerialOp::addReduction(
MLIRContext *context,
2807 mlir::acc::ReductionOp op,
2808 mlir::acc::ReductionRecipeOp recipe) {
2809 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2810 getReductionOperandsMutable().append(op.getResult());
2817unsigned KernelsOp::getNumDataOperands() {
2818 return getDataClauseOperands().size();
2821Value KernelsOp::getDataOperand(
unsigned i) {
2823 numOptional += getWaitOperands().size();
2824 numOptional += getNumGangs().size();
2825 numOptional += getNumWorkers().size();
2826 numOptional += getVectorLength().size();
2827 numOptional += getIfCond() ? 1 : 0;
2828 numOptional += getSelfCond() ? 1 : 0;
2829 return getOperand(numOptional + i);
2832bool acc::KernelsOp::hasAsyncOnly() {
2833 return hasAsyncOnly(mlir::acc::DeviceType::None);
2836bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2841 return getAsyncValue(mlir::acc::DeviceType::None);
2844mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2850 return getNumWorkersValue(mlir::acc::DeviceType::None);
2854acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2859mlir::Value acc::KernelsOp::getVectorLengthValue() {
2860 return getVectorLengthValue(mlir::acc::DeviceType::None);
2864acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2866 getVectorLength(), deviceType);
2870 return getNumGangsValues(mlir::acc::DeviceType::None);
2874KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2876 getNumGangsSegments(), deviceType);
2879bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2881 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2882 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2883 getVectorLength(), deviceType);
2886bool acc::KernelsOp::isEffectivelySerial() {
2890bool acc::KernelsOp::hasWaitOnly() {
2891 return hasWaitOnly(mlir::acc::DeviceType::None);
2894bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2899 return getWaitValues(mlir::acc::DeviceType::None);
2903KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2905 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2906 getHasWaitDevnum(), deviceType);
2910 return getWaitDevnum(mlir::acc::DeviceType::None);
2913mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2915 getWaitOperandsSegments(), getHasWaitDevnum(),
2919LogicalResult acc::KernelsOp::verify() {
2921 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2922 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2926 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2927 getWaitOperandsDeviceTypeAttr(),
"wait")))
2931 getNumWorkersDeviceTypeAttr(),
2936 getVectorLengthDeviceTypeAttr(),
2941 getAsyncOperandsDeviceTypeAttr(),
2951void acc::KernelsOp::addPrivatization(
MLIRContext *context,
2952 mlir::acc::PrivateOp op,
2953 mlir::acc::PrivateRecipeOp recipe) {
2954 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2955 getPrivateOperandsMutable().append(op.getResult());
2958void acc::KernelsOp::addFirstPrivatization(
2959 MLIRContext *context, mlir::acc::FirstprivateOp op,
2960 mlir::acc::FirstprivateRecipeOp recipe) {
2961 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2962 getFirstprivateOperandsMutable().append(op.getResult());
2965void acc::KernelsOp::addReduction(
MLIRContext *context,
2966 mlir::acc::ReductionOp op,
2967 mlir::acc::ReductionRecipeOp recipe) {
2968 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2969 getReductionOperandsMutable().append(op.getResult());
2972void acc::KernelsOp::addNumWorkersOperand(
2975 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2976 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2977 getNumWorkersMutable()));
2980void acc::KernelsOp::addVectorLengthOperand(
2983 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2984 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2985 getVectorLengthMutable()));
2987void acc::KernelsOp::addAsyncOnly(
2989 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2990 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2993void acc::KernelsOp::addAsyncOperand(
2996 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2997 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2998 getAsyncOperandsMutable()));
3001void acc::KernelsOp::addNumGangsOperands(
3005 if (getNumGangsSegmentsAttr())
3006 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3008 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3009 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3010 getNumGangsMutable(), segments));
3012 setNumGangsSegments(segments);
3015void acc::KernelsOp::addWaitOnly(
3017 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3018 effectiveDeviceTypes));
3020void acc::KernelsOp::addWaitOperands(
3025 if (getWaitOperandsSegments())
3026 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3028 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3029 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3030 getWaitOperandsMutable(), segments));
3031 setWaitOperandsSegments(segments);
3034 if (getHasWaitDevnumAttr())
3035 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3038 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3040 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3047LogicalResult acc::HostDataOp::verify() {
3048 if (getDataClauseOperands().empty())
3049 return emitError(
"at least one operand must appear on the host_data "
3053 for (
mlir::Value operand : getDataClauseOperands()) {
3055 mlir::dyn_cast_if_present<acc::UseDeviceOp>(operand.getDefiningOp());
3057 return emitError(
"expect data entry operation as defining op");
3060 if (!seenVars.insert(useDeviceOp.getVar()).second)
3061 return emitError(
"duplicate use_device variable");
3068 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3080 bool &needCommaBetweenValues,
bool &newValue) {
3087 attributes.push_back(gangArgType);
3088 needCommaBetweenValues =
true;
3099 mlir::ArrayAttr &gangOnlyDeviceType) {
3104 bool needCommaBetweenValues =
false;
3105 bool needCommaBeforeOperands =
false;
3109 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3110 parser.
getContext(), mlir::acc::DeviceType::None));
3111 gangOnlyDeviceType =
3112 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3120 if (parser.parseAttribute(
3121 gangOnlyDeviceTypeAttributes.emplace_back()))
3128 needCommaBeforeOperands =
true;
3131 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3132 mlir::acc::GangArgType::Num);
3133 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3134 mlir::acc::GangArgType::Dim);
3135 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3136 parser.
getContext(), mlir::acc::GangArgType::Static);
3139 if (needCommaBeforeOperands) {
3140 needCommaBeforeOperands =
false;
3147 int32_t crtOperandsSize = gangOperands.size();
3149 bool newValue =
false;
3150 bool needValue =
false;
3151 if (needCommaBetweenValues) {
3159 gangOperands, gangOperandsType,
3160 gangArgTypeAttributes, argNum,
3161 needCommaBetweenValues, newValue)))
3164 gangOperands, gangOperandsType,
3165 gangArgTypeAttributes, argDim,
3166 needCommaBetweenValues, newValue)))
3168 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3169 gangOperands, gangOperandsType,
3170 gangArgTypeAttributes, argStatic,
3171 needCommaBetweenValues, newValue)))
3174 if (!newValue && needValue) {
3176 "new value expected after comma");
3184 if (gangOperands.empty())
3187 "expect at least one of num, dim or static values");
3193 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3197 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3198 parser.
getContext(), mlir::acc::DeviceType::None));
3201 seg.push_back(gangOperands.size() - crtOperandsSize);
3209 gangArgTypeAttributes.end());
3210 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3211 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3214 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3215 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3223 std::optional<mlir::ArrayAttr> gangArgTypes,
3224 std::optional<mlir::ArrayAttr> deviceTypes,
3225 std::optional<mlir::DenseI32ArrayAttr> segments,
3226 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3228 if (operands.begin() == operands.end() &&
3243 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3245 llvm::interleaveComma(
3246 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3247 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3248 (*gangArgTypes)[opIdx]);
3249 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3250 p << LoopOp::getGangNumKeyword();
3251 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3252 p << LoopOp::getGangDimKeyword();
3253 else if (gangArgTypeAttr.getValue() ==
3254 mlir::acc::GangArgType::Static)
3255 p << LoopOp::getGangStaticKeyword();
3256 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3267 std::optional<mlir::ArrayAttr> segments,
3268 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3271 for (
auto attr : *segments) {
3272 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3273 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3281static std::optional<mlir::acc::DeviceType>
3283 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3285 return std::nullopt;
3286 for (
auto attr : deviceTypes) {
3287 auto deviceTypeAttr =
3288 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3289 if (!deviceTypeAttr)
3290 return mlir::acc::DeviceType::None;
3291 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3292 return deviceTypeAttr.getValue();
3294 return std::nullopt;
3297LogicalResult acc::LoopOp::verify() {
3298 if (getUpperbound().size() != getStep().size())
3299 return emitError() <<
"number of upperbounds expected to be the same as "
3302 if (getUpperbound().size() != getLowerbound().size())
3303 return emitError() <<
"number of upperbounds expected to be the same as "
3304 "number of lowerbounds";
3306 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3307 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3308 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3309 <<
" as upperbound size";
3312 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3313 return emitOpError() <<
"collapse device_type attr must be define when"
3314 <<
" collapse attr is present";
3316 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3317 getCollapseAttr().getValue().size() !=
3318 getCollapseDeviceTypeAttr().getValue().size())
3319 return emitOpError() <<
"collapse attribute count must match collapse"
3320 <<
" device_type count";
3321 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3322 return emitOpError() <<
"duplicate device_type `"
3323 << acc::stringifyDeviceType(*duplicateDeviceType)
3324 <<
"` found in collapseDeviceType attribute";
3327 if (!getGangOperands().empty()) {
3328 if (!getGangOperandsArgType())
3329 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3330 <<
" when gang operands are present";
3332 if (getGangOperands().size() !=
3333 getGangOperandsArgTypeAttr().getValue().size())
3334 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3335 <<
" gangOperands count";
3337 if (getGangAttr()) {
3339 return emitOpError() <<
"duplicate device_type `"
3340 << acc::stringifyDeviceType(*duplicateDeviceType)
3341 <<
"` found in gang attribute";
3345 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3346 getGangOperandsDeviceTypeAttr(),
"gang")))
3351 return emitOpError() <<
"duplicate device_type `"
3352 << acc::stringifyDeviceType(*duplicateDeviceType)
3353 <<
"` found in worker attribute";
3354 if (
auto duplicateDeviceType =
3356 return emitOpError() <<
"duplicate device_type `"
3357 << acc::stringifyDeviceType(*duplicateDeviceType)
3358 <<
"` found in workerNumOperandsDeviceType attribute";
3360 getWorkerNumOperandsDeviceTypeAttr(),
3366 return emitOpError() <<
"duplicate device_type `"
3367 << acc::stringifyDeviceType(*duplicateDeviceType)
3368 <<
"` found in vector attribute";
3369 if (
auto duplicateDeviceType =
3371 return emitOpError() <<
"duplicate device_type `"
3372 << acc::stringifyDeviceType(*duplicateDeviceType)
3373 <<
"` found in vectorOperandsDeviceType attribute";
3375 getVectorOperandsDeviceTypeAttr(),
3380 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3381 getTileOperandsDeviceTypeAttr(),
"tile")))
3385 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3389 return emitError() <<
"only one of auto, independent, seq can be present "
3395 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3396 return attr.getValue() == mlir::acc::DeviceType::None;
3398 bool hasDefaultSeq =
3400 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3403 bool hasDefaultIndependent =
3404 getIndependentAttr()
3406 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3409 bool hasDefaultAuto =
3411 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3414 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3416 <<
"at least one of auto, independent, seq must be present";
3421 for (
auto attr : getSeqAttr()) {
3422 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3423 if (hasVector(deviceTypeAttr.getValue()) ||
3424 getVectorValue(deviceTypeAttr.getValue()) ||
3425 hasWorker(deviceTypeAttr.getValue()) ||
3426 getWorkerValue(deviceTypeAttr.getValue()) ||
3427 hasGang(deviceTypeAttr.getValue()) ||
3428 getGangValue(mlir::acc::GangArgType::Num,
3429 deviceTypeAttr.getValue()) ||
3430 getGangValue(mlir::acc::GangArgType::Dim,
3431 deviceTypeAttr.getValue()) ||
3432 getGangValue(mlir::acc::GangArgType::Static,
3433 deviceTypeAttr.getValue()))
3434 return emitError() <<
"gang, worker or vector cannot appear with seq";
3439 mlir::acc::PrivateRecipeOp>(
3440 *
this, getPrivateOperands(),
"private")))
3444 mlir::acc::FirstprivateRecipeOp>(
3445 *
this, getFirstprivateOperands(),
"firstprivate")))
3449 mlir::acc::ReductionRecipeOp>(
3450 *
this, getReductionOperands(),
"reduction")))
3453 if (getCombined().has_value() &&
3454 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3455 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3456 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3457 return emitError(
"unexpected combined constructs attribute");
3461 if (getRegion().empty())
3462 return emitError(
"expected non-empty body.");
3464 if (getUnstructured()) {
3465 if (!isContainerLike())
3467 "unstructured acc.loop must not have induction variables");
3468 }
else if (isContainerLike()) {
3472 uint64_t collapseCount = getCollapseValue().value_or(1);
3473 if (getCollapseAttr()) {
3474 for (
auto collapseEntry : getCollapseAttr()) {
3475 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3476 if (intAttr.getValue().getZExtValue() > collapseCount)
3477 collapseCount = intAttr.getValue().getZExtValue();
3485 bool foundSibling =
false;
3487 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3489 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3491 foundSibling =
true;
3496 expectedParent = op;
3499 if (collapseCount == 0)
3505 return emitError(
"found sibling loops inside container-like acc.loop");
3506 if (collapseCount != 0)
3507 return emitError(
"failed to find enough loop-like operations inside "
3508 "container-like acc.loop");
3514unsigned LoopOp::getNumDataOperands() {
3515 return getReductionOperands().size() + getPrivateOperands().size() +
3516 getFirstprivateOperands().size();
3519Value LoopOp::getDataOperand(
unsigned i) {
3520 unsigned numOptional =
3521 getLowerbound().size() + getUpperbound().size() + getStep().size();
3522 numOptional += getGangOperands().size();
3523 numOptional += getVectorOperands().size();
3524 numOptional += getWorkerNumOperands().size();
3525 numOptional += getTileOperands().size();
3526 numOptional += getCacheOperands().size();
3527 return getOperand(numOptional + i);
3530bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3532bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3536bool LoopOp::hasIndependent() {
3537 return hasIndependent(mlir::acc::DeviceType::None);
3540bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3544bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3546bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3551 return getVectorValue(mlir::acc::DeviceType::None);
3554mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3556 getVectorOperands(), deviceType);
3559bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3561bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3566 return getWorkerValue(mlir::acc::DeviceType::None);
3569mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3571 getWorkerNumOperands(), deviceType);
3574bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3576bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3581 return getTileValues(mlir::acc::DeviceType::None);
3585LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3587 getTileOperandsSegments(), deviceType);
3590std::optional<int64_t> LoopOp::getCollapseValue() {
3591 return getCollapseValue(mlir::acc::DeviceType::None);
3594std::optional<int64_t>
3595LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3596 if (!getCollapseAttr())
3597 return std::nullopt;
3598 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3600 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3601 return intAttr.getValue().getZExtValue();
3603 return std::nullopt;
3606mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3607 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3610mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3611 mlir::acc::DeviceType deviceType) {
3612 if (getGangOperands().empty())
3614 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3615 int32_t nbOperandsBefore = 0;
3616 for (
unsigned i = 0; i < *pos; ++i)
3617 nbOperandsBefore += (*getGangOperandsSegments())[i];
3620 .drop_front(nbOperandsBefore)
3621 .take_front((*getGangOperandsSegments())[*pos]);
3623 int32_t argTypeIdx = nbOperandsBefore;
3624 for (
auto value : values) {
3625 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3626 (*getGangOperandsArgType())[argTypeIdx]);
3627 if (gangArgTypeAttr.getValue() == gangArgType)
3635bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
3637bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
3642 return {&getRegion()};
3686 if (!regionArgs.empty()) {
3687 p << acc::LoopOp::getControlKeyword() <<
"(";
3688 llvm::interleaveComma(regionArgs, p,
3690 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
3691 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
3692 <<
" : " << stepType <<
") ";
3699 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
3700 effectiveDeviceTypes));
3703void acc::LoopOp::addIndependent(
3705 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
3706 context, getIndependentAttr(), effectiveDeviceTypes));
3711 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
3712 effectiveDeviceTypes));
3715void acc::LoopOp::setCollapseForDeviceTypes(
3717 llvm::APInt value) {
3721 assert((getCollapseAttr() ==
nullptr) ==
3722 (getCollapseDeviceTypeAttr() ==
nullptr));
3723 assert(value.getBitWidth() == 64);
3725 if (getCollapseAttr()) {
3726 for (
const auto &existing :
3727 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
3728 newValues.push_back(std::get<0>(existing));
3729 newDeviceTypes.push_back(std::get<1>(existing));
3733 if (effectiveDeviceTypes.empty()) {
3736 newValues.push_back(
3737 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3738 newDeviceTypes.push_back(
3739 acc::DeviceTypeAttr::get(context, DeviceType::None));
3741 for (DeviceType dt : effectiveDeviceTypes) {
3742 newValues.push_back(
3743 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3744 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
3748 setCollapseAttr(ArrayAttr::get(context, newValues));
3749 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
3752void acc::LoopOp::setTileForDeviceTypes(
3756 if (getTileOperandsSegments())
3757 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
3759 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3760 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3761 getTileOperandsMutable(), segments));
3763 setTileOperandsSegments(segments);
3766void acc::LoopOp::addVectorOperand(
3769 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3770 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
3771 newValue, getVectorOperandsMutable()));
3774void acc::LoopOp::addEmptyVector(
3776 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
3777 effectiveDeviceTypes));
3780void acc::LoopOp::addWorkerNumOperand(
3783 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3784 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
3785 newValue, getWorkerNumOperandsMutable()));
3788void acc::LoopOp::addEmptyWorker(
3790 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
3791 effectiveDeviceTypes));
3794void acc::LoopOp::addEmptyGang(
3796 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
3797 effectiveDeviceTypes));
3800bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
3801 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
3802 return attr.getValue() == dt;
3804 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
3805 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
3808 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
3810 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
3812 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
3818bool acc::LoopOp::hasDefaultGangWorkerVector() {
3819 return hasAnyGangWorkerVector(DeviceType::None);
3822bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
3823 return hasVector(deviceType) || getVectorValue(deviceType) ||
3824 hasWorker(deviceType) || getWorkerValue(deviceType) ||
3825 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
3826 getGangValue(GangArgType::Dim, deviceType) ||
3827 getGangValue(GangArgType::Static, deviceType);
3831acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
3832 if (hasSeq(deviceType))
3833 return LoopParMode::loop_seq;
3834 if (hasAuto(deviceType))
3835 return LoopParMode::loop_auto;
3836 if (hasIndependent(deviceType))
3837 return LoopParMode::loop_independent;
3839 return LoopParMode::loop_seq;
3841 return LoopParMode::loop_auto;
3842 assert(hasIndependent() &&
3843 "loop must have default auto, seq, or independent");
3844 return LoopParMode::loop_independent;
3847void acc::LoopOp::addGangOperands(
3852 getGangOperandsSegments())
3853 llvm::copy(*existingSegments, std::back_inserter(segments));
3855 unsigned beforeCount = segments.size();
3857 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3858 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3859 getGangOperandsMutable(), segments));
3861 setGangOperandsSegments(segments);
3868 unsigned numAdded = segments.size() - beforeCount;
3872 if (getGangOperandsArgTypeAttr())
3873 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
3875 for (
auto i : llvm::index_range(0u, numAdded)) {
3876 llvm::transform(argTypes, std::back_inserter(gangTypes),
3877 [=](mlir::acc::GangArgType gangTy) {
3878 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
3883 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
3887void acc::LoopOp::addPrivatization(
MLIRContext *context,
3888 mlir::acc::PrivateOp op,
3889 mlir::acc::PrivateRecipeOp recipe) {
3890 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3891 getPrivateOperandsMutable().append(op.getResult());
3894void acc::LoopOp::addFirstPrivatization(
3895 MLIRContext *context, mlir::acc::FirstprivateOp op,
3896 mlir::acc::FirstprivateRecipeOp recipe) {
3897 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3898 getFirstprivateOperandsMutable().append(op.getResult());
3901void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
3902 mlir::acc::ReductionRecipeOp recipe) {
3903 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3904 getReductionOperandsMutable().append(op.getResult());
3911LogicalResult acc::DataOp::verify() {
3916 return emitError(
"at least one operand or the default attribute "
3917 "must appear on the data operation");
3919 for (
mlir::Value operand : getDataClauseOperands())
3920 if (isa<BlockArgument>(operand) ||
3921 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
3922 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
3923 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
3924 acc::MapInfoOp>(operand.getDefiningOp()))
3925 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
3934unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
3936Value DataOp::getDataOperand(
unsigned i) {
3937 unsigned numOptional = getIfCond() ? 1 : 0;
3939 numOptional += getWaitOperands().size();
3940 return getOperand(numOptional + i);
3943bool acc::DataOp::hasAsyncOnly() {
3944 return hasAsyncOnly(mlir::acc::DeviceType::None);
3947bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3952 return getAsyncValue(mlir::acc::DeviceType::None);
3955mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3960bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
3962bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3967 return getWaitValues(mlir::acc::DeviceType::None);
3971DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3973 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3974 getHasWaitDevnum(), deviceType);
3978 return getWaitDevnum(mlir::acc::DeviceType::None);
3981mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3983 getWaitOperandsSegments(), getHasWaitDevnum(),
3987void acc::DataOp::addAsyncOnly(
3989 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3990 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3993void acc::DataOp::addAsyncOperand(
3996 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3997 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3998 getAsyncOperandsMutable()));
4001void acc::DataOp::addWaitOnly(
MLIRContext *context,
4003 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4004 effectiveDeviceTypes));
4007void acc::DataOp::addWaitOperands(
4012 if (getWaitOperandsSegments())
4013 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4015 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4016 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4017 getWaitOperandsMutable(), segments));
4018 setWaitOperandsSegments(segments);
4021 if (getHasWaitDevnumAttr())
4022 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4025 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4027 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4034LogicalResult acc::ExitDataOp::verify() {
4038 if (getDataClauseOperands().empty())
4039 return emitError(
"at least one operand must be present in dataOperands on "
4040 "the exit data operation");
4044 if (getAsyncOperand() && getAsync())
4045 return emitError(
"async attribute cannot appear with asyncOperand");
4049 if (!getWaitOperands().empty() && getWait())
4050 return emitError(
"wait attribute cannot appear with waitOperands");
4052 if (getWaitDevnum() && getWaitOperands().empty())
4053 return emitError(
"wait_devnum cannot appear without waitOperands");
4058unsigned ExitDataOp::getNumDataOperands() {
4059 return getDataClauseOperands().size();
4062Value ExitDataOp::getDataOperand(
unsigned i) {
4063 unsigned numOptional = getIfCond() ? 1 : 0;
4064 numOptional += getAsyncOperand() ? 1 : 0;
4065 numOptional += getWaitDevnum() ? 1 : 0;
4066 return getOperand(getWaitOperands().size() + numOptional + i);
4071 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4074void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4076 assert(effectiveDeviceTypes.empty());
4077 assert(!getAsyncAttr());
4078 assert(!getAsyncOperand());
4080 setAsyncAttr(mlir::UnitAttr::get(context));
4083void ExitDataOp::addAsyncOperand(
4086 assert(effectiveDeviceTypes.empty());
4087 assert(!getAsyncAttr());
4088 assert(!getAsyncOperand());
4090 getAsyncOperandMutable().append(newValue);
4095 assert(effectiveDeviceTypes.empty());
4100 setWaitAttr(mlir::UnitAttr::get(context));
4102 getWaitDevnumMutable().clear();
4103 getWaitOperandsMutable().clear();
4106void ExitDataOp::addWaitOperands(
4109 assert(effectiveDeviceTypes.empty());
4118 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4123 getWaitDevnumMutable().append(newValues.front());
4124 newValues = newValues.drop_front();
4127 getWaitOperandsMutable().append(newValues);
4134LogicalResult acc::EnterDataOp::verify() {
4138 if (getDataClauseOperands().empty())
4139 return emitError(
"at least one operand must be present in dataOperands on "
4140 "the enter data operation");
4144 if (getAsyncOperand() && getAsync())
4145 return emitError(
"async attribute cannot appear with asyncOperand");
4149 if (!getWaitOperands().empty() && getWait())
4150 return emitError(
"wait attribute cannot appear with waitOperands");
4152 if (getWaitDevnum() && getWaitOperands().empty())
4153 return emitError(
"wait_devnum cannot appear without waitOperands");
4155 for (
mlir::Value operand : getDataClauseOperands())
4156 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp, acc::MapInfoOp>(
4157 operand.getDefiningOp()))
4158 return emitError(
"expect data entry operation as defining op");
4163unsigned EnterDataOp::getNumDataOperands() {
4164 return getDataClauseOperands().size();
4167Value EnterDataOp::getDataOperand(
unsigned i) {
4168 unsigned numOptional = getIfCond() ? 1 : 0;
4169 numOptional += getAsyncOperand() ? 1 : 0;
4170 numOptional += getWaitDevnum() ? 1 : 0;
4171 return getOperand(getWaitOperands().size() + numOptional + i);
4176 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4179void EnterDataOp::addAsyncOnly(
4181 assert(effectiveDeviceTypes.empty());
4182 assert(!getAsyncAttr());
4183 assert(!getAsyncOperand());
4185 setAsyncAttr(mlir::UnitAttr::get(context));
4188void EnterDataOp::addAsyncOperand(
4191 assert(effectiveDeviceTypes.empty());
4192 assert(!getAsyncAttr());
4193 assert(!getAsyncOperand());
4195 getAsyncOperandMutable().append(newValue);
4198void EnterDataOp::addWaitOnly(
MLIRContext *context,
4200 assert(effectiveDeviceTypes.empty());
4205 setWaitAttr(mlir::UnitAttr::get(context));
4207 getWaitDevnumMutable().clear();
4208 getWaitOperandsMutable().clear();
4211void EnterDataOp::addWaitOperands(
4214 assert(effectiveDeviceTypes.empty());
4223 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4228 getWaitDevnumMutable().append(newValues.front());
4229 newValues = newValues.drop_front();
4232 getWaitOperandsMutable().append(newValues);
4239LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4245LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4251LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4258 if (
Value writeVal = op.getWriteOpVal()) {
4267LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4269LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4275AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4276 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4278 return dyn_cast<AtomicReadOp>(getSecondOp());
4281AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4282 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4284 return dyn_cast<AtomicWriteOp>(getSecondOp());
4287AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4288 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4290 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4293LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4299template <
typename Op>
4302 bool requireAtLeastOneOperand =
true) {
4303 if (operands.empty() && requireAtLeastOneOperand)
4306 "at least one operand must appear on the declare operation");
4309 if (isa<BlockArgument>(operand) ||
4310 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4311 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4312 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp,
4313 acc::MapInfoOp>(operand.getDefiningOp()))
4315 "expect valid declare data entry operation or acc.getdeviceptr "
4319 assert(var &&
"declare operands can only be data entry operations which "
4323 if (!mlir::isa<acc::MapInfoOp>(operand.getDefiningOp())) {
4324 std::optional<mlir::acc::DataClause> dataClauseOptional{
4326 assert(dataClauseOptional.has_value() &&
4327 "declare operands can only be data entry operations which must "
4329 (
void)dataClauseOptional;
4336LogicalResult acc::DeclareEnterOp::verify() {
4344LogicalResult acc::DeclareExitOp::verify() {
4355LogicalResult acc::DeclareOp::verify() {
4364 acc::DeviceType dtype) {
4365 unsigned parallelism = 0;
4366 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4367 parallelism += op.hasWorker(dtype) ? 1 : 0;
4368 parallelism += op.hasVector(dtype) ? 1 : 0;
4369 parallelism += op.hasSeq(dtype) ? 1 : 0;
4373LogicalResult acc::RoutineOp::verify() {
4374 unsigned baseParallelism =
4377 if (baseParallelism > 1)
4378 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4379 "be present at the same time";
4381 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4383 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4384 if (dtype == acc::DeviceType::None)
4388 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4389 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4390 "be present at the same time for device_type `"
4391 << acc::stringifyDeviceType(dtype) <<
"`";
4398 mlir::ArrayAttr &bindIdName,
4399 mlir::ArrayAttr &bindStrName,
4400 mlir::ArrayAttr &deviceIdTypes,
4401 mlir::ArrayAttr &deviceStrTypes) {
4408 llvm::SMLoc attrLoc = parser.getCurrentLocation();
4409 mlir::Attribute newAttr;
4410 bool isSymbolRefAttr;
4411 if (parser.parseAttribute(newAttr))
4413 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4414 bindIdNameAttrs.push_back(symbolRefAttr);
4415 isSymbolRefAttr = true;
4416 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4417 bindStrNameAttrs.push_back(stringAttr);
4418 isSymbolRefAttr =
false;
4421 "expected symbol reference or string attribute");
4425 if (isSymbolRefAttr) {
4426 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4427 parser.getContext(), mlir::acc::DeviceType::None));
4429 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4430 parser.getContext(), mlir::acc::DeviceType::None));
4433 if (isSymbolRefAttr) {
4434 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4435 parser.parseRSquare())
4438 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4439 parser.parseRSquare())
4447 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4448 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4449 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4450 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4456 std::optional<mlir::ArrayAttr> bindIdName,
4457 std::optional<mlir::ArrayAttr> bindStrName,
4458 std::optional<mlir::ArrayAttr> deviceIdTypes,
4459 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4466 allBindNames.append(bindIdName->begin(), bindIdName->end());
4467 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4472 allBindNames.append(bindStrName->begin(), bindStrName->end());
4473 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4477 if (!allBindNames.empty())
4478 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4479 [&](
const auto &pair) {
4480 p << std::get<0>(pair);
4486 mlir::ArrayAttr &gang,
4487 mlir::ArrayAttr &gangDim,
4488 mlir::ArrayAttr &gangDimDeviceTypes) {
4491 gangDimDeviceTypeAttrs;
4492 bool needCommaBeforeOperands =
false;
4496 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4497 parser.
getContext(), mlir::acc::DeviceType::None));
4498 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4505 if (parser.parseAttribute(gangAttrs.emplace_back()))
4512 needCommaBeforeOperands =
true;
4515 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4519 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4520 parser.parseColon() ||
4521 parser.parseAttribute(gangDimAttrs.emplace_back()))
4523 if (succeeded(parser.parseOptionalLSquare())) {
4524 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4525 parser.parseRSquare())
4528 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4529 parser.getContext(), mlir::acc::DeviceType::None));
4535 if (
failed(parser.parseRParen()))
4538 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4539 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4540 gangDimDeviceTypes =
4541 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4547 std::optional<mlir::ArrayAttr> gang,
4548 std::optional<mlir::ArrayAttr> gangDim,
4549 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4552 gang->size() == 1) {
4553 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4554 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4566 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4567 [&](
const auto &pair) {
4568 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4569 p << std::get<0>(pair);
4577 mlir::ArrayAttr &deviceTypes) {
4581 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4582 parser.
getContext(), mlir::acc::DeviceType::None));
4583 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4590 if (parser.parseAttribute(attributes.emplace_back()))
4598 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4604 std::optional<mlir::ArrayAttr> deviceTypes) {
4607 auto deviceTypeAttr =
4608 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4609 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4618 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4624bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4626bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4630bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4632bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4636bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4638bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4642std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4643RoutineOp::getBindNameValue() {
4644 return getBindNameValue(mlir::acc::DeviceType::None);
4647std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4648RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4650 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4651 auto attr = (*getBindIdName())[*pos];
4652 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4653 assert(symbolRefAttr &&
"expected SymbolRef");
4654 return symbolRefAttr;
4659 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
4660 auto attr = (*getBindStrName())[*pos];
4661 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
4662 assert(stringAttr &&
"expected String");
4667 return std::nullopt;
4670std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4671RoutineOp::getEffectiveBindName(mlir::acc::DeviceType targetDeviceType) {
4672 assert(targetDeviceType != DeviceType::Star &&
4673 "expected a valid target device type");
4675 if (!getBindIdName() && !getBindStrName())
4676 return std::nullopt;
4679 if (targetDeviceType == DeviceType::None)
4680 return getBindNameValue();
4683 if (
auto bindName = getBindNameValue(targetDeviceType))
4688 bool hasNamedDeviceType = hasGang(targetDeviceType) ||
4689 getGangDimValue(targetDeviceType).has_value() ||
4690 hasWorker(targetDeviceType) ||
4691 hasVector(targetDeviceType) ||
4692 hasSeq(targetDeviceType);
4693 if (!hasNamedDeviceType) {
4694 if (
auto bindName = getBindNameValue(DeviceType::Star))
4698 return getBindNameValue();
4701bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4703bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
4707std::optional<int64_t> RoutineOp::getGangDimValue() {
4708 return getGangDimValue(mlir::acc::DeviceType::None);
4711std::optional<int64_t>
4712RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
4714 return std::nullopt;
4715 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
4716 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
4717 return intAttr.getInt();
4719 return std::nullopt;
4724 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4725 effectiveDeviceTypes));
4730 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4731 effectiveDeviceTypes));
4736 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4737 effectiveDeviceTypes));
4742 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4743 effectiveDeviceTypes));
4752 if (getGangDimAttr())
4753 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
4754 if (getGangDimDeviceTypeAttr())
4755 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
4757 assert(dimValues.size() == deviceTypes.size());
4759 if (effectiveDeviceTypes.empty()) {
4760 dimValues.push_back(
4761 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4762 deviceTypes.push_back(
4763 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
4765 for (DeviceType dt : effectiveDeviceTypes) {
4766 dimValues.push_back(
4767 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4768 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4771 assert(dimValues.size() == deviceTypes.size());
4773 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
4774 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
4777void RoutineOp::addBindStrName(
MLIRContext *context,
4779 mlir::StringAttr val) {
4780 unsigned before = getBindStrNameDeviceTypeAttr()
4781 ? getBindStrNameDeviceTypeAttr().size()
4784 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4785 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
4786 unsigned after = getBindStrNameDeviceTypeAttr().size();
4789 if (getBindStrNameAttr())
4790 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
4791 for (
unsigned i = 0; i < after - before; ++i)
4792 vals.push_back(val);
4794 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
4797void RoutineOp::addBindIDName(
MLIRContext *context,
4799 mlir::SymbolRefAttr val) {
4801 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
4803 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4804 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
4805 unsigned after = getBindIdNameDeviceTypeAttr().size();
4808 if (getBindIdNameAttr())
4809 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
4810 for (
unsigned i = 0; i < after - before; ++i)
4811 vals.push_back(val);
4813 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
4820LogicalResult acc::InitOp::verify() {
4821 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4822 return emitOpError(
"cannot be nested in a compute operation");
4826void acc::InitOp::addDeviceType(
MLIRContext *context,
4827 mlir::acc::DeviceType deviceType) {
4829 if (getDeviceTypesAttr())
4830 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
4832 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
4833 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
4840LogicalResult acc::ShutdownOp::verify() {
4841 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4842 return emitOpError(
"cannot be nested in a compute operation");
4846void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
4847 mlir::acc::DeviceType deviceType) {
4849 if (getDeviceTypesAttr())
4850 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
4852 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
4853 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
4860LogicalResult acc::SetOp::verify() {
4861 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4862 return emitOpError(
"cannot be nested in a compute operation");
4863 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
4864 return emitOpError(
"at least one default_async, device_num, or device_type "
4865 "operand must appear");
4873LogicalResult acc::UpdateOp::verify() {
4875 if (getDataClauseOperands().empty())
4876 return emitError(
"at least one value must be present in dataOperands");
4879 getAsyncOperandsDeviceTypeAttr(),
4884 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
4885 getWaitOperandsDeviceTypeAttr(),
"wait")))
4891 for (
mlir::Value operand : getDataClauseOperands())
4892 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp,
4893 acc::MapInfoOp>(operand.getDefiningOp()))
4894 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4900unsigned UpdateOp::getNumDataOperands() {
4901 return getDataClauseOperands().size();
4904Value UpdateOp::getDataOperand(
unsigned i) {
4906 numOptional += getIfCond() ? 1 : 0;
4907 return getOperand(getWaitOperands().size() + numOptional + i);
4912 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
4915bool UpdateOp::hasAsyncOnly() {
4916 return hasAsyncOnly(mlir::acc::DeviceType::None);
4919bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4924 return getAsyncValue(mlir::acc::DeviceType::None);
4927mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4937bool UpdateOp::hasWaitOnly() {
4938 return hasWaitOnly(mlir::acc::DeviceType::None);
4941bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4946 return getWaitValues(mlir::acc::DeviceType::None);
4950UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4952 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4953 getHasWaitDevnum(), deviceType);
4957 return getWaitDevnum(mlir::acc::DeviceType::None);
4960mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4962 getWaitOperandsSegments(), getHasWaitDevnum(),
4968 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4969 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4972void UpdateOp::addAsyncOperand(
4975 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4976 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4977 getAsyncOperandsMutable()));
4982 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4983 effectiveDeviceTypes));
4986void UpdateOp::addWaitOperands(
4991 if (getWaitOperandsSegments())
4992 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4994 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4995 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4996 getWaitOperandsMutable(), segments));
4997 setWaitOperandsSegments(segments);
5000 if (getHasWaitDevnumAttr())
5001 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5004 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5006 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5013LogicalResult acc::WaitOp::verify() {
5016 if (getAsyncOperand() && getAsync())
5017 return emitError(
"async attribute cannot appear with asyncOperand");
5019 if (getWaitDevnum() && getWaitOperands().empty())
5020 return emitError(
"wait_devnum cannot appear without waitOperands");
5025#define GET_OP_CLASSES
5026#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5028#define GET_ATTRDEF_CLASSES
5029#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5031#define GET_TYPEDEF_CLASSES
5032#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5043 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5044 [&](
auto entry) {
return entry.getVarPtr(); })
5045 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5046 [&](
auto exit) {
return exit.getVarPtr(); })
5056 [&](
auto entry) {
return entry.getVar(); })
5064 [&](
auto entry) {
return entry.getVarType(); })
5065 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5066 [&](
auto exit) {
return exit.getVarType(); })
5077 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5078 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5089 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5098 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5108 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5109 [&](
auto dataClause) {
5111 dataClause.getBounds().begin(),
5112 dataClause.getBounds().end());
5124 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5126 dataClause.getAsyncOperands().begin(),
5127 dataClause.getAsyncOperands().end());
5138 return dataClause.getAsyncOperandsDeviceTypeAttr();
5146 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5153 if (deviceType != DeviceType::None && deviceType != DeviceType::Star)
5154 deviceTypes.push_back(deviceType);
5155 deviceTypes.push_back(DeviceType::Star);
5156 deviceTypes.push_back(DeviceType::None);
5163 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5164 [&](
auto entry) {
return entry.getName(); })
5171std::optional<mlir::acc::DataClause>
5176 .Case<ACC_DATA_ENTRY_OPS>(
5177 [&](
auto entry) {
return entry.getDataClause(); })
5183 return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(op);
5189 .Case<mlir::acc::MapInfoOp>([&](
auto mapInfo) {
5190 return bitEnumContainsAny(mapInfo.getMapFlags(),
5191 mlir::acc::MapFlags::implicit);
5199 [&](
auto dataClause) {
return dataClause.getSynthetic(); })
5207 mlir::acc::KernelEnvironmentOp>(
5208 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5210 return dataOperands;
5218 mlir::acc::KernelEnvironmentOp>(
5219 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5221 return dataOperands;
5228 [&](
auto entry) {
return entry.getRecipeAttr(); })
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
static void printSourceLocation(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::LocationAttr locAttr)
void printRoutineGangClause(OpAsmPrinter &p, Operation *op, std::optional< mlir::ArrayAttr > gang, std::optional< mlir::ArrayAttr > gangDim, std::optional< mlir::ArrayAttr > gangDimDeviceTypes)
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)
static ParseResult parseArrayAttr(mlir::OpAsmParser &parser, mlir::ArrayAttr &attr)
static ParseResult parseBindName(OpAsmParser &parser, mlir::ArrayAttr &bindIdName, mlir::ArrayAttr &bindStrName, mlir::ArrayAttr &deviceIdTypes, mlir::ArrayAttr &deviceStrTypes)
static void printRecipeSym(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::SymbolRefAttr recipeAttr)
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 printArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::ArrayAttr attr)
static bool hasOnlyDeviceTypeNone(std::optional< mlir::ArrayAttr > attrs)
static ParseResult parseRecipeSym(mlir::OpAsmParser &parser, mlir::SymbolRefAttr &recipeAttr)
static void printAccVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value accVar, mlir::Type accVarType)
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 bool hasAnyGangWorkerVectorForDeviceType(std::optional< mlir::ArrayAttr > numGangsDeviceType, mlir::Operation::operand_range numGangs, std::optional< llvm::ArrayRef< int32_t > > numGangsSegments, std::optional< mlir::ArrayAttr > numWorkersDeviceType, mlir::Operation::operand_range numWorkers, std::optional< mlir::ArrayAttr > vectorLengthDeviceType, mlir::Operation::operand_range vectorLength, mlir::acc::DeviceType deviceType)
static void printVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value var)
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 BodyExecution getBodyExecution(LoopOp loopOp)
Prove whether the body of loopOp runs.
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 std::optional< mlir::acc::DeviceType > checkDeviceTypes(mlir::ArrayAttr deviceTypes)
Check for duplicates in the DeviceType array attribute.
static LogicalResult checkDeclareOperands(Op &op, const mlir::ValueRange &operands, bool requireAtLeastOneOperand=true)
static LogicalResult checkVarAndAccVar(Op op)
static ParseResult parseOperandsWithKeywordOnly(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::UnitAttr &attr)
static void printDeviceTypes(mlir::OpAsmPrinter &p, std::optional< mlir::ArrayAttr > deviceTypes)
static LogicalResult checkVarAndVarType(Op op)
static LogicalResult checkValidModifier(Op op, acc::DataClauseModifier validModifiers)
static void addOperandEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, MutableOperandRange operand)
Helper to add an effect on an operand, referenced by its mutable range.
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 void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
static LogicalResult checkNoModifier(Op op)
static ParseResult parseAccVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var, mlir::Type &accVarType)
static std::optional< unsigned > findSegment(ArrayAttr segments, mlir::acc::DeviceType deviceType)
static ParseResult parseDenseBoolArrayAttr(mlir::OpAsmParser &parser, mlir::DenseBoolArrayAttr &attr)
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)
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 ParseResult parseVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var)
void printLoopControl(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lowerbound, TypeRange lowerboundType, ValueRange upperbound, TypeRange upperboundType, ValueRange steps, TypeRange stepType)
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
static void printDenseBoolArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::DenseBoolArrayAttr attr)
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 printOperandWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::Value > operand, mlir::Type operandType, mlir::UnitAttr attr)
static ParseResult parseSourceLocation(mlir::OpAsmParser &parser, mlir::LocationAttr &locAttr)
static ParseResult parseDeviceTypeOperandsWithSegment(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
static bool isEnclosedIntoComputeOp(mlir::Operation *op)
static ParseResult parseOperandWithKeywordOnly(mlir::OpAsmParser &parser, std::optional< OpAsmParser::UnresolvedOperand > &operand, mlir::Type &operandType, mlir::UnitAttr &attr)
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 printOperandsWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, mlir::UnitAttr attr)
static void printSingleDeviceType(mlir::OpAsmPrinter &p, mlir::Attribute attr)
static LogicalResult checkRecipe(OpT op, llvm::StringRef operandName)
static LogicalResult checkPrivateOperands(mlir::Operation *accConstructOp, const mlir::ValueRange &operands, llvm::StringRef operandName)
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 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)
BodyExecution
Whether the body of a structured acc.loop is proven to run.
@ Always
The body runs at least once, so the parent cannot bypass the region.
@ Never
The body never runs, so the parent cannot enter the region.
@ Maybe
Neither could be proven, so the parent may do either.
static void printCombinedConstructsLoop(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::acc::CombinedConstructsTypeAttr attr)
static void printBindName(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > bindIdName, std::optional< mlir::ArrayAttr > bindStrName, std::optional< mlir::ArrayAttr > deviceIdTypes, std::optional< mlir::ArrayAttr > deviceStrTypes)
static LogicalResult verifyYield(linalg::YieldOp op, LinalgOp linalgOp)
false
Parses a map_entries map type from a string format back into its numeric value.
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 parseOptionalRParen()=0
Parse a ) token if present.
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)
virtual void printAttribute(Attribute attr)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
static BoolAttr get(MLIRContext *context, bool value)
This is a utility class for mapping one set of IR entities to another.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
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.
void append(ValueRange values)
Append the given values to the range.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region ®ion, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
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.
virtual void printOperand(Value value)=0
Print implementations for various things an operation contains.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
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.
OperandRange operand_range
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
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 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.
iterator_range< OpIterator > getOps()
bool hasOneBlock()
Return true if this region has exactly one block.
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.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
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()
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
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 WalkResult advance()
static WalkResult interrupt()
Base attribute class for language-specific variable information carried through the OpenACC type inte...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
ArrayRef< T > asArrayRef() const
#define ACC_COMPUTE_CONSTRUCT_OPS
#define ACC_COMPUTE_AND_DATA_CONSTRUCT_OPS
#define ACC_DATA_CLAUSE_OPS
#define ACC_DATA_ENTRY_OPS
#define ACC_DATA_EXIT_OPS
SmallVector< DeviceType, 3 > getDeviceTypesByPrecedence(DeviceType deviceType)
The clauses of a construct can be given once per device type.
bool getSyntheticFlag(mlir::Operation *accDataClauseOp)
Used to find out whether the implementation created the data operation for its own bookkeeping,...
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.
mlir::TypedValue< mlir::acc::PointerLikeType > getAccPtr(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation if it implements PointerLikeType.
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.
bool isDataEntryOp(mlir::Operation *op)
Used to find out whether op is a data entry operation or an acc.map_info.
std::optional< ClauseDefaultValue > getDefaultAttr(mlir::Operation *op)
Looks for an OpenACC default attribute on the current operation op or in a parent operation which enc...
bool hasWaitDevnum(OpTy op, DeviceType deviceType)
Returns whether the wait clause op gives for deviceType carries a devnum modifier,...
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 isGangWorkerVectorAllOne(ComputeOpT op)
bool getImplicitFlag(mlir::Operation *accDataEntryOp)
Used to find out whether data operation is implicit.
mlir::SymbolRefAttr getRecipe(mlir::Operation *accOp)
Used to get the recipe attribute from a data clause operation.
mlir::SmallVector< mlir::Value > getAsyncOperands(mlir::Operation *accDataClauseOp)
Used to obtain async operands from an acc data clause operation.
bool isMappableType(mlir::Type type)
Used to check whether the provided type implements the MappableType interface.
mlir::Value getVarPtrPtr(mlir::Operation *accDataClauseOp)
Used to obtain the varPtrPtr 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,...
mlir::Type getVarType(mlir::Operation *accDataClauseOp)
Used to obtains the varType from a data clause operation which records the type of variable.
mlir::TypedValue< mlir::acc::PointerLikeType > getVarPtr(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation if it implements PointerLikeType.
mlir::ArrayAttr getAsyncOperandsDeviceType(mlir::Operation *accDataClauseOp)
Returns an array of acc:DeviceTypeAttr attributes attached to an acc data clause operation,...
Value genCast(OpBuilder &builder, Location loc, Value value, Type dstTy)
Add type casting between arith and index types when needed.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
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.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
detail::DenseArrayAttrImpl< bool > DenseBoolArrayAttr
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
This is the representation of an operand reference.
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.