26#include "llvm/ADT/SmallSet.h"
27#include "llvm/ADT/TypeSwitch.h"
28#include "llvm/Support/LogicalResult.h"
34#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
35#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
36#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
37#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
38#include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
42static bool isScalarLikeType(
Type type) {
50 if (!varName.empty()) {
51 auto varNameAttr = acc::VarNameAttr::get(builder.
getContext(), varName);
57struct MemRefPointerLikeModel
58 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel<T>, T> {
60 return cast<T>(pointer).getElementType();
63 mlir::acc::VariableTypeCategory
66 if (
auto mappableTy = dyn_cast<MappableType>(varType)) {
67 return mappableTy.getTypeCategory(varPtr);
69 auto memrefTy = cast<T>(pointer);
70 if (!memrefTy.hasRank()) {
73 return mlir::acc::VariableTypeCategory::uncategorized;
76 if (memrefTy.getRank() == 0) {
77 if (isScalarLikeType(memrefTy.getElementType())) {
78 return mlir::acc::VariableTypeCategory::scalar;
82 return mlir::acc::VariableTypeCategory::uncategorized;
86 assert(memrefTy.getRank() > 0 &&
"rank expected to be positive");
87 return mlir::acc::VariableTypeCategory::array;
90 mlir::Value genAllocate(Type pointer, OpBuilder &builder, Location loc,
91 StringRef varName, Type varType, Value originalVar,
92 bool &needsFree)
const {
93 auto memrefTy = cast<MemRefType>(pointer);
97 if (memrefTy.hasStaticShape()) {
99 auto allocaOp = memref::AllocaOp::create(builder, loc, memrefTy);
100 attachVarNameAttr(allocaOp, builder, varName);
101 return allocaOp.getResult();
106 if (originalVar && originalVar.
getType() == memrefTy &&
107 memrefTy.hasRank()) {
108 SmallVector<Value> dynamicSizes;
109 for (int64_t i = 0; i < memrefTy.getRank(); ++i) {
110 if (memrefTy.isDynamicDim(i)) {
114 memref::DimOp::create(builder, loc, originalVar, indexValue);
115 dynamicSizes.push_back(dimSize);
122 memref::AllocOp::create(builder, loc, memrefTy, dynamicSizes);
123 attachVarNameAttr(allocOp, builder, varName);
124 return allocOp.getResult();
131 bool genFree(Type pointer, OpBuilder &builder, Location loc,
133 Type varType)
const {
136 Value valueToInspect = allocRes ? allocRes : memrefValue;
139 Value currentValue = valueToInspect;
140 Operation *originalAlloc =
nullptr;
144 while (currentValue) {
147 if (isa<memref::AllocOp, memref::AllocaOp>(definingOp)) {
148 originalAlloc = definingOp;
153 if (
auto castOp = dyn_cast<memref::CastOp>(definingOp)) {
154 currentValue = castOp.getSource();
159 if (
auto reinterpretCastOp =
160 dyn_cast<memref::ReinterpretCastOp>(definingOp)) {
161 currentValue = reinterpretCastOp.getSource();
173 if (isa<memref::AllocaOp>(originalAlloc)) {
177 if (isa<memref::AllocOp>(originalAlloc)) {
179 memref::DeallocOp::create(builder, loc, memrefValue);
188 bool genCopy(Type pointer, OpBuilder &builder, Location loc,
192 auto destMemref = dyn_cast_if_present<TypedValue<MemRefType>>(destination);
193 auto srcMemref = dyn_cast_if_present<TypedValue<MemRefType>>(source);
199 if (destMemref && srcMemref &&
200 destMemref.getType().getElementType() ==
201 srcMemref.getType().getElementType() &&
202 destMemref.getType().getShape() == srcMemref.getType().getShape()) {
203 memref::CopyOp::create(builder, loc, srcMemref, destMemref);
210 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
212 Type valueType)
const {
217 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(srcPtr);
221 auto memrefTy = memrefValue.
getType();
224 if (memrefTy.getRank() != 0)
227 return memref::LoadOp::create(builder, loc, memrefValue);
230 bool genStore(Type pointer, OpBuilder &builder, Location loc,
236 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(destPtr);
240 auto memrefTy = memrefValue.getType();
243 if (memrefTy.getRank() != 0)
246 memref::StoreOp::create(builder, loc, valueToStore, memrefValue);
250 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
251 Type resultType)
const {
252 if (value.
getType() == resultType)
255 if (isa<BaseMemRefType>(value.
getType()) &&
256 isa<BaseMemRefType>(resultType)) {
259 return memref::CastOp::create(builder, loc, resultType, value);
260 if (memref::MemorySpaceCastOp::areCastCompatible(
262 return memref::MemorySpaceCastOp::create(builder, loc, resultType,
269 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
270 if (!isa<BaseMemRefType>(resPtrLike))
271 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
273 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
274 if (!isa<BaseMemRefType>(valPtrLike))
275 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
281 bool isDeviceData(Type pointer, Value var)
const {
282 auto memrefTy = cast<T>(pointer);
283 Attribute memSpace = memrefTy.getMemorySpace();
284 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
287 MemRefType getAsMemRefType(Type pointer, ModuleOp module)
const {
289 return dyn_cast<MemRefType>(pointer);
293struct LLVMPointerPointerLikeModel
294 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
295 LLVM::LLVMPointerType> {
298 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
300 Type valueType)
const {
305 return LLVM::LoadOp::create(builder, loc, valueType, srcPtr);
308 bool genStore(Type pointer, OpBuilder &builder, Location loc,
310 LLVM::StoreOp::create(builder, loc, valueToStore, destPtr);
314 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
315 Type resultType)
const {
316 if (value.
getType() == resultType)
319 auto srcPtrTy = dyn_cast<LLVM::LLVMPointerType>(value.
getType());
320 auto dstPtrTy = dyn_cast<LLVM::LLVMPointerType>(resultType);
321 if (srcPtrTy && dstPtrTy) {
322 if (srcPtrTy.getAddressSpace() != dstPtrTy.getAddressSpace())
323 return LLVM::AddrSpaceCastOp::create(builder, loc, resultType, value);
327 if (srcPtrTy && isa<IntegerType>(resultType))
328 return LLVM::PtrToIntOp::create(builder, loc, resultType, value);
331 Value intVal = value;
332 if (isa<IndexType>(value.
getType()))
333 intVal = arith::IndexCastUIOp::create(builder, loc,
335 if (isa<IntegerType>(intVal.
getType()))
336 return LLVM::IntToPtrOp::create(builder, loc, resultType, intVal);
339 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
340 if (!isa<LLVM::LLVMPointerType>(resPtrLike))
341 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
343 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
344 if (!isa<LLVM::LLVMPointerType>(valPtrLike))
345 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
348 return UnrealizedConversionCastOp::create(builder, loc,
354struct PrivateTypePointerLikeModel
355 :
public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
358 return cast<PrivateType>(type).getBaseTy();
361 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
362 Type resultType)
const {
363 if (value.
getType() == resultType)
365 if (!isa<PointerLikeType>(resultType))
367 return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
370 MemRefType getAsMemRefType(Type type, ModuleOp module)
const {
371 Type baseTy = cast<PrivateType>(type).getBaseTy();
372 if (
auto memrefTy = dyn_cast<MemRefType>(baseTy))
374 if (
auto ptrLikeTy = dyn_cast<PointerLikeType>(baseTy))
375 return ptrLikeTy.getAsMemRefType(module);
380struct MemrefAddressOfGlobalModel
381 :
public AddressOfGlobalOpInterface::ExternalModel<
382 MemrefAddressOfGlobalModel, memref::GetGlobalOp> {
383 SymbolRefAttr getSymbol(Operation *op)
const {
384 auto getGlobalOp = cast<memref::GetGlobalOp>(op);
385 return getGlobalOp.getNameAttr();
389struct MemrefGlobalVariableModel
390 :
public GlobalVariableOpInterface::ExternalModel<MemrefGlobalVariableModel,
392 bool isConstant(Operation *op)
const {
393 auto globalOp = cast<memref::GlobalOp>(op);
394 return globalOp.getConstant();
397 bool hasInitializer(Operation *op)
const {
398 auto globalOp = cast<memref::GlobalOp>(op);
399 return globalOp.getInitialValue().has_value();
402 Region *getInitRegion(Operation *op)
const {
407 bool isDeviceData(Operation *op)
const {
408 auto globalOp = cast<memref::GlobalOp>(op);
409 Attribute memSpace = globalOp.getType().getMemorySpace();
410 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
414struct GPULaunchOffloadRegionModel
415 :
public acc::OffloadRegionOpInterface::ExternalModel<
416 GPULaunchOffloadRegionModel, gpu::LaunchOp> {
417 mlir::Region &getOffloadRegion(mlir::Operation *op)
const {
418 return cast<gpu::LaunchOp>(op).getBody();
426mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
427 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
430 if (existingDeviceTypes)
431 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
433 if (newDeviceTypes.empty())
434 deviceTypes.push_back(
435 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
437 for (DeviceType dt : newDeviceTypes)
438 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
440 return mlir::ArrayAttr::get(context, deviceTypes);
449mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
450 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
455 if (existingDeviceTypes)
456 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
458 if (newDeviceTypes.empty()) {
459 argCollection.
append(arguments);
460 segments.push_back(arguments.size());
461 deviceTypes.push_back(
462 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
465 for (DeviceType dt : newDeviceTypes) {
466 argCollection.
append(arguments);
467 segments.push_back(arguments.size());
468 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
471 return mlir::ArrayAttr::get(context, deviceTypes);
475mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
476 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
480 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
481 newDeviceTypes, arguments,
482 argCollection, segments);
490void OpenACCDialect::initialize() {
493#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
496#define GET_ATTRDEF_LIST
497#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
500#define GET_TYPEDEF_LIST
501#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
507 MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
509 UnrankedMemRefType::attachInterface<
510 MemRefPointerLikeModel<UnrankedMemRefType>>(*
getContext());
511 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
513 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
516 memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
518 memref::GlobalOp::attachInterface<MemrefGlobalVariableModel>(*
getContext());
519 gpu::LaunchOp::attachInterface<GPULaunchOffloadRegionModel>(*
getContext());
556void ParallelOp::getSuccessorRegions(
586void HostDataOp::getSuccessorRegions(
601 if (getUnstructured()) {
634 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
638 mlir::acc::DeviceType deviceType) {
642 for (
auto attr : *arrayAttr) {
643 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
644 if (deviceTypeAttr.getValue() == deviceType)
652 std::optional<mlir::ArrayAttr> deviceTypes) {
657 llvm::interleaveComma(*deviceTypes, p,
663 mlir::acc::DeviceType deviceType) {
664 unsigned segmentIdx = 0;
665 for (
auto attr : segments) {
666 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
667 if (deviceTypeAttr.getValue() == deviceType)
668 return std::make_optional(segmentIdx);
678 mlir::acc::DeviceType deviceType) {
680 return range.take_front(0);
681 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
682 int32_t nbOperandsBefore = 0;
683 for (
unsigned i = 0; i < *pos; ++i)
684 nbOperandsBefore += (*segments)[i];
685 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
687 return range.take_front(0);
694 std::optional<mlir::ArrayAttr> hasWaitDevnum,
695 mlir::acc::DeviceType deviceType) {
698 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
699 if (hasWaitDevnum && *hasWaitDevnum) {
700 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
701 if (boolAttr && boolAttr.getValue())
714 std::optional<mlir::ArrayAttr> hasWaitDevnum,
715 mlir::acc::DeviceType deviceType) {
720 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
721 if (hasWaitDevnum && *hasWaitDevnum) {
722 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
723 if (boolAttr.getValue())
724 return range.drop_front(1);
730template <
typename Op>
732 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
734 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
739 op.hasAsyncOnly(dtype))
741 "asyncOnly attribute cannot appear with asyncOperand");
746 op.hasWaitOnly(dtype))
747 return op.
emitError(
"wait attribute cannot appear with waitOperands");
752template <
typename Op>
755 return op.
emitError(
"must have var operand");
758 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
759 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
760 return op.
emitError(
"var must be mappable or pointer-like");
763 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
764 op.getVarType() == op.getVar().getType())
765 return op.
emitError(
"varType must capture the element type of var");
770template <
typename Op>
772 if (op.getVar().getType() != op.getAccVar().getType())
773 return op.
emitError(
"input and output types must match");
778template <
typename Op>
780 if (op.getModifiers() != acc::DataClauseModifier::none)
781 return op.
emitError(
"no data clause modifiers are allowed");
785template <
typename Op>
788 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
790 "invalid data clause modifiers: " +
791 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
796template <
typename OpT,
typename RecipeOpT>
797static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
802 !std::is_same_v<OpT, acc::ReductionOp>)
805 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
807 return op->emitOpError() <<
"recipe expected for " << operandName;
812 return op->emitOpError()
813 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
814 << operandName <<
" declaration";
835 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
856 if (failed(parser.
parseType(accVarType)))
866 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
878 mlir::TypeAttr &varTypeAttr) {
879 if (failed(parser.
parseType(varPtrType)))
890 varTypeAttr = mlir::TypeAttr::get(varType);
895 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
896 Type elementType = ptrTy.getElementType();
899 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
901 varTypeAttr = mlir::TypeAttr::get(varPtrType);
909 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
917 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
918 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
922 if (!typeToCheckAgainst)
923 typeToCheckAgainst = varPtrType;
924 if (typeToCheckAgainst != varType) {
932 mlir::SymbolRefAttr &recipeAttr) {
939 mlir::SymbolRefAttr recipeAttr) {
946LogicalResult acc::DataBoundsOp::verify() {
947 auto extent = getExtent();
948 auto upperbound = getUpperbound();
949 if (!extent && !upperbound)
950 return emitError(
"expected extent or upperbound.");
957LogicalResult acc::PrivateOp::verify() {
960 "data clause associated with private operation must match its intent");
974LogicalResult acc::FirstprivateOp::verify() {
976 return emitError(
"data clause associated with firstprivate operation must "
983 *
this,
"firstprivate")))
991LogicalResult acc::ReductionOp::verify() {
993 return emitError(
"data clause associated with reduction operation must "
1000 *
this,
"reduction")))
1008LogicalResult acc::DevicePtrOp::verify() {
1010 return emitError(
"data clause associated with deviceptr operation must "
1011 "match its intent");
1024LogicalResult acc::PresentOp::verify() {
1027 "data clause associated with present operation must match its intent");
1040LogicalResult acc::CopyinOp::verify() {
1042 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
1047 "data clause associated with copyin operation must match its intent"
1048 " or specify original clause this operation was decomposed from");
1054 acc::DataClauseModifier::always |
1055 acc::DataClauseModifier::capture)))
1060bool acc::CopyinOp::isCopyinReadonly() {
1061 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
1062 acc::bitEnumContainsAny(getModifiers(),
1063 acc::DataClauseModifier::readonly);
1069LogicalResult acc::CreateOp::verify() {
1076 "data clause associated with create operation must match its intent"
1077 " or specify original clause this operation was decomposed from");
1085 acc::DataClauseModifier::always |
1086 acc::DataClauseModifier::capture)))
1091bool acc::CreateOp::isCreateZero() {
1093 return getDataClause() == acc::DataClause::acc_create_zero ||
1095 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1101LogicalResult acc::NoCreateOp::verify() {
1103 return emitError(
"data clause associated with no_create operation must "
1104 "match its intent");
1117LogicalResult acc::AttachOp::verify() {
1120 "data clause associated with attach operation must match its intent");
1134LogicalResult acc::DeclareDeviceResidentOp::verify() {
1135 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
1136 return emitError(
"data clause associated with device_resident operation "
1137 "must match its intent");
1151LogicalResult acc::DeclareLinkOp::verify() {
1154 "data clause associated with link operation must match its intent");
1167LogicalResult acc::CopyoutOp::verify() {
1174 "data clause associated with copyout operation must match its intent"
1175 " or specify original clause this operation was decomposed from");
1177 return emitError(
"must have both host and device pointers");
1183 acc::DataClauseModifier::always |
1184 acc::DataClauseModifier::capture)))
1189bool acc::CopyoutOp::isCopyoutZero() {
1190 return getDataClause() == acc::DataClause::acc_copyout_zero ||
1191 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1197LogicalResult acc::DeleteOp::verify() {
1206 getDataClause() != acc::DataClause::acc_declare_device_resident &&
1209 "data clause associated with delete operation must match its intent"
1210 " or specify original clause this operation was decomposed from");
1212 return emitError(
"must have device pointer");
1216 acc::DataClauseModifier::readonly |
1217 acc::DataClauseModifier::always |
1218 acc::DataClauseModifier::capture)))
1226LogicalResult acc::DetachOp::verify() {
1231 "data clause associated with detach operation must match its intent"
1232 " or specify original clause this operation was decomposed from");
1234 return emitError(
"must have device pointer");
1243LogicalResult acc::UpdateHostOp::verify() {
1248 "data clause associated with host operation must match its intent"
1249 " or specify original clause this operation was decomposed from");
1251 return emitError(
"must have both host and device pointers");
1264LogicalResult acc::UpdateDeviceOp::verify() {
1268 "data clause associated with device operation must match its intent"
1269 " or specify original clause this operation was decomposed from");
1282LogicalResult acc::UseDeviceOp::verify() {
1286 "data clause associated with use_device operation must match its intent"
1287 " or specify original clause this operation was decomposed from");
1300LogicalResult acc::CacheOp::verify() {
1305 "data clause associated with cache operation must match its intent"
1306 " or specify original clause this operation was decomposed from");
1316bool acc::CacheOp::isCacheReadonly() {
1317 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1318 acc::bitEnumContainsAny(getModifiers(),
1319 acc::DataClauseModifier::readonly);
1335template <
typename EffectTy>
1340 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1341 effects.emplace_back(EffectTy::get(), &operand[i]);
1345template <
typename EffectTy>
1350 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1354void acc::PrivateOp::getEffects(
1368void acc::FirstprivateOp::getEffects(
1382void acc::ReductionOp::getEffects(
1396void acc::DevicePtrOp::getEffects(
1405void acc::PresentOp::getEffects(
1416void acc::CopyinOp::getEffects(
1429void acc::CreateOp::getEffects(
1442void acc::NoCreateOp::getEffects(
1453void acc::AttachOp::getEffects(
1466void acc::GetDevicePtrOp::getEffects(
1475void acc::UpdateDeviceOp::getEffects(
1485void acc::UseDeviceOp::getEffects(
1494void acc::DeclareDeviceResidentOp::getEffects(
1505void acc::DeclareLinkOp::getEffects(
1516void acc::CacheOp::getEffects(
1521void acc::CopyoutOp::getEffects(
1534void acc::DeleteOp::getEffects(
1546void acc::DetachOp::getEffects(
1558void acc::UpdateHostOp::getEffects(
1570template <
typename StructureOp>
1572 unsigned nRegions = 1) {
1575 for (
unsigned i = 0; i < nRegions; ++i)
1578 for (
Region *region : regions)
1589template <
typename OpTy>
1591 using OpRewritePattern<OpTy>::OpRewritePattern;
1593 LogicalResult matchAndRewrite(OpTy op,
1594 PatternRewriter &rewriter)
const override {
1596 Value ifCond = op.getIfCond();
1600 IntegerAttr constAttr;
1603 if (constAttr.getInt())
1604 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1616 assert(region.
hasOneBlock() &&
"expected single-block region");
1628template <
typename OpTy>
1629struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1630 using OpRewritePattern<OpTy>::OpRewritePattern;
1632 LogicalResult matchAndRewrite(OpTy op,
1633 PatternRewriter &rewriter)
const override {
1635 Value ifCond = op.getIfCond();
1639 IntegerAttr constAttr;
1642 if (constAttr.getInt())
1643 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1671 for (
Value bound : bounds) {
1672 argTypes.push_back(bound.getType());
1673 argLocs.push_back(loc);
1680 Value privatizedValue;
1686 if (isa<MappableType>(varType)) {
1687 auto mappableTy = cast<MappableType>(varType);
1688 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1689 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1690 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1691 privatizedValue = mappableTy.generatePrivateInit(
1692 builder, loc, typedVar, varName, bounds, {}, varInfo, needsFree);
1693 if (!privatizedValue)
1696 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1697 auto pointerLikeTy = cast<PointerLikeType>(varType);
1699 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1700 blockArgVar, needsFree);
1701 if (!privatizedValue)
1706 acc::YieldOp::create(builder, loc, privatizedValue);
1723 for (
Value bound : bounds) {
1724 copyArgTypes.push_back(bound.getType());
1725 copyArgLocs.push_back(loc);
1735 if (isa<MappableType>(varType)) {
1736 auto mappableTy = cast<MappableType>(varType);
1739 if (!mappableTy.generateCopy(
1744 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1745 auto pointerLikeTy = cast<PointerLikeType>(varType);
1746 if (!pointerLikeTy.genCopy(
1753 acc::TerminatorOp::create(builder, loc);
1770 for (
Value bound : bounds) {
1771 destroyArgTypes.push_back(bound.getType());
1772 destroyArgLocs.push_back(loc);
1776 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1780 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1781 if (isa<MappableType>(varType)) {
1782 auto mappableTy = cast<MappableType>(varType);
1783 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds,
1787 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1788 auto pointerLikeTy = cast<PointerLikeType>(varType);
1789 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1793 acc::TerminatorOp::create(builder, loc);
1804 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1806 if (optional && region.
empty())
1810 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1814 return op->
emitOpError() <<
"expects " << regionName
1817 << regionType <<
" type";
1820 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1821 if (yieldOp.getOperands().size() != 1 ||
1822 yieldOp.getOperands().getTypes()[0] != type)
1823 return op->
emitOpError() <<
"expects " << regionName
1825 "yield a value of the "
1826 << regionType <<
" type";
1832LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1834 "privatization",
"init",
getType(),
1838 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1844std::optional<PrivateRecipeOp>
1846 StringRef recipeName,
Value hostVar,
1851 bool isMappable = isa<MappableType>(varType);
1852 bool isPointerLike = isa<PointerLikeType>(varType);
1855 if (!isMappable && !isPointerLike)
1856 return std::nullopt;
1861 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1864 bool needsFree =
false;
1866 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1867 varName, bounds, needsFree, varInfo))) {
1869 return std::nullopt;
1876 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1877 Value allocRes = yieldOp.getOperand(0);
1879 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1880 varType, allocRes, bounds, varInfo))) {
1882 return std::nullopt;
1889std::optional<PrivateRecipeOp>
1891 StringRef recipeName,
1892 FirstprivateRecipeOp firstprivRecipe) {
1895 auto varType = firstprivRecipe.getType();
1896 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1900 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
1903 if (!firstprivRecipe.getDestroyRegion().empty()) {
1905 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
1915LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
1917 "privatization",
"init",
getType(),
1921 if (getCopyRegion().empty())
1922 return emitOpError() <<
"expects non-empty copy region";
1927 return emitOpError() <<
"expects copy region with two arguments of the "
1928 "privatization type";
1930 if (getDestroyRegion().empty())
1934 "privatization",
"destroy",
1941std::optional<FirstprivateRecipeOp>
1943 StringRef recipeName,
Value hostVar,
1948 bool isMappable = isa<MappableType>(varType);
1949 bool isPointerLike = isa<PointerLikeType>(varType);
1952 if (!isMappable && !isPointerLike)
1953 return std::nullopt;
1958 auto recipe = FirstprivateRecipeOp::create(builder, loc, recipeName, varType);
1961 bool needsFree =
false;
1966 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1967 varName, bounds, needsFree, varInfo))) {
1969 return std::nullopt;
1973 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
1974 bounds, varInfo))) {
1976 return std::nullopt;
1983 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1984 Value allocRes = yieldOp.getOperand(0);
1986 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1987 varType, allocRes, bounds, varInfo))) {
1989 return std::nullopt;
2000LogicalResult acc::ReductionRecipeOp::verifyRegions() {
2006 if (getCombinerRegion().empty())
2007 return emitOpError() <<
"expects non-empty combiner region";
2009 Block &reductionBlock = getCombinerRegion().
front();
2013 return emitOpError() <<
"expects combiner region with the first two "
2014 <<
"arguments of the reduction type";
2016 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
2017 if (yieldOp.getOperands().size() != 1 ||
2018 yieldOp.getOperands().getTypes()[0] !=
getType())
2019 return emitOpError() <<
"expects combiner region to yield a value "
2020 "of the reduction type";
2031template <
typename Op>
2035 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2036 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2037 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
2038 operand.getDefiningOp()))
2040 "expect data entry/exit operation or acc.getdeviceptr "
2045template <
typename OpT,
typename RecipeOpT>
2048 llvm::StringRef operandName) {
2051 if (!mlir::isa<OpT>(operand.getDefiningOp()))
2053 <<
"expected " << operandName <<
" as defining op";
2054 if (!set.insert(operand).second)
2056 << operandName <<
" operand appears more than once";
2061unsigned ParallelOp::getNumDataOperands() {
2062 return getReductionOperands().size() + getPrivateOperands().size() +
2063 getFirstprivateOperands().size() + getDataClauseOperands().size();
2066Value ParallelOp::getDataOperand(
unsigned i) {
2068 numOptional += getNumGangs().size();
2069 numOptional += getNumWorkers().size();
2070 numOptional += getVectorLength().size();
2071 numOptional += getIfCond() ? 1 : 0;
2072 numOptional += getSelfCond() ? 1 : 0;
2073 return getOperand(getWaitOperands().size() + numOptional + i);
2076template <
typename Op>
2079 llvm::StringRef keyword) {
2080 if (!operands.empty() &&
2081 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
2082 return op.
emitOpError() << keyword <<
" operands count must match "
2083 << keyword <<
" device_type count";
2087template <
typename Op>
2090 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
2091 std::size_t numOperandsInSegments = 0;
2092 std::size_t nbOfSegments = 0;
2095 for (
auto segCount : segments.
asArrayRef()) {
2096 if (maxInSegment != 0 && segCount > maxInSegment)
2097 return op.
emitOpError() << keyword <<
" expects a maximum of "
2098 << maxInSegment <<
" values per segment";
2099 numOperandsInSegments += segCount;
2104 if ((numOperandsInSegments != operands.size()) ||
2105 (!deviceTypes && !operands.empty()))
2107 << keyword <<
" operand count does not match count in segments";
2108 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
2110 << keyword <<
" segment count does not match device_type count";
2114LogicalResult acc::ParallelOp::verify() {
2116 mlir::acc::PrivateRecipeOp>(
2117 *
this, getPrivateOperands(),
"private")))
2120 mlir::acc::FirstprivateRecipeOp>(
2121 *
this, getFirstprivateOperands(),
"firstprivate")))
2124 mlir::acc::ReductionRecipeOp>(
2125 *
this, getReductionOperands(),
"reduction")))
2129 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2130 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2134 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2135 getWaitOperandsDeviceTypeAttr(),
"wait")))
2139 getNumWorkersDeviceTypeAttr(),
2144 getVectorLengthDeviceTypeAttr(),
2149 getAsyncOperandsDeviceTypeAttr(),
2162 mlir::acc::DeviceType deviceType) {
2165 if (
auto pos =
findSegment(*arrayAttr, deviceType))
2170bool acc::ParallelOp::hasAsyncOnly() {
2171 return hasAsyncOnly(mlir::acc::DeviceType::None);
2174bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2179 return getAsyncValue(mlir::acc::DeviceType::None);
2182mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2187mlir::Value acc::ParallelOp::getNumWorkersValue() {
2188 return getNumWorkersValue(mlir::acc::DeviceType::None);
2192acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2197mlir::Value acc::ParallelOp::getVectorLengthValue() {
2198 return getVectorLengthValue(mlir::acc::DeviceType::None);
2202acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2204 getVectorLength(), deviceType);
2208 return getNumGangsValues(mlir::acc::DeviceType::None);
2212ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2214 getNumGangsSegments(), deviceType);
2218 std::optional<mlir::ArrayAttr> numGangsDeviceType,
2221 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
2223 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
2225 mlir::acc::DeviceType deviceType) {
2235bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2237 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2238 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2239 getVectorLength(), deviceType);
2242bool acc::ParallelOp::isEffectivelySerial() {
2246bool acc::ParallelOp::hasWaitOnly() {
2247 return hasWaitOnly(mlir::acc::DeviceType::None);
2250bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2255 return getWaitValues(mlir::acc::DeviceType::None);
2259ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2261 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2262 getHasWaitDevnum(), deviceType);
2266 return getWaitDevnum(mlir::acc::DeviceType::None);
2269mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2271 getWaitOperandsSegments(), getHasWaitDevnum(),
2286 odsBuilder, odsState, asyncOperands,
nullptr,
2287 nullptr, waitOperands,
nullptr,
2289 nullptr, numGangs,
nullptr,
2290 nullptr, numWorkers,
2291 nullptr, vectorLength,
2292 nullptr, ifCond, selfCond,
2293 nullptr, reductionOperands, gangPrivateOperands,
2294 gangFirstPrivateOperands, dataClauseOperands,
2298void acc::ParallelOp::addNumWorkersOperand(
2301 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2302 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2303 getNumWorkersMutable()));
2305void acc::ParallelOp::addVectorLengthOperand(
2308 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2309 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2310 getVectorLengthMutable()));
2313void acc::ParallelOp::addAsyncOnly(
2315 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2316 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2319void acc::ParallelOp::addAsyncOperand(
2322 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2323 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2324 getAsyncOperandsMutable()));
2327void acc::ParallelOp::addNumGangsOperands(
2331 if (getNumGangsSegments())
2332 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2334 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2335 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2336 getNumGangsMutable(), segments));
2338 setNumGangsSegments(segments);
2340void acc::ParallelOp::addWaitOnly(
2342 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2343 effectiveDeviceTypes));
2345void acc::ParallelOp::addWaitOperands(
2350 if (getWaitOperandsSegments())
2351 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2353 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2354 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2355 getWaitOperandsMutable(), segments));
2356 setWaitOperandsSegments(segments);
2359 if (getHasWaitDevnumAttr())
2360 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2363 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2365 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2368void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2369 mlir::acc::PrivateOp op,
2370 mlir::acc::PrivateRecipeOp recipe) {
2371 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2372 getPrivateOperandsMutable().append(op.getResult());
2375void acc::ParallelOp::addFirstPrivatization(
2376 MLIRContext *context, mlir::acc::FirstprivateOp op,
2377 mlir::acc::FirstprivateRecipeOp recipe) {
2378 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2379 getFirstprivateOperandsMutable().append(op.getResult());
2382void acc::ParallelOp::addReduction(
MLIRContext *context,
2383 mlir::acc::ReductionOp op,
2384 mlir::acc::ReductionRecipeOp recipe) {
2385 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2386 getReductionOperandsMutable().append(op.getResult());
2401 int32_t crtOperandsSize = operands.size();
2404 if (parser.parseOperand(operands.emplace_back()) ||
2405 parser.parseColonType(types.emplace_back()))
2410 seg.push_back(operands.size() - crtOperandsSize);
2420 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2421 parser.
getContext(), mlir::acc::DeviceType::None));
2427 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2434 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2435 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2436 p <<
" [" << attr <<
"]";
2441 std::optional<mlir::ArrayAttr> deviceTypes,
2442 std::optional<mlir::DenseI32ArrayAttr> segments) {
2444 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2446 llvm::interleaveComma(
2447 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2448 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2468 int32_t crtOperandsSize = operands.size();
2472 if (parser.parseOperand(operands.emplace_back()) ||
2473 parser.parseColonType(types.emplace_back()))
2479 seg.push_back(operands.size() - crtOperandsSize);
2489 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2490 parser.
getContext(), mlir::acc::DeviceType::None));
2496 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2505 std::optional<mlir::DenseI32ArrayAttr> segments) {
2507 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2509 llvm::interleaveComma(
2510 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2511 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2524 mlir::ArrayAttr &keywordOnly) {
2528 bool needCommaBeforeOperands =
false;
2532 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2533 parser.
getContext(), mlir::acc::DeviceType::None));
2534 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2541 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2548 needCommaBeforeOperands =
true;
2551 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2558 int32_t crtOperandsSize = operands.size();
2570 if (parser.parseOperand(operands.emplace_back()) ||
2571 parser.parseColonType(types.emplace_back()))
2577 seg.push_back(operands.size() - crtOperandsSize);
2587 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2588 parser.
getContext(), mlir::acc::DeviceType::None));
2595 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2596 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2598 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2606 if (attrs->size() != 1)
2608 if (
auto deviceTypeAttr =
2609 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2610 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2616 std::optional<mlir::ArrayAttr> deviceTypes,
2617 std::optional<mlir::DenseI32ArrayAttr> segments,
2618 std::optional<mlir::ArrayAttr> hasDevNum,
2619 std::optional<mlir::ArrayAttr> keywordOnly) {
2632 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2634 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2635 if (boolAttr && boolAttr.getValue())
2637 llvm::interleaveComma(
2638 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2639 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2656 if (parser.parseOperand(operands.emplace_back()) ||
2657 parser.parseColonType(types.emplace_back()))
2659 if (succeeded(parser.parseOptionalLSquare())) {
2660 if (parser.parseAttribute(attributes.emplace_back()) ||
2661 parser.parseRSquare())
2664 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2665 parser.getContext(), mlir::acc::DeviceType::None));
2672 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2679 std::optional<mlir::ArrayAttr> deviceTypes) {
2682 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2683 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2692 mlir::ArrayAttr &keywordOnlyDeviceType) {
2695 bool needCommaBeforeOperands =
false;
2699 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2700 parser.
getContext(), mlir::acc::DeviceType::None));
2701 keywordOnlyDeviceType =
2702 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2710 if (parser.parseAttribute(
2711 keywordOnlyDeviceTypeAttributes.emplace_back()))
2718 needCommaBeforeOperands =
true;
2721 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2726 if (parser.parseOperand(operands.emplace_back()) ||
2727 parser.parseColonType(types.emplace_back()))
2729 if (succeeded(parser.parseOptionalLSquare())) {
2730 if (parser.parseAttribute(attributes.emplace_back()) ||
2731 parser.parseRSquare())
2734 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2735 parser.getContext(), mlir::acc::DeviceType::None));
2741 if (
failed(parser.parseRParen()))
2746 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2753 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2755 if (operands.begin() == operands.end() &&
2771 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2772 mlir::Type &operandType, mlir::UnitAttr &attr) {
2775 attr = mlir::UnitAttr::get(parser.
getContext());
2785 if (failed(parser.
parseType(operandType)))
2795 std::optional<mlir::Value> operand,
2797 mlir::UnitAttr attr) {
2814 attr = mlir::UnitAttr::get(parser.
getContext());
2819 if (parser.parseOperand(operands.emplace_back()))
2827 if (parser.parseType(types.emplace_back()))
2842 mlir::UnitAttr attr) {
2847 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2849 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2855 mlir::acc::CombinedConstructsTypeAttr &attr) {
2857 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2858 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2860 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2861 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2863 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2864 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2867 "expected compute construct name");
2875 mlir::acc::CombinedConstructsTypeAttr attr) {
2877 switch (attr.getValue()) {
2878 case mlir::acc::CombinedConstructsType::KernelsLoop:
2881 case mlir::acc::CombinedConstructsType::ParallelLoop:
2884 case mlir::acc::CombinedConstructsType::SerialLoop:
2895unsigned SerialOp::getNumDataOperands() {
2896 return getReductionOperands().size() + getPrivateOperands().size() +
2897 getFirstprivateOperands().size() + getDataClauseOperands().size();
2900Value SerialOp::getDataOperand(
unsigned i) {
2902 numOptional += getIfCond() ? 1 : 0;
2903 numOptional += getSelfCond() ? 1 : 0;
2904 return getOperand(getWaitOperands().size() + numOptional + i);
2907bool acc::SerialOp::hasAsyncOnly() {
2908 return hasAsyncOnly(mlir::acc::DeviceType::None);
2911bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2916 return getAsyncValue(mlir::acc::DeviceType::None);
2919mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2924bool acc::SerialOp::hasWaitOnly() {
2925 return hasWaitOnly(mlir::acc::DeviceType::None);
2928bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2933 return getWaitValues(mlir::acc::DeviceType::None);
2937SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2939 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2940 getHasWaitDevnum(), deviceType);
2944 return getWaitDevnum(mlir::acc::DeviceType::None);
2947mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2949 getWaitOperandsSegments(), getHasWaitDevnum(),
2953LogicalResult acc::SerialOp::verify() {
2955 mlir::acc::PrivateRecipeOp>(
2956 *
this, getPrivateOperands(),
"private")))
2959 mlir::acc::FirstprivateRecipeOp>(
2960 *
this, getFirstprivateOperands(),
"firstprivate")))
2963 mlir::acc::ReductionRecipeOp>(
2964 *
this, getReductionOperands(),
"reduction")))
2968 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2969 getWaitOperandsDeviceTypeAttr(),
"wait")))
2973 getAsyncOperandsDeviceTypeAttr(),
2983void acc::SerialOp::addAsyncOnly(
2985 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2986 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2989void acc::SerialOp::addAsyncOperand(
2992 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2993 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2994 getAsyncOperandsMutable()));
2997void acc::SerialOp::addWaitOnly(
2999 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3000 effectiveDeviceTypes));
3002void acc::SerialOp::addWaitOperands(
3007 if (getWaitOperandsSegments())
3008 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3010 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3011 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3012 getWaitOperandsMutable(), segments));
3013 setWaitOperandsSegments(segments);
3016 if (getHasWaitDevnumAttr())
3017 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3020 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3022 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3025void acc::SerialOp::addPrivatization(
MLIRContext *context,
3026 mlir::acc::PrivateOp op,
3027 mlir::acc::PrivateRecipeOp recipe) {
3028 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3029 getPrivateOperandsMutable().append(op.getResult());
3032void acc::SerialOp::addFirstPrivatization(
3033 MLIRContext *context, mlir::acc::FirstprivateOp op,
3034 mlir::acc::FirstprivateRecipeOp recipe) {
3035 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3036 getFirstprivateOperandsMutable().append(op.getResult());
3039void acc::SerialOp::addReduction(
MLIRContext *context,
3040 mlir::acc::ReductionOp op,
3041 mlir::acc::ReductionRecipeOp recipe) {
3042 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3043 getReductionOperandsMutable().append(op.getResult());
3050unsigned KernelsOp::getNumDataOperands() {
3051 return getDataClauseOperands().size();
3054Value KernelsOp::getDataOperand(
unsigned i) {
3056 numOptional += getWaitOperands().size();
3057 numOptional += getNumGangs().size();
3058 numOptional += getNumWorkers().size();
3059 numOptional += getVectorLength().size();
3060 numOptional += getIfCond() ? 1 : 0;
3061 numOptional += getSelfCond() ? 1 : 0;
3062 return getOperand(numOptional + i);
3065bool acc::KernelsOp::hasAsyncOnly() {
3066 return hasAsyncOnly(mlir::acc::DeviceType::None);
3069bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3074 return getAsyncValue(mlir::acc::DeviceType::None);
3077mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3083 return getNumWorkersValue(mlir::acc::DeviceType::None);
3087acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
3092mlir::Value acc::KernelsOp::getVectorLengthValue() {
3093 return getVectorLengthValue(mlir::acc::DeviceType::None);
3097acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
3099 getVectorLength(), deviceType);
3103 return getNumGangsValues(mlir::acc::DeviceType::None);
3107KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
3109 getNumGangsSegments(), deviceType);
3112bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
3114 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
3115 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
3116 getVectorLength(), deviceType);
3119bool acc::KernelsOp::isEffectivelySerial() {
3123bool acc::KernelsOp::hasWaitOnly() {
3124 return hasWaitOnly(mlir::acc::DeviceType::None);
3127bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3132 return getWaitValues(mlir::acc::DeviceType::None);
3136KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3138 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3139 getHasWaitDevnum(), deviceType);
3143 return getWaitDevnum(mlir::acc::DeviceType::None);
3146mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3148 getWaitOperandsSegments(), getHasWaitDevnum(),
3152LogicalResult acc::KernelsOp::verify() {
3154 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
3155 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
3159 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3160 getWaitOperandsDeviceTypeAttr(),
"wait")))
3164 getNumWorkersDeviceTypeAttr(),
3169 getVectorLengthDeviceTypeAttr(),
3174 getAsyncOperandsDeviceTypeAttr(),
3184void acc::KernelsOp::addPrivatization(
MLIRContext *context,
3185 mlir::acc::PrivateOp op,
3186 mlir::acc::PrivateRecipeOp recipe) {
3187 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3188 getPrivateOperandsMutable().append(op.getResult());
3191void acc::KernelsOp::addFirstPrivatization(
3192 MLIRContext *context, mlir::acc::FirstprivateOp op,
3193 mlir::acc::FirstprivateRecipeOp recipe) {
3194 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3195 getFirstprivateOperandsMutable().append(op.getResult());
3198void acc::KernelsOp::addReduction(
MLIRContext *context,
3199 mlir::acc::ReductionOp op,
3200 mlir::acc::ReductionRecipeOp recipe) {
3201 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3202 getReductionOperandsMutable().append(op.getResult());
3205void acc::KernelsOp::addNumWorkersOperand(
3208 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3209 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3210 getNumWorkersMutable()));
3213void acc::KernelsOp::addVectorLengthOperand(
3216 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3217 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3218 getVectorLengthMutable()));
3220void acc::KernelsOp::addAsyncOnly(
3222 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3223 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3226void acc::KernelsOp::addAsyncOperand(
3229 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3230 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3231 getAsyncOperandsMutable()));
3234void acc::KernelsOp::addNumGangsOperands(
3238 if (getNumGangsSegmentsAttr())
3239 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3241 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3242 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3243 getNumGangsMutable(), segments));
3245 setNumGangsSegments(segments);
3248void acc::KernelsOp::addWaitOnly(
3250 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3251 effectiveDeviceTypes));
3253void acc::KernelsOp::addWaitOperands(
3258 if (getWaitOperandsSegments())
3259 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3261 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3262 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3263 getWaitOperandsMutable(), segments));
3264 setWaitOperandsSegments(segments);
3267 if (getHasWaitDevnumAttr())
3268 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3271 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3273 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3280LogicalResult acc::HostDataOp::verify() {
3281 if (getDataClauseOperands().empty())
3282 return emitError(
"at least one operand must appear on the host_data "
3286 for (
mlir::Value operand : getDataClauseOperands()) {
3288 mlir::dyn_cast<acc::UseDeviceOp>(operand.getDefiningOp());
3290 return emitError(
"expect data entry operation as defining op");
3293 if (!seenVars.insert(useDeviceOp.getVar()).second)
3294 return emitError(
"duplicate use_device variable");
3301 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3313 bool &needCommaBetweenValues,
bool &newValue) {
3320 attributes.push_back(gangArgType);
3321 needCommaBetweenValues =
true;
3332 mlir::ArrayAttr &gangOnlyDeviceType) {
3337 bool needCommaBetweenValues =
false;
3338 bool needCommaBeforeOperands =
false;
3342 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3343 parser.
getContext(), mlir::acc::DeviceType::None));
3344 gangOnlyDeviceType =
3345 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3353 if (parser.parseAttribute(
3354 gangOnlyDeviceTypeAttributes.emplace_back()))
3361 needCommaBeforeOperands =
true;
3364 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3365 mlir::acc::GangArgType::Num);
3366 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3367 mlir::acc::GangArgType::Dim);
3368 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3369 parser.
getContext(), mlir::acc::GangArgType::Static);
3372 if (needCommaBeforeOperands) {
3373 needCommaBeforeOperands =
false;
3380 int32_t crtOperandsSize = gangOperands.size();
3382 bool newValue =
false;
3383 bool needValue =
false;
3384 if (needCommaBetweenValues) {
3392 gangOperands, gangOperandsType,
3393 gangArgTypeAttributes, argNum,
3394 needCommaBetweenValues, newValue)))
3397 gangOperands, gangOperandsType,
3398 gangArgTypeAttributes, argDim,
3399 needCommaBetweenValues, newValue)))
3401 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3402 gangOperands, gangOperandsType,
3403 gangArgTypeAttributes, argStatic,
3404 needCommaBetweenValues, newValue)))
3407 if (!newValue && needValue) {
3409 "new value expected after comma");
3417 if (gangOperands.empty())
3420 "expect at least one of num, dim or static values");
3426 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3430 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3431 parser.
getContext(), mlir::acc::DeviceType::None));
3434 seg.push_back(gangOperands.size() - crtOperandsSize);
3442 gangArgTypeAttributes.end());
3443 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3444 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3447 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3448 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3456 std::optional<mlir::ArrayAttr> gangArgTypes,
3457 std::optional<mlir::ArrayAttr> deviceTypes,
3458 std::optional<mlir::DenseI32ArrayAttr> segments,
3459 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3461 if (operands.begin() == operands.end() &&
3476 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3478 llvm::interleaveComma(
3479 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3480 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3481 (*gangArgTypes)[opIdx]);
3482 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3483 p << LoopOp::getGangNumKeyword();
3484 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3485 p << LoopOp::getGangDimKeyword();
3486 else if (gangArgTypeAttr.getValue() ==
3487 mlir::acc::GangArgType::Static)
3488 p << LoopOp::getGangStaticKeyword();
3489 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3500 std::optional<mlir::ArrayAttr> segments,
3501 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3504 for (
auto attr : *segments) {
3505 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3506 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3514static std::optional<mlir::acc::DeviceType>
3516 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3518 return std::nullopt;
3519 for (
auto attr : deviceTypes) {
3520 auto deviceTypeAttr =
3521 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3522 if (!deviceTypeAttr)
3523 return mlir::acc::DeviceType::None;
3524 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3525 return deviceTypeAttr.getValue();
3527 return std::nullopt;
3530LogicalResult acc::LoopOp::verify() {
3531 if (getUpperbound().size() != getStep().size())
3532 return emitError() <<
"number of upperbounds expected to be the same as "
3535 if (getUpperbound().size() != getLowerbound().size())
3536 return emitError() <<
"number of upperbounds expected to be the same as "
3537 "number of lowerbounds";
3539 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3540 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3541 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3542 <<
" as upperbound size";
3545 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3546 return emitOpError() <<
"collapse device_type attr must be define when"
3547 <<
" collapse attr is present";
3549 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3550 getCollapseAttr().getValue().size() !=
3551 getCollapseDeviceTypeAttr().getValue().size())
3552 return emitOpError() <<
"collapse attribute count must match collapse"
3553 <<
" device_type count";
3554 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3556 << acc::stringifyDeviceType(*duplicateDeviceType)
3557 <<
"` found in collapseDeviceType attribute";
3560 if (!getGangOperands().empty()) {
3561 if (!getGangOperandsArgType())
3562 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3563 <<
" when gang operands are present";
3565 if (getGangOperands().size() !=
3566 getGangOperandsArgTypeAttr().getValue().size())
3567 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3568 <<
" gangOperands count";
3570 if (getGangAttr()) {
3573 << acc::stringifyDeviceType(*duplicateDeviceType)
3574 <<
"` found in gang attribute";
3578 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3579 getGangOperandsDeviceTypeAttr(),
"gang")))
3585 << acc::stringifyDeviceType(*duplicateDeviceType)
3586 <<
"` found in worker attribute";
3587 if (
auto duplicateDeviceType =
3590 << acc::stringifyDeviceType(*duplicateDeviceType)
3591 <<
"` found in workerNumOperandsDeviceType attribute";
3593 getWorkerNumOperandsDeviceTypeAttr(),
3600 << acc::stringifyDeviceType(*duplicateDeviceType)
3601 <<
"` found in vector attribute";
3602 if (
auto duplicateDeviceType =
3605 << acc::stringifyDeviceType(*duplicateDeviceType)
3606 <<
"` found in vectorOperandsDeviceType attribute";
3608 getVectorOperandsDeviceTypeAttr(),
3613 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3614 getTileOperandsDeviceTypeAttr(),
"tile")))
3618 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3622 return emitError() <<
"only one of auto, independent, seq can be present "
3628 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3629 return attr.getValue() == mlir::acc::DeviceType::None;
3631 bool hasDefaultSeq =
3633 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3636 bool hasDefaultIndependent =
3637 getIndependentAttr()
3639 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3642 bool hasDefaultAuto =
3644 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3647 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3649 <<
"at least one of auto, independent, seq must be present";
3654 for (
auto attr : getSeqAttr()) {
3655 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3656 if (hasVector(deviceTypeAttr.getValue()) ||
3657 getVectorValue(deviceTypeAttr.getValue()) ||
3658 hasWorker(deviceTypeAttr.getValue()) ||
3659 getWorkerValue(deviceTypeAttr.getValue()) ||
3660 hasGang(deviceTypeAttr.getValue()) ||
3661 getGangValue(mlir::acc::GangArgType::Num,
3662 deviceTypeAttr.getValue()) ||
3663 getGangValue(mlir::acc::GangArgType::Dim,
3664 deviceTypeAttr.getValue()) ||
3665 getGangValue(mlir::acc::GangArgType::Static,
3666 deviceTypeAttr.getValue()))
3667 return emitError() <<
"gang, worker or vector cannot appear with seq";
3672 mlir::acc::PrivateRecipeOp>(
3673 *
this, getPrivateOperands(),
"private")))
3677 mlir::acc::FirstprivateRecipeOp>(
3678 *
this, getFirstprivateOperands(),
"firstprivate")))
3682 mlir::acc::ReductionRecipeOp>(
3683 *
this, getReductionOperands(),
"reduction")))
3686 if (getCombined().has_value() &&
3687 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3688 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3689 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3690 return emitError(
"unexpected combined constructs attribute");
3694 if (getRegion().empty())
3695 return emitError(
"expected non-empty body.");
3697 if (getUnstructured()) {
3698 if (!isContainerLike())
3700 "unstructured acc.loop must not have induction variables");
3701 }
else if (isContainerLike()) {
3705 uint64_t collapseCount = getCollapseValue().value_or(1);
3706 if (getCollapseAttr()) {
3707 for (
auto collapseEntry : getCollapseAttr()) {
3708 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3709 if (intAttr.getValue().getZExtValue() > collapseCount)
3710 collapseCount = intAttr.getValue().getZExtValue();
3718 bool foundSibling =
false;
3720 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3722 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3724 foundSibling =
true;
3729 expectedParent = op;
3732 if (collapseCount == 0)
3738 return emitError(
"found sibling loops inside container-like acc.loop");
3739 if (collapseCount != 0)
3740 return emitError(
"failed to find enough loop-like operations inside "
3741 "container-like acc.loop");
3747unsigned LoopOp::getNumDataOperands() {
3748 return getReductionOperands().size() + getPrivateOperands().size() +
3749 getFirstprivateOperands().size();
3752Value LoopOp::getDataOperand(
unsigned i) {
3753 unsigned numOptional =
3754 getLowerbound().size() + getUpperbound().size() + getStep().size();
3755 numOptional += getGangOperands().size();
3756 numOptional += getVectorOperands().size();
3757 numOptional += getWorkerNumOperands().size();
3758 numOptional += getTileOperands().size();
3759 numOptional += getCacheOperands().size();
3760 return getOperand(numOptional + i);
3763bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3765bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3769bool LoopOp::hasIndependent() {
3770 return hasIndependent(mlir::acc::DeviceType::None);
3773bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3777bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3779bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3784 return getVectorValue(mlir::acc::DeviceType::None);
3787mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3789 getVectorOperands(), deviceType);
3792bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3794bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3799 return getWorkerValue(mlir::acc::DeviceType::None);
3802mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3804 getWorkerNumOperands(), deviceType);
3807bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3809bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3814 return getTileValues(mlir::acc::DeviceType::None);
3818LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3820 getTileOperandsSegments(), deviceType);
3823std::optional<int64_t> LoopOp::getCollapseValue() {
3824 return getCollapseValue(mlir::acc::DeviceType::None);
3827std::optional<int64_t>
3828LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3829 if (!getCollapseAttr())
3830 return std::nullopt;
3831 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3833 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3834 return intAttr.getValue().getZExtValue();
3836 return std::nullopt;
3839mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3840 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3843mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3844 mlir::acc::DeviceType deviceType) {
3845 if (getGangOperands().empty())
3847 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3848 int32_t nbOperandsBefore = 0;
3849 for (
unsigned i = 0; i < *pos; ++i)
3850 nbOperandsBefore += (*getGangOperandsSegments())[i];
3853 .drop_front(nbOperandsBefore)
3854 .take_front((*getGangOperandsSegments())[*pos]);
3856 int32_t argTypeIdx = nbOperandsBefore;
3857 for (
auto value : values) {
3858 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3859 (*getGangOperandsArgType())[argTypeIdx]);
3860 if (gangArgTypeAttr.getValue() == gangArgType)
3868bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
3870bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
3875 return {&getRegion()};
3919 if (!regionArgs.empty()) {
3920 p << acc::LoopOp::getControlKeyword() <<
"(";
3921 llvm::interleaveComma(regionArgs, p,
3923 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
3924 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
3925 <<
" : " << stepType <<
") ";
3932 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
3933 effectiveDeviceTypes));
3936void acc::LoopOp::addIndependent(
3938 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
3939 context, getIndependentAttr(), effectiveDeviceTypes));
3944 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
3945 effectiveDeviceTypes));
3948void acc::LoopOp::setCollapseForDeviceTypes(
3950 llvm::APInt value) {
3954 assert((getCollapseAttr() ==
nullptr) ==
3955 (getCollapseDeviceTypeAttr() ==
nullptr));
3956 assert(value.getBitWidth() == 64);
3958 if (getCollapseAttr()) {
3959 for (
const auto &existing :
3960 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
3961 newValues.push_back(std::get<0>(existing));
3962 newDeviceTypes.push_back(std::get<1>(existing));
3966 if (effectiveDeviceTypes.empty()) {
3969 newValues.push_back(
3970 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3971 newDeviceTypes.push_back(
3972 acc::DeviceTypeAttr::get(context, DeviceType::None));
3974 for (DeviceType dt : effectiveDeviceTypes) {
3975 newValues.push_back(
3976 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3977 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
3981 setCollapseAttr(ArrayAttr::get(context, newValues));
3982 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
3985void acc::LoopOp::setTileForDeviceTypes(
3989 if (getTileOperandsSegments())
3990 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
3992 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3993 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3994 getTileOperandsMutable(), segments));
3996 setTileOperandsSegments(segments);
3999void acc::LoopOp::addVectorOperand(
4002 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4003 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4004 newValue, getVectorOperandsMutable()));
4007void acc::LoopOp::addEmptyVector(
4009 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4010 effectiveDeviceTypes));
4013void acc::LoopOp::addWorkerNumOperand(
4016 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4017 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4018 newValue, getWorkerNumOperandsMutable()));
4021void acc::LoopOp::addEmptyWorker(
4023 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4024 effectiveDeviceTypes));
4027void acc::LoopOp::addEmptyGang(
4029 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4030 effectiveDeviceTypes));
4033bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
4034 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
4035 return attr.getValue() == dt;
4037 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
4038 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
4041 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
4043 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
4045 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
4051bool acc::LoopOp::hasDefaultGangWorkerVector() {
4052 return hasAnyGangWorkerVector(DeviceType::None);
4055bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
4056 return hasVector(deviceType) || getVectorValue(deviceType) ||
4057 hasWorker(deviceType) || getWorkerValue(deviceType) ||
4058 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
4059 getGangValue(GangArgType::Dim, deviceType) ||
4060 getGangValue(GangArgType::Static, deviceType);
4064acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
4065 if (hasSeq(deviceType))
4066 return LoopParMode::loop_seq;
4067 if (hasAuto(deviceType))
4068 return LoopParMode::loop_auto;
4069 if (hasIndependent(deviceType))
4070 return LoopParMode::loop_independent;
4072 return LoopParMode::loop_seq;
4074 return LoopParMode::loop_auto;
4075 assert(hasIndependent() &&
4076 "loop must have default auto, seq, or independent");
4077 return LoopParMode::loop_independent;
4080void acc::LoopOp::addGangOperands(
4085 getGangOperandsSegments())
4086 llvm::copy(*existingSegments, std::back_inserter(segments));
4088 unsigned beforeCount = segments.size();
4090 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4091 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4092 getGangOperandsMutable(), segments));
4094 setGangOperandsSegments(segments);
4101 unsigned numAdded = segments.size() - beforeCount;
4105 if (getGangOperandsArgTypeAttr())
4106 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
4108 for (
auto i : llvm::index_range(0u, numAdded)) {
4109 llvm::transform(argTypes, std::back_inserter(gangTypes),
4110 [=](mlir::acc::GangArgType gangTy) {
4111 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
4116 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
4120void acc::LoopOp::addPrivatization(
MLIRContext *context,
4121 mlir::acc::PrivateOp op,
4122 mlir::acc::PrivateRecipeOp recipe) {
4123 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4124 getPrivateOperandsMutable().append(op.getResult());
4127void acc::LoopOp::addFirstPrivatization(
4128 MLIRContext *context, mlir::acc::FirstprivateOp op,
4129 mlir::acc::FirstprivateRecipeOp recipe) {
4130 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4131 getFirstprivateOperandsMutable().append(op.getResult());
4134void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
4135 mlir::acc::ReductionRecipeOp recipe) {
4136 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4137 getReductionOperandsMutable().append(op.getResult());
4144LogicalResult acc::DataOp::verify() {
4149 return emitError(
"at least one operand or the default attribute "
4150 "must appear on the data operation");
4152 for (
mlir::Value operand : getDataClauseOperands())
4153 if (isa<BlockArgument>(operand) ||
4154 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4155 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
4156 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
4157 operand.getDefiningOp()))
4158 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4167unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
4169Value DataOp::getDataOperand(
unsigned i) {
4170 unsigned numOptional = getIfCond() ? 1 : 0;
4172 numOptional += getWaitOperands().size();
4173 return getOperand(numOptional + i);
4176bool acc::DataOp::hasAsyncOnly() {
4177 return hasAsyncOnly(mlir::acc::DeviceType::None);
4180bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4185 return getAsyncValue(mlir::acc::DeviceType::None);
4188mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4193bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
4195bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4200 return getWaitValues(mlir::acc::DeviceType::None);
4204DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4206 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4207 getHasWaitDevnum(), deviceType);
4211 return getWaitDevnum(mlir::acc::DeviceType::None);
4214mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4216 getWaitOperandsSegments(), getHasWaitDevnum(),
4220void acc::DataOp::addAsyncOnly(
4222 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4223 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4226void acc::DataOp::addAsyncOperand(
4229 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4230 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4231 getAsyncOperandsMutable()));
4234void acc::DataOp::addWaitOnly(
MLIRContext *context,
4236 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4237 effectiveDeviceTypes));
4240void acc::DataOp::addWaitOperands(
4245 if (getWaitOperandsSegments())
4246 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4248 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4249 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4250 getWaitOperandsMutable(), segments));
4251 setWaitOperandsSegments(segments);
4254 if (getHasWaitDevnumAttr())
4255 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4258 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4260 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4267LogicalResult acc::ExitDataOp::verify() {
4271 if (getDataClauseOperands().empty())
4272 return emitError(
"at least one operand must be present in dataOperands on "
4273 "the exit data operation");
4277 if (getAsyncOperand() && getAsync())
4278 return emitError(
"async attribute cannot appear with asyncOperand");
4282 if (!getWaitOperands().empty() && getWait())
4283 return emitError(
"wait attribute cannot appear with waitOperands");
4285 if (getWaitDevnum() && getWaitOperands().empty())
4286 return emitError(
"wait_devnum cannot appear without waitOperands");
4291unsigned ExitDataOp::getNumDataOperands() {
4292 return getDataClauseOperands().size();
4295Value ExitDataOp::getDataOperand(
unsigned i) {
4296 unsigned numOptional = getIfCond() ? 1 : 0;
4297 numOptional += getAsyncOperand() ? 1 : 0;
4298 numOptional += getWaitDevnum() ? 1 : 0;
4299 return getOperand(getWaitOperands().size() + numOptional + i);
4304 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4307void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4309 assert(effectiveDeviceTypes.empty());
4310 assert(!getAsyncAttr());
4311 assert(!getAsyncOperand());
4313 setAsyncAttr(mlir::UnitAttr::get(context));
4316void ExitDataOp::addAsyncOperand(
4319 assert(effectiveDeviceTypes.empty());
4320 assert(!getAsyncAttr());
4321 assert(!getAsyncOperand());
4323 getAsyncOperandMutable().append(newValue);
4328 assert(effectiveDeviceTypes.empty());
4329 assert(!getWaitAttr());
4330 assert(getWaitOperands().empty());
4331 assert(!getWaitDevnum());
4333 setWaitAttr(mlir::UnitAttr::get(context));
4336void ExitDataOp::addWaitOperands(
4339 assert(effectiveDeviceTypes.empty());
4340 assert(!getWaitAttr());
4341 assert(getWaitOperands().empty());
4342 assert(!getWaitDevnum());
4347 getWaitDevnumMutable().append(newValues.front());
4348 newValues = newValues.drop_front();
4351 getWaitOperandsMutable().append(newValues);
4358LogicalResult acc::EnterDataOp::verify() {
4362 if (getDataClauseOperands().empty())
4363 return emitError(
"at least one operand must be present in dataOperands on "
4364 "the enter data operation");
4368 if (getAsyncOperand() && getAsync())
4369 return emitError(
"async attribute cannot appear with asyncOperand");
4373 if (!getWaitOperands().empty() && getWait())
4374 return emitError(
"wait attribute cannot appear with waitOperands");
4376 if (getWaitDevnum() && getWaitOperands().empty())
4377 return emitError(
"wait_devnum cannot appear without waitOperands");
4379 for (
mlir::Value operand : getDataClauseOperands())
4380 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp>(
4381 operand.getDefiningOp()))
4382 return emitError(
"expect data entry operation as defining op");
4387unsigned EnterDataOp::getNumDataOperands() {
4388 return getDataClauseOperands().size();
4391Value EnterDataOp::getDataOperand(
unsigned i) {
4392 unsigned numOptional = getIfCond() ? 1 : 0;
4393 numOptional += getAsyncOperand() ? 1 : 0;
4394 numOptional += getWaitDevnum() ? 1 : 0;
4395 return getOperand(getWaitOperands().size() + numOptional + i);
4400 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4403void EnterDataOp::addAsyncOnly(
4405 assert(effectiveDeviceTypes.empty());
4406 assert(!getAsyncAttr());
4407 assert(!getAsyncOperand());
4409 setAsyncAttr(mlir::UnitAttr::get(context));
4412void EnterDataOp::addAsyncOperand(
4415 assert(effectiveDeviceTypes.empty());
4416 assert(!getAsyncAttr());
4417 assert(!getAsyncOperand());
4419 getAsyncOperandMutable().append(newValue);
4422void EnterDataOp::addWaitOnly(
MLIRContext *context,
4424 assert(effectiveDeviceTypes.empty());
4425 assert(!getWaitAttr());
4426 assert(getWaitOperands().empty());
4427 assert(!getWaitDevnum());
4429 setWaitAttr(mlir::UnitAttr::get(context));
4432void EnterDataOp::addWaitOperands(
4435 assert(effectiveDeviceTypes.empty());
4436 assert(!getWaitAttr());
4437 assert(getWaitOperands().empty());
4438 assert(!getWaitDevnum());
4443 getWaitDevnumMutable().append(newValues.front());
4444 newValues = newValues.drop_front();
4447 getWaitOperandsMutable().append(newValues);
4454LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4460LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4466LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4473 if (
Value writeVal = op.getWriteOpVal()) {
4482LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4484LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4490AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4491 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4493 return dyn_cast<AtomicReadOp>(getSecondOp());
4496AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4497 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4499 return dyn_cast<AtomicWriteOp>(getSecondOp());
4502AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4503 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4505 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4508LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4514template <
typename Op>
4517 bool requireAtLeastOneOperand =
true) {
4518 if (operands.empty() && requireAtLeastOneOperand)
4521 "at least one operand must appear on the declare operation");
4524 if (isa<BlockArgument>(operand) ||
4525 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4526 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4527 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp>(
4528 operand.getDefiningOp()))
4530 "expect valid declare data entry operation or acc.getdeviceptr "
4534 assert(var &&
"declare operands can only be data entry operations which "
4537 std::optional<mlir::acc::DataClause> dataClauseOptional{
4539 assert(dataClauseOptional.has_value() &&
4540 "declare operands can only be data entry operations which must have "
4542 (
void)dataClauseOptional;
4548LogicalResult acc::DeclareEnterOp::verify() {
4556LogicalResult acc::DeclareExitOp::verify() {
4567LogicalResult acc::DeclareOp::verify() {
4576 acc::DeviceType dtype) {
4577 unsigned parallelism = 0;
4578 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4579 parallelism += op.hasWorker(dtype) ? 1 : 0;
4580 parallelism += op.hasVector(dtype) ? 1 : 0;
4581 parallelism += op.hasSeq(dtype) ? 1 : 0;
4585LogicalResult acc::RoutineOp::verify() {
4586 unsigned baseParallelism =
4589 if (baseParallelism > 1)
4590 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4591 "be present at the same time";
4593 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4595 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4596 if (dtype == acc::DeviceType::None)
4600 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4601 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4602 "be present at the same time for device_type `"
4603 << acc::stringifyDeviceType(dtype) <<
"`";
4610 mlir::ArrayAttr &bindIdName,
4611 mlir::ArrayAttr &bindStrName,
4612 mlir::ArrayAttr &deviceIdTypes,
4613 mlir::ArrayAttr &deviceStrTypes) {
4620 mlir::Attribute newAttr;
4621 bool isSymbolRefAttr;
4622 auto parseResult = parser.parseAttribute(newAttr);
4623 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4624 bindIdNameAttrs.push_back(symbolRefAttr);
4625 isSymbolRefAttr = true;
4626 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4627 bindStrNameAttrs.push_back(stringAttr);
4628 isSymbolRefAttr =
false;
4633 if (isSymbolRefAttr) {
4634 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4635 parser.getContext(), mlir::acc::DeviceType::None));
4637 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4638 parser.getContext(), mlir::acc::DeviceType::None));
4641 if (isSymbolRefAttr) {
4642 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4643 parser.parseRSquare())
4646 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4647 parser.parseRSquare())
4655 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4656 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4657 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4658 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4664 std::optional<mlir::ArrayAttr> bindIdName,
4665 std::optional<mlir::ArrayAttr> bindStrName,
4666 std::optional<mlir::ArrayAttr> deviceIdTypes,
4667 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4674 allBindNames.append(bindIdName->begin(), bindIdName->end());
4675 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4680 allBindNames.append(bindStrName->begin(), bindStrName->end());
4681 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4685 if (!allBindNames.empty())
4686 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4687 [&](
const auto &pair) {
4688 p << std::get<0>(pair);
4694 mlir::ArrayAttr &gang,
4695 mlir::ArrayAttr &gangDim,
4696 mlir::ArrayAttr &gangDimDeviceTypes) {
4699 gangDimDeviceTypeAttrs;
4700 bool needCommaBeforeOperands =
false;
4704 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4705 parser.
getContext(), mlir::acc::DeviceType::None));
4706 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4713 if (parser.parseAttribute(gangAttrs.emplace_back()))
4720 needCommaBeforeOperands =
true;
4723 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4727 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4728 parser.parseColon() ||
4729 parser.parseAttribute(gangDimAttrs.emplace_back()))
4731 if (succeeded(parser.parseOptionalLSquare())) {
4732 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4733 parser.parseRSquare())
4736 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4737 parser.getContext(), mlir::acc::DeviceType::None));
4743 if (
failed(parser.parseRParen()))
4746 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4747 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4748 gangDimDeviceTypes =
4749 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4755 std::optional<mlir::ArrayAttr> gang,
4756 std::optional<mlir::ArrayAttr> gangDim,
4757 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4760 gang->size() == 1) {
4761 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4762 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4774 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4775 [&](
const auto &pair) {
4776 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4777 p << std::get<0>(pair);
4785 mlir::ArrayAttr &deviceTypes) {
4789 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4790 parser.
getContext(), mlir::acc::DeviceType::None));
4791 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4798 if (parser.parseAttribute(attributes.emplace_back()))
4806 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4812 std::optional<mlir::ArrayAttr> deviceTypes) {
4815 auto deviceTypeAttr =
4816 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4817 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4826 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4832bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4834bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4838bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4840bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4844bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4846bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4850std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4851RoutineOp::getBindNameValue() {
4852 return getBindNameValue(mlir::acc::DeviceType::None);
4855std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4856RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4858 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4859 auto attr = (*getBindIdName())[*pos];
4860 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4861 assert(symbolRefAttr &&
"expected SymbolRef");
4862 return symbolRefAttr;
4867 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
4868 auto attr = (*getBindStrName())[*pos];
4869 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
4870 assert(stringAttr &&
"expected String");
4875 return std::nullopt;
4878bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4880bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
4884std::optional<int64_t> RoutineOp::getGangDimValue() {
4885 return getGangDimValue(mlir::acc::DeviceType::None);
4888std::optional<int64_t>
4889RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
4891 return std::nullopt;
4892 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
4893 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
4894 return intAttr.getInt();
4896 return std::nullopt;
4901 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4902 effectiveDeviceTypes));
4907 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4908 effectiveDeviceTypes));
4913 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4914 effectiveDeviceTypes));
4919 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4920 effectiveDeviceTypes));
4929 if (getGangDimAttr())
4930 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
4931 if (getGangDimDeviceTypeAttr())
4932 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
4934 assert(dimValues.size() == deviceTypes.size());
4936 if (effectiveDeviceTypes.empty()) {
4937 dimValues.push_back(
4938 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4939 deviceTypes.push_back(
4940 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
4942 for (DeviceType dt : effectiveDeviceTypes) {
4943 dimValues.push_back(
4944 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4945 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4948 assert(dimValues.size() == deviceTypes.size());
4950 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
4951 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
4954void RoutineOp::addBindStrName(
MLIRContext *context,
4956 mlir::StringAttr val) {
4957 unsigned before = getBindStrNameDeviceTypeAttr()
4958 ? getBindStrNameDeviceTypeAttr().size()
4961 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4962 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
4963 unsigned after = getBindStrNameDeviceTypeAttr().size();
4966 if (getBindStrNameAttr())
4967 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
4968 for (
unsigned i = 0; i < after - before; ++i)
4969 vals.push_back(val);
4971 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
4974void RoutineOp::addBindIDName(
MLIRContext *context,
4976 mlir::SymbolRefAttr val) {
4978 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
4980 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4981 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
4982 unsigned after = getBindIdNameDeviceTypeAttr().size();
4985 if (getBindIdNameAttr())
4986 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
4987 for (
unsigned i = 0; i < after - before; ++i)
4988 vals.push_back(val);
4990 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
4997LogicalResult acc::InitOp::verify() {
4998 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4999 return emitOpError(
"cannot be nested in a compute operation");
5003void acc::InitOp::addDeviceType(
MLIRContext *context,
5004 mlir::acc::DeviceType deviceType) {
5006 if (getDeviceTypesAttr())
5007 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5009 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5010 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5017LogicalResult acc::ShutdownOp::verify() {
5018 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5019 return emitOpError(
"cannot be nested in a compute operation");
5023void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
5024 mlir::acc::DeviceType deviceType) {
5026 if (getDeviceTypesAttr())
5027 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5029 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5030 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5037LogicalResult acc::SetOp::verify() {
5038 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5039 return emitOpError(
"cannot be nested in a compute operation");
5040 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
5041 return emitOpError(
"at least one default_async, device_num, or device_type "
5042 "operand must appear");
5050LogicalResult acc::UpdateOp::verify() {
5052 if (getDataClauseOperands().empty())
5053 return emitError(
"at least one value must be present in dataOperands");
5056 getAsyncOperandsDeviceTypeAttr(),
5061 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
5062 getWaitOperandsDeviceTypeAttr(),
"wait")))
5068 for (
mlir::Value operand : getDataClauseOperands())
5069 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp>(
5070 operand.getDefiningOp()))
5071 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
5077unsigned UpdateOp::getNumDataOperands() {
5078 return getDataClauseOperands().size();
5081Value UpdateOp::getDataOperand(
unsigned i) {
5083 numOptional += getIfCond() ? 1 : 0;
5084 return getOperand(getWaitOperands().size() + numOptional + i);
5089 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
5092bool UpdateOp::hasAsyncOnly() {
5093 return hasAsyncOnly(mlir::acc::DeviceType::None);
5096bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
5101 return getAsyncValue(mlir::acc::DeviceType::None);
5104mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
5114bool UpdateOp::hasWaitOnly() {
5115 return hasWaitOnly(mlir::acc::DeviceType::None);
5118bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
5123 return getWaitValues(mlir::acc::DeviceType::None);
5127UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
5129 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
5130 getHasWaitDevnum(), deviceType);
5134 return getWaitDevnum(mlir::acc::DeviceType::None);
5137mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
5139 getWaitOperandsSegments(), getHasWaitDevnum(),
5145 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
5146 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
5149void UpdateOp::addAsyncOperand(
5152 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5153 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
5154 getAsyncOperandsMutable()));
5159 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
5160 effectiveDeviceTypes));
5163void UpdateOp::addWaitOperands(
5168 if (getWaitOperandsSegments())
5169 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
5171 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5172 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
5173 getWaitOperandsMutable(), segments));
5174 setWaitOperandsSegments(segments);
5177 if (getHasWaitDevnumAttr())
5178 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5181 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5183 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5190LogicalResult acc::WaitOp::verify() {
5193 if (getAsyncOperand() && getAsync())
5194 return emitError(
"async attribute cannot appear with asyncOperand");
5196 if (getWaitDevnum() && getWaitOperands().empty())
5197 return emitError(
"wait_devnum cannot appear without waitOperands");
5202#define GET_OP_CLASSES
5203#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5205#define GET_ATTRDEF_CLASSES
5206#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5208#define GET_TYPEDEF_CLASSES
5209#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5220 .Case<ACC_DATA_ENTRY_OPS>(
5221 [&](
auto entry) {
return entry.getVarPtr(); })
5222 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5223 [&](
auto exit) {
return exit.getVarPtr(); })
5241 [&](
auto entry) {
return entry.getVarType(); })
5242 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5243 [&](
auto exit) {
return exit.getVarType(); })
5253 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>(
5254 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5264 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5273 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5283 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5285 dataClause.getBounds().begin(), dataClause.getBounds().end());
5297 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5299 dataClause.getAsyncOperands().begin(),
5300 dataClause.getAsyncOperands().end());
5311 return dataClause.getAsyncOperandsDeviceTypeAttr();
5319 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5326 .Case<ACC_DATA_ENTRY_OPS>([&](
auto entry) {
return entry.getName(); })
5333std::optional<mlir::acc::DataClause>
5338 .Case<ACC_DATA_ENTRY_OPS>(
5339 [&](
auto entry) {
return entry.getDataClause(); })
5347 [&](
auto entry) {
return entry.getImplicit(); })
5356 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5358 return dataOperands;
5366 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5368 return dataOperands;
5375 [&](
auto entry) {
return entry.getRecipeAttr(); })
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
void printRoutineGangClause(OpAsmPrinter &p, Operation *op, std::optional< mlir::ArrayAttr > gang, std::optional< mlir::ArrayAttr > gangDim, std::optional< mlir::ArrayAttr > gangDimDeviceTypes)
static ParseResult parseRegions(OpAsmParser &parser, OperationState &state, unsigned nRegions=1)
bool hasDuplicateDeviceTypes(std::optional< mlir::ArrayAttr > segments, llvm::SmallSet< mlir::acc::DeviceType, 3 > &deviceTypes)
static LogicalResult verifyDeviceTypeCountMatch(Op op, OperandRange operands, ArrayAttr deviceTypes, llvm::StringRef keyword)
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 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 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 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 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 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)
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 Type getElementType(Type type)
Determine the element type of type.
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 void genStore(OpBuilder &builder, Location loc, Value val, Value mem, Value idx)
Generates a store with proper index typing and proper value.
static Value genLoad(OpBuilder &builder, Location loc, Value mem, Value idx)
Generates a load with proper index typing.
virtual ParseResult parseLBrace()=0
Parse a { token.
@ None
Zero or more operands with no delimiters.
virtual ParseResult parseColonTypeList(SmallVectorImpl< Type > &result)=0
Parse a colon followed by a type list, which must have at least one type.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual ParseResult parseRBrace()=0
Parse a } token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printType(Type type)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
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)
MLIRContext * getContext() const
This is a utility class for mapping one set of IR entities to another.
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'.
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
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...
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
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.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static WalkResult advance()
static WalkResult interrupt()
Base attribute class for language-specific variable information carried through the OpenACC type inte...
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
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_ENTRY_OPS
#define ACC_DATA_EXIT_OPS
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.
static bool isGangWorkerVectorAllOne(ComputeOpT op)
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...
mlir::ValueRange getDataOperands(mlir::Operation *accOp)
Used to get an immutable range iterating over the data operands.
std::optional< llvm::StringRef > getVarName(mlir::Operation *accOp)
Used to obtain the name from an acc operation.
bool getImplicitFlag(mlir::Operation *accDataEntryOp)
Used to find out whether data operation is implicit.
mlir::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.
static constexpr StringLiteral getVarNameAttrName()
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.
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::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.
Region * addRegion()
Create a region that should be attached to the operation.