26#include "llvm/ADT/SmallSet.h"
27#include "llvm/ADT/TypeSwitch.h"
28#include "llvm/Support/LogicalResult.h"
34#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
35#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
36#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
37#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
38#include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
42static bool isScalarLikeType(
Type type) {
50 if (!varName.empty()) {
51 auto varNameAttr = acc::VarNameAttr::get(builder.
getContext(), varName);
57struct MemRefPointerLikeModel
58 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel<T>, T> {
60 return cast<T>(pointer).getElementType();
63 mlir::acc::VariableTypeCategory
66 if (
auto mappableTy = dyn_cast<MappableType>(varType)) {
67 return mappableTy.getTypeCategory(varPtr);
69 auto memrefTy = cast<T>(pointer);
70 if (!memrefTy.hasRank()) {
73 return mlir::acc::VariableTypeCategory::uncategorized;
76 if (memrefTy.getRank() == 0) {
77 if (isScalarLikeType(memrefTy.getElementType())) {
78 return mlir::acc::VariableTypeCategory::scalar;
82 return mlir::acc::VariableTypeCategory::uncategorized;
86 assert(memrefTy.getRank() > 0 &&
"rank expected to be positive");
87 return mlir::acc::VariableTypeCategory::array;
90 mlir::Value genAllocate(Type pointer, OpBuilder &builder, Location loc,
91 StringRef varName, Type varType, Value originalVar,
92 bool &needsFree)
const {
93 auto memrefTy = cast<MemRefType>(pointer);
97 if (memrefTy.hasStaticShape()) {
99 auto allocaOp = memref::AllocaOp::create(builder, loc, memrefTy);
100 attachVarNameAttr(allocaOp, builder, varName);
101 return allocaOp.getResult();
106 if (originalVar && originalVar.
getType() == memrefTy &&
107 memrefTy.hasRank()) {
108 SmallVector<Value> dynamicSizes;
109 for (int64_t i = 0; i < memrefTy.getRank(); ++i) {
110 if (memrefTy.isDynamicDim(i)) {
114 memref::DimOp::create(builder, loc, originalVar, indexValue);
115 dynamicSizes.push_back(dimSize);
122 memref::AllocOp::create(builder, loc, memrefTy, dynamicSizes);
123 attachVarNameAttr(allocOp, builder, varName);
124 return allocOp.getResult();
131 bool genFree(Type pointer, OpBuilder &builder, Location loc,
133 Type varType)
const {
136 Value valueToInspect = allocRes ? allocRes : memrefValue;
139 Value currentValue = valueToInspect;
140 Operation *originalAlloc =
nullptr;
144 while (currentValue) {
147 if (isa<memref::AllocOp, memref::AllocaOp>(definingOp)) {
148 originalAlloc = definingOp;
153 if (
auto castOp = dyn_cast<memref::CastOp>(definingOp)) {
154 currentValue = castOp.getSource();
159 if (
auto reinterpretCastOp =
160 dyn_cast<memref::ReinterpretCastOp>(definingOp)) {
161 currentValue = reinterpretCastOp.getSource();
173 if (isa<memref::AllocaOp>(originalAlloc)) {
177 if (isa<memref::AllocOp>(originalAlloc)) {
179 memref::DeallocOp::create(builder, loc, memrefValue);
188 bool genCopy(Type pointer, OpBuilder &builder, Location loc,
192 auto destMemref = dyn_cast_if_present<TypedValue<MemRefType>>(destination);
193 auto srcMemref = dyn_cast_if_present<TypedValue<MemRefType>>(source);
199 if (destMemref && srcMemref &&
200 destMemref.getType().getElementType() ==
201 srcMemref.getType().getElementType() &&
202 destMemref.getType().getShape() == srcMemref.getType().getShape()) {
203 memref::CopyOp::create(builder, loc, srcMemref, destMemref);
210 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
212 Type valueType)
const {
217 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(srcPtr);
221 auto memrefTy = memrefValue.
getType();
224 if (memrefTy.getRank() != 0)
227 return memref::LoadOp::create(builder, loc, memrefValue);
230 bool genStore(Type pointer, OpBuilder &builder, Location loc,
236 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(destPtr);
240 auto memrefTy = memrefValue.getType();
243 if (memrefTy.getRank() != 0)
246 memref::StoreOp::create(builder, loc, valueToStore, memrefValue);
250 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
251 Type resultType)
const {
252 if (value.
getType() == resultType)
255 if (isa<BaseMemRefType>(value.
getType()) &&
256 isa<BaseMemRefType>(resultType)) {
259 return memref::CastOp::create(builder, loc, resultType, value);
260 if (memref::MemorySpaceCastOp::areCastCompatible(
262 return memref::MemorySpaceCastOp::create(builder, loc, resultType,
269 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
270 if (!isa<BaseMemRefType>(resPtrLike))
271 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
273 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
274 if (!isa<BaseMemRefType>(valPtrLike))
275 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
281 bool isDeviceData(Type pointer, Value var)
const {
282 auto memrefTy = cast<T>(pointer);
283 Attribute memSpace = memrefTy.getMemorySpace();
284 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
287 MemRefType getAsMemRefType(Type pointer, ModuleOp module)
const {
289 return dyn_cast<MemRefType>(pointer);
293struct LLVMPointerPointerLikeModel
294 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
295 LLVM::LLVMPointerType> {
298 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
300 Type valueType)
const {
305 return LLVM::LoadOp::create(builder, loc, valueType, srcPtr);
308 bool genStore(Type pointer, OpBuilder &builder, Location loc,
310 LLVM::StoreOp::create(builder, loc, valueToStore, destPtr);
314 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
315 Type resultType)
const {
316 if (value.
getType() == resultType)
319 auto srcPtrTy = dyn_cast<LLVM::LLVMPointerType>(value.
getType());
320 auto dstPtrTy = dyn_cast<LLVM::LLVMPointerType>(resultType);
321 if (srcPtrTy && dstPtrTy) {
322 if (srcPtrTy.getAddressSpace() != dstPtrTy.getAddressSpace())
323 return LLVM::AddrSpaceCastOp::create(builder, loc, resultType, value);
327 if (srcPtrTy && isa<IntegerType>(resultType))
328 return LLVM::PtrToIntOp::create(builder, loc, resultType, value);
331 Value intVal = value;
332 if (isa<IndexType>(value.
getType()))
333 intVal = arith::IndexCastUIOp::create(builder, loc,
335 if (isa<IntegerType>(intVal.
getType()))
336 return LLVM::IntToPtrOp::create(builder, loc, resultType, intVal);
339 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
340 if (!isa<LLVM::LLVMPointerType>(resPtrLike))
341 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
343 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
344 if (!isa<LLVM::LLVMPointerType>(valPtrLike))
345 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
348 return UnrealizedConversionCastOp::create(builder, loc,
354struct PrivateTypePointerLikeModel
355 :
public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
358 return cast<PrivateType>(type).getBaseTy();
361 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
362 Type resultType)
const {
363 if (value.
getType() == resultType)
365 if (!isa<PointerLikeType>(resultType))
367 return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
370 MemRefType getAsMemRefType(Type type, ModuleOp module)
const {
371 Type baseTy = cast<PrivateType>(type).getBaseTy();
372 if (
auto memrefTy = dyn_cast<MemRefType>(baseTy))
374 if (
auto ptrLikeTy = dyn_cast<PointerLikeType>(baseTy))
375 return ptrLikeTy.getAsMemRefType(module);
380struct MemrefAddressOfGlobalModel
381 :
public AddressOfGlobalOpInterface::ExternalModel<
382 MemrefAddressOfGlobalModel, memref::GetGlobalOp> {
383 SymbolRefAttr getSymbol(Operation *op)
const {
384 auto getGlobalOp = cast<memref::GetGlobalOp>(op);
385 return getGlobalOp.getNameAttr();
389struct MemrefGlobalVariableModel
390 :
public GlobalVariableOpInterface::ExternalModel<MemrefGlobalVariableModel,
392 bool isConstant(Operation *op)
const {
393 auto globalOp = cast<memref::GlobalOp>(op);
394 return globalOp.getConstant();
397 bool hasInitializer(Operation *op)
const {
398 auto globalOp = cast<memref::GlobalOp>(op);
399 return globalOp.getInitialValue().has_value();
402 Region *getInitRegion(Operation *op)
const {
407 bool isDeviceData(Operation *op)
const {
408 auto globalOp = cast<memref::GlobalOp>(op);
409 Attribute memSpace = globalOp.getType().getMemorySpace();
410 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
414struct GPULaunchOffloadRegionModel
415 :
public acc::OffloadRegionOpInterface::ExternalModel<
416 GPULaunchOffloadRegionModel, gpu::LaunchOp> {
417 mlir::Region &getOffloadRegion(mlir::Operation *op)
const {
418 return cast<gpu::LaunchOp>(op).getBody();
426mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
427 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
430 if (existingDeviceTypes)
431 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
433 if (newDeviceTypes.empty())
434 deviceTypes.push_back(
435 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
437 for (DeviceType dt : newDeviceTypes)
438 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
440 return mlir::ArrayAttr::get(context, deviceTypes);
449mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
450 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
455 if (existingDeviceTypes)
456 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
458 if (newDeviceTypes.empty()) {
459 argCollection.
append(arguments);
460 segments.push_back(arguments.size());
461 deviceTypes.push_back(
462 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
465 for (DeviceType dt : newDeviceTypes) {
466 argCollection.
append(arguments);
467 segments.push_back(arguments.size());
468 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
471 return mlir::ArrayAttr::get(context, deviceTypes);
475mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
476 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
480 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
481 newDeviceTypes, arguments,
482 argCollection, segments);
490void OpenACCDialect::initialize() {
493#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
496#define GET_ATTRDEF_LIST
497#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
500#define GET_TYPEDEF_LIST
501#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
507 MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
509 UnrankedMemRefType::attachInterface<
510 MemRefPointerLikeModel<UnrankedMemRefType>>(*
getContext());
511 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
513 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
516 memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
518 memref::GlobalOp::attachInterface<MemrefGlobalVariableModel>(*
getContext());
519 gpu::LaunchOp::attachInterface<GPULaunchOffloadRegionModel>(*
getContext());
556void ParallelOp::getSuccessorRegions(
586void HostDataOp::getSuccessorRegions(
601 if (getUnstructured()) {
634 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
638 mlir::acc::DeviceType deviceType) {
642 for (
auto attr : *arrayAttr) {
643 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
644 if (deviceTypeAttr.getValue() == deviceType)
652 std::optional<mlir::ArrayAttr> deviceTypes) {
657 llvm::interleaveComma(*deviceTypes, p,
663 mlir::acc::DeviceType deviceType) {
664 unsigned segmentIdx = 0;
665 for (
auto attr : segments) {
666 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
667 if (deviceTypeAttr.getValue() == deviceType)
668 return std::make_optional(segmentIdx);
678 mlir::acc::DeviceType deviceType) {
680 return range.take_front(0);
681 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
682 int32_t nbOperandsBefore = 0;
683 for (
unsigned i = 0; i < *pos; ++i)
684 nbOperandsBefore += (*segments)[i];
685 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
687 return range.take_front(0);
694 std::optional<mlir::ArrayAttr> hasWaitDevnum,
695 mlir::acc::DeviceType deviceType) {
698 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
699 if (hasWaitDevnum && *hasWaitDevnum) {
700 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
701 if (boolAttr && boolAttr.getValue())
714 std::optional<mlir::ArrayAttr> hasWaitDevnum,
715 mlir::acc::DeviceType deviceType) {
720 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
721 if (hasWaitDevnum && *hasWaitDevnum) {
722 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
723 if (boolAttr.getValue())
724 return range.drop_front(1);
730template <
typename Op>
732 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
734 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
739 op.hasAsyncOnly(dtype))
741 "asyncOnly attribute cannot appear with asyncOperand");
746 op.hasWaitOnly(dtype))
747 return op.
emitError(
"wait attribute cannot appear with waitOperands");
752template <
typename Op>
755 return op.
emitError(
"must have var operand");
758 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
759 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
760 return op.
emitError(
"var must be mappable or pointer-like");
763 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
764 op.getVarType() == op.getVar().getType())
765 return op.
emitError(
"varType must capture the element type of var");
770template <
typename Op>
772 if (op.getVar().getType() != op.getAccVar().getType())
773 return op.
emitError(
"input and output types must match");
778template <
typename Op>
780 if (op.getModifiers() != acc::DataClauseModifier::none)
781 return op.
emitError(
"no data clause modifiers are allowed");
785template <
typename Op>
788 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
790 "invalid data clause modifiers: " +
791 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
796template <
typename OpT,
typename RecipeOpT>
797static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
802 !std::is_same_v<OpT, acc::ReductionOp>)
805 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
807 return op->emitOpError() <<
"recipe expected for " << operandName;
812 return op->emitOpError()
813 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
814 << operandName <<
" declaration";
835 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
856 if (failed(parser.
parseType(accVarType)))
866 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
878 mlir::TypeAttr &varTypeAttr) {
879 if (failed(parser.
parseType(varPtrType)))
890 varTypeAttr = mlir::TypeAttr::get(varType);
895 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
896 Type elementType = ptrTy.getElementType();
899 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
901 varTypeAttr = mlir::TypeAttr::get(varPtrType);
909 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
917 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
918 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
922 if (!typeToCheckAgainst)
923 typeToCheckAgainst = varPtrType;
924 if (typeToCheckAgainst != varType) {
932 mlir::SymbolRefAttr &recipeAttr) {
939 mlir::SymbolRefAttr recipeAttr) {
954 mlir::ArrayAttr &attr) {
959 mlir::ArrayAttr attr) {
966LogicalResult acc::DataBoundsOp::verify() {
967 auto extent = getExtent();
968 auto upperbound = getUpperbound();
969 if (!extent && !upperbound)
970 return emitError(
"expected extent or upperbound.");
977LogicalResult acc::PrivateOp::verify() {
980 "data clause associated with private operation must match its intent");
994LogicalResult acc::FirstprivateOp::verify() {
996 return emitError(
"data clause associated with firstprivate operation must "
1003 *
this,
"firstprivate")))
1011LogicalResult acc::ReductionOp::verify() {
1013 return emitError(
"data clause associated with reduction operation must "
1014 "match its intent");
1020 *
this,
"reduction")))
1028LogicalResult acc::DevicePtrOp::verify() {
1030 return emitError(
"data clause associated with deviceptr operation must "
1031 "match its intent");
1044LogicalResult acc::PresentOp::verify() {
1047 "data clause associated with present operation must match its intent");
1060LogicalResult acc::CopyinOp::verify() {
1062 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
1067 "data clause associated with copyin operation must match its intent"
1068 " or specify original clause this operation was decomposed from");
1074 acc::DataClauseModifier::always |
1075 acc::DataClauseModifier::capture)))
1080bool acc::CopyinOp::isCopyinReadonly() {
1081 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
1082 acc::bitEnumContainsAny(getModifiers(),
1083 acc::DataClauseModifier::readonly);
1089LogicalResult acc::CreateOp::verify() {
1096 "data clause associated with create operation must match its intent"
1097 " or specify original clause this operation was decomposed from");
1105 acc::DataClauseModifier::always |
1106 acc::DataClauseModifier::capture)))
1111bool acc::CreateOp::isCreateZero() {
1113 return getDataClause() == acc::DataClause::acc_create_zero ||
1115 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1121LogicalResult acc::NoCreateOp::verify() {
1123 return emitError(
"data clause associated with no_create operation must "
1124 "match its intent");
1137LogicalResult acc::AttachOp::verify() {
1140 "data clause associated with attach operation must match its intent");
1154LogicalResult acc::DeclareDeviceResidentOp::verify() {
1155 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
1156 return emitError(
"data clause associated with device_resident operation "
1157 "must match its intent");
1171LogicalResult acc::DeclareLinkOp::verify() {
1174 "data clause associated with link operation must match its intent");
1187LogicalResult acc::CopyoutOp::verify() {
1194 "data clause associated with copyout operation must match its intent"
1195 " or specify original clause this operation was decomposed from");
1197 return emitError(
"must have both host and device pointers");
1203 acc::DataClauseModifier::always |
1204 acc::DataClauseModifier::capture)))
1209bool acc::CopyoutOp::isCopyoutZero() {
1210 return getDataClause() == acc::DataClause::acc_copyout_zero ||
1211 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1217LogicalResult acc::DeleteOp::verify() {
1226 getDataClause() != acc::DataClause::acc_declare_device_resident &&
1229 "data clause associated with delete operation must match its intent"
1230 " or specify original clause this operation was decomposed from");
1232 return emitError(
"must have device pointer");
1236 acc::DataClauseModifier::readonly |
1237 acc::DataClauseModifier::always |
1238 acc::DataClauseModifier::capture)))
1246LogicalResult acc::DetachOp::verify() {
1251 "data clause associated with detach operation must match its intent"
1252 " or specify original clause this operation was decomposed from");
1254 return emitError(
"must have device pointer");
1263LogicalResult acc::UpdateHostOp::verify() {
1268 "data clause associated with host operation must match its intent"
1269 " or specify original clause this operation was decomposed from");
1271 return emitError(
"must have both host and device pointers");
1284LogicalResult acc::UpdateDeviceOp::verify() {
1288 "data clause associated with device operation must match its intent"
1289 " or specify original clause this operation was decomposed from");
1302LogicalResult acc::UseDeviceOp::verify() {
1306 "data clause associated with use_device operation must match its intent"
1307 " or specify original clause this operation was decomposed from");
1320LogicalResult acc::CacheOp::verify() {
1325 "data clause associated with cache operation must match its intent"
1326 " or specify original clause this operation was decomposed from");
1336bool acc::CacheOp::isCacheReadonly() {
1337 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1338 acc::bitEnumContainsAny(getModifiers(),
1339 acc::DataClauseModifier::readonly);
1355template <
typename EffectTy>
1360 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1361 effects.emplace_back(EffectTy::get(), &operand[i]);
1365template <
typename EffectTy>
1370 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1374void acc::PrivateOp::getEffects(
1388void acc::FirstprivateOp::getEffects(
1402void acc::ReductionOp::getEffects(
1416void acc::DevicePtrOp::getEffects(
1425void acc::PresentOp::getEffects(
1436void acc::CopyinOp::getEffects(
1449void acc::CreateOp::getEffects(
1462void acc::NoCreateOp::getEffects(
1473void acc::AttachOp::getEffects(
1486void acc::GetDevicePtrOp::getEffects(
1495void acc::UpdateDeviceOp::getEffects(
1505void acc::UseDeviceOp::getEffects(
1514void acc::DeclareDeviceResidentOp::getEffects(
1525void acc::DeclareLinkOp::getEffects(
1536void acc::CacheOp::getEffects(
1541void acc::CopyoutOp::getEffects(
1554void acc::DeleteOp::getEffects(
1566void acc::DetachOp::getEffects(
1578void acc::UpdateHostOp::getEffects(
1590template <
typename StructureOp>
1592 unsigned nRegions = 1) {
1595 for (
unsigned i = 0; i < nRegions; ++i)
1598 for (
Region *region : regions)
1609template <
typename OpTy>
1611 using OpRewritePattern<OpTy>::OpRewritePattern;
1613 LogicalResult matchAndRewrite(OpTy op,
1614 PatternRewriter &rewriter)
const override {
1616 Value ifCond = op.getIfCond();
1620 IntegerAttr constAttr;
1623 if (constAttr.getInt())
1624 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1636 assert(region.
hasOneBlock() &&
"expected single-block region");
1648template <
typename OpTy>
1649struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1650 using OpRewritePattern<OpTy>::OpRewritePattern;
1652 LogicalResult matchAndRewrite(OpTy op,
1653 PatternRewriter &rewriter)
const override {
1655 Value ifCond = op.getIfCond();
1659 IntegerAttr constAttr;
1662 if (constAttr.getInt())
1663 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1691 for (
Value bound : bounds) {
1692 argTypes.push_back(bound.getType());
1693 argLocs.push_back(loc);
1700 Value privatizedValue;
1706 if (isa<MappableType>(varType)) {
1707 auto mappableTy = cast<MappableType>(varType);
1708 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1709 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1710 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1711 privatizedValue = mappableTy.generatePrivateInit(
1712 builder, loc, typedVar, varName, bounds, {}, varInfo, needsFree);
1713 if (!privatizedValue)
1716 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1717 auto pointerLikeTy = cast<PointerLikeType>(varType);
1719 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1720 blockArgVar, needsFree);
1721 if (!privatizedValue)
1726 acc::YieldOp::create(builder, loc, privatizedValue);
1743 for (
Value bound : bounds) {
1744 copyArgTypes.push_back(bound.getType());
1745 copyArgLocs.push_back(loc);
1755 if (isa<MappableType>(varType)) {
1756 auto mappableTy = cast<MappableType>(varType);
1759 if (!mappableTy.generateCopy(
1764 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1765 auto pointerLikeTy = cast<PointerLikeType>(varType);
1766 if (!pointerLikeTy.genCopy(
1773 acc::TerminatorOp::create(builder, loc);
1790 for (
Value bound : bounds) {
1791 destroyArgTypes.push_back(bound.getType());
1792 destroyArgLocs.push_back(loc);
1796 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1800 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1801 if (isa<MappableType>(varType)) {
1802 auto mappableTy = cast<MappableType>(varType);
1803 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds,
1807 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1808 auto pointerLikeTy = cast<PointerLikeType>(varType);
1809 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1813 acc::TerminatorOp::create(builder, loc);
1824 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1826 if (optional && region.
empty())
1830 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1834 return op->
emitOpError() <<
"expects " << regionName
1837 << regionType <<
" type";
1840 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1841 if (yieldOp.getOperands().size() != 1 ||
1842 yieldOp.getOperands().getTypes()[0] != type)
1843 return op->
emitOpError() <<
"expects " << regionName
1845 "yield a value of the "
1846 << regionType <<
" type";
1852LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1854 "privatization",
"init",
getType(),
1858 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1864std::optional<PrivateRecipeOp>
1866 StringRef recipeName,
Value hostVar,
1871 bool isMappable = isa<MappableType>(varType);
1872 bool isPointerLike = isa<PointerLikeType>(varType);
1875 if (!isMappable && !isPointerLike)
1876 return std::nullopt;
1881 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1884 bool needsFree =
false;
1886 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1887 varName, bounds, needsFree, varInfo))) {
1889 return std::nullopt;
1896 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1897 Value allocRes = yieldOp.getOperand(0);
1899 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1900 varType, allocRes, bounds, varInfo))) {
1902 return std::nullopt;
1909std::optional<PrivateRecipeOp>
1911 StringRef recipeName,
1912 FirstprivateRecipeOp firstprivRecipe) {
1915 auto varType = firstprivRecipe.getType();
1916 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
1920 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
1923 if (!firstprivRecipe.getDestroyRegion().empty()) {
1925 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
1935LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
1937 "privatization",
"init",
getType(),
1941 if (getCopyRegion().empty())
1942 return emitOpError() <<
"expects non-empty copy region";
1947 return emitOpError() <<
"expects copy region with two arguments of the "
1948 "privatization type";
1950 if (getDestroyRegion().empty())
1954 "privatization",
"destroy",
1961std::optional<FirstprivateRecipeOp>
1963 StringRef recipeName,
Value hostVar,
1968 bool isMappable = isa<MappableType>(varType);
1969 bool isPointerLike = isa<PointerLikeType>(varType);
1972 if (!isMappable && !isPointerLike)
1973 return std::nullopt;
1978 auto recipe = FirstprivateRecipeOp::create(builder, loc, recipeName, varType);
1981 bool needsFree =
false;
1986 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1987 varName, bounds, needsFree, varInfo))) {
1989 return std::nullopt;
1993 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
1994 bounds, varInfo))) {
1996 return std::nullopt;
2003 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
2004 Value allocRes = yieldOp.getOperand(0);
2006 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
2007 varType, allocRes, bounds, varInfo))) {
2009 return std::nullopt;
2020LogicalResult acc::ReductionRecipeOp::verifyRegions() {
2026 if (getCombinerRegion().empty())
2027 return emitOpError() <<
"expects non-empty combiner region";
2029 Block &reductionBlock = getCombinerRegion().
front();
2033 return emitOpError() <<
"expects combiner region with the first two "
2034 <<
"arguments of the reduction type";
2036 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
2037 if (yieldOp.getOperands().size() != 1 ||
2038 yieldOp.getOperands().getTypes()[0] !=
getType())
2039 return emitOpError() <<
"expects combiner region to yield a value "
2040 "of the reduction type";
2051template <
typename Op>
2055 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2056 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2057 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
2058 operand.getDefiningOp()))
2060 "expect data entry/exit operation or acc.getdeviceptr "
2065template <
typename OpT,
typename RecipeOpT>
2068 llvm::StringRef operandName) {
2071 if (!mlir::isa<OpT>(operand.getDefiningOp()))
2073 <<
"expected " << operandName <<
" as defining op";
2074 if (!set.insert(operand).second)
2076 << operandName <<
" operand appears more than once";
2081unsigned ParallelOp::getNumDataOperands() {
2082 return getReductionOperands().size() + getPrivateOperands().size() +
2083 getFirstprivateOperands().size() + getDataClauseOperands().size();
2086Value ParallelOp::getDataOperand(
unsigned i) {
2088 numOptional += getNumGangs().size();
2089 numOptional += getNumWorkers().size();
2090 numOptional += getVectorLength().size();
2091 numOptional += getIfCond() ? 1 : 0;
2092 numOptional += getSelfCond() ? 1 : 0;
2093 return getOperand(getWaitOperands().size() + numOptional + i);
2096template <
typename Op>
2099 llvm::StringRef keyword) {
2100 if (!operands.empty() &&
2101 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
2102 return op.
emitOpError() << keyword <<
" operands count must match "
2103 << keyword <<
" device_type count";
2107template <
typename Op>
2110 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
2111 std::size_t numOperandsInSegments = 0;
2112 std::size_t nbOfSegments = 0;
2115 for (
auto segCount : segments.
asArrayRef()) {
2116 if (maxInSegment != 0 && segCount > maxInSegment)
2117 return op.
emitOpError() << keyword <<
" expects a maximum of "
2118 << maxInSegment <<
" values per segment";
2119 numOperandsInSegments += segCount;
2124 if ((numOperandsInSegments != operands.size()) ||
2125 (!deviceTypes && !operands.empty()))
2127 << keyword <<
" operand count does not match count in segments";
2128 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
2130 << keyword <<
" segment count does not match device_type count";
2134LogicalResult acc::ParallelOp::verify() {
2136 mlir::acc::PrivateRecipeOp>(
2137 *
this, getPrivateOperands(),
"private")))
2140 mlir::acc::FirstprivateRecipeOp>(
2141 *
this, getFirstprivateOperands(),
"firstprivate")))
2144 mlir::acc::ReductionRecipeOp>(
2145 *
this, getReductionOperands(),
"reduction")))
2149 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2150 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2154 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2155 getWaitOperandsDeviceTypeAttr(),
"wait")))
2159 getNumWorkersDeviceTypeAttr(),
2164 getVectorLengthDeviceTypeAttr(),
2169 getAsyncOperandsDeviceTypeAttr(),
2182 mlir::acc::DeviceType deviceType) {
2185 if (
auto pos =
findSegment(*arrayAttr, deviceType))
2190bool acc::ParallelOp::hasAsyncOnly() {
2191 return hasAsyncOnly(mlir::acc::DeviceType::None);
2194bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2199 return getAsyncValue(mlir::acc::DeviceType::None);
2202mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2207mlir::Value acc::ParallelOp::getNumWorkersValue() {
2208 return getNumWorkersValue(mlir::acc::DeviceType::None);
2212acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2217mlir::Value acc::ParallelOp::getVectorLengthValue() {
2218 return getVectorLengthValue(mlir::acc::DeviceType::None);
2222acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2224 getVectorLength(), deviceType);
2228 return getNumGangsValues(mlir::acc::DeviceType::None);
2232ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2234 getNumGangsSegments(), deviceType);
2238 std::optional<mlir::ArrayAttr> numGangsDeviceType,
2241 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
2243 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
2245 mlir::acc::DeviceType deviceType) {
2255bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2257 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2258 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2259 getVectorLength(), deviceType);
2262bool acc::ParallelOp::isEffectivelySerial() {
2266bool acc::ParallelOp::hasWaitOnly() {
2267 return hasWaitOnly(mlir::acc::DeviceType::None);
2270bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2275 return getWaitValues(mlir::acc::DeviceType::None);
2279ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2281 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2282 getHasWaitDevnum(), deviceType);
2286 return getWaitDevnum(mlir::acc::DeviceType::None);
2289mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2291 getWaitOperandsSegments(), getHasWaitDevnum(),
2306 odsBuilder, odsState, asyncOperands,
nullptr,
2307 nullptr, waitOperands,
nullptr,
2309 nullptr, numGangs,
nullptr,
2310 nullptr, numWorkers,
2311 nullptr, vectorLength,
2312 nullptr, ifCond, selfCond,
2313 nullptr, reductionOperands, gangPrivateOperands,
2314 gangFirstPrivateOperands, dataClauseOperands,
2318void acc::ParallelOp::addNumWorkersOperand(
2321 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2322 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2323 getNumWorkersMutable()));
2325void acc::ParallelOp::addVectorLengthOperand(
2328 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2329 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2330 getVectorLengthMutable()));
2333void acc::ParallelOp::addAsyncOnly(
2335 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2336 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2339void acc::ParallelOp::addAsyncOperand(
2342 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2343 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2344 getAsyncOperandsMutable()));
2347void acc::ParallelOp::addNumGangsOperands(
2351 if (getNumGangsSegments())
2352 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2354 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2355 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2356 getNumGangsMutable(), segments));
2358 setNumGangsSegments(segments);
2360void acc::ParallelOp::addWaitOnly(
2362 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2363 effectiveDeviceTypes));
2365void acc::ParallelOp::addWaitOperands(
2370 if (getWaitOperandsSegments())
2371 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2373 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2374 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2375 getWaitOperandsMutable(), segments));
2376 setWaitOperandsSegments(segments);
2379 if (getHasWaitDevnumAttr())
2380 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2383 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2385 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2388void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2389 mlir::acc::PrivateOp op,
2390 mlir::acc::PrivateRecipeOp recipe) {
2391 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2392 getPrivateOperandsMutable().append(op.getResult());
2395void acc::ParallelOp::addFirstPrivatization(
2396 MLIRContext *context, mlir::acc::FirstprivateOp op,
2397 mlir::acc::FirstprivateRecipeOp recipe) {
2398 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2399 getFirstprivateOperandsMutable().append(op.getResult());
2402void acc::ParallelOp::addReduction(
MLIRContext *context,
2403 mlir::acc::ReductionOp op,
2404 mlir::acc::ReductionRecipeOp recipe) {
2405 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2406 getReductionOperandsMutable().append(op.getResult());
2421 int32_t crtOperandsSize = operands.size();
2424 if (parser.parseOperand(operands.emplace_back()) ||
2425 parser.parseColonType(types.emplace_back()))
2430 seg.push_back(operands.size() - crtOperandsSize);
2440 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2441 parser.
getContext(), mlir::acc::DeviceType::None));
2447 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2454 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2455 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2456 p <<
" [" << attr <<
"]";
2461 std::optional<mlir::ArrayAttr> deviceTypes,
2462 std::optional<mlir::DenseI32ArrayAttr> segments) {
2464 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2466 llvm::interleaveComma(
2467 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2468 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2488 int32_t crtOperandsSize = operands.size();
2492 if (parser.parseOperand(operands.emplace_back()) ||
2493 parser.parseColonType(types.emplace_back()))
2499 seg.push_back(operands.size() - crtOperandsSize);
2509 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2510 parser.
getContext(), mlir::acc::DeviceType::None));
2516 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2525 std::optional<mlir::DenseI32ArrayAttr> segments) {
2527 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2529 llvm::interleaveComma(
2530 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2531 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2544 mlir::ArrayAttr &keywordOnly) {
2548 bool needCommaBeforeOperands =
false;
2552 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2553 parser.
getContext(), mlir::acc::DeviceType::None));
2554 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2561 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2568 needCommaBeforeOperands =
true;
2571 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2578 int32_t crtOperandsSize = operands.size();
2590 if (parser.parseOperand(operands.emplace_back()) ||
2591 parser.parseColonType(types.emplace_back()))
2597 seg.push_back(operands.size() - crtOperandsSize);
2607 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2608 parser.
getContext(), mlir::acc::DeviceType::None));
2615 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2616 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2618 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2626 if (attrs->size() != 1)
2628 if (
auto deviceTypeAttr =
2629 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2630 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2636 std::optional<mlir::ArrayAttr> deviceTypes,
2637 std::optional<mlir::DenseI32ArrayAttr> segments,
2638 std::optional<mlir::ArrayAttr> hasDevNum,
2639 std::optional<mlir::ArrayAttr> keywordOnly) {
2652 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2654 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2655 if (boolAttr && boolAttr.getValue())
2657 llvm::interleaveComma(
2658 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2659 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2676 if (parser.parseOperand(operands.emplace_back()) ||
2677 parser.parseColonType(types.emplace_back()))
2679 if (succeeded(parser.parseOptionalLSquare())) {
2680 if (parser.parseAttribute(attributes.emplace_back()) ||
2681 parser.parseRSquare())
2684 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2685 parser.getContext(), mlir::acc::DeviceType::None));
2692 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2699 std::optional<mlir::ArrayAttr> deviceTypes) {
2702 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2703 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2712 mlir::ArrayAttr &keywordOnlyDeviceType) {
2715 bool needCommaBeforeOperands =
false;
2719 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2720 parser.
getContext(), mlir::acc::DeviceType::None));
2721 keywordOnlyDeviceType =
2722 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2730 if (parser.parseAttribute(
2731 keywordOnlyDeviceTypeAttributes.emplace_back()))
2738 keywordOnlyDeviceType =
2739 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2740 needCommaBeforeOperands =
true;
2743 if (needCommaBeforeOperands) {
2752 if (parser.parseOperand(operands.emplace_back()) ||
2753 parser.parseColonType(types.emplace_back()))
2755 if (succeeded(parser.parseOptionalLSquare())) {
2756 if (parser.parseAttribute(attributes.emplace_back()) ||
2757 parser.parseRSquare())
2760 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2761 parser.getContext(), mlir::acc::DeviceType::None));
2767 if (
failed(parser.parseRParen()))
2772 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2779 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2781 if (operands.begin() == operands.end() &&
2797 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2798 mlir::Type &operandType, mlir::UnitAttr &attr) {
2801 attr = mlir::UnitAttr::get(parser.
getContext());
2811 if (failed(parser.
parseType(operandType)))
2821 std::optional<mlir::Value> operand,
2823 mlir::UnitAttr attr) {
2840 attr = mlir::UnitAttr::get(parser.
getContext());
2845 if (parser.parseOperand(operands.emplace_back()))
2853 if (parser.parseType(types.emplace_back()))
2868 mlir::UnitAttr attr) {
2873 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2875 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2881 mlir::acc::CombinedConstructsTypeAttr &attr) {
2883 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2884 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2886 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2887 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2889 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2890 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2893 "expected compute construct name");
2901 mlir::acc::CombinedConstructsTypeAttr attr) {
2903 switch (attr.getValue()) {
2904 case mlir::acc::CombinedConstructsType::KernelsLoop:
2907 case mlir::acc::CombinedConstructsType::ParallelLoop:
2910 case mlir::acc::CombinedConstructsType::SerialLoop:
2921unsigned SerialOp::getNumDataOperands() {
2922 return getReductionOperands().size() + getPrivateOperands().size() +
2923 getFirstprivateOperands().size() + getDataClauseOperands().size();
2926Value SerialOp::getDataOperand(
unsigned i) {
2928 numOptional += getIfCond() ? 1 : 0;
2929 numOptional += getSelfCond() ? 1 : 0;
2930 return getOperand(getWaitOperands().size() + numOptional + i);
2933bool acc::SerialOp::hasAsyncOnly() {
2934 return hasAsyncOnly(mlir::acc::DeviceType::None);
2937bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2942 return getAsyncValue(mlir::acc::DeviceType::None);
2945mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2950bool acc::SerialOp::hasWaitOnly() {
2951 return hasWaitOnly(mlir::acc::DeviceType::None);
2954bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2959 return getWaitValues(mlir::acc::DeviceType::None);
2963SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2965 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2966 getHasWaitDevnum(), deviceType);
2970 return getWaitDevnum(mlir::acc::DeviceType::None);
2973mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2975 getWaitOperandsSegments(), getHasWaitDevnum(),
2979LogicalResult acc::SerialOp::verify() {
2981 mlir::acc::PrivateRecipeOp>(
2982 *
this, getPrivateOperands(),
"private")))
2985 mlir::acc::FirstprivateRecipeOp>(
2986 *
this, getFirstprivateOperands(),
"firstprivate")))
2989 mlir::acc::ReductionRecipeOp>(
2990 *
this, getReductionOperands(),
"reduction")))
2994 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2995 getWaitOperandsDeviceTypeAttr(),
"wait")))
2999 getAsyncOperandsDeviceTypeAttr(),
3009void acc::SerialOp::addAsyncOnly(
3011 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3012 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3015void acc::SerialOp::addAsyncOperand(
3018 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3019 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3020 getAsyncOperandsMutable()));
3023void acc::SerialOp::addWaitOnly(
3025 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3026 effectiveDeviceTypes));
3028void acc::SerialOp::addWaitOperands(
3033 if (getWaitOperandsSegments())
3034 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3036 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3037 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3038 getWaitOperandsMutable(), segments));
3039 setWaitOperandsSegments(segments);
3042 if (getHasWaitDevnumAttr())
3043 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3046 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3048 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3051void acc::SerialOp::addPrivatization(
MLIRContext *context,
3052 mlir::acc::PrivateOp op,
3053 mlir::acc::PrivateRecipeOp recipe) {
3054 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3055 getPrivateOperandsMutable().append(op.getResult());
3058void acc::SerialOp::addFirstPrivatization(
3059 MLIRContext *context, mlir::acc::FirstprivateOp op,
3060 mlir::acc::FirstprivateRecipeOp recipe) {
3061 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3062 getFirstprivateOperandsMutable().append(op.getResult());
3065void acc::SerialOp::addReduction(
MLIRContext *context,
3066 mlir::acc::ReductionOp op,
3067 mlir::acc::ReductionRecipeOp recipe) {
3068 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3069 getReductionOperandsMutable().append(op.getResult());
3076unsigned KernelsOp::getNumDataOperands() {
3077 return getDataClauseOperands().size();
3080Value KernelsOp::getDataOperand(
unsigned i) {
3082 numOptional += getWaitOperands().size();
3083 numOptional += getNumGangs().size();
3084 numOptional += getNumWorkers().size();
3085 numOptional += getVectorLength().size();
3086 numOptional += getIfCond() ? 1 : 0;
3087 numOptional += getSelfCond() ? 1 : 0;
3088 return getOperand(numOptional + i);
3091bool acc::KernelsOp::hasAsyncOnly() {
3092 return hasAsyncOnly(mlir::acc::DeviceType::None);
3095bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3100 return getAsyncValue(mlir::acc::DeviceType::None);
3103mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3109 return getNumWorkersValue(mlir::acc::DeviceType::None);
3113acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
3118mlir::Value acc::KernelsOp::getVectorLengthValue() {
3119 return getVectorLengthValue(mlir::acc::DeviceType::None);
3123acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
3125 getVectorLength(), deviceType);
3129 return getNumGangsValues(mlir::acc::DeviceType::None);
3133KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
3135 getNumGangsSegments(), deviceType);
3138bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
3140 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
3141 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
3142 getVectorLength(), deviceType);
3145bool acc::KernelsOp::isEffectivelySerial() {
3149bool acc::KernelsOp::hasWaitOnly() {
3150 return hasWaitOnly(mlir::acc::DeviceType::None);
3153bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3158 return getWaitValues(mlir::acc::DeviceType::None);
3162KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3164 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3165 getHasWaitDevnum(), deviceType);
3169 return getWaitDevnum(mlir::acc::DeviceType::None);
3172mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3174 getWaitOperandsSegments(), getHasWaitDevnum(),
3178LogicalResult acc::KernelsOp::verify() {
3180 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
3181 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
3185 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3186 getWaitOperandsDeviceTypeAttr(),
"wait")))
3190 getNumWorkersDeviceTypeAttr(),
3195 getVectorLengthDeviceTypeAttr(),
3200 getAsyncOperandsDeviceTypeAttr(),
3210void acc::KernelsOp::addPrivatization(
MLIRContext *context,
3211 mlir::acc::PrivateOp op,
3212 mlir::acc::PrivateRecipeOp recipe) {
3213 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3214 getPrivateOperandsMutable().append(op.getResult());
3217void acc::KernelsOp::addFirstPrivatization(
3218 MLIRContext *context, mlir::acc::FirstprivateOp op,
3219 mlir::acc::FirstprivateRecipeOp recipe) {
3220 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3221 getFirstprivateOperandsMutable().append(op.getResult());
3224void acc::KernelsOp::addReduction(
MLIRContext *context,
3225 mlir::acc::ReductionOp op,
3226 mlir::acc::ReductionRecipeOp recipe) {
3227 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3228 getReductionOperandsMutable().append(op.getResult());
3231void acc::KernelsOp::addNumWorkersOperand(
3234 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3235 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3236 getNumWorkersMutable()));
3239void acc::KernelsOp::addVectorLengthOperand(
3242 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3243 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3244 getVectorLengthMutable()));
3246void acc::KernelsOp::addAsyncOnly(
3248 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3249 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3252void acc::KernelsOp::addAsyncOperand(
3255 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3256 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3257 getAsyncOperandsMutable()));
3260void acc::KernelsOp::addNumGangsOperands(
3264 if (getNumGangsSegmentsAttr())
3265 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3267 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3268 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3269 getNumGangsMutable(), segments));
3271 setNumGangsSegments(segments);
3274void acc::KernelsOp::addWaitOnly(
3276 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3277 effectiveDeviceTypes));
3279void acc::KernelsOp::addWaitOperands(
3284 if (getWaitOperandsSegments())
3285 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3287 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3288 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3289 getWaitOperandsMutable(), segments));
3290 setWaitOperandsSegments(segments);
3293 if (getHasWaitDevnumAttr())
3294 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3297 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3299 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3306LogicalResult acc::HostDataOp::verify() {
3307 if (getDataClauseOperands().empty())
3308 return emitError(
"at least one operand must appear on the host_data "
3312 for (
mlir::Value operand : getDataClauseOperands()) {
3314 mlir::dyn_cast<acc::UseDeviceOp>(operand.getDefiningOp());
3316 return emitError(
"expect data entry operation as defining op");
3319 if (!seenVars.insert(useDeviceOp.getVar()).second)
3320 return emitError(
"duplicate use_device variable");
3327 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3339 bool &needCommaBetweenValues,
bool &newValue) {
3346 attributes.push_back(gangArgType);
3347 needCommaBetweenValues =
true;
3358 mlir::ArrayAttr &gangOnlyDeviceType) {
3363 bool needCommaBetweenValues =
false;
3364 bool needCommaBeforeOperands =
false;
3368 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3369 parser.
getContext(), mlir::acc::DeviceType::None));
3370 gangOnlyDeviceType =
3371 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3379 if (parser.parseAttribute(
3380 gangOnlyDeviceTypeAttributes.emplace_back()))
3387 needCommaBeforeOperands =
true;
3390 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3391 mlir::acc::GangArgType::Num);
3392 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3393 mlir::acc::GangArgType::Dim);
3394 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3395 parser.
getContext(), mlir::acc::GangArgType::Static);
3398 if (needCommaBeforeOperands) {
3399 needCommaBeforeOperands =
false;
3406 int32_t crtOperandsSize = gangOperands.size();
3408 bool newValue =
false;
3409 bool needValue =
false;
3410 if (needCommaBetweenValues) {
3418 gangOperands, gangOperandsType,
3419 gangArgTypeAttributes, argNum,
3420 needCommaBetweenValues, newValue)))
3423 gangOperands, gangOperandsType,
3424 gangArgTypeAttributes, argDim,
3425 needCommaBetweenValues, newValue)))
3427 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3428 gangOperands, gangOperandsType,
3429 gangArgTypeAttributes, argStatic,
3430 needCommaBetweenValues, newValue)))
3433 if (!newValue && needValue) {
3435 "new value expected after comma");
3443 if (gangOperands.empty())
3446 "expect at least one of num, dim or static values");
3452 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3456 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3457 parser.
getContext(), mlir::acc::DeviceType::None));
3460 seg.push_back(gangOperands.size() - crtOperandsSize);
3468 gangArgTypeAttributes.end());
3469 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3470 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3473 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3474 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3482 std::optional<mlir::ArrayAttr> gangArgTypes,
3483 std::optional<mlir::ArrayAttr> deviceTypes,
3484 std::optional<mlir::DenseI32ArrayAttr> segments,
3485 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3487 if (operands.begin() == operands.end() &&
3502 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3504 llvm::interleaveComma(
3505 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3506 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3507 (*gangArgTypes)[opIdx]);
3508 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3509 p << LoopOp::getGangNumKeyword();
3510 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3511 p << LoopOp::getGangDimKeyword();
3512 else if (gangArgTypeAttr.getValue() ==
3513 mlir::acc::GangArgType::Static)
3514 p << LoopOp::getGangStaticKeyword();
3515 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3526 std::optional<mlir::ArrayAttr> segments,
3527 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3530 for (
auto attr : *segments) {
3531 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3532 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3540static std::optional<mlir::acc::DeviceType>
3542 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3544 return std::nullopt;
3545 for (
auto attr : deviceTypes) {
3546 auto deviceTypeAttr =
3547 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3548 if (!deviceTypeAttr)
3549 return mlir::acc::DeviceType::None;
3550 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3551 return deviceTypeAttr.getValue();
3553 return std::nullopt;
3556LogicalResult acc::LoopOp::verify() {
3557 if (getUpperbound().size() != getStep().size())
3558 return emitError() <<
"number of upperbounds expected to be the same as "
3561 if (getUpperbound().size() != getLowerbound().size())
3562 return emitError() <<
"number of upperbounds expected to be the same as "
3563 "number of lowerbounds";
3565 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3566 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3567 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3568 <<
" as upperbound size";
3571 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3572 return emitOpError() <<
"collapse device_type attr must be define when"
3573 <<
" collapse attr is present";
3575 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3576 getCollapseAttr().getValue().size() !=
3577 getCollapseDeviceTypeAttr().getValue().size())
3578 return emitOpError() <<
"collapse attribute count must match collapse"
3579 <<
" device_type count";
3580 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3582 << acc::stringifyDeviceType(*duplicateDeviceType)
3583 <<
"` found in collapseDeviceType attribute";
3586 if (!getGangOperands().empty()) {
3587 if (!getGangOperandsArgType())
3588 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3589 <<
" when gang operands are present";
3591 if (getGangOperands().size() !=
3592 getGangOperandsArgTypeAttr().getValue().size())
3593 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3594 <<
" gangOperands count";
3596 if (getGangAttr()) {
3599 << acc::stringifyDeviceType(*duplicateDeviceType)
3600 <<
"` found in gang attribute";
3604 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3605 getGangOperandsDeviceTypeAttr(),
"gang")))
3611 << acc::stringifyDeviceType(*duplicateDeviceType)
3612 <<
"` found in worker attribute";
3613 if (
auto duplicateDeviceType =
3616 << acc::stringifyDeviceType(*duplicateDeviceType)
3617 <<
"` found in workerNumOperandsDeviceType attribute";
3619 getWorkerNumOperandsDeviceTypeAttr(),
3626 << acc::stringifyDeviceType(*duplicateDeviceType)
3627 <<
"` found in vector attribute";
3628 if (
auto duplicateDeviceType =
3631 << acc::stringifyDeviceType(*duplicateDeviceType)
3632 <<
"` found in vectorOperandsDeviceType attribute";
3634 getVectorOperandsDeviceTypeAttr(),
3639 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3640 getTileOperandsDeviceTypeAttr(),
"tile")))
3644 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3648 return emitError() <<
"only one of auto, independent, seq can be present "
3654 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3655 return attr.getValue() == mlir::acc::DeviceType::None;
3657 bool hasDefaultSeq =
3659 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3662 bool hasDefaultIndependent =
3663 getIndependentAttr()
3665 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3668 bool hasDefaultAuto =
3670 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3673 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3675 <<
"at least one of auto, independent, seq must be present";
3680 for (
auto attr : getSeqAttr()) {
3681 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3682 if (hasVector(deviceTypeAttr.getValue()) ||
3683 getVectorValue(deviceTypeAttr.getValue()) ||
3684 hasWorker(deviceTypeAttr.getValue()) ||
3685 getWorkerValue(deviceTypeAttr.getValue()) ||
3686 hasGang(deviceTypeAttr.getValue()) ||
3687 getGangValue(mlir::acc::GangArgType::Num,
3688 deviceTypeAttr.getValue()) ||
3689 getGangValue(mlir::acc::GangArgType::Dim,
3690 deviceTypeAttr.getValue()) ||
3691 getGangValue(mlir::acc::GangArgType::Static,
3692 deviceTypeAttr.getValue()))
3693 return emitError() <<
"gang, worker or vector cannot appear with seq";
3698 mlir::acc::PrivateRecipeOp>(
3699 *
this, getPrivateOperands(),
"private")))
3703 mlir::acc::FirstprivateRecipeOp>(
3704 *
this, getFirstprivateOperands(),
"firstprivate")))
3708 mlir::acc::ReductionRecipeOp>(
3709 *
this, getReductionOperands(),
"reduction")))
3712 if (getCombined().has_value() &&
3713 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3714 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3715 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3716 return emitError(
"unexpected combined constructs attribute");
3720 if (getRegion().empty())
3721 return emitError(
"expected non-empty body.");
3723 if (getUnstructured()) {
3724 if (!isContainerLike())
3726 "unstructured acc.loop must not have induction variables");
3727 }
else if (isContainerLike()) {
3731 uint64_t collapseCount = getCollapseValue().value_or(1);
3732 if (getCollapseAttr()) {
3733 for (
auto collapseEntry : getCollapseAttr()) {
3734 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3735 if (intAttr.getValue().getZExtValue() > collapseCount)
3736 collapseCount = intAttr.getValue().getZExtValue();
3744 bool foundSibling =
false;
3746 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3748 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3750 foundSibling =
true;
3755 expectedParent = op;
3758 if (collapseCount == 0)
3764 return emitError(
"found sibling loops inside container-like acc.loop");
3765 if (collapseCount != 0)
3766 return emitError(
"failed to find enough loop-like operations inside "
3767 "container-like acc.loop");
3773unsigned LoopOp::getNumDataOperands() {
3774 return getReductionOperands().size() + getPrivateOperands().size() +
3775 getFirstprivateOperands().size();
3778Value LoopOp::getDataOperand(
unsigned i) {
3779 unsigned numOptional =
3780 getLowerbound().size() + getUpperbound().size() + getStep().size();
3781 numOptional += getGangOperands().size();
3782 numOptional += getVectorOperands().size();
3783 numOptional += getWorkerNumOperands().size();
3784 numOptional += getTileOperands().size();
3785 numOptional += getCacheOperands().size();
3786 return getOperand(numOptional + i);
3789bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3791bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3795bool LoopOp::hasIndependent() {
3796 return hasIndependent(mlir::acc::DeviceType::None);
3799bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3803bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3805bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3810 return getVectorValue(mlir::acc::DeviceType::None);
3813mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3815 getVectorOperands(), deviceType);
3818bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3820bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3825 return getWorkerValue(mlir::acc::DeviceType::None);
3828mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3830 getWorkerNumOperands(), deviceType);
3833bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3835bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3840 return getTileValues(mlir::acc::DeviceType::None);
3844LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3846 getTileOperandsSegments(), deviceType);
3849std::optional<int64_t> LoopOp::getCollapseValue() {
3850 return getCollapseValue(mlir::acc::DeviceType::None);
3853std::optional<int64_t>
3854LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3855 if (!getCollapseAttr())
3856 return std::nullopt;
3857 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3859 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3860 return intAttr.getValue().getZExtValue();
3862 return std::nullopt;
3865mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3866 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3869mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3870 mlir::acc::DeviceType deviceType) {
3871 if (getGangOperands().empty())
3873 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3874 int32_t nbOperandsBefore = 0;
3875 for (
unsigned i = 0; i < *pos; ++i)
3876 nbOperandsBefore += (*getGangOperandsSegments())[i];
3879 .drop_front(nbOperandsBefore)
3880 .take_front((*getGangOperandsSegments())[*pos]);
3882 int32_t argTypeIdx = nbOperandsBefore;
3883 for (
auto value : values) {
3884 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3885 (*getGangOperandsArgType())[argTypeIdx]);
3886 if (gangArgTypeAttr.getValue() == gangArgType)
3894bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
3896bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
3901 return {&getRegion()};
3945 if (!regionArgs.empty()) {
3946 p << acc::LoopOp::getControlKeyword() <<
"(";
3947 llvm::interleaveComma(regionArgs, p,
3949 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
3950 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
3951 <<
" : " << stepType <<
") ";
3958 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
3959 effectiveDeviceTypes));
3962void acc::LoopOp::addIndependent(
3964 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
3965 context, getIndependentAttr(), effectiveDeviceTypes));
3970 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
3971 effectiveDeviceTypes));
3974void acc::LoopOp::setCollapseForDeviceTypes(
3976 llvm::APInt value) {
3980 assert((getCollapseAttr() ==
nullptr) ==
3981 (getCollapseDeviceTypeAttr() ==
nullptr));
3982 assert(value.getBitWidth() == 64);
3984 if (getCollapseAttr()) {
3985 for (
const auto &existing :
3986 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
3987 newValues.push_back(std::get<0>(existing));
3988 newDeviceTypes.push_back(std::get<1>(existing));
3992 if (effectiveDeviceTypes.empty()) {
3995 newValues.push_back(
3996 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
3997 newDeviceTypes.push_back(
3998 acc::DeviceTypeAttr::get(context, DeviceType::None));
4000 for (DeviceType dt : effectiveDeviceTypes) {
4001 newValues.push_back(
4002 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
4003 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4007 setCollapseAttr(ArrayAttr::get(context, newValues));
4008 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
4011void acc::LoopOp::setTileForDeviceTypes(
4015 if (getTileOperandsSegments())
4016 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
4018 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4019 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4020 getTileOperandsMutable(), segments));
4022 setTileOperandsSegments(segments);
4025void acc::LoopOp::addVectorOperand(
4028 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4029 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4030 newValue, getVectorOperandsMutable()));
4033void acc::LoopOp::addEmptyVector(
4035 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4036 effectiveDeviceTypes));
4039void acc::LoopOp::addWorkerNumOperand(
4042 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4043 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4044 newValue, getWorkerNumOperandsMutable()));
4047void acc::LoopOp::addEmptyWorker(
4049 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4050 effectiveDeviceTypes));
4053void acc::LoopOp::addEmptyGang(
4055 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4056 effectiveDeviceTypes));
4059bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
4060 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
4061 return attr.getValue() == dt;
4063 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
4064 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
4067 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
4069 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
4071 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
4077bool acc::LoopOp::hasDefaultGangWorkerVector() {
4078 return hasAnyGangWorkerVector(DeviceType::None);
4081bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
4082 return hasVector(deviceType) || getVectorValue(deviceType) ||
4083 hasWorker(deviceType) || getWorkerValue(deviceType) ||
4084 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
4085 getGangValue(GangArgType::Dim, deviceType) ||
4086 getGangValue(GangArgType::Static, deviceType);
4090acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
4091 if (hasSeq(deviceType))
4092 return LoopParMode::loop_seq;
4093 if (hasAuto(deviceType))
4094 return LoopParMode::loop_auto;
4095 if (hasIndependent(deviceType))
4096 return LoopParMode::loop_independent;
4098 return LoopParMode::loop_seq;
4100 return LoopParMode::loop_auto;
4101 assert(hasIndependent() &&
4102 "loop must have default auto, seq, or independent");
4103 return LoopParMode::loop_independent;
4106void acc::LoopOp::addGangOperands(
4111 getGangOperandsSegments())
4112 llvm::copy(*existingSegments, std::back_inserter(segments));
4114 unsigned beforeCount = segments.size();
4116 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4117 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4118 getGangOperandsMutable(), segments));
4120 setGangOperandsSegments(segments);
4127 unsigned numAdded = segments.size() - beforeCount;
4131 if (getGangOperandsArgTypeAttr())
4132 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
4134 for (
auto i : llvm::index_range(0u, numAdded)) {
4135 llvm::transform(argTypes, std::back_inserter(gangTypes),
4136 [=](mlir::acc::GangArgType gangTy) {
4137 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
4142 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
4146void acc::LoopOp::addPrivatization(
MLIRContext *context,
4147 mlir::acc::PrivateOp op,
4148 mlir::acc::PrivateRecipeOp recipe) {
4149 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4150 getPrivateOperandsMutable().append(op.getResult());
4153void acc::LoopOp::addFirstPrivatization(
4154 MLIRContext *context, mlir::acc::FirstprivateOp op,
4155 mlir::acc::FirstprivateRecipeOp recipe) {
4156 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4157 getFirstprivateOperandsMutable().append(op.getResult());
4160void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
4161 mlir::acc::ReductionRecipeOp recipe) {
4162 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4163 getReductionOperandsMutable().append(op.getResult());
4170LogicalResult acc::DataOp::verify() {
4175 return emitError(
"at least one operand or the default attribute "
4176 "must appear on the data operation");
4178 for (
mlir::Value operand : getDataClauseOperands())
4179 if (isa<BlockArgument>(operand) ||
4180 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4181 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
4182 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp>(
4183 operand.getDefiningOp()))
4184 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4193unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
4195Value DataOp::getDataOperand(
unsigned i) {
4196 unsigned numOptional = getIfCond() ? 1 : 0;
4198 numOptional += getWaitOperands().size();
4199 return getOperand(numOptional + i);
4202bool acc::DataOp::hasAsyncOnly() {
4203 return hasAsyncOnly(mlir::acc::DeviceType::None);
4206bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4211 return getAsyncValue(mlir::acc::DeviceType::None);
4214mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4219bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
4221bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4226 return getWaitValues(mlir::acc::DeviceType::None);
4230DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4232 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4233 getHasWaitDevnum(), deviceType);
4237 return getWaitDevnum(mlir::acc::DeviceType::None);
4240mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4242 getWaitOperandsSegments(), getHasWaitDevnum(),
4246void acc::DataOp::addAsyncOnly(
4248 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4249 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4252void acc::DataOp::addAsyncOperand(
4255 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4256 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4257 getAsyncOperandsMutable()));
4260void acc::DataOp::addWaitOnly(
MLIRContext *context,
4262 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4263 effectiveDeviceTypes));
4266void acc::DataOp::addWaitOperands(
4271 if (getWaitOperandsSegments())
4272 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4274 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4275 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4276 getWaitOperandsMutable(), segments));
4277 setWaitOperandsSegments(segments);
4280 if (getHasWaitDevnumAttr())
4281 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4284 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4286 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4293LogicalResult acc::ExitDataOp::verify() {
4297 if (getDataClauseOperands().empty())
4298 return emitError(
"at least one operand must be present in dataOperands on "
4299 "the exit data operation");
4303 if (getAsyncOperand() && getAsync())
4304 return emitError(
"async attribute cannot appear with asyncOperand");
4308 if (!getWaitOperands().empty() && getWait())
4309 return emitError(
"wait attribute cannot appear with waitOperands");
4311 if (getWaitDevnum() && getWaitOperands().empty())
4312 return emitError(
"wait_devnum cannot appear without waitOperands");
4317unsigned ExitDataOp::getNumDataOperands() {
4318 return getDataClauseOperands().size();
4321Value ExitDataOp::getDataOperand(
unsigned i) {
4322 unsigned numOptional = getIfCond() ? 1 : 0;
4323 numOptional += getAsyncOperand() ? 1 : 0;
4324 numOptional += getWaitDevnum() ? 1 : 0;
4325 return getOperand(getWaitOperands().size() + numOptional + i);
4330 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4333void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4335 assert(effectiveDeviceTypes.empty());
4336 assert(!getAsyncAttr());
4337 assert(!getAsyncOperand());
4339 setAsyncAttr(mlir::UnitAttr::get(context));
4342void ExitDataOp::addAsyncOperand(
4345 assert(effectiveDeviceTypes.empty());
4346 assert(!getAsyncAttr());
4347 assert(!getAsyncOperand());
4349 getAsyncOperandMutable().append(newValue);
4354 assert(effectiveDeviceTypes.empty());
4355 assert(!getWaitAttr());
4356 assert(getWaitOperands().empty());
4357 assert(!getWaitDevnum());
4359 setWaitAttr(mlir::UnitAttr::get(context));
4362void ExitDataOp::addWaitOperands(
4365 assert(effectiveDeviceTypes.empty());
4366 assert(!getWaitAttr());
4367 assert(getWaitOperands().empty());
4368 assert(!getWaitDevnum());
4373 getWaitDevnumMutable().append(newValues.front());
4374 newValues = newValues.drop_front();
4377 getWaitOperandsMutable().append(newValues);
4384LogicalResult acc::EnterDataOp::verify() {
4388 if (getDataClauseOperands().empty())
4389 return emitError(
"at least one operand must be present in dataOperands on "
4390 "the enter data operation");
4394 if (getAsyncOperand() && getAsync())
4395 return emitError(
"async attribute cannot appear with asyncOperand");
4399 if (!getWaitOperands().empty() && getWait())
4400 return emitError(
"wait attribute cannot appear with waitOperands");
4402 if (getWaitDevnum() && getWaitOperands().empty())
4403 return emitError(
"wait_devnum cannot appear without waitOperands");
4405 for (
mlir::Value operand : getDataClauseOperands())
4406 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp>(
4407 operand.getDefiningOp()))
4408 return emitError(
"expect data entry operation as defining op");
4413unsigned EnterDataOp::getNumDataOperands() {
4414 return getDataClauseOperands().size();
4417Value EnterDataOp::getDataOperand(
unsigned i) {
4418 unsigned numOptional = getIfCond() ? 1 : 0;
4419 numOptional += getAsyncOperand() ? 1 : 0;
4420 numOptional += getWaitDevnum() ? 1 : 0;
4421 return getOperand(getWaitOperands().size() + numOptional + i);
4426 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4429void EnterDataOp::addAsyncOnly(
4431 assert(effectiveDeviceTypes.empty());
4432 assert(!getAsyncAttr());
4433 assert(!getAsyncOperand());
4435 setAsyncAttr(mlir::UnitAttr::get(context));
4438void EnterDataOp::addAsyncOperand(
4441 assert(effectiveDeviceTypes.empty());
4442 assert(!getAsyncAttr());
4443 assert(!getAsyncOperand());
4445 getAsyncOperandMutable().append(newValue);
4448void EnterDataOp::addWaitOnly(
MLIRContext *context,
4450 assert(effectiveDeviceTypes.empty());
4451 assert(!getWaitAttr());
4452 assert(getWaitOperands().empty());
4453 assert(!getWaitDevnum());
4455 setWaitAttr(mlir::UnitAttr::get(context));
4458void EnterDataOp::addWaitOperands(
4461 assert(effectiveDeviceTypes.empty());
4462 assert(!getWaitAttr());
4463 assert(getWaitOperands().empty());
4464 assert(!getWaitDevnum());
4469 getWaitDevnumMutable().append(newValues.front());
4470 newValues = newValues.drop_front();
4473 getWaitOperandsMutable().append(newValues);
4480LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4486LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4492LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4499 if (
Value writeVal = op.getWriteOpVal()) {
4508LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4510LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4516AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4517 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4519 return dyn_cast<AtomicReadOp>(getSecondOp());
4522AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4523 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4525 return dyn_cast<AtomicWriteOp>(getSecondOp());
4528AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4529 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4531 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4534LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4540template <
typename Op>
4543 bool requireAtLeastOneOperand =
true) {
4544 if (operands.empty() && requireAtLeastOneOperand)
4547 "at least one operand must appear on the declare operation");
4550 if (isa<BlockArgument>(operand) ||
4551 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4552 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4553 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp>(
4554 operand.getDefiningOp()))
4556 "expect valid declare data entry operation or acc.getdeviceptr "
4560 assert(var &&
"declare operands can only be data entry operations which "
4563 std::optional<mlir::acc::DataClause> dataClauseOptional{
4565 assert(dataClauseOptional.has_value() &&
4566 "declare operands can only be data entry operations which must have "
4568 (
void)dataClauseOptional;
4574LogicalResult acc::DeclareEnterOp::verify() {
4582LogicalResult acc::DeclareExitOp::verify() {
4593LogicalResult acc::DeclareOp::verify() {
4602 acc::DeviceType dtype) {
4603 unsigned parallelism = 0;
4604 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4605 parallelism += op.hasWorker(dtype) ? 1 : 0;
4606 parallelism += op.hasVector(dtype) ? 1 : 0;
4607 parallelism += op.hasSeq(dtype) ? 1 : 0;
4611LogicalResult acc::RoutineOp::verify() {
4612 unsigned baseParallelism =
4615 if (baseParallelism > 1)
4616 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4617 "be present at the same time";
4619 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4621 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4622 if (dtype == acc::DeviceType::None)
4626 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4627 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4628 "be present at the same time for device_type `"
4629 << acc::stringifyDeviceType(dtype) <<
"`";
4636 mlir::ArrayAttr &bindIdName,
4637 mlir::ArrayAttr &bindStrName,
4638 mlir::ArrayAttr &deviceIdTypes,
4639 mlir::ArrayAttr &deviceStrTypes) {
4646 mlir::Attribute newAttr;
4647 bool isSymbolRefAttr;
4648 auto parseResult = parser.parseAttribute(newAttr);
4649 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4650 bindIdNameAttrs.push_back(symbolRefAttr);
4651 isSymbolRefAttr = true;
4652 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4653 bindStrNameAttrs.push_back(stringAttr);
4654 isSymbolRefAttr =
false;
4659 if (isSymbolRefAttr) {
4660 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4661 parser.getContext(), mlir::acc::DeviceType::None));
4663 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4664 parser.getContext(), mlir::acc::DeviceType::None));
4667 if (isSymbolRefAttr) {
4668 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4669 parser.parseRSquare())
4672 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4673 parser.parseRSquare())
4681 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4682 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4683 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4684 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4690 std::optional<mlir::ArrayAttr> bindIdName,
4691 std::optional<mlir::ArrayAttr> bindStrName,
4692 std::optional<mlir::ArrayAttr> deviceIdTypes,
4693 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4700 allBindNames.append(bindIdName->begin(), bindIdName->end());
4701 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4706 allBindNames.append(bindStrName->begin(), bindStrName->end());
4707 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4711 if (!allBindNames.empty())
4712 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4713 [&](
const auto &pair) {
4714 p << std::get<0>(pair);
4720 mlir::ArrayAttr &gang,
4721 mlir::ArrayAttr &gangDim,
4722 mlir::ArrayAttr &gangDimDeviceTypes) {
4725 gangDimDeviceTypeAttrs;
4726 bool needCommaBeforeOperands =
false;
4730 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4731 parser.
getContext(), mlir::acc::DeviceType::None));
4732 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4739 if (parser.parseAttribute(gangAttrs.emplace_back()))
4746 needCommaBeforeOperands =
true;
4749 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4753 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4754 parser.parseColon() ||
4755 parser.parseAttribute(gangDimAttrs.emplace_back()))
4757 if (succeeded(parser.parseOptionalLSquare())) {
4758 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4759 parser.parseRSquare())
4762 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4763 parser.getContext(), mlir::acc::DeviceType::None));
4769 if (
failed(parser.parseRParen()))
4772 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4773 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4774 gangDimDeviceTypes =
4775 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4781 std::optional<mlir::ArrayAttr> gang,
4782 std::optional<mlir::ArrayAttr> gangDim,
4783 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4786 gang->size() == 1) {
4787 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4788 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4800 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4801 [&](
const auto &pair) {
4802 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4803 p << std::get<0>(pair);
4811 mlir::ArrayAttr &deviceTypes) {
4815 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4816 parser.
getContext(), mlir::acc::DeviceType::None));
4817 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4824 if (parser.parseAttribute(attributes.emplace_back()))
4832 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4838 std::optional<mlir::ArrayAttr> deviceTypes) {
4841 auto deviceTypeAttr =
4842 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4843 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4852 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4858bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4860bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4864bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4866bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4870bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4872bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4876std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4877RoutineOp::getBindNameValue() {
4878 return getBindNameValue(mlir::acc::DeviceType::None);
4881std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4882RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4884 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4885 auto attr = (*getBindIdName())[*pos];
4886 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4887 assert(symbolRefAttr &&
"expected SymbolRef");
4888 return symbolRefAttr;
4893 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
4894 auto attr = (*getBindStrName())[*pos];
4895 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
4896 assert(stringAttr &&
"expected String");
4901 return std::nullopt;
4904bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4906bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
4910std::optional<int64_t> RoutineOp::getGangDimValue() {
4911 return getGangDimValue(mlir::acc::DeviceType::None);
4914std::optional<int64_t>
4915RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
4917 return std::nullopt;
4918 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
4919 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
4920 return intAttr.getInt();
4922 return std::nullopt;
4927 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4928 effectiveDeviceTypes));
4933 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4934 effectiveDeviceTypes));
4939 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4940 effectiveDeviceTypes));
4945 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4946 effectiveDeviceTypes));
4955 if (getGangDimAttr())
4956 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
4957 if (getGangDimDeviceTypeAttr())
4958 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
4960 assert(dimValues.size() == deviceTypes.size());
4962 if (effectiveDeviceTypes.empty()) {
4963 dimValues.push_back(
4964 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4965 deviceTypes.push_back(
4966 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
4968 for (DeviceType dt : effectiveDeviceTypes) {
4969 dimValues.push_back(
4970 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
4971 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4974 assert(dimValues.size() == deviceTypes.size());
4976 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
4977 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
4980void RoutineOp::addBindStrName(
MLIRContext *context,
4982 mlir::StringAttr val) {
4983 unsigned before = getBindStrNameDeviceTypeAttr()
4984 ? getBindStrNameDeviceTypeAttr().size()
4987 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4988 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
4989 unsigned after = getBindStrNameDeviceTypeAttr().size();
4992 if (getBindStrNameAttr())
4993 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
4994 for (
unsigned i = 0; i < after - before; ++i)
4995 vals.push_back(val);
4997 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
5000void RoutineOp::addBindIDName(
MLIRContext *context,
5002 mlir::SymbolRefAttr val) {
5004 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
5006 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5007 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
5008 unsigned after = getBindIdNameDeviceTypeAttr().size();
5011 if (getBindIdNameAttr())
5012 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
5013 for (
unsigned i = 0; i < after - before; ++i)
5014 vals.push_back(val);
5016 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
5023LogicalResult acc::InitOp::verify() {
5024 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5025 return emitOpError(
"cannot be nested in a compute operation");
5029void acc::InitOp::addDeviceType(
MLIRContext *context,
5030 mlir::acc::DeviceType deviceType) {
5032 if (getDeviceTypesAttr())
5033 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5035 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5036 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5043LogicalResult acc::ShutdownOp::verify() {
5044 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5045 return emitOpError(
"cannot be nested in a compute operation");
5049void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
5050 mlir::acc::DeviceType deviceType) {
5052 if (getDeviceTypesAttr())
5053 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5055 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5056 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5063LogicalResult acc::SetOp::verify() {
5064 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5065 return emitOpError(
"cannot be nested in a compute operation");
5066 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
5067 return emitOpError(
"at least one default_async, device_num, or device_type "
5068 "operand must appear");
5076LogicalResult acc::UpdateOp::verify() {
5078 if (getDataClauseOperands().empty())
5079 return emitError(
"at least one value must be present in dataOperands");
5082 getAsyncOperandsDeviceTypeAttr(),
5087 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
5088 getWaitOperandsDeviceTypeAttr(),
"wait")))
5094 for (
mlir::Value operand : getDataClauseOperands())
5095 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp>(
5096 operand.getDefiningOp()))
5097 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
5103unsigned UpdateOp::getNumDataOperands() {
5104 return getDataClauseOperands().size();
5107Value UpdateOp::getDataOperand(
unsigned i) {
5109 numOptional += getIfCond() ? 1 : 0;
5110 return getOperand(getWaitOperands().size() + numOptional + i);
5115 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
5118bool UpdateOp::hasAsyncOnly() {
5119 return hasAsyncOnly(mlir::acc::DeviceType::None);
5122bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
5127 return getAsyncValue(mlir::acc::DeviceType::None);
5130mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
5140bool UpdateOp::hasWaitOnly() {
5141 return hasWaitOnly(mlir::acc::DeviceType::None);
5144bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
5149 return getWaitValues(mlir::acc::DeviceType::None);
5153UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
5155 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
5156 getHasWaitDevnum(), deviceType);
5160 return getWaitDevnum(mlir::acc::DeviceType::None);
5163mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
5165 getWaitOperandsSegments(), getHasWaitDevnum(),
5171 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
5172 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
5175void UpdateOp::addAsyncOperand(
5178 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5179 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
5180 getAsyncOperandsMutable()));
5185 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
5186 effectiveDeviceTypes));
5189void UpdateOp::addWaitOperands(
5194 if (getWaitOperandsSegments())
5195 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
5197 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5198 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
5199 getWaitOperandsMutable(), segments));
5200 setWaitOperandsSegments(segments);
5203 if (getHasWaitDevnumAttr())
5204 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5207 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5209 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5216LogicalResult acc::WaitOp::verify() {
5219 if (getAsyncOperand() && getAsync())
5220 return emitError(
"async attribute cannot appear with asyncOperand");
5222 if (getWaitDevnum() && getWaitOperands().empty())
5223 return emitError(
"wait_devnum cannot appear without waitOperands");
5228#define GET_OP_CLASSES
5229#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5231#define GET_ATTRDEF_CLASSES
5232#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5234#define GET_TYPEDEF_CLASSES
5235#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5246 .Case<ACC_DATA_ENTRY_OPS>(
5247 [&](
auto entry) {
return entry.getVarPtr(); })
5248 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5249 [&](
auto exit) {
return exit.getVarPtr(); })
5267 [&](
auto entry) {
return entry.getVarType(); })
5268 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5269 [&](
auto exit) {
return exit.getVarType(); })
5279 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>(
5280 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5290 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5299 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5309 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5311 dataClause.getBounds().begin(), dataClause.getBounds().end());
5323 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5325 dataClause.getAsyncOperands().begin(),
5326 dataClause.getAsyncOperands().end());
5337 return dataClause.getAsyncOperandsDeviceTypeAttr();
5345 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5352 .Case<ACC_DATA_ENTRY_OPS>([&](
auto entry) {
return entry.getName(); })
5359std::optional<mlir::acc::DataClause>
5364 .Case<ACC_DATA_ENTRY_OPS>(
5365 [&](
auto entry) {
return entry.getDataClause(); })
5373 [&](
auto entry) {
return entry.getImplicit(); })
5382 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5384 return dataOperands;
5392 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5394 return dataOperands;
5401 [&](
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 parseArrayAttr(mlir::OpAsmParser &parser, mlir::ArrayAttr &attr)
static ParseResult parseBindName(OpAsmParser &parser, mlir::ArrayAttr &bindIdName, mlir::ArrayAttr &bindStrName, mlir::ArrayAttr &deviceIdTypes, mlir::ArrayAttr &deviceStrTypes)
static void printRecipeSym(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::SymbolRefAttr recipeAttr)
static mlir::Operation::operand_range getWaitValuesWithoutDevnum(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t > > segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static void printArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::ArrayAttr attr)
static bool hasOnlyDeviceTypeNone(std::optional< mlir::ArrayAttr > attrs)
static ParseResult parseRecipeSym(mlir::OpAsmParser &parser, mlir::SymbolRefAttr &recipeAttr)
static void printAccVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value accVar, mlir::Type accVarType)
static mlir::Value getWaitDevnumValue(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t > > segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static bool hasAnyGangWorkerVectorForDeviceType(std::optional< mlir::ArrayAttr > numGangsDeviceType, mlir::Operation::operand_range numGangs, std::optional< llvm::ArrayRef< int32_t > > numGangsSegments, std::optional< mlir::ArrayAttr > numWorkersDeviceType, mlir::Operation::operand_range numWorkers, std::optional< mlir::ArrayAttr > vectorLengthDeviceType, mlir::Operation::operand_range vectorLength, mlir::acc::DeviceType deviceType)
static void printVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value var)
static void printWaitClause(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments, std::optional< mlir::ArrayAttr > hasDevNum, std::optional< mlir::ArrayAttr > keywordOnly)
static ParseResult parseWaitClause(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments, mlir::ArrayAttr &hasDevNum, mlir::ArrayAttr &keywordOnly)
static bool hasDeviceTypeValues(std::optional< mlir::ArrayAttr > arrayAttr)
static void printDeviceTypeArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > deviceTypes)
static ParseResult parseGangValue(OpAsmParser &parser, llvm::StringRef keyword, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, llvm::SmallVector< GangArgTypeAttr > &attributes, GangArgTypeAttr gangArgType, bool &needCommaBetweenValues, bool &newValue)
static ParseResult parseCombinedConstructsLoop(mlir::OpAsmParser &parser, mlir::acc::CombinedConstructsTypeAttr &attr)
static std::optional< mlir::acc::DeviceType > checkDeviceTypes(mlir::ArrayAttr deviceTypes)
Check for duplicates in the DeviceType array attribute.
static LogicalResult checkDeclareOperands(Op &op, const mlir::ValueRange &operands, bool requireAtLeastOneOperand=true)
static LogicalResult checkVarAndAccVar(Op op)
static ParseResult parseOperandsWithKeywordOnly(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::UnitAttr &attr)
static void printDeviceTypes(mlir::OpAsmPrinter &p, std::optional< mlir::ArrayAttr > deviceTypes)
static LogicalResult checkVarAndVarType(Op op)
static LogicalResult checkValidModifier(Op op, acc::DataClauseModifier validModifiers)
static void addOperandEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, MutableOperandRange operand)
Helper to add an effect on an operand, referenced by its mutable range.
ParseResult parseLoopControl(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &lowerbound, SmallVectorImpl< Type > &lowerboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &upperbound, SmallVectorImpl< Type > &upperboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &step, SmallVectorImpl< Type > &stepType)
loop-control ::= control ( ssa-id-and-type-list ) = ( ssa-id-and-type-list ) to ( ssa-id-and-type-lis...
static LogicalResult checkDataOperands(Op op, const mlir::ValueRange &operands)
Check dataOperands for acc.parallel, acc.serial and acc.kernels.
static ParseResult parseDeviceTypeOperands(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes)
static mlir::Value getValueInDeviceTypeSegment(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, mlir::acc::DeviceType deviceType)
static void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
static LogicalResult checkNoModifier(Op op)
static ParseResult parseAccVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var, mlir::Type &accVarType)
static std::optional< unsigned > findSegment(ArrayAttr segments, mlir::acc::DeviceType deviceType)
static ParseResult parseDenseBoolArrayAttr(mlir::OpAsmParser &parser, mlir::DenseBoolArrayAttr &attr)
static mlir::Operation::operand_range getValuesFromSegments(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, std::optional< llvm::ArrayRef< int32_t > > segments, mlir::acc::DeviceType deviceType)
static ParseResult parseNumGangs(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
static void getSingleRegionOpSuccessorRegions(Operation *op, Region ®ion, RegionBranchPoint point, SmallVectorImpl< RegionSuccessor > ®ions)
Generic helper for single-region OpenACC ops that execute their body once and then continue after the...
static ParseResult parseVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var)
void printLoopControl(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lowerbound, TypeRange lowerboundType, ValueRange upperbound, TypeRange upperboundType, ValueRange steps, TypeRange stepType)
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
static void printDenseBoolArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::DenseBoolArrayAttr attr)
static ParseResult parseDeviceTypeArrayAttr(OpAsmParser &parser, mlir::ArrayAttr &deviceTypes)
static ParseResult parseRoutineGangClause(OpAsmParser &parser, mlir::ArrayAttr &gang, mlir::ArrayAttr &gangDim, mlir::ArrayAttr &gangDimDeviceTypes)
static void printDeviceTypeOperandsWithSegment(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments)
static void printDeviceTypeOperands(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes)
static void printOperandWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::Value > operand, mlir::Type operandType, mlir::UnitAttr attr)
static ParseResult 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 parseOptionalRParen()=0
Parse a ) token if present.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
virtual void printType(Type type)
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::DenseArrayAttrImpl< bool > DenseBoolArrayAttr
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
This is the representation of an operand reference.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Region * addRegion()
Create a region that should be attached to the operation.