25 #include "llvm/ADT/ArrayRef.h"
26 #include "llvm/ADT/BitVector.h"
27 #include "llvm/ADT/STLExtras.h"
28 #include "llvm/ADT/STLForwardCompat.h"
29 #include "llvm/ADT/SmallString.h"
30 #include "llvm/ADT/StringExtras.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/ADT/TypeSwitch.h"
33 #include "llvm/Frontend/OpenMP/OMPConstants.h"
34 #include "llvm/Frontend/OpenMP/OMPDeviceConstants.h"
40 #include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc"
41 #include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
42 #include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.cpp.inc"
43 #include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.cpp.inc"
59 struct MemRefPointerLikeModel
60 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
63 return llvm::cast<MemRefType>(pointer).getElementType();
67 struct LLVMPointerPointerLikeModel
68 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
69 LLVM::LLVMPointerType> {
74 void OpenMPDialect::initialize() {
77 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
80 #define GET_ATTRDEF_LIST
81 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
84 #define GET_TYPEDEF_LIST
85 #include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
88 declarePromisedInterface<ConvertToLLVMPatternInterface, OpenMPDialect>();
90 MemRefType::attachInterface<MemRefPointerLikeModel>(*
getContext());
91 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
96 mlir::ModuleOp::attachInterface<mlir::omp::OffloadModuleDefaultModel>(
102 mlir::LLVM::GlobalOp::attachInterface<
105 mlir::LLVM::LLVMFuncOp::attachInterface<
108 mlir::func::FuncOp::attachInterface<
134 allocatorVars.push_back(operand);
135 allocatorTypes.push_back(type);
141 allocateVars.push_back(operand);
142 allocateTypes.push_back(type);
153 for (
unsigned i = 0; i < allocateVars.size(); ++i) {
154 std::string separator = i == allocateVars.size() - 1 ?
"" :
", ";
155 p << allocatorVars[i] <<
" : " << allocatorTypes[i] <<
" -> ";
156 p << allocateVars[i] <<
" : " << allocateTypes[i] << separator;
164 template <
typename ClauseAttr>
166 using ClauseT = decltype(std::declval<ClauseAttr>().getValue());
171 if (std::optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
175 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
178 template <
typename ClauseAttr>
180 p << stringifyEnum(attr.getValue());
203 linearVars.push_back(var);
204 linearTypes.push_back(type);
205 linearStepVars.push_back(stepVar);
214 size_t linearVarsSize = linearVars.size();
215 for (
unsigned i = 0; i < linearVarsSize; ++i) {
216 std::string separator = i == linearVarsSize - 1 ?
"" :
", ";
218 if (linearStepVars.size() > i)
219 p <<
" = " << linearStepVars[i];
220 p <<
" : " << linearVars[i].getType() << separator;
233 for (
const auto &it : nontemporalVars)
234 if (!nontemporalItems.insert(it).second)
235 return op->
emitOpError() <<
"nontemporal variable used more than once";
244 std::optional<ArrayAttr> alignments,
247 if (!alignedVars.empty()) {
248 if (!alignments || alignments->size() != alignedVars.size())
250 <<
"expected as many alignment values as aligned variables";
253 return op->
emitOpError() <<
"unexpected alignment values attribute";
259 for (
auto it : alignedVars)
260 if (!alignedItems.insert(it).second)
261 return op->
emitOpError() <<
"aligned variable used more than once";
267 for (
unsigned i = 0; i < (*alignments).size(); ++i) {
268 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>((*alignments)[i])) {
269 if (intAttr.getValue().sle(0))
270 return op->
emitOpError() <<
"alignment should be greater than 0";
272 return op->
emitOpError() <<
"expected integer alignment";
286 ArrayAttr &alignmentsAttr) {
289 if (parser.parseOperand(alignedVars.emplace_back()) ||
290 parser.parseColonType(alignedTypes.emplace_back()) ||
291 parser.parseArrow() ||
292 parser.parseAttribute(alignmentVec.emplace_back())) {
306 std::optional<ArrayAttr> alignments) {
307 for (
unsigned i = 0; i < alignedVars.size(); ++i) {
310 p << alignedVars[i] <<
" : " << alignedVars[i].
getType();
311 p <<
" -> " << (*alignments)[i];
322 if (modifiers.size() > 2)
324 for (
const auto &mod : modifiers) {
327 auto symbol = symbolizeScheduleModifier(mod);
330 <<
" unknown modifier type: " << mod;
335 if (modifiers.size() == 1) {
336 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
337 modifiers.push_back(modifiers[0]);
338 modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
340 }
else if (modifiers.size() == 2) {
343 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
344 symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
346 <<
" incorrect modifier order";
362 ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd,
363 std::optional<OpAsmParser::UnresolvedOperand> &chunkSize,
368 std::optional<mlir::omp::ClauseScheduleKind> schedule =
369 symbolizeClauseScheduleKind(keyword);
375 case ClauseScheduleKind::Static:
376 case ClauseScheduleKind::Dynamic:
377 case ClauseScheduleKind::Guided:
383 chunkSize = std::nullopt;
386 case ClauseScheduleKind::Auto:
388 chunkSize = std::nullopt;
397 modifiers.push_back(mod);
403 if (!modifiers.empty()) {
405 if (std::optional<ScheduleModifier> mod =
406 symbolizeScheduleModifier(modifiers[0])) {
409 return parser.
emitError(loc,
"invalid schedule modifier");
412 if (modifiers.size() > 1) {
413 assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
423 ClauseScheduleKindAttr scheduleKind,
424 ScheduleModifierAttr scheduleMod,
425 UnitAttr scheduleSimd,
Value scheduleChunk,
426 Type scheduleChunkType) {
427 p << stringifyClauseScheduleKind(scheduleKind.getValue());
429 p <<
" = " << scheduleChunk <<
" : " << scheduleChunk.
getType();
431 p <<
", " << stringifyScheduleModifier(scheduleMod.getValue());
443 ClauseOrderKindAttr &order,
444 OrderModifierAttr &orderMod) {
449 if (std::optional<OrderModifier> enumValue =
450 symbolizeOrderModifier(enumStr)) {
458 if (std::optional<ClauseOrderKind> enumValue =
459 symbolizeClauseOrderKind(enumStr)) {
463 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
467 ClauseOrderKindAttr order,
468 OrderModifierAttr orderMod) {
470 p << stringifyOrderModifier(orderMod.getValue()) <<
":";
472 p << stringifyClauseOrderKind(order.getValue());
475 template <
typename ClauseTypeAttr,
typename ClauseType>
478 std::optional<OpAsmParser::UnresolvedOperand> &operand,
480 std::optional<ClauseType> (*symbolizeClause)(StringRef),
481 StringRef clauseName) {
484 if (std::optional<ClauseType> enumValue = symbolizeClause(enumStr)) {
490 <<
"invalid " << clauseName <<
" modifier : '" << enumStr <<
"'";
500 <<
"expected " << clauseName <<
" operand";
503 if (operand.has_value()) {
511 template <
typename ClauseTypeAttr,
typename ClauseType>
514 ClauseTypeAttr prescriptiveness,
Value operand,
516 StringRef (*stringifyClauseType)(ClauseType)) {
518 if (prescriptiveness)
519 p << stringifyClauseType(prescriptiveness.getValue()) <<
", ";
522 p << operand <<
": " << operandType;
532 std::optional<OpAsmParser::UnresolvedOperand> &grainsize,
533 Type &grainsizeType) {
534 return parseGranularityClause<ClauseGrainsizeTypeAttr, ClauseGrainsizeType>(
535 parser, grainsizeMod, grainsize, grainsizeType,
536 &symbolizeClauseGrainsizeType,
"grainsize");
540 ClauseGrainsizeTypeAttr grainsizeMod,
542 printGranularityClause<ClauseGrainsizeTypeAttr, ClauseGrainsizeType>(
543 p, op, grainsizeMod, grainsize, grainsizeType,
544 &stringifyClauseGrainsizeType);
554 std::optional<OpAsmParser::UnresolvedOperand> &numTasks,
555 Type &numTasksType) {
556 return parseGranularityClause<ClauseNumTasksTypeAttr, ClauseNumTasksType>(
557 parser, numTasksMod, numTasks, numTasksType, &symbolizeClauseNumTasksType,
562 ClauseNumTasksTypeAttr numTasksMod,
564 printGranularityClause<ClauseNumTasksTypeAttr, ClauseNumTasksType>(
565 p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
573 struct MapParseArgs {
578 : vars(vars), types(types) {}
580 struct PrivateParseArgs {
588 : vars(vars), types(types), syms(syms), mapIndices(mapIndices) {}
591 struct ReductionParseArgs {
596 ReductionModifierAttr *modifier;
599 ArrayAttr &syms, ReductionModifierAttr *mod =
nullptr)
600 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
603 struct AllRegionParseArgs {
604 std::optional<MapParseArgs> hasDeviceAddrArgs;
605 std::optional<MapParseArgs> hostEvalArgs;
606 std::optional<ReductionParseArgs> inReductionArgs;
607 std::optional<MapParseArgs> mapArgs;
608 std::optional<PrivateParseArgs> privateArgs;
609 std::optional<ReductionParseArgs> reductionArgs;
610 std::optional<ReductionParseArgs> taskReductionArgs;
611 std::optional<MapParseArgs> useDeviceAddrArgs;
612 std::optional<MapParseArgs> useDevicePtrArgs;
623 ReductionModifierAttr *modifier =
nullptr) {
627 unsigned regionArgOffset = regionPrivateArgs.size();
637 std::optional<ReductionModifier> enumValue =
638 symbolizeReductionModifier(enumStr);
639 if (!enumValue.has_value())
648 isByRefVec.push_back(
649 parser.parseOptionalKeyword(
"byref").succeeded());
651 if (symbols && parser.parseAttribute(symbolVec.emplace_back()))
654 if (parser.parseOperand(operands.emplace_back()) ||
655 parser.parseArrow() ||
656 parser.parseArgument(regionPrivateArgs.emplace_back()))
660 if (parser.parseOptionalLSquare().succeeded()) {
661 if (parser.parseKeyword(
"map_idx") || parser.parseEqual() ||
662 parser.parseInteger(mapIndicesVec.emplace_back()) ||
663 parser.parseRSquare())
666 mapIndicesVec.push_back(-1);
678 if (parser.parseType(types.emplace_back()))
685 if (operands.size() != types.size())
691 auto *argsBegin = regionPrivateArgs.begin();
693 argsBegin + regionArgOffset + types.size());
694 for (
auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
703 if (!mapIndicesVec.empty())
716 StringRef keyword, std::optional<MapParseArgs> mapArgs) {
731 StringRef keyword, std::optional<PrivateParseArgs> privateArgs) {
737 parser, privateArgs->vars, privateArgs->types, entryBlockArgs,
738 &privateArgs->syms, privateArgs->mapIndices)))
747 StringRef keyword, std::optional<ReductionParseArgs> reductionArgs) {
752 parser, reductionArgs->vars, reductionArgs->types, entryBlockArgs,
753 &reductionArgs->syms,
nullptr, &reductionArgs->byref,
754 reductionArgs->modifier)))
761 AllRegionParseArgs args) {
765 args.hasDeviceAddrArgs)))
767 <<
"invalid `has_device_addr` format";
772 <<
"invalid `host_eval` format";
775 args.inReductionArgs)))
777 <<
"invalid `in_reduction` format";
782 <<
"invalid `map_entries` format";
787 <<
"invalid `private` format";
790 args.reductionArgs)))
792 <<
"invalid `reduction` format";
795 args.taskReductionArgs)))
797 <<
"invalid `task_reduction` format";
800 args.useDeviceAddrArgs)))
802 <<
"invalid `use_device_addr` format";
805 args.useDevicePtrArgs)))
807 <<
"invalid `use_device_addr` format";
828 AllRegionParseArgs args;
829 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
830 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
831 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
832 inReductionByref, inReductionSyms);
833 args.mapArgs.emplace(mapVars, mapTypes);
834 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
846 AllRegionParseArgs args;
847 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
848 inReductionByref, inReductionSyms);
849 args.privateArgs.emplace(privateVars, privateTypes, privateSyms);
860 ReductionModifierAttr &reductionMod,
863 ArrayAttr &reductionSyms) {
864 AllRegionParseArgs args;
865 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
866 inReductionByref, inReductionSyms);
867 args.privateArgs.emplace(privateVars, privateTypes, privateSyms);
868 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
869 reductionSyms, &reductionMod);
877 AllRegionParseArgs args;
878 args.privateArgs.emplace(privateVars, privateTypes, privateSyms);
886 ReductionModifierAttr &reductionMod,
889 ArrayAttr &reductionSyms) {
890 AllRegionParseArgs args;
891 args.privateArgs.emplace(privateVars, privateTypes, privateSyms);
892 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
893 reductionSyms, &reductionMod);
902 AllRegionParseArgs args;
903 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
904 taskReductionByref, taskReductionSyms);
914 AllRegionParseArgs args;
915 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
916 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
925 struct MapPrintArgs {
930 struct PrivatePrintArgs {
937 : vars(vars), types(types), syms(syms), mapIndices(mapIndices) {}
939 struct ReductionPrintArgs {
944 ReductionModifierAttr modifier;
946 ArrayAttr syms, ReductionModifierAttr mod =
nullptr)
947 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
949 struct AllRegionPrintArgs {
950 std::optional<MapPrintArgs> hasDeviceAddrArgs;
951 std::optional<MapPrintArgs> hostEvalArgs;
952 std::optional<ReductionPrintArgs> inReductionArgs;
953 std::optional<MapPrintArgs> mapArgs;
954 std::optional<PrivatePrintArgs> privateArgs;
955 std::optional<ReductionPrintArgs> reductionArgs;
956 std::optional<ReductionPrintArgs> taskReductionArgs;
957 std::optional<MapPrintArgs> useDeviceAddrArgs;
958 std::optional<MapPrintArgs> useDevicePtrArgs;
967 ReductionModifierAttr modifier =
nullptr) {
968 if (argsSubrange.empty())
971 p << clauseName <<
"(";
974 p <<
"mod: " << stringifyReductionModifier(modifier.getValue()) <<
", ";
991 llvm::interleaveComma(llvm::zip_equal(operands, argsSubrange, symbols,
992 mapIndices.asArrayRef(),
995 auto [op, arg, sym, map, isByRef] = t;
1001 p << op <<
" -> " << arg;
1004 p <<
" [map_idx=" << map <<
"]";
1007 llvm::interleaveComma(types, p);
1012 StringRef clauseName,
ValueRange argsSubrange,
1013 std::optional<MapPrintArgs> mapArgs) {
1020 StringRef clauseName,
ValueRange argsSubrange,
1021 std::optional<PrivatePrintArgs> privateArgs) {
1024 privateArgs->vars, privateArgs->types,
1025 privateArgs->syms, privateArgs->mapIndices);
1031 std::optional<ReductionPrintArgs> reductionArgs) {
1034 reductionArgs->vars, reductionArgs->types,
1035 reductionArgs->syms,
nullptr,
1036 reductionArgs->byref, reductionArgs->modifier);
1040 const AllRegionPrintArgs &args) {
1041 auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op);
1045 iface.getHasDeviceAddrBlockArgs(),
1046 args.hasDeviceAddrArgs);
1050 args.inReductionArgs);
1056 args.reductionArgs);
1058 iface.getTaskReductionBlockArgs(),
1059 args.taskReductionArgs);
1061 iface.getUseDeviceAddrBlockArgs(),
1062 args.useDeviceAddrArgs);
1064 iface.getUseDevicePtrBlockArgs(), args.useDevicePtrArgs);
1077 ArrayAttr inReductionSyms,
ValueRange mapVars,
1079 TypeRange privateTypes, ArrayAttr privateSyms,
1081 AllRegionPrintArgs args;
1082 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1083 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1084 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1085 inReductionByref, inReductionSyms);
1086 args.mapArgs.emplace(mapVars, mapTypes);
1087 args.privateArgs.emplace(privateVars, privateTypes, privateSyms, privateMaps);
1095 ArrayAttr privateSyms) {
1096 AllRegionPrintArgs args;
1097 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1098 inReductionByref, inReductionSyms);
1099 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1108 ArrayAttr privateSyms, ReductionModifierAttr reductionMod,
1111 AllRegionPrintArgs args;
1112 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1113 inReductionByref, inReductionSyms);
1114 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1116 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1117 reductionSyms, reductionMod);
1123 ArrayAttr privateSyms) {
1124 AllRegionPrintArgs args;
1125 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1132 TypeRange privateTypes, ArrayAttr privateSyms,
1133 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1135 ArrayAttr reductionSyms) {
1136 AllRegionPrintArgs args;
1137 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1139 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1140 reductionSyms, reductionMod);
1149 ArrayAttr taskReductionSyms) {
1150 AllRegionPrintArgs args;
1151 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1152 taskReductionByref, taskReductionSyms);
1162 AllRegionPrintArgs args;
1163 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1164 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1169 static LogicalResult
1173 if (!reductionVars.empty()) {
1174 if (!reductionSyms || reductionSyms->size() != reductionVars.size())
1176 <<
"expected as many reduction symbol references "
1177 "as reduction variables";
1178 if (reductionByref && reductionByref->size() != reductionVars.size())
1179 return op->
emitError() <<
"expected as many reduction variable by "
1180 "reference attributes as reduction variables";
1183 return op->
emitOpError() <<
"unexpected reduction symbol references";
1190 for (
auto args : llvm::zip(reductionVars, *reductionSyms)) {
1191 Value accum = std::get<0>(args);
1193 if (!accumulators.insert(accum).second)
1194 return op->
emitOpError() <<
"accumulator variable used more than once";
1197 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
1199 SymbolTable::lookupNearestSymbolFrom<DeclareReductionOp>(op, symbolRef);
1201 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1202 <<
" to point to a reduction declaration";
1204 if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
1206 <<
"expected accumulator (" << varType
1207 <<
") to be the same type as reduction declaration ("
1208 << decl.getAccumulatorType() <<
")";
1227 if (parser.parseOperand(copyprivateVars.emplace_back()) ||
1228 parser.parseArrow() ||
1229 parser.parseAttribute(symsVec.emplace_back()) ||
1230 parser.parseColonType(copyprivateTypes.emplace_back()))
1244 std::optional<ArrayAttr> copyprivateSyms) {
1245 if (!copyprivateSyms.has_value())
1247 llvm::interleaveComma(
1248 llvm::zip(copyprivateVars, *copyprivateSyms, copyprivateTypes), p,
1249 [&](
const auto &args) {
1250 p << std::get<0>(args) <<
" -> " << std::get<1>(args) <<
" : "
1251 << std::get<2>(args);
1256 static LogicalResult
1258 std::optional<ArrayAttr> copyprivateSyms) {
1259 size_t copyprivateSymsSize =
1260 copyprivateSyms.has_value() ? copyprivateSyms->size() : 0;
1261 if (copyprivateSymsSize != copyprivateVars.size())
1262 return op->
emitOpError() <<
"inconsistent number of copyprivate vars (= "
1263 << copyprivateVars.size()
1264 <<
") and functions (= " << copyprivateSymsSize
1265 <<
"), both must be equal";
1266 if (!copyprivateSyms.has_value())
1269 for (
auto copyprivateVarAndSym :
1270 llvm::zip(copyprivateVars, *copyprivateSyms)) {
1272 llvm::cast<SymbolRefAttr>(std::get<1>(copyprivateVarAndSym));
1273 std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
1275 if (mlir::func::FuncOp mlirFuncOp =
1276 SymbolTable::lookupNearestSymbolFrom<mlir::func::FuncOp>(op,
1278 funcOp = mlirFuncOp;
1279 else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
1280 SymbolTable::lookupNearestSymbolFrom<mlir::LLVM::LLVMFuncOp>(
1282 funcOp = llvmFuncOp;
1284 auto getNumArguments = [&] {
1285 return std::visit([](
auto &f) {
return f.getNumArguments(); }, *funcOp);
1288 auto getArgumentType = [&](
unsigned i) {
1289 return std::visit([i](
auto &f) {
return f.getArgumentTypes()[i]; },
1294 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1295 <<
" to point to a copy function";
1297 if (getNumArguments() != 2)
1299 <<
"expected copy function " << symbolRef <<
" to have 2 operands";
1301 Type argTy = getArgumentType(0);
1302 if (argTy != getArgumentType(1))
1303 return op->
emitOpError() <<
"expected copy function " << symbolRef
1304 <<
" arguments to have the same type";
1306 Type varType = std::get<0>(copyprivateVarAndSym).getType();
1307 if (argTy != varType)
1309 <<
"expected copy function arguments' type (" << argTy
1310 <<
") to be the same as copyprivate variable's type (" << varType
1331 if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
1332 parser.parseOperand(dependVars.emplace_back()) ||
1333 parser.parseColonType(dependTypes.emplace_back()))
1335 if (std::optional<ClauseTaskDepend> keywordDepend =
1336 (symbolizeClauseTaskDepend(keyword)))
1337 kindsVec.emplace_back(
1338 ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend));
1352 std::optional<ArrayAttr> dependKinds) {
1354 for (
unsigned i = 0, e = dependKinds->size(); i < e; ++i) {
1357 p << stringifyClauseTaskDepend(
1358 llvm::cast<mlir::omp::ClauseTaskDependAttr>((*dependKinds)[i])
1360 <<
" -> " << dependVars[i] <<
" : " << dependTypes[i];
1366 std::optional<ArrayAttr> dependKinds,
1368 if (!dependVars.empty()) {
1369 if (!dependKinds || dependKinds->size() != dependVars.size())
1370 return op->
emitOpError() <<
"expected as many depend values"
1371 " as depend variables";
1373 if (dependKinds && !dependKinds->empty())
1374 return op->
emitOpError() <<
"unexpected depend values";
1390 IntegerAttr &hintAttr) {
1391 StringRef hintKeyword;
1397 auto parseKeyword = [&]() -> ParseResult {
1400 if (hintKeyword ==
"uncontended")
1402 else if (hintKeyword ==
"contended")
1404 else if (hintKeyword ==
"nonspeculative")
1406 else if (hintKeyword ==
"speculative")
1410 << hintKeyword <<
" is not a valid hint";
1421 IntegerAttr hintAttr) {
1422 int64_t hint = hintAttr.getInt();
1430 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
1432 bool uncontended = bitn(hint, 0);
1433 bool contended = bitn(hint, 1);
1434 bool nonspeculative = bitn(hint, 2);
1435 bool speculative = bitn(hint, 3);
1439 hints.push_back(
"uncontended");
1441 hints.push_back(
"contended");
1443 hints.push_back(
"nonspeculative");
1445 hints.push_back(
"speculative");
1447 llvm::interleaveComma(hints, p);
1454 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
1456 bool uncontended = bitn(hint, 0);
1457 bool contended = bitn(hint, 1);
1458 bool nonspeculative = bitn(hint, 2);
1459 bool speculative = bitn(hint, 3);
1461 if (uncontended && contended)
1462 return op->
emitOpError() <<
"the hints omp_sync_hint_uncontended and "
1463 "omp_sync_hint_contended cannot be combined";
1464 if (nonspeculative && speculative)
1465 return op->
emitOpError() <<
"the hints omp_sync_hint_nonspeculative and "
1466 "omp_sync_hint_speculative cannot be combined.";
1476 llvm::omp::OpenMPOffloadMappingFlags flag) {
1477 return value & llvm::to_underlying(flag);
1486 llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
1487 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
1491 auto parseTypeAndMod = [&]() -> ParseResult {
1492 StringRef mapTypeMod;
1496 if (mapTypeMod ==
"always")
1497 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
1499 if (mapTypeMod ==
"implicit")
1500 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
1502 if (mapTypeMod ==
"ompx_hold")
1503 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
1505 if (mapTypeMod ==
"close")
1506 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
1508 if (mapTypeMod ==
"present")
1509 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
1511 if (mapTypeMod ==
"to")
1512 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
1514 if (mapTypeMod ==
"from")
1515 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
1517 if (mapTypeMod ==
"tofrom")
1518 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
1519 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
1521 if (mapTypeMod ==
"delete")
1522 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
1524 if (mapTypeMod ==
"return_param")
1525 mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
1535 llvm::to_underlying(mapTypeBits));
1543 IntegerAttr mapType) {
1544 uint64_t mapTypeBits = mapType.getUInt();
1546 bool emitAllocRelease =
true;
1552 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS))
1553 mapTypeStrs.push_back(
"always");
1555 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
1556 mapTypeStrs.push_back(
"implicit");
1558 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD))
1559 mapTypeStrs.push_back(
"ompx_hold");
1561 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE))
1562 mapTypeStrs.push_back(
"close");
1564 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT))
1565 mapTypeStrs.push_back(
"present");
1571 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
1573 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM);
1575 emitAllocRelease =
false;
1576 mapTypeStrs.push_back(
"tofrom");
1578 emitAllocRelease =
false;
1579 mapTypeStrs.push_back(
"from");
1581 emitAllocRelease =
false;
1582 mapTypeStrs.push_back(
"to");
1585 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE)) {
1586 emitAllocRelease =
false;
1587 mapTypeStrs.push_back(
"delete");
1591 llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM)) {
1592 emitAllocRelease =
false;
1593 mapTypeStrs.push_back(
"return_param");
1595 if (emitAllocRelease)
1596 mapTypeStrs.push_back(
"exit_release_or_enter_alloc");
1598 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
1599 p << mapTypeStrs[i];
1600 if (i + 1 < mapTypeStrs.size()) {
1607 ArrayAttr &membersIdx) {
1610 auto parseIndices = [&]() -> ParseResult {
1615 APInt(64, value,
false)));
1633 if (!memberIdxs.empty())
1640 ArrayAttr membersIdx) {
1644 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
1646 auto memberIdx = cast<ArrayAttr>(v);
1647 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
1648 p << cast<IntegerAttr>(v2).getInt();
1655 VariableCaptureKindAttr mapCaptureType) {
1656 std::string typeCapStr;
1657 llvm::raw_string_ostream typeCap(typeCapStr);
1658 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
1660 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
1661 typeCap <<
"ByCopy";
1662 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
1663 typeCap <<
"VLAType";
1664 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
1670 VariableCaptureKindAttr &mapCaptureType) {
1671 StringRef mapCaptureKey;
1675 if (mapCaptureKey ==
"This")
1677 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
1678 if (mapCaptureKey ==
"ByRef")
1680 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
1681 if (mapCaptureKey ==
"ByCopy")
1683 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
1684 if (mapCaptureKey ==
"VLAType")
1686 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
1695 for (
auto mapOp : mapVars) {
1696 if (!mapOp.getDefiningOp())
1699 if (
auto mapInfoOp =
1700 mlir::dyn_cast<mlir::omp::MapInfoOp>(mapOp.getDefiningOp())) {
1701 uint64_t mapTypeBits = mapInfoOp.getMapType();
1704 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
1706 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM);
1708 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE);
1711 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS);
1713 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
1715 mapTypeBits, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
1717 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
1719 "to, from, tofrom and alloc map types are permitted");
1721 if (isa<TargetEnterDataOp>(op) && (from || del))
1722 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
1724 if (isa<TargetExitDataOp>(op) && to)
1726 "from, release and delete map types are permitted");
1728 if (isa<TargetUpdateOp>(op)) {
1731 "at least one of to or from map types must be "
1732 "specified, other map types are not permitted");
1737 "at least one of to or from map types must be "
1738 "specified, other map types are not permitted");
1741 auto updateVar = mapInfoOp.getVarPtr();
1743 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
1744 (from && updateToVars.contains(updateVar))) {
1747 "either to or from map types can be specified, not both");
1750 if (always || close || implicit) {
1753 "present, mapper and iterator map type modifiers are permitted");
1756 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
1758 }
else if (!isa<DeclareMapperInfoOp>(op)) {
1760 "map argument is not a map entry operation");
1768 std::optional<DenseI64ArrayAttr> privateMapIndices =
1769 targetOp.getPrivateMapsAttr();
1772 if (!privateMapIndices.has_value() || !privateMapIndices.value())
1777 if (privateMapIndices.value().size() !=
1778 static_cast<int64_t
>(privateVars.size()))
1779 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
1780 "`private_maps` attribute mismatch");
1790 StringRef clauseName,
1792 for (
Value var : vars)
1793 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
1795 <<
"'" << clauseName
1796 <<
"' arguments must be defined by 'omp.map.info' ops";
1801 if (getMapperId() &&
1802 !SymbolTable::lookupNearestSymbolFrom<omp::DeclareMapperOp>(
1803 *
this, getMapperIdAttr())) {
1818 const TargetDataOperands &clauses) {
1819 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
1820 clauses.mapVars, clauses.useDeviceAddrVars,
1821 clauses.useDevicePtrVars);
1825 if (getMapVars().empty() && getUseDevicePtrVars().empty() &&
1826 getUseDeviceAddrVars().empty()) {
1828 "At least one of map, use_device_ptr_vars, or "
1829 "use_device_addr_vars operand must be present");
1833 getUseDevicePtrVars())))
1837 getUseDeviceAddrVars())))
1847 void TargetEnterDataOp::build(
1851 TargetEnterDataOp::build(builder, state,
1853 clauses.dependVars, clauses.device, clauses.ifExpr,
1854 clauses.mapVars, clauses.nowait);
1858 LogicalResult verifyDependVars =
1860 return failed(verifyDependVars) ? verifyDependVars
1871 TargetExitDataOp::build(builder, state,
1873 clauses.dependVars, clauses.device, clauses.ifExpr,
1874 clauses.mapVars, clauses.nowait);
1878 LogicalResult verifyDependVars =
1880 return failed(verifyDependVars) ? verifyDependVars
1891 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
1892 clauses.dependVars, clauses.device, clauses.ifExpr,
1893 clauses.mapVars, clauses.nowait);
1897 LogicalResult verifyDependVars =
1899 return failed(verifyDependVars) ? verifyDependVars
1908 const TargetOperands &clauses) {
1912 TargetOp::build(builder, state, {}, {},
1914 clauses.dependVars, clauses.device, clauses.hasDeviceAddrVars,
1915 clauses.hostEvalVars, clauses.ifExpr,
1917 nullptr, clauses.isDevicePtrVars,
1918 clauses.mapVars, clauses.nowait, clauses.privateVars,
1919 makeArrayAttr(ctx, clauses.privateSyms), clauses.threadLimit,
1928 getHasDeviceAddrVars())))
1937 LogicalResult TargetOp::verifyRegions() {
1938 auto teamsOps = getOps<TeamsOp>();
1939 if (std::distance(teamsOps.begin(), teamsOps.end()) > 1)
1940 return emitError(
"target containing multiple 'omp.teams' nested ops");
1943 Operation *capturedOp = getInnermostCapturedOmpOp();
1944 TargetRegionFlags execFlags = getKernelExecFlags(capturedOp);
1945 for (
Value hostEvalArg :
1946 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs()) {
1948 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
1949 if (llvm::is_contained({teamsOp.getNumTeamsLower(),
1950 teamsOp.getNumTeamsUpper(),
1951 teamsOp.getThreadLimit()},
1955 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
1956 "and 'thread_limit' in 'omp.teams'";
1958 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
1959 if (bitEnumContainsAny(execFlags, TargetRegionFlags::spmd) &&
1960 parallelOp->isAncestor(capturedOp) &&
1961 hostEvalArg == parallelOp.getNumThreads())
1964 return emitOpError()
1965 <<
"host_eval argument only legal as 'num_threads' in "
1966 "'omp.parallel' when representing target SPMD";
1968 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
1969 if (bitEnumContainsAny(execFlags, TargetRegionFlags::trip_count) &&
1970 loopNestOp.getOperation() == capturedOp &&
1971 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
1972 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
1973 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
1976 return emitOpError() <<
"host_eval argument only legal as loop bounds "
1977 "and steps in 'omp.loop_nest' when trip count "
1978 "must be evaluated in the host";
1981 return emitOpError() <<
"host_eval argument illegal use in '"
1982 << user->getName() <<
"' operation";
1991 assert(rootOp &&
"expected valid operation");
2003 return WalkResult::advance();
2008 bool isOmpDialect = op->
getDialect() == ompDialect;
2010 if (!isOmpDialect || !hasRegions)
2011 return WalkResult::skip();
2017 if (checkSingleMandatoryExec) {
2022 if (successor->isReachable(parentBlock))
2023 return WalkResult::interrupt();
2025 for (
Block &block : *parentRegion)
2027 !domInfo.
dominates(parentBlock, &block))
2028 return WalkResult::interrupt();
2034 if (&sibling != op && !siblingAllowedFn(&sibling))
2035 return WalkResult::interrupt();
2040 return llvm::isa<LoopNestOp>(op) ? WalkResult::interrupt()
2041 : WalkResult::advance();
2047 Operation *TargetOp::getInnermostCapturedOmpOp() {
2060 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(sibling)) {
2063 memOp.getEffects(effects);
2064 return !llvm::any_of(
2066 return isa<MemoryEffects::Write>(effect.
getEffect()) &&
2067 isa<SideEffects::AutomaticAllocationScopeResource>(
2075 TargetRegionFlags TargetOp::getKernelExecFlags(
Operation *capturedOp) {
2080 assert((!capturedOp ||
2081 (targetOp && targetOp.getInnermostCapturedOmpOp() == capturedOp)) &&
2082 "unexpected captured op");
2085 if (!isa_and_present<LoopNestOp>(capturedOp))
2086 return TargetRegionFlags::generic;
2090 cast<LoopNestOp>(capturedOp).gatherWrappers(loopWrappers);
2091 assert(!loopWrappers.empty());
2093 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2094 if (isa<SimdOp>(innermostWrapper))
2095 innermostWrapper = std::next(innermostWrapper);
2097 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2098 if (numWrappers != 1 && numWrappers != 2)
2099 return TargetRegionFlags::generic;
2102 if (numWrappers == 2) {
2103 if (!isa<WsloopOp>(innermostWrapper))
2104 return TargetRegionFlags::generic;
2106 innermostWrapper = std::next(innermostWrapper);
2107 if (!isa<DistributeOp>(innermostWrapper))
2108 return TargetRegionFlags::generic;
2111 if (!isa_and_present<ParallelOp>(parallelOp))
2112 return TargetRegionFlags::generic;
2115 if (!isa_and_present<TeamsOp>(teamsOp))
2116 return TargetRegionFlags::generic;
2118 if (teamsOp->
getParentOp() == targetOp.getOperation())
2119 return TargetRegionFlags::spmd | TargetRegionFlags::trip_count;
2122 else if (isa<DistributeOp, LoopOp>(innermostWrapper)) {
2124 if (!isa_and_present<TeamsOp>(teamsOp))
2125 return TargetRegionFlags::generic;
2127 if (teamsOp->
getParentOp() != targetOp.getOperation())
2128 return TargetRegionFlags::generic;
2130 if (isa<LoopOp>(innermostWrapper))
2131 return TargetRegionFlags::spmd | TargetRegionFlags::trip_count;
2141 Dialect *ompDialect = targetOp->getDialect();
2145 return sibling && (ompDialect != sibling->
getDialect() ||
2149 TargetRegionFlags result =
2150 TargetRegionFlags::generic | TargetRegionFlags::trip_count;
2155 while (nestedCapture->
getParentOp() != capturedOp)
2158 return isa<ParallelOp>(nestedCapture) ? result | TargetRegionFlags::spmd
2162 else if (isa<WsloopOp>(innermostWrapper)) {
2164 if (!isa_and_present<ParallelOp>(parallelOp))
2165 return TargetRegionFlags::generic;
2167 if (parallelOp->
getParentOp() == targetOp.getOperation())
2168 return TargetRegionFlags::spmd;
2171 return TargetRegionFlags::generic;
2180 ParallelOp::build(builder, state,
ValueRange(),
2186 state.addAttributes(attributes);
2190 const ParallelOperands &clauses) {
2192 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2193 clauses.ifExpr, clauses.numThreads, clauses.privateVars,
2195 clauses.procBindKind, clauses.reductionMod,
2196 clauses.reductionVars,
2201 template <
typename OpType>
2203 auto privateVars = op.getPrivateVars();
2204 auto privateSyms = op.getPrivateSymsAttr();
2206 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
2209 auto numPrivateVars = privateVars.size();
2210 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
2212 if (numPrivateVars != numPrivateSyms)
2213 return op.emitError() <<
"inconsistent number of private variables and "
2214 "privatizer op symbols, private vars: "
2216 <<
" vs. privatizer op symbols: " << numPrivateSyms;
2218 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
2219 Type varType = std::get<0>(privateVarInfo).getType();
2220 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
2221 PrivateClauseOp privatizerOp =
2222 SymbolTable::lookupNearestSymbolFrom<PrivateClauseOp>(op, privateSym);
2224 if (privatizerOp ==
nullptr)
2225 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
2226 << privateSym <<
"'";
2228 Type privatizerType = privatizerOp.getArgType();
2230 if (privatizerType && (varType != privatizerType))
2231 return op.emitError()
2232 <<
"type mismatch between a "
2233 << (privatizerOp.getDataSharingType() ==
2234 DataSharingClauseType::Private
2237 <<
" variable and its privatizer op, var type: " << varType
2238 <<
" vs. privatizer op type: " << privatizerType;
2245 if (getAllocateVars().size() != getAllocatorVars().size())
2247 "expected equal sizes for allocate and allocator variables");
2253 getReductionByref());
2256 LogicalResult ParallelOp::verifyRegions() {
2257 auto distChildOps = getOps<DistributeOp>();
2258 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
2259 if (numDistChildOps > 1)
2261 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
2263 if (numDistChildOps == 1) {
2266 <<
"'omp.composite' attribute missing from composite operation";
2269 Operation &distributeOp = **distChildOps.begin();
2271 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
2275 return emitError() <<
"unexpected OpenMP operation inside of composite "
2277 << childOp.getName();
2279 }
else if (isComposite()) {
2281 <<
"'omp.composite' attribute present in non-composite operation";
2298 const TeamsOperands &clauses) {
2301 TeamsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2302 clauses.ifExpr, clauses.numTeamsLower, clauses.numTeamsUpper,
2304 clauses.reductionMod, clauses.reductionVars,
2307 clauses.threadLimit);
2319 return emitError(
"expected to be nested inside of omp.target or not nested "
2320 "in any OpenMP dialect operations");
2323 if (
auto numTeamsLowerBound = getNumTeamsLower()) {
2324 auto numTeamsUpperBound = getNumTeamsUpper();
2325 if (!numTeamsUpperBound)
2326 return emitError(
"expected num_teams upper bound to be defined if the "
2327 "lower bound is defined");
2328 if (numTeamsLowerBound.getType() != numTeamsUpperBound.getType())
2330 "expected num_teams upper bound and lower bound to be the same type");
2334 if (getAllocateVars().size() != getAllocatorVars().size())
2336 "expected equal sizes for allocate and allocator variables");
2339 getReductionByref());
2347 return getParentOp().getPrivateVars();
2351 return getParentOp().getReductionVars();
2359 const SectionsOperands &clauses) {
2362 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2364 nullptr, clauses.reductionMod,
2365 clauses.reductionVars,
2371 if (getAllocateVars().size() != getAllocatorVars().size())
2373 "expected equal sizes for allocate and allocator variables");
2376 getReductionByref());
2379 LogicalResult SectionsOp::verifyRegions() {
2380 for (
auto &inst : *getRegion().begin()) {
2381 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
2382 return emitOpError()
2383 <<
"expected omp.section op or terminator op inside region";
2395 const SingleOperands &clauses) {
2398 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2399 clauses.copyprivateVars,
2400 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
2406 if (getAllocateVars().size() != getAllocatorVars().size())
2408 "expected equal sizes for allocate and allocator variables");
2411 getCopyprivateSyms());
2419 const WorkshareOperands &clauses) {
2420 WorkshareOp::build(builder, state, clauses.nowait);
2428 if (!(*this)->getParentOfType<WorkshareOp>())
2429 return emitOpError() <<
"must be nested in an omp.workshare";
2433 LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
2434 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
2436 return emitOpError() <<
"expected to be a standalone loop wrapper";
2445 LogicalResult LoopWrapperInterface::verifyImpl() {
2449 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
2450 "and `SingleBlock` traits";
2453 return emitOpError() <<
"loop wrapper does not contain exactly one region";
2456 if (range_size(region.
getOps()) != 1)
2457 return emitOpError()
2458 <<
"loop wrapper does not contain exactly one nested op";
2461 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
2462 return emitOpError() <<
"nested in loop wrapper is not another loop "
2463 "wrapper or `omp.loop_nest`";
2473 const LoopOperands &clauses) {
2476 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
2478 clauses.orderMod, clauses.reductionMod, clauses.reductionVars,
2485 getReductionByref());
2488 LogicalResult LoopOp::verifyRegions() {
2489 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
2491 return emitOpError() <<
"expected to be a standalone loop wrapper";
2502 build(builder, state, {}, {},
2504 false,
nullptr,
nullptr,
2505 nullptr, {},
nullptr,
2511 state.addAttributes(attributes);
2515 const WsloopOperands &clauses) {
2519 WsloopOp::build(builder, state,
2521 clauses.linearVars, clauses.linearStepVars, clauses.nowait,
2522 clauses.order, clauses.orderMod, clauses.ordered,
2523 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
2524 clauses.reductionMod, clauses.reductionVars,
2527 clauses.scheduleKind, clauses.scheduleChunk,
2528 clauses.scheduleMod, clauses.scheduleSimd);
2533 getReductionByref());
2536 LogicalResult WsloopOp::verifyRegions() {
2537 bool isCompositeChildLeaf =
2538 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
2540 if (LoopWrapperInterface nested = getNestedWrapper()) {
2543 <<
"'omp.composite' attribute missing from composite wrapper";
2547 if (!isa<SimdOp>(nested))
2548 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
2550 }
else if (isComposite() && !isCompositeChildLeaf) {
2552 <<
"'omp.composite' attribute present in non-composite wrapper";
2553 }
else if (!isComposite() && isCompositeChildLeaf) {
2555 <<
"'omp.composite' attribute missing from composite wrapper";
2566 const SimdOperands &clauses) {
2570 SimdOp::build(builder, state, clauses.alignedVars,
2573 clauses.nontemporalVars, clauses.order, clauses.orderMod,
2574 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
2575 clauses.reductionMod, clauses.reductionVars,
2582 if (getSimdlen().has_value() && getSafelen().has_value() &&
2583 getSimdlen().value() > getSafelen().value())
2584 return emitOpError()
2585 <<
"simdlen clause and safelen clause are both present, but the "
2586 "simdlen value is not less than or equal to safelen value";
2594 bool isCompositeChildLeaf =
2595 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
2597 if (!isComposite() && isCompositeChildLeaf)
2599 <<
"'omp.composite' attribute missing from composite wrapper";
2601 if (isComposite() && !isCompositeChildLeaf)
2603 <<
"'omp.composite' attribute present in non-composite wrapper";
2608 LogicalResult SimdOp::verifyRegions() {
2609 if (getNestedWrapper())
2610 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
2620 const DistributeOperands &clauses) {
2621 DistributeOp::build(builder, state, clauses.allocateVars,
2622 clauses.allocatorVars, clauses.distScheduleStatic,
2623 clauses.distScheduleChunkSize, clauses.order,
2624 clauses.orderMod, clauses.privateVars,
2629 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
2630 return emitOpError() <<
"chunk size set without "
2631 "dist_schedule_static being present";
2633 if (getAllocateVars().size() != getAllocatorVars().size())
2635 "expected equal sizes for allocate and allocator variables");
2640 LogicalResult DistributeOp::verifyRegions() {
2641 if (LoopWrapperInterface nested = getNestedWrapper()) {
2644 <<
"'omp.composite' attribute missing from composite wrapper";
2647 if (isa<WsloopOp>(nested)) {
2649 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
2650 !cast<ComposableOpInterface>(parentOp).isComposite()) {
2651 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
2652 "when a composite 'omp.parallel' is the direct "
2655 }
else if (!isa<SimdOp>(nested))
2656 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
2658 }
else if (isComposite()) {
2660 <<
"'omp.composite' attribute present in non-composite wrapper";
2674 LogicalResult DeclareMapperOp::verifyRegions() {
2675 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
2676 getRegion().getBlocks().front().getTerminator()))
2677 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
2686 LogicalResult DeclareReductionOp::verifyRegions() {
2687 if (!getAllocRegion().empty()) {
2688 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
2689 if (yieldOp.getResults().size() != 1 ||
2690 yieldOp.getResults().getTypes()[0] !=
getType())
2691 return emitOpError() <<
"expects alloc region to yield a value "
2692 "of the reduction type";
2696 if (getInitializerRegion().empty())
2697 return emitOpError() <<
"expects non-empty initializer region";
2698 Block &initializerEntryBlock = getInitializerRegion().
front();
2701 if (!getAllocRegion().empty())
2702 return emitOpError() <<
"expects two arguments to the initializer region "
2703 "when an allocation region is used";
2705 if (getAllocRegion().empty())
2706 return emitOpError() <<
"expects one argument to the initializer region "
2707 "when no allocation region is used";
2709 return emitOpError()
2710 <<
"expects one or two arguments to the initializer region";
2714 if (arg.getType() !=
getType())
2715 return emitOpError() <<
"expects initializer region argument to match "
2716 "the reduction type";
2718 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
2719 if (yieldOp.getResults().size() != 1 ||
2720 yieldOp.getResults().getTypes()[0] !=
getType())
2721 return emitOpError() <<
"expects initializer region to yield a value "
2722 "of the reduction type";
2725 if (getReductionRegion().empty())
2726 return emitOpError() <<
"expects non-empty reduction region";
2727 Block &reductionEntryBlock = getReductionRegion().
front();
2732 return emitOpError() <<
"expects reduction region with two arguments of "
2733 "the reduction type";
2734 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
2735 if (yieldOp.getResults().size() != 1 ||
2736 yieldOp.getResults().getTypes()[0] !=
getType())
2737 return emitOpError() <<
"expects reduction region to yield a value "
2738 "of the reduction type";
2741 if (!getAtomicReductionRegion().empty()) {
2742 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
2746 return emitOpError() <<
"expects atomic reduction region with two "
2747 "arguments of the same type";
2748 auto ptrType = llvm::dyn_cast<PointerLikeType>(
2751 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
2752 return emitOpError() <<
"expects atomic reduction region arguments to "
2753 "be accumulators containing the reduction type";
2756 if (getCleanupRegion().empty())
2758 Block &cleanupEntryBlock = getCleanupRegion().
front();
2761 return emitOpError() <<
"expects cleanup region with one argument "
2762 "of the reduction type";
2772 const TaskOperands &clauses) {
2774 TaskOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2775 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2776 clauses.final, clauses.ifExpr, clauses.inReductionVars,
2778 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
2779 clauses.priority, clauses.privateVars,
2781 clauses.untied, clauses.eventHandle);
2785 LogicalResult verifyDependVars =
2787 return failed(verifyDependVars)
2790 getInReductionVars(),
2791 getInReductionByref());
2799 const TaskgroupOperands &clauses) {
2801 TaskgroupOp::build(builder, state, clauses.allocateVars,
2802 clauses.allocatorVars, clauses.taskReductionVars,
2809 getTaskReductionVars(),
2810 getTaskReductionByref());
2818 const TaskloopOperands &clauses) {
2820 TaskloopOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2821 clauses.final, clauses.grainsizeMod, clauses.grainsize,
2822 clauses.ifExpr, clauses.inReductionVars,
2825 clauses.mergeable, clauses.nogroup, clauses.numTasksMod,
2826 clauses.numTasks, clauses.priority,
2827 clauses.privateVars,
2829 clauses.reductionMod, clauses.reductionVars,
2835 if (getAllocateVars().size() != getAllocatorVars().size())
2837 "expected equal sizes for allocate and allocator variables");
2839 getReductionVars(), getReductionByref())) ||
2841 getInReductionVars(),
2842 getInReductionByref())))
2845 if (!getReductionVars().empty() && getNogroup())
2846 return emitError(
"if a reduction clause is present on the taskloop "
2847 "directive, the nogroup clause must not be specified");
2848 for (
auto var : getReductionVars()) {
2849 if (llvm::is_contained(getInReductionVars(), var))
2850 return emitError(
"the same list item cannot appear in both a reduction "
2851 "and an in_reduction clause");
2854 if (getGrainsize() && getNumTasks()) {
2856 "the grainsize clause and num_tasks clause are mutually exclusive and "
2857 "may not appear on the same taskloop directive");
2863 LogicalResult TaskloopOp::verifyRegions() {
2864 if (LoopWrapperInterface nested = getNestedWrapper()) {
2867 <<
"'omp.composite' attribute missing from composite wrapper";
2871 if (!isa<SimdOp>(nested))
2872 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
2873 }
else if (isComposite()) {
2875 <<
"'omp.composite' attribute present in non-composite wrapper";
2899 for (
auto &iv : ivs)
2900 iv.type = loopVarType;
2929 Region ®ion = getRegion();
2931 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
2932 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
2933 if (getLoopInclusive())
2935 p <<
"step (" << getLoopSteps() <<
") ";
2940 const LoopNestOperands &clauses) {
2941 LoopNestOp::build(builder, state, clauses.loopLowerBounds,
2942 clauses.loopUpperBounds, clauses.loopSteps,
2943 clauses.loopInclusive);
2947 if (getLoopLowerBounds().empty())
2948 return emitOpError() <<
"must represent at least one loop";
2950 if (getLoopLowerBounds().size() != getIVs().size())
2951 return emitOpError() <<
"number of range arguments and IVs do not match";
2953 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
2954 if (lb.getType() != iv.getType())
2955 return emitOpError()
2956 <<
"range argument type does not match corresponding IV type";
2959 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
2960 return emitOpError() <<
"expects parent op to be a loop wrapper";
2965 void LoopNestOp::gatherWrappers(
2968 while (
auto wrapper =
2969 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
2970 wrappers.push_back(wrapper);
2980 const CriticalDeclareOperands &clauses) {
2981 CriticalDeclareOp::build(builder, state, clauses.symName, clauses.hint);
2989 if (getNameAttr()) {
2990 SymbolRefAttr symbolRef = getNameAttr();
2994 return emitOpError() <<
"expected symbol reference " << symbolRef
2995 <<
" to point to a critical declaration";
3015 return op.
emitOpError() <<
"must be nested inside of a loop";
3019 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
3020 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
3022 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
3023 "have an ordered clause";
3025 if (hasRegion && orderedAttr.getInt() != 0)
3026 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
3027 "have a parameter present";
3029 if (!hasRegion && orderedAttr.getInt() == 0)
3030 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
3031 "have a parameter present";
3032 }
else if (!isa<SimdOp>(wrapper)) {
3033 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
3034 "or worksharing simd loop";
3040 const OrderedOperands &clauses) {
3041 OrderedOp::build(builder, state, clauses.doacrossDependType,
3042 clauses.doacrossNumLoops, clauses.doacrossDependVars);
3049 auto wrapper = (*this)->getParentOfType<WsloopOp>();
3050 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
3051 return emitOpError() <<
"number of variables in depend clause does not "
3052 <<
"match number of iteration variables in the "
3059 const OrderedRegionOperands &clauses) {
3060 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
3070 const TaskwaitOperands &clauses) {
3072 TaskwaitOp::build(builder, state,
nullptr,
3081 if (verifyCommon().failed())
3082 return mlir::failure();
3084 if (
auto mo = getMemoryOrder()) {
3085 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
3086 *mo == ClauseMemoryOrderKind::Release) {
3088 "memory-order must not be acq_rel or release for atomic reads");
3099 if (verifyCommon().failed())
3100 return mlir::failure();
3102 if (
auto mo = getMemoryOrder()) {
3103 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
3104 *mo == ClauseMemoryOrderKind::Acquire) {
3106 "memory-order must not be acq_rel or acquire for atomic writes");
3116 LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
3122 if (
Value writeVal = op.getWriteOpVal()) {
3124 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
3131 if (verifyCommon().failed())
3132 return mlir::failure();
3134 if (
auto mo = getMemoryOrder()) {
3135 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
3136 *mo == ClauseMemoryOrderKind::Acquire) {
3138 "memory-order must not be acq_rel or acquire for atomic updates");
3145 LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
3151 AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
3152 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
3154 return dyn_cast<AtomicReadOp>(getSecondOp());
3157 AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
3158 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
3160 return dyn_cast<AtomicWriteOp>(getSecondOp());
3163 AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
3164 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
3166 return dyn_cast<AtomicUpdateOp>(getSecondOp());
3173 LogicalResult AtomicCaptureOp::verifyRegions() {
3174 if (verifyRegionsCommon().failed())
3175 return mlir::failure();
3177 if (getFirstOp()->getAttr(
"hint") || getSecondOp()->getAttr(
"hint"))
3179 "operations inside capture region must not have hint clause");
3181 if (getFirstOp()->getAttr(
"memory_order") ||
3182 getSecondOp()->getAttr(
"memory_order"))
3184 "operations inside capture region must not have memory_order clause");
3193 const CancelOperands &clauses) {
3194 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
3208 ClauseCancellationConstructType cct = getCancelDirective();
3211 if (!structuralParent)
3212 return emitOpError() <<
"Orphaned cancel construct";
3214 if ((cct == ClauseCancellationConstructType::Parallel) &&
3215 !mlir::isa<ParallelOp>(structuralParent)) {
3216 return emitOpError() <<
"cancel parallel must appear "
3217 <<
"inside a parallel region";
3219 if (cct == ClauseCancellationConstructType::Loop) {
3222 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
3225 return emitOpError()
3226 <<
"cancel loop must appear inside a worksharing-loop region";
3228 if (wsloopOp.getNowaitAttr()) {
3229 return emitError() <<
"A worksharing construct that is canceled "
3230 <<
"must not have a nowait clause";
3232 if (wsloopOp.getOrderedAttr()) {
3233 return emitError() <<
"A worksharing construct that is canceled "
3234 <<
"must not have an ordered clause";
3237 }
else if (cct == ClauseCancellationConstructType::Sections) {
3241 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
3243 return emitOpError() <<
"cancel sections must appear "
3244 <<
"inside a sections region";
3246 if (sectionsOp.getNowait()) {
3247 return emitError() <<
"A sections construct that is canceled "
3248 <<
"must not have a nowait clause";
3251 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
3252 (!mlir::isa<omp::TaskOp>(structuralParent) &&
3253 !mlir::isa<omp::TaskloopOp>(structuralParent->
getParentOp()))) {
3254 return emitOpError() <<
"cancel taskgroup must appear "
3255 <<
"inside a task region";
3265 const CancellationPointOperands &clauses) {
3266 CancellationPointOp::build(builder, state, clauses.cancelDirective);
3270 ClauseCancellationConstructType cct = getCancelDirective();
3273 if (!structuralParent)
3274 return emitOpError() <<
"Orphaned cancellation point";
3276 if ((cct == ClauseCancellationConstructType::Parallel) &&
3277 !mlir::isa<ParallelOp>(structuralParent)) {
3278 return emitOpError() <<
"cancellation point parallel must appear "
3279 <<
"inside a parallel region";
3283 if ((cct == ClauseCancellationConstructType::Loop) &&
3284 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
3285 return emitOpError() <<
"cancellation point loop must appear "
3286 <<
"inside a worksharing-loop region";
3288 if ((cct == ClauseCancellationConstructType::Sections) &&
3289 !mlir::isa<omp::SectionOp>(structuralParent)) {
3290 return emitOpError() <<
"cancellation point sections must appear "
3291 <<
"inside a sections region";
3293 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
3294 !mlir::isa<omp::TaskOp>(structuralParent)) {
3295 return emitOpError() <<
"cancellation point taskgroup must appear "
3296 <<
"inside a task region";
3306 auto extent = getExtent();
3308 if (!extent && !upperbound)
3309 return emitError(
"expected extent or upperbound.");
3316 PrivateClauseOp::build(
3317 odsBuilder, odsState, symName, type,
3319 DataSharingClauseType::Private));
3322 LogicalResult PrivateClauseOp::verifyRegions() {
3323 Type argType = getArgType();
3324 auto verifyTerminator = [&](
Operation *terminator,
3325 bool yieldsValue) -> LogicalResult {
3329 if (!llvm::isa<YieldOp>(terminator))
3331 <<
"expected exit block terminator to be an `omp.yield` op.";
3333 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
3334 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
3337 if (yieldedTypes.empty())
3341 <<
"Did not expect any values to be yielded.";
3344 if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)
3348 <<
"Invalid yielded value. Expected type: " << argType
3351 if (yieldedTypes.empty())
3354 error << yieldedTypes;
3360 StringRef regionName,
3361 bool yieldsValue) -> LogicalResult {
3362 assert(!region.
empty());
3366 <<
"`" << regionName <<
"`: "
3367 <<
"expected " << expectedNumArgs
3370 for (
Block &block : region) {
3372 if (!block.mightHaveTerminator())
3375 if (failed(verifyTerminator(block.getTerminator(), yieldsValue)))
3383 for (
Region *region : getRegions())
3384 for (
Type ty : region->getArgumentTypes())
3386 return emitError() <<
"Region argument type mismatch: got " << ty
3387 <<
" expected " << argType <<
".";
3390 if (!initRegion.
empty() &&
3395 DataSharingClauseType dsType = getDataSharingType();
3397 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
3398 return emitError(
"`private` clauses do not require a `copy` region.");
3400 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
3402 "`firstprivate` clauses require at least a `copy` region.");
3404 if (dsType == DataSharingClauseType::FirstPrivate &&
3409 if (!getDeallocRegion().empty() &&
3422 const MaskedOperands &clauses) {
3423 MaskedOp::build(builder, state, clauses.filteredThreadId);
3431 const ScanOperands &clauses) {
3432 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
3436 if (hasExclusiveVars() == hasInclusiveVars())
3438 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
3439 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
3440 if (parentWsLoopOp.getReductionModAttr() &&
3441 parentWsLoopOp.getReductionModAttr().getValue() ==
3442 ReductionModifier::inscan)
3445 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
3446 if (parentSimdOp.getReductionModAttr() &&
3447 parentSimdOp.getReductionModAttr().getValue() ==
3448 ReductionModifier::inscan)
3451 return emitError(
"SCAN directive needs to be enclosed within a parent "
3452 "worksharing loop construct or SIMD construct with INSCAN "
3453 "reduction modifier");
3456 #define GET_ATTRDEF_CLASSES
3457 #include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
3459 #define GET_OP_CLASSES
3460 #include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
3462 #define GET_TYPEDEF_CLASSES
3463 #include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, const Twine &name)
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static MLIRContext * getContext(OpFoldResult val)
void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr)
static LogicalResult verifyNontemporalClause(Operation *op, OperandRange nontemporalVars)
static ParseResult parsePrivateRegion(OpAsmParser &parser, Region ®ion, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms)
static LogicalResult verifyMapClause(Operation *op, OperandRange mapVars)
static ArrayAttr makeArrayAttr(MLIRContext *context, llvm::ArrayRef< Attribute > attrs)
static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr)
static void printTargetOpRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange hasDeviceAddrVars, TypeRange hasDeviceAddrTypes, ValueRange hostEvalVars, TypeRange hostEvalTypes, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms, ValueRange mapVars, TypeRange mapTypes, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, DenseI64ArrayAttr privateMaps)
static void printAllocateAndAllocator(OpAsmPrinter &p, Operation *op, OperandRange allocateVars, TypeRange allocateTypes, OperandRange allocatorVars, TypeRange allocatorTypes)
Print allocate clause.
static DenseBoolArrayAttr makeDenseBoolArrayAttr(MLIRContext *ctx, const ArrayRef< bool > boolArray)
static ParseResult parseInReductionPrivateRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms)
static void printBlockArgClause(OpAsmPrinter &p, MLIRContext *ctx, StringRef clauseName, ValueRange argsSubrange, std::optional< MapPrintArgs > mapArgs)
static void printBlockArgRegion(OpAsmPrinter &p, Operation *op, Region ®ion, const AllRegionPrintArgs &args)
static ParseResult parseGranularityClause(OpAsmParser &parser, ClauseTypeAttr &prescriptiveness, std::optional< OpAsmParser::UnresolvedOperand > &operand, Type &operandType, std::optional< ClauseType >(*symbolizeClause)(StringRef), StringRef clauseName)
static ParseResult parseBlockArgRegion(OpAsmParser &parser, Region ®ion, AllRegionParseArgs args)
static ParseResult parseSynchronizationHint(OpAsmParser &parser, IntegerAttr &hintAttr)
Parses a Synchronization Hint clause.
static void printClauseWithRegionArgs(OpAsmPrinter &p, MLIRContext *ctx, StringRef clauseName, ValueRange argsSubrange, ValueRange operands, TypeRange types, ArrayAttr symbols=nullptr, DenseI64ArrayAttr mapIndices=nullptr, DenseBoolArrayAttr byref=nullptr, ReductionModifierAttr modifier=nullptr)
uint64_t mapTypeToBitFlag(uint64_t value, llvm::omp::OpenMPOffloadMappingFlags flag)
static ParseResult parseLinearClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearVars, SmallVectorImpl< Type > &linearTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearStepVars)
linear ::= linear ( linear-list ) linear-list := linear-val | linear-val linear-list linear-val := ss...
static void printInReductionPrivateReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, ReductionModifierAttr reductionMod, ValueRange reductionVars, TypeRange reductionTypes, DenseBoolArrayAttr reductionByref, ArrayAttr reductionSyms)
static void printScheduleClause(OpAsmPrinter &p, Operation *op, ClauseScheduleKindAttr scheduleKind, ScheduleModifierAttr scheduleMod, UnitAttr scheduleSimd, Value scheduleChunk, Type scheduleChunkType)
Print schedule clause.
static void printPrivateReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, ReductionModifierAttr reductionMod, ValueRange reductionVars, TypeRange reductionTypes, DenseBoolArrayAttr reductionByref, ArrayAttr reductionSyms)
static void printCopyprivate(OpAsmPrinter &p, Operation *op, OperandRange copyprivateVars, TypeRange copyprivateTypes, std::optional< ArrayAttr > copyprivateSyms)
Print Copyprivate clause.
static ParseResult parseOrderClause(OpAsmParser &parser, ClauseOrderKindAttr &order, OrderModifierAttr &orderMod)
static void printAlignedClause(OpAsmPrinter &p, Operation *op, ValueRange alignedVars, TypeRange alignedTypes, std::optional< ArrayAttr > alignments)
Print Aligned Clause.
static LogicalResult verifySynchronizationHint(Operation *op, uint64_t hint)
Verifies a synchronization hint clause.
static ParseResult parseUseDeviceAddrUseDevicePtrRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &useDeviceAddrVars, SmallVectorImpl< Type > &useDeviceAddrTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &useDevicePtrVars, SmallVectorImpl< Type > &useDevicePtrTypes)
static void printLinearClause(OpAsmPrinter &p, Operation *op, ValueRange linearVars, TypeRange linearTypes, ValueRange linearStepVars)
Print Linear Clause.
static void printSynchronizationHint(OpAsmPrinter &p, Operation *op, IntegerAttr hintAttr)
Prints a Synchronization Hint clause.
static void printGranularityClause(OpAsmPrinter &p, Operation *op, ClauseTypeAttr prescriptiveness, Value operand, mlir::Type operandType, StringRef(*stringifyClauseType)(ClauseType))
static void printDependVarList(OpAsmPrinter &p, Operation *op, OperandRange dependVars, TypeRange dependTypes, std::optional< ArrayAttr > dependKinds)
Print Depend clause.
static LogicalResult verifyCopyprivateVarList(Operation *op, OperandRange copyprivateVars, std::optional< ArrayAttr > copyprivateSyms)
Verifies CopyPrivate Clause.
static LogicalResult verifyAlignedClause(Operation *op, std::optional< ArrayAttr > alignments, OperandRange alignedVars)
static void printNumTasksClause(OpAsmPrinter &p, Operation *op, ClauseNumTasksTypeAttr numTasksMod, Value numTasks, mlir::Type numTasksType)
static void printTaskReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange taskReductionVars, TypeRange taskReductionTypes, DenseBoolArrayAttr taskReductionByref, ArrayAttr taskReductionSyms)
static ParseResult parseInReductionPrivateReductionRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, ReductionModifierAttr &reductionMod, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionVars, SmallVectorImpl< Type > &reductionTypes, DenseBoolArrayAttr &reductionByref, ArrayAttr &reductionSyms)
static ParseResult parseMapClause(OpAsmParser &parser, IntegerAttr &mapType)
Parses a map_entries map type from a string format back into its numeric value.
static LogicalResult verifyOrderedParent(Operation &op)
static void printOrderClause(OpAsmPrinter &p, Operation *op, ClauseOrderKindAttr order, OrderModifierAttr orderMod)
static ParseResult parseBlockArgClause(OpAsmParser &parser, llvm::SmallVectorImpl< OpAsmParser::Argument > &entryBlockArgs, StringRef keyword, std::optional< MapParseArgs > mapArgs)
static ParseResult verifyScheduleModifiers(OpAsmParser &parser, SmallVectorImpl< SmallString< 12 >> &modifiers)
static LogicalResult verifyPrivateVarsMapping(TargetOp targetOp)
static ParseResult parseScheduleClause(OpAsmParser &parser, ClauseScheduleKindAttr &scheduleAttr, ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd, std::optional< OpAsmParser::UnresolvedOperand > &chunkSize, Type &chunkType)
schedule ::= schedule ( sched-list ) sched-list ::= sched-val | sched-val sched-list | sched-val ,...
static void printPrivateRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms)
static Operation * getParentInSameDialect(Operation *thisOp)
static ParseResult parseAllocateAndAllocator(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &allocateVars, SmallVectorImpl< Type > &allocateTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &allocatorVars, SmallVectorImpl< Type > &allocatorTypes)
Parse an allocate clause with allocators and a list of operands with types.
static void printMembersIndex(OpAsmPrinter &p, MapInfoOp op, ArrayAttr membersIdx)
static ParseResult parseTargetOpRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hasDeviceAddrVars, SmallVectorImpl< Type > &hasDeviceAddrTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hostEvalVars, SmallVectorImpl< Type > &hostEvalTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &mapVars, SmallVectorImpl< Type > &mapTypes, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, DenseI64ArrayAttr &privateMaps)
static void printCaptureType(OpAsmPrinter &p, Operation *op, VariableCaptureKindAttr mapCaptureType)
static LogicalResult verifyReductionVarList(Operation *op, std::optional< ArrayAttr > reductionSyms, OperandRange reductionVars, std::optional< ArrayRef< bool >> reductionByref)
Verifies Reduction Clause.
static ParseResult parseClauseWithRegionArgs(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &operands, SmallVectorImpl< Type > &types, SmallVectorImpl< OpAsmParser::Argument > ®ionPrivateArgs, ArrayAttr *symbols=nullptr, DenseI64ArrayAttr *mapIndices=nullptr, DenseBoolArrayAttr *byref=nullptr, ReductionModifierAttr *modifier=nullptr)
static Operation * findCapturedOmpOp(Operation *rootOp, bool checkSingleMandatoryExec, llvm::function_ref< bool(Operation *)> siblingAllowedFn)
static bool opInGlobalImplicitParallelRegion(Operation *op)
static void printUseDeviceAddrUseDevicePtrRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange useDeviceAddrVars, TypeRange useDeviceAddrTypes, ValueRange useDevicePtrVars, TypeRange useDevicePtrTypes)
static LogicalResult verifyPrivateVarList(OpType &op)
static void printMapClause(OpAsmPrinter &p, Operation *op, IntegerAttr mapType)
Prints a map_entries map type from its numeric value out into its string format.
static ParseResult parseNumTasksClause(OpAsmParser &parser, ClauseNumTasksTypeAttr &numTasksMod, std::optional< OpAsmParser::UnresolvedOperand > &numTasks, Type &numTasksType)
static ParseResult parseMembersIndex(OpAsmParser &parser, ArrayAttr &membersIdx)
static ParseResult parseAlignedClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &alignedVars, SmallVectorImpl< Type > &alignedTypes, ArrayAttr &alignmentsAttr)
aligned ::= aligned ( aligned-list ) aligned-list := aligned-val | aligned-val aligned-list aligned-v...
static void printInReductionPrivateRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms)
static ParseResult parseCaptureType(OpAsmParser &parser, VariableCaptureKindAttr &mapCaptureType)
static ParseResult parseTaskReductionRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &taskReductionVars, SmallVectorImpl< Type > &taskReductionTypes, DenseBoolArrayAttr &taskReductionByref, ArrayAttr &taskReductionSyms)
static ParseResult parseGrainsizeClause(OpAsmParser &parser, ClauseGrainsizeTypeAttr &grainsizeMod, std::optional< OpAsmParser::UnresolvedOperand > &grainsize, Type &grainsizeType)
static ParseResult parseCopyprivate(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > ©privateVars, SmallVectorImpl< Type > ©privateTypes, ArrayAttr ©privateSyms)
copyprivate-entry-list ::= copyprivate-entry | copyprivate-entry-list , copyprivate-entry copyprivate...
static LogicalResult verifyDependVarList(Operation *op, std::optional< ArrayAttr > dependKinds, OperandRange dependVars)
Verifies Depend clause.
static ParseResult parseDependVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &dependVars, SmallVectorImpl< Type > &dependTypes, ArrayAttr &dependKinds)
depend-entry-list ::= depend-entry | depend-entry-list , depend-entry depend-entry ::= depend-kind ->...
static ParseResult parsePrivateReductionRegion(OpAsmParser &parser, Region ®ion, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, ReductionModifierAttr &reductionMod, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionVars, SmallVectorImpl< Type > &reductionTypes, DenseBoolArrayAttr &reductionByref, ArrayAttr &reductionSyms)
static LogicalResult verifyMapInfoDefinedArgs(Operation *op, StringRef clauseName, OperandRange vars)
static void printGrainsizeClause(OpAsmPrinter &p, Operation *op, ClauseGrainsizeTypeAttr grainsizeMod, Value grainsize, mlir::Type grainsizeType)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
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,...
This base class exposes generic asm parser hooks, usable across the various derived parsers.
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 Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
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 parseOptionalColon()=0
Parse a : token if present.
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
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 SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseComma()=0
Parse a , token.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
SuccessorRange getSuccessors()
BlockArgListType getArguments()
IntegerAttr getIntegerAttr(Type type, int64_t value)
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
MLIRContext is the top-level object for a collection of MLIR operations.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
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.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
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.
This class helps build Operations.
This class provides the API for ops that are known to be terminators.
This class indicates that the regions associated with this op don't have terminators.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Block * getBlock()
Returns the operation block that contains this operation.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
user_range getUsers()
Returns a range of all users.
Region * getParentRegion()
Returns the region to which the instruction belongs.
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 contains a list of basic blocks and a link to the parent operation it is attached to.
iterator_range< OpIterator > getOps()
BlockArgListType getArguments()
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
unsigned getNumArguments()
Location getLoc()
Return a location for this region.
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
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.
Resource * getResource() const
Return the resource that the effect applies to.
EffectT * getEffect() const
Return the effect being applied.
This class represents a collection of SymbolTables.
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...
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
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.
Base class for DenseArrayAttr that is instantiated and specialized for each supported element type be...
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< T > content)
Builder from ArrayRef<T>.
bool isReachableFromEntry(Block *a) const
Return true if the specified block is reachable from the entry block of its region.
Runtime
Potential runtimes for AMD GPU kernels.
TargetEnterDataOperands TargetEnterExitUpdateDataOperands
omp.target_enter_data, omp.target_exit_data and omp.target_update take the same clauses,...
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
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.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
This is the representation of an operand reference.
This class provides APIs and verifiers for ops with regions having a single block.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
SmallVector< Value, 4 > operands
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
Region * addRegion()
Create a region that should be attached to the operation.