28#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/PostOrderIterator.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/STLForwardCompat.h"
32#include "llvm/ADT/SmallString.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/ADT/TypeSwitch.h"
36#include "llvm/ADT/bit.h"
37#include "llvm/Support/InterleavedRange.h"
43#include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc"
44#include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
45#include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.cpp.inc"
46#include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.cpp.inc"
53 return attrs.empty() ?
nullptr : ArrayAttr::get(context, attrs);
67struct MemRefPointerLikeModel
68 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
71 return llvm::cast<MemRefType>(pointer).getElementType();
75struct LLVMPointerPointerLikeModel
76 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
77 LLVM::LLVMPointerType> {
102 bool isRegionArgOfOp;
112 assert(isRegionArgOfOp &&
"Must describe a region operand");
115 size_t &getArgIdx() {
116 assert(isRegionArgOfOp &&
"Must describe a region operand");
121 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
125 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
128 bool isLoopOp()
const {
129 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
130 return isa<CanonicalLoopOp>(op);
132 Region *&getParentRegion() {
133 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
136 size_t &getLoopDepth() {
137 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
141 void skipIf(
bool v =
true) { skip = skip || v; }
159 llvm::ReversePostOrderTraversal<Block *> traversal(&r->
getBlocks().front());
162 size_t sequentialIdx = -1;
163 bool isOnlyContainerOp =
true;
164 for (
Block *
b : traversal) {
166 if (&op == o && !found) {
170 if (op.getNumRegions()) {
173 isOnlyContainerOp =
false;
175 if (found && !isOnlyContainerOp)
180 Component &containerOpInRegion = components.emplace_back();
181 containerOpInRegion.isRegionArgOfOp =
false;
182 containerOpInRegion.isUnique = isOnlyContainerOp;
183 containerOpInRegion.getContainerOp() = o;
184 containerOpInRegion.getOpPos() = sequentialIdx;
185 containerOpInRegion.getParentRegion() = r;
190 Component ®ionArgOfOperation = components.emplace_back();
191 regionArgOfOperation.isRegionArgOfOp =
true;
192 regionArgOfOperation.isUnique =
true;
193 regionArgOfOperation.getArgIdx() = 0;
194 regionArgOfOperation.getOwnerOp() = parent;
206 for (
auto [idx, region] : llvm::enumerate(o->
getRegions())) {
210 llvm_unreachable(
"Region not child of its parent operation");
212 regionArgOfOperation.isUnique =
false;
213 regionArgOfOperation.getArgIdx() = getRegionIndex(parent, r);
221 for (Component &c : components)
222 c.skipIf(c.isRegionArgOfOp && c.isUnique);
225 size_t numSurroundingLoops = 0;
226 for (Component &c : llvm::reverse(components)) {
231 if (c.isRegionArgOfOp) {
232 numSurroundingLoops = 0;
239 numSurroundingLoops = 0;
241 c.getLoopDepth() = numSurroundingLoops;
244 if (isa<CanonicalLoopOp>(c.getContainerOp()))
245 numSurroundingLoops += 1;
250 bool isLoopNest =
false;
251 for (Component &c : components) {
252 if (c.skip || c.isRegionArgOfOp)
255 if (!isLoopNest && c.getLoopDepth() >= 1) {
258 }
else if (isLoopNest) {
260 c.skipIf(c.isUnique);
264 if (c.getLoopDepth() == 0)
271 for (Component &c : components)
272 c.skipIf(!c.isRegionArgOfOp && c.isUnique &&
273 !isa<CanonicalLoopOp>(c.getContainerOp()));
277 bool newRegion =
true;
278 for (Component &c : llvm::reverse(components)) {
279 c.skipIf(newRegion && c.isUnique);
286 if (!c.isRegionArgOfOp && c.getContainerOp())
292 llvm::raw_svector_ostream NameOS(Name);
293 for (
auto &c : llvm::reverse(components)) {
297 if (c.isRegionArgOfOp)
298 NameOS <<
"_r" << c.getArgIdx();
299 else if (c.getLoopDepth() >= 1)
300 NameOS <<
"_d" << c.getLoopDepth();
302 NameOS <<
"_s" << c.getOpPos();
305 return NameOS.str().str();
308void OpenMPDialect::initialize() {
311#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
314#define GET_ATTRDEF_LIST
315#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
318#define GET_TYPEDEF_LIST
319#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
322 declarePromisedInterface<ConvertToLLVMPatternInterface, OpenMPDialect>();
324 MemRefType::attachInterface<MemRefPointerLikeModel>(*
getContext());
325 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
330 mlir::ModuleOp::attachInterface<mlir::omp::OffloadModuleDefaultModel>(
336 mlir::LLVM::GlobalOp::attachInterface<
339 mlir::LLVM::LLVMFuncOp::attachInterface<
342 mlir::func::FuncOp::attachInterface<
368 allocatorVars.push_back(operand);
369 allocatorTypes.push_back(type);
375 allocateVars.push_back(operand);
376 allocateTypes.push_back(type);
387 for (
unsigned i = 0; i < allocateVars.size(); ++i) {
388 std::string separator = i == allocateVars.size() - 1 ?
"" :
", ";
389 p << allocatorVars[i] <<
" : " << allocatorTypes[i] <<
" -> ";
390 p << allocateVars[i] <<
" : " << allocateTypes[i] << separator;
398template <
typename ClauseAttr>
400 using ClauseT =
decltype(std::declval<ClauseAttr>().getValue());
405 if (std::optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
406 attr = ClauseAttr::get(parser.
getContext(), *enumValue);
409 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
412template <
typename ClauseAttr>
414 p << stringifyEnum(attr.getValue());
439 std::optional<omp::LinearModifier> linearModifier;
441 linearModifier = omp::LinearModifier::val;
443 linearModifier = omp::LinearModifier::ref;
445 linearModifier = omp::LinearModifier::uval;
448 bool hasLinearModifierParens = linearModifier.has_value();
449 if (hasLinearModifierParens && parser.
parseLParen())
457 if (hasLinearModifierParens && parser.
parseRParen())
460 linearVars.push_back(var);
461 linearTypes.push_back(type);
462 linearStepVars.push_back(stepVar);
463 linearStepTypes.push_back(stepType);
464 if (linearModifier) {
466 omp::LinearModifierAttr::get(parser.
getContext(), *linearModifier));
468 modifiers.push_back(UnitAttr::get(parser.
getContext()));
474 linearModifiers = ArrayAttr::get(parser.
getContext(), modifiers);
483 size_t linearVarsSize = linearVars.size();
484 for (
unsigned i = 0; i < linearVarsSize; ++i) {
488 Attribute modAttr = linearModifiers ? linearModifiers[i] :
nullptr;
489 auto mod = modAttr ? dyn_cast<omp::LinearModifierAttr>(modAttr) :
nullptr;
491 p << omp::stringifyLinearModifier(mod.getValue()) <<
"(";
493 p << linearVars[i] <<
" : " << linearTypes[i];
494 p <<
" = " << linearStepVars[i] <<
" : " << stepVarTypes[i];
510 if (!linearModifiers)
512 if (linearModifiers->size() != linearVars.size())
514 <<
"expected as many linear modifiers as linear variables";
515 if (!isDeclareSimd) {
516 for (
Attribute attr : *linearModifiers) {
519 auto modAttr = dyn_cast<omp::LinearModifierAttr>(attr);
522 omp::LinearModifier mod = modAttr.getValue();
523 if (mod == omp::LinearModifier::ref || mod == omp::LinearModifier::uval)
525 <<
"linear modifier '" << omp::stringifyLinearModifier(mod)
526 <<
"' may only be specified on a declare simd directive";
541 for (
const auto &it : nontemporalVars)
542 if (!nontemporalItems.insert(it).second)
543 return op->
emitOpError() <<
"nontemporal variable used more than once";
552 std::optional<ArrayAttr> alignments,
555 if (!alignedVars.empty()) {
556 if (!alignments || alignments->size() != alignedVars.size())
558 <<
"expected as many alignment values as aligned variables";
561 return op->
emitOpError() <<
"unexpected alignment values attribute";
567 for (
auto it : alignedVars)
568 if (!alignedItems.insert(it).second)
569 return op->
emitOpError() <<
"aligned variable used more than once";
575 for (
unsigned i = 0; i < (*alignments).size(); ++i) {
576 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>((*alignments)[i])) {
577 if (intAttr.getValue().sle(0))
578 return op->
emitOpError() <<
"alignment should be greater than 0";
580 return op->
emitOpError() <<
"expected integer alignment";
597 if (parser.parseOperand(alignedVars.emplace_back()) ||
598 parser.parseColonType(alignedTypes.emplace_back()) ||
599 parser.parseArrow() ||
600 parser.parseAttribute(alignmentVec.emplace_back())) {
607 alignmentsAttr = ArrayAttr::get(parser.getContext(), alignments);
614 std::optional<ArrayAttr> alignments) {
615 for (
unsigned i = 0; i < alignedVars.size(); ++i) {
618 p << alignedVars[i] <<
" : " << alignedVars[i].
getType();
619 p <<
" -> " << (*alignments)[i];
630 if (modifiers.size() > 2)
632 for (
const auto &mod : modifiers) {
635 auto symbol = symbolizeScheduleModifier(mod);
638 <<
" unknown modifier type: " << mod;
643 if (modifiers.size() == 1) {
644 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
645 modifiers.push_back(modifiers[0]);
646 modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
648 }
else if (modifiers.size() == 2) {
651 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
652 symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
654 <<
" incorrect modifier order";
670 ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd,
671 std::optional<OpAsmParser::UnresolvedOperand> &chunkSize,
676 std::optional<mlir::omp::ClauseScheduleKind> schedule =
677 symbolizeClauseScheduleKind(keyword);
681 scheduleAttr = ClauseScheduleKindAttr::get(parser.
getContext(), *schedule);
683 case ClauseScheduleKind::Static:
684 case ClauseScheduleKind::Dynamic:
685 case ClauseScheduleKind::Guided:
691 chunkSize = std::nullopt;
694 case ClauseScheduleKind::Auto:
695 case ClauseScheduleKind::Runtime:
696 case ClauseScheduleKind::Distribute:
697 chunkSize = std::nullopt;
706 modifiers.push_back(mod);
712 if (!modifiers.empty()) {
714 if (std::optional<ScheduleModifier> mod =
715 symbolizeScheduleModifier(modifiers[0])) {
716 scheduleMod = ScheduleModifierAttr::get(parser.
getContext(), *mod);
718 return parser.
emitError(loc,
"invalid schedule modifier");
721 if (modifiers.size() > 1) {
722 assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
732 ClauseScheduleKindAttr scheduleKind,
733 ScheduleModifierAttr scheduleMod,
734 UnitAttr scheduleSimd,
Value scheduleChunk,
735 Type scheduleChunkType) {
736 p << stringifyClauseScheduleKind(scheduleKind.getValue());
738 p <<
" = " << scheduleChunk <<
" : " << scheduleChunk.
getType();
740 p <<
", " << stringifyScheduleModifier(scheduleMod.getValue());
752 ClauseOrderKindAttr &order,
753 OrderModifierAttr &orderMod) {
758 if (std::optional<OrderModifier> enumValue =
759 symbolizeOrderModifier(enumStr)) {
760 orderMod = OrderModifierAttr::get(parser.
getContext(), *enumValue);
767 if (std::optional<ClauseOrderKind> enumValue =
768 symbolizeClauseOrderKind(enumStr)) {
769 order = ClauseOrderKindAttr::get(parser.
getContext(), *enumValue);
772 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
776 ClauseOrderKindAttr order,
777 OrderModifierAttr orderMod) {
779 p << stringifyOrderModifier(orderMod.getValue()) <<
":";
781 p << stringifyClauseOrderKind(order.getValue());
784template <
typename ClauseTypeAttr,
typename ClauseType>
787 std::optional<OpAsmParser::UnresolvedOperand> &operand,
789 std::optional<ClauseType> (*symbolizeClause)(StringRef),
790 StringRef clauseName) {
793 if (std::optional<ClauseType> enumValue = symbolizeClause(enumStr)) {
794 prescriptiveness = ClauseTypeAttr::get(parser.
getContext(), *enumValue);
799 <<
"invalid " << clauseName <<
" modifier : '" << enumStr <<
"'";
809 <<
"expected " << clauseName <<
" operand";
812 if (operand.has_value()) {
820template <
typename ClauseTypeAttr,
typename ClauseType>
823 ClauseTypeAttr prescriptiveness,
Value operand,
825 StringRef (*stringifyClauseType)(ClauseType)) {
827 if (prescriptiveness)
828 p << stringifyClauseType(prescriptiveness.getValue()) <<
", ";
831 p << operand <<
": " << operandType;
841 std::optional<OpAsmParser::UnresolvedOperand> &grainsize,
842 Type &grainsizeType) {
844 parser, grainsizeMod, grainsize, grainsizeType,
845 &symbolizeClauseGrainsizeType,
"grainsize");
849 ClauseGrainsizeTypeAttr grainsizeMod,
852 p, op, grainsizeMod, grainsize, grainsizeType,
853 &stringifyClauseGrainsizeType);
863 std::optional<OpAsmParser::UnresolvedOperand> &numTasks,
864 Type &numTasksType) {
866 parser, numTasksMod, numTasks, numTasksType, &symbolizeClauseNumTasksType,
871 ClauseNumTasksTypeAttr numTasksMod,
874 p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
890 return mlir::failure();
891 inTypeAttr = TypeAttr::get(inType);
920 if (!typeparams.empty()) {
921 p <<
'(' << typeparams <<
" : " << typeparamsTypes <<
')';
923 for (
auto sh :
shape) {
935 FallbackModifierAttr fallback,
936 Value dynGroupprivateSize) {
937 if (!dynGroupprivateSize && (accessGroup || fallback))
938 return op->
emitOpError(
"dyn_groupprivate modifiers require a size operand");
944 OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr,
945 FallbackModifierAttr &fallbackAttr,
946 std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
949 bool parsedAccessGroup =
false;
950 bool parsedFallback =
false;
951 bool parsedSize =
false;
956 if (parsedAccessGroup)
958 "duplicate access group modifier");
959 accessGroupAttr = AccessGroupModifierAttr::get(
960 parser.
getContext(), AccessGroupModifier::cgroup);
961 parsedAccessGroup =
true;
968 "duplicate fallback modifier");
971 "expected '(' after 'fallback'");
972 llvm::StringRef fbKind;
976 "expected fallback modifier (abort/null/default_mem)");
977 std::optional<FallbackModifier> fbEnum;
978 if (fbKind ==
"abort")
979 fbEnum = FallbackModifier::abort;
980 else if (fbKind ==
"null")
981 fbEnum = FallbackModifier::null;
982 else if (fbKind ==
"default_mem")
983 fbEnum = FallbackModifier::default_mem;
986 "invalid fallback modifier '" + fbKind +
"'");
987 fallbackAttr = FallbackModifierAttr::get(parser.
getContext(), *fbEnum);
990 "expected ')' after fallback modifier");
991 parsedFallback =
true;
999 "duplicate size operand");
1000 dynGroupprivateSize = operand;
1004 "expected ':' and type after size operand");
1008 "expected dyn_groupprivate_size operand");
1013 AccessGroupModifierAttr modifierFirst,
1014 FallbackModifierAttr modifierSecond,
1015 Value dynGroupprivateSize,
1018 bool needsComma =
false;
1020 if (modifierFirst) {
1021 printer << modifierFirst.getValue();
1025 if (modifierSecond) {
1028 printer <<
"fallback(";
1029 printer << modifierSecond.getValue();
1034 if (dynGroupprivateSize) {
1037 printer << dynGroupprivateSize <<
" : " << sizeType;
1057 isByRefVec.push_back(parser.parseOptionalKeyword(
"byref").succeeded());
1058 if (parser.parseAttribute(symbolVec.emplace_back()) ||
1059 parser.parseOperand(inReductionVars.emplace_back()))
1069 [&]() { return parser.parseType(inReductionTypes.emplace_back()); }))
1072 if (inReductionVars.size() != inReductionTypes.size())
1077 inReductionSyms = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1094 syms = ArrayAttr::get(ctx, values);
1103 llvm::interleaveComma(
1104 llvm::zip_equal(inReductionVars, syms.getValue(), byref.
asArrayRef()), p,
1106 auto [var, sym, isByRef] = t;
1114 llvm::interleaveComma(inReductionTypes, p);
1122struct MapParseArgs {
1123 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1124 SmallVectorImpl<Type> &types;
1125 MapParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1126 SmallVectorImpl<Type> &types)
1127 : vars(vars), types(types) {}
1129struct PrivateParseArgs {
1130 llvm::SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1131 llvm::SmallVectorImpl<Type> &types;
1133 UnitAttr &needsBarrier;
1135 PrivateParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1136 SmallVectorImpl<Type> &types,
ArrayAttr &syms,
1137 UnitAttr &needsBarrier,
1139 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1140 mapIndices(mapIndices) {}
1143struct ReductionParseArgs {
1144 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1145 SmallVectorImpl<Type> &types;
1148 ReductionModifierAttr *modifier;
1149 ReductionParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1151 ArrayAttr &syms, ReductionModifierAttr *mod =
nullptr)
1152 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1155struct AllRegionParseArgs {
1156 std::optional<MapParseArgs> hasDeviceAddrArgs;
1157 std::optional<MapParseArgs> hostEvalArgs;
1158 std::optional<ReductionParseArgs> inReductionArgs;
1159 std::optional<MapParseArgs> mapArgs;
1160 std::optional<PrivateParseArgs> privateArgs;
1161 std::optional<ReductionParseArgs> reductionArgs;
1162 std::optional<ReductionParseArgs> taskReductionArgs;
1163 std::optional<MapParseArgs> useDeviceAddrArgs;
1164 std::optional<MapParseArgs> useDevicePtrArgs;
1169 return "private_barrier";
1179 ReductionModifierAttr *modifier =
nullptr,
1180 UnitAttr *needsBarrier =
nullptr) {
1184 unsigned regionArgOffset = regionPrivateArgs.size();
1194 std::optional<ReductionModifier> enumValue =
1195 symbolizeReductionModifier(enumStr);
1196 if (!enumValue.has_value())
1198 *modifier = ReductionModifierAttr::get(parser.
getContext(), *enumValue);
1205 isByRefVec.push_back(
1206 parser.parseOptionalKeyword(
"byref").succeeded());
1208 if (symbols && parser.parseAttribute(symbolVec.emplace_back()))
1211 if (parser.parseOperand(operands.emplace_back()) ||
1212 parser.parseArrow() ||
1213 parser.parseArgument(regionPrivateArgs.emplace_back()))
1217 if (parser.parseOptionalLSquare().succeeded()) {
1218 if (parser.parseKeyword(
"map_idx") || parser.parseEqual() ||
1219 parser.parseInteger(mapIndicesVec.emplace_back()) ||
1220 parser.parseRSquare())
1223 mapIndicesVec.push_back(-1);
1235 if (parser.parseType(types.emplace_back()))
1242 if (operands.size() != types.size())
1251 *needsBarrier = mlir::UnitAttr::get(parser.
getContext());
1254 auto *argsBegin = regionPrivateArgs.begin();
1256 argsBegin + regionArgOffset + types.size());
1257 for (
auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
1263 *symbols = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1266 if (!mapIndicesVec.empty())
1279 StringRef keyword, std::optional<MapParseArgs> mapArgs) {
1294 StringRef keyword, std::optional<PrivateParseArgs> privateArgs) {
1300 parser, privateArgs->vars, privateArgs->types, entryBlockArgs,
1301 &privateArgs->syms, privateArgs->mapIndices,
nullptr,
1302 nullptr, &privateArgs->needsBarrier)))
1311 StringRef keyword, std::optional<ReductionParseArgs> reductionArgs) {
1316 parser, reductionArgs->vars, reductionArgs->types, entryBlockArgs,
1317 &reductionArgs->syms,
nullptr, &reductionArgs->byref,
1318 reductionArgs->modifier)))
1325 AllRegionParseArgs args) {
1329 args.hasDeviceAddrArgs)))
1331 <<
"invalid `has_device_addr` format";
1334 args.hostEvalArgs)))
1336 <<
"invalid `host_eval` format";
1339 args.inReductionArgs)))
1341 <<
"invalid `in_reduction` format";
1346 <<
"invalid `map_entries` format";
1351 <<
"invalid `private` format";
1354 args.reductionArgs)))
1356 <<
"invalid `reduction` format";
1359 args.taskReductionArgs)))
1361 <<
"invalid `task_reduction` format";
1364 args.useDeviceAddrArgs)))
1366 <<
"invalid `use_device_addr` format";
1369 args.useDevicePtrArgs)))
1371 <<
"invalid `use_device_addr` format";
1373 return parser.
parseRegion(region, entryBlockArgs);
1389 AllRegionParseArgs args;
1390 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1391 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1392 args.mapArgs.emplace(mapVars, mapTypes);
1393 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1394 privateNeedsBarrier, &privateMaps);
1405 UnitAttr &privateNeedsBarrier) {
1406 AllRegionParseArgs args;
1407 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1408 inReductionByref, inReductionSyms);
1409 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1410 privateNeedsBarrier);
1421 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1425 AllRegionParseArgs args;
1426 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1427 inReductionByref, inReductionSyms);
1428 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1429 privateNeedsBarrier);
1430 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1431 reductionSyms, &reductionMod);
1439 UnitAttr &privateNeedsBarrier) {
1440 AllRegionParseArgs args;
1441 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1442 privateNeedsBarrier);
1450 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1454 AllRegionParseArgs args;
1455 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1456 privateNeedsBarrier);
1457 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1458 reductionSyms, &reductionMod);
1467 AllRegionParseArgs args;
1468 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1469 taskReductionByref, taskReductionSyms);
1479 AllRegionParseArgs args;
1480 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1481 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1490struct MapPrintArgs {
1495struct PrivatePrintArgs {
1499 UnitAttr needsBarrier;
1503 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1504 mapIndices(mapIndices) {}
1506struct ReductionPrintArgs {
1511 ReductionModifierAttr modifier;
1513 ArrayAttr syms, ReductionModifierAttr mod =
nullptr)
1514 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1516struct AllRegionPrintArgs {
1517 std::optional<MapPrintArgs> hasDeviceAddrArgs;
1518 std::optional<MapPrintArgs> hostEvalArgs;
1519 std::optional<ReductionPrintArgs> inReductionArgs;
1520 std::optional<MapPrintArgs> mapArgs;
1521 std::optional<PrivatePrintArgs> privateArgs;
1522 std::optional<ReductionPrintArgs> reductionArgs;
1523 std::optional<ReductionPrintArgs> taskReductionArgs;
1524 std::optional<MapPrintArgs> useDeviceAddrArgs;
1525 std::optional<MapPrintArgs> useDevicePtrArgs;
1534 ReductionModifierAttr modifier =
nullptr, UnitAttr needsBarrier =
nullptr) {
1535 if (argsSubrange.empty())
1538 p << clauseName <<
"(";
1541 p <<
"mod: " << stringifyReductionModifier(modifier.getValue()) <<
", ";
1545 symbols = ArrayAttr::get(ctx, values);
1558 llvm::interleaveComma(llvm::zip_equal(operands, argsSubrange, symbols,
1559 mapIndices.asArrayRef(),
1560 byref.asArrayRef()),
1562 auto [op, arg, sym, map, isByRef] = t;
1568 p << op <<
" -> " << arg;
1571 p <<
" [map_idx=" << map <<
"]";
1574 llvm::interleaveComma(types, p);
1582 StringRef clauseName,
ValueRange argsSubrange,
1583 std::optional<MapPrintArgs> mapArgs) {
1590 StringRef clauseName,
ValueRange argsSubrange,
1591 std::optional<PrivatePrintArgs> privateArgs) {
1594 p, ctx, clauseName, argsSubrange, privateArgs->vars, privateArgs->types,
1595 privateArgs->syms, privateArgs->mapIndices,
nullptr,
1596 nullptr, privateArgs->needsBarrier);
1602 std::optional<ReductionPrintArgs> reductionArgs) {
1605 reductionArgs->vars, reductionArgs->types,
1606 reductionArgs->syms,
nullptr,
1607 reductionArgs->byref, reductionArgs->modifier);
1611 const AllRegionPrintArgs &args) {
1612 auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op);
1616 iface.getHasDeviceAddrBlockArgs(),
1617 args.hasDeviceAddrArgs);
1621 args.inReductionArgs);
1627 args.reductionArgs);
1629 iface.getTaskReductionBlockArgs(),
1630 args.taskReductionArgs);
1632 iface.getUseDeviceAddrBlockArgs(),
1633 args.useDeviceAddrArgs);
1635 iface.getUseDevicePtrBlockArgs(), args.useDevicePtrArgs);
1649 UnitAttr privateNeedsBarrier,
1651 AllRegionPrintArgs args;
1652 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1653 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1654 args.mapArgs.emplace(mapVars, mapTypes);
1655 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1656 privateNeedsBarrier, privateMaps);
1664 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier) {
1665 AllRegionPrintArgs args;
1666 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1667 inReductionByref, inReductionSyms);
1668 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1669 privateNeedsBarrier,
1678 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier,
1679 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1682 AllRegionPrintArgs args;
1683 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1684 inReductionByref, inReductionSyms);
1685 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1686 privateNeedsBarrier,
1688 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1689 reductionSyms, reductionMod);
1696 UnitAttr privateNeedsBarrier) {
1697 AllRegionPrintArgs args;
1698 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1699 privateNeedsBarrier,
1707 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1710 AllRegionPrintArgs args;
1711 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1712 privateNeedsBarrier,
1714 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1715 reductionSyms, reductionMod);
1725 AllRegionPrintArgs args;
1726 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1727 taskReductionByref, taskReductionSyms);
1737 AllRegionPrintArgs args;
1738 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1739 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1743template <
typename ParsePrefixFn>
1752 if (failed(parsePrefix()))
1760 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
1761 iteratedVars.push_back(v);
1762 iteratedTypes.push_back(ty);
1764 plainVars.push_back(v);
1765 plainTypes.push_back(ty);
1771template <
typename Pr
intPrefixFn>
1775 PrintPrefixFn &&printPrefixForPlain,
1776 PrintPrefixFn &&printPrefixForIterated) {
1783 p << v <<
" : " << t;
1787 for (
unsigned i = 0; i < iteratedVars.size(); ++i)
1788 emit(iteratedVars[i], iteratedTypes[i], printPrefixForIterated);
1789 for (
unsigned i = 0; i < plainVars.size(); ++i)
1790 emit(plainVars[i], plainTypes[i], printPrefixForPlain);
1798 if (!reductionVars.empty()) {
1799 if (!reductionSyms || reductionSyms->size() != reductionVars.size())
1801 <<
"expected as many reduction symbol references "
1802 "as reduction variables";
1803 if (reductionByref && reductionByref->size() != reductionVars.size())
1804 return op->
emitError() <<
"expected as many reduction variable by "
1805 "reference attributes as reduction variables";
1808 return op->
emitOpError() <<
"unexpected reduction symbol references";
1815 for (
auto args : llvm::zip(reductionVars, *reductionSyms)) {
1816 Value accum = std::get<0>(args);
1818 if (!accumulators.insert(accum).second)
1819 return op->
emitOpError() <<
"accumulator variable used more than once";
1822 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
1826 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1827 <<
" to point to a reduction declaration";
1829 if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
1831 <<
"expected accumulator (" << varType
1832 <<
") to be the same type as reduction declaration ("
1833 << decl.getAccumulatorType() <<
")";
1852 if (parser.parseOperand(copyprivateVars.emplace_back()) ||
1853 parser.parseArrow() ||
1854 parser.parseAttribute(symsVec.emplace_back()) ||
1855 parser.parseColonType(copyprivateTypes.emplace_back()))
1861 copyprivateSyms = ArrayAttr::get(parser.
getContext(), syms);
1869 std::optional<ArrayAttr> copyprivateSyms) {
1870 if (!copyprivateSyms.has_value())
1872 llvm::interleaveComma(
1873 llvm::zip(copyprivateVars, *copyprivateSyms, copyprivateTypes), p,
1874 [&](
const auto &args) {
1875 p << std::get<0>(args) <<
" -> " << std::get<1>(args) <<
" : "
1876 << std::get<2>(args);
1883 std::optional<ArrayAttr> copyprivateSyms) {
1884 size_t copyprivateSymsSize =
1885 copyprivateSyms.has_value() ? copyprivateSyms->size() : 0;
1886 if (copyprivateSymsSize != copyprivateVars.size())
1887 return op->
emitOpError() <<
"inconsistent number of copyprivate vars (= "
1888 << copyprivateVars.size()
1889 <<
") and functions (= " << copyprivateSymsSize
1890 <<
"), both must be equal";
1891 if (!copyprivateSyms.has_value())
1894 for (
auto copyprivateVarAndSym :
1895 llvm::zip(copyprivateVars, *copyprivateSyms)) {
1897 llvm::cast<SymbolRefAttr>(std::get<1>(copyprivateVarAndSym));
1898 std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
1900 if (mlir::func::FuncOp mlirFuncOp =
1903 funcOp = mlirFuncOp;
1904 else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
1907 funcOp = llvmFuncOp;
1909 auto getNumArguments = [&] {
1910 return std::visit([](
auto &f) {
return f.getNumArguments(); }, *funcOp);
1913 auto getArgumentType = [&](
unsigned i) {
1914 return std::visit([i](
auto &f) {
return f.getArgumentTypes()[i]; },
1919 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1920 <<
" to point to a copy function";
1922 if (getNumArguments() != 2)
1924 <<
"expected copy function " << symbolRef <<
" to have 2 operands";
1926 Type argTy = getArgumentType(0);
1927 if (argTy != getArgumentType(1))
1928 return op->
emitOpError() <<
"expected copy function " << symbolRef
1929 <<
" arguments to have the same type";
1931 Type varType = std::get<0>(copyprivateVarAndSym).getType();
1932 if (argTy != varType)
1934 <<
"expected copy function arguments' type (" << argTy
1935 <<
") to be the same as copyprivate variable's type (" << varType
1960 OpAsmParser::UnresolvedOperand operand;
1962 if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
1963 parser.parseOperand(operand) || parser.parseColonType(ty))
1965 std::optional<ClauseTaskDepend> keywordDepend =
1966 symbolizeClauseTaskDepend(keyword);
1970 ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend);
1971 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
1972 iteratedVars.push_back(operand);
1973 iteratedTypes.push_back(ty);
1974 iterKindsVec.push_back(kindAttr);
1976 dependVars.push_back(operand);
1977 dependTypes.push_back(ty);
1978 kindsVec.push_back(kindAttr);
1984 dependKinds = ArrayAttr::get(parser.
getContext(), kinds);
1986 iteratedKinds = ArrayAttr::get(parser.
getContext(), iterKinds);
1993 std::optional<ArrayAttr> dependKinds,
1996 std::optional<ArrayAttr> iteratedKinds) {
1999 std::optional<ArrayAttr> kinds) {
2000 for (
unsigned i = 0, e = vars.size(); i < e; ++i) {
2003 p << stringifyClauseTaskDepend(
2004 llvm::cast<mlir::omp::ClauseTaskDependAttr>((*kinds)[i])
2006 <<
" -> " << vars[i] <<
" : " << types[i];
2010 printEntries(dependVars, dependTypes, dependKinds);
2011 printEntries(iteratedVars, iteratedTypes, iteratedKinds);
2016 std::optional<ArrayAttr> dependKinds,
2018 std::optional<ArrayAttr> iteratedKinds,
2020 if (!dependVars.empty()) {
2021 if (!dependKinds || dependKinds->size() != dependVars.size())
2022 return op->
emitOpError() <<
"expected as many depend values"
2023 " as depend variables";
2025 if (dependKinds && !dependKinds->empty())
2026 return op->
emitOpError() <<
"unexpected depend values";
2029 if (!iteratedVars.empty()) {
2030 if (!iteratedKinds || iteratedKinds->size() != iteratedVars.size())
2031 return op->
emitOpError() <<
"expected as many depend iterated values"
2032 " as depend iterated variables";
2034 if (iteratedKinds && !iteratedKinds->empty())
2035 return op->
emitOpError() <<
"unexpected depend iterated values";
2050 IntegerAttr &hintAttr) {
2051 StringRef hintKeyword;
2057 auto parseKeyword = [&]() -> ParseResult {
2060 if (hintKeyword ==
"uncontended")
2062 else if (hintKeyword ==
"contended")
2064 else if (hintKeyword ==
"nonspeculative")
2066 else if (hintKeyword ==
"speculative")
2070 << hintKeyword <<
" is not a valid hint";
2081 IntegerAttr hintAttr) {
2082 int64_t hint = hintAttr.getInt();
2090 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2092 bool uncontended = bitn(hint, 0);
2093 bool contended = bitn(hint, 1);
2094 bool nonspeculative = bitn(hint, 2);
2095 bool speculative = bitn(hint, 3);
2099 hints.push_back(
"uncontended");
2101 hints.push_back(
"contended");
2103 hints.push_back(
"nonspeculative");
2105 hints.push_back(
"speculative");
2107 llvm::interleaveComma(hints, p);
2114 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2116 bool uncontended = bitn(hint, 0);
2117 bool contended = bitn(hint, 1);
2118 bool nonspeculative = bitn(hint, 2);
2119 bool speculative = bitn(hint, 3);
2121 if (uncontended && contended)
2122 return op->
emitOpError() <<
"the hints omp_sync_hint_uncontended and "
2123 "omp_sync_hint_contended cannot be combined";
2124 if (nonspeculative && speculative)
2125 return op->
emitOpError() <<
"the hints omp_sync_hint_nonspeculative and "
2126 "omp_sync_hint_speculative cannot be combined.";
2137 return (value & flag) == flag;
2145static ParseResult parseMapClause(
OpAsmParser &parser,
2146 ClauseMapFlagsAttr &mapType) {
2147 ClauseMapFlags mapTypeBits = ClauseMapFlags::none;
2150 auto parseTypeAndMod = [&]() -> ParseResult {
2151 StringRef mapTypeMod;
2155 if (mapTypeMod ==
"always")
2156 mapTypeBits |= ClauseMapFlags::always;
2158 if (mapTypeMod ==
"implicit")
2159 mapTypeBits |= ClauseMapFlags::implicit;
2161 if (mapTypeMod ==
"ompx_hold")
2162 mapTypeBits |= ClauseMapFlags::ompx_hold;
2164 if (mapTypeMod ==
"close")
2165 mapTypeBits |= ClauseMapFlags::close;
2167 if (mapTypeMod ==
"present")
2168 mapTypeBits |= ClauseMapFlags::present;
2170 if (mapTypeMod ==
"to")
2171 mapTypeBits |= ClauseMapFlags::to;
2173 if (mapTypeMod ==
"from")
2174 mapTypeBits |= ClauseMapFlags::from;
2176 if (mapTypeMod ==
"tofrom")
2177 mapTypeBits |= ClauseMapFlags::to | ClauseMapFlags::from;
2179 if (mapTypeMod ==
"delete")
2180 mapTypeBits |= ClauseMapFlags::del;
2182 if (mapTypeMod ==
"storage")
2183 mapTypeBits |= ClauseMapFlags::storage;
2185 if (mapTypeMod ==
"return_param")
2186 mapTypeBits |= ClauseMapFlags::return_param;
2188 if (mapTypeMod ==
"private")
2189 mapTypeBits |= ClauseMapFlags::priv;
2191 if (mapTypeMod ==
"literal")
2192 mapTypeBits |= ClauseMapFlags::literal;
2194 if (mapTypeMod ==
"attach")
2195 mapTypeBits |= ClauseMapFlags::attach;
2197 if (mapTypeMod ==
"attach_always")
2198 mapTypeBits |= ClauseMapFlags::attach_always;
2200 if (mapTypeMod ==
"attach_never")
2201 mapTypeBits |= ClauseMapFlags::attach_never;
2203 if (mapTypeMod ==
"attach_auto")
2204 mapTypeBits |= ClauseMapFlags::attach_auto;
2206 if (mapTypeMod ==
"ref_ptr")
2207 mapTypeBits |= ClauseMapFlags::ref_ptr;
2209 if (mapTypeMod ==
"ref_ptee")
2210 mapTypeBits |= ClauseMapFlags::ref_ptee;
2212 if (mapTypeMod ==
"is_device_ptr")
2213 mapTypeBits |= ClauseMapFlags::is_device_ptr;
2230 ClauseMapFlagsAttr mapType) {
2232 ClauseMapFlags mapFlags = mapType.getValue();
2237 mapTypeStrs.push_back(
"always");
2239 mapTypeStrs.push_back(
"implicit");
2241 mapTypeStrs.push_back(
"ompx_hold");
2243 mapTypeStrs.push_back(
"close");
2245 mapTypeStrs.push_back(
"present");
2254 mapTypeStrs.push_back(
"tofrom");
2256 mapTypeStrs.push_back(
"from");
2258 mapTypeStrs.push_back(
"to");
2261 mapTypeStrs.push_back(
"delete");
2263 mapTypeStrs.push_back(
"return_param");
2265 mapTypeStrs.push_back(
"storage");
2267 mapTypeStrs.push_back(
"private");
2269 mapTypeStrs.push_back(
"literal");
2271 mapTypeStrs.push_back(
"attach");
2273 mapTypeStrs.push_back(
"attach_always");
2275 mapTypeStrs.push_back(
"attach_never");
2277 mapTypeStrs.push_back(
"attach_auto");
2279 mapTypeStrs.push_back(
"ref_ptr");
2281 mapTypeStrs.push_back(
"ref_ptee");
2283 mapTypeStrs.push_back(
"is_device_ptr");
2284 if (mapFlags == ClauseMapFlags::none)
2285 mapTypeStrs.push_back(
"none");
2287 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
2288 p << mapTypeStrs[i];
2289 if (i + 1 < mapTypeStrs.size()) {
2295static ParseResult parseMembersIndex(
OpAsmParser &parser,
2299 auto parseIndices = [&]() -> ParseResult {
2304 APInt(64, value,
false)));
2318 memberIdxs.push_back(ArrayAttr::get(parser.
getContext(), values));
2322 if (!memberIdxs.empty())
2323 membersIdx = ArrayAttr::get(parser.
getContext(), memberIdxs);
2333 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
2335 auto memberIdx = cast<ArrayAttr>(v);
2336 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
2337 p << cast<IntegerAttr>(v2).getInt();
2344 VariableCaptureKindAttr mapCaptureType) {
2345 std::string typeCapStr;
2346 llvm::raw_string_ostream typeCap(typeCapStr);
2347 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
2349 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
2350 typeCap <<
"ByCopy";
2351 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
2352 typeCap <<
"VLAType";
2353 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
2359 VariableCaptureKindAttr &mapCaptureType) {
2360 StringRef mapCaptureKey;
2364 if (mapCaptureKey ==
"This")
2365 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2366 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
2367 if (mapCaptureKey ==
"ByRef")
2368 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2369 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
2370 if (mapCaptureKey ==
"ByCopy")
2371 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2372 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
2373 if (mapCaptureKey ==
"VLAType")
2374 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2375 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
2381 Operation *op, mlir::omp::MapInfoOp mapInfoOp,
2385 mlir::omp::ClauseMapFlags mapTypeBits = mapInfoOp.getMapType();
2388 bool from =
mapTypeToBool(mapTypeBits, ClauseMapFlags::from);
2391 bool always =
mapTypeToBool(mapTypeBits, ClauseMapFlags::always);
2392 bool close =
mapTypeToBool(mapTypeBits, ClauseMapFlags::close);
2393 bool implicit =
mapTypeToBool(mapTypeBits, ClauseMapFlags::implicit);
2394 bool attach =
mapTypeToBool(mapTypeBits, ClauseMapFlags::attach);
2396 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
2398 "to, from, tofrom and alloc map types are permitted");
2400 if (isa<TargetEnterDataOp>(op) && (from || del))
2401 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
2403 if (isa<TargetExitDataOp>(op) && to)
2405 "from, release and delete map types are permitted");
2407 if (isa<TargetUpdateOp>(op)) {
2410 "at least one of to or from map types must be "
2411 "specified, other map types are not permitted");
2414 if (!to && !from && !attach) {
2416 "at least one of to or from or attach map types must be "
2417 "specified, other map types are not permitted");
2420 auto updateVar = mapInfoOp.getVarPtr();
2422 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
2423 (from && updateToVars.contains(updateVar))) {
2426 "either to or from map types can be specified, not both");
2429 if (always || close || implicit) {
2432 "present, mapper and iterator map type modifiers are permitted");
2438 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
2442 if ((mapInfoOp.getVarPtrPtr() && !mapInfoOp.getVarPtrPtrType()) ||
2443 (!mapInfoOp.getVarPtrPtr() && mapInfoOp.getVarPtrPtrType())) {
2445 "if varPtrPtr or varPtrPtrType is specified, then both "
2457 for (
auto mapOp : mapVars) {
2458 if (!mapOp.getDefiningOp())
2461 if (
auto mapInfoOp = mapOp.getDefiningOp<mlir::omp::MapInfoOp>()) {
2465 }
else if (!isa<DeclareMapperInfoOp>(op)) {
2467 "map argument is not a map entry operation");
2472 for (
auto iterVal : mapIterated) {
2473 auto iterOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
2475 return op->
emitOpError() <<
"'map_iterated' arguments must be defined by "
2476 "'omp.iterator' ops";
2480 cast<mlir::omp::YieldOp>(iterOp.getRegion().front().getTerminator());
2481 auto yieldedMapInfo =
2482 yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
2483 if (!yieldedMapInfo)
2484 return op->
emitOpError() <<
"'map_iterated' iterator body must yield "
2485 "a value defined by 'omp.map.info'";
2495template <
typename OpType>
2499 std::optional<DenseI64ArrayAttr> privateMapIndices =
2500 targetOp.getPrivateMapsAttr();
2503 if (!privateMapIndices.has_value() || !privateMapIndices.value())
2508 if (privateMapIndices.value().size() !=
2509 static_cast<int64_t>(privateVars.size()))
2510 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
2511 "`private_maps` attribute mismatch");
2521 StringRef clauseName,
2523 for (
Value var : vars)
2524 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
2526 <<
"'" << clauseName
2527 <<
"' arguments must be defined by 'omp.map.info' ops";
2531LogicalResult MapInfoOp::verify() {
2532 if (getMapperId() &&
2534 *
this, getMapperIdAttr())) {
2549 const TargetDataOperands &clauses) {
2550 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
2551 clauses.mapVars, clauses.mapIterated,
2552 clauses.useDeviceAddrVars, clauses.useDevicePtrVars);
2555LogicalResult TargetDataOp::verify() {
2556 if (getMapVars().empty() && getMapIterated().empty() &&
2557 getUseDevicePtrVars().empty() && getUseDeviceAddrVars().empty()) {
2558 return ::emitError(this->getLoc(),
2559 "At least one of map, use_device_ptr_vars, or "
2560 "use_device_addr_vars operand must be present");
2564 getUseDevicePtrVars())))
2568 getUseDeviceAddrVars())))
2578void TargetEnterDataOp::build(
2582 TargetEnterDataOp::build(
2584 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2585 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2586 clauses.mapIterated, clauses.nowait);
2589LogicalResult TargetEnterDataOp::verify() {
2590 LogicalResult verifyDependVars =
2592 getDependIteratedKinds(), getDependIterated());
2593 return failed(verifyDependVars)
2605 TargetExitDataOp::build(
2607 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2608 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2609 clauses.mapIterated, clauses.nowait);
2612LogicalResult TargetExitDataOp::verify() {
2613 LogicalResult verifyDependVars =
2615 getDependIteratedKinds(), getDependIterated());
2616 return failed(verifyDependVars)
2628 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
2631 clauses.dependIterated, clauses.device, clauses.ifExpr,
2632 clauses.mapVars, clauses.mapIterated, clauses.nowait);
2635LogicalResult TargetUpdateOp::verify() {
2636 LogicalResult verifyDependVars =
2638 getDependIteratedKinds(), getDependIterated());
2639 return failed(verifyDependVars)
2653 builder, state, {}, {},
2654 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2655 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
2656 clauses.device, clauses.dynGroupprivateAccessGroup,
2657 clauses.dynGroupprivateFallback, clauses.dynGroupprivateSize,
2658 clauses.hasDeviceAddrVars, clauses.hostEvalVars, clauses.ifExpr,
2659 clauses.inReductionVars,
2661 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.isDevicePtrVars,
2662 clauses.mapVars, clauses.mapIterated, clauses.nowait, clauses.privateVars,
2663 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
2664 clauses.threadLimitVars,
nullptr, clauses.
kernelType);
2667bool TargetOp::hasHostEvalTripCount() {
2668 TargetExecMode mode = getKernelType();
2669 if (mode == TargetExecMode::spmd || mode == TargetExecMode::spmd_no_loop)
2672 if (mode == TargetExecMode::bare)
2678 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2679 if (
auto loopNestOp = dyn_cast_if_present<LoopNestOp>(capturedOp)) {
2681 loopNestOp.gatherWrappers(loopWrappers);
2683 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2684 if (isa<SimdOp>(innermostWrapper))
2685 innermostWrapper = std::next(innermostWrapper);
2687 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2688 if (numWrappers != 1)
2691 if (!isa<DistributeOp>(innermostWrapper))
2695 if (isa_and_present<TeamsOp>(parentOp) &&
2711 if (mapVarPtr == inReductionVar)
2717LogicalResult TargetOp::verify() {
2718 if (getKernelType() == TargetExecMode::bare && !isCombined())
2719 return emitOpError() <<
"bare kernel requires 'omp.combined'";
2722 getDependIteratedKinds(),
2723 getDependIterated())))
2727 getHasDeviceAddrVars())))
2734 *
this, getDynGroupprivateAccessGroupAttr(),
2735 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
2742 getInReductionVars(),
2743 getInReductionByref())))
2751 for (
Value inReductionVar : getInReductionVars()) {
2752 bool captured =
false;
2753 for (
Value mapVar : getMapVars()) {
2754 auto mapInfo = mapVar.getDefiningOp<MapInfoOp>();
2761 return emitOpError() <<
"in_reduction variable must be captured by a "
2762 "matching map_entries entry";
2768LogicalResult TargetOp::verifyRegions() {
2769 auto teamsOps = getOps<TeamsOp>();
2770 auto numNestedTeams = std::distance(teamsOps.begin(), teamsOps.end());
2771 if (numNestedTeams > 1)
2772 return emitError(
"target containing multiple 'omp.teams' nested ops");
2774 if (numNestedTeams == 0) {
2775 switch (getKernelType()) {
2776 case TargetExecMode::bare:
2778 <<
"bare kernel must contain a nested 'omp.teams' operation";
2779 case TargetExecMode::spmd_no_loop:
2780 return emitOpError() <<
"spmd_no_loop kernel must contain a nested "
2781 "'omp.teams' operation";
2788 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2789 if ((getKernelType() == TargetExecMode::spmd ||
2790 getKernelType() == TargetExecMode::spmd_no_loop) &&
2791 !isa_and_present<LoopNestOp>(capturedOp))
2793 <<
"SPMD kernel must capture an 'omp.loop_nest' operation";
2795 bool isTargetDevice =
false;
2796 if (
auto offloadMod = (*this)->getParentOfType<OffloadModuleInterface>())
2797 if (offloadMod.getIsTargetDevice())
2798 isTargetDevice =
true;
2802 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs();
2804 bool hostEvalTripCount = hasHostEvalTripCount();
2805 for (
Value hostEvalArg : hostEvalBlockArgs) {
2807 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
2809 if (hostEvalArg == teamsOp.getNumTeamsLower() ||
2810 llvm::is_contained(teamsOp.getNumTeamsUpperVars(), hostEvalArg) ||
2811 llvm::is_contained(teamsOp.getThreadLimitVars(), hostEvalArg))
2814 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
2815 "and 'thread_limit' in 'omp.teams'";
2817 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
2818 if (llvm::is_contained(parallelOp.getNumThreadsVars(), hostEvalArg))
2822 <<
"host_eval argument only legal as 'num_threads' in "
2825 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
2826 if (hostEvalTripCount &&
2827 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
2828 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
2829 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
2832 return emitOpError() <<
"host_eval argument only legal as loop bounds "
2833 "and steps in 'omp.loop_nest' when trip count "
2834 "must be evaluated in the host";
2837 return emitOpError() <<
"host_eval argument illegal use in '"
2838 << user->getName() <<
"' operation";
2842 if (hostEvalTripCount && !isTargetDevice) {
2843 auto loopOp = cast<LoopNestOp>(capturedOp);
2844 for (
auto arg : llvm::concat<Value>(loopOp.getLoopLowerBounds(),
2845 loopOp.getLoopUpperBounds(),
2846 loopOp.getLoopSteps())) {
2847 if (!llvm::is_contained(hostEvalBlockArgs, arg))
2848 return emitOpError() <<
"nested 'omp.loop_nest' bounds expected to "
2849 "be host-evaluated";
2862 ParallelOp::build(builder, state,
ValueRange(),
2874 const ParallelOperands &clauses) {
2876 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2877 clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
2879 clauses.privateNeedsBarrier, clauses.procBindKind,
2880 clauses.reductionMod, clauses.reductionVars,
2885template <
typename OpType>
2887 auto privateVars = op.getPrivateVars();
2888 auto privateSyms = op.getPrivateSymsAttr();
2890 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
2893 auto numPrivateVars = privateVars.size();
2894 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
2896 if (numPrivateVars != numPrivateSyms)
2897 return op.emitError() <<
"inconsistent number of private variables and "
2898 "privatizer op symbols, private vars: "
2900 <<
" vs. privatizer op symbols: " << numPrivateSyms;
2902 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
2903 Type varType = std::get<0>(privateVarInfo).getType();
2904 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
2905 PrivateClauseOp privatizerOp =
2908 if (privatizerOp ==
nullptr)
2909 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
2910 << privateSym <<
"'";
2912 Type privatizerType = privatizerOp.getArgType();
2914 if (privatizerType && (varType != privatizerType))
2915 return op.emitError()
2916 <<
"type mismatch between a "
2917 << (privatizerOp.getDataSharingType() ==
2918 DataSharingClauseType::Private
2921 <<
" variable and its privatizer op, var type: " << varType
2922 <<
" vs. privatizer op type: " << privatizerType;
2928LogicalResult ParallelOp::verify() {
2929 if (getAllocateVars().size() != getAllocatorVars().size())
2931 "expected equal sizes for allocate and allocator variables");
2937 getReductionByref());
2940LogicalResult ParallelOp::verifyRegions() {
2941 auto distChildOps = getOps<DistributeOp>();
2942 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
2943 if (numDistChildOps > 1)
2945 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
2947 if (numDistChildOps == 1) {
2950 <<
"'omp.composite' attribute missing from composite operation";
2952 auto *ompDialect =
getContext()->getLoadedDialect<OpenMPDialect>();
2953 Operation &distributeOp = **distChildOps.begin();
2955 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
2959 return emitError() <<
"unexpected OpenMP operation inside of composite "
2961 << childOp.getName();
2963 }
else if (isComposite()) {
2965 <<
"'omp.composite' attribute present in non-composite operation";
2982 const TeamsOperands &clauses) {
2986 builder, state, clauses.allocateVars, clauses.allocatorVars,
2987 clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
2988 clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
2989 clauses.numTeamsUpperVars, {},
nullptr,
2990 nullptr, clauses.reductionMod,
2991 clauses.reductionVars,
2993 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
3000 if (numTeamsLower) {
3001 if (numTeamsUpperVars.size() != 1)
3003 "expected exactly one num_teams upper bound when lower bound is "
3007 "expected num_teams upper bound and lower bound to be "
3014LogicalResult TeamsOp::verify() {
3021 auto parentTarget = llvm::dyn_cast_if_present<TargetOp>(op->
getParentOp());
3023 return emitError(
"expected to be nested inside of omp.target or not nested "
3024 "in any OpenMP dialect operations");
3028 this->getNumTeamsUpperVars())))
3032 parentTarget.getKernelType() == TargetExecMode::spmd_no_loop &&
3033 (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
3034 return emitOpError() <<
"'num_teams' not allowed in SPMD-no-loop kernels";
3037 if (getAllocateVars().size() != getAllocatorVars().size())
3039 "expected equal sizes for allocate and allocator variables");
3042 op, getDynGroupprivateAccessGroupAttr(),
3043 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3050 getReductionByref());
3058 return getParentOp().getPrivateVars();
3062 return getParentOp().getReductionVars();
3070 const SectionsOperands &clauses) {
3073 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3076 clauses.reductionMod, clauses.reductionVars,
3081LogicalResult SectionsOp::verify() {
3083 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3085 if (getAllocateVars().size() != getAllocatorVars().size())
3087 "expected equal sizes for allocate and allocator variables");
3090 getReductionByref());
3093LogicalResult SectionsOp::verifyRegions() {
3094 for (
auto &inst : *getRegion().begin()) {
3095 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
3097 <<
"expected omp.section op or terminator op inside region";
3109 const ScopeOperands &clauses) {
3111 ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3112 clauses.nowait, clauses.privateVars,
3114 clauses.privateNeedsBarrier, clauses.reductionMod,
3115 clauses.reductionVars,
3120LogicalResult ScopeOp::verify() {
3121 if (getAllocateVars().size() != getAllocatorVars().size())
3123 "expected equal sizes for allocate and allocator variables");
3129 getReductionByref());
3137 const SingleOperands &clauses) {
3140 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3141 clauses.copyprivateVars,
3142 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
3147LogicalResult SingleOp::verify() {
3149 if (getAllocateVars().size() != getAllocatorVars().size())
3151 "expected equal sizes for allocate and allocator variables");
3154 getCopyprivateSyms());
3162 const WorkshareOperands &clauses) {
3163 WorkshareOp::build(builder, state, clauses.nowait);
3166LogicalResult WorkshareOp::verify() {
3168 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3177LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
3178 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3180 return emitOpError() <<
"expected to be a standalone loop wrapper";
3189LogicalResult LoopWrapperInterface::verifyImpl() {
3193 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
3194 "and `SingleBlock` traits";
3197 return emitOpError() <<
"loop wrapper does not contain exactly one region";
3200 if (range_size(region.
getOps()) != 1)
3202 <<
"loop wrapper does not contain exactly one nested op";
3205 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
3206 return emitOpError() <<
"nested in loop wrapper is not another loop "
3207 "wrapper or `omp.loop_nest`";
3216Operation *ComposableOpInterface::findCapturedOp() {
3220 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(op))
3221 return wrapperOp.getWrappedLoop();
3226 if (!isCombined() && !isComposite())
3231 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(&nestedOp))
3232 return wrapperOp.getWrappedLoop();
3234 if (
auto composableOp = dyn_cast<ComposableOpInterface>(&nestedOp))
3235 return composableOp.findCapturedOp();
3244LogicalResult ComposableOpInterface::verifyImpl() {
3248 return emitOpError() <<
"composable ops must have a single region";
3250 if (isComposite() && !isa<LoopWrapperInterface, ParallelOp>(op))
3251 return emitOpError() <<
"non-loop wrapper cannot be composite";
3257 auto count = llvm::count_if(
3259 if (isa<ComposableOpInterface, LoopWrapperInterface>(op)) {
3281 <<
"multiple eligible child ops found in combined op";
3292 if (successor->isReachable(parentBlock))
3293 return emitOpError() <<
"nested combined child op is part of a loop";
3297 !domInfo.
dominates(parentBlock, &block))
3299 <<
"nested combined child op doesn't unconditionally execute";
3309 const LoopOperands &clauses) {
3312 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
3314 clauses.privateNeedsBarrier, clauses.order, clauses.orderMod,
3315 clauses.reductionMod, clauses.reductionVars,
3320LogicalResult LoopOp::verify() {
3325 getReductionByref());
3328LogicalResult LoopOp::verifyRegions() {
3329 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3331 return emitOpError() <<
"expected to be a standalone loop wrapper";
3342 build(builder, state, {}, {},
3345 false,
nullptr,
nullptr,
3346 nullptr, {},
nullptr,
3357 const WsloopOperands &clauses) {
3362 {}, {}, clauses.linearVars,
3363 clauses.linearStepVars, clauses.linearVarTypes, clauses.linearModifiers,
3364 clauses.nowait, clauses.order, clauses.orderMod, clauses.ordered,
3365 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3366 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3368 makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
3369 clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
3372LogicalResult WsloopOp::verify() {
3376 if (getLinearVars().size() &&
3377 getLinearVarTypes().value().size() != getLinearVars().size())
3378 return emitError() <<
"Ill-formed type attributes for linear variables";
3384 getReductionByref());
3387LogicalResult WsloopOp::verifyRegions() {
3388 bool isCompositeChildLeaf =
3389 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3391 if (LoopWrapperInterface nested = getNestedWrapper()) {
3394 <<
"'omp.composite' attribute missing from composite wrapper";
3398 if (!isa<SimdOp>(nested))
3399 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3401 }
else if (isComposite() && !isCompositeChildLeaf) {
3403 <<
"'omp.composite' attribute present in non-composite wrapper";
3404 }
else if (!isComposite() && isCompositeChildLeaf) {
3406 <<
"'omp.composite' attribute missing from composite wrapper";
3417 const SimdOperands &clauses) {
3419 SimdOp::build(builder, state, clauses.alignedVars,
3421 clauses.linearVars, clauses.linearStepVars,
3422 clauses.linearVarTypes, clauses.linearModifiers,
3423 clauses.nontemporalVars, clauses.order, clauses.orderMod,
3424 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3425 clauses.privateNeedsBarrier, clauses.reductionMod,
3426 clauses.reductionVars,
3432LogicalResult SimdOp::verify() {
3433 if (getSimdlen().has_value() && getSafelen().has_value() &&
3434 getSimdlen().value() > getSafelen().value())
3436 <<
"simdlen clause and safelen clause are both present, but the "
3437 "simdlen value is not less than or equal to safelen value";
3449 bool isCompositeChildLeaf =
3450 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3452 if (!isComposite() && isCompositeChildLeaf)
3454 <<
"'omp.composite' attribute missing from composite wrapper";
3456 if (isComposite() && !isCompositeChildLeaf)
3458 <<
"'omp.composite' attribute present in non-composite wrapper";
3462 std::optional<ArrayAttr> privateSyms = getPrivateSyms();
3464 for (
const Attribute &sym : *privateSyms) {
3465 auto symRef = cast<SymbolRefAttr>(sym);
3466 omp::PrivateClauseOp privatizer =
3468 getOperation(), symRef);
3470 return emitError() <<
"Cannot find privatizer '" << symRef <<
"'";
3471 if (privatizer.getDataSharingType() ==
3472 DataSharingClauseType::FirstPrivate)
3473 return emitError() <<
"FIRSTPRIVATE cannot be used with SIMD";
3480 if (getLinearVars().size() &&
3481 getLinearVarTypes().value().size() != getLinearVars().size())
3482 return emitError() <<
"Ill-formed type attributes for linear variables";
3486LogicalResult SimdOp::verifyRegions() {
3487 if (getNestedWrapper())
3488 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
3498 const DistributeOperands &clauses) {
3499 DistributeOp::build(builder, state, clauses.allocateVars,
3500 clauses.allocatorVars, clauses.distScheduleStatic,
3501 clauses.distScheduleChunkSize, clauses.order,
3502 clauses.orderMod, clauses.privateVars,
3504 clauses.privateNeedsBarrier);
3507LogicalResult DistributeOp::verify() {
3508 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
3510 "dist_schedule_static being present";
3512 if (getAllocateVars().size() != getAllocatorVars().size())
3514 "expected equal sizes for allocate and allocator variables");
3522LogicalResult DistributeOp::verifyRegions() {
3523 if (LoopWrapperInterface nested = getNestedWrapper()) {
3526 <<
"'omp.composite' attribute missing from composite wrapper";
3529 if (isa<WsloopOp>(nested)) {
3531 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
3532 !cast<ComposableOpInterface>(parentOp).isComposite()) {
3533 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
3534 "when a composite 'omp.parallel' is the direct "
3537 }
else if (!isa<SimdOp>(nested))
3538 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
3540 }
else if (isComposite()) {
3542 <<
"'omp.composite' attribute present in non-composite wrapper";
3553 const DeclareMapperInfoOperands &clauses) {
3554 DeclareMapperInfoOp::build(builder, state, clauses.mapVars,
3555 clauses.mapIterated);
3558LogicalResult DeclareMapperInfoOp::verify() {
3562LogicalResult DeclareMapperOp::verifyRegions() {
3563 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
3564 getRegion().getBlocks().front().getTerminator()))
3565 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
3574LogicalResult DeclareReductionOp::verifyRegions() {
3575 if (!getAllocRegion().empty()) {
3576 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
3577 if (yieldOp.getResults().size() != 1 ||
3578 yieldOp.getResults().getTypes()[0] !=
getType())
3579 return emitOpError() <<
"expects alloc region to yield a value "
3580 "of the reduction type";
3584 if (getInitializerRegion().empty())
3585 return emitOpError() <<
"expects non-empty initializer region";
3586 Block &initializerEntryBlock = getInitializerRegion().
front();
3589 if (!getAllocRegion().empty())
3590 return emitOpError() <<
"expects two arguments to the initializer region "
3591 "when an allocation region is used";
3593 if (getAllocRegion().empty())
3594 return emitOpError() <<
"expects one argument to the initializer region "
3595 "when no allocation region is used";
3598 <<
"expects one or two arguments to the initializer region";
3602 if (arg.getType() !=
getType())
3603 return emitOpError() <<
"expects initializer region argument to match "
3604 "the reduction type";
3606 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
3607 if (yieldOp.getResults().size() != 1 ||
3608 yieldOp.getResults().getTypes()[0] !=
getType())
3609 return emitOpError() <<
"expects initializer region to yield a value "
3610 "of the reduction type";
3613 if (getReductionRegion().empty())
3614 return emitOpError() <<
"expects non-empty reduction region";
3615 Block &reductionEntryBlock = getReductionRegion().
front();
3620 return emitOpError() <<
"expects reduction region with two arguments of "
3621 "the reduction type";
3622 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
3623 if (yieldOp.getResults().size() != 1 ||
3624 yieldOp.getResults().getTypes()[0] !=
getType())
3625 return emitOpError() <<
"expects reduction region to yield a value "
3626 "of the reduction type";
3629 if (!getAtomicReductionRegion().empty()) {
3630 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
3634 return emitOpError() <<
"expects atomic reduction region with two "
3635 "arguments of the same type";
3636 auto ptrType = llvm::dyn_cast<PointerLikeType>(
3639 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
3640 return emitOpError() <<
"expects atomic reduction region arguments to "
3641 "be accumulators containing the reduction type";
3644 if (getCleanupRegion().empty())
3646 Block &cleanupEntryBlock = getCleanupRegion().
front();
3649 return emitOpError() <<
"expects cleanup region with one argument "
3650 "of the reduction type";
3660 const TaskOperands &clauses) {
3663 builder, state, clauses.iterated, clauses.affinityVars,
3664 clauses.allocateVars, clauses.allocatorVars,
3665 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
3666 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
3667 clauses.final, clauses.ifExpr, clauses.inReductionVars,
3669 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3670 clauses.priority, clauses.privateVars,
3672 clauses.privateNeedsBarrier, clauses.untied, clauses.eventHandle);
3675LogicalResult TaskOp::verify() {
3676 LogicalResult verifyDependVars =
3678 getDependIteratedKinds(), getDependIterated());
3679 if (
failed(verifyDependVars))
3680 return verifyDependVars;
3686 getInReductionVars(), getInReductionByref());
3694 const TaskgroupOperands &clauses) {
3696 TaskgroupOp::build(builder, state, clauses.allocateVars,
3697 clauses.allocatorVars, clauses.taskReductionVars,
3702LogicalResult TaskgroupOp::verify() {
3704 getTaskReductionVars(),
3705 getTaskReductionByref());
3713 const TaskloopContextOperands &clauses) {
3715 TaskloopContextOp::build(
3716 builder, state, clauses.allocateVars, clauses.allocatorVars,
3717 clauses.final, clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
3718 clauses.inReductionVars,
3720 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3721 clauses.nogroup, clauses.numTasksMod, clauses.numTasks, clauses.priority,
3722 clauses.privateVars,
3724 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3727 state.
addAttribute(
"omp.combined", UnitAttr::get(ctx));
3730TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
3731 return cast<TaskloopWrapperOp>(
3733 return isa<TaskloopWrapperOp>(op);
3737LogicalResult TaskloopContextOp::verify() {
3738 if (getAllocateVars().size() != getAllocatorVars().size())
3740 "expected equal sizes for allocate and allocator variables");
3746 getReductionVars(), getReductionByref())) ||
3748 getInReductionVars(),
3749 getInReductionByref())))
3752 if (!getReductionVars().empty() && getNogroup())
3753 return emitError(
"if a reduction clause is present on the taskloop "
3754 "directive, the nogroup clause must not be specified");
3755 for (
auto var : getReductionVars()) {
3756 if (llvm::is_contained(getInReductionVars(), var))
3757 return emitError(
"the same list item cannot appear in both a reduction "
3758 "and an in_reduction clause");
3761 if (getGrainsize() && getNumTasks()) {
3763 "the grainsize clause and num_tasks clause are mutually exclusive and "
3764 "may not appear on the same taskloop directive");
3772 return emitOpError(
"must always contain the 'omp.combined' attribute");
3777LogicalResult TaskloopContextOp::verifyRegions() {
3778 Region ®ion = getRegion();
3780 return isa<TaskloopWrapperOp>(op);
3782 if (loopWrapperIt == region.
front().
end())
3784 <<
"expected a TaskloopWrapperOp directly nested in the region";
3786 auto loopWrapperOp = cast<TaskloopWrapperOp>(*loopWrapperIt);
3787 auto loopNestOp = dyn_cast<LoopNestOp>(loopWrapperOp.getWrappedLoop());
3793 std::function<
bool(
Value)> isValidBoundValue = [&](
Value value) ->
bool {
3794 Region *valueRegion = value.getParentRegion();
3800 Operation *defOp = value.getDefiningOp();
3804 return llvm::all_of(defOp->
getOperands(), isValidBoundValue);
3806 auto hasUnsupportedTaskloopLocalBound = [&](
OperandRange range) ->
bool {
3807 return llvm::any_of(range,
3808 [&](
Value value) {
return !isValidBoundValue(value); });
3811 if (hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopLowerBounds()) ||
3812 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopUpperBounds()) ||
3813 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopSteps())) {
3815 <<
"expects loop bounds and steps to be defined outside of the "
3816 "taskloop.context region or by pure, regionless operations "
3817 "that do not depend on block arguments";
3828 const TaskloopWrapperOperands &clauses) {
3829 TaskloopWrapperOp::build(builder, state);
3832TaskloopContextOp TaskloopWrapperOp::getTaskloopContext() {
3833 return dyn_cast<TaskloopContextOp>(getOperation()->getParentOp());
3836LogicalResult TaskloopWrapperOp::verify() {
3837 TaskloopContextOp context = getTaskloopContext();
3839 return emitOpError() <<
"expected to be nested in a taskloop context op";
3843LogicalResult TaskloopWrapperOp::verifyRegions() {
3844 if (LoopWrapperInterface nested = getNestedWrapper()) {
3847 <<
"'omp.composite' attribute missing from composite wrapper";
3851 if (!isa<SimdOp>(nested))
3852 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3853 }
else if (isComposite()) {
3855 <<
"'omp.composite' attribute present in non-composite wrapper";
3879 for (
auto &iv : ivs)
3880 iv.type = loopVarType;
3885 result.addAttribute(
"loop_inclusive", UnitAttr::get(ctx));
3901 "collapse_num_loops",
3906 auto parseTiles = [&]() -> ParseResult {
3910 tiles.push_back(
tile);
3919 if (tiles.size() > 0)
3938 Region ®ion = getRegion();
3940 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
3941 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
3942 if (getLoopInclusive())
3944 p <<
"step (" << getLoopSteps() <<
") ";
3945 if (
int64_t numCollapse = getCollapseNumLoops())
3946 if (numCollapse > 1)
3947 p <<
"collapse(" << numCollapse <<
") ";
3950 p <<
"tiles(" << tiles.value() <<
") ";
3956 const LoopNestOperands &clauses) {
3958 LoopNestOp::build(builder, state, clauses.collapseNumLoops,
3959 clauses.loopLowerBounds, clauses.loopUpperBounds,
3960 clauses.loopSteps, clauses.loopInclusive,
3964LogicalResult LoopNestOp::verify() {
3965 if (getLoopLowerBounds().empty())
3966 return emitOpError() <<
"must represent at least one loop";
3968 if (getLoopLowerBounds().size() != getIVs().size())
3969 return emitOpError() <<
"number of range arguments and IVs do not match";
3971 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
3972 if (lb.getType() != iv.getType())
3974 <<
"range argument type does not match corresponding IV type";
3977 uint64_t numIVs = getIVs().size();
3979 if (
const auto &numCollapse = getCollapseNumLoops())
3980 if (numCollapse > numIVs)
3982 <<
"collapse value is larger than the number of loops";
3985 if (tiles.value().size() > numIVs)
3986 return emitOpError() <<
"too few canonical loops for tile dimensions";
3988 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
3989 return emitOpError() <<
"expects parent op to be a loop wrapper";
3994void LoopNestOp::gatherWrappers(
3997 while (
auto wrapper =
3998 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
3999 wrappers.push_back(wrapper);
4008std::tuple<NewCliOp, OpOperand *, OpOperand *>
4014 return {{},
nullptr,
nullptr};
4017 "Unexpected type of cli");
4023 auto op = cast<LoopTransformationInterface>(use.getOwner());
4025 unsigned opnum = use.getOperandNumber();
4026 if (op.isGeneratee(opnum)) {
4027 assert(!gen &&
"Each CLI may have at most one def");
4029 }
else if (op.isApplyee(opnum)) {
4030 assert(!cons &&
"Each CLI may have at most one consumer");
4033 llvm_unreachable(
"Unexpected operand for a CLI");
4037 return {create, gen, cons};
4043 case llvm::omp::ProcBindKind::OMP_PROC_BIND_close:
4044 return ClauseProcBindKind::Close;
4045 case llvm::omp::ProcBindKind::OMP_PROC_BIND_master:
4046 return ClauseProcBindKind::Master;
4047 case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary:
4048 return ClauseProcBindKind::Primary;
4049 case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread:
4050 return ClauseProcBindKind::Spread;
4051 case llvm::omp::ProcBindKind::OMP_PROC_BIND_default:
4052 case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown:
4055 llvm_unreachable(
"unexpected proc-bind kind");
4078 std::string cliName{
"cli"};
4082 .Case([&](CanonicalLoopOp op) {
4085 .Case([&](UnrollHeuristicOp op) -> std::string {
4086 llvm_unreachable(
"heuristic unrolling does not generate a loop");
4088 .Case([&](FuseOp op) -> std::string {
4089 unsigned opnum =
generator->getOperandNumber();
4092 if (op.getFirst().has_value() && opnum != op.getFirst().value())
4093 return "canonloop_fuse";
4097 .Case([&](TileOp op) -> std::string {
4098 auto [generateesFirst, generateesCount] =
4099 op.getGenerateesODSOperandIndexAndLength();
4100 unsigned firstGrid = generateesFirst;
4101 unsigned firstIntratile = generateesFirst + generateesCount / 2;
4102 unsigned end = generateesFirst + generateesCount;
4103 unsigned opnum =
generator->getOperandNumber();
4105 if (firstGrid <= opnum && opnum < firstIntratile) {
4106 unsigned gridnum = opnum - firstGrid + 1;
4107 return (
"grid" + Twine(gridnum)).str();
4109 if (firstIntratile <= opnum && opnum < end) {
4110 unsigned intratilenum = opnum - firstIntratile + 1;
4111 return (
"intratile" + Twine(intratilenum)).str();
4113 llvm_unreachable(
"Unexpected generatee argument");
4115 .DefaultUnreachable(
"TODO: Custom name for this operation");
4118 setNameFn(
result, cliName);
4121LogicalResult NewCliOp::verify() {
4122 Value cli = getResult();
4125 "Unexpected type of cli");
4131 auto op = cast<mlir::omp::LoopTransformationInterface>(use.getOwner());
4133 unsigned opnum = use.getOperandNumber();
4134 if (op.isGeneratee(opnum)) {
4137 emitOpError(
"CLI must have at most one generator");
4139 .
append(
"first generator here:");
4141 .
append(
"second generator here:");
4146 }
else if (op.isApplyee(opnum)) {
4149 emitOpError(
"CLI must have at most one consumer");
4151 .
append(
"first consumer here:")
4155 .
append(
"second consumer here:")
4162 llvm_unreachable(
"Unexpected operand for a CLI");
4170 .
append(
"see consumer here: ")
4193 setNameFn(&getRegion().front(),
"body_entry");
4196void CanonicalLoopOp::getAsmBlockArgumentNames(
Region ®ion,
4204 p <<
'(' << getCli() <<
')';
4205 p <<
' ' << getInductionVar() <<
" : " << getInductionVar().getType()
4206 <<
" in range(" << getTripCount() <<
") ";
4216 CanonicalLoopInfoType cliType =
4217 CanonicalLoopInfoType::get(parser.
getContext());
4242 if (parser.
parseRegion(*region, {inductionVariable}))
4247 result.operands.append(cliOperand);
4253 return mlir::success();
4256LogicalResult CanonicalLoopOp::verify() {
4259 if (!getRegion().empty()) {
4260 Region ®ion = getRegion();
4263 "Canonical loop region must have exactly one argument");
4267 "Region argument must be the same type as the trip count");
4273Value CanonicalLoopOp::getInductionVar() {
return getRegion().getArgument(0); }
4275std::pair<unsigned, unsigned>
4276CanonicalLoopOp::getApplyeesODSOperandIndexAndLength() {
4281std::pair<unsigned, unsigned>
4282CanonicalLoopOp::getGenerateesODSOperandIndexAndLength() {
4283 return getODSOperandIndexAndLength(odsIndex_cli);
4297 p <<
'(' << getApplyee() <<
')';
4304 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4327 return mlir::success();
4330std::pair<unsigned, unsigned>
4331UnrollHeuristicOp ::getApplyeesODSOperandIndexAndLength() {
4332 return getODSOperandIndexAndLength(odsIndex_applyee);
4335std::pair<unsigned, unsigned>
4336UnrollHeuristicOp::getGenerateesODSOperandIndexAndLength() {
4346 uint64_t unrollFactor) {
4353 p <<
'(' << getApplyee() <<
')';
4360 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4377 return mlir::success();
4380std::pair<unsigned, unsigned>
4381UnrollPartialOp::getApplyeesODSOperandIndexAndLength() {
4382 return getODSOperandIndexAndLength(odsIndex_applyee);
4385std::pair<unsigned, unsigned>
4386UnrollPartialOp::getGenerateesODSOperandIndexAndLength() {
4397 if (!generatees.empty())
4398 p <<
'(' << llvm::interleaved(generatees) <<
')';
4400 if (!applyees.empty())
4401 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4443 bool isOnlyCanonLoops =
true;
4445 for (
Value applyee : op.getApplyees()) {
4446 auto [create, gen, cons] =
decodeCli(applyee);
4449 return op.emitOpError() <<
"applyee CLI has no generator";
4451 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4452 canonLoops.push_back(loop);
4454 isOnlyCanonLoops =
false;
4459 if (!isOnlyCanonLoops)
4463 for (
auto i : llvm::seq<int>(1, canonLoops.size())) {
4464 auto parentLoop = canonLoops[i - 1];
4465 auto loop = canonLoops[i];
4467 if (parentLoop.getOperation() != loop.getOperation()->getParentOp())
4468 return op.emitOpError()
4469 <<
"tiled loop nest must be nested within each other";
4471 parentIVs.insert(parentLoop.getInductionVar());
4476 bool isPerfectlyNested = [&]() {
4477 auto &parentBody = parentLoop.getRegion();
4478 if (!parentBody.hasOneBlock())
4480 auto &parentBlock = parentBody.getBlocks().
front();
4482 auto nestedLoopIt = parentBlock.
begin();
4483 if (nestedLoopIt == parentBlock.
end() ||
4484 (&*nestedLoopIt != loop.getOperation()))
4487 auto termIt = std::next(nestedLoopIt);
4488 if (termIt == parentBlock.
end() || !isa<TerminatorOp>(termIt))
4491 if (std::next(termIt) != parentBlock.
end())
4496 if (!isPerfectlyNested)
4497 return op.emitOpError() <<
"tiled loop nest must be perfectly nested";
4499 if (parentIVs.contains(loop.getTripCount()))
4500 return op.emitOpError() <<
"tiled loop nest must be rectangular";
4517LogicalResult TileOp::verify() {
4518 if (getApplyees().empty())
4519 return emitOpError() <<
"must apply to at least one loop";
4521 if (getSizes().size() != getApplyees().size())
4522 return emitOpError() <<
"there must be one tile size for each applyee";
4524 if (!getGeneratees().empty() &&
4525 2 * getSizes().size() != getGeneratees().size())
4527 <<
"expecting two times the number of generatees than applyees";
4532std::pair<unsigned, unsigned> TileOp ::getApplyeesODSOperandIndexAndLength() {
4533 return getODSOperandIndexAndLength(odsIndex_applyees);
4536std::pair<unsigned, unsigned> TileOp::getGenerateesODSOperandIndexAndLength() {
4537 return getODSOperandIndexAndLength(odsIndex_generatees);
4547 if (!generatees.empty())
4548 p <<
'(' << llvm::interleaved(generatees) <<
')';
4550 if (!applyees.empty())
4551 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4554LogicalResult FuseOp::verify() {
4555 if (getApplyees().size() < 2)
4556 return emitOpError() <<
"must apply to at least two loops";
4558 if (getFirst().has_value() && getCount().has_value()) {
4559 int64_t first = getFirst().value();
4560 int64_t count = getCount().value();
4561 if ((
unsigned)(first + count - 1) > getApplyees().size())
4562 return emitOpError() <<
"the numbers of applyees must be at least first "
4563 "minus one plus count attributes";
4564 if (!getGeneratees().empty() &&
4565 getGeneratees().size() != getApplyees().size() + 1 - count)
4566 return emitOpError() <<
"the number of generatees must be the number of "
4567 "aplyees plus one minus count";
4570 if (!getGeneratees().empty() && getGeneratees().size() != 1)
4572 <<
"in a complete fuse the number of generatees must be exactly 1";
4574 for (
auto &&applyee : getApplyees()) {
4575 auto [create, gen, cons] =
decodeCli(applyee);
4578 return emitOpError() <<
"applyee CLI has no generator";
4579 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4582 <<
"currently only supports omp.canonical_loop as applyee";
4586std::pair<unsigned, unsigned> FuseOp::getApplyeesODSOperandIndexAndLength() {
4587 return getODSOperandIndexAndLength(odsIndex_applyees);
4590std::pair<unsigned, unsigned> FuseOp::getGenerateesODSOperandIndexAndLength() {
4591 return getODSOperandIndexAndLength(odsIndex_generatees);
4599 const CriticalDeclareOperands &clauses) {
4600 CriticalDeclareOp::build(builder, state, clauses.symName, clauses.hint);
4603LogicalResult CriticalDeclareOp::verify() {
4608 if (getNameAttr()) {
4609 SymbolRefAttr symbolRef = getNameAttr();
4613 return emitOpError() <<
"expected symbol reference " << symbolRef
4614 <<
" to point to a critical declaration";
4634 return op.
emitOpError() <<
"must be nested inside of a loop";
4638 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
4639 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
4641 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
4642 "have an ordered clause";
4644 if (hasRegion && orderedAttr.getInt() != 0)
4645 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
4646 "have a parameter present";
4648 if (!hasRegion && orderedAttr.getInt() == 0)
4649 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
4650 "have a parameter present";
4651 }
else if (!isa<SimdOp>(wrapper)) {
4652 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
4653 "or worksharing simd loop";
4659 const OrderedOperands &clauses) {
4660 OrderedOp::build(builder, state, clauses.doacrossDependType,
4661 clauses.doacrossNumLoops, clauses.doacrossDependVars);
4664LogicalResult OrderedOp::verify() {
4668 auto wrapper = (*this)->getParentOfType<WsloopOp>();
4669 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
4670 return emitOpError() <<
"number of variables in depend clause does not "
4671 <<
"match number of iteration variables in the "
4678 const OrderedRegionOperands &clauses) {
4679 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
4689 const TaskwaitOperands &clauses) {
4705LogicalResult AtomicReadOp::verify() {
4706 if (verifyCommon().
failed())
4707 return mlir::failure();
4710 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4711 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4712 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4714 if (
auto mo = getMemoryOrder()) {
4715 if (*mo == ClauseMemoryOrderKind::Release) {
4716 return emitError(
"memory-order must not be release for atomic reads");
4718 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
4721 return emitError(
"memory-order must not be acq_rel for atomic reads");
4731LogicalResult AtomicWriteOp::verify() {
4732 if (verifyCommon().
failed())
4733 return mlir::failure();
4736 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4737 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4738 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4740 if (
auto mo = getMemoryOrder()) {
4741 if (*mo == ClauseMemoryOrderKind::Acquire) {
4742 return emitError(
"memory-order must not be acquire for atomic writes");
4744 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
4747 return emitError(
"memory-order must not be acq_rel for atomic writes");
4757LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4763 if (
Value writeVal = op.getWriteOpVal()) {
4765 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
4771LogicalResult AtomicUpdateOp::verify() {
4772 if (verifyCommon().
failed())
4773 return mlir::failure();
4776 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4777 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4778 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4780 if (
auto mo = getMemoryOrder()) {
4781 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
4782 *mo == ClauseMemoryOrderKind::Acquire) {
4786 "memory-order must not be acq_rel or acquire for atomic updates");
4793LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4799AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4800 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4802 return dyn_cast<AtomicReadOp>(getSecondOp());
4805AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4806 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4808 return dyn_cast<AtomicWriteOp>(getSecondOp());
4811AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4812 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4814 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4817LogicalResult AtomicCaptureOp::verify() {
4821LogicalResult AtomicCaptureOp::verifyRegions() {
4822 if (verifyRegionsCommon().
failed())
4823 return mlir::failure();
4825 if (getFirstOp()->getAttr(
"hint") || getSecondOp()->getAttr(
"hint"))
4827 "operations inside capture region must not have hint clause");
4829 if (getFirstOp()->getAttr(
"memory_order") ||
4830 getSecondOp()->getAttr(
"memory_order"))
4832 "operations inside capture region must not have memory_order clause");
4840LogicalResult AtomicCompareOp::verify() {
4841 if (verifyCommon().
failed())
4842 return mlir::failure();
4846LogicalResult AtomicCompareOp::verifyRegions() {
4847 if (verifyRegionsCommon().
failed())
4848 return mlir::failure();
4850 if (verifyOperator().
failed())
4851 return mlir::failure();
4856 if (!terminator || !isa<YieldOp>(terminator))
4857 return emitOpError(
"region must be terminated with omp.yield");
4867 const CancelOperands &clauses) {
4868 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
4881LogicalResult CancelOp::verify() {
4882 ClauseCancellationConstructType cct = getCancelDirective();
4885 if (!structuralParent)
4886 return emitOpError() <<
"Orphaned cancel construct";
4888 if ((cct == ClauseCancellationConstructType::Parallel) &&
4889 !mlir::isa<ParallelOp>(structuralParent)) {
4890 return emitOpError() <<
"cancel parallel must appear "
4891 <<
"inside a parallel region";
4893 if (cct == ClauseCancellationConstructType::Loop) {
4896 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
4900 <<
"cancel loop must appear inside a worksharing-loop region";
4902 if (wsloopOp.getNowaitAttr()) {
4903 return emitError() <<
"A worksharing construct that is canceled "
4904 <<
"must not have a nowait clause";
4906 if (wsloopOp.getOrderedAttr()) {
4907 return emitError() <<
"A worksharing construct that is canceled "
4908 <<
"must not have an ordered clause";
4911 }
else if (cct == ClauseCancellationConstructType::Sections) {
4915 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
4917 return emitOpError() <<
"cancel sections must appear "
4918 <<
"inside a sections region";
4920 if (sectionsOp.getNowait()) {
4921 return emitError() <<
"A sections construct that is canceled "
4922 <<
"must not have a nowait clause";
4925 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
4926 (!mlir::isa<omp::TaskOp>(structuralParent) &&
4927 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
4928 return emitOpError() <<
"cancel taskgroup must appear "
4929 <<
"inside a task region";
4939 const CancellationPointOperands &clauses) {
4940 CancellationPointOp::build(builder, state, clauses.cancelDirective);
4943LogicalResult CancellationPointOp::verify() {
4944 ClauseCancellationConstructType cct = getCancelDirective();
4947 if (!structuralParent)
4948 return emitOpError() <<
"Orphaned cancellation point";
4950 if ((cct == ClauseCancellationConstructType::Parallel) &&
4951 !mlir::isa<ParallelOp>(structuralParent)) {
4952 return emitOpError() <<
"cancellation point parallel must appear "
4953 <<
"inside a parallel region";
4957 if ((cct == ClauseCancellationConstructType::Loop) &&
4958 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
4959 return emitOpError() <<
"cancellation point loop must appear "
4960 <<
"inside a worksharing-loop region";
4962 if ((cct == ClauseCancellationConstructType::Sections) &&
4963 !mlir::isa<omp::SectionOp>(structuralParent)) {
4964 return emitOpError() <<
"cancellation point sections must appear "
4965 <<
"inside a sections region";
4967 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
4968 (!mlir::isa<omp::TaskOp>(structuralParent) &&
4969 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
4970 return emitOpError() <<
"cancellation point taskgroup must appear "
4971 <<
"inside a task region";
4980LogicalResult MapBoundsOp::verify() {
4981 auto extent = getExtent();
4983 if (!extent && !upperbound)
4984 return emitError(
"expected extent or upperbound.");
4991 PrivateClauseOp::build(
4992 odsBuilder, odsState, symName, type,
4993 DataSharingClauseTypeAttr::get(odsBuilder.
getContext(),
4994 DataSharingClauseType::Private));
4997LogicalResult PrivateClauseOp::verifyRegions() {
4998 Type argType = getArgType();
4999 auto verifyTerminator = [&](
Operation *terminator,
5000 bool yieldsValue) -> LogicalResult {
5004 if (!llvm::isa<YieldOp>(terminator))
5006 <<
"expected exit block terminator to be an `omp.yield` op.";
5008 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
5009 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
5012 if (yieldedTypes.empty())
5016 <<
"Did not expect any values to be yielded.";
5019 if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)
5023 <<
"Invalid yielded value. Expected type: " << argType
5026 if (yieldedTypes.empty())
5029 error << yieldedTypes;
5035 StringRef regionName,
5036 bool yieldsValue) -> LogicalResult {
5037 assert(!region.
empty());
5041 <<
"`" << regionName <<
"`: " <<
"expected " << expectedNumArgs
5044 for (
Block &block : region) {
5057 for (
Region *region : getRegions())
5058 for (
Type ty : region->getArgumentTypes())
5060 return emitError() <<
"Region argument type mismatch: got " << ty
5061 <<
" expected " << argType <<
".";
5064 if (!initRegion.
empty() &&
5069 DataSharingClauseType dsType = getDataSharingType();
5071 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
5072 return emitError(
"`private` clauses do not require a `copy` region.");
5074 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
5076 "`firstprivate` clauses require at least a `copy` region.");
5078 if (dsType == DataSharingClauseType::FirstPrivate &&
5083 if (!getDeallocRegion().empty() &&
5096 const MaskedOperands &clauses) {
5097 MaskedOp::build(builder, state, clauses.filteredThreadId);
5105 const ScanOperands &clauses) {
5106 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
5109LogicalResult ScanOp::verify() {
5110 if (hasExclusiveVars() == hasInclusiveVars())
5112 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
5113 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
5114 if (parentWsLoopOp.getReductionModAttr() &&
5115 parentWsLoopOp.getReductionModAttr().getValue() ==
5116 ReductionModifier::inscan)
5119 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
5120 if (parentSimdOp.getReductionModAttr() &&
5121 parentSimdOp.getReductionModAttr().getValue() ==
5122 ReductionModifier::inscan)
5125 return emitError(
"SCAN directive needs to be enclosed within a parent "
5126 "worksharing loop construct or SIMD construct with INSCAN "
5127 "reduction modifier");
5132 std::optional<uint64_t> alignment) {
5133 if (alignment.has_value()) {
5134 if ((alignment.value() != 0) && !llvm::has_single_bit(alignment.value()))
5136 <<
"ALIGN value : " << alignment.value() <<
" must be power of 2";
5141LogicalResult AllocateDirOp::verify() {
5149LogicalResult AllocSharedMemOp::verify() {
5157LogicalResult FreeSharedMemOp::verify() {
5165LogicalResult WorkdistributeOp::verify() {
5167 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
5170 Region ®ion = getRegion();
5175 if (entryBlock.
empty())
5176 return emitOpError(
"region must contain a structured block");
5178 bool hasTerminator =
false;
5179 for (
Block &block : region) {
5180 if (isa<TerminatorOp>(block.
back())) {
5181 if (hasTerminator) {
5182 return emitOpError(
"region must have exactly one terminator");
5184 hasTerminator =
true;
5187 if (!hasTerminator) {
5188 return emitOpError(
"region must be terminated with omp.terminator");
5192 if (isa<BarrierOp>(op)) {
5194 "explicit barriers are not allowed in workdistribute region");
5197 if (isa<ParallelOp>(op)) {
5199 "nested parallel constructs not allowed in workdistribute");
5201 if (isa<TeamsOp>(op)) {
5203 "nested teams constructs not allowed in workdistribute");
5207 if (walkResult.wasInterrupted())
5211 if (!llvm::dyn_cast<TeamsOp>(parentOp))
5212 return emitOpError(
"workdistribute must be nested under teams");
5220LogicalResult DeclareSimdOp::verify() {
5223 dyn_cast_if_present<mlir::FunctionOpInterface>((*this)->getParentOp());
5225 return emitOpError() <<
"must be nested inside a function";
5227 if (getInbranch() && getNotinbranch())
5228 return emitOpError(
"cannot have both 'inbranch' and 'notinbranch'");
5238 const DeclareSimdOperands &clauses) {
5240 DeclareSimdOp::build(odsBuilder, odsState, clauses.alignedVars,
5242 clauses.linearVars, clauses.linearStepVars,
5243 clauses.linearVarTypes, clauses.linearModifiers,
5244 clauses.notinbranch, clauses.simdlen,
5245 clauses.uniformVars);
5262 return mlir::failure();
5263 return mlir::success();
5270 for (
unsigned i = 0; i < uniformVars.size(); ++i) {
5273 p << uniformVars[i] <<
" : " << uniformTypes[i];
5288 parser, iterated, iteratedTypes, affinityVars, affinityVarTypes,
5289 [&]() -> ParseResult {
return success(); })))
5323 OpAsmParser::Argument &arg = ivArgs.emplace_back();
5324 if (parser.parseArgument(arg))
5328 if (succeeded(parser.parseOptionalColon())) {
5329 if (parser.parseType(arg.type))
5332 arg.type = parser.getBuilder().getIndexType();
5344 OpAsmParser::UnresolvedOperand lb, ub, st;
5345 if (parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
5346 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
5347 parser.parseOperand(st))
5352 steps.push_back(st);
5360 if (ivArgs.size() != lbs.size())
5362 <<
"mismatch: " << ivArgs.size() <<
" variables but " << lbs.size()
5365 for (
auto &arg : ivArgs) {
5366 lbTypes.push_back(arg.type);
5367 ubTypes.push_back(arg.type);
5368 stepTypes.push_back(arg.type);
5388 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
5391 p << lbs[i] <<
" to " << ubs[i] <<
" step " << steps[i];
5399LogicalResult IteratorOp::verify() {
5400 auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().
getType());
5402 return emitOpError() <<
"result must be omp.iterated<entry_ty>";
5404 for (
auto [lb,
ub, step] : llvm::zip_equal(
5405 getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
5407 return emitOpError() <<
"loop step must not be zero";
5411 IntegerAttr stepAttr;
5417 const APInt &lbVal = lbAttr.getValue();
5418 const APInt &ubVal = ubAttr.getValue();
5419 const APInt &stepVal = stepAttr.getValue();
5420 if (stepVal.isStrictlyPositive() && lbVal.sgt(ubVal))
5421 return emitOpError() <<
"positive loop step requires lower bound to be "
5422 "less than or equal to upper bound";
5423 if (stepVal.isNegative() && lbVal.slt(ubVal))
5424 return emitOpError() <<
"negative loop step requires lower bound to be "
5425 "greater than or equal to upper bound";
5428 Block &
b = getRegion().front();
5429 auto yield = llvm::dyn_cast<omp::YieldOp>(
b.getTerminator());
5432 return emitOpError() <<
"region must be terminated by omp.yield";
5434 if (yield.getNumOperands() != 1)
5436 <<
"omp.yield in omp.iterator region must yield exactly one value";
5438 mlir::Type yieldedTy = yield.getOperand(0).getType();
5439 mlir::Type elemTy = iteratedTy.getElementType();
5441 if (yieldedTy != elemTy)
5442 return emitOpError() <<
"omp.iterated element type (" << elemTy
5443 <<
") does not match omp.yield operand type ("
5444 << yieldedTy <<
")";
5457 return emitOpError() <<
"expected symbol reference '" << getSymName()
5458 <<
"' to point to a global variable";
5460 if (isa<FunctionOpInterface>(symbol))
5461 return emitOpError() <<
"expected symbol reference '" << getSymName()
5462 <<
"' to point to a global variable, not a function";
5467#define GET_ATTRDEF_CLASSES
5468#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
5470#define GET_OP_CLASSES
5471#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
5473#define GET_TYPEDEF_CLASSES
5474#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
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 Type getElementType(Type type)
Determine the element type of type.
static const mlir::GenInfo * generator
static LogicalResult verifyNontemporalClause(Operation *op, OperandRange nontemporalVars)
static DenseI64ArrayAttr makeDenseI64ArrayAttr(MLIRContext *ctx, const ArrayRef< int64_t > intArray)
static void printDependVarList(OpAsmPrinter &p, Operation *op, OperandRange dependVars, TypeRange dependTypes, std::optional< ArrayAttr > dependKinds, OperandRange iteratedVars, TypeRange iteratedTypes, std::optional< ArrayAttr > iteratedKinds)
Print Depend clause.
static ParseResult parseTargetOpRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hasDeviceAddrVars, SmallVectorImpl< Type > &hasDeviceAddrTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hostEvalVars, SmallVectorImpl< Type > &hostEvalTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &mapVars, SmallVectorImpl< Type > &mapTypes, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, UnitAttr &privateNeedsBarrier, DenseI64ArrayAttr &privateMaps)
static constexpr StringRef getPrivateNeedsBarrierSpelling()
static void printHeapAllocClause(OpAsmPrinter &p, Operation *op, TypeAttr inType, ValueRange typeparams, TypeRange typeparamsTypes, ValueRange shape, TypeRange shapeTypes)
static LogicalResult verifyReductionVarList(Operation *op, std::optional< ArrayAttr > reductionSyms, OperandRange reductionVars, std::optional< ArrayRef< bool > > reductionByref)
Verifies Reduction Clause.
static ParseResult parseLinearClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearVars, SmallVectorImpl< Type > &linearTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearStepVars, SmallVectorImpl< Type > &linearStepTypes, ArrayAttr &linearModifiers)
linear ::= linear ( linear-list ) linear-list := linear-val | linear-val linear-list linear-val := ss...
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, UnitAttr &privateNeedsBarrier)
static ArrayAttr makeArrayAttr(MLIRContext *context, llvm::ArrayRef< Attribute > attrs)
static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr)
static void printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op, AccessGroupModifierAttr modifierFirst, FallbackModifierAttr modifierSecond, Value dynGroupprivateSize, Type sizeType)
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 std::string generateLoopNestingName(StringRef prefix, CanonicalLoopOp op)
Generate a name of a canonical loop nest of the format <prefix>(_r<idx>_s<idx>)*.
static ParseResult parseAffinityClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &iterated, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &affinityVars, SmallVectorImpl< Type > &iteratedTypes, SmallVectorImpl< Type > &affinityVarTypes)
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, UnitAttr needsBarrier=nullptr)
static void printSplitIteratedList(OpAsmPrinter &p, ValueRange iteratedVars, TypeRange iteratedTypes, ValueRange plainVars, TypeRange plainTypes, PrintPrefixFn &&printPrefixForPlain, PrintPrefixFn &&printPrefixForIterated)
static LogicalResult verifyDependVarList(Operation *op, std::optional< ArrayAttr > dependKinds, OperandRange dependVars, std::optional< ArrayAttr > iteratedKinds, OperandRange iteratedVars)
Verifies Depend clause.
static void printBlockArgClause(OpAsmPrinter &p, MLIRContext *ctx, StringRef clauseName, ValueRange argsSubrange, std::optional< MapPrintArgs > mapArgs)
static void printAffinityClause(OpAsmPrinter &p, Operation *op, ValueRange iterated, ValueRange affinityVars, TypeRange iteratedTypes, TypeRange affinityVarTypes)
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 void printIteratorHeader(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lbs, ValueRange ubs, ValueRange steps, TypeRange, TypeRange, TypeRange)
static ParseResult parseHeapAllocClause(OpAsmParser &parser, TypeAttr &inTypeAttr, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &typeparams, SmallVectorImpl< Type > &typeparamsTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &shape, SmallVectorImpl< Type > &shapeTypes)
operation ::= $in_type ( ( $typeparams ) )? ( , $shape )?
static void printInReductionClause(OpAsmPrinter &p, Operation *op, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms)
Prints an in_reduction clause for an operation that does not give its list items entry block argument...
static ParseResult parseIteratorHeader(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &lbs, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &ubs, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &steps, SmallVectorImpl< Type > &lbTypes, SmallVectorImpl< Type > &ubTypes, SmallVectorImpl< Type > &stepTypes)
static ParseResult parseBlockArgRegion(OpAsmParser &parser, Region ®ion, AllRegionParseArgs args)
static ParseResult parseLoopTransformClis(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &generateesOperands, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &applyeesOperands)
static ParseResult parseSynchronizationHint(OpAsmParser &parser, IntegerAttr &hintAttr)
Parses a Synchronization Hint clause.
static void printScheduleClause(OpAsmPrinter &p, Operation *op, ClauseScheduleKindAttr scheduleKind, ScheduleModifierAttr scheduleMod, UnitAttr scheduleSimd, Value scheduleChunk, Type scheduleChunkType)
Print schedule clause.
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 bool mapTypeToBool(ClauseMapFlags value, ClauseMapFlags flag)
static void printAlignedClause(OpAsmPrinter &p, Operation *op, ValueRange alignedVars, TypeRange alignedTypes, std::optional< ArrayAttr > alignments)
Print Aligned Clause.
static bool targetInReductionCapturedBy(Value inReductionVar, Value mapVarPtr)
An omp.target in_reduction operand is captured by a map_entries entry when the entry's MapInfoOp var_...
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 ParseResult parseUniformClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &uniformVars, SmallVectorImpl< Type > &uniformTypes)
uniform ::= uniform ( uniform-list ) uniform-list := uniform-val (, uniform-val)* uniform-val := ssa-...
static void printInReductionPrivateReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier, ReductionModifierAttr reductionMod, ValueRange reductionVars, TypeRange reductionTypes, DenseBoolArrayAttr reductionByref, ArrayAttr reductionSyms)
static void printInReductionPrivateRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange inReductionVars, TypeRange inReductionTypes, DenseBoolArrayAttr inReductionByref, ArrayAttr inReductionSyms, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier)
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 ParseResult parseDependVarList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &dependVars, SmallVectorImpl< Type > &dependTypes, ArrayAttr &dependKinds, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &iteratedVars, SmallVectorImpl< Type > &iteratedTypes, ArrayAttr &iteratedKinds)
depend-entry-list ::= depend-entry | depend-entry-list , depend-entry depend-entry ::= depend-kind ->...
static Operation * getParentInSameDialect(Operation *thisOp)
static void printUniformClause(OpAsmPrinter &p, Operation *op, ValueRange uniformVars, TypeRange uniformTypes)
Print Uniform Clauses.
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 ParseResult parsePrivateRegion(OpAsmParser &parser, Region ®ion, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, UnitAttr &privateNeedsBarrier)
static void printNumTasksClause(OpAsmPrinter &p, Operation *op, ClauseNumTasksTypeAttr numTasksMod, Value numTasks, mlir::Type numTasksType)
static void printLoopTransformClis(OpAsmPrinter &p, TileOp op, OperandRange generatees, OperandRange applyees)
static ParseResult parseDynGroupprivateClause(OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr, FallbackModifierAttr &fallbackAttr, std::optional< OpAsmParser::UnresolvedOperand > &dynGroupprivateSize, Type &sizeType)
static void printPrivateRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier)
static void printPrivateReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier, ReductionModifierAttr reductionMod, ValueRange reductionVars, TypeRange reductionTypes, DenseBoolArrayAttr reductionByref, ArrayAttr reductionSyms)
static ParseResult parseSplitIteratedList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &iteratedVars, SmallVectorImpl< Type > &iteratedTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &plainVars, SmallVectorImpl< Type > &plainTypes, ParsePrefixFn &&parsePrefix)
static void printTaskReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange taskReductionVars, TypeRange taskReductionTypes, DenseBoolArrayAttr taskReductionByref, ArrayAttr taskReductionSyms)
static LogicalResult verifyMapInfoForMapClause(Operation *op, mlir::omp::MapInfoOp mapInfoOp, llvm::DenseSet< mlir::TypedValue< mlir::omp::PointerLikeType > > &updateToVars, llvm::DenseSet< mlir::TypedValue< mlir::omp::PointerLikeType > > &updateFromVars)
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 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, UnitAttr *needsBarrier=nullptr)
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 LogicalResult verifyDynGroupprivateClause(Operation *op, AccessGroupModifierAttr accessGroup, FallbackModifierAttr fallback, Value dynGroupprivateSize)
static LogicalResult verifyLinearModifiers(Operation *op, std::optional< ArrayAttr > linearModifiers, OperandRange linearVars, bool isDeclareSimd=false)
OpenMP 5.2, Section 5.4.6: "A linear-modifier may be specified as ref or uval only on a declare simd ...
static void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr)
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 void printCaptureType(OpAsmPrinter &p, Operation *op, VariableCaptureKindAttr mapCaptureType)
static LogicalResult verifyNumTeamsClause(Operation *op, Value numTeamsLower, OperandRange numTeamsUpperVars)
static bool opInGlobalImplicitParallelRegion(Operation *op)
static void printTargetOpRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange hasDeviceAddrVars, TypeRange hasDeviceAddrTypes, ValueRange hostEvalVars, TypeRange hostEvalTypes, ValueRange mapVars, TypeRange mapTypes, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier, DenseI64ArrayAttr privateMaps)
static void printUseDeviceAddrUseDevicePtrRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange useDeviceAddrVars, TypeRange useDeviceAddrTypes, ValueRange useDevicePtrVars, TypeRange useDevicePtrTypes)
static LogicalResult verifyMapClause(Operation *op, OperandRange mapVars, OperandRange mapIterated)
static LogicalResult verifyPrivateVarList(OpType &op)
static ParseResult parseNumTasksClause(OpAsmParser &parser, ClauseNumTasksTypeAttr &numTasksMod, std::optional< OpAsmParser::UnresolvedOperand > &numTasks, Type &numTasksType)
LogicalResult verifyAlignment(Operation &op, std::optional< uint64_t > alignment)
Verifies align clause in allocate directive.
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 ParseResult parsePrivateReductionRegion(OpAsmParser &parser, Region ®ion, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionVars, SmallVectorImpl< Type > &reductionTypes, DenseBoolArrayAttr &reductionByref, ArrayAttr &reductionSyms)
static void printLinearClause(OpAsmPrinter &p, Operation *op, ValueRange linearVars, TypeRange linearTypes, ValueRange linearStepVars, TypeRange stepVarTypes, ArrayAttr linearModifiers)
Print Linear Clause.
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, UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &reductionVars, SmallVectorImpl< Type > &reductionTypes, DenseBoolArrayAttr &reductionByref, ArrayAttr &reductionSyms)
static LogicalResult checkApplyeesNesting(TileOp op)
Check properties of the loop nest consisting of the transformation's applyees:
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 ParseResult parseInReductionClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms)
Parses an in_reduction clause for an operation that does not give its list items entry block argument...
static LogicalResult verifyMapInfoDefinedArgs(Operation *op, StringRef clauseName, OperandRange vars)
static void printGrainsizeClause(OpAsmPrinter &p, Operation *op, ClauseGrainsizeTypeAttr grainsizeMod, Value grainsize, mlir::Type grainsizeType)
static ParseResult verifyScheduleModifiers(OpAsmParser &parser, SmallVectorImpl< SmallString< 12 > > &modifiers)
static bool isUnique(It begin, It end)
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
static SmallVector< Value > getTileSizes(Location loc, x86::amx::TileType tType, RewriterBase &rewriter)
Maps the 2-dim vector shape to the two 16-bit tile sizes.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseMinus()=0
Parse a '-' token.
@ Paren
Parens surrounding zero or more operands.
@ 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 Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
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 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 parseOptionalArrow()=0
Parse a '->' token if present.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalLess()=0
Parse a '<' token if present.
virtual ParseResult parseArrow()=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.
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()
Operation * getTerminator()
Get the terminator operation of this block.
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
BlockArgListType getArguments()
IntegerAttr getI64IntegerAttr(int64_t value)
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
Diagnostic & append(Arg1 &&arg1, Arg2 &&arg2, Args &&...args)
Append arguments to the diagnostic.
Diagnostic & appendOp(Operation &op, const OpPrintingFlags &flags)
Append an operation with the given printing flags.
A class for computing basic dominance information.
bool dominates(Operation *a, Operation *b) const
Return true if operation A dominates operation B, i.e.
This class represents a diagnostic that is inflight and set to be reported.
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
MLIRContext is the top-level object for a collection of MLIR operations.
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 parseArgument(Argument &result, bool allowType=false, bool allowAttrs=false)=0
Parse a single argument with the following syntax:
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 resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
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 printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
virtual void printRegionArgument(BlockArgument arg, ArrayRef< NamedAttribute > argAttrs={}, bool omitType=false)=0
Print a block argument in the usual format of: ssaName : type {attr1=42} loc("here") where location p...
virtual void printOperand(Value value)=0
Print implementations for various things an operation contains.
This class helps build Operations.
This class represents an operand of an operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
This class provides the API for ops that are known to be isolated from above.
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.
type_range getType() const
Operation is the basic unit of execution within MLIR.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Block * getBlock()
Returns the operation block that contains this operation.
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...
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
operand_range getOperands()
Returns an iterator on the underlying Value's.
user_range getUsers()
Returns a range of all users.
Region * getParentRegion()
Returns the region to which the instruction belongs.
MLIRContext * getContext()
Return the context this operation is associated with.
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.
BlockArgListType getArguments()
OpIterator op_begin()
Return iterators that walk the operations nested directly within this region.
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
iterator_range< OpIterator > getOps()
unsigned getNumArguments()
Location getLoc()
Return a location for this region.
BlockArgument getArgument(unsigned i)
Operation * getParentOp()
Return the parent operation this region is attached to.
BlockListType & getBlocks()
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 collection of SymbolTables.
virtual Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
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...
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...
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Type getType() const
Return the type of this value.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< bool > content)
ArrayRef< T > asArrayRef() const
bool isReachableFromEntry(Block *a) const
Return true if the specified block is reachable from the entry block of its region.
Operation * getOwner() const
Return the owner of this operand.
TargetEnterDataOperands TargetEnterExitUpdateDataOperands
omp.target_enter_data, omp.target_exit_data and omp.target_update take the same clauses,...
std::tuple< NewCliOp, OpOperand *, OpOperand * > decodeCli(mlir::Value cli)
Find the omp.new_cli, generator, and consumer of a canonical loop info.
ClauseProcBindKind convertProcBindKind(llvm::omp::ProcBindKind kind)
Convert a proc_bind kind from the LLVM frontend enum to the corresponding OpenMP dialect enum.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
A functor used to set the name of the start of a result group of an operation.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool isPure(Operation *op)
Returns true if the given operation is pure, i.e., is speculatable that does not touch memory.
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
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.
llvm::TypeSwitch< T, ResultT > TypeSwitch
SmallVector< Loops, 8 > tile(ArrayRef< scf::ForOp > forOps, ArrayRef< Value > sizes, ArrayRef< scf::ForOp > targets)
Performs tiling fo imperfectly nested loops (with interchange) by strip-mining the forOps by sizes an...
detail::DenseArrayAttrImpl< bool > DenseBoolArrayAttr
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
function_ref< void(Block *, StringRef)> OpAsmSetBlockNameFn
A functor used to set the name of blocks in regions directly nested under an operation.
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.
T & getOrAddProperties()
Get (or create) the properties of the provided type to be set on the operation on creation.
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
void addTypes(ArrayRef< Type > newTypes)
Region * addRegion()
Create a region that should be attached to the operation.
Extended TargetOperands with kernel_type attribute.
TargetExecModeAttr kernelType
Kernel execution mode for the target region.