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 isDeviceData(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 MemrefGlobalVariableModel
391 :
public GlobalVariableOpInterface::ExternalModel<MemrefGlobalVariableModel,
393 bool isConstant(Operation *op)
const {
394 auto globalOp = cast<memref::GlobalOp>(op);
395 return globalOp.getConstant();
398 bool hasInitializer(Operation *op)
const {
399 auto globalOp = cast<memref::GlobalOp>(op);
400 return globalOp.getInitialValue().has_value();
403 Region *getInitRegion(Operation *op)
const {
408 bool isDeviceData(Operation *op)
const {
409 auto globalOp = cast<memref::GlobalOp>(op);
410 Attribute memSpace = globalOp.getType().getMemorySpace();
411 return isa_and_nonnull<gpu::AddressSpaceAttr>(memSpace);
414 bool isCompilerGenerated(Operation *op)
const {
return false; }
417struct GPULaunchOffloadRegionModel
418 :
public acc::OffloadRegionOpInterface::ExternalModel<
419 GPULaunchOffloadRegionModel, gpu::LaunchOp> {
420 mlir::Region &getOffloadRegion(mlir::Operation *op)
const {
421 return cast<gpu::LaunchOp>(op).getBody();
429mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
430 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
433 if (existingDeviceTypes)
434 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
436 if (newDeviceTypes.empty())
437 deviceTypes.push_back(
438 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
440 for (DeviceType dt : newDeviceTypes)
441 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
443 return mlir::ArrayAttr::get(context, deviceTypes);
452mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
453 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
458 if (existingDeviceTypes)
459 llvm::copy(existingDeviceTypes, std::back_inserter(deviceTypes));
461 if (newDeviceTypes.empty()) {
462 argCollection.
append(arguments);
463 segments.push_back(arguments.size());
464 deviceTypes.push_back(
465 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
468 for (DeviceType dt : newDeviceTypes) {
469 argCollection.
append(arguments);
470 segments.push_back(arguments.size());
471 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
474 return mlir::ArrayAttr::get(context, deviceTypes);
478mlir::ArrayAttr addDeviceTypeAffectedOperandHelper(
479 MLIRContext *context, mlir::ArrayAttr existingDeviceTypes,
483 return addDeviceTypeAffectedOperandHelper(context, existingDeviceTypes,
484 newDeviceTypes, arguments,
485 argCollection, segments);
493void OpenACCDialect::initialize() {
496#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
499#define GET_ATTRDEF_LIST
500#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
503#define GET_TYPEDEF_LIST
504#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
510 MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
512 UnrankedMemRefType::attachInterface<
513 MemRefPointerLikeModel<UnrankedMemRefType>>(*
getContext());
514 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
516 PrivateType::attachInterface<PrivateTypePointerLikeModel>(*
getContext());
519 memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
521 memref::GlobalOp::attachInterface<MemrefGlobalVariableModel>(*
getContext());
522 gpu::LaunchOp::attachInterface<GPULaunchOffloadRegionModel>(*
getContext());
559void ParallelOp::getSuccessorRegions(
589void HostDataOp::getSuccessorRegions(
617 if (loopOp.isContainerLike())
627 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
634 if (!lb || !
ub || !step || *step == 0) {
643 std::optional<ArrayRef<bool>> inclusiveUbs =
644 loopOp.getInclusiveUpperbound();
645 bool inclusiveUb = inclusiveUbs && (*inclusiveUbs)[i];
646 assert(*step != 0 &&
"zero step should have been filtered out");
647 bool runsOnce = *step > 0 ? (inclusiveUb ? *lb <= *
ub : *lb < *
ub)
648 : (inclusiveUb ? *lb >= *
ub : *lb > *
ub);
666 if (getUnstructured()) {
713 return arrayAttr && *arrayAttr && arrayAttr->size() > 0;
717 mlir::acc::DeviceType deviceType) {
721 for (
auto attr : *arrayAttr) {
722 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
723 if (deviceTypeAttr.getValue() == deviceType)
731 std::optional<mlir::ArrayAttr> deviceTypes) {
736 llvm::interleaveComma(*deviceTypes, p,
742 mlir::acc::DeviceType deviceType) {
743 unsigned segmentIdx = 0;
744 for (
auto attr : segments) {
745 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
746 if (deviceTypeAttr.getValue() == deviceType)
747 return std::make_optional(segmentIdx);
757 mlir::acc::DeviceType deviceType) {
759 return range.take_front(0);
760 if (
auto pos =
findSegment(*arrayAttr, deviceType)) {
761 int32_t nbOperandsBefore = 0;
762 for (
unsigned i = 0; i < *pos; ++i)
763 nbOperandsBefore += (*segments)[i];
764 return range.drop_front(nbOperandsBefore).take_front((*segments)[*pos]);
766 return range.take_front(0);
773 std::optional<mlir::ArrayAttr> hasWaitDevnum,
774 mlir::acc::DeviceType deviceType) {
777 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
778 if (hasWaitDevnum && *hasWaitDevnum) {
779 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
780 if (boolAttr && boolAttr.getValue())
793 std::optional<mlir::ArrayAttr> hasWaitDevnum,
794 mlir::acc::DeviceType deviceType) {
799 if (
auto pos =
findSegment(*deviceTypeAttr, deviceType)) {
800 if (hasWaitDevnum && *hasWaitDevnum) {
801 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasWaitDevnum)[*pos]);
802 if (boolAttr.getValue())
803 return range.drop_front(1);
809template <
typename Op>
811 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
813 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
818 op.hasAsyncOnly(dtype))
820 "asyncOnly attribute cannot appear with asyncOperand");
825 op.hasWaitOnly(dtype))
826 return op.
emitError(
"wait attribute cannot appear with waitOperands");
831template <
typename Op>
834 return op.
emitError(
"must have var operand");
837 if (!mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
838 !mlir::isa<mlir::acc::MappableType>(op.getVar().getType()))
839 return op.
emitError(
"var must be mappable or pointer-like");
842 if (mlir::isa<mlir::acc::PointerLikeType>(op.getVar().getType()) &&
843 op.getVarType() == op.getVar().getType())
844 return op.
emitError(
"varType must capture the element type of var");
849template <
typename Op>
851 if (op.getVar().getType() != op.getAccVar().getType())
852 return op.
emitError(
"input and output types must match");
857template <
typename Op>
859 if (op.getModifiers() != acc::DataClauseModifier::none)
860 return op.
emitError(
"no data clause modifiers are allowed");
864template <
typename Op>
867 if (acc::bitEnumContainsAny(op.getModifiers(), ~validModifiers))
869 "invalid data clause modifiers: " +
870 acc::stringifyDataClauseModifier(op.getModifiers() & ~validModifiers));
875template <
typename OpT,
typename RecipeOpT>
876static LogicalResult
checkRecipe(OpT op, llvm::StringRef operandName) {
881 !std::is_same_v<OpT, acc::ReductionOp>)
884 mlir::SymbolRefAttr operandRecipe = op.getRecipeAttr();
886 return op->emitOpError() <<
"recipe expected for " << operandName;
891 return op->emitOpError()
892 <<
"expected symbol reference " << operandRecipe <<
" to point to a "
893 << operandName <<
" declaration";
914 if (mlir::isa<mlir::acc::PointerLikeType>(var.
getType()))
935 if (failed(parser.
parseType(accVarType)))
945 if (mlir::isa<mlir::acc::PointerLikeType>(accVar.
getType()))
957 mlir::TypeAttr &varTypeAttr) {
958 if (failed(parser.
parseType(varPtrType)))
969 varTypeAttr = mlir::TypeAttr::get(varType);
974 if (
auto ptrTy = dyn_cast<acc::PointerLikeType>(varPtrType)) {
975 Type elementType = ptrTy.getElementType();
978 varTypeAttr = mlir::TypeAttr::get(elementType ? elementType : varPtrType);
980 varTypeAttr = mlir::TypeAttr::get(varPtrType);
988 mlir::Type varPtrType, mlir::TypeAttr varTypeAttr) {
996 mlir::isa<mlir::acc::PointerLikeType>(varPtrType)
997 ? mlir::cast<mlir::acc::PointerLikeType>(varPtrType).getElementType()
1001 if (!typeToCheckAgainst)
1002 typeToCheckAgainst = varPtrType;
1003 if (typeToCheckAgainst != varType) {
1019 locAttr = mlir::dyn_cast<mlir::LocationAttr>(attr);
1021 return parser.
emitError(attrLoc,
"expected location attribute");
1031 mlir::SymbolRefAttr &recipeAttr) {
1038 mlir::SymbolRefAttr recipeAttr) {
1053 mlir::ArrayAttr &attr) {
1058 mlir::ArrayAttr attr) {
1065LogicalResult acc::DataBoundsOp::verify() {
1066 auto extent = getExtent();
1067 auto upperbound = getUpperbound();
1068 if (!extent && !upperbound)
1069 return emitError(
"expected extent or upperbound.");
1076LogicalResult acc::PrivateOp::verify() {
1079 "data clause associated with private operation must match its intent");
1093LogicalResult acc::FirstprivateOp::verify() {
1095 return emitError(
"data clause associated with firstprivate operation must "
1096 "match its intent");
1102 *
this,
"firstprivate")))
1110LogicalResult acc::ReductionOp::verify() {
1112 return emitError(
"data clause associated with reduction operation must "
1113 "match its intent");
1119 *
this,
"reduction")))
1127LogicalResult acc::DevicePtrOp::verify() {
1129 return emitError(
"data clause associated with deviceptr operation must "
1130 "match its intent");
1143LogicalResult acc::PresentOp::verify() {
1146 "data clause associated with present operation must match its intent");
1159LogicalResult acc::CopyinOp::verify() {
1161 if (!getImplicit() &&
getDataClause() != acc::DataClause::acc_copyin &&
1166 "data clause associated with copyin operation must match its intent"
1167 " or specify original clause this operation was decomposed from");
1173 acc::DataClauseModifier::always |
1174 acc::DataClauseModifier::capture)))
1179bool acc::CopyinOp::isCopyinReadonly() {
1180 return getDataClause() == acc::DataClause::acc_copyin_readonly ||
1181 acc::bitEnumContainsAny(getModifiers(),
1182 acc::DataClauseModifier::readonly);
1188LogicalResult acc::CreateOp::verify() {
1195 "data clause associated with create operation must match its intent"
1196 " or specify original clause this operation was decomposed from");
1204 acc::DataClauseModifier::always |
1205 acc::DataClauseModifier::capture)))
1210bool acc::CreateOp::isCreateZero() {
1212 return getDataClause() == acc::DataClause::acc_create_zero ||
1214 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1220LogicalResult acc::NoCreateOp::verify() {
1222 return emitError(
"data clause associated with no_create operation must "
1223 "match its intent");
1236LogicalResult acc::AttachOp::verify() {
1239 "data clause associated with attach operation must match its intent");
1253LogicalResult acc::DeclareDeviceResidentOp::verify() {
1254 if (
getDataClause() != acc::DataClause::acc_declare_device_resident)
1255 return emitError(
"data clause associated with device_resident operation "
1256 "must match its intent");
1270LogicalResult acc::DeclareLinkOp::verify() {
1273 "data clause associated with link operation must match its intent");
1286LogicalResult acc::CopyoutOp::verify() {
1293 "data clause associated with copyout operation must match its intent"
1294 " or specify original clause this operation was decomposed from");
1296 return emitError(
"must have both host and device pointers");
1302 acc::DataClauseModifier::always |
1303 acc::DataClauseModifier::capture)))
1308bool acc::CopyoutOp::isCopyoutZero() {
1309 return getDataClause() == acc::DataClause::acc_copyout_zero ||
1310 acc::bitEnumContainsAny(getModifiers(), acc::DataClauseModifier::zero);
1316LogicalResult acc::DeleteOp::verify() {
1325 getDataClause() != acc::DataClause::acc_declare_device_resident &&
1328 "data clause associated with delete operation must match its intent"
1329 " or specify original clause this operation was decomposed from");
1331 return emitError(
"must have device pointer");
1335 acc::DataClauseModifier::readonly |
1336 acc::DataClauseModifier::always |
1337 acc::DataClauseModifier::capture)))
1345LogicalResult acc::DetachOp::verify() {
1350 "data clause associated with detach operation must match its intent"
1351 " or specify original clause this operation was decomposed from");
1353 return emitError(
"must have device pointer");
1362LogicalResult acc::UpdateHostOp::verify() {
1367 "data clause associated with host operation must match its intent"
1368 " or specify original clause this operation was decomposed from");
1370 return emitError(
"must have both host and device pointers");
1383LogicalResult acc::UpdateDeviceOp::verify() {
1387 "data clause associated with device operation must match its intent"
1388 " or specify original clause this operation was decomposed from");
1401LogicalResult acc::UseDeviceOp::verify() {
1405 "data clause associated with use_device operation must match its intent"
1406 " or specify original clause this operation was decomposed from");
1419LogicalResult acc::CacheOp::verify() {
1424 "data clause associated with cache operation must match its intent"
1425 " or specify original clause this operation was decomposed from");
1435bool acc::CacheOp::isCacheReadonly() {
1436 return getDataClause() == acc::DataClause::acc_cache_readonly ||
1437 acc::bitEnumContainsAny(getModifiers(),
1438 acc::DataClauseModifier::readonly);
1454template <
typename EffectTy>
1459 for (
unsigned i = 0, e = operand.
size(); i < e; ++i)
1460 effects.emplace_back(EffectTy::get(), &operand[i]);
1464template <
typename EffectTy>
1469 effects.emplace_back(EffectTy::get(), mlir::cast<mlir::OpResult>(
result));
1473void acc::PrivateOp::getEffects(
1487void acc::FirstprivateOp::getEffects(
1501void acc::ReductionOp::getEffects(
1515void acc::DevicePtrOp::getEffects(
1524void acc::PresentOp::getEffects(
1535void acc::CopyinOp::getEffects(
1548void acc::CreateOp::getEffects(
1561void acc::NoCreateOp::getEffects(
1572void acc::AttachOp::getEffects(
1585void acc::GetDevicePtrOp::getEffects(
1594void acc::UpdateDeviceOp::getEffects(
1604void acc::UseDeviceOp::getEffects(
1613void acc::DeclareDeviceResidentOp::getEffects(
1624void acc::DeclareLinkOp::getEffects(
1635void acc::CacheOp::getEffects(
1640void acc::CopyoutOp::getEffects(
1653void acc::DeleteOp::getEffects(
1665void acc::DetachOp::getEffects(
1677void acc::UpdateHostOp::getEffects(
1693template <
typename OpTy>
1695 using OpRewritePattern<OpTy>::OpRewritePattern;
1697 LogicalResult matchAndRewrite(OpTy op,
1698 PatternRewriter &rewriter)
const override {
1700 Value ifCond = op.getIfCond();
1704 IntegerAttr constAttr;
1707 if (constAttr.getInt())
1708 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1720 assert(region.
hasOneBlock() &&
"expected single-block region");
1732template <
typename OpTy>
1733struct RemoveConstantIfConditionWithRegion :
public OpRewritePattern<OpTy> {
1734 using OpRewritePattern<OpTy>::OpRewritePattern;
1736 LogicalResult matchAndRewrite(OpTy op,
1737 PatternRewriter &rewriter)
const override {
1739 Value ifCond = op.getIfCond();
1743 IntegerAttr constAttr;
1746 if (constAttr.getInt())
1747 rewriter.
modifyOpInPlace(op, [&]() { op.getIfCondMutable().erase(0); });
1776 for (
Value bound : bounds) {
1777 argTypes.push_back(bound.getType());
1778 argLocs.push_back(loc);
1785 Value privatizedValue;
1791 if (isa<MappableType>(varType)) {
1792 auto mappableTy = cast<MappableType>(varType);
1793 auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
1794 auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
1795 varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
1797 mappableTy.generatePrivateInit(builder, loc, typedVar, varName, bounds,
1798 {}, varInfo, needsFree, destroyValues);
1799 if (!privatizedValue)
1802 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1803 auto pointerLikeTy = cast<PointerLikeType>(varType);
1805 privatizedValue = pointerLikeTy.genAllocate(builder, loc, varName, varType,
1806 blockArgVar, needsFree);
1807 if (!privatizedValue)
1813 initResults.append(destroyValues);
1814 acc::YieldOp::create(builder, loc, initResults);
1831 for (
Value bound : bounds) {
1832 copyArgTypes.push_back(bound.getType());
1833 copyArgLocs.push_back(loc);
1843 if (isa<MappableType>(varType)) {
1844 auto mappableTy = cast<MappableType>(varType);
1847 if (!mappableTy.generateCopy(
1852 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1853 auto pointerLikeTy = cast<PointerLikeType>(varType);
1854 if (!pointerLikeTy.genCopy(
1861 acc::TerminatorOp::create(builder, loc);
1878 for (
Value destroyValue : destroyValues) {
1879 destroyArgTypes.push_back(destroyValue.getType());
1880 destroyArgLocs.push_back(loc);
1882 for (
Value bound : bounds) {
1883 destroyArgTypes.push_back(bound.getType());
1884 destroyArgLocs.push_back(loc);
1888 destroyBlock->
addArguments(destroyArgTypes, destroyArgLocs);
1892 cast<TypedValue<PointerLikeType>>(destroyBlock->
getArgument(1));
1893 if (isa<MappableType>(varType)) {
1894 auto mappableTy = cast<MappableType>(varType);
1896 destroyBlock->
getArguments().slice(2, destroyValues.size());
1898 destroyBlock->
getArguments().drop_front(2 + destroyValues.size());
1899 if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, destroyArgs,
1900 destroyBounds, varInfo))
1903 assert(isa<PointerLikeType>(varType) &&
"Expected PointerLikeType");
1904 auto pointerLikeTy = cast<PointerLikeType>(varType);
1905 if (!pointerLikeTy.genFree(builder, loc, varToFree, allocRes, varType))
1909 acc::TerminatorOp::create(builder, loc);
1920 Operation *op,
Region ®ion, StringRef regionType, StringRef regionName,
1922 if (optional && region.
empty())
1926 return op->
emitOpError() <<
"expects non-empty " << regionName <<
" region";
1930 return op->
emitOpError() <<
"expects " << regionName
1933 << regionType <<
" type";
1936 for (YieldOp yieldOp : region.
getOps<acc::YieldOp>()) {
1937 if (yieldOp.getOperands().size() != 1 ||
1938 yieldOp.getOperands().getTypes()[0] != type)
1939 return op->
emitOpError() <<
"expects " << regionName
1941 "yield a value of the "
1942 << regionType <<
" type";
1948LogicalResult acc::PrivateRecipeOp::verifyRegions() {
1950 "privatization",
"init",
getType(),
1954 *
this, getDestroyRegion(),
"privatization",
"destroy",
getType(),
1960std::optional<PrivateRecipeOp>
1962 StringRef recipeName,
Value hostVar,
1967 bool isMappable = isa<MappableType>(varType);
1968 bool isPointerLike = isa<PointerLikeType>(varType);
1971 if (!isMappable && !isPointerLike)
1972 return std::nullopt;
1977 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
1981 bool needsFree =
false;
1984 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
1985 varName, bounds, needsFree, varInfo,
1988 return std::nullopt;
1995 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
1996 Value allocRes = yieldOp.getOperand(0);
1998 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
1999 varType, allocRes, destroyValues, bounds,
2002 return std::nullopt;
2009std::optional<PrivateRecipeOp>
2011 StringRef recipeName,
2012 FirstprivateRecipeOp firstprivRecipe) {
2015 auto varType = firstprivRecipe.getType();
2016 auto recipe = PrivateRecipeOp::create(builder, loc, recipeName,
2021 firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
2024 if (!firstprivRecipe.getDestroyRegion().empty()) {
2026 firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
2036LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
2038 "privatization",
"init",
getType(),
2042 if (getCopyRegion().empty())
2043 return emitOpError() <<
"expects non-empty copy region";
2048 return emitOpError() <<
"expects copy region with two arguments of the "
2049 "privatization type";
2051 if (getDestroyRegion().empty())
2055 "privatization",
"destroy",
2062std::optional<FirstprivateRecipeOp>
2064 StringRef recipeName,
Value hostVar,
2069 bool isMappable = isa<MappableType>(varType);
2070 bool isPointerLike = isa<PointerLikeType>(varType);
2073 if (!isMappable && !isPointerLike)
2074 return std::nullopt;
2079 auto recipe = FirstprivateRecipeOp::create(
2080 builder, loc, recipeName,
nullptr, varType);
2083 bool needsFree =
false;
2089 if (
failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
2090 varName, bounds, needsFree, varInfo,
2093 return std::nullopt;
2097 if (
failed(createCopyRegion(builder, loc, recipe.getCopyRegion(), varType,
2098 bounds, varInfo))) {
2100 return std::nullopt;
2107 cast<acc::YieldOp>(recipe.getInitRegion().front().getTerminator());
2108 Value allocRes = yieldOp.getOperand(0);
2110 if (
failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
2111 varType, allocRes, destroyValues, bounds,
2114 return std::nullopt;
2125LogicalResult acc::ReductionRecipeOp::verifyRegions() {
2131 if (getCombinerRegion().empty())
2132 return emitOpError() <<
"expects non-empty combiner region";
2134 Block &reductionBlock = getCombinerRegion().
front();
2138 return emitOpError() <<
"expects combiner region with the first two "
2139 <<
"arguments of the reduction type";
2141 for (YieldOp yieldOp : getCombinerRegion().getOps<YieldOp>()) {
2142 if (yieldOp.getOperands().size() != 1 ||
2143 yieldOp.getOperands().getTypes()[0] !=
getType())
2144 return emitOpError() <<
"expects combiner region to yield a value "
2145 "of the reduction type";
2156template <
typename Op>
2160 if (!mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
2161 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
2162 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
2163 acc::MapInfoOp>(operand.getDefiningOp()))
2165 "expect data entry/exit operation or acc.getdeviceptr "
2170template <
typename OpT,
typename RecipeOpT>
2173 llvm::StringRef operandName) {
2176 if (!mlir::isa<OpT>(operand.getDefiningOp()))
2178 <<
"expected " << operandName <<
" as defining op";
2179 if (!set.insert(operand).second)
2181 << operandName <<
" operand appears more than once";
2186unsigned ParallelOp::getNumDataOperands() {
2187 return getReductionOperands().size() + getPrivateOperands().size() +
2188 getFirstprivateOperands().size() + getDataClauseOperands().size();
2191Value ParallelOp::getDataOperand(
unsigned i) {
2193 numOptional += getNumGangs().size();
2194 numOptional += getNumWorkers().size();
2195 numOptional += getVectorLength().size();
2196 numOptional += getIfCond() ? 1 : 0;
2197 numOptional += getSelfCond() ? 1 : 0;
2198 return getOperand(getWaitOperands().size() + numOptional + i);
2201template <
typename Op>
2204 llvm::StringRef keyword) {
2205 if (!operands.empty() &&
2206 (!deviceTypes || deviceTypes.getValue().size() != operands.size()))
2207 return op.
emitOpError() << keyword <<
" operands count must match "
2208 << keyword <<
" device_type count";
2212template <
typename Op>
2215 ArrayAttr deviceTypes, llvm::StringRef keyword, int32_t maxInSegment = 0) {
2216 std::size_t numOperandsInSegments = 0;
2217 std::size_t nbOfSegments = 0;
2220 for (
auto segCount : segments.
asArrayRef()) {
2221 if (maxInSegment != 0 && segCount > maxInSegment)
2222 return op.
emitOpError() << keyword <<
" expects a maximum of "
2223 << maxInSegment <<
" values per segment";
2224 numOperandsInSegments += segCount;
2229 if ((numOperandsInSegments != operands.size()) ||
2230 (!deviceTypes && !operands.empty()))
2232 << keyword <<
" operand count does not match count in segments";
2233 if (deviceTypes && deviceTypes.getValue().size() != nbOfSegments)
2235 << keyword <<
" segment count does not match device_type count";
2239LogicalResult acc::ParallelOp::verify() {
2241 mlir::acc::PrivateRecipeOp>(
2242 *
this, getPrivateOperands(),
"private")))
2245 mlir::acc::FirstprivateRecipeOp>(
2246 *
this, getFirstprivateOperands(),
"firstprivate")))
2249 mlir::acc::ReductionRecipeOp>(
2250 *
this, getReductionOperands(),
"reduction")))
2254 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
2255 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
2259 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
2260 getWaitOperandsDeviceTypeAttr(),
"wait")))
2264 getNumWorkersDeviceTypeAttr(),
2269 getVectorLengthDeviceTypeAttr(),
2274 getAsyncOperandsDeviceTypeAttr(),
2287 mlir::acc::DeviceType deviceType) {
2290 if (
auto pos =
findSegment(*arrayAttr, deviceType))
2295bool acc::ParallelOp::hasAsyncOnly() {
2296 return hasAsyncOnly(mlir::acc::DeviceType::None);
2299bool acc::ParallelOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
2304 return getAsyncValue(mlir::acc::DeviceType::None);
2307mlir::Value acc::ParallelOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
2312mlir::Value acc::ParallelOp::getNumWorkersValue() {
2313 return getNumWorkersValue(mlir::acc::DeviceType::None);
2317acc::ParallelOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
2322mlir::Value acc::ParallelOp::getVectorLengthValue() {
2323 return getVectorLengthValue(mlir::acc::DeviceType::None);
2327acc::ParallelOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
2329 getVectorLength(), deviceType);
2333 return getNumGangsValues(mlir::acc::DeviceType::None);
2337ParallelOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
2339 getNumGangsSegments(), deviceType);
2343 std::optional<mlir::ArrayAttr> numGangsDeviceType,
2346 std::optional<mlir::ArrayAttr> numWorkersDeviceType,
2348 std::optional<mlir::ArrayAttr> vectorLengthDeviceType,
2350 mlir::acc::DeviceType deviceType) {
2360bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
2362 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
2363 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
2364 getVectorLength(), deviceType);
2367bool acc::ParallelOp::isEffectivelySerial() {
2371bool acc::ParallelOp::hasWaitOnly() {
2372 return hasWaitOnly(mlir::acc::DeviceType::None);
2375bool acc::ParallelOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
2380 return getWaitValues(mlir::acc::DeviceType::None);
2384ParallelOp::getWaitValues(mlir::acc::DeviceType deviceType) {
2386 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
2387 getHasWaitDevnum(), deviceType);
2391 return getWaitDevnum(mlir::acc::DeviceType::None);
2394mlir::Value ParallelOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
2396 getWaitOperandsSegments(), getHasWaitDevnum(),
2411 odsBuilder, odsState, asyncOperands,
nullptr,
2412 nullptr, waitOperands,
nullptr,
2414 nullptr, numGangs,
nullptr,
2415 nullptr, numWorkers,
2416 nullptr, vectorLength,
2417 nullptr, ifCond, selfCond,
2418 nullptr, reductionOperands, gangPrivateOperands,
2419 gangFirstPrivateOperands, dataClauseOperands,
2423void acc::ParallelOp::addNumWorkersOperand(
2426 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2427 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2428 getNumWorkersMutable()));
2430void acc::ParallelOp::addVectorLengthOperand(
2433 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2434 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2435 getVectorLengthMutable()));
2438void acc::ParallelOp::addAsyncOnly(
2440 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
2441 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
2444void acc::ParallelOp::addAsyncOperand(
2447 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2448 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
2449 getAsyncOperandsMutable()));
2452void acc::ParallelOp::addNumGangsOperands(
2456 if (getNumGangsSegments())
2457 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
2459 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2460 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2461 getNumGangsMutable(), segments));
2463 setNumGangsSegments(segments);
2465void acc::ParallelOp::addWaitOnly(
2467 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
2468 effectiveDeviceTypes));
2470void acc::ParallelOp::addWaitOperands(
2475 if (getWaitOperandsSegments())
2476 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
2478 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
2479 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
2480 getWaitOperandsMutable(), segments));
2481 setWaitOperandsSegments(segments);
2484 if (getHasWaitDevnumAttr())
2485 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
2488 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
2490 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
2493void acc::ParallelOp::addPrivatization(
MLIRContext *context,
2494 mlir::acc::PrivateOp op,
2495 mlir::acc::PrivateRecipeOp recipe) {
2496 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2497 getPrivateOperandsMutable().append(op.getResult());
2500void acc::ParallelOp::addFirstPrivatization(
2501 MLIRContext *context, mlir::acc::FirstprivateOp op,
2502 mlir::acc::FirstprivateRecipeOp recipe) {
2503 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2504 getFirstprivateOperandsMutable().append(op.getResult());
2507void acc::ParallelOp::addReduction(
MLIRContext *context,
2508 mlir::acc::ReductionOp op,
2509 mlir::acc::ReductionRecipeOp recipe) {
2510 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
2511 getReductionOperandsMutable().append(op.getResult());
2526 int32_t crtOperandsSize = operands.size();
2529 if (parser.parseOperand(operands.emplace_back()) ||
2530 parser.parseColonType(types.emplace_back()))
2535 seg.push_back(operands.size() - crtOperandsSize);
2545 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2546 parser.
getContext(), mlir::acc::DeviceType::None));
2552 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2559 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
2560 if (deviceTypeAttr.getValue() != mlir::acc::DeviceType::None)
2561 p <<
" [" << attr <<
"]";
2566 std::optional<mlir::ArrayAttr> deviceTypes,
2567 std::optional<mlir::DenseI32ArrayAttr> segments) {
2569 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2571 llvm::interleaveComma(
2572 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2573 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2593 int32_t crtOperandsSize = operands.size();
2597 if (parser.parseOperand(operands.emplace_back()) ||
2598 parser.parseColonType(types.emplace_back()))
2604 seg.push_back(operands.size() - crtOperandsSize);
2614 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2615 parser.
getContext(), mlir::acc::DeviceType::None));
2621 deviceTypes = ArrayAttr::get(parser.
getContext(), arrayAttr);
2630 std::optional<mlir::DenseI32ArrayAttr> segments) {
2632 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2634 llvm::interleaveComma(
2635 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2636 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2649 mlir::ArrayAttr &keywordOnly) {
2653 bool needCommaBeforeOperands =
false;
2657 keywordAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2658 parser.
getContext(), mlir::acc::DeviceType::None));
2659 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2666 if (parser.parseAttribute(keywordAttrs.emplace_back()))
2673 needCommaBeforeOperands =
true;
2676 if (needCommaBeforeOperands && failed(parser.
parseComma()))
2683 int32_t crtOperandsSize = operands.size();
2695 if (parser.parseOperand(operands.emplace_back()) ||
2696 parser.parseColonType(types.emplace_back()))
2702 seg.push_back(operands.size() - crtOperandsSize);
2712 deviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
2713 parser.
getContext(), mlir::acc::DeviceType::None));
2720 deviceTypes = ArrayAttr::get(parser.
getContext(), deviceTypeAttrs);
2721 keywordOnly = ArrayAttr::get(parser.
getContext(), keywordAttrs);
2723 hasDevNum = ArrayAttr::get(parser.
getContext(), devnum);
2731 if (attrs->size() != 1)
2733 if (
auto deviceTypeAttr =
2734 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*attrs)[0]))
2735 return deviceTypeAttr.getValue() == mlir::acc::DeviceType::None;
2741 std::optional<mlir::ArrayAttr> deviceTypes,
2742 std::optional<mlir::DenseI32ArrayAttr> segments,
2743 std::optional<mlir::ArrayAttr> hasDevNum,
2744 std::optional<mlir::ArrayAttr> keywordOnly) {
2757 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
2759 auto boolAttr = mlir::dyn_cast<mlir::BoolAttr>((*hasDevNum)[it.index()]);
2760 if (boolAttr && boolAttr.getValue())
2762 llvm::interleaveComma(
2763 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
2764 p << operands[opIdx] <<
" : " << operands[opIdx].getType();
2781 if (parser.parseOperand(operands.emplace_back()) ||
2782 parser.parseColonType(types.emplace_back()))
2784 if (succeeded(parser.parseOptionalLSquare())) {
2785 if (parser.parseAttribute(attributes.emplace_back()) ||
2786 parser.parseRSquare())
2789 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2790 parser.getContext(), mlir::acc::DeviceType::None));
2797 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2804 std::optional<mlir::ArrayAttr> deviceTypes) {
2807 llvm::interleaveComma(llvm::zip(*deviceTypes, operands), p, [&](
auto it) {
2808 p << std::get<1>(it) <<
" : " << std::get<1>(it).getType();
2817 mlir::ArrayAttr &keywordOnlyDeviceType) {
2820 bool needCommaBeforeOperands =
false;
2824 keywordOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
2825 parser.
getContext(), mlir::acc::DeviceType::None));
2826 keywordOnlyDeviceType =
2827 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2835 if (parser.parseAttribute(
2836 keywordOnlyDeviceTypeAttributes.emplace_back()))
2843 keywordOnlyDeviceType =
2844 ArrayAttr::get(parser.
getContext(), keywordOnlyDeviceTypeAttributes);
2845 needCommaBeforeOperands =
true;
2848 if (needCommaBeforeOperands) {
2857 if (parser.parseOperand(operands.emplace_back()) ||
2858 parser.parseColonType(types.emplace_back()))
2860 if (succeeded(parser.parseOptionalLSquare())) {
2861 if (parser.parseAttribute(attributes.emplace_back()) ||
2862 parser.parseRSquare())
2865 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
2866 parser.getContext(), mlir::acc::DeviceType::None));
2872 if (
failed(parser.parseRParen()))
2877 deviceTypes = ArrayAttr::get(parser.getContext(), arrayAttr);
2884 std::optional<mlir::ArrayAttr> keywordOnlyDeviceTypes) {
2886 if (operands.begin() == operands.end() &&
2902 std::optional<OpAsmParser::UnresolvedOperand> &operand,
2903 mlir::Type &operandType, mlir::UnitAttr &attr) {
2906 attr = mlir::UnitAttr::get(parser.
getContext());
2916 if (failed(parser.
parseType(operandType)))
2926 std::optional<mlir::Value> operand,
2928 mlir::UnitAttr attr) {
2945 attr = mlir::UnitAttr::get(parser.
getContext());
2950 if (parser.parseOperand(operands.emplace_back()))
2958 if (parser.parseType(types.emplace_back()))
2973 mlir::UnitAttr attr) {
2978 llvm::interleaveComma(operands, p, [&](
auto it) { p << it; });
2980 llvm::interleaveComma(types, p, [&](
auto it) { p << it; });
2986 mlir::acc::CombinedConstructsTypeAttr &attr) {
2988 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2989 parser.
getContext(), mlir::acc::CombinedConstructsType::KernelsLoop);
2991 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2992 parser.
getContext(), mlir::acc::CombinedConstructsType::ParallelLoop);
2994 attr = mlir::acc::CombinedConstructsTypeAttr::get(
2995 parser.
getContext(), mlir::acc::CombinedConstructsType::SerialLoop);
2998 "expected compute construct name");
3006 mlir::acc::CombinedConstructsTypeAttr attr) {
3008 switch (attr.getValue()) {
3009 case mlir::acc::CombinedConstructsType::KernelsLoop:
3012 case mlir::acc::CombinedConstructsType::ParallelLoop:
3015 case mlir::acc::CombinedConstructsType::SerialLoop:
3026unsigned SerialOp::getNumDataOperands() {
3027 return getReductionOperands().size() + getPrivateOperands().size() +
3028 getFirstprivateOperands().size() + getDataClauseOperands().size();
3031Value SerialOp::getDataOperand(
unsigned i) {
3033 numOptional += getIfCond() ? 1 : 0;
3034 numOptional += getSelfCond() ? 1 : 0;
3035 return getOperand(getWaitOperands().size() + numOptional + i);
3038bool acc::SerialOp::hasAsyncOnly() {
3039 return hasAsyncOnly(mlir::acc::DeviceType::None);
3042bool acc::SerialOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3047 return getAsyncValue(mlir::acc::DeviceType::None);
3050mlir::Value acc::SerialOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3055bool acc::SerialOp::hasWaitOnly() {
3056 return hasWaitOnly(mlir::acc::DeviceType::None);
3059bool acc::SerialOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3064 return getWaitValues(mlir::acc::DeviceType::None);
3068SerialOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3070 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3071 getHasWaitDevnum(), deviceType);
3075 return getWaitDevnum(mlir::acc::DeviceType::None);
3078mlir::Value SerialOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3080 getWaitOperandsSegments(), getHasWaitDevnum(),
3084LogicalResult acc::SerialOp::verify() {
3086 mlir::acc::PrivateRecipeOp>(
3087 *
this, getPrivateOperands(),
"private")))
3090 mlir::acc::FirstprivateRecipeOp>(
3091 *
this, getFirstprivateOperands(),
"firstprivate")))
3094 mlir::acc::ReductionRecipeOp>(
3095 *
this, getReductionOperands(),
"reduction")))
3099 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3100 getWaitOperandsDeviceTypeAttr(),
"wait")))
3104 getAsyncOperandsDeviceTypeAttr(),
3114void acc::SerialOp::addAsyncOnly(
3116 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3117 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3120void acc::SerialOp::addAsyncOperand(
3123 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3124 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3125 getAsyncOperandsMutable()));
3128void acc::SerialOp::addWaitOnly(
3130 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3131 effectiveDeviceTypes));
3133void acc::SerialOp::addWaitOperands(
3138 if (getWaitOperandsSegments())
3139 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3141 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3142 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3143 getWaitOperandsMutable(), segments));
3144 setWaitOperandsSegments(segments);
3147 if (getHasWaitDevnumAttr())
3148 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3151 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3153 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3156void acc::SerialOp::addPrivatization(
MLIRContext *context,
3157 mlir::acc::PrivateOp op,
3158 mlir::acc::PrivateRecipeOp recipe) {
3159 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3160 getPrivateOperandsMutable().append(op.getResult());
3163void acc::SerialOp::addFirstPrivatization(
3164 MLIRContext *context, mlir::acc::FirstprivateOp op,
3165 mlir::acc::FirstprivateRecipeOp recipe) {
3166 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3167 getFirstprivateOperandsMutable().append(op.getResult());
3170void acc::SerialOp::addReduction(
MLIRContext *context,
3171 mlir::acc::ReductionOp op,
3172 mlir::acc::ReductionRecipeOp recipe) {
3173 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3174 getReductionOperandsMutable().append(op.getResult());
3181unsigned KernelsOp::getNumDataOperands() {
3182 return getDataClauseOperands().size();
3185Value KernelsOp::getDataOperand(
unsigned i) {
3187 numOptional += getWaitOperands().size();
3188 numOptional += getNumGangs().size();
3189 numOptional += getNumWorkers().size();
3190 numOptional += getVectorLength().size();
3191 numOptional += getIfCond() ? 1 : 0;
3192 numOptional += getSelfCond() ? 1 : 0;
3193 return getOperand(numOptional + i);
3196bool acc::KernelsOp::hasAsyncOnly() {
3197 return hasAsyncOnly(mlir::acc::DeviceType::None);
3200bool acc::KernelsOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
3205 return getAsyncValue(mlir::acc::DeviceType::None);
3208mlir::Value acc::KernelsOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
3214 return getNumWorkersValue(mlir::acc::DeviceType::None);
3218acc::KernelsOp::getNumWorkersValue(mlir::acc::DeviceType deviceType) {
3223mlir::Value acc::KernelsOp::getVectorLengthValue() {
3224 return getVectorLengthValue(mlir::acc::DeviceType::None);
3228acc::KernelsOp::getVectorLengthValue(mlir::acc::DeviceType deviceType) {
3230 getVectorLength(), deviceType);
3234 return getNumGangsValues(mlir::acc::DeviceType::None);
3238KernelsOp::getNumGangsValues(mlir::acc::DeviceType deviceType) {
3240 getNumGangsSegments(), deviceType);
3243bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
3245 getNumGangsDeviceType(), getNumGangs(), getNumGangsSegments(),
3246 getNumWorkersDeviceType(), getNumWorkers(), getVectorLengthDeviceType(),
3247 getVectorLength(), deviceType);
3250bool acc::KernelsOp::isEffectivelySerial() {
3254bool acc::KernelsOp::hasWaitOnly() {
3255 return hasWaitOnly(mlir::acc::DeviceType::None);
3258bool acc::KernelsOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
3263 return getWaitValues(mlir::acc::DeviceType::None);
3267KernelsOp::getWaitValues(mlir::acc::DeviceType deviceType) {
3269 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
3270 getHasWaitDevnum(), deviceType);
3274 return getWaitDevnum(mlir::acc::DeviceType::None);
3277mlir::Value KernelsOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
3279 getWaitOperandsSegments(), getHasWaitDevnum(),
3283LogicalResult acc::KernelsOp::verify() {
3285 *
this, getNumGangs(), getNumGangsSegmentsAttr(),
3286 getNumGangsDeviceTypeAttr(),
"num_gangs", 3)))
3290 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
3291 getWaitOperandsDeviceTypeAttr(),
"wait")))
3295 getNumWorkersDeviceTypeAttr(),
3300 getVectorLengthDeviceTypeAttr(),
3305 getAsyncOperandsDeviceTypeAttr(),
3315void acc::KernelsOp::addPrivatization(
MLIRContext *context,
3316 mlir::acc::PrivateOp op,
3317 mlir::acc::PrivateRecipeOp recipe) {
3318 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3319 getPrivateOperandsMutable().append(op.getResult());
3322void acc::KernelsOp::addFirstPrivatization(
3323 MLIRContext *context, mlir::acc::FirstprivateOp op,
3324 mlir::acc::FirstprivateRecipeOp recipe) {
3325 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3326 getFirstprivateOperandsMutable().append(op.getResult());
3329void acc::KernelsOp::addReduction(
MLIRContext *context,
3330 mlir::acc::ReductionOp op,
3331 mlir::acc::ReductionRecipeOp recipe) {
3332 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
3333 getReductionOperandsMutable().append(op.getResult());
3336void acc::KernelsOp::addNumWorkersOperand(
3339 setNumWorkersDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3340 context, getNumWorkersDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3341 getNumWorkersMutable()));
3344void acc::KernelsOp::addVectorLengthOperand(
3347 setVectorLengthDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3348 context, getVectorLengthDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3349 getVectorLengthMutable()));
3351void acc::KernelsOp::addAsyncOnly(
3353 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
3354 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
3357void acc::KernelsOp::addAsyncOperand(
3360 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3361 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
3362 getAsyncOperandsMutable()));
3365void acc::KernelsOp::addNumGangsOperands(
3369 if (getNumGangsSegmentsAttr())
3370 llvm::copy(*getNumGangsSegments(), std::back_inserter(segments));
3372 setNumGangsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3373 context, getNumGangsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3374 getNumGangsMutable(), segments));
3376 setNumGangsSegments(segments);
3379void acc::KernelsOp::addWaitOnly(
3381 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
3382 effectiveDeviceTypes));
3384void acc::KernelsOp::addWaitOperands(
3389 if (getWaitOperandsSegments())
3390 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
3392 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
3393 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
3394 getWaitOperandsMutable(), segments));
3395 setWaitOperandsSegments(segments);
3398 if (getHasWaitDevnumAttr())
3399 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
3402 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
3404 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
3411LogicalResult acc::HostDataOp::verify() {
3412 if (getDataClauseOperands().empty())
3413 return emitError(
"at least one operand must appear on the host_data "
3417 for (
mlir::Value operand : getDataClauseOperands()) {
3419 mlir::dyn_cast<acc::UseDeviceOp>(operand.getDefiningOp());
3421 return emitError(
"expect data entry operation as defining op");
3424 if (!seenVars.insert(useDeviceOp.getVar()).second)
3425 return emitError(
"duplicate use_device variable");
3432 results.
add<RemoveConstantIfConditionWithRegion<HostDataOp>>(context);
3444 bool &needCommaBetweenValues,
bool &newValue) {
3451 attributes.push_back(gangArgType);
3452 needCommaBetweenValues =
true;
3463 mlir::ArrayAttr &gangOnlyDeviceType) {
3468 bool needCommaBetweenValues =
false;
3469 bool needCommaBeforeOperands =
false;
3473 gangOnlyDeviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3474 parser.
getContext(), mlir::acc::DeviceType::None));
3475 gangOnlyDeviceType =
3476 ArrayAttr::get(parser.
getContext(), gangOnlyDeviceTypeAttributes);
3484 if (parser.parseAttribute(
3485 gangOnlyDeviceTypeAttributes.emplace_back()))
3492 needCommaBeforeOperands =
true;
3495 auto argNum = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3496 mlir::acc::GangArgType::Num);
3497 auto argDim = mlir::acc::GangArgTypeAttr::get(parser.
getContext(),
3498 mlir::acc::GangArgType::Dim);
3499 auto argStatic = mlir::acc::GangArgTypeAttr::get(
3500 parser.
getContext(), mlir::acc::GangArgType::Static);
3503 if (needCommaBeforeOperands) {
3504 needCommaBeforeOperands =
false;
3511 int32_t crtOperandsSize = gangOperands.size();
3513 bool newValue =
false;
3514 bool needValue =
false;
3515 if (needCommaBetweenValues) {
3523 gangOperands, gangOperandsType,
3524 gangArgTypeAttributes, argNum,
3525 needCommaBetweenValues, newValue)))
3528 gangOperands, gangOperandsType,
3529 gangArgTypeAttributes, argDim,
3530 needCommaBetweenValues, newValue)))
3532 if (failed(
parseGangValue(parser, LoopOp::getGangStaticKeyword(),
3533 gangOperands, gangOperandsType,
3534 gangArgTypeAttributes, argStatic,
3535 needCommaBetweenValues, newValue)))
3538 if (!newValue && needValue) {
3540 "new value expected after comma");
3548 if (gangOperands.empty())
3551 "expect at least one of num, dim or static values");
3557 if (parser.
parseAttribute(deviceTypeAttributes.emplace_back()) ||
3561 deviceTypeAttributes.push_back(mlir::acc::DeviceTypeAttr::get(
3562 parser.
getContext(), mlir::acc::DeviceType::None));
3565 seg.push_back(gangOperands.size() - crtOperandsSize);
3573 gangArgTypeAttributes.end());
3574 gangArgType = ArrayAttr::get(parser.
getContext(), arrayAttr);
3575 deviceType = ArrayAttr::get(parser.
getContext(), deviceTypeAttributes);
3578 gangOnlyDeviceTypeAttributes.begin(), gangOnlyDeviceTypeAttributes.end());
3579 gangOnlyDeviceType = ArrayAttr::get(parser.
getContext(), gangOnlyAttr);
3587 std::optional<mlir::ArrayAttr> gangArgTypes,
3588 std::optional<mlir::ArrayAttr> deviceTypes,
3589 std::optional<mlir::DenseI32ArrayAttr> segments,
3590 std::optional<mlir::ArrayAttr> gangOnlyDeviceTypes) {
3592 if (operands.begin() == operands.end() &&
3607 llvm::interleaveComma(llvm::enumerate(*deviceTypes), p, [&](
auto it) {
3609 llvm::interleaveComma(
3610 llvm::seq<int32_t>(0, (*segments)[it.index()]), p, [&](
auto it) {
3611 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3612 (*gangArgTypes)[opIdx]);
3613 if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Num)
3614 p << LoopOp::getGangNumKeyword();
3615 else if (gangArgTypeAttr.getValue() == mlir::acc::GangArgType::Dim)
3616 p << LoopOp::getGangDimKeyword();
3617 else if (gangArgTypeAttr.getValue() ==
3618 mlir::acc::GangArgType::Static)
3619 p << LoopOp::getGangStaticKeyword();
3620 p <<
"=" << operands[opIdx] <<
" : " << operands[opIdx].getType();
3631 std::optional<mlir::ArrayAttr> segments,
3632 llvm::SmallSet<mlir::acc::DeviceType, 3> &deviceTypes) {
3635 for (
auto attr : *segments) {
3636 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3637 if (!deviceTypes.insert(deviceTypeAttr.getValue()).second)
3645static std::optional<mlir::acc::DeviceType>
3647 llvm::SmallSet<mlir::acc::DeviceType, 3> crtDeviceTypes;
3649 return std::nullopt;
3650 for (
auto attr : deviceTypes) {
3651 auto deviceTypeAttr =
3652 mlir::dyn_cast_or_null<mlir::acc::DeviceTypeAttr>(attr);
3653 if (!deviceTypeAttr)
3654 return mlir::acc::DeviceType::None;
3655 if (!crtDeviceTypes.insert(deviceTypeAttr.getValue()).second)
3656 return deviceTypeAttr.getValue();
3658 return std::nullopt;
3661LogicalResult acc::LoopOp::verify() {
3662 if (getUpperbound().size() != getStep().size())
3663 return emitError() <<
"number of upperbounds expected to be the same as "
3666 if (getUpperbound().size() != getLowerbound().size())
3667 return emitError() <<
"number of upperbounds expected to be the same as "
3668 "number of lowerbounds";
3670 if (!getUpperbound().empty() && getInclusiveUpperbound() &&
3671 (getUpperbound().size() != getInclusiveUpperbound()->size()))
3672 return emitError() <<
"inclusiveUpperbound size is expected to be the same"
3673 <<
" as upperbound size";
3676 if (getCollapseAttr() && !getCollapseDeviceTypeAttr())
3677 return emitOpError() <<
"collapse device_type attr must be define when"
3678 <<
" collapse attr is present";
3680 if (getCollapseAttr() && getCollapseDeviceTypeAttr() &&
3681 getCollapseAttr().getValue().size() !=
3682 getCollapseDeviceTypeAttr().getValue().size())
3683 return emitOpError() <<
"collapse attribute count must match collapse"
3684 <<
" device_type count";
3685 if (
auto duplicateDeviceType =
checkDeviceTypes(getCollapseDeviceTypeAttr()))
3686 return emitOpError() <<
"duplicate device_type `"
3687 << acc::stringifyDeviceType(*duplicateDeviceType)
3688 <<
"` found in collapseDeviceType attribute";
3691 if (!getGangOperands().empty()) {
3692 if (!getGangOperandsArgType())
3693 return emitOpError() <<
"gangOperandsArgType attribute must be defined"
3694 <<
" when gang operands are present";
3696 if (getGangOperands().size() !=
3697 getGangOperandsArgTypeAttr().getValue().size())
3698 return emitOpError() <<
"gangOperandsArgType attribute count must match"
3699 <<
" gangOperands count";
3701 if (getGangAttr()) {
3703 return emitOpError() <<
"duplicate device_type `"
3704 << acc::stringifyDeviceType(*duplicateDeviceType)
3705 <<
"` found in gang attribute";
3709 *
this, getGangOperands(), getGangOperandsSegmentsAttr(),
3710 getGangOperandsDeviceTypeAttr(),
"gang")))
3715 return emitOpError() <<
"duplicate device_type `"
3716 << acc::stringifyDeviceType(*duplicateDeviceType)
3717 <<
"` found in worker attribute";
3718 if (
auto duplicateDeviceType =
3720 return emitOpError() <<
"duplicate device_type `"
3721 << acc::stringifyDeviceType(*duplicateDeviceType)
3722 <<
"` found in workerNumOperandsDeviceType attribute";
3724 getWorkerNumOperandsDeviceTypeAttr(),
3730 return emitOpError() <<
"duplicate device_type `"
3731 << acc::stringifyDeviceType(*duplicateDeviceType)
3732 <<
"` found in vector attribute";
3733 if (
auto duplicateDeviceType =
3735 return emitOpError() <<
"duplicate device_type `"
3736 << acc::stringifyDeviceType(*duplicateDeviceType)
3737 <<
"` found in vectorOperandsDeviceType attribute";
3739 getVectorOperandsDeviceTypeAttr(),
3744 *
this, getTileOperands(), getTileOperandsSegmentsAttr(),
3745 getTileOperandsDeviceTypeAttr(),
"tile")))
3749 llvm::SmallSet<mlir::acc::DeviceType, 3> deviceTypes;
3753 return emitError() <<
"only one of auto, independent, seq can be present "
3759 auto hasDeviceNone = [](mlir::acc::DeviceTypeAttr attr) ->
bool {
3760 return attr.getValue() == mlir::acc::DeviceType::None;
3762 bool hasDefaultSeq =
3764 ? llvm::any_of(getSeqAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3767 bool hasDefaultIndependent =
3768 getIndependentAttr()
3770 getIndependentAttr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3773 bool hasDefaultAuto =
3775 ? llvm::any_of(getAuto_Attr().getAsRange<mlir::acc::DeviceTypeAttr>(),
3778 if (!hasDefaultSeq && !hasDefaultIndependent && !hasDefaultAuto) {
3780 <<
"at least one of auto, independent, seq must be present";
3785 for (
auto attr : getSeqAttr()) {
3786 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
3787 if (hasVector(deviceTypeAttr.getValue()) ||
3788 getVectorValue(deviceTypeAttr.getValue()) ||
3789 hasWorker(deviceTypeAttr.getValue()) ||
3790 getWorkerValue(deviceTypeAttr.getValue()) ||
3791 hasGang(deviceTypeAttr.getValue()) ||
3792 getGangValue(mlir::acc::GangArgType::Num,
3793 deviceTypeAttr.getValue()) ||
3794 getGangValue(mlir::acc::GangArgType::Dim,
3795 deviceTypeAttr.getValue()) ||
3796 getGangValue(mlir::acc::GangArgType::Static,
3797 deviceTypeAttr.getValue()))
3798 return emitError() <<
"gang, worker or vector cannot appear with seq";
3803 mlir::acc::PrivateRecipeOp>(
3804 *
this, getPrivateOperands(),
"private")))
3808 mlir::acc::FirstprivateRecipeOp>(
3809 *
this, getFirstprivateOperands(),
"firstprivate")))
3813 mlir::acc::ReductionRecipeOp>(
3814 *
this, getReductionOperands(),
"reduction")))
3817 if (getCombined().has_value() &&
3818 (getCombined().value() != acc::CombinedConstructsType::ParallelLoop &&
3819 getCombined().value() != acc::CombinedConstructsType::KernelsLoop &&
3820 getCombined().value() != acc::CombinedConstructsType::SerialLoop)) {
3821 return emitError(
"unexpected combined constructs attribute");
3825 if (getRegion().empty())
3826 return emitError(
"expected non-empty body.");
3828 if (getUnstructured()) {
3829 if (!isContainerLike())
3831 "unstructured acc.loop must not have induction variables");
3832 }
else if (isContainerLike()) {
3836 uint64_t collapseCount = getCollapseValue().value_or(1);
3837 if (getCollapseAttr()) {
3838 for (
auto collapseEntry : getCollapseAttr()) {
3839 auto intAttr = mlir::dyn_cast<IntegerAttr>(collapseEntry);
3840 if (intAttr.getValue().getZExtValue() > collapseCount)
3841 collapseCount = intAttr.getValue().getZExtValue();
3849 bool foundSibling =
false;
3851 if (mlir::isa<mlir::LoopLikeOpInterface>(op)) {
3853 if (op->getParentOfType<mlir::LoopLikeOpInterface>() !=
3855 foundSibling =
true;
3860 expectedParent = op;
3863 if (collapseCount == 0)
3869 return emitError(
"found sibling loops inside container-like acc.loop");
3870 if (collapseCount != 0)
3871 return emitError(
"failed to find enough loop-like operations inside "
3872 "container-like acc.loop");
3878unsigned LoopOp::getNumDataOperands() {
3879 return getReductionOperands().size() + getPrivateOperands().size() +
3880 getFirstprivateOperands().size();
3883Value LoopOp::getDataOperand(
unsigned i) {
3884 unsigned numOptional =
3885 getLowerbound().size() + getUpperbound().size() + getStep().size();
3886 numOptional += getGangOperands().size();
3887 numOptional += getVectorOperands().size();
3888 numOptional += getWorkerNumOperands().size();
3889 numOptional += getTileOperands().size();
3890 numOptional += getCacheOperands().size();
3891 return getOperand(numOptional + i);
3894bool LoopOp::hasAuto() {
return hasAuto(mlir::acc::DeviceType::None); }
3896bool LoopOp::hasAuto(mlir::acc::DeviceType deviceType) {
3900bool LoopOp::hasIndependent() {
3901 return hasIndependent(mlir::acc::DeviceType::None);
3904bool LoopOp::hasIndependent(mlir::acc::DeviceType deviceType) {
3908bool LoopOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
3910bool LoopOp::hasSeq(mlir::acc::DeviceType deviceType) {
3915 return getVectorValue(mlir::acc::DeviceType::None);
3918mlir::Value LoopOp::getVectorValue(mlir::acc::DeviceType deviceType) {
3920 getVectorOperands(), deviceType);
3923bool LoopOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
3925bool LoopOp::hasVector(mlir::acc::DeviceType deviceType) {
3930 return getWorkerValue(mlir::acc::DeviceType::None);
3933mlir::Value LoopOp::getWorkerValue(mlir::acc::DeviceType deviceType) {
3935 getWorkerNumOperands(), deviceType);
3938bool LoopOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
3940bool LoopOp::hasWorker(mlir::acc::DeviceType deviceType) {
3945 return getTileValues(mlir::acc::DeviceType::None);
3949LoopOp::getTileValues(mlir::acc::DeviceType deviceType) {
3951 getTileOperandsSegments(), deviceType);
3954std::optional<int64_t> LoopOp::getCollapseValue() {
3955 return getCollapseValue(mlir::acc::DeviceType::None);
3958std::optional<int64_t>
3959LoopOp::getCollapseValue(mlir::acc::DeviceType deviceType) {
3960 if (!getCollapseAttr())
3961 return std::nullopt;
3962 if (
auto pos =
findSegment(getCollapseDeviceTypeAttr(), deviceType)) {
3964 mlir::dyn_cast<IntegerAttr>(getCollapseAttr().getValue()[*pos]);
3965 return intAttr.getValue().getZExtValue();
3967 return std::nullopt;
3970mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType) {
3971 return getGangValue(gangArgType, mlir::acc::DeviceType::None);
3974mlir::Value LoopOp::getGangValue(mlir::acc::GangArgType gangArgType,
3975 mlir::acc::DeviceType deviceType) {
3976 if (getGangOperands().empty())
3978 if (
auto pos =
findSegment(*getGangOperandsDeviceType(), deviceType)) {
3979 int32_t nbOperandsBefore = 0;
3980 for (
unsigned i = 0; i < *pos; ++i)
3981 nbOperandsBefore += (*getGangOperandsSegments())[i];
3984 .drop_front(nbOperandsBefore)
3985 .take_front((*getGangOperandsSegments())[*pos]);
3987 int32_t argTypeIdx = nbOperandsBefore;
3988 for (
auto value : values) {
3989 auto gangArgTypeAttr = mlir::dyn_cast<mlir::acc::GangArgTypeAttr>(
3990 (*getGangOperandsArgType())[argTypeIdx]);
3991 if (gangArgTypeAttr.getValue() == gangArgType)
3999bool LoopOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
4001bool LoopOp::hasGang(mlir::acc::DeviceType deviceType) {
4006 return {&getRegion()};
4050 if (!regionArgs.empty()) {
4051 p << acc::LoopOp::getControlKeyword() <<
"(";
4052 llvm::interleaveComma(regionArgs, p,
4054 p <<
") = (" << lowerbound <<
" : " << lowerboundType <<
") to ("
4055 << upperbound <<
" : " << upperboundType <<
") " <<
" step (" << steps
4056 <<
" : " << stepType <<
") ";
4063 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
4064 effectiveDeviceTypes));
4067void acc::LoopOp::addIndependent(
4069 setIndependentAttr(addDeviceTypeAffectedOperandHelper(
4070 context, getIndependentAttr(), effectiveDeviceTypes));
4075 setAuto_Attr(addDeviceTypeAffectedOperandHelper(context, getAuto_Attr(),
4076 effectiveDeviceTypes));
4079void acc::LoopOp::setCollapseForDeviceTypes(
4081 llvm::APInt value) {
4085 assert((getCollapseAttr() ==
nullptr) ==
4086 (getCollapseDeviceTypeAttr() ==
nullptr));
4087 assert(value.getBitWidth() == 64);
4089 if (getCollapseAttr()) {
4090 for (
const auto &existing :
4091 llvm::zip_equal(getCollapseAttr(), getCollapseDeviceTypeAttr())) {
4092 newValues.push_back(std::get<0>(existing));
4093 newDeviceTypes.push_back(std::get<1>(existing));
4097 if (effectiveDeviceTypes.empty()) {
4100 newValues.push_back(
4101 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
4102 newDeviceTypes.push_back(
4103 acc::DeviceTypeAttr::get(context, DeviceType::None));
4105 for (DeviceType dt : effectiveDeviceTypes) {
4106 newValues.push_back(
4107 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), value));
4108 newDeviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
4112 setCollapseAttr(ArrayAttr::get(context, newValues));
4113 setCollapseDeviceTypeAttr(ArrayAttr::get(context, newDeviceTypes));
4116void acc::LoopOp::setTileForDeviceTypes(
4120 if (getTileOperandsSegments())
4121 llvm::copy(*getTileOperandsSegments(), std::back_inserter(segments));
4123 setTileOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4124 context, getTileOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4125 getTileOperandsMutable(), segments));
4127 setTileOperandsSegments(segments);
4130void acc::LoopOp::addVectorOperand(
4133 setVectorOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4134 context, getVectorOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4135 newValue, getVectorOperandsMutable()));
4138void acc::LoopOp::addEmptyVector(
4140 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
4141 effectiveDeviceTypes));
4144void acc::LoopOp::addWorkerNumOperand(
4147 setWorkerNumOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4148 context, getWorkerNumOperandsDeviceTypeAttr(), effectiveDeviceTypes,
4149 newValue, getWorkerNumOperandsMutable()));
4152void acc::LoopOp::addEmptyWorker(
4154 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
4155 effectiveDeviceTypes));
4158void acc::LoopOp::addEmptyGang(
4160 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
4161 effectiveDeviceTypes));
4164bool acc::LoopOp::hasParallelismFlag(DeviceType dt) {
4165 auto hasDevice = [=](DeviceTypeAttr attr) ->
bool {
4166 return attr.getValue() == dt;
4168 auto testFromArr = [=](
ArrayAttr arr) ->
bool {
4169 return llvm::any_of(arr.getAsRange<DeviceTypeAttr>(), hasDevice);
4172 if (
ArrayAttr arr = getSeqAttr(); arr && testFromArr(arr))
4174 if (
ArrayAttr arr = getIndependentAttr(); arr && testFromArr(arr))
4176 if (
ArrayAttr arr = getAuto_Attr(); arr && testFromArr(arr))
4182bool acc::LoopOp::hasDefaultGangWorkerVector() {
4183 return hasAnyGangWorkerVector(DeviceType::None);
4186bool acc::LoopOp::hasAnyGangWorkerVector(DeviceType deviceType) {
4187 return hasVector(deviceType) || getVectorValue(deviceType) ||
4188 hasWorker(deviceType) || getWorkerValue(deviceType) ||
4189 hasGang(deviceType) || getGangValue(GangArgType::Num, deviceType) ||
4190 getGangValue(GangArgType::Dim, deviceType) ||
4191 getGangValue(GangArgType::Static, deviceType);
4195acc::LoopOp::getDefaultOrDeviceTypeParallelism(DeviceType deviceType) {
4196 if (hasSeq(deviceType))
4197 return LoopParMode::loop_seq;
4198 if (hasAuto(deviceType))
4199 return LoopParMode::loop_auto;
4200 if (hasIndependent(deviceType))
4201 return LoopParMode::loop_independent;
4203 return LoopParMode::loop_seq;
4205 return LoopParMode::loop_auto;
4206 assert(hasIndependent() &&
4207 "loop must have default auto, seq, or independent");
4208 return LoopParMode::loop_independent;
4211void acc::LoopOp::addGangOperands(
4216 getGangOperandsSegments())
4217 llvm::copy(*existingSegments, std::back_inserter(segments));
4219 unsigned beforeCount = segments.size();
4221 setGangOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4222 context, getGangOperandsDeviceTypeAttr(), effectiveDeviceTypes, values,
4223 getGangOperandsMutable(), segments));
4225 setGangOperandsSegments(segments);
4232 unsigned numAdded = segments.size() - beforeCount;
4236 if (getGangOperandsArgTypeAttr())
4237 llvm::copy(getGangOperandsArgTypeAttr(), std::back_inserter(gangTypes));
4239 for (
auto i : llvm::index_range(0u, numAdded)) {
4240 llvm::transform(argTypes, std::back_inserter(gangTypes),
4241 [=](mlir::acc::GangArgType gangTy) {
4242 return mlir::acc::GangArgTypeAttr::get(context, gangTy);
4247 setGangOperandsArgTypeAttr(mlir::ArrayAttr::get(context, gangTypes));
4251void acc::LoopOp::addPrivatization(
MLIRContext *context,
4252 mlir::acc::PrivateOp op,
4253 mlir::acc::PrivateRecipeOp recipe) {
4254 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4255 getPrivateOperandsMutable().append(op.getResult());
4258void acc::LoopOp::addFirstPrivatization(
4259 MLIRContext *context, mlir::acc::FirstprivateOp op,
4260 mlir::acc::FirstprivateRecipeOp recipe) {
4261 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4262 getFirstprivateOperandsMutable().append(op.getResult());
4265void acc::LoopOp::addReduction(
MLIRContext *context, mlir::acc::ReductionOp op,
4266 mlir::acc::ReductionRecipeOp recipe) {
4267 op.setRecipeAttr(mlir::SymbolRefAttr::get(context, recipe.getSymName()));
4268 getReductionOperandsMutable().append(op.getResult());
4275LogicalResult acc::DataOp::verify() {
4280 return emitError(
"at least one operand or the default attribute "
4281 "must appear on the data operation");
4283 for (
mlir::Value operand : getDataClauseOperands())
4284 if (isa<BlockArgument>(operand) ||
4285 !mlir::isa<acc::AttachOp, acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4286 acc::DeleteOp, acc::DetachOp, acc::DevicePtrOp,
4287 acc::GetDevicePtrOp, acc::NoCreateOp, acc::PresentOp,
4288 acc::MapInfoOp>(operand.getDefiningOp()))
4289 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
4298unsigned DataOp::getNumDataOperands() {
return getDataClauseOperands().size(); }
4300Value DataOp::getDataOperand(
unsigned i) {
4301 unsigned numOptional = getIfCond() ? 1 : 0;
4303 numOptional += getWaitOperands().size();
4304 return getOperand(numOptional + i);
4307bool acc::DataOp::hasAsyncOnly() {
4308 return hasAsyncOnly(mlir::acc::DeviceType::None);
4311bool acc::DataOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
4316 return getAsyncValue(mlir::acc::DeviceType::None);
4319mlir::Value DataOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
4324bool DataOp::hasWaitOnly() {
return hasWaitOnly(mlir::acc::DeviceType::None); }
4326bool DataOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
4331 return getWaitValues(mlir::acc::DeviceType::None);
4335DataOp::getWaitValues(mlir::acc::DeviceType deviceType) {
4337 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
4338 getHasWaitDevnum(), deviceType);
4342 return getWaitDevnum(mlir::acc::DeviceType::None);
4345mlir::Value DataOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
4347 getWaitOperandsSegments(), getHasWaitDevnum(),
4351void acc::DataOp::addAsyncOnly(
4353 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
4354 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
4357void acc::DataOp::addAsyncOperand(
4360 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4361 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
4362 getAsyncOperandsMutable()));
4365void acc::DataOp::addWaitOnly(
MLIRContext *context,
4367 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
4368 effectiveDeviceTypes));
4371void acc::DataOp::addWaitOperands(
4376 if (getWaitOperandsSegments())
4377 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
4379 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
4380 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
4381 getWaitOperandsMutable(), segments));
4382 setWaitOperandsSegments(segments);
4385 if (getHasWaitDevnumAttr())
4386 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
4389 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
4391 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
4398LogicalResult acc::ExitDataOp::verify() {
4402 if (getDataClauseOperands().empty())
4403 return emitError(
"at least one operand must be present in dataOperands on "
4404 "the exit data operation");
4408 if (getAsyncOperand() && getAsync())
4409 return emitError(
"async attribute cannot appear with asyncOperand");
4413 if (!getWaitOperands().empty() && getWait())
4414 return emitError(
"wait attribute cannot appear with waitOperands");
4416 if (getWaitDevnum() && getWaitOperands().empty())
4417 return emitError(
"wait_devnum cannot appear without waitOperands");
4422unsigned ExitDataOp::getNumDataOperands() {
4423 return getDataClauseOperands().size();
4426Value ExitDataOp::getDataOperand(
unsigned i) {
4427 unsigned numOptional = getIfCond() ? 1 : 0;
4428 numOptional += getAsyncOperand() ? 1 : 0;
4429 numOptional += getWaitDevnum() ? 1 : 0;
4430 return getOperand(getWaitOperands().size() + numOptional + i);
4435 results.
add<RemoveConstantIfCondition<ExitDataOp>>(context);
4438void ExitDataOp::addAsyncOnly(
MLIRContext *context,
4440 assert(effectiveDeviceTypes.empty());
4441 assert(!getAsyncAttr());
4442 assert(!getAsyncOperand());
4444 setAsyncAttr(mlir::UnitAttr::get(context));
4447void ExitDataOp::addAsyncOperand(
4450 assert(effectiveDeviceTypes.empty());
4451 assert(!getAsyncAttr());
4452 assert(!getAsyncOperand());
4454 getAsyncOperandMutable().append(newValue);
4459 assert(effectiveDeviceTypes.empty());
4460 assert(!getWaitAttr());
4461 assert(getWaitOperands().empty());
4462 assert(!getWaitDevnum());
4464 setWaitAttr(mlir::UnitAttr::get(context));
4467void ExitDataOp::addWaitOperands(
4470 assert(effectiveDeviceTypes.empty());
4471 assert(!getWaitAttr());
4472 assert(getWaitOperands().empty());
4473 assert(!getWaitDevnum());
4478 getWaitDevnumMutable().append(newValues.front());
4479 newValues = newValues.drop_front();
4482 getWaitOperandsMutable().append(newValues);
4489LogicalResult acc::EnterDataOp::verify() {
4493 if (getDataClauseOperands().empty())
4494 return emitError(
"at least one operand must be present in dataOperands on "
4495 "the enter data operation");
4499 if (getAsyncOperand() && getAsync())
4500 return emitError(
"async attribute cannot appear with asyncOperand");
4504 if (!getWaitOperands().empty() && getWait())
4505 return emitError(
"wait attribute cannot appear with waitOperands");
4507 if (getWaitDevnum() && getWaitOperands().empty())
4508 return emitError(
"wait_devnum cannot appear without waitOperands");
4510 for (
mlir::Value operand : getDataClauseOperands())
4511 if (!mlir::isa<acc::AttachOp, acc::CreateOp, acc::CopyinOp, acc::MapInfoOp>(
4512 operand.getDefiningOp()))
4513 return emitError(
"expect data entry operation as defining op");
4518unsigned EnterDataOp::getNumDataOperands() {
4519 return getDataClauseOperands().size();
4522Value EnterDataOp::getDataOperand(
unsigned i) {
4523 unsigned numOptional = getIfCond() ? 1 : 0;
4524 numOptional += getAsyncOperand() ? 1 : 0;
4525 numOptional += getWaitDevnum() ? 1 : 0;
4526 return getOperand(getWaitOperands().size() + numOptional + i);
4531 results.
add<RemoveConstantIfCondition<EnterDataOp>>(context);
4534void EnterDataOp::addAsyncOnly(
4536 assert(effectiveDeviceTypes.empty());
4537 assert(!getAsyncAttr());
4538 assert(!getAsyncOperand());
4540 setAsyncAttr(mlir::UnitAttr::get(context));
4543void EnterDataOp::addAsyncOperand(
4546 assert(effectiveDeviceTypes.empty());
4547 assert(!getAsyncAttr());
4548 assert(!getAsyncOperand());
4550 getAsyncOperandMutable().append(newValue);
4553void EnterDataOp::addWaitOnly(
MLIRContext *context,
4555 assert(effectiveDeviceTypes.empty());
4556 assert(!getWaitAttr());
4557 assert(getWaitOperands().empty());
4558 assert(!getWaitDevnum());
4560 setWaitAttr(mlir::UnitAttr::get(context));
4563void EnterDataOp::addWaitOperands(
4566 assert(effectiveDeviceTypes.empty());
4567 assert(!getWaitAttr());
4568 assert(getWaitOperands().empty());
4569 assert(!getWaitDevnum());
4574 getWaitDevnumMutable().append(newValues.front());
4575 newValues = newValues.drop_front();
4578 getWaitOperandsMutable().append(newValues);
4585LogicalResult AtomicReadOp::verify() {
return verifyCommon(); }
4591LogicalResult AtomicWriteOp::verify() {
return verifyCommon(); }
4597LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4604 if (
Value writeVal = op.getWriteOpVal()) {
4613LogicalResult AtomicUpdateOp::verify() {
return verifyCommon(); }
4615LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4621AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4622 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4624 return dyn_cast<AtomicReadOp>(getSecondOp());
4627AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4628 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4630 return dyn_cast<AtomicWriteOp>(getSecondOp());
4633AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4634 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4636 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4639LogicalResult AtomicCaptureOp::verifyRegions() {
return verifyRegionsCommon(); }
4645template <
typename Op>
4648 bool requireAtLeastOneOperand =
true) {
4649 if (operands.empty() && requireAtLeastOneOperand)
4652 "at least one operand must appear on the declare operation");
4655 if (isa<BlockArgument>(operand) ||
4656 !mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
4657 acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
4658 acc::DeclareDeviceResidentOp, acc::DeclareLinkOp,
4659 acc::MapInfoOp>(operand.getDefiningOp()))
4661 "expect valid declare data entry operation or acc.getdeviceptr "
4665 assert(var &&
"declare operands can only be data entry operations which "
4669 if (!mlir::isa<acc::MapInfoOp>(operand.getDefiningOp())) {
4670 std::optional<mlir::acc::DataClause> dataClauseOptional{
4672 assert(dataClauseOptional.has_value() &&
4673 "declare operands can only be data entry operations which must "
4675 (
void)dataClauseOptional;
4682LogicalResult acc::DeclareEnterOp::verify() {
4690LogicalResult acc::DeclareExitOp::verify() {
4701LogicalResult acc::DeclareOp::verify() {
4710 acc::DeviceType dtype) {
4711 unsigned parallelism = 0;
4712 parallelism += (op.hasGang(dtype) || op.getGangDimValue(dtype)) ? 1 : 0;
4713 parallelism += op.hasWorker(dtype) ? 1 : 0;
4714 parallelism += op.hasVector(dtype) ? 1 : 0;
4715 parallelism += op.hasSeq(dtype) ? 1 : 0;
4719LogicalResult acc::RoutineOp::verify() {
4720 unsigned baseParallelism =
4723 if (baseParallelism > 1)
4724 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4725 "be present at the same time";
4727 for (uint32_t dtypeInt = 0; dtypeInt != acc::getMaxEnumValForDeviceType();
4729 auto dtype =
static_cast<acc::DeviceType
>(dtypeInt);
4730 if (dtype == acc::DeviceType::None)
4734 if (parallelism > 1 || (baseParallelism == 1 && parallelism == 1))
4735 return emitError() <<
"only one of `gang`, `worker`, `vector`, `seq` can "
4736 "be present at the same time for device_type `"
4737 << acc::stringifyDeviceType(dtype) <<
"`";
4744 mlir::ArrayAttr &bindIdName,
4745 mlir::ArrayAttr &bindStrName,
4746 mlir::ArrayAttr &deviceIdTypes,
4747 mlir::ArrayAttr &deviceStrTypes) {
4754 llvm::SMLoc attrLoc = parser.getCurrentLocation();
4755 mlir::Attribute newAttr;
4756 bool isSymbolRefAttr;
4757 if (parser.parseAttribute(newAttr))
4759 if (auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(newAttr)) {
4760 bindIdNameAttrs.push_back(symbolRefAttr);
4761 isSymbolRefAttr = true;
4762 }
else if (
auto stringAttr = dyn_cast<mlir::StringAttr>(newAttr)) {
4763 bindStrNameAttrs.push_back(stringAttr);
4764 isSymbolRefAttr =
false;
4767 "expected symbol reference or string attribute");
4771 if (isSymbolRefAttr) {
4772 deviceIdTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4773 parser.getContext(), mlir::acc::DeviceType::None));
4775 deviceStrTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4776 parser.getContext(), mlir::acc::DeviceType::None));
4779 if (isSymbolRefAttr) {
4780 if (parser.parseAttribute(deviceIdTypeAttrs.emplace_back()) ||
4781 parser.parseRSquare())
4784 if (parser.parseAttribute(deviceStrTypeAttrs.emplace_back()) ||
4785 parser.parseRSquare())
4793 bindIdName = ArrayAttr::get(parser.getContext(), bindIdNameAttrs);
4794 bindStrName = ArrayAttr::get(parser.getContext(), bindStrNameAttrs);
4795 deviceIdTypes = ArrayAttr::get(parser.getContext(), deviceIdTypeAttrs);
4796 deviceStrTypes = ArrayAttr::get(parser.getContext(), deviceStrTypeAttrs);
4802 std::optional<mlir::ArrayAttr> bindIdName,
4803 std::optional<mlir::ArrayAttr> bindStrName,
4804 std::optional<mlir::ArrayAttr> deviceIdTypes,
4805 std::optional<mlir::ArrayAttr> deviceStrTypes) {
4812 allBindNames.append(bindIdName->begin(), bindIdName->end());
4813 allDeviceTypes.append(deviceIdTypes->begin(), deviceIdTypes->end());
4818 allBindNames.append(bindStrName->begin(), bindStrName->end());
4819 allDeviceTypes.append(deviceStrTypes->begin(), deviceStrTypes->end());
4823 if (!allBindNames.empty())
4824 llvm::interleaveComma(llvm::zip(allBindNames, allDeviceTypes), p,
4825 [&](
const auto &pair) {
4826 p << std::get<0>(pair);
4832 mlir::ArrayAttr &gang,
4833 mlir::ArrayAttr &gangDim,
4834 mlir::ArrayAttr &gangDimDeviceTypes) {
4837 gangDimDeviceTypeAttrs;
4838 bool needCommaBeforeOperands =
false;
4842 gangAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4843 parser.
getContext(), mlir::acc::DeviceType::None));
4844 gang = ArrayAttr::get(parser.
getContext(), gangAttrs);
4851 if (parser.parseAttribute(gangAttrs.emplace_back()))
4858 needCommaBeforeOperands =
true;
4861 if (needCommaBeforeOperands && failed(parser.
parseComma()))
4865 if (parser.parseKeyword(acc::RoutineOp::getGangDimKeyword()) ||
4866 parser.parseColon() ||
4867 parser.parseAttribute(gangDimAttrs.emplace_back()))
4869 if (succeeded(parser.parseOptionalLSquare())) {
4870 if (parser.parseAttribute(gangDimDeviceTypeAttrs.emplace_back()) ||
4871 parser.parseRSquare())
4874 gangDimDeviceTypeAttrs.push_back(mlir::acc::DeviceTypeAttr::get(
4875 parser.getContext(), mlir::acc::DeviceType::None));
4881 if (
failed(parser.parseRParen()))
4884 gang = ArrayAttr::get(parser.getContext(), gangAttrs);
4885 gangDim = ArrayAttr::get(parser.getContext(), gangDimAttrs);
4886 gangDimDeviceTypes =
4887 ArrayAttr::get(parser.getContext(), gangDimDeviceTypeAttrs);
4893 std::optional<mlir::ArrayAttr> gang,
4894 std::optional<mlir::ArrayAttr> gangDim,
4895 std::optional<mlir::ArrayAttr> gangDimDeviceTypes) {
4898 gang->size() == 1) {
4899 auto deviceTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*gang)[0]);
4900 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4912 llvm::interleaveComma(llvm::zip(*gangDim, *gangDimDeviceTypes), p,
4913 [&](
const auto &pair) {
4914 p << acc::RoutineOp::getGangDimKeyword() <<
": ";
4915 p << std::get<0>(pair);
4923 mlir::ArrayAttr &deviceTypes) {
4927 attributes.push_back(mlir::acc::DeviceTypeAttr::get(
4928 parser.
getContext(), mlir::acc::DeviceType::None));
4929 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4936 if (parser.parseAttribute(attributes.emplace_back()))
4944 deviceTypes = ArrayAttr::get(parser.
getContext(), attributes);
4950 std::optional<mlir::ArrayAttr> deviceTypes) {
4953 auto deviceTypeAttr =
4954 mlir::dyn_cast<mlir::acc::DeviceTypeAttr>((*deviceTypes)[0]);
4955 if (deviceTypeAttr.getValue() == mlir::acc::DeviceType::None)
4964 auto dTypeAttr = mlir::dyn_cast<mlir::acc::DeviceTypeAttr>(attr);
4970bool RoutineOp::hasWorker() {
return hasWorker(mlir::acc::DeviceType::None); }
4972bool RoutineOp::hasWorker(mlir::acc::DeviceType deviceType) {
4976bool RoutineOp::hasVector() {
return hasVector(mlir::acc::DeviceType::None); }
4978bool RoutineOp::hasVector(mlir::acc::DeviceType deviceType) {
4982bool RoutineOp::hasSeq() {
return hasSeq(mlir::acc::DeviceType::None); }
4984bool RoutineOp::hasSeq(mlir::acc::DeviceType deviceType) {
4988std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4989RoutineOp::getBindNameValue() {
4990 return getBindNameValue(mlir::acc::DeviceType::None);
4993std::optional<std::variant<mlir::SymbolRefAttr, mlir::StringAttr>>
4994RoutineOp::getBindNameValue(mlir::acc::DeviceType deviceType) {
4996 if (
auto pos =
findSegment(*getBindIdNameDeviceType(), deviceType)) {
4997 auto attr = (*getBindIdName())[*pos];
4998 auto symbolRefAttr = dyn_cast<mlir::SymbolRefAttr>(attr);
4999 assert(symbolRefAttr &&
"expected SymbolRef");
5000 return symbolRefAttr;
5005 if (
auto pos =
findSegment(*getBindStrNameDeviceType(), deviceType)) {
5006 auto attr = (*getBindStrName())[*pos];
5007 auto stringAttr = dyn_cast<mlir::StringAttr>(attr);
5008 assert(stringAttr &&
"expected String");
5013 return std::nullopt;
5016bool RoutineOp::hasGang() {
return hasGang(mlir::acc::DeviceType::None); }
5018bool RoutineOp::hasGang(mlir::acc::DeviceType deviceType) {
5022std::optional<int64_t> RoutineOp::getGangDimValue() {
5023 return getGangDimValue(mlir::acc::DeviceType::None);
5026std::optional<int64_t>
5027RoutineOp::getGangDimValue(mlir::acc::DeviceType deviceType) {
5029 return std::nullopt;
5030 if (
auto pos =
findSegment(*getGangDimDeviceType(), deviceType)) {
5031 auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>((*getGangDim())[*pos]);
5032 return intAttr.getInt();
5034 return std::nullopt;
5039 setSeqAttr(addDeviceTypeAffectedOperandHelper(context, getSeqAttr(),
5040 effectiveDeviceTypes));
5045 setVectorAttr(addDeviceTypeAffectedOperandHelper(context, getVectorAttr(),
5046 effectiveDeviceTypes));
5051 setWorkerAttr(addDeviceTypeAffectedOperandHelper(context, getWorkerAttr(),
5052 effectiveDeviceTypes));
5057 setGangAttr(addDeviceTypeAffectedOperandHelper(context, getGangAttr(),
5058 effectiveDeviceTypes));
5067 if (getGangDimAttr())
5068 llvm::copy(getGangDimAttr(), std::back_inserter(dimValues));
5069 if (getGangDimDeviceTypeAttr())
5070 llvm::copy(getGangDimDeviceTypeAttr(), std::back_inserter(deviceTypes));
5072 assert(dimValues.size() == deviceTypes.size());
5074 if (effectiveDeviceTypes.empty()) {
5075 dimValues.push_back(
5076 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
5077 deviceTypes.push_back(
5078 acc::DeviceTypeAttr::get(context, acc::DeviceType::None));
5080 for (DeviceType dt : effectiveDeviceTypes) {
5081 dimValues.push_back(
5082 mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64), val));
5083 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, dt));
5086 assert(dimValues.size() == deviceTypes.size());
5088 setGangDimAttr(mlir::ArrayAttr::get(context, dimValues));
5089 setGangDimDeviceTypeAttr(mlir::ArrayAttr::get(context, deviceTypes));
5092void RoutineOp::addBindStrName(
MLIRContext *context,
5094 mlir::StringAttr val) {
5095 unsigned before = getBindStrNameDeviceTypeAttr()
5096 ? getBindStrNameDeviceTypeAttr().size()
5099 setBindStrNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5100 context, getBindStrNameDeviceTypeAttr(), effectiveDeviceTypes));
5101 unsigned after = getBindStrNameDeviceTypeAttr().size();
5104 if (getBindStrNameAttr())
5105 llvm::copy(getBindStrNameAttr(), std::back_inserter(vals));
5106 for (
unsigned i = 0; i < after - before; ++i)
5107 vals.push_back(val);
5109 setBindStrNameAttr(mlir::ArrayAttr::get(context, vals));
5112void RoutineOp::addBindIDName(
MLIRContext *context,
5114 mlir::SymbolRefAttr val) {
5116 getBindIdNameDeviceTypeAttr() ? getBindIdNameDeviceTypeAttr().size() : 0;
5118 setBindIdNameDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5119 context, getBindIdNameDeviceTypeAttr(), effectiveDeviceTypes));
5120 unsigned after = getBindIdNameDeviceTypeAttr().size();
5123 if (getBindIdNameAttr())
5124 llvm::copy(getBindIdNameAttr(), std::back_inserter(vals));
5125 for (
unsigned i = 0; i < after - before; ++i)
5126 vals.push_back(val);
5128 setBindIdNameAttr(mlir::ArrayAttr::get(context, vals));
5135LogicalResult acc::InitOp::verify() {
5136 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5137 return emitOpError(
"cannot be nested in a compute operation");
5141void acc::InitOp::addDeviceType(
MLIRContext *context,
5142 mlir::acc::DeviceType deviceType) {
5144 if (getDeviceTypesAttr())
5145 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5147 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5148 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5155LogicalResult acc::ShutdownOp::verify() {
5156 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5157 return emitOpError(
"cannot be nested in a compute operation");
5161void acc::ShutdownOp::addDeviceType(
MLIRContext *context,
5162 mlir::acc::DeviceType deviceType) {
5164 if (getDeviceTypesAttr())
5165 llvm::copy(getDeviceTypesAttr(), std::back_inserter(deviceTypes));
5167 deviceTypes.push_back(acc::DeviceTypeAttr::get(context, deviceType));
5168 setDeviceTypesAttr(mlir::ArrayAttr::get(context, deviceTypes));
5175LogicalResult acc::SetOp::verify() {
5176 if (getOperation()->getParentOfType<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>())
5177 return emitOpError(
"cannot be nested in a compute operation");
5178 if (!getDeviceTypeAttr() && !getDefaultAsync() && !getDeviceNum())
5179 return emitOpError(
"at least one default_async, device_num, or device_type "
5180 "operand must appear");
5188LogicalResult acc::UpdateOp::verify() {
5190 if (getDataClauseOperands().empty())
5191 return emitError(
"at least one value must be present in dataOperands");
5194 getAsyncOperandsDeviceTypeAttr(),
5199 *
this, getWaitOperands(), getWaitOperandsSegmentsAttr(),
5200 getWaitOperandsDeviceTypeAttr(),
"wait")))
5206 for (
mlir::Value operand : getDataClauseOperands())
5207 if (!mlir::isa<acc::UpdateDeviceOp, acc::UpdateHostOp, acc::GetDevicePtrOp,
5208 acc::MapInfoOp>(operand.getDefiningOp()))
5209 return emitError(
"expect data entry/exit operation or acc.getdeviceptr "
5215unsigned UpdateOp::getNumDataOperands() {
5216 return getDataClauseOperands().size();
5219Value UpdateOp::getDataOperand(
unsigned i) {
5221 numOptional += getIfCond() ? 1 : 0;
5222 return getOperand(getWaitOperands().size() + numOptional + i);
5227 results.
add<RemoveConstantIfCondition<UpdateOp>>(context);
5230bool UpdateOp::hasAsyncOnly() {
5231 return hasAsyncOnly(mlir::acc::DeviceType::None);
5234bool UpdateOp::hasAsyncOnly(mlir::acc::DeviceType deviceType) {
5239 return getAsyncValue(mlir::acc::DeviceType::None);
5242mlir::Value UpdateOp::getAsyncValue(mlir::acc::DeviceType deviceType) {
5252bool UpdateOp::hasWaitOnly() {
5253 return hasWaitOnly(mlir::acc::DeviceType::None);
5256bool UpdateOp::hasWaitOnly(mlir::acc::DeviceType deviceType) {
5261 return getWaitValues(mlir::acc::DeviceType::None);
5265UpdateOp::getWaitValues(mlir::acc::DeviceType deviceType) {
5267 getWaitOperandsDeviceType(), getWaitOperands(), getWaitOperandsSegments(),
5268 getHasWaitDevnum(), deviceType);
5272 return getWaitDevnum(mlir::acc::DeviceType::None);
5275mlir::Value UpdateOp::getWaitDevnum(mlir::acc::DeviceType deviceType) {
5277 getWaitOperandsSegments(), getHasWaitDevnum(),
5283 setAsyncOnlyAttr(addDeviceTypeAffectedOperandHelper(
5284 context, getAsyncOnlyAttr(), effectiveDeviceTypes));
5287void UpdateOp::addAsyncOperand(
5290 setAsyncOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5291 context, getAsyncOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValue,
5292 getAsyncOperandsMutable()));
5297 setWaitOnlyAttr(addDeviceTypeAffectedOperandHelper(context, getWaitOnlyAttr(),
5298 effectiveDeviceTypes));
5301void UpdateOp::addWaitOperands(
5306 if (getWaitOperandsSegments())
5307 llvm::copy(*getWaitOperandsSegments(), std::back_inserter(segments));
5309 setWaitOperandsDeviceTypeAttr(addDeviceTypeAffectedOperandHelper(
5310 context, getWaitOperandsDeviceTypeAttr(), effectiveDeviceTypes, newValues,
5311 getWaitOperandsMutable(), segments));
5312 setWaitOperandsSegments(segments);
5315 if (getHasWaitDevnumAttr())
5316 llvm::copy(getHasWaitDevnumAttr(), std::back_inserter(hasDevnums));
5319 std::max(effectiveDeviceTypes.size(),
static_cast<size_t>(1)),
5321 setHasWaitDevnumAttr(mlir::ArrayAttr::get(context, hasDevnums));
5328LogicalResult acc::WaitOp::verify() {
5331 if (getAsyncOperand() && getAsync())
5332 return emitError(
"async attribute cannot appear with asyncOperand");
5334 if (getWaitDevnum() && getWaitOperands().empty())
5335 return emitError(
"wait_devnum cannot appear without waitOperands");
5340#define GET_OP_CLASSES
5341#include "mlir/Dialect/OpenACC/OpenACCOps.cpp.inc"
5343#define GET_ATTRDEF_CLASSES
5344#include "mlir/Dialect/OpenACC/OpenACCOpsAttributes.cpp.inc"
5346#define GET_TYPEDEF_CLASSES
5347#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
5358 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5359 [&](
auto entry) {
return entry.getVarPtr(); })
5360 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5361 [&](
auto exit) {
return exit.getVarPtr(); })
5371 [&](
auto entry) {
return entry.getVar(); })
5379 [&](
auto entry) {
return entry.getVarType(); })
5380 .Case<mlir::acc::CopyoutOp, mlir::acc::UpdateHostOp>(
5381 [&](
auto exit) {
return exit.getVarType(); })
5392 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5393 [&](
auto dataClause) {
return dataClause.getAccPtr(); })
5404 [&](
auto dataClause) {
return dataClause.getAccVar(); })
5413 [&](
auto dataClause) {
return dataClause.getVarPtrPtr(); })
5423 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS, mlir::acc::MapInfoOp>(
5424 [&](
auto dataClause) {
5426 dataClause.getBounds().begin(),
5427 dataClause.getBounds().end());
5439 .Case<ACC_DATA_ENTRY_OPS, ACC_DATA_EXIT_OPS>([&](
auto dataClause) {
5441 dataClause.getAsyncOperands().begin(),
5442 dataClause.getAsyncOperands().end());
5453 return dataClause.getAsyncOperandsDeviceTypeAttr();
5461 [&](
auto dataClause) {
return dataClause.getAsyncOnlyAttr(); })
5468 .Case<ACC_DATA_ENTRY_OPS, mlir::acc::MapInfoOp>(
5469 [&](
auto entry) {
return entry.getName(); })
5476std::optional<mlir::acc::DataClause>
5481 .Case<ACC_DATA_ENTRY_OPS>(
5482 [&](
auto entry) {
return entry.getDataClause(); })
5490 .Case<mlir::acc::MapInfoOp>([&](
auto mapInfo) {
5491 return bitEnumContainsAny(mapInfo.getMapFlags(),
5492 mlir::acc::MapFlags::implicit);
5501 mlir::acc::KernelEnvironmentOp>(
5502 [&](
auto entry) {
return entry.getDataClauseOperands(); })
5504 return dataOperands;
5512 mlir::acc::KernelEnvironmentOp>(
5513 [&](
auto entry) {
return entry.getDataClauseOperandsMutable(); })
5515 return dataOperands;
5522 [&](
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_ENTRY_OPS
#define ACC_DATA_EXIT_OPS
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
mlir::TypedValue< mlir::acc::PointerLikeType > getAccPtr(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation if it implements PointerLikeType.
std::optional< mlir::acc::DataClause > getDataClause(mlir::Operation *accDataEntryOp)
Used to obtain the dataClause from a data entry operation.
mlir::MutableOperandRange getMutableDataOperands(mlir::Operation *accOp)
Used to get a mutable range iterating over the data operands.
mlir::SmallVector< mlir::Value > getBounds(mlir::Operation *accDataClauseOp)
Used to obtain bounds from an acc data clause operation.
std::optional< ClauseDefaultValue > getDefaultAttr(mlir::Operation *op)
Looks for an OpenACC default attribute on the current operation op or in a parent operation which enc...
mlir::ValueRange getDataOperands(mlir::Operation *accOp)
Used to get an immutable range iterating over the data operands.
std::optional< llvm::StringRef > getVarName(mlir::Operation *accOp)
Used to obtain the name from an acc operation.
bool 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.