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 Region *getInitRegion(Operation *op)
const {
402 bool isDeviceData(Operation *op)
const {
403 auto globalOp = cast<memref::GlobalOp>(op);
404 Attribute memSpace = globalOp.getType().getMemorySpace();
405 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
409struct GPULaunchOffloadRegionModel
410 :
public acc::OffloadRegionOpInterface::ExternalModel<
411 GPULaunchOffloadRegionModel, gpu::LaunchOp> {
412 mlir::Region &getOffloadRegion(mlir::Operation *op)
const {
413 return cast<gpu::LaunchOp>(op).getBody();
421mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
422 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
425 if (existingDeviceTypes)
426 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
428 if (newDeviceTypes.empty())
429 deviceTypes.push_back(
430 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
432 for (DeviceType dt : newDeviceTypes)
433 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
435 return mlir::ArrayAttr::get(context, deviceTypes);
444mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
445 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
450 if (existingDeviceTypes)
451 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
453 if (newDeviceTypes.empty()) {
454 argCollection.
append(arguments);
455 segments.push_back(arguments.size());
456 deviceTypes.push_back(
457 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
460 for (DeviceType dt : newDeviceTypes) {
461 argCollection.
append(arguments);
462 segments.push_back(arguments.size());
463 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
466 return mlir::ArrayAttr::get(context, deviceTypes);
470mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
471 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
475 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
476 newDeviceTypes, arguments,
477 argCollection, segments);
485void OpenACCDialect::initialize() {
488#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
491#define GET_ATTRDEF_LIST
492#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
495#define GET_TYPEDEF_LIST
496#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
502 MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
504 UnrankedMemRefType::attachInterface<
505 MemRefPointerLikeModel<UnrankedMemRefType>>(*
getContext());
506 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
508 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
511 memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
513 memref::GlobalOp::attachInterface<MemrefGlobalVariableModel>(*
getContext());
514 gpu::LaunchOp::attachInterface<GPULaunchOffloadRegionModel>(*
getContext());
551void ParallelOp::getSuccessorRegions(
581void HostDataOp::getSuccessorRegions(
596 if (getUnstructured()) {
629 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
633 mlir::acc::DeviceType deviceType) {
637 for (
auto attr : *arrayAttr) {
638 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
639 if (deviceTypeAttr.getValue() == deviceType)
647 std::optional<mlir::ArrayAttr> deviceTypes) {
652 llvm::interleaveComma(*deviceTypes, p,
658 mlir::acc::DeviceType deviceType) {
659 unsigned segmentIdx = 0;
660 for (
auto attr : segments) {
661 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
662 if (deviceTypeAttr.getValue() == deviceType)
663 return std::make_optional(segmentIdx);
673 mlir::acc::DeviceType deviceType) {
675 return range.take_front(0);
676 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
677 int32_t nbOperandsBefore = 0;
678 for (
unsigned i = 0; i < *pos; ++i)
679 nbOperandsBefore += (*segments)[i];
680 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
682 return range.take_front(0);
689 std::optional<mlir::ArrayAttr> hasWaitDevnum,
690 mlir::acc::DeviceType deviceType) {
693 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
694 if (hasWaitDevnum && *hasWaitDevnum) {
695 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
696 if (boolAttr && boolAttr.getValue())
709 std::optional<mlir::ArrayAttr> hasWaitDevnum,
710 mlir::acc::DeviceType deviceType) {
715 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
716 if (hasWaitDevnum && *hasWaitDevnum) {
717 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
718 if (boolAttr.getValue())
719 return range.drop_front(1);
725template <
typename Op>
727 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
729 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
734 op.hasAsyncOnly(dtype))
736 "asyncOnly attribute cannot appear with asyncOperand");
741 op.hasWaitOnly(dtype))
742 return op.
emitError(
"wait attribute cannot appear with waitOperands");
747template <
typename Op>
750 return op.
emitError(
"must have var operand");
753 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
754 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
755 return op.
emitError(
"var must be mappable or pointer-like");
758 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
759 op.getVarType() == op.getVar().getType())
760 return op.
emitError(
"varType must capture the element type of var");
765template <
typename Op>
767 if (op.getVar().getType() != op.getAccVar().getType())
768 return op.
emitError(
"input and output types must match");
773template <
typename Op>
775 if (op.getModifiers() != acc::DataClauseModifier::none)
776 return op.
emitError(
"no data clause modifiers are allowed");
780template <
typename Op>
783 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
785 "invalid data clause modifiers: " +
786 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
791template <
typename OpT,
typename RecipeOpT>
792static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
797 !std::is_same_v<OpT, acc::ReductionOp>)
800 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
802 return op->emitOpError() <<
"recipe expected for " << operandName;
807 return op->emitOpError()
808 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
809 << operandName <<
" declaration";
830 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
851 if (failed(parser.
parseType(accVarType)))
861 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
873 mlir::TypeAttr &varTypeAttr) {
874 if (failed(parser.
parseType(varPtrType)))
885 varTypeAttr = mlir::TypeAttr::get(varType);
890 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
891 Type elementType = ptrTy.getElementType();
894 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
896 varTypeAttr = mlir::TypeAttr::get(varPtrType);
904 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
912 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
913 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
917 if (!typeToCheckAgainst)
918 typeToCheckAgainst = varPtrType;
919 if (typeToCheckAgainst != varType) {
927 mlir::SymbolRefAttr &recipeAttr) {
934 mlir::SymbolRefAttr recipeAttr) {
941LogicalResult acc::DataBoundsOp::verify() {
942 auto extent = getExtent();
943 auto upperbound = getUpperbound();
944 if (!extent && !upperbound)
945 return emitError(
"expected extent or upperbound.");
952LogicalResult acc::PrivateOp::verify() {
955 "data clause associated with private operation must match its intent");
969LogicalResult acc::FirstprivateOp::verify() {
971 return emitError(
"data clause associated with firstprivate operation must "
978 *
this,
"firstprivate")))
986LogicalResult acc::ReductionOp::verify() {
988 return emitError(
"data clause associated with reduction operation must "
995 *
this,
"reduction")))
1003LogicalResult acc::DevicePtrOp::verify() {
1005 return emitError(
"data clause associated with deviceptr operation must "
1006 "match its intent");
1019LogicalResult acc::PresentOp::verify() {
1022 "data clause associated with present operation must match its intent");
1035LogicalResult acc::CopyinOp::verify() {
1037 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
1042 "data clause associated with copyin operation must match its intent"
1043 " or specify original clause this operation was decomposed from");
1049 acc::DataClauseModifier::always |
1050 acc::DataClauseModifier::capture)))
1055bool acc::CopyinOp::isCopyinReadonly() {
1056 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
1057 acc::bitEnumContainsAny(getModifiers(),
1058 acc::DataClauseModifier::readonly);
1064LogicalResult acc::CreateOp::verify() {
1071 "data clause associated with create operation must match its intent"
1072 " or specify original clause this operation was decomposed from");
1080 acc::DataClauseModifier::always |
1081 acc::DataClauseModifier::capture)))
1086bool acc::CreateOp::isCreateZero() {
1088 return getDataClause() == acc::DataClause::acc_create_zero ||
1090 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1096LogicalResult acc::NoCreateOp::verify() {
1098 return emitError(
"data clause associated with no_create operation must "
1099 "match its intent");
1112LogicalResult acc::AttachOp::verify() {
1115 "data clause associated with attach operation must match its intent");
1129LogicalResult acc::DeclareDeviceResidentOp::verify() {
1130 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
1131 return emitError(
"data clause associated with device_resident operation "
1132 "must match its intent");
1146LogicalResult acc::DeclareLinkOp::verify() {
1149 "data clause associated with link operation must match its intent");
1162LogicalResult acc::CopyoutOp::verify() {
1169 "data clause associated with copyout operation must match its intent"
1170 " or specify original clause this operation was decomposed from");
1172 return emitError(
"must have both host and device pointers");
1178 acc::DataClauseModifier::always |
1179 acc::DataClauseModifier::capture)))
1184bool acc::CopyoutOp::isCopyoutZero() {
1185 return getDataClause() == acc::DataClause::acc_copyout_zero ||
1186 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1192LogicalResult acc::DeleteOp::verify() {
1201 getDataClause() != acc::DataClause::acc_declare_device_resident &&
1204 "data clause associated with delete operation must match its intent"
1205 " or specify original clause this operation was decomposed from");
1207 return emitError(
"must have device pointer");
1211 acc::DataClauseModifier::readonly |
1212 acc::DataClauseModifier::always |
1213 acc::DataClauseModifier::capture)))
1221LogicalResult acc::DetachOp::verify() {
1226 "data clause associated with detach operation must match its intent"
1227 " or specify original clause this operation was decomposed from");
1229 return emitError(
"must have device pointer");
1238LogicalResult acc::UpdateHostOp::verify() {
1243 "data clause associated with host operation must match its intent"
1244 " or specify original clause this operation was decomposed from");
1246 return emitError(
"must have both host and device pointers");
1259LogicalResult acc::UpdateDeviceOp::verify() {
1263 "data clause associated with device operation must match its intent"
1264 " or specify original clause this operation was decomposed from");
1277LogicalResult acc::UseDeviceOp::verify() {
1281 "data clause associated with use_device operation must match its intent"
1282 " or specify original clause this operation was decomposed from");
1295LogicalResult acc::CacheOp::verify() {
1300 "data clause associated with cache operation must match its intent"
1301 " or specify original clause this operation was decomposed from");
1311bool acc::CacheOp::isCacheReadonly() {
1312 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1313 acc::bitEnumContainsAny(getModifiers(),
1314 acc::DataClauseModifier::readonly);
1330template <
typename EffectTy>
1335 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1336 effects.emplace_back(EffectTy::get(), &operand[i]);
1340template <
typename EffectTy>
1345 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1349void acc::PrivateOp::getEffects(
1363void acc::FirstprivateOp::getEffects(
1377void acc::ReductionOp::getEffects(
1391void acc::DevicePtrOp::getEffects(
1400void acc::PresentOp::getEffects(
1411void acc::CopyinOp::getEffects(
1424void acc::CreateOp::getEffects(
1437void acc::NoCreateOp::getEffects(
1448void acc::AttachOp::getEffects(
1461void acc::GetDevicePtrOp::getEffects(
1470void acc::UpdateDeviceOp::getEffects(
1480void acc::UseDeviceOp::getEffects(
1489void acc::DeclareDeviceResidentOp::getEffects(
1500void acc::DeclareLinkOp::getEffects(
1511void acc::CacheOp::getEffects(
1516void acc::CopyoutOp::getEffects(
1529void acc::DeleteOp::getEffects(
1541void acc::DetachOp::getEffects(
1553void acc::UpdateHostOp::getEffects(
1565template <
typename StructureOp>
1567 unsigned nRegions = 1) {
1570 for (
unsigned i = 0; i < nRegions; ++i)
1573 for (
Region *region : regions)
1584template <
typename OpTy>
1586 using OpRewritePattern<OpTy>::OpRewritePattern;
1588 LogicalResult matchAndRewrite(OpTy op,
1589 PatternRewriter &rewriter)
const override {
1591 Value ifCond = op.getIfCond();
1595 IntegerAttr constAttr;
1598 if (constAttr.getInt())
1599 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1611 assert(region.
hasOneBlock() &&
"expected single-block region");
1623template <
typename OpTy>
1624struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1625 using OpRewritePattern<OpTy>::OpRewritePattern;
1627 LogicalResult matchAndRewrite(OpTy op,
1628 PatternRewriter &rewriter)
const override {
1630 Value ifCond = op.getIfCond();
1634 IntegerAttr constAttr;
1637 if (constAttr.getInt())
1638 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1666 for (
Value bound : bounds) {
1667 argTypes.push_back(bound.getType());
1668 argLocs.push_back(loc);
1675 Value privatizedValue;
1681 if (isa<MappableType>(varType)) {
1682 auto mappableTy = cast<MappableType>(varType);
1683 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1684 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1685 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1686 privatizedValue = mappableTy.generatePrivateInit(
1687 builder, loc, typedVar, varName, bounds, {}, varInfo, needsFree);
1688 if (!privatizedValue)
1691 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1692 auto pointerLikeTy = cast<PointerLikeType>(varType);
1694 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1695 blockArgVar, needsFree);
1696 if (!privatizedValue)
1701 acc::YieldOp::create(builder, loc, privatizedValue);
1718 for (
Value bound : bounds) {
1719 copyArgTypes.push_back(bound.getType());
1720 copyArgLocs.push_back(loc);
1730 if (isa<MappableType>(varType)) {
1731 auto mappableTy = cast<MappableType>(varType);
1734 if (!mappableTy.generateCopy(
1739 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1740 auto pointerLikeTy = cast<PointerLikeType>(varType);
1741 if (!pointerLikeTy.genCopy(
1748 acc::TerminatorOp::create(builder, loc);
1765 for (
Value bound : bounds) {
1766 destroyArgTypes.push_back(bound.getType());
1767 destroyArgLocs.push_back(loc);
1771 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1775 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1776 if (isa<MappableType>(varType)) {
1777 auto mappableTy = cast<MappableType>(varType);
1778 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds,
1782 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1783 auto pointerLikeTy = cast<PointerLikeType>(varType);
1784 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1788 acc::TerminatorOp::create(builder, loc);
1799 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1801 if (optional && region.
empty())
1805 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1809 return op->
emitOpError() <<
"expects " << regionName
1812 << regionType <<
" type";
1815 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1816 if (yieldOp.getOperands().size() != 1 ||
1817 yieldOp.getOperands().getTypes()[0] != type)
1818 return op->
emitOpError() <<
"expects " << regionName
1820 "yield a value of the "
1821 << regionType <<
" type";
1827LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1829 "privatization",
"init",
getType(),
1833 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1839std::optional<PrivateRecipeOp>
1841 StringRef recipeName,
Value hostVar,
1846 bool isMappable = isa<MappableType>(varType);
1847 bool isPointerLike = isa<PointerLikeType>(varType);
1850 if (!isMappable && !isPointerLike)
1851 return std::nullopt;
1856 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1859 bool needsFree =
false;
1861 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1862 varName, bounds, needsFree, varInfo))) {
1864 return std::nullopt;
1871 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1872 Value allocRes = yieldOp.getOperand(0);
1874 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1875 varType, allocRes, bounds, varInfo))) {
1877 return std::nullopt;
1884std::optional<PrivateRecipeOp>
1886 StringRef recipeName,
1887 FirstprivateRecipeOp firstprivRecipe) {
1890 auto varType = firstprivRecipe.getType();
1891 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1895 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
1898 if (!firstprivRecipe.getDestroyRegion().empty()) {
1900 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
1910LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
1912 "privatization",
"init",
getType(),
1916 if (getCopyRegion().empty())
1917 return emitOpError() <<
"expects non-empty copy region";
1922 return emitOpError() <<
"expects copy region with two arguments of the "
1923 "privatization type";
1925 if (getDestroyRegion().empty())
1929 "privatization",
"destroy",
1936std::optional<FirstprivateRecipeOp>
1938 StringRef recipeName,
Value hostVar,
1943 bool isMappable = isa<MappableType>(varType);
1944 bool isPointerLike = isa<PointerLikeType>(varType);
1947 if (!isMappable && !isPointerLike)
1948 return std::nullopt;
1953 auto recipe = FirstprivateRecipeOp::create(builder, loc, recipeName, varType);
1956 bool needsFree =
false;
1961 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1962 varName, bounds, needsFree, varInfo))) {
1964 return std::nullopt;
1968 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
1969 bounds, varInfo))) {
1971 return std::nullopt;
1978 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1979 Value allocRes = yieldOp.getOperand(0);
1981 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1982 varType, allocRes, bounds, varInfo))) {
1984 return std::nullopt;
1995LogicalResult acc::ReductionRecipeOp::verifyRegions() {
2001 if (getCombinerRegion().empty())
2002 return emitOpError() <<
"expects non-empty combiner region";
2004 Block &reductionBlock = getCombinerRegion().
front();
2008 return emitOpError() <<
"expects combiner region with the first two "
2009 <<
"arguments of the reduction type";
2011 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
2012 if (yieldOp.getOperands().size() != 1 ||
2013 yieldOp.getOperands().getTypes()[0] !=
getType())
2014 return emitOpError() <<
"expects combiner region to yield a value "
2015 "of the reduction type";
2026template <
typename Op>
2030 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2031 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2032 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
2033 operand.getDefiningOp()))
2035 "expect data entry/exit operation or acc.getdeviceptr "
2040template <
typename OpT,
typename RecipeOpT>
2043 llvm::StringRef operandName) {
2046 if (!mlir::isa<OpT>(operand.getDefiningOp()))
2048 <<
"expected " << operandName <<
" as defining op";
2049 if (!set.insert(operand).second)
2051 << operandName <<
" operand appears more than once";
2056unsigned ParallelOp::getNumDataOperands() {
2057 return getReductionOperands().size() + getPrivateOperands().size() +
2058 getFirstprivateOperands().size() + getDataClauseOperands().size();
2061Value ParallelOp::getDataOperand(
unsigned i) {
2063 numOptional += getNumGangs().size();
2064 numOptional += getNumWorkers().size();
2065 numOptional += getVectorLength().size();
2066 numOptional += getIfCond() ? 1 : 0;
2067 numOptional += getSelfCond() ? 1 : 0;
2068 return getOperand(getWaitOperands().size() + numOptional + i);
2071template <
typename Op>
2074 llvm::StringRef keyword) {
2075 if (!operands.empty() &&
2076 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
2077 return op.
emitOpError() << keyword <<
" operands count must match "
2078 << keyword <<
" device_type count";
2082template <
typename Op>
2085 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
2086 std::size_t numOperandsInSegments = 0;
2087 std::size_t nbOfSegments = 0;
2090 for (
auto segCount : segments.
asArrayRef()) {
2091 if (maxInSegment != 0 && segCount > maxInSegment)
2092 return op.
emitOpError() << keyword <<
" expects a maximum of "
2093 << maxInSegment <<
" values per segment";
2094 numOperandsInSegments += segCount;
2099 if ((numOperandsInSegments != operands.size()) ||
2100 (!deviceTypes && !operands.empty()))
2102 << keyword <<
" operand count does not match count in segments";
2103 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
2105 << keyword <<
" segment count does not match device_type count";
2109LogicalResult acc::ParallelOp::verify() {
2111 mlir::acc::PrivateRecipeOp>(
2112 *
this, getPrivateOperands(),
"private")))
2115 mlir::acc::FirstprivateRecipeOp>(
2116 *
this, getFirstprivateOperands(),
"firstprivate")))
2119 mlir::acc::ReductionRecipeOp>(
2120 *
this, getReductionOperands(),
"reduction")))
2124 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2125 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2129 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2130 getWaitOperandsDeviceTypeAttr(),
"wait")))
2134 getNumWorkersDeviceTypeAttr(),
2139 getVectorLengthDeviceTypeAttr(),
2144 getAsyncOperandsDeviceTypeAttr(),
2157 mlir::acc::DeviceType deviceType) {
2160 if (
auto pos =
findSegment(*arrayAttr, deviceType))
2165bool acc::ParallelOp::hasAsyncOnly() {
2166 return hasAsyncOnly(mlir::acc::DeviceType::None);
2169bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2174 return getAsyncValue(mlir::acc::DeviceType::None);
2177mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2182mlir::Value acc::ParallelOp::getNumWorkersValue() {
2183 return getNumWorkersValue(mlir::acc::DeviceType::None);
2187acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2192mlir::Value acc::ParallelOp::getVectorLengthValue() {
2193 return getVectorLengthValue(mlir::acc::DeviceType::None);
2197acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2199 getVectorLength(), deviceType);
2203 return getNumGangsValues(mlir::acc::DeviceType::None);
2207ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2209 getNumGangsSegments(), deviceType);
2213 std::optional<mlir::ArrayAttr> numGangsDeviceType,
2216 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
2218 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
2220 mlir::acc::DeviceType deviceType) {
2230bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2232 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2233 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2234 getVectorLength(), deviceType);
2237bool acc::ParallelOp::isEffectivelySerial() {
2241bool acc::ParallelOp::hasWaitOnly() {
2242 return hasWaitOnly(mlir::acc::DeviceType::None);
2245bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2250 return getWaitValues(mlir::acc::DeviceType::None);
2254ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2256 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2257 getHasWaitDevnum(), deviceType);
2261 return getWaitDevnum(mlir::acc::DeviceType::None);
2264mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2266 getWaitOperandsSegments(), getHasWaitDevnum(),
2281 odsBuilder, odsState, asyncOperands,
nullptr,
2282 nullptr, waitOperands,
nullptr,
2284 nullptr, numGangs,
nullptr,
2285 nullptr, numWorkers,
2286 nullptr, vectorLength,
2287 nullptr, ifCond, selfCond,
2288 nullptr, reductionOperands, gangPrivateOperands,
2289 gangFirstPrivateOperands, dataClauseOperands,
2293void acc::ParallelOp::addNumWorkersOperand(
2296 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2297 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2298 getNumWorkersMutable()));
2300void acc::ParallelOp::addVectorLengthOperand(
2303 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2304 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2305 getVectorLengthMutable()));
2308void acc::ParallelOp::addAsyncOnly(
2310 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2311 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2314void acc::ParallelOp::addAsyncOperand(
2317 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2318 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2319 getAsyncOperandsMutable()));
2322void acc::ParallelOp::addNumGangsOperands(
2326 if (getNumGangsSegments())
2327 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2329 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2330 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2331 getNumGangsMutable(), segments));
2333 setNumGangsSegments(segments);
2335void acc::ParallelOp::addWaitOnly(
2337 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2338 effectiveDeviceTypes));
2340void acc::ParallelOp::addWaitOperands(
2345 if (getWaitOperandsSegments())
2346 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2348 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2349 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2350 getWaitOperandsMutable(), segments));
2351 setWaitOperandsSegments(segments);
2354 if (getHasWaitDevnumAttr())
2355 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2358 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2360 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2363void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2364 mlir::acc::PrivateOp op,
2365 mlir::acc::PrivateRecipeOp recipe) {
2366 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2367 getPrivateOperandsMutable().append(op.getResult());
2370void acc::ParallelOp::addFirstPrivatization(
2371 MLIRContext *context, mlir::acc::FirstprivateOp op,
2372 mlir::acc::FirstprivateRecipeOp recipe) {
2373 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2374 getFirstprivateOperandsMutable().append(op.getResult());
2377void acc::ParallelOp::addReduction(
MLIRContext *context,
2378 mlir::acc::ReductionOp op,
2379 mlir::acc::ReductionRecipeOp recipe) {
2380 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2381 getReductionOperandsMutable().append(op.getResult());
2396 int32_t crtOperandsSize = operands.size();
2399 if (parser.parseOperand(operands.emplace_back()) ||
2400 parser.parseColonType(types.emplace_back()))
2405 seg.push_back(operands.size() - crtOperandsSize);
2415 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2416 parser.
getContext(), mlir::acc::DeviceType::None));
2422 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2429 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2430 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2431 p <<
" [" << attr <<
"]";
2436 std::optional<mlir::ArrayAttr> deviceTypes,
2437 std::optional<mlir::DenseI32ArrayAttr> segments) {
2439 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2441 llvm::interleaveComma(
2442 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2443 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2463 int32_t crtOperandsSize = operands.size();
2467 if (parser.parseOperand(operands.emplace_back()) ||
2468 parser.parseColonType(types.emplace_back()))
2474 seg.push_back(operands.size() - crtOperandsSize);
2484 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2485 parser.
getContext(), mlir::acc::DeviceType::None));
2491 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2500 std::optional<mlir::DenseI32ArrayAttr> segments) {
2502 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2504 llvm::interleaveComma(
2505 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2506 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2519 mlir::ArrayAttr &keywordOnly) {
2523 bool needCommaBeforeOperands =
false;
2527 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2528 parser.
getContext(), mlir::acc::DeviceType::None));
2529 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2536 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2543 needCommaBeforeOperands =
true;
2546 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2553 int32_t crtOperandsSize = operands.size();
2565 if (parser.parseOperand(operands.emplace_back()) ||
2566 parser.parseColonType(types.emplace_back()))
2572 seg.push_back(operands.size() - crtOperandsSize);
2582 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2583 parser.
getContext(), mlir::acc::DeviceType::None));
2590 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2591 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2593 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2601 if (attrs->size() != 1)
2603 if (
auto deviceTypeAttr =
2604 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2605 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2611 std::optional<mlir::ArrayAttr> deviceTypes,
2612 std::optional<mlir::DenseI32ArrayAttr> segments,
2613 std::optional<mlir::ArrayAttr> hasDevNum,
2614 std::optional<mlir::ArrayAttr> keywordOnly) {
2627 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2629 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2630 if (boolAttr && boolAttr.getValue())
2632 llvm::interleaveComma(
2633 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2634 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2651 if (parser.parseOperand(operands.emplace_back()) ||
2652 parser.parseColonType(types.emplace_back()))
2654 if (succeeded(parser.parseOptionalLSquare())) {
2655 if (parser.parseAttribute(attributes.emplace_back()) ||
2656 parser.parseRSquare())
2659 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2660 parser.getContext(), mlir::acc::DeviceType::None));
2667 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2674 std::optional<mlir::ArrayAttr> deviceTypes) {
2677 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2678 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2687 mlir::ArrayAttr &keywordOnlyDeviceType) {
2690 bool needCommaBeforeOperands =
false;
2694 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2695 parser.
getContext(), mlir::acc::DeviceType::None));
2696 keywordOnlyDeviceType =
2697 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2705 if (parser.parseAttribute(
2706 keywordOnlyDeviceTypeAttributes.emplace_back()))
2713 needCommaBeforeOperands =
true;
2716 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2721 if (parser.parseOperand(operands.emplace_back()) ||
2722 parser.parseColonType(types.emplace_back()))
2724 if (succeeded(parser.parseOptionalLSquare())) {
2725 if (parser.parseAttribute(attributes.emplace_back()) ||
2726 parser.parseRSquare())
2729 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2730 parser.getContext(), mlir::acc::DeviceType::None));
2736 if (
failed(parser.parseRParen()))
2741 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2748 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2750 if (operands.begin() == operands.end() &&
2766 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2767 mlir::Type &operandType, mlir::UnitAttr &attr) {
2770 attr = mlir::UnitAttr::get(parser.
getContext());
2780 if (failed(parser.
parseType(operandType)))
2790 std::optional<mlir::Value> operand,
2792 mlir::UnitAttr attr) {
2809 attr = mlir::UnitAttr::get(parser.
getContext());
2814 if (parser.parseOperand(operands.emplace_back()))
2822 if (parser.parseType(types.emplace_back()))
2837 mlir::UnitAttr attr) {
2842 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2844 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2850 mlir::acc::CombinedConstructsTypeAttr &attr) {
2852 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2853 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2855 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2856 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2858 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2859 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2862 "expected compute construct name");
2870 mlir::acc::CombinedConstructsTypeAttr attr) {
2872 switch (attr.getValue()) {
2873 case mlir::acc::CombinedConstructsType::KernelsLoop:
2876 case mlir::acc::CombinedConstructsType::ParallelLoop:
2879 case mlir::acc::CombinedConstructsType::SerialLoop:
2890unsigned SerialOp::getNumDataOperands() {
2891 return getReductionOperands().size() + getPrivateOperands().size() +
2892 getFirstprivateOperands().size() + getDataClauseOperands().size();
2895Value SerialOp::getDataOperand(
unsigned i) {
2897 numOptional += getIfCond() ? 1 : 0;
2898 numOptional += getSelfCond() ? 1 : 0;
2899 return getOperand(getWaitOperands().size() + numOptional + i);
2902bool acc::SerialOp::hasAsyncOnly() {
2903 return hasAsyncOnly(mlir::acc::DeviceType::None);
2906bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2911 return getAsyncValue(mlir::acc::DeviceType::None);
2914mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2919bool acc::SerialOp::hasWaitOnly() {
2920 return hasWaitOnly(mlir::acc::DeviceType::None);
2923bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2928 return getWaitValues(mlir::acc::DeviceType::None);
2932SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2934 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2935 getHasWaitDevnum(), deviceType);
2939 return getWaitDevnum(mlir::acc::DeviceType::None);
2942mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2944 getWaitOperandsSegments(), getHasWaitDevnum(),
2948LogicalResult acc::SerialOp::verify() {
2950 mlir::acc::PrivateRecipeOp>(
2951 *
this, getPrivateOperands(),
"private")))
2954 mlir::acc::FirstprivateRecipeOp>(
2955 *
this, getFirstprivateOperands(),
"firstprivate")))
2958 mlir::acc::ReductionRecipeOp>(
2959 *
this, getReductionOperands(),
"reduction")))
2963 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2964 getWaitOperandsDeviceTypeAttr(),
"wait")))
2968 getAsyncOperandsDeviceTypeAttr(),
2978void acc::SerialOp::addAsyncOnly(
2980 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2981 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2984void acc::SerialOp::addAsyncOperand(
2987 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2988 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2989 getAsyncOperandsMutable()));
2992void acc::SerialOp::addWaitOnly(
2994 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2995 effectiveDeviceTypes));
2997void acc::SerialOp::addWaitOperands(
3002 if (getWaitOperandsSegments())
3003 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3005 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3006 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3007 getWaitOperandsMutable(), segments));
3008 setWaitOperandsSegments(segments);
3011 if (getHasWaitDevnumAttr())
3012 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3015 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3017 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3020void acc::SerialOp::addPrivatization(
MLIRContext *context,
3021 mlir::acc::PrivateOp op,
3022 mlir::acc::PrivateRecipeOp recipe) {
3023 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3024 getPrivateOperandsMutable().append(op.getResult());
3027void acc::SerialOp::addFirstPrivatization(
3028 MLIRContext *context, mlir::acc::FirstprivateOp op,
3029 mlir::acc::FirstprivateRecipeOp recipe) {
3030 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3031 getFirstprivateOperandsMutable().append(op.getResult());
3034void acc::SerialOp::addReduction(
MLIRContext *context,
3035 mlir::acc::ReductionOp op,
3036 mlir::acc::ReductionRecipeOp recipe) {
3037 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3038 getReductionOperandsMutable().append(op.getResult());
3045unsigned KernelsOp::getNumDataOperands() {
3046 return getDataClauseOperands().size();
3049Value KernelsOp::getDataOperand(
unsigned i) {
3051 numOptional += getWaitOperands().size();
3052 numOptional += getNumGangs().size();
3053 numOptional += getNumWorkers().size();
3054 numOptional += getVectorLength().size();
3055 numOptional += getIfCond() ? 1 : 0;
3056 numOptional += getSelfCond() ? 1 : 0;
3057 return getOperand(numOptional + i);
3060bool acc::KernelsOp::hasAsyncOnly() {
3061 return hasAsyncOnly(mlir::acc::DeviceType::None);
3064bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3069 return getAsyncValue(mlir::acc::DeviceType::None);
3072mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3078 return getNumWorkersValue(mlir::acc::DeviceType::None);
3082acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
3087mlir::Value acc::KernelsOp::getVectorLengthValue() {
3088 return getVectorLengthValue(mlir::acc::DeviceType::None);
3092acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
3094 getVectorLength(), deviceType);
3098 return getNumGangsValues(mlir::acc::DeviceType::None);
3102KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
3104 getNumGangsSegments(), deviceType);
3107bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
3109 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
3110 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
3111 getVectorLength(), deviceType);
3114bool acc::KernelsOp::isEffectivelySerial() {
3118bool acc::KernelsOp::hasWaitOnly() {
3119 return hasWaitOnly(mlir::acc::DeviceType::None);
3122bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3127 return getWaitValues(mlir::acc::DeviceType::None);
3131KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3133 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3134 getHasWaitDevnum(), deviceType);
3138 return getWaitDevnum(mlir::acc::DeviceType::None);
3141mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3143 getWaitOperandsSegments(), getHasWaitDevnum(),
3147LogicalResult acc::KernelsOp::verify() {
3149 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
3150 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
3154 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3155 getWaitOperandsDeviceTypeAttr(),
"wait")))
3159 getNumWorkersDeviceTypeAttr(),
3164 getVectorLengthDeviceTypeAttr(),
3169 getAsyncOperandsDeviceTypeAttr(),
3179void acc::KernelsOp::addPrivatization(
MLIRContext *context,
3180 mlir::acc::PrivateOp op,
3181 mlir::acc::PrivateRecipeOp recipe) {
3182 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3183 getPrivateOperandsMutable().append(op.getResult());
3186void acc::KernelsOp::addFirstPrivatization(
3187 MLIRContext *context, mlir::acc::FirstprivateOp op,
3188 mlir::acc::FirstprivateRecipeOp recipe) {
3189 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3190 getFirstprivateOperandsMutable().append(op.getResult());
3193void acc::KernelsOp::addReduction(
MLIRContext *context,
3194 mlir::acc::ReductionOp op,
3195 mlir::acc::ReductionRecipeOp recipe) {
3196 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3197 getReductionOperandsMutable().append(op.getResult());
3200void acc::KernelsOp::addNumWorkersOperand(
3203 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3204 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3205 getNumWorkersMutable()));
3208void acc::KernelsOp::addVectorLengthOperand(
3211 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3212 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3213 getVectorLengthMutable()));
3215void acc::KernelsOp::addAsyncOnly(
3217 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3218 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3221void acc::KernelsOp::addAsyncOperand(
3224 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3225 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3226 getAsyncOperandsMutable()));
3229void acc::KernelsOp::addNumGangsOperands(
3233 if (getNumGangsSegmentsAttr())
3234 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3236 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3237 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3238 getNumGangsMutable(), segments));
3240 setNumGangsSegments(segments);
3243void acc::KernelsOp::addWaitOnly(
3245 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3246 effectiveDeviceTypes));
3248void acc::KernelsOp::addWaitOperands(
3253 if (getWaitOperandsSegments())
3254 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3256 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3257 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3258 getWaitOperandsMutable(), segments));
3259 setWaitOperandsSegments(segments);
3262 if (getHasWaitDevnumAttr())
3263 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3266 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3268 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3275LogicalResult acc::HostDataOp::verify() {
3276 if (getDataClauseOperands().empty())
3277 return emitError(
"at least one operand must appear on the host_data "
3281 for (
mlir::Value operand : getDataClauseOperands()) {
3283 mlir::dyn_cast<acc::UseDeviceOp>(operand.getDefiningOp());
3285 return emitError(
"expect data entry operation as defining op");
3288 if (!seenVars.insert(useDeviceOp.getVar()).second)
3289 return emitError(
"duplicate use_device variable");
3296 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3308 bool &needCommaBetweenValues,
bool &newValue) {
3315 attributes.push_back(gangArgType);
3316 needCommaBetweenValues =
true;
3327 mlir::ArrayAttr &gangOnlyDeviceType) {
3332 bool needCommaBetweenValues =
false;
3333 bool needCommaBeforeOperands =
false;
3337 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3338 parser.
getContext(), mlir::acc::DeviceType::None));
3339 gangOnlyDeviceType =
3340 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3348 if (parser.parseAttribute(
3349 gangOnlyDeviceTypeAttributes.emplace_back()))
3356 needCommaBeforeOperands =
true;
3359 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3360 mlir::acc::GangArgType::Num);
3361 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3362 mlir::acc::GangArgType::Dim);
3363 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3364 parser.
getContext(), mlir::acc::GangArgType::Static);
3367 if (needCommaBeforeOperands) {
3368 needCommaBeforeOperands =
false;
3375 int32_t crtOperandsSize = gangOperands.size();
3377 bool newValue =
false;
3378 bool needValue =
false;
3379 if (needCommaBetweenValues) {
3387 gangOperands, gangOperandsType,
3388 gangArgTypeAttributes, argNum,
3389 needCommaBetweenValues, newValue)))
3392 gangOperands, gangOperandsType,
3393 gangArgTypeAttributes, argDim,
3394 needCommaBetweenValues, newValue)))
3396 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3397 gangOperands, gangOperandsType,
3398 gangArgTypeAttributes, argStatic,
3399 needCommaBetweenValues, newValue)))
3402 if (!newValue && needValue) {
3404 "new value expected after comma");
3412 if (gangOperands.empty())
3415 "expect at least one of num, dim or static values");
3421 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3425 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3426 parser.
getContext(), mlir::acc::DeviceType::None));
3429 seg.push_back(gangOperands.size() - crtOperandsSize);
3437 gangArgTypeAttributes.end());
3438 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3439 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3442 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3443 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3451 std::optional<mlir::ArrayAttr> gangArgTypes,
3452 std::optional<mlir::ArrayAttr> deviceTypes,
3453 std::optional<mlir::DenseI32ArrayAttr> segments,
3454 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3456 if (operands.begin() == operands.end() &&
3471 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3473 llvm::interleaveComma(
3474 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3475 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3476 (*gangArgTypes)[opIdx]);
3477 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3478 p << LoopOp::getGangNumKeyword();
3479 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3480 p << LoopOp::getGangDimKeyword();
3481 else if (gangArgTypeAttr.getValue() ==
3482 mlir::acc::GangArgType::Static)
3483 p << LoopOp::getGangStaticKeyword();
3484 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3495 std::optional<mlir::ArrayAttr> segments,
3496 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3499 for (
auto attr : *segments) {
3500 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3501 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3509static std::optional<mlir::acc::DeviceType>
3511 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3513 return std::nullopt;
3514 for (
auto attr : deviceTypes) {
3515 auto deviceTypeAttr =
3516 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3517 if (!deviceTypeAttr)
3518 return mlir::acc::DeviceType::None;
3519 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3520 return deviceTypeAttr.getValue();
3522 return std::nullopt;
3525LogicalResult acc::LoopOp::verify() {
3526 if (getUpperbound().size() != getStep().size())
3527 return emitError() <<
"number of upperbounds expected to be the same as "
3530 if (getUpperbound().size() != getLowerbound().size())
3531 return emitError() <<
"number of upperbounds expected to be the same as "
3532 "number of lowerbounds";
3534 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3535 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3536 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3537 <<
" as upperbound size";
3540 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3541 return emitOpError() <<
"collapse device_type attr must be define when"
3542 <<
" collapse attr is present";
3544 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3545 getCollapseAttr().getValue().size() !=
3546 getCollapseDeviceTypeAttr().getValue().size())
3547 return emitOpError() <<
"collapse attribute count must match collapse"
3548 <<
" device_type count";
3549 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3551 << acc::stringifyDeviceType(*duplicateDeviceType)
3552 <<
"` found in collapseDeviceType attribute";
3555 if (!getGangOperands().empty()) {
3556 if (!getGangOperandsArgType())
3557 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3558 <<
" when gang operands are present";
3560 if (getGangOperands().size() !=
3561 getGangOperandsArgTypeAttr().getValue().size())
3562 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3563 <<
" gangOperands count";
3565 if (getGangAttr()) {
3568 << acc::stringifyDeviceType(*duplicateDeviceType)
3569 <<
"` found in gang attribute";
3573 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3574 getGangOperandsDeviceTypeAttr(),
"gang")))
3580 << acc::stringifyDeviceType(*duplicateDeviceType)
3581 <<
"` found in worker attribute";
3582 if (
auto duplicateDeviceType =
3585 << acc::stringifyDeviceType(*duplicateDeviceType)
3586 <<
"` found in workerNumOperandsDeviceType attribute";
3588 getWorkerNumOperandsDeviceTypeAttr(),
3595 << acc::stringifyDeviceType(*duplicateDeviceType)
3596 <<
"` found in vector attribute";
3597 if (
auto duplicateDeviceType =
3600 << acc::stringifyDeviceType(*duplicateDeviceType)
3601 <<
"` found in vectorOperandsDeviceType attribute";
3603 getVectorOperandsDeviceTypeAttr(),
3608 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3609 getTileOperandsDeviceTypeAttr(),
"tile")))
3613 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3617 return emitError() <<
"only one of auto, independent, seq can be present "
3623 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3624 return attr.getValue() == mlir::acc::DeviceType::None;
3626 bool hasDefaultSeq =
3628 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3631 bool hasDefaultIndependent =
3632 getIndependentAttr()
3634 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3637 bool hasDefaultAuto =
3639 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3642 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3644 <<
"at least one of auto, independent, seq must be present";
3649 for (
auto attr : getSeqAttr()) {
3650 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3651 if (hasVector(deviceTypeAttr.getValue()) ||
3652 getVectorValue(deviceTypeAttr.getValue()) ||
3653 hasWorker(deviceTypeAttr.getValue()) ||
3654 getWorkerValue(deviceTypeAttr.getValue()) ||
3655 hasGang(deviceTypeAttr.getValue()) ||
3656 getGangValue(mlir::acc::GangArgType::Num,
3657 deviceTypeAttr.getValue()) ||
3658 getGangValue(mlir::acc::GangArgType::Dim,
3659 deviceTypeAttr.getValue()) ||
3660 getGangValue(mlir::acc::GangArgType::Static,
3661 deviceTypeAttr.getValue()))
3662 return emitError() <<
"gang, worker or vector cannot appear with seq";
3667 mlir::acc::PrivateRecipeOp>(
3668 *
this, getPrivateOperands(),
"private")))
3672 mlir::acc::FirstprivateRecipeOp>(
3673 *
this, getFirstprivateOperands(),
"firstprivate")))
3677 mlir::acc::ReductionRecipeOp>(
3678 *
this, getReductionOperands(),
"reduction")))
3681 if (getCombined().has_value() &&
3682 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3683 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3684 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3685 return emitError(
"unexpected combined constructs attribute");
3689 if (getRegion().empty())
3690 return emitError(
"expected non-empty body.");
3692 if (getUnstructured()) {
3693 if (!isContainerLike())
3695 "unstructured acc.loop must not have induction variables");
3696 }
else if (isContainerLike()) {
3700 uint64_t collapseCount = getCollapseValue().value_or(1);
3701 if (getCollapseAttr()) {
3702 for (
auto collapseEntry : getCollapseAttr()) {
3703 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3704 if (intAttr.getValue().getZExtValue() > collapseCount)
3705 collapseCount = intAttr.getValue().getZExtValue();
3713 bool foundSibling =
false;
3715 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3717 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3719 foundSibling =
true;
3724 expectedParent = op;
3727 if (collapseCount == 0)
3733 return emitError(
"found sibling loops inside container-like acc.loop");
3734 if (collapseCount != 0)
3735 return emitError(
"failed to find enough loop-like operations inside "
3736 "container-like acc.loop");
3742unsigned LoopOp::getNumDataOperands() {
3743 return getReductionOperands().size() + getPrivateOperands().size() +
3744 getFirstprivateOperands().size();
3747Value LoopOp::getDataOperand(
unsigned i) {
3748 unsigned numOptional =
3749 getLowerbound().size() + getUpperbound().size() + getStep().size();
3750 numOptional += getGangOperands().size();
3751 numOptional += getVectorOperands().size();
3752 numOptional += getWorkerNumOperands().size();
3753 numOptional += getTileOperands().size();
3754 numOptional += getCacheOperands().size();
3755 return getOperand(numOptional + i);
3758bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3760bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3764bool LoopOp::hasIndependent() {
3765 return hasIndependent(mlir::acc::DeviceType::None);
3768bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3772bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3774bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3779 return getVectorValue(mlir::acc::DeviceType::None);
3782mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3784 getVectorOperands(), deviceType);
3787bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3789bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3794 return getWorkerValue(mlir::acc::DeviceType::None);
3797mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3799 getWorkerNumOperands(), deviceType);
3802bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3804bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3809 return getTileValues(mlir::acc::DeviceType::None);
3813LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3815 getTileOperandsSegments(), deviceType);
3818std::optional<int64_t> LoopOp::getCollapseValue() {
3819 return getCollapseValue(mlir::acc::DeviceType::None);
3822std::optional<int64_t>
3823LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3824 if (!getCollapseAttr())
3825 return std::nullopt;
3826 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3828 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3829 return intAttr.getValue().getZExtValue();
3831 return std::nullopt;
3834mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3835 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3838mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3839 mlir::acc::DeviceType deviceType) {
3840 if (getGangOperands().empty())
3842 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3843 int32_t nbOperandsBefore = 0;
3844 for (
unsigned i = 0; i < *pos; ++i)
3845 nbOperandsBefore += (*getGangOperandsSegments())[i];
3848 .drop_front(nbOperandsBefore)
3849 .take_front((*getGangOperandsSegments())[*pos]);
3851 int32_t argTypeIdx = nbOperandsBefore;
3852 for (
auto value : values) {
3853 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3854 (*getGangOperandsArgType())[argTypeIdx]);
3855 if (gangArgTypeAttr.getValue() == gangArgType)
3863bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
3865bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
3870 return {&getRegion()};
3914 if (!regionArgs.empty()) {
3915 p << acc::LoopOp::getControlKeyword() <<
"(";
3916 llvm::interleaveComma(regionArgs, p,
3918 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
3919 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
3920 <<
" : " << stepType <<
") ";
3927 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
3928 effectiveDeviceTypes));
3931void acc::LoopOp::addIndependent(
3933 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
3934 context, getIndependentAttr(), effectiveDeviceTypes));
3939 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
3940 effectiveDeviceTypes));
3943void acc::LoopOp::setCollapseForDeviceTypes(
3945 llvm::APInt value) {
3949 assert((getCollapseAttr() ==
nullptr) ==
3950 (getCollapseDeviceTypeAttr() ==
nullptr));
3951 assert(value.getBitWidth() == 64);
3953 if (getCollapseAttr()) {
3954 for (
const auto &existing :
3955 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
3956 newValues.push_back(std::get<0>(existing));
3957 newDeviceTypes.push_back(std::get<1>(existing));
3961 if (effectiveDeviceTypes.empty()) {
3964 newValues.push_back(
3965 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3966 newDeviceTypes.push_back(
3967 acc::DeviceTypeAttr::get(context, DeviceType::None));
3969 for (DeviceType dt : effectiveDeviceTypes) {
3970 newValues.push_back(
3971 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3972 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
3976 setCollapseAttr(ArrayAttr::get(context, newValues));
3977 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
3980void acc::LoopOp::setTileForDeviceTypes(
3984 if (getTileOperandsSegments())
3985 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
3987 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3988 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
3989 getTileOperandsMutable(), segments));
3991 setTileOperandsSegments(segments);
3994void acc::LoopOp::addVectorOperand(
3997 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3998 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
3999 newValue, getVectorOperandsMutable()));
4002void acc::LoopOp::addEmptyVector(
4004 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4005 effectiveDeviceTypes));
4008void acc::LoopOp::addWorkerNumOperand(
4011 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4012 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4013 newValue, getWorkerNumOperandsMutable()));
4016void acc::LoopOp::addEmptyWorker(
4018 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4019 effectiveDeviceTypes));
4022void acc::LoopOp::addEmptyGang(
4024 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4025 effectiveDeviceTypes));
4028bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
4029 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
4030 return attr.getValue() == dt;
4032 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
4033 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
4036 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
4038 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
4040 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
4046bool acc::LoopOp::hasDefaultGangWorkerVector() {
4047 return hasAnyGangWorkerVector(DeviceType::None);
4050bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
4051 return hasVector(deviceType) || getVectorValue(deviceType) ||
4052 hasWorker(deviceType) || getWorkerValue(deviceType) ||
4053 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
4054 getGangValue(GangArgType::Dim, deviceType) ||
4055 getGangValue(GangArgType::Static, deviceType);
4059acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
4060 if (hasSeq(deviceType))
4061 return LoopParMode::loop_seq;
4062 if (hasAuto(deviceType))
4063 return LoopParMode::loop_auto;
4064 if (hasIndependent(deviceType))
4065 return LoopParMode::loop_independent;
4067 return LoopParMode::loop_seq;
4069 return LoopParMode::loop_auto;
4070 assert(hasIndependent() &&
4071 "loop must have default auto, seq, or independent");
4072 return LoopParMode::loop_independent;
4075void acc::LoopOp::addGangOperands(
4080 getGangOperandsSegments())
4081 llvm::copy(*existingSegments, std::back_inserter(segments));
4083 unsigned beforeCount = segments.size();
4085 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4086 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4087 getGangOperandsMutable(), segments));
4089 setGangOperandsSegments(segments);
4096 unsigned numAdded = segments.size() - beforeCount;
4100 if (getGangOperandsArgTypeAttr())
4101 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
4103 for (
auto i : llvm::index_range(0u, numAdded)) {
4104 llvm::transform(argTypes, std::back_inserter(gangTypes),
4105 [=](mlir::acc::GangArgType gangTy) {
4106 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
4111 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
4115void acc::LoopOp::addPrivatization(
MLIRContext *context,
4116 mlir::acc::PrivateOp op,
4117 mlir::acc::PrivateRecipeOp recipe) {
4118 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4119 getPrivateOperandsMutable().append(op.getResult());
4122void acc::LoopOp::addFirstPrivatization(
4123 MLIRContext *context, mlir::acc::FirstprivateOp op,
4124 mlir::acc::FirstprivateRecipeOp recipe) {
4125 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4126 getFirstprivateOperandsMutable().append(op.getResult());
4129void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
4130 mlir::acc::ReductionRecipeOp recipe) {
4131 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4132 getReductionOperandsMutable().append(op.getResult());
4139LogicalResult acc::DataOp::verify() {
4144 return emitError(
"at least one operand or the default attribute "
4145 "must appear on the data operation");
4147 for (
mlir::Value operand : getDataClauseOperands())
4148 if (isa<BlockArgument>(operand) ||
4149 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4150 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
4151 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
4152 operand.getDefiningOp()))
4153 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4162unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
4164Value DataOp::getDataOperand(
unsigned i) {
4165 unsigned numOptional = getIfCond() ? 1 : 0;
4167 numOptional += getWaitOperands().size();
4168 return getOperand(numOptional + i);
4171bool acc::DataOp::hasAsyncOnly() {
4172 return hasAsyncOnly(mlir::acc::DeviceType::None);
4175bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4180 return getAsyncValue(mlir::acc::DeviceType::None);
4183mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4188bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
4190bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4195 return getWaitValues(mlir::acc::DeviceType::None);
4199DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4201 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4202 getHasWaitDevnum(), deviceType);
4206 return getWaitDevnum(mlir::acc::DeviceType::None);
4209mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4211 getWaitOperandsSegments(), getHasWaitDevnum(),
4215void acc::DataOp::addAsyncOnly(
4217 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4218 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4221void acc::DataOp::addAsyncOperand(
4224 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4225 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4226 getAsyncOperandsMutable()));
4229void acc::DataOp::addWaitOnly(
MLIRContext *context,
4231 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4232 effectiveDeviceTypes));
4235void acc::DataOp::addWaitOperands(
4240 if (getWaitOperandsSegments())
4241 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4243 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4244 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4245 getWaitOperandsMutable(), segments));
4246 setWaitOperandsSegments(segments);
4249 if (getHasWaitDevnumAttr())
4250 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4253 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4255 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4262LogicalResult acc::ExitDataOp::verify() {
4266 if (getDataClauseOperands().empty())
4267 return emitError(
"at least one operand must be present in dataOperands on "
4268 "the exit data operation");
4272 if (getAsyncOperand() && getAsync())
4273 return emitError(
"async attribute cannot appear with asyncOperand");
4277 if (!getWaitOperands().empty() && getWait())
4278 return emitError(
"wait attribute cannot appear with waitOperands");
4280 if (getWaitDevnum() && getWaitOperands().empty())
4281 return emitError(
"wait_devnum cannot appear without waitOperands");
4286unsigned ExitDataOp::getNumDataOperands() {
4287 return getDataClauseOperands().size();
4290Value ExitDataOp::getDataOperand(
unsigned i) {
4291 unsigned numOptional = getIfCond() ? 1 : 0;
4292 numOptional += getAsyncOperand() ? 1 : 0;
4293 numOptional += getWaitDevnum() ? 1 : 0;
4294 return getOperand(getWaitOperands().size() + numOptional + i);
4299 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4302void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4304 assert(effectiveDeviceTypes.empty());
4305 assert(!getAsyncAttr());
4306 assert(!getAsyncOperand());
4308 setAsyncAttr(mlir::UnitAttr::get(context));
4311void ExitDataOp::addAsyncOperand(
4314 assert(effectiveDeviceTypes.empty());
4315 assert(!getAsyncAttr());
4316 assert(!getAsyncOperand());
4318 getAsyncOperandMutable().append(newValue);
4323 assert(effectiveDeviceTypes.empty());
4324 assert(!getWaitAttr());
4325 assert(getWaitOperands().empty());
4326 assert(!getWaitDevnum());
4328 setWaitAttr(mlir::UnitAttr::get(context));
4331void ExitDataOp::addWaitOperands(
4334 assert(effectiveDeviceTypes.empty());
4335 assert(!getWaitAttr());
4336 assert(getWaitOperands().empty());
4337 assert(!getWaitDevnum());
4342 getWaitDevnumMutable().append(newValues.front());
4343 newValues = newValues.drop_front();
4346 getWaitOperandsMutable().append(newValues);
4353LogicalResult acc::EnterDataOp::verify() {
4357 if (getDataClauseOperands().empty())
4358 return emitError(
"at least one operand must be present in dataOperands on "
4359 "the enter data operation");
4363 if (getAsyncOperand() && getAsync())
4364 return emitError(
"async attribute cannot appear with asyncOperand");
4368 if (!getWaitOperands().empty() && getWait())
4369 return emitError(
"wait attribute cannot appear with waitOperands");
4371 if (getWaitDevnum() && getWaitOperands().empty())
4372 return emitError(
"wait_devnum cannot appear without waitOperands");
4374 for (
mlir::Value operand : getDataClauseOperands())
4375 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp>(
4376 operand.getDefiningOp()))
4377 return emitError(
"expect data entry operation as defining op");
4382unsigned EnterDataOp::getNumDataOperands() {
4383 return getDataClauseOperands().size();
4386Value EnterDataOp::getDataOperand(
unsigned i) {
4387 unsigned numOptional = getIfCond() ? 1 : 0;
4388 numOptional += getAsyncOperand() ? 1 : 0;
4389 numOptional += getWaitDevnum() ? 1 : 0;
4390 return getOperand(getWaitOperands().size() + numOptional + i);
4395 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4398void EnterDataOp::addAsyncOnly(
4400 assert(effectiveDeviceTypes.empty());
4401 assert(!getAsyncAttr());
4402 assert(!getAsyncOperand());
4404 setAsyncAttr(mlir::UnitAttr::get(context));
4407void EnterDataOp::addAsyncOperand(
4410 assert(effectiveDeviceTypes.empty());
4411 assert(!getAsyncAttr());
4412 assert(!getAsyncOperand());
4414 getAsyncOperandMutable().append(newValue);
4417void EnterDataOp::addWaitOnly(
MLIRContext *context,
4419 assert(effectiveDeviceTypes.empty());
4420 assert(!getWaitAttr());
4421 assert(getWaitOperands().empty());
4422 assert(!getWaitDevnum());
4424 setWaitAttr(mlir::UnitAttr::get(context));
4427void EnterDataOp::addWaitOperands(
4430 assert(effectiveDeviceTypes.empty());
4431 assert(!getWaitAttr());
4432 assert(getWaitOperands().empty());
4433 assert(!getWaitDevnum());
4438 getWaitDevnumMutable().append(newValues.front());
4439 newValues = newValues.drop_front();
4442 getWaitOperandsMutable().append(newValues);
4449LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4455LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4461LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4468 if (
Value writeVal = op.getWriteOpVal()) {
4477LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4479LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4485AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4486 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4488 return dyn_cast<AtomicReadOp>(getSecondOp());
4491AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4492 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4494 return dyn_cast<AtomicWriteOp>(getSecondOp());
4497AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4498 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4500 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4503LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4509template <
typename Op>
4512 bool requireAtLeastOneOperand =
true) {
4513 if (operands.empty() && requireAtLeastOneOperand)
4516 "at least one operand must appear on the declare operation");
4519 if (isa<BlockArgument>(operand) ||
4520 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4521 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4522 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp>(
4523 operand.getDefiningOp()))
4525 "expect valid declare data entry operation or acc.getdeviceptr "
4529 assert(var &&
"declare operands can only be data entry operations which "
4532 std::optional<mlir::acc::DataClause> dataClauseOptional{
4534 assert(dataClauseOptional.has_value() &&
4535 "declare operands can only be data entry operations which must have "
4537 (
void)dataClauseOptional;
4543LogicalResult acc::DeclareEnterOp::verify() {
4551LogicalResult acc::DeclareExitOp::verify() {
4562LogicalResult acc::DeclareOp::verify() {
4571 acc::DeviceType dtype) {
4572 unsigned parallelism = 0;
4573 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4574 parallelism += op.hasWorker(dtype) ? 1 : 0;
4575 parallelism += op.hasVector(dtype) ? 1 : 0;
4576 parallelism += op.hasSeq(dtype) ? 1 : 0;
4580LogicalResult acc::RoutineOp::verify() {
4581 unsigned baseParallelism =
4584 if (baseParallelism > 1)
4585 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4586 "be present at the same time";
4588 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4590 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4591 if (dtype == acc::DeviceType::None)
4595 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4596 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4597 "be present at the same time for device_type `"
4598 << acc::stringifyDeviceType(dtype) <<
"`";
4605 mlir::ArrayAttr &bindIdName,
4606 mlir::ArrayAttr &bindStrName,
4607 mlir::ArrayAttr &deviceIdTypes,
4608 mlir::ArrayAttr &deviceStrTypes) {
4615 mlir::Attribute newAttr;
4616 bool isSymbolRefAttr;
4617 auto parseResult = parser.parseAttribute(newAttr);
4618 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4619 bindIdNameAttrs.push_back(symbolRefAttr);
4620 isSymbolRefAttr = true;
4621 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4622 bindStrNameAttrs.push_back(stringAttr);
4623 isSymbolRefAttr =
false;
4628 if (isSymbolRefAttr) {
4629 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4630 parser.getContext(), mlir::acc::DeviceType::None));
4632 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4633 parser.getContext(), mlir::acc::DeviceType::None));
4636 if (isSymbolRefAttr) {
4637 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4638 parser.parseRSquare())
4641 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4642 parser.parseRSquare())
4650 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4651 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4652 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4653 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4659 std::optional<mlir::ArrayAttr> bindIdName,
4660 std::optional<mlir::ArrayAttr> bindStrName,
4661 std::optional<mlir::ArrayAttr> deviceIdTypes,
4662 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4669 allBindNames.append(bindIdName->begin(), bindIdName->end());
4670 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4675 allBindNames.append(bindStrName->begin(), bindStrName->end());
4676 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4680 if (!allBindNames.empty())
4681 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4682 [&](
const auto &pair) {
4683 p << std::get<0>(pair);
4689 mlir::ArrayAttr &gang,
4690 mlir::ArrayAttr &gangDim,
4691 mlir::ArrayAttr &gangDimDeviceTypes) {
4694 gangDimDeviceTypeAttrs;
4695 bool needCommaBeforeOperands =
false;
4699 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4700 parser.
getContext(), mlir::acc::DeviceType::None));
4701 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4708 if (parser.parseAttribute(gangAttrs.emplace_back()))
4715 needCommaBeforeOperands =
true;
4718 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4722 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4723 parser.parseColon() ||
4724 parser.parseAttribute(gangDimAttrs.emplace_back()))
4726 if (succeeded(parser.parseOptionalLSquare())) {
4727 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4728 parser.parseRSquare())
4731 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4732 parser.getContext(), mlir::acc::DeviceType::None));
4738 if (
failed(parser.parseRParen()))
4741 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4742 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4743 gangDimDeviceTypes =
4744 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4750 std::optional<mlir::ArrayAttr> gang,
4751 std::optional<mlir::ArrayAttr> gangDim,
4752 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4755 gang->size() == 1) {
4756 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4757 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4769 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4770 [&](
const auto &pair) {
4771 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4772 p << std::get<0>(pair);
4780 mlir::ArrayAttr &deviceTypes) {
4784 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4785 parser.
getContext(), mlir::acc::DeviceType::None));
4786 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4793 if (parser.parseAttribute(attributes.emplace_back()))
4801 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4807 std::optional<mlir::ArrayAttr> deviceTypes) {
4810 auto deviceTypeAttr =
4811 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4812 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4821 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4827bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4829bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4833bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4835bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4839bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4841bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4845std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4846RoutineOp::getBindNameValue() {
4847 return getBindNameValue(mlir::acc::DeviceType::None);
4850std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4851RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4853 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4854 auto attr = (*getBindIdName())[*pos];
4855 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4856 assert(symbolRefAttr &&
"expected SymbolRef");
4857 return symbolRefAttr;
4862 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
4863 auto attr = (*getBindStrName())[*pos];
4864 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
4865 assert(stringAttr &&
"expected String");
4870 return std::nullopt;
4873bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4875bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
4879std::optional<int64_t> RoutineOp::getGangDimValue() {
4880 return getGangDimValue(mlir::acc::DeviceType::None);
4883std::optional<int64_t>
4884RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
4886 return std::nullopt;
4887 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
4888 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
4889 return intAttr.getInt();
4891 return std::nullopt;
4896 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4897 effectiveDeviceTypes));
4902 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4903 effectiveDeviceTypes));
4908 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4909 effectiveDeviceTypes));
4914 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4915 effectiveDeviceTypes));
4924 if (getGangDimAttr())
4925 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
4926 if (getGangDimDeviceTypeAttr())
4927 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
4929 assert(dimValues.size() == deviceTypes.size());
4931 if (effectiveDeviceTypes.empty()) {
4932 dimValues.push_back(
4933 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4934 deviceTypes.push_back(
4935 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
4937 for (DeviceType dt : effectiveDeviceTypes) {
4938 dimValues.push_back(
4939 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4940 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4943 assert(dimValues.size() == deviceTypes.size());
4945 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
4946 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
4949void RoutineOp::addBindStrName(
MLIRContext *context,
4951 mlir::StringAttr val) {
4952 unsigned before = getBindStrNameDeviceTypeAttr()
4953 ? getBindStrNameDeviceTypeAttr().size()
4956 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4957 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
4958 unsigned after = getBindStrNameDeviceTypeAttr().size();
4961 if (getBindStrNameAttr())
4962 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
4963 for (
unsigned i = 0; i < after - before; ++i)
4964 vals.push_back(val);
4966 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
4969void RoutineOp::addBindIDName(
MLIRContext *context,
4971 mlir::SymbolRefAttr val) {
4973 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
4975 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4976 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
4977 unsigned after = getBindIdNameDeviceTypeAttr().size();
4980 if (getBindIdNameAttr())
4981 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
4982 for (
unsigned i = 0; i < after - before; ++i)
4983 vals.push_back(val);
4985 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
4992LogicalResult acc::InitOp::verify() {
4993 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
4994 return emitOpError(
"cannot be nested in a compute operation");
4998void acc::InitOp::addDeviceType(
MLIRContext *context,
4999 mlir::acc::DeviceType deviceType) {
5001 if (getDeviceTypesAttr())
5002 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5004 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5005 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5012LogicalResult acc::ShutdownOp::verify() {
5013 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5014 return emitOpError(
"cannot be nested in a compute operation");
5018void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
5019 mlir::acc::DeviceType deviceType) {
5021 if (getDeviceTypesAttr())
5022 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5024 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5025 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5032LogicalResult acc::SetOp::verify() {
5033 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5034 return emitOpError(
"cannot be nested in a compute operation");
5035 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
5036 return emitOpError(
"at least one default_async, device_num, or device_type "
5037 "operand must appear");
5045LogicalResult acc::UpdateOp::verify() {
5047 if (getDataClauseOperands().empty())
5048 return emitError(
"at least one value must be present in dataOperands");
5051 getAsyncOperandsDeviceTypeAttr(),
5056 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
5057 getWaitOperandsDeviceTypeAttr(),
"wait")))
5063 for (
mlir::Value operand : getDataClauseOperands())
5064 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp>(
5065 operand.getDefiningOp()))
5066 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
5072unsigned UpdateOp::getNumDataOperands() {
5073 return getDataClauseOperands().size();
5076Value UpdateOp::getDataOperand(
unsigned i) {
5078 numOptional += getIfCond() ? 1 : 0;
5079 return getOperand(getWaitOperands().size() + numOptional + i);
5084 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
5087bool UpdateOp::hasAsyncOnly() {
5088 return hasAsyncOnly(mlir::acc::DeviceType::None);
5091bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
5096 return getAsyncValue(mlir::acc::DeviceType::None);
5099mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
5109bool UpdateOp::hasWaitOnly() {
5110 return hasWaitOnly(mlir::acc::DeviceType::None);
5113bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
5118 return getWaitValues(mlir::acc::DeviceType::None);
5122UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
5124 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
5125 getHasWaitDevnum(), deviceType);
5129 return getWaitDevnum(mlir::acc::DeviceType::None);
5132mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
5134 getWaitOperandsSegments(), getHasWaitDevnum(),
5140 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
5141 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
5144void UpdateOp::addAsyncOperand(
5147 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5148 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
5149 getAsyncOperandsMutable()));
5154 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
5155 effectiveDeviceTypes));
5158void UpdateOp::addWaitOperands(
5163 if (getWaitOperandsSegments())
5164 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
5166 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5167 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
5168 getWaitOperandsMutable(), segments));
5169 setWaitOperandsSegments(segments);
5172 if (getHasWaitDevnumAttr())
5173 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5176 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5178 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5185LogicalResult acc::WaitOp::verify() {
5188 if (getAsyncOperand() && getAsync())
5189 return emitError(
"async attribute cannot appear with asyncOperand");
5191 if (getWaitDevnum() && getWaitOperands().empty())
5192 return emitError(
"wait_devnum cannot appear without waitOperands");
5197#define GET_OP_CLASSES
5198#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5200#define GET_ATTRDEF_CLASSES
5201#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5203#define GET_TYPEDEF_CLASSES
5204#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5215 .Case<ACC_DATA_ENTRY_OPS>(
5216 [&](
auto entry) {
return entry.getVarPtr(); })
5217 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5218 [&](
auto exit) {
return exit.getVarPtr(); })
5236 [&](
auto entry) {
return entry.getVarType(); })
5237 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5238 [&](
auto exit) {
return exit.getVarType(); })
5248 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>(
5249 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5259 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5268 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5278 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5280 dataClause.getBounds().begin(), dataClause.getBounds().end());
5292 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5294 dataClause.getAsyncOperands().begin(),
5295 dataClause.getAsyncOperands().end());
5306 return dataClause.getAsyncOperandsDeviceTypeAttr();
5314 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5321 .Case<ACC_DATA_ENTRY_OPS>([&](
auto entry) {
return entry.getName(); })
5328std::optional<mlir::acc::DataClause>
5333 .Case<ACC_DATA_ENTRY_OPS>(
5334 [&](
auto entry) {
return entry.getDataClause(); })
5342 [&](
auto entry) {
return entry.getImplicit(); })
5351 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5353 return dataOperands;
5361 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5363 return dataOperands;
5370 [&](
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.