23#include "llvm/ADT/SmallSet.h"
24#include "llvm/ADT/TypeSwitch.h"
25#include "llvm/Support/LogicalResult.h"
31#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
32#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
33#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
34#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
35#include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
38struct PrivateTypePointerLikeModel
39 :
public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
42 return cast<PrivateType>(type).getBaseTy();
45 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
46 Type resultType)
const {
47 if (value.
getType() == resultType)
49 if (!isa<PointerLikeType>(resultType))
51 return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
54 MemRefType getAsMemRefType(Type type, ModuleOp module)
const {
55 Type baseTy = cast<PrivateType>(type).getBaseTy();
56 if (
auto memrefTy = dyn_cast<MemRefType>(baseTy))
58 if (
auto ptrLikeTy = dyn_cast<PointerLikeType>(baseTy))
59 return ptrLikeTy.getAsMemRefType(module);
68mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
69 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
72 if (existingDeviceTypes)
73 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
75 if (newDeviceTypes.empty())
76 deviceTypes.push_back(
77 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
79 for (DeviceType dt : newDeviceTypes)
80 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
82 return mlir::ArrayAttr::get(context, deviceTypes);
91mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
92 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
97 if (existingDeviceTypes)
98 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
100 if (newDeviceTypes.empty()) {
101 argCollection.
append(arguments);
102 segments.push_back(arguments.size());
103 deviceTypes.push_back(
104 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
107 for (DeviceType dt : newDeviceTypes) {
108 argCollection.
append(arguments);
109 segments.push_back(arguments.size());
110 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
113 return mlir::ArrayAttr::get(context, deviceTypes);
117mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
118 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
122 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
123 newDeviceTypes, arguments,
124 argCollection, segments);
132void OpenACCDialect::initialize() {
135#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
138#define GET_ATTRDEF_LIST
139#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
142#define GET_TYPEDEF_LIST
143#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
146 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
183void ParallelOp::getSuccessorRegions(
213void HostDataOp::getSuccessorRegions(
241 if (loopOp.isContainerLike())
251 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
258 if (!lb || !
ub || !step || *step == 0) {
267 std::optional<ArrayRef<bool>> inclusiveUbs =
268 loopOp.getInclusiveUpperbound();
269 bool inclusiveUb = inclusiveUbs && (*inclusiveUbs)[i];
270 assert(*step != 0 &&
"zero step should have been filtered out");
271 bool runsOnce = *step > 0 ? (inclusiveUb ? *lb <= *
ub : *lb < *
ub)
272 : (inclusiveUb ? *lb >= *
ub : *lb > *
ub);
290 if (getUnstructured()) {
337 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
341 mlir::acc::DeviceType deviceType) {
345 for (
auto attr : *arrayAttr) {
346 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
347 if (deviceTypeAttr.getValue() == deviceType)
355 std::optional<mlir::ArrayAttr> deviceTypes) {
360 llvm::interleaveComma(*deviceTypes, p,
366 mlir::acc::DeviceType deviceType) {
367 unsigned segmentIdx = 0;
368 for (
auto attr : segments) {
369 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
370 if (deviceTypeAttr.getValue() == deviceType)
371 return std::make_optional(segmentIdx);
381 mlir::acc::DeviceType deviceType) {
383 return range.take_front(0);
384 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
385 int32_t nbOperandsBefore = 0;
386 for (
unsigned i = 0; i < *pos; ++i)
387 nbOperandsBefore += (*segments)[i];
388 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
390 return range.take_front(0);
398 mlir::acc::DeviceType deviceType) {
401 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
403 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
404 if (boolAttr && boolAttr.getValue())
418 mlir::acc::DeviceType deviceType) {
423 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
425 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
426 if (boolAttr.getValue())
427 return range.drop_front(1);
433template <
typename Op>
435 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
437 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
442 op.hasAsyncOnly(dtype))
444 "asyncOnly attribute cannot appear with asyncOperand");
449 op.hasWaitOnly(dtype))
450 return op.
emitError(
"wait attribute cannot appear with waitOperands");
455template <
typename Op>
458 return op.
emitError(
"must have var operand");
461 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
462 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
463 return op.
emitError(
"var must be mappable or pointer-like");
466 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
467 op.getVarType() == op.getVar().getType())
468 return op.
emitError(
"varType must capture the element type of var");
473template <
typename Op>
475 if (op.getVar().getType() != op.getAccVar().getType())
476 return op.
emitError(
"input and output types must match");
481template <
typename Op>
483 if (op.getModifiers() != acc::DataClauseModifier::none)
484 return op.
emitError(
"no data clause modifiers are allowed");
488template <
typename Op>
491 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
493 "invalid data clause modifiers: " +
494 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
499template <
typename OpT,
typename RecipeOpT>
500static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
505 !std::is_same_v<OpT, acc::ReductionOp>)
508 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
510 return op->emitOpError() <<
"recipe expected for " << operandName;
515 return op->emitOpError()
516 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
517 << operandName <<
" declaration";
538 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
559 if (failed(parser.
parseType(accVarType)))
569 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
581 mlir::TypeAttr &varTypeAttr) {
582 if (failed(parser.
parseType(varPtrType)))
593 varTypeAttr = mlir::TypeAttr::get(varType);
598 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
599 Type elementType = ptrTy.getElementType();
602 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
604 varTypeAttr = mlir::TypeAttr::get(varPtrType);
612 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
620 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
621 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
625 if (!typeToCheckAgainst)
626 typeToCheckAgainst = varPtrType;
627 if (typeToCheckAgainst != varType) {
643 locAttr = mlir::dyn_cast<mlir::LocationAttr>(attr);
645 return parser.
emitError(attrLoc,
"expected location attribute");
655 mlir::SymbolRefAttr &recipeAttr) {
662 mlir::SymbolRefAttr recipeAttr) {
677 mlir::ArrayAttr &attr) {
682 mlir::ArrayAttr attr) {
689LogicalResult acc::DataBoundsOp::verify() {
690 auto extent = getExtent();
691 auto upperbound = getUpperbound();
692 if (!extent && !upperbound)
693 return emitError(
"expected extent or upperbound.");
700LogicalResult acc::PrivateOp::verify() {
703 "data clause associated with private operation must match its intent");
717LogicalResult acc::FirstprivateOp::verify() {
719 return emitError(
"data clause associated with firstprivate operation must "
726 *
this,
"firstprivate")))
734LogicalResult acc::ReductionOp::verify() {
736 return emitError(
"data clause associated with reduction operation must "
743 *
this,
"reduction")))
751LogicalResult acc::DevicePtrOp::verify() {
753 return emitError(
"data clause associated with deviceptr operation must "
767LogicalResult acc::PresentOp::verify() {
770 "data clause associated with present operation must match its intent");
783LogicalResult acc::CopyinOp::verify() {
785 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
790 "data clause associated with copyin operation must match its intent"
791 " or specify original clause this operation was decomposed from");
797 acc::DataClauseModifier::always |
798 acc::DataClauseModifier::capture)))
803bool acc::CopyinOp::isCopyinReadonly() {
804 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
805 acc::bitEnumContainsAny(getModifiers(),
806 acc::DataClauseModifier::readonly);
812LogicalResult acc::CreateOp::verify() {
819 "data clause associated with create operation must match its intent"
820 " or specify original clause this operation was decomposed from");
828 acc::DataClauseModifier::always |
829 acc::DataClauseModifier::capture)))
834bool acc::CreateOp::isCreateZero() {
836 return getDataClause() == acc::DataClause::acc_create_zero ||
838 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
844LogicalResult acc::NoCreateOp::verify() {
846 return emitError(
"data clause associated with no_create operation must "
860LogicalResult acc::AttachOp::verify() {
863 "data clause associated with attach operation must match its intent");
877LogicalResult acc::DeclareDeviceResidentOp::verify() {
878 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
879 return emitError(
"data clause associated with device_resident operation "
880 "must match its intent");
894LogicalResult acc::DeclareLinkOp::verify() {
897 "data clause associated with link operation must match its intent");
910LogicalResult acc::CopyoutOp::verify() {
917 "data clause associated with copyout operation must match its intent"
918 " or specify original clause this operation was decomposed from");
920 return emitError(
"must have both host and device pointers");
926 acc::DataClauseModifier::always |
927 acc::DataClauseModifier::capture)))
932bool acc::CopyoutOp::isCopyoutZero() {
933 return getDataClause() == acc::DataClause::acc_copyout_zero ||
934 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
940LogicalResult acc::DeleteOp::verify() {
949 getDataClause() != acc::DataClause::acc_declare_device_resident &&
952 "data clause associated with delete operation must match its intent"
953 " or specify original clause this operation was decomposed from");
955 return emitError(
"must have device pointer");
959 acc::DataClauseModifier::readonly |
960 acc::DataClauseModifier::always |
961 acc::DataClauseModifier::capture)))
969LogicalResult acc::DetachOp::verify() {
974 "data clause associated with detach operation must match its intent"
975 " or specify original clause this operation was decomposed from");
977 return emitError(
"must have device pointer");
986LogicalResult acc::UpdateHostOp::verify() {
991 "data clause associated with host operation must match its intent"
992 " or specify original clause this operation was decomposed from");
994 return emitError(
"must have both host and device pointers");
1007LogicalResult acc::UpdateDeviceOp::verify() {
1011 "data clause associated with device operation must match its intent"
1012 " or specify original clause this operation was decomposed from");
1025LogicalResult acc::UseDeviceOp::verify() {
1029 "data clause associated with use_device operation must match its intent"
1030 " or specify original clause this operation was decomposed from");
1043LogicalResult acc::CacheOp::verify() {
1048 "data clause associated with cache operation must match its intent"
1049 " or specify original clause this operation was decomposed from");
1059bool acc::CacheOp::isCacheReadonly() {
1060 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1061 acc::bitEnumContainsAny(getModifiers(),
1062 acc::DataClauseModifier::readonly);
1078template <
typename EffectTy>
1083 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1084 effects.emplace_back(EffectTy::get(), &operand[i]);
1088template <
typename EffectTy>
1093 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1097void acc::PrivateOp::getEffects(
1111void acc::FirstprivateOp::getEffects(
1125void acc::ReductionOp::getEffects(
1139void acc::DevicePtrOp::getEffects(
1148void acc::PresentOp::getEffects(
1159void acc::CopyinOp::getEffects(
1172void acc::CreateOp::getEffects(
1185void acc::NoCreateOp::getEffects(
1196void acc::AttachOp::getEffects(
1209void acc::GetDevicePtrOp::getEffects(
1218void acc::UpdateDeviceOp::getEffects(
1228void acc::UseDeviceOp::getEffects(
1237void acc::DeclareDeviceResidentOp::getEffects(
1248void acc::DeclareLinkOp::getEffects(
1259void acc::CacheOp::getEffects(
1264void acc::CopyoutOp::getEffects(
1277void acc::DeleteOp::getEffects(
1289void acc::DetachOp::getEffects(
1301void acc::UpdateHostOp::getEffects(
1317template <
typename OpTy>
1319 using OpRewritePattern<OpTy>::OpRewritePattern;
1321 LogicalResult matchAndRewrite(OpTy op,
1322 PatternRewriter &rewriter)
const override {
1324 Value ifCond = op.getIfCond();
1328 IntegerAttr constAttr;
1331 if (constAttr.getInt())
1332 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1344 assert(region.
hasOneBlock() &&
"expected single-block region");
1356template <
typename OpTy>
1357struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1358 using OpRewritePattern<OpTy>::OpRewritePattern;
1360 LogicalResult matchAndRewrite(OpTy op,
1361 PatternRewriter &rewriter)
const override {
1363 Value ifCond = op.getIfCond();
1367 IntegerAttr constAttr;
1370 if (constAttr.getInt())
1371 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1400 for (
Value bound : bounds) {
1401 argTypes.push_back(bound.getType());
1402 argLocs.push_back(loc);
1409 Value privatizedValue;
1415 if (isa<MappableType>(varType)) {
1416 auto mappableTy = cast<MappableType>(varType);
1417 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1418 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1419 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1421 mappableTy.generatePrivateInit(builder, loc, typedVar, varName, bounds,
1422 {}, varInfo, needsFree, destroyValues);
1423 if (!privatizedValue)
1426 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1427 auto pointerLikeTy = cast<PointerLikeType>(varType);
1429 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1430 blockArgVar, needsFree);
1431 if (!privatizedValue)
1437 initResults.append(destroyValues);
1438 acc::YieldOp::create(builder, loc, initResults);
1455 for (
Value bound : bounds) {
1456 copyArgTypes.push_back(bound.getType());
1457 copyArgLocs.push_back(loc);
1467 if (isa<MappableType>(varType)) {
1468 auto mappableTy = cast<MappableType>(varType);
1471 if (!mappableTy.generateCopy(
1476 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1477 auto pointerLikeTy = cast<PointerLikeType>(varType);
1478 if (!pointerLikeTy.genCopy(
1485 acc::TerminatorOp::create(builder, loc);
1502 for (
Value destroyValue : destroyValues) {
1503 destroyArgTypes.push_back(destroyValue.getType());
1504 destroyArgLocs.push_back(loc);
1506 for (
Value bound : bounds) {
1507 destroyArgTypes.push_back(bound.getType());
1508 destroyArgLocs.push_back(loc);
1512 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1516 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1517 if (isa<MappableType>(varType)) {
1518 auto mappableTy = cast<MappableType>(varType);
1520 destroyBlock->
getArguments().slice(2, destroyValues.size());
1522 destroyBlock->
getArguments().drop_front(2 + destroyValues.size());
1523 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, destroyArgs,
1524 destroyBounds, varInfo))
1527 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1528 auto pointerLikeTy = cast<PointerLikeType>(varType);
1529 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1533 acc::TerminatorOp::create(builder, loc);
1543 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1545 if (optional && region.
empty())
1549 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1553 return op->
emitOpError() <<
"expects " << regionName
1556 << regionType <<
" type";
1559 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1560 if (yieldOp.getOperands().size() != 1 ||
1561 yieldOp.getOperands().getTypes()[0] != type)
1562 return op->
emitOpError() <<
"expects " << regionName
1564 "yield a value of the "
1565 << regionType <<
" type";
1571LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1573 "privatization",
"init",
getType(),
1577 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1583std::optional<PrivateRecipeOp>
1585 StringRef recipeName,
Value hostVar,
1590 bool isMappable = isa<MappableType>(varType);
1591 bool isPointerLike = isa<PointerLikeType>(varType);
1594 if (!isMappable && !isPointerLike)
1595 return std::nullopt;
1600 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1604 bool needsFree =
false;
1607 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1608 varName, bounds, needsFree, varInfo,
1611 return std::nullopt;
1618 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1619 Value allocRes = yieldOp.getOperand(0);
1621 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1622 varType, allocRes, destroyValues, bounds,
1625 return std::nullopt;
1632std::optional<PrivateRecipeOp>
1634 StringRef recipeName,
1635 FirstprivateRecipeOp firstprivRecipe) {
1638 auto varType = firstprivRecipe.getType();
1639 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1644 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
1647 if (!firstprivRecipe.getDestroyRegion().empty()) {
1649 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
1659LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
1661 "privatization",
"init",
getType(),
1665 if (getCopyRegion().empty())
1666 return emitOpError() <<
"expects non-empty copy region";
1671 return emitOpError() <<
"expects copy region with two arguments of the "
1672 "privatization type";
1674 if (getDestroyRegion().empty())
1678 "privatization",
"destroy",
1685std::optional<FirstprivateRecipeOp>
1687 StringRef recipeName,
Value hostVar,
1692 bool isMappable = isa<MappableType>(varType);
1693 bool isPointerLike = isa<PointerLikeType>(varType);
1696 if (!isMappable && !isPointerLike)
1697 return std::nullopt;
1702 auto recipe = FirstprivateRecipeOp::create(
1703 builder, loc, recipeName,
nullptr, varType);
1706 bool needsFree =
false;
1712 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1713 varName, bounds, needsFree, varInfo,
1716 return std::nullopt;
1720 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
1721 bounds, varInfo))) {
1723 return std::nullopt;
1730 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1731 Value allocRes = yieldOp.getOperand(0);
1733 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1734 varType, allocRes, destroyValues, bounds,
1737 return std::nullopt;
1748LogicalResult acc::ReductionRecipeOp::verifyRegions() {
1754 if (getCombinerRegion().empty())
1755 return emitOpError() <<
"expects non-empty combiner region";
1757 Block &reductionBlock = getCombinerRegion().
front();
1761 return emitOpError() <<
"expects combiner region with the first two "
1762 <<
"arguments of the reduction type";
1764 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
1765 if (yieldOp.getOperands().size() != 1 ||
1766 yieldOp.getOperands().getTypes()[0] !=
getType())
1767 return emitOpError() <<
"expects combiner region to yield a value "
1768 "of the reduction type";
1779template <
typename Op>
1783 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
1784 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
1785 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
1786 acc::MapInfoOp>(operand.getDefiningOp()))
1788 "expect data entry/exit operation or acc.getdeviceptr "
1793template <
typename OpT,
typename RecipeOpT>
1796 llvm::StringRef operandName) {
1799 if (!mlir::isa<OpT>(operand.getDefiningOp()))
1801 <<
"expected " << operandName <<
" as defining op";
1802 if (!set.insert(operand).second)
1804 << operandName <<
" operand appears more than once";
1809unsigned ParallelOp::getNumDataOperands() {
1810 return getReductionOperands().size() + getPrivateOperands().size() +
1811 getFirstprivateOperands().size() + getDataClauseOperands().size();
1814Value ParallelOp::getDataOperand(
unsigned i) {
1816 numOptional += getNumGangs().size();
1817 numOptional += getNumWorkers().size();
1818 numOptional += getVectorLength().size();
1819 numOptional += getIfCond() ? 1 : 0;
1820 numOptional += getSelfCond() ? 1 : 0;
1821 return getOperand(getWaitOperands().size() + numOptional + i);
1824template <
typename Op>
1827 llvm::StringRef keyword) {
1828 if (!operands.empty() &&
1829 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
1830 return op.
emitOpError() << keyword <<
" operands count must match "
1831 << keyword <<
" device_type count";
1835template <
typename Op>
1838 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
1839 std::size_t numOperandsInSegments = 0;
1840 std::size_t nbOfSegments = 0;
1843 for (
auto segCount : segments.
asArrayRef()) {
1844 if (maxInSegment != 0 && segCount > maxInSegment)
1845 return op.
emitOpError() << keyword <<
" expects a maximum of "
1846 << maxInSegment <<
" values per segment";
1847 numOperandsInSegments += segCount;
1852 if ((numOperandsInSegments != operands.size()) ||
1853 (!deviceTypes && !operands.empty()))
1855 << keyword <<
" operand count does not match count in segments";
1856 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
1858 << keyword <<
" segment count does not match device_type count";
1862LogicalResult acc::ParallelOp::verify() {
1864 mlir::acc::PrivateRecipeOp>(
1865 *
this, getPrivateOperands(),
"private")))
1868 mlir::acc::FirstprivateRecipeOp>(
1869 *
this, getFirstprivateOperands(),
"firstprivate")))
1872 mlir::acc::ReductionRecipeOp>(
1873 *
this, getReductionOperands(),
"reduction")))
1877 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
1878 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
1882 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
1883 getWaitOperandsDeviceTypeAttr(),
"wait")))
1887 getNumWorkersDeviceTypeAttr(),
1892 getVectorLengthDeviceTypeAttr(),
1897 getAsyncOperandsDeviceTypeAttr(),
1910 mlir::acc::DeviceType deviceType) {
1913 if (
auto pos =
findSegment(*arrayAttr, deviceType))
1918bool acc::ParallelOp::hasAsyncOnly() {
1919 return hasAsyncOnly(mlir::acc::DeviceType::None);
1922bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
1927 return getAsyncValue(mlir::acc::DeviceType::None);
1930mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
1935mlir::Value acc::ParallelOp::getNumWorkersValue() {
1936 return getNumWorkersValue(mlir::acc::DeviceType::None);
1940acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
1945mlir::Value acc::ParallelOp::getVectorLengthValue() {
1946 return getVectorLengthValue(mlir::acc::DeviceType::None);
1950acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
1952 getVectorLength(), deviceType);
1956 return getNumGangsValues(mlir::acc::DeviceType::None);
1960ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
1962 getNumGangsSegments(), deviceType);
1966 std::optional<mlir::ArrayAttr> numGangsDeviceType,
1969 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
1971 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
1973 mlir::acc::DeviceType deviceType) {
1983bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
1985 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
1986 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
1987 getVectorLength(), deviceType);
1990bool acc::ParallelOp::isEffectivelySerial() {
1994bool acc::ParallelOp::hasWaitOnly() {
1995 return hasWaitOnly(mlir::acc::DeviceType::None);
1998bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2003 return getWaitValues(mlir::acc::DeviceType::None);
2007ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2009 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2010 getHasWaitDevnum(), deviceType);
2014 return getWaitDevnum(mlir::acc::DeviceType::None);
2017mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2019 getWaitOperandsSegments(), getHasWaitDevnum(),
2034 odsBuilder, odsState, asyncOperands,
nullptr,
2035 nullptr, waitOperands,
nullptr,
2037 nullptr, numGangs,
nullptr,
2038 nullptr, numWorkers,
2039 nullptr, vectorLength,
2040 nullptr, ifCond, selfCond,
2041 false, reductionOperands, gangPrivateOperands,
2042 gangFirstPrivateOperands, dataClauseOperands,
2046void acc::ParallelOp::addNumWorkersOperand(
2049 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2050 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2051 getNumWorkersMutable()));
2053void acc::ParallelOp::addVectorLengthOperand(
2056 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2057 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2058 getVectorLengthMutable()));
2061void acc::ParallelOp::addAsyncOnly(
2063 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2064 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2067void acc::ParallelOp::addAsyncOperand(
2070 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2071 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2072 getAsyncOperandsMutable()));
2075void acc::ParallelOp::addNumGangsOperands(
2079 if (getNumGangsSegments())
2080 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2082 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2083 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2084 getNumGangsMutable(), segments));
2086 setNumGangsSegments(segments);
2088void acc::ParallelOp::addWaitOnly(
2090 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2091 effectiveDeviceTypes));
2093void acc::ParallelOp::addWaitOperands(
2098 if (getWaitOperandsSegments())
2099 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2101 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2102 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2103 getWaitOperandsMutable(), segments));
2104 setWaitOperandsSegments(segments);
2107 if (getHasWaitDevnumAttr())
2108 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2111 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2113 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2116void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2117 mlir::acc::PrivateOp op,
2118 mlir::acc::PrivateRecipeOp recipe) {
2119 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2120 getPrivateOperandsMutable().append(op.getResult());
2123void acc::ParallelOp::addFirstPrivatization(
2124 MLIRContext *context, mlir::acc::FirstprivateOp op,
2125 mlir::acc::FirstprivateRecipeOp recipe) {
2126 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2127 getFirstprivateOperandsMutable().append(op.getResult());
2130void acc::ParallelOp::addReduction(
MLIRContext *context,
2131 mlir::acc::ReductionOp op,
2132 mlir::acc::ReductionRecipeOp recipe) {
2133 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2134 getReductionOperandsMutable().append(op.getResult());
2149 int32_t crtOperandsSize = operands.size();
2152 if (parser.parseOperand(operands.emplace_back()) ||
2153 parser.parseColonType(types.emplace_back()))
2158 seg.push_back(operands.size() - crtOperandsSize);
2168 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2169 parser.
getContext(), mlir::acc::DeviceType::None));
2175 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2182 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2183 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2184 p <<
" [" << attr <<
"]";
2189 std::optional<mlir::ArrayAttr> deviceTypes,
2190 std::optional<mlir::DenseI32ArrayAttr> segments) {
2192 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2194 llvm::interleaveComma(
2195 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2196 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2216 int32_t crtOperandsSize = operands.size();
2220 if (parser.parseOperand(operands.emplace_back()) ||
2221 parser.parseColonType(types.emplace_back()))
2227 seg.push_back(operands.size() - crtOperandsSize);
2237 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2238 parser.
getContext(), mlir::acc::DeviceType::None));
2244 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2253 std::optional<mlir::DenseI32ArrayAttr> segments) {
2255 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2257 llvm::interleaveComma(
2258 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2259 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2272 mlir::ArrayAttr &keywordOnly) {
2276 bool needCommaBeforeOperands =
false;
2280 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2281 parser.
getContext(), mlir::acc::DeviceType::None));
2282 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2289 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2296 needCommaBeforeOperands =
true;
2299 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2306 int32_t crtOperandsSize = operands.size();
2318 if (parser.parseOperand(operands.emplace_back()) ||
2319 parser.parseColonType(types.emplace_back()))
2325 seg.push_back(operands.size() - crtOperandsSize);
2335 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2336 parser.
getContext(), mlir::acc::DeviceType::None));
2343 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2344 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2346 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2354 if (attrs->size() != 1)
2356 if (
auto deviceTypeAttr =
2357 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2358 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2364 std::optional<mlir::ArrayAttr> deviceTypes,
2365 std::optional<mlir::DenseI32ArrayAttr> segments,
2366 std::optional<mlir::ArrayAttr> hasDevNum,
2367 std::optional<mlir::ArrayAttr> keywordOnly) {
2380 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2382 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2383 if (boolAttr && boolAttr.getValue())
2385 llvm::interleaveComma(
2386 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2387 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2404 if (parser.parseOperand(operands.emplace_back()) ||
2405 parser.parseColonType(types.emplace_back()))
2407 if (succeeded(parser.parseOptionalLSquare())) {
2408 if (parser.parseAttribute(attributes.emplace_back()) ||
2409 parser.parseRSquare())
2412 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2413 parser.getContext(), mlir::acc::DeviceType::None));
2420 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2427 std::optional<mlir::ArrayAttr> deviceTypes) {
2430 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2431 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2440 mlir::ArrayAttr &keywordOnlyDeviceType) {
2443 bool needCommaBeforeOperands =
false;
2447 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2448 parser.
getContext(), mlir::acc::DeviceType::None));
2449 keywordOnlyDeviceType =
2450 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2458 if (parser.parseAttribute(
2459 keywordOnlyDeviceTypeAttributes.emplace_back()))
2466 keywordOnlyDeviceType =
2467 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2468 needCommaBeforeOperands =
true;
2471 if (needCommaBeforeOperands) {
2480 if (parser.parseOperand(operands.emplace_back()) ||
2481 parser.parseColonType(types.emplace_back()))
2483 if (succeeded(parser.parseOptionalLSquare())) {
2484 if (parser.parseAttribute(attributes.emplace_back()) ||
2485 parser.parseRSquare())
2488 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2489 parser.getContext(), mlir::acc::DeviceType::None));
2495 if (
failed(parser.parseRParen()))
2500 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2507 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2509 if (operands.begin() == operands.end() &&
2525 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2526 mlir::Type &operandType, mlir::UnitAttr &attr) {
2529 attr = mlir::UnitAttr::get(parser.
getContext());
2539 if (failed(parser.
parseType(operandType)))
2549 std::optional<mlir::Value> operand,
2551 mlir::UnitAttr attr) {
2568 attr = mlir::UnitAttr::get(parser.
getContext());
2573 if (parser.parseOperand(operands.emplace_back()))
2581 if (parser.parseType(types.emplace_back()))
2596 mlir::UnitAttr attr) {
2601 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2603 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2609 mlir::acc::CombinedConstructsTypeAttr &attr) {
2611 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2612 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2614 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2615 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2617 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2618 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2621 "expected compute construct name");
2629 mlir::acc::CombinedConstructsTypeAttr attr) {
2631 switch (attr.getValue()) {
2632 case mlir::acc::CombinedConstructsType::KernelsLoop:
2635 case mlir::acc::CombinedConstructsType::ParallelLoop:
2638 case mlir::acc::CombinedConstructsType::SerialLoop:
2649unsigned SerialOp::getNumDataOperands() {
2650 return getReductionOperands().size() + getPrivateOperands().size() +
2651 getFirstprivateOperands().size() + getDataClauseOperands().size();
2654Value SerialOp::getDataOperand(
unsigned i) {
2656 numOptional += getIfCond() ? 1 : 0;
2657 numOptional += getSelfCond() ? 1 : 0;
2658 return getOperand(getWaitOperands().size() + numOptional + i);
2661bool acc::SerialOp::hasAsyncOnly() {
2662 return hasAsyncOnly(mlir::acc::DeviceType::None);
2665bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2670 return getAsyncValue(mlir::acc::DeviceType::None);
2673mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2678bool acc::SerialOp::hasWaitOnly() {
2679 return hasWaitOnly(mlir::acc::DeviceType::None);
2682bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2687 return getWaitValues(mlir::acc::DeviceType::None);
2691SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2693 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2694 getHasWaitDevnum(), deviceType);
2698 return getWaitDevnum(mlir::acc::DeviceType::None);
2701mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2703 getWaitOperandsSegments(), getHasWaitDevnum(),
2707LogicalResult acc::SerialOp::verify() {
2709 mlir::acc::PrivateRecipeOp>(
2710 *
this, getPrivateOperands(),
"private")))
2713 mlir::acc::FirstprivateRecipeOp>(
2714 *
this, getFirstprivateOperands(),
"firstprivate")))
2717 mlir::acc::ReductionRecipeOp>(
2718 *
this, getReductionOperands(),
"reduction")))
2722 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2723 getWaitOperandsDeviceTypeAttr(),
"wait")))
2727 getAsyncOperandsDeviceTypeAttr(),
2737void acc::SerialOp::addAsyncOnly(
2739 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2740 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2743void acc::SerialOp::addAsyncOperand(
2746 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2747 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2748 getAsyncOperandsMutable()));
2751void acc::SerialOp::addWaitOnly(
2753 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2754 effectiveDeviceTypes));
2756void acc::SerialOp::addWaitOperands(
2761 if (getWaitOperandsSegments())
2762 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2764 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2765 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2766 getWaitOperandsMutable(), segments));
2767 setWaitOperandsSegments(segments);
2770 if (getHasWaitDevnumAttr())
2771 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2774 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2776 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2779void acc::SerialOp::addPrivatization(
MLIRContext *context,
2780 mlir::acc::PrivateOp op,
2781 mlir::acc::PrivateRecipeOp recipe) {
2782 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2783 getPrivateOperandsMutable().append(op.getResult());
2786void acc::SerialOp::addFirstPrivatization(
2787 MLIRContext *context, mlir::acc::FirstprivateOp op,
2788 mlir::acc::FirstprivateRecipeOp recipe) {
2789 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2790 getFirstprivateOperandsMutable().append(op.getResult());
2793void acc::SerialOp::addReduction(
MLIRContext *context,
2794 mlir::acc::ReductionOp op,
2795 mlir::acc::ReductionRecipeOp recipe) {
2796 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2797 getReductionOperandsMutable().append(op.getResult());
2804unsigned KernelsOp::getNumDataOperands() {
2805 return getDataClauseOperands().size();
2808Value KernelsOp::getDataOperand(
unsigned i) {
2810 numOptional += getWaitOperands().size();
2811 numOptional += getNumGangs().size();
2812 numOptional += getNumWorkers().size();
2813 numOptional += getVectorLength().size();
2814 numOptional += getIfCond() ? 1 : 0;
2815 numOptional += getSelfCond() ? 1 : 0;
2816 return getOperand(numOptional + i);
2819bool acc::KernelsOp::hasAsyncOnly() {
2820 return hasAsyncOnly(mlir::acc::DeviceType::None);
2823bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2828 return getAsyncValue(mlir::acc::DeviceType::None);
2831mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2837 return getNumWorkersValue(mlir::acc::DeviceType::None);
2841acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2846mlir::Value acc::KernelsOp::getVectorLengthValue() {
2847 return getVectorLengthValue(mlir::acc::DeviceType::None);
2851acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2853 getVectorLength(), deviceType);
2857 return getNumGangsValues(mlir::acc::DeviceType::None);
2861KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2863 getNumGangsSegments(), deviceType);
2866bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2868 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2869 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2870 getVectorLength(), deviceType);
2873bool acc::KernelsOp::isEffectivelySerial() {
2877bool acc::KernelsOp::hasWaitOnly() {
2878 return hasWaitOnly(mlir::acc::DeviceType::None);
2881bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2886 return getWaitValues(mlir::acc::DeviceType::None);
2890KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2892 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2893 getHasWaitDevnum(), deviceType);
2897 return getWaitDevnum(mlir::acc::DeviceType::None);
2900mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2902 getWaitOperandsSegments(), getHasWaitDevnum(),
2906LogicalResult acc::KernelsOp::verify() {
2908 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2909 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2913 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2914 getWaitOperandsDeviceTypeAttr(),
"wait")))
2918 getNumWorkersDeviceTypeAttr(),
2923 getVectorLengthDeviceTypeAttr(),
2928 getAsyncOperandsDeviceTypeAttr(),
2938void acc::KernelsOp::addPrivatization(
MLIRContext *context,
2939 mlir::acc::PrivateOp op,
2940 mlir::acc::PrivateRecipeOp recipe) {
2941 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2942 getPrivateOperandsMutable().append(op.getResult());
2945void acc::KernelsOp::addFirstPrivatization(
2946 MLIRContext *context, mlir::acc::FirstprivateOp op,
2947 mlir::acc::FirstprivateRecipeOp recipe) {
2948 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2949 getFirstprivateOperandsMutable().append(op.getResult());
2952void acc::KernelsOp::addReduction(
MLIRContext *context,
2953 mlir::acc::ReductionOp op,
2954 mlir::acc::ReductionRecipeOp recipe) {
2955 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2956 getReductionOperandsMutable().append(op.getResult());
2959void acc::KernelsOp::addNumWorkersOperand(
2962 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2963 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2964 getNumWorkersMutable()));
2967void acc::KernelsOp::addVectorLengthOperand(
2970 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2971 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2972 getVectorLengthMutable()));
2974void acc::KernelsOp::addAsyncOnly(
2976 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2977 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2980void acc::KernelsOp::addAsyncOperand(
2983 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2984 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2985 getAsyncOperandsMutable()));
2988void acc::KernelsOp::addNumGangsOperands(
2992 if (getNumGangsSegmentsAttr())
2993 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2995 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2996 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2997 getNumGangsMutable(), segments));
2999 setNumGangsSegments(segments);
3002void acc::KernelsOp::addWaitOnly(
3004 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3005 effectiveDeviceTypes));
3007void acc::KernelsOp::addWaitOperands(
3012 if (getWaitOperandsSegments())
3013 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3015 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3016 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3017 getWaitOperandsMutable(), segments));
3018 setWaitOperandsSegments(segments);
3021 if (getHasWaitDevnumAttr())
3022 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3025 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3027 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3034LogicalResult acc::HostDataOp::verify() {
3035 if (getDataClauseOperands().empty())
3036 return emitError(
"at least one operand must appear on the host_data "
3040 for (
mlir::Value operand : getDataClauseOperands()) {
3042 mlir::dyn_cast_if_present<acc::UseDeviceOp>(operand.getDefiningOp());
3044 return emitError(
"expect data entry operation as defining op");
3047 if (!seenVars.insert(useDeviceOp.getVar()).second)
3048 return emitError(
"duplicate use_device variable");
3055 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3067 bool &needCommaBetweenValues,
bool &newValue) {
3074 attributes.push_back(gangArgType);
3075 needCommaBetweenValues =
true;
3086 mlir::ArrayAttr &gangOnlyDeviceType) {
3091 bool needCommaBetweenValues =
false;
3092 bool needCommaBeforeOperands =
false;
3096 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3097 parser.
getContext(), mlir::acc::DeviceType::None));
3098 gangOnlyDeviceType =
3099 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3107 if (parser.parseAttribute(
3108 gangOnlyDeviceTypeAttributes.emplace_back()))
3115 needCommaBeforeOperands =
true;
3118 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3119 mlir::acc::GangArgType::Num);
3120 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3121 mlir::acc::GangArgType::Dim);
3122 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3123 parser.
getContext(), mlir::acc::GangArgType::Static);
3126 if (needCommaBeforeOperands) {
3127 needCommaBeforeOperands =
false;
3134 int32_t crtOperandsSize = gangOperands.size();
3136 bool newValue =
false;
3137 bool needValue =
false;
3138 if (needCommaBetweenValues) {
3146 gangOperands, gangOperandsType,
3147 gangArgTypeAttributes, argNum,
3148 needCommaBetweenValues, newValue)))
3151 gangOperands, gangOperandsType,
3152 gangArgTypeAttributes, argDim,
3153 needCommaBetweenValues, newValue)))
3155 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3156 gangOperands, gangOperandsType,
3157 gangArgTypeAttributes, argStatic,
3158 needCommaBetweenValues, newValue)))
3161 if (!newValue && needValue) {
3163 "new value expected after comma");
3171 if (gangOperands.empty())
3174 "expect at least one of num, dim or static values");
3180 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3184 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3185 parser.
getContext(), mlir::acc::DeviceType::None));
3188 seg.push_back(gangOperands.size() - crtOperandsSize);
3196 gangArgTypeAttributes.end());
3197 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3198 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3201 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3202 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3210 std::optional<mlir::ArrayAttr> gangArgTypes,
3211 std::optional<mlir::ArrayAttr> deviceTypes,
3212 std::optional<mlir::DenseI32ArrayAttr> segments,
3213 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3215 if (operands.begin() == operands.end() &&
3230 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3232 llvm::interleaveComma(
3233 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3234 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3235 (*gangArgTypes)[opIdx]);
3236 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3237 p << LoopOp::getGangNumKeyword();
3238 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3239 p << LoopOp::getGangDimKeyword();
3240 else if (gangArgTypeAttr.getValue() ==
3241 mlir::acc::GangArgType::Static)
3242 p << LoopOp::getGangStaticKeyword();
3243 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3254 std::optional<mlir::ArrayAttr> segments,
3255 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3258 for (
auto attr : *segments) {
3259 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3260 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3268static std::optional<mlir::acc::DeviceType>
3270 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3272 return std::nullopt;
3273 for (
auto attr : deviceTypes) {
3274 auto deviceTypeAttr =
3275 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3276 if (!deviceTypeAttr)
3277 return mlir::acc::DeviceType::None;
3278 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3279 return deviceTypeAttr.getValue();
3281 return std::nullopt;
3284LogicalResult acc::LoopOp::verify() {
3285 if (getUpperbound().size() != getStep().size())
3286 return emitError() <<
"number of upperbounds expected to be the same as "
3289 if (getUpperbound().size() != getLowerbound().size())
3290 return emitError() <<
"number of upperbounds expected to be the same as "
3291 "number of lowerbounds";
3293 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3294 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3295 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3296 <<
" as upperbound size";
3299 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3300 return emitOpError() <<
"collapse device_type attr must be define when"
3301 <<
" collapse attr is present";
3303 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3304 getCollapseAttr().getValue().size() !=
3305 getCollapseDeviceTypeAttr().getValue().size())
3306 return emitOpError() <<
"collapse attribute count must match collapse"
3307 <<
" device_type count";
3308 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3309 return emitOpError() <<
"duplicate device_type `"
3310 << acc::stringifyDeviceType(*duplicateDeviceType)
3311 <<
"` found in collapseDeviceType attribute";
3314 if (!getGangOperands().empty()) {
3315 if (!getGangOperandsArgType())
3316 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3317 <<
" when gang operands are present";
3319 if (getGangOperands().size() !=
3320 getGangOperandsArgTypeAttr().getValue().size())
3321 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3322 <<
" gangOperands count";
3324 if (getGangAttr()) {
3326 return emitOpError() <<
"duplicate device_type `"
3327 << acc::stringifyDeviceType(*duplicateDeviceType)
3328 <<
"` found in gang attribute";
3332 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3333 getGangOperandsDeviceTypeAttr(),
"gang")))
3338 return emitOpError() <<
"duplicate device_type `"
3339 << acc::stringifyDeviceType(*duplicateDeviceType)
3340 <<
"` found in worker attribute";
3341 if (
auto duplicateDeviceType =
3343 return emitOpError() <<
"duplicate device_type `"
3344 << acc::stringifyDeviceType(*duplicateDeviceType)
3345 <<
"` found in workerNumOperandsDeviceType attribute";
3347 getWorkerNumOperandsDeviceTypeAttr(),
3353 return emitOpError() <<
"duplicate device_type `"
3354 << acc::stringifyDeviceType(*duplicateDeviceType)
3355 <<
"` found in vector attribute";
3356 if (
auto duplicateDeviceType =
3358 return emitOpError() <<
"duplicate device_type `"
3359 << acc::stringifyDeviceType(*duplicateDeviceType)
3360 <<
"` found in vectorOperandsDeviceType attribute";
3362 getVectorOperandsDeviceTypeAttr(),
3367 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3368 getTileOperandsDeviceTypeAttr(),
"tile")))
3372 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3376 return emitError() <<
"only one of auto, independent, seq can be present "
3382 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3383 return attr.getValue() == mlir::acc::DeviceType::None;
3385 bool hasDefaultSeq =
3387 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3390 bool hasDefaultIndependent =
3391 getIndependentAttr()
3393 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3396 bool hasDefaultAuto =
3398 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3401 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3403 <<
"at least one of auto, independent, seq must be present";
3408 for (
auto attr : getSeqAttr()) {
3409 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3410 if (hasVector(deviceTypeAttr.getValue()) ||
3411 getVectorValue(deviceTypeAttr.getValue()) ||
3412 hasWorker(deviceTypeAttr.getValue()) ||
3413 getWorkerValue(deviceTypeAttr.getValue()) ||
3414 hasGang(deviceTypeAttr.getValue()) ||
3415 getGangValue(mlir::acc::GangArgType::Num,
3416 deviceTypeAttr.getValue()) ||
3417 getGangValue(mlir::acc::GangArgType::Dim,
3418 deviceTypeAttr.getValue()) ||
3419 getGangValue(mlir::acc::GangArgType::Static,
3420 deviceTypeAttr.getValue()))
3421 return emitError() <<
"gang, worker or vector cannot appear with seq";
3426 mlir::acc::PrivateRecipeOp>(
3427 *
this, getPrivateOperands(),
"private")))
3431 mlir::acc::FirstprivateRecipeOp>(
3432 *
this, getFirstprivateOperands(),
"firstprivate")))
3436 mlir::acc::ReductionRecipeOp>(
3437 *
this, getReductionOperands(),
"reduction")))
3440 if (getCombined().has_value() &&
3441 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3442 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3443 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3444 return emitError(
"unexpected combined constructs attribute");
3448 if (getRegion().empty())
3449 return emitError(
"expected non-empty body.");
3451 if (getUnstructured()) {
3452 if (!isContainerLike())
3454 "unstructured acc.loop must not have induction variables");
3455 }
else if (isContainerLike()) {
3459 uint64_t collapseCount = getCollapseValue().value_or(1);
3460 if (getCollapseAttr()) {
3461 for (
auto collapseEntry : getCollapseAttr()) {
3462 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3463 if (intAttr.getValue().getZExtValue() > collapseCount)
3464 collapseCount = intAttr.getValue().getZExtValue();
3472 bool foundSibling =
false;
3474 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3476 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3478 foundSibling =
true;
3483 expectedParent = op;
3486 if (collapseCount == 0)
3492 return emitError(
"found sibling loops inside container-like acc.loop");
3493 if (collapseCount != 0)
3494 return emitError(
"failed to find enough loop-like operations inside "
3495 "container-like acc.loop");
3501unsigned LoopOp::getNumDataOperands() {
3502 return getReductionOperands().size() + getPrivateOperands().size() +
3503 getFirstprivateOperands().size();
3506Value LoopOp::getDataOperand(
unsigned i) {
3507 unsigned numOptional =
3508 getLowerbound().size() + getUpperbound().size() + getStep().size();
3509 numOptional += getGangOperands().size();
3510 numOptional += getVectorOperands().size();
3511 numOptional += getWorkerNumOperands().size();
3512 numOptional += getTileOperands().size();
3513 numOptional += getCacheOperands().size();
3514 return getOperand(numOptional + i);
3517bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3519bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3523bool LoopOp::hasIndependent() {
3524 return hasIndependent(mlir::acc::DeviceType::None);
3527bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3531bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3533bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3538 return getVectorValue(mlir::acc::DeviceType::None);
3541mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3543 getVectorOperands(), deviceType);
3546bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3548bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3553 return getWorkerValue(mlir::acc::DeviceType::None);
3556mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3558 getWorkerNumOperands(), deviceType);
3561bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3563bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3568 return getTileValues(mlir::acc::DeviceType::None);
3572LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3574 getTileOperandsSegments(), deviceType);
3577std::optional<int64_t> LoopOp::getCollapseValue() {
3578 return getCollapseValue(mlir::acc::DeviceType::None);
3581std::optional<int64_t>
3582LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3583 if (!getCollapseAttr())
3584 return std::nullopt;
3585 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3587 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3588 return intAttr.getValue().getZExtValue();
3590 return std::nullopt;
3593mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3594 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3597mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3598 mlir::acc::DeviceType deviceType) {
3599 if (getGangOperands().empty())
3601 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3602 int32_t nbOperandsBefore = 0;
3603 for (
unsigned i = 0; i < *pos; ++i)
3604 nbOperandsBefore += (*getGangOperandsSegments())[i];
3607 .drop_front(nbOperandsBefore)
3608 .take_front((*getGangOperandsSegments())[*pos]);
3610 int32_t argTypeIdx = nbOperandsBefore;
3611 for (
auto value : values) {
3612 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3613 (*getGangOperandsArgType())[argTypeIdx]);
3614 if (gangArgTypeAttr.getValue() == gangArgType)
3622bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
3624bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
3629 return {&getRegion()};
3673 if (!regionArgs.empty()) {
3674 p << acc::LoopOp::getControlKeyword() <<
"(";
3675 llvm::interleaveComma(regionArgs, p,
3677 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
3678 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
3679 <<
" : " << stepType <<
") ";
3686 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
3687 effectiveDeviceTypes));
3690void acc::LoopOp::addIndependent(
3692 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
3693 context, getIndependentAttr(), effectiveDeviceTypes));
3698 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
3699 effectiveDeviceTypes));
3702void acc::LoopOp::setCollapseForDeviceTypes(
3704 llvm::APInt value) {
3708 assert((getCollapseAttr() ==
nullptr) ==
3709 (getCollapseDeviceTypeAttr() ==
nullptr));
3710 assert(value.getBitWidth() == 64);
3712 if (getCollapseAttr()) {
3713 for (
const auto &existing :
3714 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
3715 newValues.push_back(std::get<0>(existing));
3716 newDeviceTypes.push_back(std::get<1>(existing));
3720 if (effectiveDeviceTypes.empty()) {
3723 newValues.push_back(
3724 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3725 newDeviceTypes.push_back(
3726 acc::DeviceTypeAttr::get(context, DeviceType::None));
3728 for (DeviceType dt : effectiveDeviceTypes) {
3729 newValues.push_back(
3730 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3731 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
3735 setCollapseAttr(ArrayAttr::get(context, newValues));
3736 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
3739void acc::LoopOp::setTileForDeviceTypes(
3743 if (getTileOperandsSegments())
3744 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
3746 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3747 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3748 getTileOperandsMutable(), segments));
3750 setTileOperandsSegments(segments);
3753void acc::LoopOp::addVectorOperand(
3756 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3757 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
3758 newValue, getVectorOperandsMutable()));
3761void acc::LoopOp::addEmptyVector(
3763 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
3764 effectiveDeviceTypes));
3767void acc::LoopOp::addWorkerNumOperand(
3770 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3771 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
3772 newValue, getWorkerNumOperandsMutable()));
3775void acc::LoopOp::addEmptyWorker(
3777 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
3778 effectiveDeviceTypes));
3781void acc::LoopOp::addEmptyGang(
3783 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
3784 effectiveDeviceTypes));
3787bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
3788 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
3789 return attr.getValue() == dt;
3791 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
3792 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
3795 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
3797 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
3799 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
3805bool acc::LoopOp::hasDefaultGangWorkerVector() {
3806 return hasAnyGangWorkerVector(DeviceType::None);
3809bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
3810 return hasVector(deviceType) || getVectorValue(deviceType) ||
3811 hasWorker(deviceType) || getWorkerValue(deviceType) ||
3812 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
3813 getGangValue(GangArgType::Dim, deviceType) ||
3814 getGangValue(GangArgType::Static, deviceType);
3818acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
3819 if (hasSeq(deviceType))
3820 return LoopParMode::loop_seq;
3821 if (hasAuto(deviceType))
3822 return LoopParMode::loop_auto;
3823 if (hasIndependent(deviceType))
3824 return LoopParMode::loop_independent;
3826 return LoopParMode::loop_seq;
3828 return LoopParMode::loop_auto;
3829 assert(hasIndependent() &&
3830 "loop must have default auto, seq, or independent");
3831 return LoopParMode::loop_independent;
3834void acc::LoopOp::addGangOperands(
3839 getGangOperandsSegments())
3840 llvm::copy(*existingSegments, std::back_inserter(segments));
3842 unsigned beforeCount = segments.size();
3844 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3845 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3846 getGangOperandsMutable(), segments));
3848 setGangOperandsSegments(segments);
3855 unsigned numAdded = segments.size() - beforeCount;
3859 if (getGangOperandsArgTypeAttr())
3860 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
3862 for (
auto i : llvm::index_range(0u, numAdded)) {
3863 llvm::transform(argTypes, std::back_inserter(gangTypes),
3864 [=](mlir::acc::GangArgType gangTy) {
3865 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
3870 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
3874void acc::LoopOp::addPrivatization(
MLIRContext *context,
3875 mlir::acc::PrivateOp op,
3876 mlir::acc::PrivateRecipeOp recipe) {
3877 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3878 getPrivateOperandsMutable().append(op.getResult());
3881void acc::LoopOp::addFirstPrivatization(
3882 MLIRContext *context, mlir::acc::FirstprivateOp op,
3883 mlir::acc::FirstprivateRecipeOp recipe) {
3884 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3885 getFirstprivateOperandsMutable().append(op.getResult());
3888void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
3889 mlir::acc::ReductionRecipeOp recipe) {
3890 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3891 getReductionOperandsMutable().append(op.getResult());
3898LogicalResult acc::DataOp::verify() {
3903 return emitError(
"at least one operand or the default attribute "
3904 "must appear on the data operation");
3906 for (
mlir::Value operand : getDataClauseOperands())
3907 if (isa<BlockArgument>(operand) ||
3908 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
3909 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
3910 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
3911 acc::MapInfoOp>(operand.getDefiningOp()))
3912 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
3921unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
3923Value DataOp::getDataOperand(
unsigned i) {
3924 unsigned numOptional = getIfCond() ? 1 : 0;
3926 numOptional += getWaitOperands().size();
3927 return getOperand(numOptional + i);
3930bool acc::DataOp::hasAsyncOnly() {
3931 return hasAsyncOnly(mlir::acc::DeviceType::None);
3934bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3939 return getAsyncValue(mlir::acc::DeviceType::None);
3942mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3947bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
3949bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3954 return getWaitValues(mlir::acc::DeviceType::None);
3958DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3960 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3961 getHasWaitDevnum(), deviceType);
3965 return getWaitDevnum(mlir::acc::DeviceType::None);
3968mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3970 getWaitOperandsSegments(), getHasWaitDevnum(),
3974void acc::DataOp::addAsyncOnly(
3976 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3977 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3980void acc::DataOp::addAsyncOperand(
3983 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3984 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3985 getAsyncOperandsMutable()));
3988void acc::DataOp::addWaitOnly(
MLIRContext *context,
3990 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3991 effectiveDeviceTypes));
3994void acc::DataOp::addWaitOperands(
3999 if (getWaitOperandsSegments())
4000 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4002 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4003 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4004 getWaitOperandsMutable(), segments));
4005 setWaitOperandsSegments(segments);
4008 if (getHasWaitDevnumAttr())
4009 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4012 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4014 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4021LogicalResult acc::ExitDataOp::verify() {
4025 if (getDataClauseOperands().empty())
4026 return emitError(
"at least one operand must be present in dataOperands on "
4027 "the exit data operation");
4031 if (getAsyncOperand() && getAsync())
4032 return emitError(
"async attribute cannot appear with asyncOperand");
4036 if (!getWaitOperands().empty() && getWait())
4037 return emitError(
"wait attribute cannot appear with waitOperands");
4039 if (getWaitDevnum() && getWaitOperands().empty())
4040 return emitError(
"wait_devnum cannot appear without waitOperands");
4045unsigned ExitDataOp::getNumDataOperands() {
4046 return getDataClauseOperands().size();
4049Value ExitDataOp::getDataOperand(
unsigned i) {
4050 unsigned numOptional = getIfCond() ? 1 : 0;
4051 numOptional += getAsyncOperand() ? 1 : 0;
4052 numOptional += getWaitDevnum() ? 1 : 0;
4053 return getOperand(getWaitOperands().size() + numOptional + i);
4058 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4061void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4063 assert(effectiveDeviceTypes.empty());
4064 assert(!getAsyncAttr());
4065 assert(!getAsyncOperand());
4067 setAsyncAttr(mlir::UnitAttr::get(context));
4070void ExitDataOp::addAsyncOperand(
4073 assert(effectiveDeviceTypes.empty());
4074 assert(!getAsyncAttr());
4075 assert(!getAsyncOperand());
4077 getAsyncOperandMutable().append(newValue);
4082 assert(effectiveDeviceTypes.empty());
4087 setWaitAttr(mlir::UnitAttr::get(context));
4089 getWaitDevnumMutable().clear();
4090 getWaitOperandsMutable().clear();
4093void ExitDataOp::addWaitOperands(
4096 assert(effectiveDeviceTypes.empty());
4105 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4110 getWaitDevnumMutable().append(newValues.front());
4111 newValues = newValues.drop_front();
4114 getWaitOperandsMutable().append(newValues);
4121LogicalResult acc::EnterDataOp::verify() {
4125 if (getDataClauseOperands().empty())
4126 return emitError(
"at least one operand must be present in dataOperands on "
4127 "the enter data operation");
4131 if (getAsyncOperand() && getAsync())
4132 return emitError(
"async attribute cannot appear with asyncOperand");
4136 if (!getWaitOperands().empty() && getWait())
4137 return emitError(
"wait attribute cannot appear with waitOperands");
4139 if (getWaitDevnum() && getWaitOperands().empty())
4140 return emitError(
"wait_devnum cannot appear without waitOperands");
4142 for (
mlir::Value operand : getDataClauseOperands())
4143 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp, acc::MapInfoOp>(
4144 operand.getDefiningOp()))
4145 return emitError(
"expect data entry operation as defining op");
4150unsigned EnterDataOp::getNumDataOperands() {
4151 return getDataClauseOperands().size();
4154Value EnterDataOp::getDataOperand(
unsigned i) {
4155 unsigned numOptional = getIfCond() ? 1 : 0;
4156 numOptional += getAsyncOperand() ? 1 : 0;
4157 numOptional += getWaitDevnum() ? 1 : 0;
4158 return getOperand(getWaitOperands().size() + numOptional + i);
4163 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4166void EnterDataOp::addAsyncOnly(
4168 assert(effectiveDeviceTypes.empty());
4169 assert(!getAsyncAttr());
4170 assert(!getAsyncOperand());
4172 setAsyncAttr(mlir::UnitAttr::get(context));
4175void EnterDataOp::addAsyncOperand(
4178 assert(effectiveDeviceTypes.empty());
4179 assert(!getAsyncAttr());
4180 assert(!getAsyncOperand());
4182 getAsyncOperandMutable().append(newValue);
4185void EnterDataOp::addWaitOnly(
MLIRContext *context,
4187 assert(effectiveDeviceTypes.empty());
4192 setWaitAttr(mlir::UnitAttr::get(context));
4194 getWaitDevnumMutable().clear();
4195 getWaitOperandsMutable().clear();
4198void EnterDataOp::addWaitOperands(
4201 assert(effectiveDeviceTypes.empty());
4210 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4215 getWaitDevnumMutable().append(newValues.front());
4216 newValues = newValues.drop_front();
4219 getWaitOperandsMutable().append(newValues);
4226LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4232LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4238LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4245 if (
Value writeVal = op.getWriteOpVal()) {
4254LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4256LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4262AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4263 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4265 return dyn_cast<AtomicReadOp>(getSecondOp());
4268AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4269 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4271 return dyn_cast<AtomicWriteOp>(getSecondOp());
4274AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4275 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4277 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4280LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4286template <
typename Op>
4289 bool requireAtLeastOneOperand =
true) {
4290 if (operands.empty() && requireAtLeastOneOperand)
4293 "at least one operand must appear on the declare operation");
4296 if (isa<BlockArgument>(operand) ||
4297 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4298 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4299 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp,
4300 acc::MapInfoOp>(operand.getDefiningOp()))
4302 "expect valid declare data entry operation or acc.getdeviceptr "
4306 assert(var &&
"declare operands can only be data entry operations which "
4310 if (!mlir::isa<acc::MapInfoOp>(operand.getDefiningOp())) {
4311 std::optional<mlir::acc::DataClause> dataClauseOptional{
4313 assert(dataClauseOptional.has_value() &&
4314 "declare operands can only be data entry operations which must "
4316 (
void)dataClauseOptional;
4323LogicalResult acc::DeclareEnterOp::verify() {
4331LogicalResult acc::DeclareExitOp::verify() {
4342LogicalResult acc::DeclareOp::verify() {
4351 acc::DeviceType dtype) {
4352 unsigned parallelism = 0;
4353 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4354 parallelism += op.hasWorker(dtype) ? 1 : 0;
4355 parallelism += op.hasVector(dtype) ? 1 : 0;
4356 parallelism += op.hasSeq(dtype) ? 1 : 0;
4360LogicalResult acc::RoutineOp::verify() {
4361 unsigned baseParallelism =
4364 if (baseParallelism > 1)
4365 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4366 "be present at the same time";
4368 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4370 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4371 if (dtype == acc::DeviceType::None)
4375 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4376 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4377 "be present at the same time for device_type `"
4378 << acc::stringifyDeviceType(dtype) <<
"`";
4385 mlir::ArrayAttr &bindIdName,
4386 mlir::ArrayAttr &bindStrName,
4387 mlir::ArrayAttr &deviceIdTypes,
4388 mlir::ArrayAttr &deviceStrTypes) {
4395 llvm::SMLoc attrLoc = parser.getCurrentLocation();
4396 mlir::Attribute newAttr;
4397 bool isSymbolRefAttr;
4398 if (parser.parseAttribute(newAttr))
4400 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4401 bindIdNameAttrs.push_back(symbolRefAttr);
4402 isSymbolRefAttr = true;
4403 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4404 bindStrNameAttrs.push_back(stringAttr);
4405 isSymbolRefAttr =
false;
4408 "expected symbol reference or string attribute");
4412 if (isSymbolRefAttr) {
4413 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4414 parser.getContext(), mlir::acc::DeviceType::None));
4416 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4417 parser.getContext(), mlir::acc::DeviceType::None));
4420 if (isSymbolRefAttr) {
4421 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4422 parser.parseRSquare())
4425 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4426 parser.parseRSquare())
4434 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4435 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4436 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4437 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4443 std::optional<mlir::ArrayAttr> bindIdName,
4444 std::optional<mlir::ArrayAttr> bindStrName,
4445 std::optional<mlir::ArrayAttr> deviceIdTypes,
4446 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4453 allBindNames.append(bindIdName->begin(), bindIdName->end());
4454 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4459 allBindNames.append(bindStrName->begin(), bindStrName->end());
4460 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4464 if (!allBindNames.empty())
4465 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4466 [&](
const auto &pair) {
4467 p << std::get<0>(pair);
4473 mlir::ArrayAttr &gang,
4474 mlir::ArrayAttr &gangDim,
4475 mlir::ArrayAttr &gangDimDeviceTypes) {
4478 gangDimDeviceTypeAttrs;
4479 bool needCommaBeforeOperands =
false;
4483 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4484 parser.
getContext(), mlir::acc::DeviceType::None));
4485 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4492 if (parser.parseAttribute(gangAttrs.emplace_back()))
4499 needCommaBeforeOperands =
true;
4502 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4506 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4507 parser.parseColon() ||
4508 parser.parseAttribute(gangDimAttrs.emplace_back()))
4510 if (succeeded(parser.parseOptionalLSquare())) {
4511 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4512 parser.parseRSquare())
4515 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4516 parser.getContext(), mlir::acc::DeviceType::None));
4522 if (
failed(parser.parseRParen()))
4525 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4526 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4527 gangDimDeviceTypes =
4528 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4534 std::optional<mlir::ArrayAttr> gang,
4535 std::optional<mlir::ArrayAttr> gangDim,
4536 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4539 gang->size() == 1) {
4540 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4541 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4553 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4554 [&](
const auto &pair) {
4555 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4556 p << std::get<0>(pair);
4564 mlir::ArrayAttr &deviceTypes) {
4568 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4569 parser.
getContext(), mlir::acc::DeviceType::None));
4570 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4577 if (parser.parseAttribute(attributes.emplace_back()))
4585 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4591 std::optional<mlir::ArrayAttr> deviceTypes) {
4594 auto deviceTypeAttr =
4595 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4596 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4605 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4611bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4613bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4617bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4619bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4623bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4625bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4629std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4630RoutineOp::getBindNameValue() {
4631 return getBindNameValue(mlir::acc::DeviceType::None);
4634std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4635RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4637 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4638 auto attr = (*getBindIdName())[*pos];
4639 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4640 assert(symbolRefAttr &&
"expected SymbolRef");
4641 return symbolRefAttr;
4646 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
4647 auto attr = (*getBindStrName())[*pos];
4648 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
4649 assert(stringAttr &&
"expected String");
4654 return std::nullopt;
4657std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4658RoutineOp::getEffectiveBindName(mlir::acc::DeviceType targetDeviceType) {
4659 assert(targetDeviceType != DeviceType::Star &&
4660 "expected a valid target device type");
4662 if (!getBindIdName() && !getBindStrName())
4663 return std::nullopt;
4666 if (targetDeviceType == DeviceType::None)
4667 return getBindNameValue();
4670 if (
auto bindName = getBindNameValue(targetDeviceType))
4675 bool hasNamedDeviceType = hasGang(targetDeviceType) ||
4676 getGangDimValue(targetDeviceType).has_value() ||
4677 hasWorker(targetDeviceType) ||
4678 hasVector(targetDeviceType) ||
4679 hasSeq(targetDeviceType);
4680 if (!hasNamedDeviceType) {
4681 if (
auto bindName = getBindNameValue(DeviceType::Star))
4685 return getBindNameValue();
4688bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4690bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
4694std::optional<int64_t> RoutineOp::getGangDimValue() {
4695 return getGangDimValue(mlir::acc::DeviceType::None);
4698std::optional<int64_t>
4699RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
4701 return std::nullopt;
4702 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
4703 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
4704 return intAttr.getInt();
4706 return std::nullopt;
4711 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4712 effectiveDeviceTypes));
4717 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4718 effectiveDeviceTypes));
4723 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4724 effectiveDeviceTypes));
4729 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4730 effectiveDeviceTypes));
4739 if (getGangDimAttr())
4740 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
4741 if (getGangDimDeviceTypeAttr())
4742 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
4744 assert(dimValues.size() == deviceTypes.size());
4746 if (effectiveDeviceTypes.empty()) {
4747 dimValues.push_back(
4748 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4749 deviceTypes.push_back(
4750 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
4752 for (DeviceType dt : effectiveDeviceTypes) {
4753 dimValues.push_back(
4754 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4755 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4758 assert(dimValues.size() == deviceTypes.size());
4760 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
4761 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
4764void RoutineOp::addBindStrName(
MLIRContext *context,
4766 mlir::StringAttr val) {
4767 unsigned before = getBindStrNameDeviceTypeAttr()
4768 ? getBindStrNameDeviceTypeAttr().size()
4771 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4772 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
4773 unsigned after = getBindStrNameDeviceTypeAttr().size();
4776 if (getBindStrNameAttr())
4777 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
4778 for (
unsigned i = 0; i < after - before; ++i)
4779 vals.push_back(val);
4781 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
4784void RoutineOp::addBindIDName(
MLIRContext *context,
4786 mlir::SymbolRefAttr val) {
4788 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
4790 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4791 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
4792 unsigned after = getBindIdNameDeviceTypeAttr().size();
4795 if (getBindIdNameAttr())
4796 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
4797 for (
unsigned i = 0; i < after - before; ++i)
4798 vals.push_back(val);
4800 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
4807LogicalResult acc::InitOp::verify() {
4808 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4809 return emitOpError(
"cannot be nested in a compute operation");
4813void acc::InitOp::addDeviceType(
MLIRContext *context,
4814 mlir::acc::DeviceType deviceType) {
4816 if (getDeviceTypesAttr())
4817 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
4819 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
4820 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
4827LogicalResult acc::ShutdownOp::verify() {
4828 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4829 return emitOpError(
"cannot be nested in a compute operation");
4833void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
4834 mlir::acc::DeviceType deviceType) {
4836 if (getDeviceTypesAttr())
4837 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
4839 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
4840 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
4847LogicalResult acc::SetOp::verify() {
4848 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4849 return emitOpError(
"cannot be nested in a compute operation");
4850 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
4851 return emitOpError(
"at least one default_async, device_num, or device_type "
4852 "operand must appear");
4860LogicalResult acc::UpdateOp::verify() {
4862 if (getDataClauseOperands().empty())
4863 return emitError(
"at least one value must be present in dataOperands");
4866 getAsyncOperandsDeviceTypeAttr(),
4871 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
4872 getWaitOperandsDeviceTypeAttr(),
"wait")))
4878 for (
mlir::Value operand : getDataClauseOperands())
4879 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp,
4880 acc::MapInfoOp>(operand.getDefiningOp()))
4881 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4887unsigned UpdateOp::getNumDataOperands() {
4888 return getDataClauseOperands().size();
4891Value UpdateOp::getDataOperand(
unsigned i) {
4893 numOptional += getIfCond() ? 1 : 0;
4894 return getOperand(getWaitOperands().size() + numOptional + i);
4899 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
4902bool UpdateOp::hasAsyncOnly() {
4903 return hasAsyncOnly(mlir::acc::DeviceType::None);
4906bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4911 return getAsyncValue(mlir::acc::DeviceType::None);
4914mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4924bool UpdateOp::hasWaitOnly() {
4925 return hasWaitOnly(mlir::acc::DeviceType::None);
4928bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4933 return getWaitValues(mlir::acc::DeviceType::None);
4937UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4939 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4940 getHasWaitDevnum(), deviceType);
4944 return getWaitDevnum(mlir::acc::DeviceType::None);
4947mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4949 getWaitOperandsSegments(), getHasWaitDevnum(),
4955 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4956 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4959void UpdateOp::addAsyncOperand(
4962 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4963 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4964 getAsyncOperandsMutable()));
4969 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4970 effectiveDeviceTypes));
4973void UpdateOp::addWaitOperands(
4978 if (getWaitOperandsSegments())
4979 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4981 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4982 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4983 getWaitOperandsMutable(), segments));
4984 setWaitOperandsSegments(segments);
4987 if (getHasWaitDevnumAttr())
4988 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4991 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4993 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5000LogicalResult acc::WaitOp::verify() {
5003 if (getAsyncOperand() && getAsync())
5004 return emitError(
"async attribute cannot appear with asyncOperand");
5006 if (getWaitDevnum() && getWaitOperands().empty())
5007 return emitError(
"wait_devnum cannot appear without waitOperands");
5012#define GET_OP_CLASSES
5013#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5015#define GET_ATTRDEF_CLASSES
5016#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5018#define GET_TYPEDEF_CLASSES
5019#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5030 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5031 [&](
auto entry) {
return entry.getVarPtr(); })
5032 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5033 [&](
auto exit) {
return exit.getVarPtr(); })
5043 [&](
auto entry) {
return entry.getVar(); })
5051 [&](
auto entry) {
return entry.getVarType(); })
5052 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5053 [&](
auto exit) {
return exit.getVarType(); })
5064 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5065 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5076 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5085 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5095 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5096 [&](
auto dataClause) {
5098 dataClause.getBounds().begin(),
5099 dataClause.getBounds().end());
5111 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5113 dataClause.getAsyncOperands().begin(),
5114 dataClause.getAsyncOperands().end());
5125 return dataClause.getAsyncOperandsDeviceTypeAttr();
5133 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5140 if (deviceType != DeviceType::None && deviceType != DeviceType::Star)
5141 deviceTypes.push_back(deviceType);
5142 deviceTypes.push_back(DeviceType::Star);
5143 deviceTypes.push_back(DeviceType::None);
5150 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5151 [&](
auto entry) {
return entry.getName(); })
5158std::optional<mlir::acc::DataClause>
5163 .Case<ACC_DATA_ENTRY_OPS>(
5164 [&](
auto entry) {
return entry.getDataClause(); })
5170 return mlir::isa_and_nonnull<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(op);
5176 .Case<mlir::acc::MapInfoOp>([&](
auto mapInfo) {
5177 return bitEnumContainsAny(mapInfo.getMapFlags(),
5178 mlir::acc::MapFlags::implicit);
5186 [&](
auto dataClause) {
return dataClause.getSynthetic(); })
5194 mlir::acc::KernelEnvironmentOp>(
5195 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5197 return dataOperands;
5205 mlir::acc::KernelEnvironmentOp>(
5206 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5208 return dataOperands;
5215 [&](
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.
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.