27#include "llvm/ADT/SmallSet.h"
28#include "llvm/ADT/TypeSwitch.h"
29#include "llvm/Support/LogicalResult.h"
35#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.cpp.inc"
36#include "mlir/Dialect/OpenACC/OpenACCOpsEnums.cpp.inc"
37#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.cpp.inc"
38#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.cpp.inc"
39#include "mlir/Dialect/OpenACCMPCommon/Interfaces/OpenACCMPOpsInterfaces.cpp.inc"
43static bool isScalarLikeType(
Type type) {
51 if (!varName.empty()) {
52 auto varNameAttr = acc::VarNameAttr::get(builder.
getContext(), varName);
58struct MemRefPointerLikeModel
59 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel<T>, T> {
61 return cast<T>(pointer).getElementType();
64 mlir::acc::VariableTypeCategory
67 if (
auto mappableTy = dyn_cast<MappableType>(varType)) {
68 return mappableTy.getTypeCategory(varPtr);
70 auto memrefTy = cast<T>(pointer);
71 if (!memrefTy.hasRank()) {
74 return mlir::acc::VariableTypeCategory::uncategorized;
77 if (memrefTy.getRank() == 0) {
78 if (isScalarLikeType(memrefTy.getElementType())) {
79 return mlir::acc::VariableTypeCategory::scalar;
83 return mlir::acc::VariableTypeCategory::uncategorized;
87 assert(memrefTy.getRank() > 0 &&
"rank expected to be positive");
88 return mlir::acc::VariableTypeCategory::array;
91 mlir::Value genAllocate(Type pointer, OpBuilder &builder, Location loc,
92 StringRef varName, Type varType, Value originalVar,
93 bool &needsFree)
const {
94 auto memrefTy = cast<MemRefType>(pointer);
98 if (memrefTy.hasStaticShape()) {
100 auto allocaOp = memref::AllocaOp::create(builder, loc, memrefTy);
101 attachVarNameAttr(allocaOp, builder, varName);
102 return allocaOp.getResult();
107 if (originalVar && originalVar.
getType() == memrefTy &&
108 memrefTy.hasRank()) {
109 SmallVector<Value> dynamicSizes;
110 for (int64_t i = 0; i < memrefTy.getRank(); ++i) {
111 if (memrefTy.isDynamicDim(i)) {
115 memref::DimOp::create(builder, loc, originalVar, indexValue);
116 dynamicSizes.push_back(dimSize);
123 memref::AllocOp::create(builder, loc, memrefTy, dynamicSizes);
124 attachVarNameAttr(allocOp, builder, varName);
125 return allocOp.getResult();
132 bool genFree(Type pointer, OpBuilder &builder, Location loc,
134 Type varType)
const {
137 Value valueToInspect = allocRes ? allocRes : memrefValue;
140 Value currentValue = valueToInspect;
141 Operation *originalAlloc =
nullptr;
145 while (currentValue) {
148 if (isa<memref::AllocOp, memref::AllocaOp>(definingOp)) {
149 originalAlloc = definingOp;
154 if (
auto castOp = dyn_cast<memref::CastOp>(definingOp)) {
155 currentValue = castOp.getSource();
160 if (
auto reinterpretCastOp =
161 dyn_cast<memref::ReinterpretCastOp>(definingOp)) {
162 currentValue = reinterpretCastOp.getSource();
174 if (isa<memref::AllocaOp>(originalAlloc)) {
178 if (isa<memref::AllocOp>(originalAlloc)) {
180 memref::DeallocOp::create(builder, loc, memrefValue);
189 bool genCopy(Type pointer, OpBuilder &builder, Location loc,
193 auto destMemref = dyn_cast_if_present<TypedValue<MemRefType>>(destination);
194 auto srcMemref = dyn_cast_if_present<TypedValue<MemRefType>>(source);
200 if (destMemref && srcMemref &&
201 destMemref.getType().getElementType() ==
202 srcMemref.getType().getElementType() &&
203 destMemref.getType().getShape() == srcMemref.getType().getShape()) {
204 memref::CopyOp::create(builder, loc, srcMemref, destMemref);
211 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
213 Type valueType)
const {
218 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(srcPtr);
222 auto memrefTy = memrefValue.
getType();
225 if (memrefTy.getRank() != 0)
228 return memref::LoadOp::create(builder, loc, memrefValue,
ValueRange{});
231 bool genStore(Type pointer, OpBuilder &builder, Location loc,
237 auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(destPtr);
241 auto memrefTy = memrefValue.getType();
244 if (memrefTy.getRank() != 0)
247 memref::StoreOp::create(builder, loc, valueToStore, memrefValue);
251 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
252 Type resultType)
const {
253 if (value.
getType() == resultType)
256 if (isa<BaseMemRefType>(value.
getType()) &&
257 isa<BaseMemRefType>(resultType)) {
260 return memref::CastOp::create(builder, loc, resultType, value);
261 if (memref::MemorySpaceCastOp::areCastCompatible(
263 return memref::MemorySpaceCastOp::create(builder, loc, resultType,
270 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
271 if (!isa<BaseMemRefType>(resPtrLike))
272 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
274 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
275 if (!isa<BaseMemRefType>(valPtrLike))
276 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
282 bool isDeviceAccessible(Type pointer, Value var)
const {
283 auto memrefTy = cast<T>(pointer);
284 Attribute memSpace = memrefTy.getMemorySpace();
285 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
288 MemRefType getAsMemRefType(Type pointer, ModuleOp module)
const {
290 return dyn_cast<MemRefType>(pointer);
294struct LLVMPointerPointerLikeModel
295 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
296 LLVM::LLVMPointerType> {
299 mlir::Value
genLoad(Type pointer, OpBuilder &builder, Location loc,
301 Type valueType)
const {
306 return LLVM::LoadOp::create(builder, loc, valueType, srcPtr);
309 bool genStore(Type pointer, OpBuilder &builder, Location loc,
311 LLVM::StoreOp::create(builder, loc, valueToStore, destPtr);
315 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
316 Type resultType)
const {
317 if (value.
getType() == resultType)
320 auto srcPtrTy = dyn_cast<LLVM::LLVMPointerType>(value.
getType());
321 auto dstPtrTy = dyn_cast<LLVM::LLVMPointerType>(resultType);
322 if (srcPtrTy && dstPtrTy) {
323 if (srcPtrTy.getAddressSpace() != dstPtrTy.getAddressSpace())
324 return LLVM::AddrSpaceCastOp::create(builder, loc, resultType, value);
328 if (srcPtrTy && isa<IntegerType>(resultType))
329 return LLVM::PtrToIntOp::create(builder, loc, resultType, value);
332 Value intVal = value;
333 if (isa<IndexType>(value.
getType()))
334 intVal = arith::IndexCastUIOp::create(builder, loc,
336 if (isa<IntegerType>(intVal.
getType()))
337 return LLVM::IntToPtrOp::create(builder, loc, resultType, intVal);
340 if (
auto resPtrLike = dyn_cast<PointerLikeType>(resultType))
341 if (!isa<LLVM::LLVMPointerType>(resPtrLike))
342 if (Value v = resPtrLike.genCast(builder, loc, value, resultType))
344 if (
auto valPtrLike = dyn_cast<PointerLikeType>(value.
getType()))
345 if (!isa<LLVM::LLVMPointerType>(valPtrLike))
346 if (Value v = valPtrLike.genCast(builder, loc, value, resultType))
349 return UnrealizedConversionCastOp::create(builder, loc,
355struct PrivateTypePointerLikeModel
356 :
public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
359 return cast<PrivateType>(type).getBaseTy();
362 Value
genCast(Type, OpBuilder &builder, Location loc, Value value,
363 Type resultType)
const {
364 if (value.
getType() == resultType)
366 if (!isa<PointerLikeType>(resultType))
368 return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
371 MemRefType getAsMemRefType(Type type, ModuleOp module)
const {
372 Type baseTy = cast<PrivateType>(type).getBaseTy();
373 if (
auto memrefTy = dyn_cast<MemRefType>(baseTy))
375 if (
auto ptrLikeTy = dyn_cast<PointerLikeType>(baseTy))
376 return ptrLikeTy.getAsMemRefType(module);
381struct MemrefAddressOfGlobalModel
382 :
public AddressOfGlobalOpInterface::ExternalModel<
383 MemrefAddressOfGlobalModel, memref::GetGlobalOp> {
384 SymbolRefAttr getSymbol(Operation *op)
const {
385 auto getGlobalOp = cast<memref::GetGlobalOp>(op);
386 return getGlobalOp.getNameAttr();
390struct LLVMAddressOfGlobalModel
391 :
public AddressOfGlobalOpInterface::ExternalModel<LLVMAddressOfGlobalModel,
393 SymbolRefAttr getSymbol(Operation *op)
const {
394 auto addressOfOp = cast<LLVM::AddressOfOp>(op);
395 return addressOfOp.getGlobalNameAttr();
399struct MemrefGlobalVariableModel
400 :
public GlobalVariableOpInterface::ExternalModel<MemrefGlobalVariableModel,
402 bool isConstant(Operation *op)
const {
403 auto globalOp = cast<memref::GlobalOp>(op);
404 return globalOp.getConstant();
407 bool hasInitializer(Operation *op)
const {
408 auto globalOp = cast<memref::GlobalOp>(op);
409 return globalOp.getInitialValue().has_value();
412 Region *getInitRegion(Operation *op)
const {
417 bool isDeviceAccessible(Operation *op)
const {
418 auto globalOp = cast<memref::GlobalOp>(op);
419 Attribute memSpace = globalOp.getType().getMemorySpace();
420 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
423 bool isInDeviceMemory(Operation *op)
const {
427 return isDeviceAccessible(op);
430 bool isCompilerGenerated(Operation *op)
const {
return false; }
433struct GPULaunchOffloadRegionModel
434 :
public acc::OffloadRegionOpInterface::ExternalModel<
435 GPULaunchOffloadRegionModel, gpu::LaunchOp> {
436 mlir::Region &getOffloadRegion(mlir::Operation *op)
const {
437 return cast<gpu::LaunchOp>(op).getBody();
445mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
446 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
449 if (existingDeviceTypes)
450 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
452 if (newDeviceTypes.empty())
453 deviceTypes.push_back(
454 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
456 for (DeviceType dt : newDeviceTypes)
457 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
459 return mlir::ArrayAttr::get(context, deviceTypes);
468mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
469 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
474 if (existingDeviceTypes)
475 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
477 if (newDeviceTypes.empty()) {
478 argCollection.
append(arguments);
479 segments.push_back(arguments.size());
480 deviceTypes.push_back(
481 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
484 for (DeviceType dt : newDeviceTypes) {
485 argCollection.
append(arguments);
486 segments.push_back(arguments.size());
487 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
490 return mlir::ArrayAttr::get(context, deviceTypes);
494mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
495 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
499 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
500 newDeviceTypes, arguments,
501 argCollection, segments);
509void OpenACCDialect::initialize() {
512#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
515#define GET_ATTRDEF_LIST
516#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
519#define GET_TYPEDEF_LIST
520#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
526 MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
528 UnrankedMemRefType::attachInterface<
529 MemRefPointerLikeModel<UnrankedMemRefType>>(*
getContext());
530 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
532 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
535 memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
537 LLVM::AddressOfOp::attachInterface<LLVMAddressOfGlobalModel>(*
getContext());
538 memref::GlobalOp::attachInterface<MemrefGlobalVariableModel>(*
getContext());
539 gpu::LaunchOp::attachInterface<GPULaunchOffloadRegionModel>(*
getContext());
576void ParallelOp::getSuccessorRegions(
606void HostDataOp::getSuccessorRegions(
634 if (loopOp.isContainerLike())
644 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
651 if (!lb || !
ub || !step || *step == 0) {
660 std::optional<ArrayRef<bool>> inclusiveUbs =
661 loopOp.getInclusiveUpperbound();
662 bool inclusiveUb = inclusiveUbs && (*inclusiveUbs)[i];
663 assert(*step != 0 &&
"zero step should have been filtered out");
664 bool runsOnce = *step > 0 ? (inclusiveUb ? *lb <= *
ub : *lb < *
ub)
665 : (inclusiveUb ? *lb >= *
ub : *lb > *
ub);
683 if (getUnstructured()) {
730 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
734 mlir::acc::DeviceType deviceType) {
738 for (
auto attr : *arrayAttr) {
739 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
740 if (deviceTypeAttr.getValue() == deviceType)
748 std::optional<mlir::ArrayAttr> deviceTypes) {
753 llvm::interleaveComma(*deviceTypes, p,
759 mlir::acc::DeviceType deviceType) {
760 unsigned segmentIdx = 0;
761 for (
auto attr : segments) {
762 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
763 if (deviceTypeAttr.getValue() == deviceType)
764 return std::make_optional(segmentIdx);
774 mlir::acc::DeviceType deviceType) {
776 return range.take_front(0);
777 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
778 int32_t nbOperandsBefore = 0;
779 for (
unsigned i = 0; i < *pos; ++i)
780 nbOperandsBefore += (*segments)[i];
781 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
783 return range.take_front(0);
791 mlir::acc::DeviceType deviceType) {
794 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
796 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
797 if (boolAttr && boolAttr.getValue())
811 mlir::acc::DeviceType deviceType) {
816 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
818 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*
hasWaitDevnum)[*pos]);
819 if (boolAttr.getValue())
820 return range.drop_front(1);
826template <
typename Op>
828 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
830 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
835 op.hasAsyncOnly(dtype))
837 "asyncOnly attribute cannot appear with asyncOperand");
842 op.hasWaitOnly(dtype))
843 return op.
emitError(
"wait attribute cannot appear with waitOperands");
848template <
typename Op>
851 return op.
emitError(
"must have var operand");
854 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
855 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
856 return op.
emitError(
"var must be mappable or pointer-like");
859 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
860 op.getVarType() == op.getVar().getType())
861 return op.
emitError(
"varType must capture the element type of var");
866template <
typename Op>
868 if (op.getVar().getType() != op.getAccVar().getType())
869 return op.
emitError(
"input and output types must match");
874template <
typename Op>
876 if (op.getModifiers() != acc::DataClauseModifier::none)
877 return op.
emitError(
"no data clause modifiers are allowed");
881template <
typename Op>
884 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
886 "invalid data clause modifiers: " +
887 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
892template <
typename OpT,
typename RecipeOpT>
893static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
898 !std::is_same_v<OpT, acc::ReductionOp>)
901 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
903 return op->emitOpError() <<
"recipe expected for " << operandName;
908 return op->emitOpError()
909 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
910 << operandName <<
" declaration";
931 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
952 if (failed(parser.
parseType(accVarType)))
962 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
974 mlir::TypeAttr &varTypeAttr) {
975 if (failed(parser.
parseType(varPtrType)))
986 varTypeAttr = mlir::TypeAttr::get(varType);
991 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
992 Type elementType = ptrTy.getElementType();
995 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
997 varTypeAttr = mlir::TypeAttr::get(varPtrType);
1005 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
1013 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
1014 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
1018 if (!typeToCheckAgainst)
1019 typeToCheckAgainst = varPtrType;
1020 if (typeToCheckAgainst != varType) {
1036 locAttr = mlir::dyn_cast<mlir::LocationAttr>(attr);
1038 return parser.
emitError(attrLoc,
"expected location attribute");
1048 mlir::SymbolRefAttr &recipeAttr) {
1055 mlir::SymbolRefAttr recipeAttr) {
1070 mlir::ArrayAttr &attr) {
1075 mlir::ArrayAttr attr) {
1082LogicalResult acc::DataBoundsOp::verify() {
1083 auto extent = getExtent();
1084 auto upperbound = getUpperbound();
1085 if (!extent && !upperbound)
1086 return emitError(
"expected extent or upperbound.");
1093LogicalResult acc::PrivateOp::verify() {
1096 "data clause associated with private operation must match its intent");
1110LogicalResult acc::FirstprivateOp::verify() {
1112 return emitError(
"data clause associated with firstprivate operation must "
1113 "match its intent");
1119 *
this,
"firstprivate")))
1127LogicalResult acc::ReductionOp::verify() {
1129 return emitError(
"data clause associated with reduction operation must "
1130 "match its intent");
1136 *
this,
"reduction")))
1144LogicalResult acc::DevicePtrOp::verify() {
1146 return emitError(
"data clause associated with deviceptr operation must "
1147 "match its intent");
1160LogicalResult acc::PresentOp::verify() {
1163 "data clause associated with present operation must match its intent");
1176LogicalResult acc::CopyinOp::verify() {
1178 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
1183 "data clause associated with copyin operation must match its intent"
1184 " or specify original clause this operation was decomposed from");
1190 acc::DataClauseModifier::always |
1191 acc::DataClauseModifier::capture)))
1196bool acc::CopyinOp::isCopyinReadonly() {
1197 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
1198 acc::bitEnumContainsAny(getModifiers(),
1199 acc::DataClauseModifier::readonly);
1205LogicalResult acc::CreateOp::verify() {
1212 "data clause associated with create operation must match its intent"
1213 " or specify original clause this operation was decomposed from");
1221 acc::DataClauseModifier::always |
1222 acc::DataClauseModifier::capture)))
1227bool acc::CreateOp::isCreateZero() {
1229 return getDataClause() == acc::DataClause::acc_create_zero ||
1231 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1237LogicalResult acc::NoCreateOp::verify() {
1239 return emitError(
"data clause associated with no_create operation must "
1240 "match its intent");
1253LogicalResult acc::AttachOp::verify() {
1256 "data clause associated with attach operation must match its intent");
1270LogicalResult acc::DeclareDeviceResidentOp::verify() {
1271 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
1272 return emitError(
"data clause associated with device_resident operation "
1273 "must match its intent");
1287LogicalResult acc::DeclareLinkOp::verify() {
1290 "data clause associated with link operation must match its intent");
1303LogicalResult acc::CopyoutOp::verify() {
1310 "data clause associated with copyout operation must match its intent"
1311 " or specify original clause this operation was decomposed from");
1313 return emitError(
"must have both host and device pointers");
1319 acc::DataClauseModifier::always |
1320 acc::DataClauseModifier::capture)))
1325bool acc::CopyoutOp::isCopyoutZero() {
1326 return getDataClause() == acc::DataClause::acc_copyout_zero ||
1327 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1333LogicalResult acc::DeleteOp::verify() {
1342 getDataClause() != acc::DataClause::acc_declare_device_resident &&
1345 "data clause associated with delete operation must match its intent"
1346 " or specify original clause this operation was decomposed from");
1348 return emitError(
"must have device pointer");
1352 acc::DataClauseModifier::readonly |
1353 acc::DataClauseModifier::always |
1354 acc::DataClauseModifier::capture)))
1362LogicalResult acc::DetachOp::verify() {
1367 "data clause associated with detach operation must match its intent"
1368 " or specify original clause this operation was decomposed from");
1370 return emitError(
"must have device pointer");
1379LogicalResult acc::UpdateHostOp::verify() {
1384 "data clause associated with host operation must match its intent"
1385 " or specify original clause this operation was decomposed from");
1387 return emitError(
"must have both host and device pointers");
1400LogicalResult acc::UpdateDeviceOp::verify() {
1404 "data clause associated with device operation must match its intent"
1405 " or specify original clause this operation was decomposed from");
1418LogicalResult acc::UseDeviceOp::verify() {
1422 "data clause associated with use_device operation must match its intent"
1423 " or specify original clause this operation was decomposed from");
1436LogicalResult acc::CacheOp::verify() {
1441 "data clause associated with cache operation must match its intent"
1442 " or specify original clause this operation was decomposed from");
1452bool acc::CacheOp::isCacheReadonly() {
1453 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1454 acc::bitEnumContainsAny(getModifiers(),
1455 acc::DataClauseModifier::readonly);
1471template <
typename EffectTy>
1476 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1477 effects.emplace_back(EffectTy::get(), &operand[i]);
1481template <
typename EffectTy>
1486 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1490void acc::PrivateOp::getEffects(
1504void acc::FirstprivateOp::getEffects(
1518void acc::ReductionOp::getEffects(
1532void acc::DevicePtrOp::getEffects(
1541void acc::PresentOp::getEffects(
1552void acc::CopyinOp::getEffects(
1565void acc::CreateOp::getEffects(
1578void acc::NoCreateOp::getEffects(
1589void acc::AttachOp::getEffects(
1602void acc::GetDevicePtrOp::getEffects(
1611void acc::UpdateDeviceOp::getEffects(
1621void acc::UseDeviceOp::getEffects(
1630void acc::DeclareDeviceResidentOp::getEffects(
1641void acc::DeclareLinkOp::getEffects(
1652void acc::CacheOp::getEffects(
1657void acc::CopyoutOp::getEffects(
1670void acc::DeleteOp::getEffects(
1682void acc::DetachOp::getEffects(
1694void acc::UpdateHostOp::getEffects(
1710template <
typename OpTy>
1712 using OpRewritePattern<OpTy>::OpRewritePattern;
1714 LogicalResult matchAndRewrite(OpTy op,
1715 PatternRewriter &rewriter)
const override {
1717 Value ifCond = op.getIfCond();
1721 IntegerAttr constAttr;
1724 if (constAttr.getInt())
1725 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1737 assert(region.
hasOneBlock() &&
"expected single-block region");
1749template <
typename OpTy>
1750struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1751 using OpRewritePattern<OpTy>::OpRewritePattern;
1753 LogicalResult matchAndRewrite(OpTy op,
1754 PatternRewriter &rewriter)
const override {
1756 Value ifCond = op.getIfCond();
1760 IntegerAttr constAttr;
1763 if (constAttr.getInt())
1764 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1793 for (
Value bound : bounds) {
1794 argTypes.push_back(bound.getType());
1795 argLocs.push_back(loc);
1802 Value privatizedValue;
1808 if (isa<MappableType>(varType)) {
1809 auto mappableTy = cast<MappableType>(varType);
1810 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1811 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1812 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1814 mappableTy.generatePrivateInit(builder, loc, typedVar, varName, bounds,
1815 {}, varInfo, needsFree, destroyValues);
1816 if (!privatizedValue)
1819 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1820 auto pointerLikeTy = cast<PointerLikeType>(varType);
1822 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1823 blockArgVar, needsFree);
1824 if (!privatizedValue)
1830 initResults.append(destroyValues);
1831 acc::YieldOp::create(builder, loc, initResults);
1848 for (
Value bound : bounds) {
1849 copyArgTypes.push_back(bound.getType());
1850 copyArgLocs.push_back(loc);
1860 if (isa<MappableType>(varType)) {
1861 auto mappableTy = cast<MappableType>(varType);
1864 if (!mappableTy.generateCopy(
1869 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1870 auto pointerLikeTy = cast<PointerLikeType>(varType);
1871 if (!pointerLikeTy.genCopy(
1878 acc::TerminatorOp::create(builder, loc);
1895 for (
Value destroyValue : destroyValues) {
1896 destroyArgTypes.push_back(destroyValue.getType());
1897 destroyArgLocs.push_back(loc);
1899 for (
Value bound : bounds) {
1900 destroyArgTypes.push_back(bound.getType());
1901 destroyArgLocs.push_back(loc);
1905 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1909 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1910 if (isa<MappableType>(varType)) {
1911 auto mappableTy = cast<MappableType>(varType);
1913 destroyBlock->
getArguments().slice(2, destroyValues.size());
1915 destroyBlock->
getArguments().drop_front(2 + destroyValues.size());
1916 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, destroyArgs,
1917 destroyBounds, varInfo))
1920 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1921 auto pointerLikeTy = cast<PointerLikeType>(varType);
1922 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1926 acc::TerminatorOp::create(builder, loc);
1937 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1939 if (optional && region.
empty())
1943 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1947 return op->
emitOpError() <<
"expects " << regionName
1950 << regionType <<
" type";
1953 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1954 if (yieldOp.getOperands().size() != 1 ||
1955 yieldOp.getOperands().getTypes()[0] != type)
1956 return op->
emitOpError() <<
"expects " << regionName
1958 "yield a value of the "
1959 << regionType <<
" type";
1965LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1967 "privatization",
"init",
getType(),
1971 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1977std::optional<PrivateRecipeOp>
1979 StringRef recipeName,
Value hostVar,
1984 bool isMappable = isa<MappableType>(varType);
1985 bool isPointerLike = isa<PointerLikeType>(varType);
1988 if (!isMappable && !isPointerLike)
1989 return std::nullopt;
1994 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1998 bool needsFree =
false;
2001 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
2002 varName, bounds, needsFree, varInfo,
2005 return std::nullopt;
2012 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
2013 Value allocRes = yieldOp.getOperand(0);
2015 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
2016 varType, allocRes, destroyValues, bounds,
2019 return std::nullopt;
2026std::optional<PrivateRecipeOp>
2028 StringRef recipeName,
2029 FirstprivateRecipeOp firstprivRecipe) {
2032 auto varType = firstprivRecipe.getType();
2033 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
2038 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
2041 if (!firstprivRecipe.getDestroyRegion().empty()) {
2043 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
2053LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
2055 "privatization",
"init",
getType(),
2059 if (getCopyRegion().empty())
2060 return emitOpError() <<
"expects non-empty copy region";
2065 return emitOpError() <<
"expects copy region with two arguments of the "
2066 "privatization type";
2068 if (getDestroyRegion().empty())
2072 "privatization",
"destroy",
2079std::optional<FirstprivateRecipeOp>
2081 StringRef recipeName,
Value hostVar,
2086 bool isMappable = isa<MappableType>(varType);
2087 bool isPointerLike = isa<PointerLikeType>(varType);
2090 if (!isMappable && !isPointerLike)
2091 return std::nullopt;
2096 auto recipe = FirstprivateRecipeOp::create(
2097 builder, loc, recipeName,
nullptr, varType);
2100 bool needsFree =
false;
2106 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
2107 varName, bounds, needsFree, varInfo,
2110 return std::nullopt;
2114 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
2115 bounds, varInfo))) {
2117 return std::nullopt;
2124 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
2125 Value allocRes = yieldOp.getOperand(0);
2127 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
2128 varType, allocRes, destroyValues, bounds,
2131 return std::nullopt;
2142LogicalResult acc::ReductionRecipeOp::verifyRegions() {
2148 if (getCombinerRegion().empty())
2149 return emitOpError() <<
"expects non-empty combiner region";
2151 Block &reductionBlock = getCombinerRegion().
front();
2155 return emitOpError() <<
"expects combiner region with the first two "
2156 <<
"arguments of the reduction type";
2158 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
2159 if (yieldOp.getOperands().size() != 1 ||
2160 yieldOp.getOperands().getTypes()[0] !=
getType())
2161 return emitOpError() <<
"expects combiner region to yield a value "
2162 "of the reduction type";
2173template <
typename Op>
2177 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2178 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2179 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
2180 acc::MapInfoOp>(operand.getDefiningOp()))
2182 "expect data entry/exit operation or acc.getdeviceptr "
2187template <
typename OpT,
typename RecipeOpT>
2190 llvm::StringRef operandName) {
2193 if (!mlir::isa<OpT>(operand.getDefiningOp()))
2195 <<
"expected " << operandName <<
" as defining op";
2196 if (!set.insert(operand).second)
2198 << operandName <<
" operand appears more than once";
2203unsigned ParallelOp::getNumDataOperands() {
2204 return getReductionOperands().size() + getPrivateOperands().size() +
2205 getFirstprivateOperands().size() + getDataClauseOperands().size();
2208Value ParallelOp::getDataOperand(
unsigned i) {
2210 numOptional += getNumGangs().size();
2211 numOptional += getNumWorkers().size();
2212 numOptional += getVectorLength().size();
2213 numOptional += getIfCond() ? 1 : 0;
2214 numOptional += getSelfCond() ? 1 : 0;
2215 return getOperand(getWaitOperands().size() + numOptional + i);
2218template <
typename Op>
2221 llvm::StringRef keyword) {
2222 if (!operands.empty() &&
2223 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
2224 return op.
emitOpError() << keyword <<
" operands count must match "
2225 << keyword <<
" device_type count";
2229template <
typename Op>
2232 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
2233 std::size_t numOperandsInSegments = 0;
2234 std::size_t nbOfSegments = 0;
2237 for (
auto segCount : segments.
asArrayRef()) {
2238 if (maxInSegment != 0 && segCount > maxInSegment)
2239 return op.
emitOpError() << keyword <<
" expects a maximum of "
2240 << maxInSegment <<
" values per segment";
2241 numOperandsInSegments += segCount;
2246 if ((numOperandsInSegments != operands.size()) ||
2247 (!deviceTypes && !operands.empty()))
2249 << keyword <<
" operand count does not match count in segments";
2250 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
2252 << keyword <<
" segment count does not match device_type count";
2256LogicalResult acc::ParallelOp::verify() {
2258 mlir::acc::PrivateRecipeOp>(
2259 *
this, getPrivateOperands(),
"private")))
2262 mlir::acc::FirstprivateRecipeOp>(
2263 *
this, getFirstprivateOperands(),
"firstprivate")))
2266 mlir::acc::ReductionRecipeOp>(
2267 *
this, getReductionOperands(),
"reduction")))
2271 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2272 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2276 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2277 getWaitOperandsDeviceTypeAttr(),
"wait")))
2281 getNumWorkersDeviceTypeAttr(),
2286 getVectorLengthDeviceTypeAttr(),
2291 getAsyncOperandsDeviceTypeAttr(),
2304 mlir::acc::DeviceType deviceType) {
2307 if (
auto pos =
findSegment(*arrayAttr, deviceType))
2312bool acc::ParallelOp::hasAsyncOnly() {
2313 return hasAsyncOnly(mlir::acc::DeviceType::None);
2316bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2321 return getAsyncValue(mlir::acc::DeviceType::None);
2324mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2329mlir::Value acc::ParallelOp::getNumWorkersValue() {
2330 return getNumWorkersValue(mlir::acc::DeviceType::None);
2334acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2339mlir::Value acc::ParallelOp::getVectorLengthValue() {
2340 return getVectorLengthValue(mlir::acc::DeviceType::None);
2344acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2346 getVectorLength(), deviceType);
2350 return getNumGangsValues(mlir::acc::DeviceType::None);
2354ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2356 getNumGangsSegments(), deviceType);
2360 std::optional<mlir::ArrayAttr> numGangsDeviceType,
2363 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
2365 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
2367 mlir::acc::DeviceType deviceType) {
2377bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2379 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2380 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2381 getVectorLength(), deviceType);
2384bool acc::ParallelOp::isEffectivelySerial() {
2388bool acc::ParallelOp::hasWaitOnly() {
2389 return hasWaitOnly(mlir::acc::DeviceType::None);
2392bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2397 return getWaitValues(mlir::acc::DeviceType::None);
2401ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2403 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2404 getHasWaitDevnum(), deviceType);
2408 return getWaitDevnum(mlir::acc::DeviceType::None);
2411mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2413 getWaitOperandsSegments(), getHasWaitDevnum(),
2428 odsBuilder, odsState, asyncOperands,
nullptr,
2429 nullptr, waitOperands,
nullptr,
2431 nullptr, numGangs,
nullptr,
2432 nullptr, numWorkers,
2433 nullptr, vectorLength,
2434 nullptr, ifCond, selfCond,
2435 false, reductionOperands, gangPrivateOperands,
2436 gangFirstPrivateOperands, dataClauseOperands,
2440void acc::ParallelOp::addNumWorkersOperand(
2443 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2444 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2445 getNumWorkersMutable()));
2447void acc::ParallelOp::addVectorLengthOperand(
2450 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2451 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2452 getVectorLengthMutable()));
2455void acc::ParallelOp::addAsyncOnly(
2457 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2458 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2461void acc::ParallelOp::addAsyncOperand(
2464 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2465 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2466 getAsyncOperandsMutable()));
2469void acc::ParallelOp::addNumGangsOperands(
2473 if (getNumGangsSegments())
2474 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2476 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2477 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2478 getNumGangsMutable(), segments));
2480 setNumGangsSegments(segments);
2482void acc::ParallelOp::addWaitOnly(
2484 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2485 effectiveDeviceTypes));
2487void acc::ParallelOp::addWaitOperands(
2492 if (getWaitOperandsSegments())
2493 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2495 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2496 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2497 getWaitOperandsMutable(), segments));
2498 setWaitOperandsSegments(segments);
2501 if (getHasWaitDevnumAttr())
2502 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2505 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2507 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2510void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2511 mlir::acc::PrivateOp op,
2512 mlir::acc::PrivateRecipeOp recipe) {
2513 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2514 getPrivateOperandsMutable().append(op.getResult());
2517void acc::ParallelOp::addFirstPrivatization(
2518 MLIRContext *context, mlir::acc::FirstprivateOp op,
2519 mlir::acc::FirstprivateRecipeOp recipe) {
2520 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2521 getFirstprivateOperandsMutable().append(op.getResult());
2524void acc::ParallelOp::addReduction(
MLIRContext *context,
2525 mlir::acc::ReductionOp op,
2526 mlir::acc::ReductionRecipeOp recipe) {
2527 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2528 getReductionOperandsMutable().append(op.getResult());
2543 int32_t crtOperandsSize = operands.size();
2546 if (parser.parseOperand(operands.emplace_back()) ||
2547 parser.parseColonType(types.emplace_back()))
2552 seg.push_back(operands.size() - crtOperandsSize);
2562 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2563 parser.
getContext(), mlir::acc::DeviceType::None));
2569 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2576 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2577 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2578 p <<
" [" << attr <<
"]";
2583 std::optional<mlir::ArrayAttr> deviceTypes,
2584 std::optional<mlir::DenseI32ArrayAttr> segments) {
2586 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2588 llvm::interleaveComma(
2589 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2590 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2610 int32_t crtOperandsSize = operands.size();
2614 if (parser.parseOperand(operands.emplace_back()) ||
2615 parser.parseColonType(types.emplace_back()))
2621 seg.push_back(operands.size() - crtOperandsSize);
2631 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2632 parser.
getContext(), mlir::acc::DeviceType::None));
2638 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2647 std::optional<mlir::DenseI32ArrayAttr> segments) {
2649 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2651 llvm::interleaveComma(
2652 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2653 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2666 mlir::ArrayAttr &keywordOnly) {
2670 bool needCommaBeforeOperands =
false;
2674 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2675 parser.
getContext(), mlir::acc::DeviceType::None));
2676 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2683 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2690 needCommaBeforeOperands =
true;
2693 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2700 int32_t crtOperandsSize = operands.size();
2712 if (parser.parseOperand(operands.emplace_back()) ||
2713 parser.parseColonType(types.emplace_back()))
2719 seg.push_back(operands.size() - crtOperandsSize);
2729 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2730 parser.
getContext(), mlir::acc::DeviceType::None));
2737 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2738 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2740 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2748 if (attrs->size() != 1)
2750 if (
auto deviceTypeAttr =
2751 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2752 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2758 std::optional<mlir::ArrayAttr> deviceTypes,
2759 std::optional<mlir::DenseI32ArrayAttr> segments,
2760 std::optional<mlir::ArrayAttr> hasDevNum,
2761 std::optional<mlir::ArrayAttr> keywordOnly) {
2774 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2776 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2777 if (boolAttr && boolAttr.getValue())
2779 llvm::interleaveComma(
2780 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2781 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2798 if (parser.parseOperand(operands.emplace_back()) ||
2799 parser.parseColonType(types.emplace_back()))
2801 if (succeeded(parser.parseOptionalLSquare())) {
2802 if (parser.parseAttribute(attributes.emplace_back()) ||
2803 parser.parseRSquare())
2806 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2807 parser.getContext(), mlir::acc::DeviceType::None));
2814 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2821 std::optional<mlir::ArrayAttr> deviceTypes) {
2824 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2825 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2834 mlir::ArrayAttr &keywordOnlyDeviceType) {
2837 bool needCommaBeforeOperands =
false;
2841 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2842 parser.
getContext(), mlir::acc::DeviceType::None));
2843 keywordOnlyDeviceType =
2844 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2852 if (parser.parseAttribute(
2853 keywordOnlyDeviceTypeAttributes.emplace_back()))
2860 keywordOnlyDeviceType =
2861 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2862 needCommaBeforeOperands =
true;
2865 if (needCommaBeforeOperands) {
2874 if (parser.parseOperand(operands.emplace_back()) ||
2875 parser.parseColonType(types.emplace_back()))
2877 if (succeeded(parser.parseOptionalLSquare())) {
2878 if (parser.parseAttribute(attributes.emplace_back()) ||
2879 parser.parseRSquare())
2882 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2883 parser.getContext(), mlir::acc::DeviceType::None));
2889 if (
failed(parser.parseRParen()))
2894 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2901 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2903 if (operands.begin() == operands.end() &&
2919 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2920 mlir::Type &operandType, mlir::UnitAttr &attr) {
2923 attr = mlir::UnitAttr::get(parser.
getContext());
2933 if (failed(parser.
parseType(operandType)))
2943 std::optional<mlir::Value> operand,
2945 mlir::UnitAttr attr) {
2962 attr = mlir::UnitAttr::get(parser.
getContext());
2967 if (parser.parseOperand(operands.emplace_back()))
2975 if (parser.parseType(types.emplace_back()))
2990 mlir::UnitAttr attr) {
2995 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2997 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
3003 mlir::acc::CombinedConstructsTypeAttr &attr) {
3005 attr = mlir::acc::CombinedConstructsTypeAttr::get(
3006 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
3008 attr = mlir::acc::CombinedConstructsTypeAttr::get(
3009 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
3011 attr = mlir::acc::CombinedConstructsTypeAttr::get(
3012 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
3015 "expected compute construct name");
3023 mlir::acc::CombinedConstructsTypeAttr attr) {
3025 switch (attr.getValue()) {
3026 case mlir::acc::CombinedConstructsType::KernelsLoop:
3029 case mlir::acc::CombinedConstructsType::ParallelLoop:
3032 case mlir::acc::CombinedConstructsType::SerialLoop:
3043unsigned SerialOp::getNumDataOperands() {
3044 return getReductionOperands().size() + getPrivateOperands().size() +
3045 getFirstprivateOperands().size() + getDataClauseOperands().size();
3048Value SerialOp::getDataOperand(
unsigned i) {
3050 numOptional += getIfCond() ? 1 : 0;
3051 numOptional += getSelfCond() ? 1 : 0;
3052 return getOperand(getWaitOperands().size() + numOptional + i);
3055bool acc::SerialOp::hasAsyncOnly() {
3056 return hasAsyncOnly(mlir::acc::DeviceType::None);
3059bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3064 return getAsyncValue(mlir::acc::DeviceType::None);
3067mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3072bool acc::SerialOp::hasWaitOnly() {
3073 return hasWaitOnly(mlir::acc::DeviceType::None);
3076bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3081 return getWaitValues(mlir::acc::DeviceType::None);
3085SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3087 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3088 getHasWaitDevnum(), deviceType);
3092 return getWaitDevnum(mlir::acc::DeviceType::None);
3095mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3097 getWaitOperandsSegments(), getHasWaitDevnum(),
3101LogicalResult acc::SerialOp::verify() {
3103 mlir::acc::PrivateRecipeOp>(
3104 *
this, getPrivateOperands(),
"private")))
3107 mlir::acc::FirstprivateRecipeOp>(
3108 *
this, getFirstprivateOperands(),
"firstprivate")))
3111 mlir::acc::ReductionRecipeOp>(
3112 *
this, getReductionOperands(),
"reduction")))
3116 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3117 getWaitOperandsDeviceTypeAttr(),
"wait")))
3121 getAsyncOperandsDeviceTypeAttr(),
3131void acc::SerialOp::addAsyncOnly(
3133 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3134 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3137void acc::SerialOp::addAsyncOperand(
3140 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3141 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3142 getAsyncOperandsMutable()));
3145void acc::SerialOp::addWaitOnly(
3147 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3148 effectiveDeviceTypes));
3150void acc::SerialOp::addWaitOperands(
3155 if (getWaitOperandsSegments())
3156 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3158 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3159 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3160 getWaitOperandsMutable(), segments));
3161 setWaitOperandsSegments(segments);
3164 if (getHasWaitDevnumAttr())
3165 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3168 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3170 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3173void acc::SerialOp::addPrivatization(
MLIRContext *context,
3174 mlir::acc::PrivateOp op,
3175 mlir::acc::PrivateRecipeOp recipe) {
3176 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3177 getPrivateOperandsMutable().append(op.getResult());
3180void acc::SerialOp::addFirstPrivatization(
3181 MLIRContext *context, mlir::acc::FirstprivateOp op,
3182 mlir::acc::FirstprivateRecipeOp recipe) {
3183 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3184 getFirstprivateOperandsMutable().append(op.getResult());
3187void acc::SerialOp::addReduction(
MLIRContext *context,
3188 mlir::acc::ReductionOp op,
3189 mlir::acc::ReductionRecipeOp recipe) {
3190 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3191 getReductionOperandsMutable().append(op.getResult());
3198unsigned KernelsOp::getNumDataOperands() {
3199 return getDataClauseOperands().size();
3202Value KernelsOp::getDataOperand(
unsigned i) {
3204 numOptional += getWaitOperands().size();
3205 numOptional += getNumGangs().size();
3206 numOptional += getNumWorkers().size();
3207 numOptional += getVectorLength().size();
3208 numOptional += getIfCond() ? 1 : 0;
3209 numOptional += getSelfCond() ? 1 : 0;
3210 return getOperand(numOptional + i);
3213bool acc::KernelsOp::hasAsyncOnly() {
3214 return hasAsyncOnly(mlir::acc::DeviceType::None);
3217bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3222 return getAsyncValue(mlir::acc::DeviceType::None);
3225mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3231 return getNumWorkersValue(mlir::acc::DeviceType::None);
3235acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
3240mlir::Value acc::KernelsOp::getVectorLengthValue() {
3241 return getVectorLengthValue(mlir::acc::DeviceType::None);
3245acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
3247 getVectorLength(), deviceType);
3251 return getNumGangsValues(mlir::acc::DeviceType::None);
3255KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
3257 getNumGangsSegments(), deviceType);
3260bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
3262 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
3263 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
3264 getVectorLength(), deviceType);
3267bool acc::KernelsOp::isEffectivelySerial() {
3271bool acc::KernelsOp::hasWaitOnly() {
3272 return hasWaitOnly(mlir::acc::DeviceType::None);
3275bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3280 return getWaitValues(mlir::acc::DeviceType::None);
3284KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3286 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3287 getHasWaitDevnum(), deviceType);
3291 return getWaitDevnum(mlir::acc::DeviceType::None);
3294mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3296 getWaitOperandsSegments(), getHasWaitDevnum(),
3300LogicalResult acc::KernelsOp::verify() {
3302 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
3303 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
3307 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3308 getWaitOperandsDeviceTypeAttr(),
"wait")))
3312 getNumWorkersDeviceTypeAttr(),
3317 getVectorLengthDeviceTypeAttr(),
3322 getAsyncOperandsDeviceTypeAttr(),
3332void acc::KernelsOp::addPrivatization(
MLIRContext *context,
3333 mlir::acc::PrivateOp op,
3334 mlir::acc::PrivateRecipeOp recipe) {
3335 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3336 getPrivateOperandsMutable().append(op.getResult());
3339void acc::KernelsOp::addFirstPrivatization(
3340 MLIRContext *context, mlir::acc::FirstprivateOp op,
3341 mlir::acc::FirstprivateRecipeOp recipe) {
3342 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3343 getFirstprivateOperandsMutable().append(op.getResult());
3346void acc::KernelsOp::addReduction(
MLIRContext *context,
3347 mlir::acc::ReductionOp op,
3348 mlir::acc::ReductionRecipeOp recipe) {
3349 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3350 getReductionOperandsMutable().append(op.getResult());
3353void acc::KernelsOp::addNumWorkersOperand(
3356 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3357 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3358 getNumWorkersMutable()));
3361void acc::KernelsOp::addVectorLengthOperand(
3364 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3365 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3366 getVectorLengthMutable()));
3368void acc::KernelsOp::addAsyncOnly(
3370 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3371 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3374void acc::KernelsOp::addAsyncOperand(
3377 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3378 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3379 getAsyncOperandsMutable()));
3382void acc::KernelsOp::addNumGangsOperands(
3386 if (getNumGangsSegmentsAttr())
3387 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3389 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3390 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3391 getNumGangsMutable(), segments));
3393 setNumGangsSegments(segments);
3396void acc::KernelsOp::addWaitOnly(
3398 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3399 effectiveDeviceTypes));
3401void acc::KernelsOp::addWaitOperands(
3406 if (getWaitOperandsSegments())
3407 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3409 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3410 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3411 getWaitOperandsMutable(), segments));
3412 setWaitOperandsSegments(segments);
3415 if (getHasWaitDevnumAttr())
3416 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3419 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3421 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3428LogicalResult acc::HostDataOp::verify() {
3429 if (getDataClauseOperands().empty())
3430 return emitError(
"at least one operand must appear on the host_data "
3434 for (
mlir::Value operand : getDataClauseOperands()) {
3436 mlir::dyn_cast_if_present<acc::UseDeviceOp>(operand.getDefiningOp());
3438 return emitError(
"expect data entry operation as defining op");
3441 if (!seenVars.insert(useDeviceOp.getVar()).second)
3442 return emitError(
"duplicate use_device variable");
3449 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3461 bool &needCommaBetweenValues,
bool &newValue) {
3468 attributes.push_back(gangArgType);
3469 needCommaBetweenValues =
true;
3480 mlir::ArrayAttr &gangOnlyDeviceType) {
3485 bool needCommaBetweenValues =
false;
3486 bool needCommaBeforeOperands =
false;
3490 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3491 parser.
getContext(), mlir::acc::DeviceType::None));
3492 gangOnlyDeviceType =
3493 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3501 if (parser.parseAttribute(
3502 gangOnlyDeviceTypeAttributes.emplace_back()))
3509 needCommaBeforeOperands =
true;
3512 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3513 mlir::acc::GangArgType::Num);
3514 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3515 mlir::acc::GangArgType::Dim);
3516 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3517 parser.
getContext(), mlir::acc::GangArgType::Static);
3520 if (needCommaBeforeOperands) {
3521 needCommaBeforeOperands =
false;
3528 int32_t crtOperandsSize = gangOperands.size();
3530 bool newValue =
false;
3531 bool needValue =
false;
3532 if (needCommaBetweenValues) {
3540 gangOperands, gangOperandsType,
3541 gangArgTypeAttributes, argNum,
3542 needCommaBetweenValues, newValue)))
3545 gangOperands, gangOperandsType,
3546 gangArgTypeAttributes, argDim,
3547 needCommaBetweenValues, newValue)))
3549 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3550 gangOperands, gangOperandsType,
3551 gangArgTypeAttributes, argStatic,
3552 needCommaBetweenValues, newValue)))
3555 if (!newValue && needValue) {
3557 "new value expected after comma");
3565 if (gangOperands.empty())
3568 "expect at least one of num, dim or static values");
3574 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3578 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3579 parser.
getContext(), mlir::acc::DeviceType::None));
3582 seg.push_back(gangOperands.size() - crtOperandsSize);
3590 gangArgTypeAttributes.end());
3591 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3592 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3595 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3596 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3604 std::optional<mlir::ArrayAttr> gangArgTypes,
3605 std::optional<mlir::ArrayAttr> deviceTypes,
3606 std::optional<mlir::DenseI32ArrayAttr> segments,
3607 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3609 if (operands.begin() == operands.end() &&
3624 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3626 llvm::interleaveComma(
3627 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3628 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3629 (*gangArgTypes)[opIdx]);
3630 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3631 p << LoopOp::getGangNumKeyword();
3632 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3633 p << LoopOp::getGangDimKeyword();
3634 else if (gangArgTypeAttr.getValue() ==
3635 mlir::acc::GangArgType::Static)
3636 p << LoopOp::getGangStaticKeyword();
3637 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3648 std::optional<mlir::ArrayAttr> segments,
3649 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3652 for (
auto attr : *segments) {
3653 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3654 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3662static std::optional<mlir::acc::DeviceType>
3664 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3666 return std::nullopt;
3667 for (
auto attr : deviceTypes) {
3668 auto deviceTypeAttr =
3669 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3670 if (!deviceTypeAttr)
3671 return mlir::acc::DeviceType::None;
3672 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3673 return deviceTypeAttr.getValue();
3675 return std::nullopt;
3678LogicalResult acc::LoopOp::verify() {
3679 if (getUpperbound().size() != getStep().size())
3680 return emitError() <<
"number of upperbounds expected to be the same as "
3683 if (getUpperbound().size() != getLowerbound().size())
3684 return emitError() <<
"number of upperbounds expected to be the same as "
3685 "number of lowerbounds";
3687 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3688 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3689 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3690 <<
" as upperbound size";
3693 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3694 return emitOpError() <<
"collapse device_type attr must be define when"
3695 <<
" collapse attr is present";
3697 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3698 getCollapseAttr().getValue().size() !=
3699 getCollapseDeviceTypeAttr().getValue().size())
3700 return emitOpError() <<
"collapse attribute count must match collapse"
3701 <<
" device_type count";
3702 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3703 return emitOpError() <<
"duplicate device_type `"
3704 << acc::stringifyDeviceType(*duplicateDeviceType)
3705 <<
"` found in collapseDeviceType attribute";
3708 if (!getGangOperands().empty()) {
3709 if (!getGangOperandsArgType())
3710 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3711 <<
" when gang operands are present";
3713 if (getGangOperands().size() !=
3714 getGangOperandsArgTypeAttr().getValue().size())
3715 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3716 <<
" gangOperands count";
3718 if (getGangAttr()) {
3720 return emitOpError() <<
"duplicate device_type `"
3721 << acc::stringifyDeviceType(*duplicateDeviceType)
3722 <<
"` found in gang attribute";
3726 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3727 getGangOperandsDeviceTypeAttr(),
"gang")))
3732 return emitOpError() <<
"duplicate device_type `"
3733 << acc::stringifyDeviceType(*duplicateDeviceType)
3734 <<
"` found in worker attribute";
3735 if (
auto duplicateDeviceType =
3737 return emitOpError() <<
"duplicate device_type `"
3738 << acc::stringifyDeviceType(*duplicateDeviceType)
3739 <<
"` found in workerNumOperandsDeviceType attribute";
3741 getWorkerNumOperandsDeviceTypeAttr(),
3747 return emitOpError() <<
"duplicate device_type `"
3748 << acc::stringifyDeviceType(*duplicateDeviceType)
3749 <<
"` found in vector attribute";
3750 if (
auto duplicateDeviceType =
3752 return emitOpError() <<
"duplicate device_type `"
3753 << acc::stringifyDeviceType(*duplicateDeviceType)
3754 <<
"` found in vectorOperandsDeviceType attribute";
3756 getVectorOperandsDeviceTypeAttr(),
3761 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3762 getTileOperandsDeviceTypeAttr(),
"tile")))
3766 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3770 return emitError() <<
"only one of auto, independent, seq can be present "
3776 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3777 return attr.getValue() == mlir::acc::DeviceType::None;
3779 bool hasDefaultSeq =
3781 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3784 bool hasDefaultIndependent =
3785 getIndependentAttr()
3787 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3790 bool hasDefaultAuto =
3792 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3795 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3797 <<
"at least one of auto, independent, seq must be present";
3802 for (
auto attr : getSeqAttr()) {
3803 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3804 if (hasVector(deviceTypeAttr.getValue()) ||
3805 getVectorValue(deviceTypeAttr.getValue()) ||
3806 hasWorker(deviceTypeAttr.getValue()) ||
3807 getWorkerValue(deviceTypeAttr.getValue()) ||
3808 hasGang(deviceTypeAttr.getValue()) ||
3809 getGangValue(mlir::acc::GangArgType::Num,
3810 deviceTypeAttr.getValue()) ||
3811 getGangValue(mlir::acc::GangArgType::Dim,
3812 deviceTypeAttr.getValue()) ||
3813 getGangValue(mlir::acc::GangArgType::Static,
3814 deviceTypeAttr.getValue()))
3815 return emitError() <<
"gang, worker or vector cannot appear with seq";
3820 mlir::acc::PrivateRecipeOp>(
3821 *
this, getPrivateOperands(),
"private")))
3825 mlir::acc::FirstprivateRecipeOp>(
3826 *
this, getFirstprivateOperands(),
"firstprivate")))
3830 mlir::acc::ReductionRecipeOp>(
3831 *
this, getReductionOperands(),
"reduction")))
3834 if (getCombined().has_value() &&
3835 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3836 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3837 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3838 return emitError(
"unexpected combined constructs attribute");
3842 if (getRegion().empty())
3843 return emitError(
"expected non-empty body.");
3845 if (getUnstructured()) {
3846 if (!isContainerLike())
3848 "unstructured acc.loop must not have induction variables");
3849 }
else if (isContainerLike()) {
3853 uint64_t collapseCount = getCollapseValue().value_or(1);
3854 if (getCollapseAttr()) {
3855 for (
auto collapseEntry : getCollapseAttr()) {
3856 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3857 if (intAttr.getValue().getZExtValue() > collapseCount)
3858 collapseCount = intAttr.getValue().getZExtValue();
3866 bool foundSibling =
false;
3868 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3870 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3872 foundSibling =
true;
3877 expectedParent = op;
3880 if (collapseCount == 0)
3886 return emitError(
"found sibling loops inside container-like acc.loop");
3887 if (collapseCount != 0)
3888 return emitError(
"failed to find enough loop-like operations inside "
3889 "container-like acc.loop");
3895unsigned LoopOp::getNumDataOperands() {
3896 return getReductionOperands().size() + getPrivateOperands().size() +
3897 getFirstprivateOperands().size();
3900Value LoopOp::getDataOperand(
unsigned i) {
3901 unsigned numOptional =
3902 getLowerbound().size() + getUpperbound().size() + getStep().size();
3903 numOptional += getGangOperands().size();
3904 numOptional += getVectorOperands().size();
3905 numOptional += getWorkerNumOperands().size();
3906 numOptional += getTileOperands().size();
3907 numOptional += getCacheOperands().size();
3908 return getOperand(numOptional + i);
3911bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3913bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3917bool LoopOp::hasIndependent() {
3918 return hasIndependent(mlir::acc::DeviceType::None);
3921bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3925bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3927bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3932 return getVectorValue(mlir::acc::DeviceType::None);
3935mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3937 getVectorOperands(), deviceType);
3940bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3942bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3947 return getWorkerValue(mlir::acc::DeviceType::None);
3950mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3952 getWorkerNumOperands(), deviceType);
3955bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3957bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3962 return getTileValues(mlir::acc::DeviceType::None);
3966LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3968 getTileOperandsSegments(), deviceType);
3971std::optional<int64_t> LoopOp::getCollapseValue() {
3972 return getCollapseValue(mlir::acc::DeviceType::None);
3975std::optional<int64_t>
3976LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3977 if (!getCollapseAttr())
3978 return std::nullopt;
3979 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3981 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3982 return intAttr.getValue().getZExtValue();
3984 return std::nullopt;
3987mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3988 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3991mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3992 mlir::acc::DeviceType deviceType) {
3993 if (getGangOperands().empty())
3995 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3996 int32_t nbOperandsBefore = 0;
3997 for (
unsigned i = 0; i < *pos; ++i)
3998 nbOperandsBefore += (*getGangOperandsSegments())[i];
4001 .drop_front(nbOperandsBefore)
4002 .take_front((*getGangOperandsSegments())[*pos]);
4004 int32_t argTypeIdx = nbOperandsBefore;
4005 for (
auto value : values) {
4006 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
4007 (*getGangOperandsArgType())[argTypeIdx]);
4008 if (gangArgTypeAttr.getValue() == gangArgType)
4016bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4018bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
4023 return {&getRegion()};
4067 if (!regionArgs.empty()) {
4068 p << acc::LoopOp::getControlKeyword() <<
"(";
4069 llvm::interleaveComma(regionArgs, p,
4071 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
4072 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
4073 <<
" : " << stepType <<
") ";
4080 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4081 effectiveDeviceTypes));
4084void acc::LoopOp::addIndependent(
4086 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
4087 context, getIndependentAttr(), effectiveDeviceTypes));
4092 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
4093 effectiveDeviceTypes));
4096void acc::LoopOp::setCollapseForDeviceTypes(
4098 llvm::APInt value) {
4102 assert((getCollapseAttr() ==
nullptr) ==
4103 (getCollapseDeviceTypeAttr() ==
nullptr));
4104 assert(value.getBitWidth() == 64);
4106 if (getCollapseAttr()) {
4107 for (
const auto &existing :
4108 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
4109 newValues.push_back(std::get<0>(existing));
4110 newDeviceTypes.push_back(std::get<1>(existing));
4114 if (effectiveDeviceTypes.empty()) {
4117 newValues.push_back(
4118 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
4119 newDeviceTypes.push_back(
4120 acc::DeviceTypeAttr::get(context, DeviceType::None));
4122 for (DeviceType dt : effectiveDeviceTypes) {
4123 newValues.push_back(
4124 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
4125 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4129 setCollapseAttr(ArrayAttr::get(context, newValues));
4130 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
4133void acc::LoopOp::setTileForDeviceTypes(
4137 if (getTileOperandsSegments())
4138 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
4140 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4141 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4142 getTileOperandsMutable(), segments));
4144 setTileOperandsSegments(segments);
4147void acc::LoopOp::addVectorOperand(
4150 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4151 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4152 newValue, getVectorOperandsMutable()));
4155void acc::LoopOp::addEmptyVector(
4157 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4158 effectiveDeviceTypes));
4161void acc::LoopOp::addWorkerNumOperand(
4164 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4165 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4166 newValue, getWorkerNumOperandsMutable()));
4169void acc::LoopOp::addEmptyWorker(
4171 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4172 effectiveDeviceTypes));
4175void acc::LoopOp::addEmptyGang(
4177 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4178 effectiveDeviceTypes));
4181bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
4182 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
4183 return attr.getValue() == dt;
4185 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
4186 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
4189 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
4191 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
4193 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
4199bool acc::LoopOp::hasDefaultGangWorkerVector() {
4200 return hasAnyGangWorkerVector(DeviceType::None);
4203bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
4204 return hasVector(deviceType) || getVectorValue(deviceType) ||
4205 hasWorker(deviceType) || getWorkerValue(deviceType) ||
4206 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
4207 getGangValue(GangArgType::Dim, deviceType) ||
4208 getGangValue(GangArgType::Static, deviceType);
4212acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
4213 if (hasSeq(deviceType))
4214 return LoopParMode::loop_seq;
4215 if (hasAuto(deviceType))
4216 return LoopParMode::loop_auto;
4217 if (hasIndependent(deviceType))
4218 return LoopParMode::loop_independent;
4220 return LoopParMode::loop_seq;
4222 return LoopParMode::loop_auto;
4223 assert(hasIndependent() &&
4224 "loop must have default auto, seq, or independent");
4225 return LoopParMode::loop_independent;
4228void acc::LoopOp::addGangOperands(
4233 getGangOperandsSegments())
4234 llvm::copy(*existingSegments, std::back_inserter(segments));
4236 unsigned beforeCount = segments.size();
4238 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4239 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4240 getGangOperandsMutable(), segments));
4242 setGangOperandsSegments(segments);
4249 unsigned numAdded = segments.size() - beforeCount;
4253 if (getGangOperandsArgTypeAttr())
4254 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
4256 for (
auto i : llvm::index_range(0u, numAdded)) {
4257 llvm::transform(argTypes, std::back_inserter(gangTypes),
4258 [=](mlir::acc::GangArgType gangTy) {
4259 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
4264 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
4268void acc::LoopOp::addPrivatization(
MLIRContext *context,
4269 mlir::acc::PrivateOp op,
4270 mlir::acc::PrivateRecipeOp recipe) {
4271 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4272 getPrivateOperandsMutable().append(op.getResult());
4275void acc::LoopOp::addFirstPrivatization(
4276 MLIRContext *context, mlir::acc::FirstprivateOp op,
4277 mlir::acc::FirstprivateRecipeOp recipe) {
4278 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4279 getFirstprivateOperandsMutable().append(op.getResult());
4282void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
4283 mlir::acc::ReductionRecipeOp recipe) {
4284 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4285 getReductionOperandsMutable().append(op.getResult());
4292LogicalResult acc::DataOp::verify() {
4297 return emitError(
"at least one operand or the default attribute "
4298 "must appear on the data operation");
4300 for (
mlir::Value operand : getDataClauseOperands())
4301 if (isa<BlockArgument>(operand) ||
4302 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4303 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
4304 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
4305 acc::MapInfoOp>(operand.getDefiningOp()))
4306 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4315unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
4317Value DataOp::getDataOperand(
unsigned i) {
4318 unsigned numOptional = getIfCond() ? 1 : 0;
4320 numOptional += getWaitOperands().size();
4321 return getOperand(numOptional + i);
4324bool acc::DataOp::hasAsyncOnly() {
4325 return hasAsyncOnly(mlir::acc::DeviceType::None);
4328bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4333 return getAsyncValue(mlir::acc::DeviceType::None);
4336mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4341bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
4343bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4348 return getWaitValues(mlir::acc::DeviceType::None);
4352DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4354 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4355 getHasWaitDevnum(), deviceType);
4359 return getWaitDevnum(mlir::acc::DeviceType::None);
4362mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4364 getWaitOperandsSegments(), getHasWaitDevnum(),
4368void acc::DataOp::addAsyncOnly(
4370 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4371 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4374void acc::DataOp::addAsyncOperand(
4377 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4378 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4379 getAsyncOperandsMutable()));
4382void acc::DataOp::addWaitOnly(
MLIRContext *context,
4384 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4385 effectiveDeviceTypes));
4388void acc::DataOp::addWaitOperands(
4393 if (getWaitOperandsSegments())
4394 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4396 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4397 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4398 getWaitOperandsMutable(), segments));
4399 setWaitOperandsSegments(segments);
4402 if (getHasWaitDevnumAttr())
4403 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4406 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4408 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4415LogicalResult acc::ExitDataOp::verify() {
4419 if (getDataClauseOperands().empty())
4420 return emitError(
"at least one operand must be present in dataOperands on "
4421 "the exit data operation");
4425 if (getAsyncOperand() && getAsync())
4426 return emitError(
"async attribute cannot appear with asyncOperand");
4430 if (!getWaitOperands().empty() && getWait())
4431 return emitError(
"wait attribute cannot appear with waitOperands");
4433 if (getWaitDevnum() && getWaitOperands().empty())
4434 return emitError(
"wait_devnum cannot appear without waitOperands");
4439unsigned ExitDataOp::getNumDataOperands() {
4440 return getDataClauseOperands().size();
4443Value ExitDataOp::getDataOperand(
unsigned i) {
4444 unsigned numOptional = getIfCond() ? 1 : 0;
4445 numOptional += getAsyncOperand() ? 1 : 0;
4446 numOptional += getWaitDevnum() ? 1 : 0;
4447 return getOperand(getWaitOperands().size() + numOptional + i);
4452 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4455void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4457 assert(effectiveDeviceTypes.empty());
4458 assert(!getAsyncAttr());
4459 assert(!getAsyncOperand());
4461 setAsyncAttr(mlir::UnitAttr::get(context));
4464void ExitDataOp::addAsyncOperand(
4467 assert(effectiveDeviceTypes.empty());
4468 assert(!getAsyncAttr());
4469 assert(!getAsyncOperand());
4471 getAsyncOperandMutable().append(newValue);
4476 assert(effectiveDeviceTypes.empty());
4481 setWaitAttr(mlir::UnitAttr::get(context));
4483 getWaitDevnumMutable().clear();
4484 getWaitOperandsMutable().clear();
4487void ExitDataOp::addWaitOperands(
4490 assert(effectiveDeviceTypes.empty());
4499 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4504 getWaitDevnumMutable().append(newValues.front());
4505 newValues = newValues.drop_front();
4508 getWaitOperandsMutable().append(newValues);
4515LogicalResult acc::EnterDataOp::verify() {
4519 if (getDataClauseOperands().empty())
4520 return emitError(
"at least one operand must be present in dataOperands on "
4521 "the enter data operation");
4525 if (getAsyncOperand() && getAsync())
4526 return emitError(
"async attribute cannot appear with asyncOperand");
4530 if (!getWaitOperands().empty() && getWait())
4531 return emitError(
"wait attribute cannot appear with waitOperands");
4533 if (getWaitDevnum() && getWaitOperands().empty())
4534 return emitError(
"wait_devnum cannot appear without waitOperands");
4536 for (
mlir::Value operand : getDataClauseOperands())
4537 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp, acc::MapInfoOp>(
4538 operand.getDefiningOp()))
4539 return emitError(
"expect data entry operation as defining op");
4544unsigned EnterDataOp::getNumDataOperands() {
4545 return getDataClauseOperands().size();
4548Value EnterDataOp::getDataOperand(
unsigned i) {
4549 unsigned numOptional = getIfCond() ? 1 : 0;
4550 numOptional += getAsyncOperand() ? 1 : 0;
4551 numOptional += getWaitDevnum() ? 1 : 0;
4552 return getOperand(getWaitOperands().size() + numOptional + i);
4557 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4560void EnterDataOp::addAsyncOnly(
4562 assert(effectiveDeviceTypes.empty());
4563 assert(!getAsyncAttr());
4564 assert(!getAsyncOperand());
4566 setAsyncAttr(mlir::UnitAttr::get(context));
4569void EnterDataOp::addAsyncOperand(
4572 assert(effectiveDeviceTypes.empty());
4573 assert(!getAsyncAttr());
4574 assert(!getAsyncOperand());
4576 getAsyncOperandMutable().append(newValue);
4579void EnterDataOp::addWaitOnly(
MLIRContext *context,
4581 assert(effectiveDeviceTypes.empty());
4586 setWaitAttr(mlir::UnitAttr::get(context));
4588 getWaitDevnumMutable().clear();
4589 getWaitOperandsMutable().clear();
4592void EnterDataOp::addWaitOperands(
4595 assert(effectiveDeviceTypes.empty());
4604 assert(!getWaitDevnum() &&
"Merging devnum not yet implemented");
4609 getWaitDevnumMutable().append(newValues.front());
4610 newValues = newValues.drop_front();
4613 getWaitOperandsMutable().append(newValues);
4620LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4626LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4632LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4639 if (
Value writeVal = op.getWriteOpVal()) {
4648LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4650LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4656AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4657 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4659 return dyn_cast<AtomicReadOp>(getSecondOp());
4662AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4663 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4665 return dyn_cast<AtomicWriteOp>(getSecondOp());
4668AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4669 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4671 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4674LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4680template <
typename Op>
4683 bool requireAtLeastOneOperand =
true) {
4684 if (operands.empty() && requireAtLeastOneOperand)
4687 "at least one operand must appear on the declare operation");
4690 if (isa<BlockArgument>(operand) ||
4691 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4692 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4693 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp,
4694 acc::MapInfoOp>(operand.getDefiningOp()))
4696 "expect valid declare data entry operation or acc.getdeviceptr "
4700 assert(var &&
"declare operands can only be data entry operations which "
4704 if (!mlir::isa<acc::MapInfoOp>(operand.getDefiningOp())) {
4705 std::optional<mlir::acc::DataClause> dataClauseOptional{
4707 assert(dataClauseOptional.has_value() &&
4708 "declare operands can only be data entry operations which must "
4710 (
void)dataClauseOptional;
4717LogicalResult acc::DeclareEnterOp::verify() {
4725LogicalResult acc::DeclareExitOp::verify() {
4736LogicalResult acc::DeclareOp::verify() {
4745 acc::DeviceType dtype) {
4746 unsigned parallelism = 0;
4747 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4748 parallelism += op.hasWorker(dtype) ? 1 : 0;
4749 parallelism += op.hasVector(dtype) ? 1 : 0;
4750 parallelism += op.hasSeq(dtype) ? 1 : 0;
4754LogicalResult acc::RoutineOp::verify() {
4755 unsigned baseParallelism =
4758 if (baseParallelism > 1)
4759 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4760 "be present at the same time";
4762 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4764 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4765 if (dtype == acc::DeviceType::None)
4769 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4770 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4771 "be present at the same time for device_type `"
4772 << acc::stringifyDeviceType(dtype) <<
"`";
4779 mlir::ArrayAttr &bindIdName,
4780 mlir::ArrayAttr &bindStrName,
4781 mlir::ArrayAttr &deviceIdTypes,
4782 mlir::ArrayAttr &deviceStrTypes) {
4789 llvm::SMLoc attrLoc = parser.getCurrentLocation();
4790 mlir::Attribute newAttr;
4791 bool isSymbolRefAttr;
4792 if (parser.parseAttribute(newAttr))
4794 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4795 bindIdNameAttrs.push_back(symbolRefAttr);
4796 isSymbolRefAttr = true;
4797 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4798 bindStrNameAttrs.push_back(stringAttr);
4799 isSymbolRefAttr =
false;
4802 "expected symbol reference or string attribute");
4806 if (isSymbolRefAttr) {
4807 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4808 parser.getContext(), mlir::acc::DeviceType::None));
4810 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4811 parser.getContext(), mlir::acc::DeviceType::None));
4814 if (isSymbolRefAttr) {
4815 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4816 parser.parseRSquare())
4819 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4820 parser.parseRSquare())
4828 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4829 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4830 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4831 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4837 std::optional<mlir::ArrayAttr> bindIdName,
4838 std::optional<mlir::ArrayAttr> bindStrName,
4839 std::optional<mlir::ArrayAttr> deviceIdTypes,
4840 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4847 allBindNames.append(bindIdName->begin(), bindIdName->end());
4848 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4853 allBindNames.append(bindStrName->begin(), bindStrName->end());
4854 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4858 if (!allBindNames.empty())
4859 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4860 [&](
const auto &pair) {
4861 p << std::get<0>(pair);
4867 mlir::ArrayAttr &gang,
4868 mlir::ArrayAttr &gangDim,
4869 mlir::ArrayAttr &gangDimDeviceTypes) {
4872 gangDimDeviceTypeAttrs;
4873 bool needCommaBeforeOperands =
false;
4877 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4878 parser.
getContext(), mlir::acc::DeviceType::None));
4879 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4886 if (parser.parseAttribute(gangAttrs.emplace_back()))
4893 needCommaBeforeOperands =
true;
4896 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4900 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4901 parser.parseColon() ||
4902 parser.parseAttribute(gangDimAttrs.emplace_back()))
4904 if (succeeded(parser.parseOptionalLSquare())) {
4905 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4906 parser.parseRSquare())
4909 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4910 parser.getContext(), mlir::acc::DeviceType::None));
4916 if (
failed(parser.parseRParen()))
4919 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4920 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4921 gangDimDeviceTypes =
4922 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4928 std::optional<mlir::ArrayAttr> gang,
4929 std::optional<mlir::ArrayAttr> gangDim,
4930 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4933 gang->size() == 1) {
4934 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4935 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4947 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4948 [&](
const auto &pair) {
4949 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4950 p << std::get<0>(pair);
4958 mlir::ArrayAttr &deviceTypes) {
4962 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4963 parser.
getContext(), mlir::acc::DeviceType::None));
4964 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4971 if (parser.parseAttribute(attributes.emplace_back()))
4979 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4985 std::optional<mlir::ArrayAttr> deviceTypes) {
4988 auto deviceTypeAttr =
4989 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4990 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4999 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
5005bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
5007bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
5011bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
5013bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
5017bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
5019bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
5023std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
5024RoutineOp::getBindNameValue() {
5025 return getBindNameValue(mlir::acc::DeviceType::None);
5028std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
5029RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
5031 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
5032 auto attr = (*getBindIdName())[*pos];
5033 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
5034 assert(symbolRefAttr &&
"expected SymbolRef");
5035 return symbolRefAttr;
5040 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
5041 auto attr = (*getBindStrName())[*pos];
5042 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
5043 assert(stringAttr &&
"expected String");
5048 return std::nullopt;
5051bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
5053bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
5057std::optional<int64_t> RoutineOp::getGangDimValue() {
5058 return getGangDimValue(mlir::acc::DeviceType::None);
5061std::optional<int64_t>
5062RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
5064 return std::nullopt;
5065 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
5066 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
5067 return intAttr.getInt();
5069 return std::nullopt;
5074 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
5075 effectiveDeviceTypes));
5080 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
5081 effectiveDeviceTypes));
5086 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
5087 effectiveDeviceTypes));
5092 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
5093 effectiveDeviceTypes));
5102 if (getGangDimAttr())
5103 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
5104 if (getGangDimDeviceTypeAttr())
5105 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
5107 assert(dimValues.size() == deviceTypes.size());
5109 if (effectiveDeviceTypes.empty()) {
5110 dimValues.push_back(
5111 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
5112 deviceTypes.push_back(
5113 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
5115 for (DeviceType dt : effectiveDeviceTypes) {
5116 dimValues.push_back(
5117 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
5118 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
5121 assert(dimValues.size() == deviceTypes.size());
5123 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
5124 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
5127void RoutineOp::addBindStrName(
MLIRContext *context,
5129 mlir::StringAttr val) {
5130 unsigned before = getBindStrNameDeviceTypeAttr()
5131 ? getBindStrNameDeviceTypeAttr().size()
5134 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5135 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
5136 unsigned after = getBindStrNameDeviceTypeAttr().size();
5139 if (getBindStrNameAttr())
5140 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
5141 for (
unsigned i = 0; i < after - before; ++i)
5142 vals.push_back(val);
5144 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
5147void RoutineOp::addBindIDName(
MLIRContext *context,
5149 mlir::SymbolRefAttr val) {
5151 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
5153 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5154 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
5155 unsigned after = getBindIdNameDeviceTypeAttr().size();
5158 if (getBindIdNameAttr())
5159 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
5160 for (
unsigned i = 0; i < after - before; ++i)
5161 vals.push_back(val);
5163 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
5170LogicalResult acc::InitOp::verify() {
5171 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5172 return emitOpError(
"cannot be nested in a compute operation");
5176void acc::InitOp::addDeviceType(
MLIRContext *context,
5177 mlir::acc::DeviceType deviceType) {
5179 if (getDeviceTypesAttr())
5180 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5182 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5183 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5190LogicalResult acc::ShutdownOp::verify() {
5191 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5192 return emitOpError(
"cannot be nested in a compute operation");
5196void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
5197 mlir::acc::DeviceType deviceType) {
5199 if (getDeviceTypesAttr())
5200 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5202 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5203 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5210LogicalResult acc::SetOp::verify() {
5211 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5212 return emitOpError(
"cannot be nested in a compute operation");
5213 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
5214 return emitOpError(
"at least one default_async, device_num, or device_type "
5215 "operand must appear");
5223LogicalResult acc::UpdateOp::verify() {
5225 if (getDataClauseOperands().empty())
5226 return emitError(
"at least one value must be present in dataOperands");
5229 getAsyncOperandsDeviceTypeAttr(),
5234 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
5235 getWaitOperandsDeviceTypeAttr(),
"wait")))
5241 for (
mlir::Value operand : getDataClauseOperands())
5242 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp,
5243 acc::MapInfoOp>(operand.getDefiningOp()))
5244 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
5250unsigned UpdateOp::getNumDataOperands() {
5251 return getDataClauseOperands().size();
5254Value UpdateOp::getDataOperand(
unsigned i) {
5256 numOptional += getIfCond() ? 1 : 0;
5257 return getOperand(getWaitOperands().size() + numOptional + i);
5262 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
5265bool UpdateOp::hasAsyncOnly() {
5266 return hasAsyncOnly(mlir::acc::DeviceType::None);
5269bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
5274 return getAsyncValue(mlir::acc::DeviceType::None);
5277mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
5287bool UpdateOp::hasWaitOnly() {
5288 return hasWaitOnly(mlir::acc::DeviceType::None);
5291bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
5296 return getWaitValues(mlir::acc::DeviceType::None);
5300UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
5302 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
5303 getHasWaitDevnum(), deviceType);
5307 return getWaitDevnum(mlir::acc::DeviceType::None);
5310mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
5312 getWaitOperandsSegments(), getHasWaitDevnum(),
5318 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
5319 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
5322void UpdateOp::addAsyncOperand(
5325 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5326 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
5327 getAsyncOperandsMutable()));
5332 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
5333 effectiveDeviceTypes));
5336void UpdateOp::addWaitOperands(
5341 if (getWaitOperandsSegments())
5342 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
5344 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5345 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
5346 getWaitOperandsMutable(), segments));
5347 setWaitOperandsSegments(segments);
5350 if (getHasWaitDevnumAttr())
5351 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5354 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5356 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5363LogicalResult acc::WaitOp::verify() {
5366 if (getAsyncOperand() && getAsync())
5367 return emitError(
"async attribute cannot appear with asyncOperand");
5369 if (getWaitDevnum() && getWaitOperands().empty())
5370 return emitError(
"wait_devnum cannot appear without waitOperands");
5375#define GET_OP_CLASSES
5376#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5378#define GET_ATTRDEF_CLASSES
5379#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5381#define GET_TYPEDEF_CLASSES
5382#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5393 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5394 [&](
auto entry) {
return entry.getVarPtr(); })
5395 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5396 [&](
auto exit) {
return exit.getVarPtr(); })
5406 [&](
auto entry) {
return entry.getVar(); })
5414 [&](
auto entry) {
return entry.getVarType(); })
5415 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5416 [&](
auto exit) {
return exit.getVarType(); })
5427 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5428 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5439 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5448 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5458 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5459 [&](
auto dataClause) {
5461 dataClause.getBounds().begin(),
5462 dataClause.getBounds().end());
5474 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5476 dataClause.getAsyncOperands().begin(),
5477 dataClause.getAsyncOperands().end());
5488 return dataClause.getAsyncOperandsDeviceTypeAttr();
5496 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5503 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5504 [&](
auto entry) {
return entry.getName(); })
5511std::optional<mlir::acc::DataClause>
5516 .Case<ACC_DATA_ENTRY_OPS>(
5517 [&](
auto entry) {
return entry.getDataClause(); })
5525 .Case<mlir::acc::MapInfoOp>([&](
auto mapInfo) {
5526 return bitEnumContainsAny(mapInfo.getMapFlags(),
5527 mlir::acc::MapFlags::implicit);
5535 [&](
auto dataClause) {
return dataClause.getSynthetic(); })
5543 mlir::acc::KernelEnvironmentOp>(
5544 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5546 return dataOperands;
5554 mlir::acc::KernelEnvironmentOp>(
5555 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5557 return dataOperands;
5564 [&](
auto entry) {
return entry.getRecipeAttr(); })
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
static void printSourceLocation(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::LocationAttr locAttr)
void printRoutineGangClause(OpAsmPrinter &p, Operation *op, std::optional< mlir::ArrayAttr > gang, std::optional< mlir::ArrayAttr > gangDim, std::optional< mlir::ArrayAttr > gangDimDeviceTypes)
bool hasDuplicateDeviceTypes(std::optional< mlir::ArrayAttr > segments, llvm::SmallSet< mlir::acc::DeviceType, 3 > &deviceTypes)
static LogicalResult verifyDeviceTypeCountMatch(Op op, OperandRange operands, ArrayAttr deviceTypes, llvm::StringRef keyword)
static ParseResult parseArrayAttr(mlir::OpAsmParser &parser, mlir::ArrayAttr &attr)
static ParseResult parseBindName(OpAsmParser &parser, mlir::ArrayAttr &bindIdName, mlir::ArrayAttr &bindStrName, mlir::ArrayAttr &deviceIdTypes, mlir::ArrayAttr &deviceStrTypes)
static void printRecipeSym(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::SymbolRefAttr recipeAttr)
static mlir::Operation::operand_range getWaitValuesWithoutDevnum(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t > > segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static void printArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::ArrayAttr attr)
static bool hasOnlyDeviceTypeNone(std::optional< mlir::ArrayAttr > attrs)
static ParseResult parseRecipeSym(mlir::OpAsmParser &parser, mlir::SymbolRefAttr &recipeAttr)
static void printAccVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value accVar, mlir::Type accVarType)
static mlir::Value getWaitDevnumValue(std::optional< mlir::ArrayAttr > deviceTypeAttr, mlir::Operation::operand_range operands, std::optional< llvm::ArrayRef< int32_t > > segments, std::optional< mlir::ArrayAttr > hasWaitDevnum, mlir::acc::DeviceType deviceType)
static bool hasAnyGangWorkerVectorForDeviceType(std::optional< mlir::ArrayAttr > numGangsDeviceType, mlir::Operation::operand_range numGangs, std::optional< llvm::ArrayRef< int32_t > > numGangsSegments, std::optional< mlir::ArrayAttr > numWorkersDeviceType, mlir::Operation::operand_range numWorkers, std::optional< mlir::ArrayAttr > vectorLengthDeviceType, mlir::Operation::operand_range vectorLength, mlir::acc::DeviceType deviceType)
static void printVar(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Value var)
static void printWaitClause(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments, std::optional< mlir::ArrayAttr > hasDevNum, std::optional< mlir::ArrayAttr > keywordOnly)
static ParseResult parseWaitClause(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments, mlir::ArrayAttr &hasDevNum, mlir::ArrayAttr &keywordOnly)
static BodyExecution getBodyExecution(LoopOp loopOp)
Prove whether the body of loopOp runs.
static bool hasDeviceTypeValues(std::optional< mlir::ArrayAttr > arrayAttr)
static void printDeviceTypeArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > deviceTypes)
static ParseResult parseGangValue(OpAsmParser &parser, llvm::StringRef keyword, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, llvm::SmallVector< GangArgTypeAttr > &attributes, GangArgTypeAttr gangArgType, bool &needCommaBetweenValues, bool &newValue)
static ParseResult parseCombinedConstructsLoop(mlir::OpAsmParser &parser, mlir::acc::CombinedConstructsTypeAttr &attr)
static std::optional< mlir::acc::DeviceType > checkDeviceTypes(mlir::ArrayAttr deviceTypes)
Check for duplicates in the DeviceType array attribute.
static LogicalResult checkDeclareOperands(Op &op, const mlir::ValueRange &operands, bool requireAtLeastOneOperand=true)
static LogicalResult checkVarAndAccVar(Op op)
static ParseResult parseOperandsWithKeywordOnly(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::UnitAttr &attr)
static void printDeviceTypes(mlir::OpAsmPrinter &p, std::optional< mlir::ArrayAttr > deviceTypes)
static LogicalResult checkVarAndVarType(Op op)
static LogicalResult checkValidModifier(Op op, acc::DataClauseModifier validModifiers)
static void addOperandEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, MutableOperandRange operand)
Helper to add an effect on an operand, referenced by its mutable range.
ParseResult parseLoopControl(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &lowerbound, SmallVectorImpl< Type > &lowerboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &upperbound, SmallVectorImpl< Type > &upperboundType, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &step, SmallVectorImpl< Type > &stepType)
loop-control ::= control ( ssa-id-and-type-list ) = ( ssa-id-and-type-list ) to ( ssa-id-and-type-lis...
static LogicalResult checkDataOperands(Op op, const mlir::ValueRange &operands)
Check dataOperands for acc.parallel, acc.serial and acc.kernels.
static ParseResult parseDeviceTypeOperands(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes)
static mlir::Value getValueInDeviceTypeSegment(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, mlir::acc::DeviceType deviceType)
static void addResultEffect(SmallVectorImpl< SideEffects::EffectInstance< MemoryEffects::Effect > > &effects, Value result)
Helper to add an effect on a result value.
static LogicalResult checkNoModifier(Op op)
static ParseResult parseAccVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var, mlir::Type &accVarType)
static std::optional< unsigned > findSegment(ArrayAttr segments, mlir::acc::DeviceType deviceType)
static ParseResult parseDenseBoolArrayAttr(mlir::OpAsmParser &parser, mlir::DenseBoolArrayAttr &attr)
static mlir::Operation::operand_range getValuesFromSegments(std::optional< mlir::ArrayAttr > arrayAttr, mlir::Operation::operand_range range, std::optional< llvm::ArrayRef< int32_t > > segments, mlir::acc::DeviceType deviceType)
static ParseResult parseNumGangs(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
static void getSingleRegionOpSuccessorRegions(Operation *op, Region ®ion, RegionBranchPoint point, SmallVectorImpl< RegionSuccessor > ®ions)
Generic helper for single-region OpenACC ops that execute their body once and then continue after the...
static ParseResult parseVar(mlir::OpAsmParser &parser, OpAsmParser::UnresolvedOperand &var)
void printLoopControl(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lowerbound, TypeRange lowerboundType, ValueRange upperbound, TypeRange upperboundType, ValueRange steps, TypeRange stepType)
static ValueRange getSingleRegionSuccessorInputs(Operation *op, RegionSuccessor successor)
static void printDenseBoolArrayAttr(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::DenseBoolArrayAttr attr)
static ParseResult parseDeviceTypeArrayAttr(OpAsmParser &parser, mlir::ArrayAttr &deviceTypes)
static ParseResult parseRoutineGangClause(OpAsmParser &parser, mlir::ArrayAttr &gang, mlir::ArrayAttr &gangDim, mlir::ArrayAttr &gangDimDeviceTypes)
static void printDeviceTypeOperandsWithSegment(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments)
static void printDeviceTypeOperands(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes)
static void printOperandWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::Value > operand, mlir::Type operandType, mlir::UnitAttr attr)
static ParseResult parseSourceLocation(mlir::OpAsmParser &parser, mlir::LocationAttr &locAttr)
static ParseResult parseDeviceTypeOperandsWithSegment(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::DenseI32ArrayAttr &segments)
static bool isEnclosedIntoComputeOp(mlir::Operation *op)
static ParseResult parseOperandWithKeywordOnly(mlir::OpAsmParser &parser, std::optional< OpAsmParser::UnresolvedOperand > &operand, mlir::Type &operandType, mlir::UnitAttr &attr)
static void printVarPtrType(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::Type varPtrType, mlir::TypeAttr varTypeAttr)
static ParseResult parseGangClause(OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &gangOperands, llvm::SmallVectorImpl< Type > &gangOperandsType, mlir::ArrayAttr &gangArgType, mlir::ArrayAttr &deviceType, mlir::DenseI32ArrayAttr &segments, mlir::ArrayAttr &gangOnlyDeviceType)
static LogicalResult verifyInitLikeSingleArgRegion(Operation *op, Region ®ion, StringRef regionType, StringRef regionName, Type type, bool verifyYield, bool optional=false)
static void printOperandsWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, mlir::UnitAttr attr)
static void printSingleDeviceType(mlir::OpAsmPrinter &p, mlir::Attribute attr)
static LogicalResult checkRecipe(OpT op, llvm::StringRef operandName)
static LogicalResult checkPrivateOperands(mlir::Operation *accConstructOp, const mlir::ValueRange &operands, llvm::StringRef operandName)
static void printDeviceTypeOperandsWithKeywordOnly(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::ArrayAttr > keywordOnlyDeviceTypes)
static bool hasDeviceType(std::optional< mlir::ArrayAttr > arrayAttr, mlir::acc::DeviceType deviceType)
void printGangClause(OpAsmPrinter &p, Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > gangArgTypes, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments, std::optional< mlir::ArrayAttr > gangOnlyDeviceTypes)
static ParseResult parseDeviceTypeOperandsWithKeywordOnly(mlir::OpAsmParser &parser, llvm::SmallVectorImpl< mlir::OpAsmParser::UnresolvedOperand > &operands, llvm::SmallVectorImpl< Type > &types, mlir::ArrayAttr &deviceTypes, mlir::ArrayAttr &keywordOnlyDeviceType)
static ParseResult parseVarPtrType(mlir::OpAsmParser &parser, mlir::Type &varPtrType, mlir::TypeAttr &varTypeAttr)
static LogicalResult checkWaitAndAsyncConflict(Op op)
static LogicalResult verifyDeviceTypeAndSegmentCountMatch(Op op, OperandRange operands, DenseI32ArrayAttr segments, ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment=0)
static unsigned getParallelismForDeviceType(acc::RoutineOp op, acc::DeviceType dtype)
static void printNumGangs(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::OperandRange operands, mlir::TypeRange types, std::optional< mlir::ArrayAttr > deviceTypes, std::optional< mlir::DenseI32ArrayAttr > segments)
BodyExecution
Whether the body of a structured acc.loop is proven to run.
@ Always
The body runs at least once, so the parent cannot bypass the region.
@ Never
The body never runs, so the parent cannot enter the region.
@ Maybe
Neither could be proven, so the parent may do either.
static void printCombinedConstructsLoop(mlir::OpAsmPrinter &p, mlir::Operation *op, mlir::acc::CombinedConstructsTypeAttr attr)
static void printBindName(mlir::OpAsmPrinter &p, mlir::Operation *op, std::optional< mlir::ArrayAttr > bindIdName, std::optional< mlir::ArrayAttr > bindStrName, std::optional< mlir::ArrayAttr > deviceIdTypes, std::optional< mlir::ArrayAttr > deviceStrTypes)
static LogicalResult verifyYield(linalg::YieldOp op, LinalgOp linalgOp)
false
Parses a map_entries map type from a string format back into its numeric value.
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
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)
virtual void printAttribute(Attribute attr)
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
static BoolAttr get(MLIRContext *context, bool value)
MLIRContext * getContext() const
This is a utility class for mapping one set of IR entities to another.
Location objects represent source locations information in MLIR.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class provides a mutable adaptor for a range of operands.
unsigned size() const
Returns the current size of the range.
void append(ValueRange values)
Append the given values to the range.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region ®ion, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult parseArgumentList(SmallVectorImpl< Argument > &result, Delimiter delimiter=Delimiter::None, bool allowType=false, bool allowAttrs=false)=0
Parse zero or more arguments with a specified surrounding delimiter.
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
virtual void printOperand(Value value)=0
Print implementations for various things an operation contains.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
OperandRange operand_range
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
bool isParent() const
Returns true if branching from the parent op.
This class represents a successor of a region.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
bool hasOneBlock()
Return true if this region has exactly one block.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
This class represents a specific instance of an effect.
static DerivedEffect * get()
static CurrentDeviceIdResource * get()
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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_CLAUSE_OPS
#define ACC_DATA_ENTRY_OPS
#define ACC_DATA_EXIT_OPS
bool getSyntheticFlag(mlir::Operation *accDataClauseOp)
Used to find out whether the implementation created the data operation for its own bookkeeping,...
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
mlir::TypedValue< mlir::acc::PointerLikeType > getAccPtr(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation if it implements PointerLikeType.
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
mlir::MutableOperandRange getMutableDataOperands(mlir::Operation *accOp)
Used to get a mutable range iterating over the data operands.
mlir::SmallVector< mlir::Value > getBounds(mlir::Operation *accDataClauseOp)
Used to obtain bounds from an acc data clause operation.
std::optional< ClauseDefaultValue > getDefaultAttr(mlir::Operation *op)
Looks for an OpenACC default attribute on the current operation op or in a parent operation which enc...
bool hasWaitDevnum(OpTy op, DeviceType deviceType)
Returns whether the wait clause op gives for deviceType carries a devnum modifier,...
mlir::ValueRange getDataOperands(mlir::Operation *accOp)
Used to get an immutable range iterating over the data operands.
std::optional< llvm::StringRef > getVarName(mlir::Operation *accOp)
Used to obtain the name from an acc operation.
bool isGangWorkerVectorAllOne(ComputeOpT op)
bool getImplicitFlag(mlir::Operation *accDataEntryOp)
Used to find out whether data operation is implicit.
mlir::SymbolRefAttr getRecipe(mlir::Operation *accOp)
Used to get the recipe attribute from a data clause operation.
mlir::SmallVector< mlir::Value > getAsyncOperands(mlir::Operation *accDataClauseOp)
Used to obtain async operands from an acc data clause operation.
bool isMappableType(mlir::Type type)
Used to check whether the provided type implements the MappableType interface.
mlir::Value getVarPtrPtr(mlir::Operation *accDataClauseOp)
Used to obtain the varPtrPtr from a data clause operation.
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.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
detail::DenseArrayAttrImpl< bool > DenseBoolArrayAttr
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
This is the representation of an operand reference.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
This represents an operation in an abstracted form, suitable for use with the builder APIs.