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];
627 ArrayAttr privateSyms =
nullptr,
bool requirePrivateIndices =
false) {
628 if (allocateVars.size() != allocatorVars.size())
630 "expected equal sizes for allocate and allocator variables");
632 if (allocateVars.empty()) {
633 if (allocateAlignments)
635 "unexpected allocate alignments without allocate variables");
636 if (allocatePrivateIndices)
638 "unexpected allocate private indices without allocate variables");
642 if (allocateAlignments) {
644 if (alignments.size() != allocateVars.size())
646 "expected as many allocate alignments as allocate variables");
647 for (
int64_t alignment : alignments) {
649 return op->
emitError(
"expected non-negative allocate alignments");
650 if (alignment != 0 && (alignment & (alignment - 1)) != 0)
652 "expected positive allocate alignments to be powers of two");
656 if (!allocatePrivateIndices) {
657 if (requirePrivateIndices)
659 "expected an allocate private index for each allocate variable");
664 if (
indices.size() != allocateVars.size())
666 "expected as many allocate private indices as allocate variables");
669 for (
auto [allocateVar, privateIndex] :
670 llvm::zip_equal(allocateVars,
indices)) {
671 if (privateIndex < 0 ||
672 static_cast<uint64_t
>(privateIndex) >= privateVars.size())
673 return op->
emitError(
"allocate private index is out of range");
674 if (!usedPrivateSlots.insert(privateIndex).second)
676 "allocate private index refers to a private variable more than once");
678 Value privateVar = privateVars[privateIndex];
679 if (allocateVar.getType() != privateVar.
getType())
681 <<
"type mismatch between allocate variable and private variable "
686 static_cast<uint64_t
>(privateIndex) >= privateSyms.size())
688 "allocate private index does not have a privatizer symbol");
690 auto privateSym = dyn_cast<SymbolRefAttr>(privateSyms[privateIndex]);
693 "allocate private index does not reference a privatizer symbol");
694 PrivateClauseOp privatizer =
697 return op->
emitError() <<
"failed to lookup privatizer op with symbol: '"
698 << privateSym <<
"'";
699 if (privatizer.getDataSharingType() != DataSharingClauseType::Private &&
700 privatizer.getDataSharingType() != DataSharingClauseType::FirstPrivate)
702 "allocate private index must refer to private or firstprivate "
716 if (modifiers.size() > 2)
718 for (
const auto &mod : modifiers) {
721 auto symbol = symbolizeScheduleModifier(mod);
724 <<
" unknown modifier type: " << mod;
729 if (modifiers.size() == 1) {
730 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
731 modifiers.push_back(modifiers[0]);
732 modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
734 }
else if (modifiers.size() == 2) {
737 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
738 symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
740 <<
" incorrect modifier order";
756 ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd,
757 std::optional<OpAsmParser::UnresolvedOperand> &chunkSize,
762 std::optional<mlir::omp::ClauseScheduleKind> schedule =
763 symbolizeClauseScheduleKind(keyword);
767 scheduleAttr = ClauseScheduleKindAttr::get(parser.
getContext(), *schedule);
769 case ClauseScheduleKind::Static:
770 case ClauseScheduleKind::Dynamic:
771 case ClauseScheduleKind::Guided:
777 chunkSize = std::nullopt;
780 case ClauseScheduleKind::Auto:
781 case ClauseScheduleKind::Runtime:
782 case ClauseScheduleKind::Distribute:
783 chunkSize = std::nullopt;
792 modifiers.push_back(mod);
798 if (!modifiers.empty()) {
800 if (std::optional<ScheduleModifier> mod =
801 symbolizeScheduleModifier(modifiers[0])) {
802 scheduleMod = ScheduleModifierAttr::get(parser.
getContext(), *mod);
804 return parser.
emitError(loc,
"invalid schedule modifier");
807 if (modifiers.size() > 1) {
808 assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
818 ClauseScheduleKindAttr scheduleKind,
819 ScheduleModifierAttr scheduleMod,
820 UnitAttr scheduleSimd,
Value scheduleChunk,
821 Type scheduleChunkType) {
822 p << stringifyClauseScheduleKind(scheduleKind.getValue());
824 p <<
" = " << scheduleChunk <<
" : " << scheduleChunk.
getType();
826 p <<
", " << stringifyScheduleModifier(scheduleMod.getValue());
838 ClauseOrderKindAttr &order,
839 OrderModifierAttr &orderMod) {
844 if (std::optional<OrderModifier> enumValue =
845 symbolizeOrderModifier(enumStr)) {
846 orderMod = OrderModifierAttr::get(parser.
getContext(), *enumValue);
853 if (std::optional<ClauseOrderKind> enumValue =
854 symbolizeClauseOrderKind(enumStr)) {
855 order = ClauseOrderKindAttr::get(parser.
getContext(), *enumValue);
858 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
862 ClauseOrderKindAttr order,
863 OrderModifierAttr orderMod) {
865 p << stringifyOrderModifier(orderMod.getValue()) <<
":";
867 p << stringifyClauseOrderKind(order.getValue());
870template <
typename ClauseTypeAttr,
typename ClauseType>
873 std::optional<OpAsmParser::UnresolvedOperand> &operand,
875 std::optional<ClauseType> (*symbolizeClause)(StringRef),
876 StringRef clauseName) {
879 if (std::optional<ClauseType> enumValue = symbolizeClause(enumStr)) {
880 prescriptiveness = ClauseTypeAttr::get(parser.
getContext(), *enumValue);
885 <<
"invalid " << clauseName <<
" modifier : '" << enumStr <<
"'";
895 <<
"expected " << clauseName <<
" operand";
898 if (operand.has_value()) {
906template <
typename ClauseTypeAttr,
typename ClauseType>
909 ClauseTypeAttr prescriptiveness,
Value operand,
911 StringRef (*stringifyClauseType)(ClauseType)) {
913 if (prescriptiveness)
914 p << stringifyClauseType(prescriptiveness.getValue()) <<
", ";
917 p << operand <<
": " << operandType;
927 std::optional<OpAsmParser::UnresolvedOperand> &grainsize,
928 Type &grainsizeType) {
930 parser, grainsizeMod, grainsize, grainsizeType,
931 &symbolizeClauseGrainsizeType,
"grainsize");
935 ClauseGrainsizeTypeAttr grainsizeMod,
938 p, op, grainsizeMod, grainsize, grainsizeType,
939 &stringifyClauseGrainsizeType);
949 std::optional<OpAsmParser::UnresolvedOperand> &numTasks,
950 Type &numTasksType) {
952 parser, numTasksMod, numTasks, numTasksType, &symbolizeClauseNumTasksType,
957 ClauseNumTasksTypeAttr numTasksMod,
960 p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
976 return mlir::failure();
977 inTypeAttr = TypeAttr::get(inType);
1006 if (!typeparams.empty()) {
1007 p <<
'(' << typeparams <<
" : " << typeparamsTypes <<
')';
1009 for (
auto sh :
shape) {
1021 FallbackModifierAttr fallback,
1022 Value dynGroupprivateSize) {
1023 if (!dynGroupprivateSize && (accessGroup || fallback))
1024 return op->
emitOpError(
"dyn_groupprivate modifiers require a size operand");
1030 OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr,
1031 FallbackModifierAttr &fallbackAttr,
1032 std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
1035 bool parsedAccessGroup =
false;
1036 bool parsedFallback =
false;
1037 bool parsedSize =
false;
1042 if (parsedAccessGroup)
1044 "duplicate access group modifier");
1045 accessGroupAttr = AccessGroupModifierAttr::get(
1046 parser.
getContext(), AccessGroupModifier::cgroup);
1047 parsedAccessGroup =
true;
1054 "duplicate fallback modifier");
1057 "expected '(' after 'fallback'");
1058 llvm::StringRef fbKind;
1062 "expected fallback modifier (abort/null/default_mem)");
1063 std::optional<FallbackModifier> fbEnum;
1064 if (fbKind ==
"abort")
1065 fbEnum = FallbackModifier::abort;
1066 else if (fbKind ==
"null")
1067 fbEnum = FallbackModifier::null;
1068 else if (fbKind ==
"default_mem")
1069 fbEnum = FallbackModifier::default_mem;
1072 "invalid fallback modifier '" + fbKind +
"'");
1073 fallbackAttr = FallbackModifierAttr::get(parser.
getContext(), *fbEnum);
1076 "expected ')' after fallback modifier");
1077 parsedFallback =
true;
1085 "duplicate size operand");
1086 dynGroupprivateSize = operand;
1090 "expected ':' and type after size operand");
1094 "expected dyn_groupprivate_size operand");
1099 AccessGroupModifierAttr modifierFirst,
1100 FallbackModifierAttr modifierSecond,
1101 Value dynGroupprivateSize,
1104 bool needsComma =
false;
1106 if (modifierFirst) {
1107 printer << modifierFirst.getValue();
1111 if (modifierSecond) {
1114 printer <<
"fallback(";
1115 printer << modifierSecond.getValue();
1120 if (dynGroupprivateSize) {
1123 printer << dynGroupprivateSize <<
" : " << sizeType;
1143 isByRefVec.push_back(parser.parseOptionalKeyword(
"byref").succeeded());
1144 if (parser.parseAttribute(symbolVec.emplace_back()) ||
1145 parser.parseOperand(inReductionVars.emplace_back()))
1155 [&]() { return parser.parseType(inReductionTypes.emplace_back()); }))
1158 if (inReductionVars.size() != inReductionTypes.size())
1163 inReductionSyms = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1180 syms = ArrayAttr::get(ctx, values);
1189 llvm::interleaveComma(
1190 llvm::zip_equal(inReductionVars, syms.getValue(), byref.
asArrayRef()), p,
1192 auto [var, sym, isByRef] = t;
1200 llvm::interleaveComma(inReductionTypes, p);
1208struct MapParseArgs {
1209 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1210 SmallVectorImpl<Type> &types;
1211 MapParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1212 SmallVectorImpl<Type> &types)
1213 : vars(vars), types(types) {}
1215struct PrivateParseArgs {
1216 llvm::SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1217 llvm::SmallVectorImpl<Type> &types;
1219 UnitAttr &needsBarrier;
1221 PrivateParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1222 SmallVectorImpl<Type> &types,
ArrayAttr &syms,
1223 UnitAttr &needsBarrier,
1225 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1226 mapIndices(mapIndices) {}
1229struct ReductionParseArgs {
1230 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1231 SmallVectorImpl<Type> &types;
1234 ReductionModifierAttr *modifier;
1235 ReductionParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1237 ArrayAttr &syms, ReductionModifierAttr *mod =
nullptr)
1238 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1241struct AllRegionParseArgs {
1242 std::optional<MapParseArgs> hasDeviceAddrArgs;
1243 std::optional<MapParseArgs> hostEvalArgs;
1244 std::optional<ReductionParseArgs> inReductionArgs;
1245 std::optional<MapParseArgs> mapArgs;
1246 std::optional<PrivateParseArgs> privateArgs;
1247 std::optional<ReductionParseArgs> reductionArgs;
1248 std::optional<ReductionParseArgs> taskReductionArgs;
1249 std::optional<MapParseArgs> useDeviceAddrArgs;
1250 std::optional<MapParseArgs> useDevicePtrArgs;
1255 return "private_barrier";
1265 ReductionModifierAttr *modifier =
nullptr,
1266 UnitAttr *needsBarrier =
nullptr) {
1270 unsigned regionArgOffset = regionPrivateArgs.size();
1280 std::optional<ReductionModifier> enumValue =
1281 symbolizeReductionModifier(enumStr);
1282 if (!enumValue.has_value())
1284 *modifier = ReductionModifierAttr::get(parser.
getContext(), *enumValue);
1291 isByRefVec.push_back(
1292 parser.parseOptionalKeyword(
"byref").succeeded());
1294 if (symbols && parser.parseAttribute(symbolVec.emplace_back()))
1297 if (parser.parseOperand(operands.emplace_back()) ||
1298 parser.parseArrow() ||
1299 parser.parseArgument(regionPrivateArgs.emplace_back()))
1303 if (parser.parseOptionalLSquare().succeeded()) {
1304 if (parser.parseKeyword(
"map_idx") || parser.parseEqual() ||
1305 parser.parseInteger(mapIndicesVec.emplace_back()) ||
1306 parser.parseRSquare())
1309 mapIndicesVec.push_back(-1);
1321 if (parser.parseType(types.emplace_back()))
1328 if (operands.size() != types.size())
1337 *needsBarrier = mlir::UnitAttr::get(parser.
getContext());
1340 auto *argsBegin = regionPrivateArgs.begin();
1342 argsBegin + regionArgOffset + types.size());
1343 for (
auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
1349 *symbols = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1352 if (!mapIndicesVec.empty())
1365 StringRef keyword, std::optional<MapParseArgs> mapArgs) {
1380 StringRef keyword, std::optional<PrivateParseArgs> privateArgs) {
1386 parser, privateArgs->vars, privateArgs->types, entryBlockArgs,
1387 &privateArgs->syms, privateArgs->mapIndices,
nullptr,
1388 nullptr, &privateArgs->needsBarrier)))
1397 StringRef keyword, std::optional<ReductionParseArgs> reductionArgs) {
1402 parser, reductionArgs->vars, reductionArgs->types, entryBlockArgs,
1403 &reductionArgs->syms,
nullptr, &reductionArgs->byref,
1404 reductionArgs->modifier)))
1411 AllRegionParseArgs args) {
1415 args.hasDeviceAddrArgs)))
1417 <<
"invalid `has_device_addr` format";
1420 args.hostEvalArgs)))
1422 <<
"invalid `host_eval` format";
1425 args.inReductionArgs)))
1427 <<
"invalid `in_reduction` format";
1432 <<
"invalid `map_entries` format";
1437 <<
"invalid `private` format";
1440 args.reductionArgs)))
1442 <<
"invalid `reduction` format";
1445 args.taskReductionArgs)))
1447 <<
"invalid `task_reduction` format";
1450 args.useDeviceAddrArgs)))
1452 <<
"invalid `use_device_addr` format";
1455 args.useDevicePtrArgs)))
1457 <<
"invalid `use_device_addr` format";
1459 return parser.
parseRegion(region, entryBlockArgs);
1475 AllRegionParseArgs args;
1476 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1477 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1478 args.mapArgs.emplace(mapVars, mapTypes);
1479 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1480 privateNeedsBarrier, &privateMaps);
1491 UnitAttr &privateNeedsBarrier) {
1492 AllRegionParseArgs args;
1493 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1494 inReductionByref, inReductionSyms);
1495 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1496 privateNeedsBarrier);
1507 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1511 AllRegionParseArgs args;
1512 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1513 inReductionByref, inReductionSyms);
1514 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1515 privateNeedsBarrier);
1516 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1517 reductionSyms, &reductionMod);
1525 UnitAttr &privateNeedsBarrier) {
1526 AllRegionParseArgs args;
1527 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1528 privateNeedsBarrier);
1536 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1540 AllRegionParseArgs args;
1541 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1542 privateNeedsBarrier);
1543 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1544 reductionSyms, &reductionMod);
1553 AllRegionParseArgs args;
1554 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1555 taskReductionByref, taskReductionSyms);
1565 AllRegionParseArgs args;
1566 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1567 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1576struct MapPrintArgs {
1581struct PrivatePrintArgs {
1585 UnitAttr needsBarrier;
1589 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1590 mapIndices(mapIndices) {}
1592struct ReductionPrintArgs {
1597 ReductionModifierAttr modifier;
1599 ArrayAttr syms, ReductionModifierAttr mod =
nullptr)
1600 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1602struct AllRegionPrintArgs {
1603 std::optional<MapPrintArgs> hasDeviceAddrArgs;
1604 std::optional<MapPrintArgs> hostEvalArgs;
1605 std::optional<ReductionPrintArgs> inReductionArgs;
1606 std::optional<MapPrintArgs> mapArgs;
1607 std::optional<PrivatePrintArgs> privateArgs;
1608 std::optional<ReductionPrintArgs> reductionArgs;
1609 std::optional<ReductionPrintArgs> taskReductionArgs;
1610 std::optional<MapPrintArgs> useDeviceAddrArgs;
1611 std::optional<MapPrintArgs> useDevicePtrArgs;
1620 ReductionModifierAttr modifier =
nullptr, UnitAttr needsBarrier =
nullptr) {
1621 if (argsSubrange.empty())
1624 p << clauseName <<
"(";
1627 p <<
"mod: " << stringifyReductionModifier(modifier.getValue()) <<
", ";
1631 symbols = ArrayAttr::get(ctx, values);
1644 llvm::interleaveComma(llvm::zip_equal(operands, argsSubrange, symbols,
1645 mapIndices.asArrayRef(),
1646 byref.asArrayRef()),
1648 auto [op, arg, sym, map, isByRef] = t;
1654 p << op <<
" -> " << arg;
1657 p <<
" [map_idx=" << map <<
"]";
1660 llvm::interleaveComma(types, p);
1668 StringRef clauseName,
ValueRange argsSubrange,
1669 std::optional<MapPrintArgs> mapArgs) {
1676 StringRef clauseName,
ValueRange argsSubrange,
1677 std::optional<PrivatePrintArgs> privateArgs) {
1680 p, ctx, clauseName, argsSubrange, privateArgs->vars, privateArgs->types,
1681 privateArgs->syms, privateArgs->mapIndices,
nullptr,
1682 nullptr, privateArgs->needsBarrier);
1688 std::optional<ReductionPrintArgs> reductionArgs) {
1691 reductionArgs->vars, reductionArgs->types,
1692 reductionArgs->syms,
nullptr,
1693 reductionArgs->byref, reductionArgs->modifier);
1697 const AllRegionPrintArgs &args) {
1698 auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op);
1702 iface.getHasDeviceAddrBlockArgs(),
1703 args.hasDeviceAddrArgs);
1707 args.inReductionArgs);
1713 args.reductionArgs);
1715 iface.getTaskReductionBlockArgs(),
1716 args.taskReductionArgs);
1718 iface.getUseDeviceAddrBlockArgs(),
1719 args.useDeviceAddrArgs);
1721 iface.getUseDevicePtrBlockArgs(), args.useDevicePtrArgs);
1735 UnitAttr privateNeedsBarrier,
1737 AllRegionPrintArgs args;
1738 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1739 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1740 args.mapArgs.emplace(mapVars, mapTypes);
1741 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1742 privateNeedsBarrier, privateMaps);
1750 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier) {
1751 AllRegionPrintArgs args;
1752 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1753 inReductionByref, inReductionSyms);
1754 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1755 privateNeedsBarrier,
1764 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier,
1765 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1768 AllRegionPrintArgs args;
1769 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1770 inReductionByref, inReductionSyms);
1771 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1772 privateNeedsBarrier,
1774 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1775 reductionSyms, reductionMod);
1782 UnitAttr privateNeedsBarrier) {
1783 AllRegionPrintArgs args;
1784 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1785 privateNeedsBarrier,
1793 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1796 AllRegionPrintArgs args;
1797 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1798 privateNeedsBarrier,
1800 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1801 reductionSyms, reductionMod);
1811 AllRegionPrintArgs args;
1812 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1813 taskReductionByref, taskReductionSyms);
1823 AllRegionPrintArgs args;
1824 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1825 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1829template <
typename ParsePrefixFn>
1838 if (failed(parsePrefix()))
1846 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
1847 iteratedVars.push_back(v);
1848 iteratedTypes.push_back(ty);
1850 plainVars.push_back(v);
1851 plainTypes.push_back(ty);
1857template <
typename Pr
intPrefixFn>
1861 PrintPrefixFn &&printPrefixForPlain,
1862 PrintPrefixFn &&printPrefixForIterated) {
1869 p << v <<
" : " << t;
1873 for (
unsigned i = 0; i < iteratedVars.size(); ++i)
1874 emit(iteratedVars[i], iteratedTypes[i], printPrefixForIterated);
1875 for (
unsigned i = 0; i < plainVars.size(); ++i)
1876 emit(plainVars[i], plainTypes[i], printPrefixForPlain);
1884 if (!reductionVars.empty()) {
1885 if (!reductionSyms || reductionSyms->size() != reductionVars.size())
1887 <<
"expected as many reduction symbol references "
1888 "as reduction variables";
1889 if (reductionByref && reductionByref->size() != reductionVars.size())
1890 return op->
emitError() <<
"expected as many reduction variable by "
1891 "reference attributes as reduction variables";
1894 return op->
emitOpError() <<
"unexpected reduction symbol references";
1901 for (
auto args : llvm::zip(reductionVars, *reductionSyms)) {
1902 Value accum = std::get<0>(args);
1904 if (!accumulators.insert(accum).second)
1905 return op->
emitOpError() <<
"accumulator variable used more than once";
1908 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
1912 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1913 <<
" to point to a reduction declaration";
1915 if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
1917 <<
"expected accumulator (" << varType
1918 <<
") to be the same type as reduction declaration ("
1919 << decl.getAccumulatorType() <<
")";
1938 if (parser.parseOperand(copyprivateVars.emplace_back()) ||
1939 parser.parseArrow() ||
1940 parser.parseAttribute(symsVec.emplace_back()) ||
1941 parser.parseColonType(copyprivateTypes.emplace_back()))
1947 copyprivateSyms = ArrayAttr::get(parser.
getContext(), syms);
1955 std::optional<ArrayAttr> copyprivateSyms) {
1956 if (!copyprivateSyms.has_value())
1958 llvm::interleaveComma(
1959 llvm::zip(copyprivateVars, *copyprivateSyms, copyprivateTypes), p,
1960 [&](
const auto &args) {
1961 p << std::get<0>(args) <<
" -> " << std::get<1>(args) <<
" : "
1962 << std::get<2>(args);
1969 std::optional<ArrayAttr> copyprivateSyms) {
1970 size_t copyprivateSymsSize =
1971 copyprivateSyms.has_value() ? copyprivateSyms->size() : 0;
1972 if (copyprivateSymsSize != copyprivateVars.size())
1973 return op->
emitOpError() <<
"inconsistent number of copyprivate vars (= "
1974 << copyprivateVars.size()
1975 <<
") and functions (= " << copyprivateSymsSize
1976 <<
"), both must be equal";
1977 if (!copyprivateSyms.has_value())
1980 for (
auto copyprivateVarAndSym :
1981 llvm::zip(copyprivateVars, *copyprivateSyms)) {
1983 llvm::cast<SymbolRefAttr>(std::get<1>(copyprivateVarAndSym));
1984 std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
1986 if (mlir::func::FuncOp mlirFuncOp =
1989 funcOp = mlirFuncOp;
1990 else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
1993 funcOp = llvmFuncOp;
1995 auto getNumArguments = [&] {
1996 return std::visit([](
auto &f) {
return f.getNumArguments(); }, *funcOp);
1999 auto getArgumentType = [&](
unsigned i) {
2000 return std::visit([i](
auto &f) {
return f.getArgumentTypes()[i]; },
2005 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
2006 <<
" to point to a copy function";
2008 if (getNumArguments() != 2)
2010 <<
"expected copy function " << symbolRef <<
" to have 2 operands";
2012 Type argTy = getArgumentType(0);
2013 if (argTy != getArgumentType(1))
2014 return op->
emitOpError() <<
"expected copy function " << symbolRef
2015 <<
" arguments to have the same type";
2017 Type varType = std::get<0>(copyprivateVarAndSym).getType();
2018 if (argTy != varType)
2020 <<
"expected copy function arguments' type (" << argTy
2021 <<
") to be the same as copyprivate variable's type (" << varType
2046 OpAsmParser::UnresolvedOperand operand;
2048 if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
2049 parser.parseOperand(operand) || parser.parseColonType(ty))
2051 std::optional<ClauseTaskDepend> keywordDepend =
2052 symbolizeClauseTaskDepend(keyword);
2056 ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend);
2057 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
2058 iteratedVars.push_back(operand);
2059 iteratedTypes.push_back(ty);
2060 iterKindsVec.push_back(kindAttr);
2062 dependVars.push_back(operand);
2063 dependTypes.push_back(ty);
2064 kindsVec.push_back(kindAttr);
2070 dependKinds = ArrayAttr::get(parser.
getContext(), kinds);
2072 iteratedKinds = ArrayAttr::get(parser.
getContext(), iterKinds);
2079 std::optional<ArrayAttr> dependKinds,
2082 std::optional<ArrayAttr> iteratedKinds) {
2085 std::optional<ArrayAttr> kinds) {
2086 for (
unsigned i = 0, e = vars.size(); i < e; ++i) {
2089 p << stringifyClauseTaskDepend(
2090 llvm::cast<mlir::omp::ClauseTaskDependAttr>((*kinds)[i])
2092 <<
" -> " << vars[i] <<
" : " << types[i];
2096 printEntries(dependVars, dependTypes, dependKinds);
2097 printEntries(iteratedVars, iteratedTypes, iteratedKinds);
2102 std::optional<ArrayAttr> dependKinds,
2104 std::optional<ArrayAttr> iteratedKinds,
2106 if (!dependVars.empty()) {
2107 if (!dependKinds || dependKinds->size() != dependVars.size())
2108 return op->
emitOpError() <<
"expected as many depend values"
2109 " as depend variables";
2111 if (dependKinds && !dependKinds->empty())
2112 return op->
emitOpError() <<
"unexpected depend values";
2115 if (!iteratedVars.empty()) {
2116 if (!iteratedKinds || iteratedKinds->size() != iteratedVars.size())
2117 return op->
emitOpError() <<
"expected as many depend iterated values"
2118 " as depend iterated variables";
2120 if (iteratedKinds && !iteratedKinds->empty())
2121 return op->
emitOpError() <<
"unexpected depend iterated values";
2136 IntegerAttr &hintAttr) {
2137 StringRef hintKeyword;
2143 auto parseKeyword = [&]() -> ParseResult {
2146 if (hintKeyword ==
"uncontended")
2148 else if (hintKeyword ==
"contended")
2150 else if (hintKeyword ==
"nonspeculative")
2152 else if (hintKeyword ==
"speculative")
2156 << hintKeyword <<
" is not a valid hint";
2167 IntegerAttr hintAttr) {
2168 int64_t hint = hintAttr.getInt();
2176 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2178 bool uncontended = bitn(hint, 0);
2179 bool contended = bitn(hint, 1);
2180 bool nonspeculative = bitn(hint, 2);
2181 bool speculative = bitn(hint, 3);
2185 hints.push_back(
"uncontended");
2187 hints.push_back(
"contended");
2189 hints.push_back(
"nonspeculative");
2191 hints.push_back(
"speculative");
2193 llvm::interleaveComma(hints, p);
2200 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2202 bool uncontended = bitn(hint, 0);
2203 bool contended = bitn(hint, 1);
2204 bool nonspeculative = bitn(hint, 2);
2205 bool speculative = bitn(hint, 3);
2207 if (uncontended && contended)
2208 return op->
emitOpError() <<
"the hints omp_sync_hint_uncontended and "
2209 "omp_sync_hint_contended cannot be combined";
2210 if (nonspeculative && speculative)
2211 return op->
emitOpError() <<
"the hints omp_sync_hint_nonspeculative and "
2212 "omp_sync_hint_speculative cannot be combined.";
2223 return (value & flag) == flag;
2231static ParseResult parseMapClause(
OpAsmParser &parser,
2232 ClauseMapFlagsAttr &mapType) {
2233 ClauseMapFlags mapTypeBits = ClauseMapFlags::none;
2236 auto parseTypeAndMod = [&]() -> ParseResult {
2237 StringRef mapTypeMod;
2241 if (mapTypeMod ==
"always")
2242 mapTypeBits |= ClauseMapFlags::always;
2244 if (mapTypeMod ==
"implicit")
2245 mapTypeBits |= ClauseMapFlags::implicit;
2247 if (mapTypeMod ==
"ompx_hold")
2248 mapTypeBits |= ClauseMapFlags::ompx_hold;
2250 if (mapTypeMod ==
"close")
2251 mapTypeBits |= ClauseMapFlags::close;
2253 if (mapTypeMod ==
"present")
2254 mapTypeBits |= ClauseMapFlags::present;
2256 if (mapTypeMod ==
"to")
2257 mapTypeBits |= ClauseMapFlags::to;
2259 if (mapTypeMod ==
"from")
2260 mapTypeBits |= ClauseMapFlags::from;
2262 if (mapTypeMod ==
"tofrom")
2263 mapTypeBits |= ClauseMapFlags::to | ClauseMapFlags::from;
2265 if (mapTypeMod ==
"delete")
2266 mapTypeBits |= ClauseMapFlags::del;
2268 if (mapTypeMod ==
"storage")
2269 mapTypeBits |= ClauseMapFlags::storage;
2271 if (mapTypeMod ==
"return_param")
2272 mapTypeBits |= ClauseMapFlags::return_param;
2274 if (mapTypeMod ==
"private")
2275 mapTypeBits |= ClauseMapFlags::priv;
2277 if (mapTypeMod ==
"literal")
2278 mapTypeBits |= ClauseMapFlags::literal;
2280 if (mapTypeMod ==
"attach")
2281 mapTypeBits |= ClauseMapFlags::attach;
2283 if (mapTypeMod ==
"attach_always")
2284 mapTypeBits |= ClauseMapFlags::attach_always;
2286 if (mapTypeMod ==
"attach_never")
2287 mapTypeBits |= ClauseMapFlags::attach_never;
2289 if (mapTypeMod ==
"attach_auto")
2290 mapTypeBits |= ClauseMapFlags::attach_auto;
2292 if (mapTypeMod ==
"ref_ptr")
2293 mapTypeBits |= ClauseMapFlags::ref_ptr;
2295 if (mapTypeMod ==
"ref_ptee")
2296 mapTypeBits |= ClauseMapFlags::ref_ptee;
2298 if (mapTypeMod ==
"is_device_ptr")
2299 mapTypeBits |= ClauseMapFlags::is_device_ptr;
2316 ClauseMapFlagsAttr mapType) {
2318 ClauseMapFlags mapFlags = mapType.getValue();
2323 mapTypeStrs.push_back(
"always");
2325 mapTypeStrs.push_back(
"implicit");
2327 mapTypeStrs.push_back(
"ompx_hold");
2329 mapTypeStrs.push_back(
"close");
2331 mapTypeStrs.push_back(
"present");
2340 mapTypeStrs.push_back(
"tofrom");
2342 mapTypeStrs.push_back(
"from");
2344 mapTypeStrs.push_back(
"to");
2347 mapTypeStrs.push_back(
"delete");
2349 mapTypeStrs.push_back(
"return_param");
2351 mapTypeStrs.push_back(
"storage");
2353 mapTypeStrs.push_back(
"private");
2355 mapTypeStrs.push_back(
"literal");
2357 mapTypeStrs.push_back(
"attach");
2359 mapTypeStrs.push_back(
"attach_always");
2361 mapTypeStrs.push_back(
"attach_never");
2363 mapTypeStrs.push_back(
"attach_auto");
2365 mapTypeStrs.push_back(
"ref_ptr");
2367 mapTypeStrs.push_back(
"ref_ptee");
2369 mapTypeStrs.push_back(
"is_device_ptr");
2370 if (mapFlags == ClauseMapFlags::none)
2371 mapTypeStrs.push_back(
"none");
2373 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
2374 p << mapTypeStrs[i];
2375 if (i + 1 < mapTypeStrs.size()) {
2381static ParseResult parseMembersIndex(
OpAsmParser &parser,
2385 auto parseIndices = [&]() -> ParseResult {
2390 APInt(64, value,
false)));
2404 memberIdxs.push_back(ArrayAttr::get(parser.
getContext(), values));
2408 if (!memberIdxs.empty())
2409 membersIdx = ArrayAttr::get(parser.
getContext(), memberIdxs);
2419 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
2421 auto memberIdx = cast<ArrayAttr>(v);
2422 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
2423 p << cast<IntegerAttr>(v2).getInt();
2430 VariableCaptureKindAttr mapCaptureType) {
2431 std::string typeCapStr;
2432 llvm::raw_string_ostream typeCap(typeCapStr);
2433 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
2435 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
2436 typeCap <<
"ByCopy";
2437 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
2438 typeCap <<
"VLAType";
2439 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
2445 VariableCaptureKindAttr &mapCaptureType) {
2446 StringRef mapCaptureKey;
2450 if (mapCaptureKey ==
"This")
2451 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2452 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
2453 if (mapCaptureKey ==
"ByRef")
2454 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2455 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
2456 if (mapCaptureKey ==
"ByCopy")
2457 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2458 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
2459 if (mapCaptureKey ==
"VLAType")
2460 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2461 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
2467 Operation *op, mlir::omp::MapInfoOp mapInfoOp,
2471 mlir::omp::ClauseMapFlags mapTypeBits = mapInfoOp.getMapType();
2474 bool from =
mapTypeToBool(mapTypeBits, ClauseMapFlags::from);
2477 bool always =
mapTypeToBool(mapTypeBits, ClauseMapFlags::always);
2478 bool close =
mapTypeToBool(mapTypeBits, ClauseMapFlags::close);
2479 bool implicit =
mapTypeToBool(mapTypeBits, ClauseMapFlags::implicit);
2480 bool attach =
mapTypeToBool(mapTypeBits, ClauseMapFlags::attach);
2482 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
2484 "to, from, tofrom and alloc map types are permitted");
2486 if (isa<TargetEnterDataOp>(op) && (from || del))
2487 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
2489 if (isa<TargetExitDataOp>(op) && to)
2491 "from, release and delete map types are permitted");
2493 if (isa<TargetUpdateOp>(op)) {
2496 "at least one of to or from map types must be "
2497 "specified, other map types are not permitted");
2500 if (!to && !from && !attach) {
2502 "at least one of to or from or attach map types must be "
2503 "specified, other map types are not permitted");
2506 auto updateVar = mapInfoOp.getVarPtr();
2508 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
2509 (from && updateToVars.contains(updateVar))) {
2512 "either to or from map types can be specified, not both");
2515 if (always || close || implicit) {
2518 "present, mapper and iterator map type modifiers are permitted");
2524 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
2528 if ((mapInfoOp.getVarPtrPtr() && !mapInfoOp.getVarPtrPtrType()) ||
2529 (!mapInfoOp.getVarPtrPtr() && mapInfoOp.getVarPtrPtrType())) {
2531 "if varPtrPtr or varPtrPtrType is specified, then both "
2543 for (
auto mapOp : mapVars) {
2544 if (!mapOp.getDefiningOp())
2547 if (
auto mapInfoOp = mapOp.getDefiningOp<mlir::omp::MapInfoOp>()) {
2551 }
else if (!isa<DeclareMapperInfoOp>(op)) {
2553 "map argument is not a map entry operation");
2558 for (
auto iterVal : mapIterated) {
2559 auto iterOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
2561 return op->
emitOpError() <<
"'map_iterated' arguments must be defined by "
2562 "'omp.iterator' ops";
2566 cast<mlir::omp::YieldOp>(iterOp.getRegion().front().getTerminator());
2567 auto yieldedMapInfo =
2568 yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
2569 if (!yieldedMapInfo)
2570 return op->
emitOpError() <<
"'map_iterated' iterator body must yield "
2571 "a value defined by 'omp.map.info'";
2581template <
typename OpType>
2585 std::optional<DenseI64ArrayAttr> privateMapIndices =
2586 targetOp.getPrivateMapsAttr();
2589 if (!privateMapIndices.has_value() || !privateMapIndices.value())
2594 if (privateMapIndices.value().size() !=
2595 static_cast<int64_t>(privateVars.size()))
2596 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
2597 "`private_maps` attribute mismatch");
2607 StringRef clauseName,
2609 for (
Value var : vars)
2610 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
2612 <<
"'" << clauseName
2613 <<
"' arguments must be defined by 'omp.map.info' ops";
2617LogicalResult MapInfoOp::verify() {
2618 if (getMapperId() &&
2620 *
this, getMapperIdAttr())) {
2635 const TargetDataOperands &clauses) {
2636 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
2637 clauses.mapVars, clauses.mapIterated,
2638 clauses.useDeviceAddrVars, clauses.useDevicePtrVars);
2641LogicalResult TargetDataOp::verify() {
2642 if (getMapVars().empty() && getMapIterated().empty() &&
2643 getUseDevicePtrVars().empty() && getUseDeviceAddrVars().empty()) {
2644 return ::emitError(this->getLoc(),
2645 "At least one of map, use_device_ptr_vars, or "
2646 "use_device_addr_vars operand must be present");
2650 getUseDevicePtrVars())))
2654 getUseDeviceAddrVars())))
2664void TargetEnterDataOp::build(
2668 TargetEnterDataOp::build(
2670 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2671 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2672 clauses.mapIterated, clauses.nowait);
2675LogicalResult TargetEnterDataOp::verify() {
2676 LogicalResult verifyDependVars =
2678 getDependIteratedKinds(), getDependIterated());
2679 return failed(verifyDependVars)
2691 TargetExitDataOp::build(
2693 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2694 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2695 clauses.mapIterated, clauses.nowait);
2698LogicalResult TargetExitDataOp::verify() {
2699 LogicalResult verifyDependVars =
2701 getDependIteratedKinds(), getDependIterated());
2702 return failed(verifyDependVars)
2714 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
2717 clauses.dependIterated, clauses.device, clauses.ifExpr,
2718 clauses.mapVars, clauses.mapIterated, clauses.nowait);
2721LogicalResult TargetUpdateOp::verify() {
2722 LogicalResult verifyDependVars =
2724 getDependIteratedKinds(), getDependIterated());
2725 return failed(verifyDependVars)
2738 builder, state, clauses.allocateVars, clauses.allocatorVars,
2741 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2742 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
2743 clauses.device, clauses.dynGroupprivateAccessGroup,
2744 clauses.dynGroupprivateFallback, clauses.dynGroupprivateSize,
2745 clauses.hasDeviceAddrVars, clauses.hostEvalVars, clauses.ifExpr,
2746 clauses.inReductionVars,
2748 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.isDevicePtrVars,
2749 clauses.mapVars, clauses.mapIterated, clauses.nowait, clauses.privateVars,
2750 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
2751 clauses.threadLimitVars,
nullptr, clauses.
kernelType);
2754bool TargetOp::hasHostEvalTripCount() {
2755 TargetExecMode mode = getKernelType();
2756 if (mode == TargetExecMode::spmd || mode == TargetExecMode::spmd_no_loop)
2759 if (mode == TargetExecMode::bare)
2765 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2766 if (
auto loopNestOp = dyn_cast_if_present<LoopNestOp>(capturedOp)) {
2768 loopNestOp.gatherWrappers(loopWrappers);
2770 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2771 if (isa<SimdOp>(innermostWrapper))
2772 innermostWrapper = std::next(innermostWrapper);
2774 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2775 if (numWrappers != 1)
2778 if (!isa<DistributeOp>(innermostWrapper))
2782 if (isa_and_present<TeamsOp>(parentOp) &&
2798 if (mapVarPtr == inReductionVar)
2804LogicalResult TargetOp::verify() {
2806 getOperation(), getAllocateVars(), getAllocatorVars(),
2807 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
2808 getPrivateVars(), getPrivateSymsAttr())))
2811 if (getKernelType() == TargetExecMode::bare && !isCombined())
2812 return emitOpError() <<
"bare kernel requires 'omp.combined'";
2815 getDependIteratedKinds(),
2816 getDependIterated())))
2820 getHasDeviceAddrVars())))
2827 *
this, getDynGroupprivateAccessGroupAttr(),
2828 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
2835 getInReductionVars(),
2836 getInReductionByref())))
2844 for (
Value inReductionVar : getInReductionVars()) {
2845 bool captured =
false;
2846 for (
Value mapVar : getMapVars()) {
2847 auto mapInfo = mapVar.getDefiningOp<MapInfoOp>();
2854 return emitOpError() <<
"in_reduction variable must be captured by a "
2855 "matching map_entries entry";
2861LogicalResult TargetOp::verifyRegions() {
2862 auto teamsOps = getOps<TeamsOp>();
2863 auto numNestedTeams = std::distance(teamsOps.begin(), teamsOps.end());
2864 if (numNestedTeams > 1)
2865 return emitError(
"target containing multiple 'omp.teams' nested ops");
2867 if (numNestedTeams == 0) {
2868 switch (getKernelType()) {
2869 case TargetExecMode::bare:
2871 <<
"bare kernel must contain a nested 'omp.teams' operation";
2872 case TargetExecMode::spmd_no_loop:
2873 return emitOpError() <<
"spmd_no_loop kernel must contain a nested "
2874 "'omp.teams' operation";
2881 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2882 if ((getKernelType() == TargetExecMode::spmd ||
2883 getKernelType() == TargetExecMode::spmd_no_loop) &&
2884 !isa_and_present<LoopNestOp>(capturedOp))
2886 <<
"SPMD kernel must capture an 'omp.loop_nest' operation";
2888 bool isTargetDevice =
false;
2889 if (
auto offloadMod = (*this)->getParentOfType<OffloadModuleInterface>())
2890 if (offloadMod.getIsTargetDevice())
2891 isTargetDevice =
true;
2895 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs();
2897 bool hostEvalTripCount = hasHostEvalTripCount();
2898 for (
Value hostEvalArg : hostEvalBlockArgs) {
2900 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
2902 if (hostEvalArg == teamsOp.getNumTeamsLower() ||
2903 llvm::is_contained(teamsOp.getNumTeamsUpperVars(), hostEvalArg) ||
2904 llvm::is_contained(teamsOp.getThreadLimitVars(), hostEvalArg))
2907 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
2908 "and 'thread_limit' in 'omp.teams'";
2910 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
2911 if (llvm::is_contained(parallelOp.getNumThreadsVars(), hostEvalArg))
2915 <<
"host_eval argument only legal as 'num_threads' in "
2918 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
2919 if (hostEvalTripCount &&
2920 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
2921 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
2922 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
2925 return emitOpError() <<
"host_eval argument only legal as loop bounds "
2926 "and steps in 'omp.loop_nest' when trip count "
2927 "must be evaluated in the host";
2930 return emitOpError() <<
"host_eval argument illegal use in '"
2931 << user->getName() <<
"' operation";
2935 if (hostEvalTripCount && !isTargetDevice) {
2936 auto loopOp = cast<LoopNestOp>(capturedOp);
2937 for (
auto arg : llvm::concat<Value>(loopOp.getLoopLowerBounds(),
2938 loopOp.getLoopUpperBounds(),
2939 loopOp.getLoopSteps())) {
2940 if (!llvm::is_contained(hostEvalBlockArgs, arg))
2941 return emitOpError() <<
"nested 'omp.loop_nest' bounds expected to "
2942 "be host-evaluated";
2955 ParallelOp::build(builder, state,
ValueRange(),
2969 const ParallelOperands &clauses) {
2971 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
2974 clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
2976 clauses.privateNeedsBarrier, clauses.procBindKind,
2977 clauses.reductionMod, clauses.reductionVars,
2982template <
typename OpType>
2984 auto privateVars = op.getPrivateVars();
2985 auto privateSyms = op.getPrivateSymsAttr();
2987 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
2990 auto numPrivateVars = privateVars.size();
2991 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
2993 if (numPrivateVars != numPrivateSyms)
2994 return op.emitError() <<
"inconsistent number of private variables and "
2995 "privatizer op symbols, private vars: "
2997 <<
" vs. privatizer op symbols: " << numPrivateSyms;
2999 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
3000 Type varType = std::get<0>(privateVarInfo).getType();
3001 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
3002 PrivateClauseOp privatizerOp =
3005 if (privatizerOp ==
nullptr)
3006 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
3007 << privateSym <<
"'";
3009 Type privatizerType = privatizerOp.getArgType();
3011 if (privatizerType && (varType != privatizerType))
3012 return op.emitError()
3013 <<
"type mismatch between a "
3014 << (privatizerOp.getDataSharingType() ==
3015 DataSharingClauseType::Private
3018 <<
" variable and its privatizer op, var type: " << varType
3019 <<
" vs. privatizer op type: " << privatizerType;
3025LogicalResult ParallelOp::verify() {
3029 getOperation(), getAllocateVars(), getAllocatorVars(),
3030 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3031 getPrivateVars(), getPrivateSymsAttr(),
3036 getReductionByref());
3039LogicalResult ParallelOp::verifyRegions() {
3040 auto distChildOps = getOps<DistributeOp>();
3041 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
3042 if (numDistChildOps > 1)
3044 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
3046 if (numDistChildOps == 1) {
3049 <<
"'omp.composite' attribute missing from composite operation";
3051 auto *ompDialect =
getContext()->getLoadedDialect<OpenMPDialect>();
3052 Operation &distributeOp = **distChildOps.begin();
3054 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
3058 return emitError() <<
"unexpected OpenMP operation inside of composite "
3060 << childOp.getName();
3062 }
else if (isComposite()) {
3064 <<
"'omp.composite' attribute present in non-composite operation";
3081 const TeamsOperands &clauses) {
3085 builder, state, clauses.allocateVars, clauses.allocatorVars,
3088 clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
3089 clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
3090 clauses.numTeamsUpperVars, {},
nullptr,
3091 nullptr, clauses.reductionMod,
3092 clauses.reductionVars,
3094 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
3101 if (numTeamsLower) {
3102 if (numTeamsUpperVars.size() != 1)
3104 "expected exactly one num_teams upper bound when lower bound is "
3108 "expected num_teams upper bound and lower bound to be "
3115LogicalResult TeamsOp::verify() {
3122 auto parentTarget = llvm::dyn_cast_if_present<TargetOp>(op->
getParentOp());
3124 return emitError(
"expected to be nested inside of omp.target or not nested "
3125 "in any OpenMP dialect operations");
3129 this->getNumTeamsUpperVars())))
3133 parentTarget.getKernelType() == TargetExecMode::spmd_no_loop &&
3134 (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
3135 return emitOpError() <<
"'num_teams' not allowed in SPMD-no-loop kernels";
3138 getOperation(), getAllocateVars(), getAllocatorVars(),
3139 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3140 getPrivateVars(), getPrivateSymsAttr())))
3144 op, getDynGroupprivateAccessGroupAttr(),
3145 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3152 getReductionByref());
3160 return getParentOp().getPrivateVars();
3164 return getParentOp().getReductionVars();
3172 const SectionsOperands &clauses) {
3175 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3180 clauses.reductionMod, clauses.reductionVars,
3185LogicalResult SectionsOp::verify() {
3187 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3190 getOperation(), getAllocateVars(), getAllocatorVars(),
3191 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3192 getPrivateVars(), getPrivateSymsAttr())))
3196 getReductionByref());
3199LogicalResult SectionsOp::verifyRegions() {
3200 for (
auto &inst : *getRegion().begin()) {
3201 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
3203 <<
"expected omp.section op or terminator op inside region";
3215 const ScopeOperands &clauses) {
3217 ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3220 clauses.nowait, clauses.privateVars,
3222 clauses.privateNeedsBarrier, clauses.reductionMod,
3223 clauses.reductionVars,
3228LogicalResult ScopeOp::verify() {
3230 getOperation(), getAllocateVars(), getAllocatorVars(),
3231 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3232 getPrivateVars(), getPrivateSymsAttr())))
3239 getReductionByref());
3247 const SingleOperands &clauses) {
3250 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3253 clauses.copyprivateVars,
3254 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
3259LogicalResult SingleOp::verify() {
3261 getOperation(), getAllocateVars(), getAllocatorVars(),
3262 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3263 getPrivateVars(), getPrivateSymsAttr())))
3267 getCopyprivateSyms());
3275 const WorkshareOperands &clauses) {
3276 WorkshareOp::build(builder, state, clauses.nowait);
3279LogicalResult WorkshareOp::verify() {
3281 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3290LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
3291 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3293 return emitOpError() <<
"expected to be a standalone loop wrapper";
3302LogicalResult LoopWrapperInterface::verifyImpl() {
3306 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
3307 "and `SingleBlock` traits";
3310 return emitOpError() <<
"loop wrapper does not contain exactly one region";
3313 if (range_size(region.
getOps()) != 1)
3315 <<
"loop wrapper does not contain exactly one nested op";
3318 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
3319 return emitOpError() <<
"nested in loop wrapper is not another loop "
3320 "wrapper or `omp.loop_nest`";
3329Operation *ComposableOpInterface::findCapturedOp() {
3333 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(op))
3334 return wrapperOp.getWrappedLoop();
3339 if (!isCombined() && !isComposite())
3344 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(&nestedOp))
3345 return wrapperOp.getWrappedLoop();
3347 if (
auto composableOp = dyn_cast<ComposableOpInterface>(&nestedOp))
3348 return composableOp.findCapturedOp();
3357LogicalResult ComposableOpInterface::verifyImpl() {
3361 return emitOpError() <<
"composable ops must have a single region";
3363 if (isComposite() && !isa<LoopWrapperInterface, ParallelOp>(op))
3364 return emitOpError() <<
"non-loop wrapper cannot be composite";
3370 auto count = llvm::count_if(
3372 if (isa<ComposableOpInterface, LoopWrapperInterface>(op)) {
3394 <<
"multiple eligible child ops found in combined op";
3405 if (successor->isReachable(parentBlock))
3406 return emitOpError() <<
"nested combined child op is part of a loop";
3410 !domInfo.
dominates(parentBlock, &block))
3412 <<
"nested combined child op doesn't unconditionally execute";
3422 const LoopOperands &clauses) {
3425 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
3427 clauses.privateNeedsBarrier, clauses.order, clauses.orderMod,
3428 clauses.reductionMod, clauses.reductionVars,
3433LogicalResult LoopOp::verify() {
3438 getReductionByref());
3441LogicalResult LoopOp::verifyRegions() {
3442 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3444 return emitOpError() <<
"expected to be a standalone loop wrapper";
3455 build(builder, state, {}, {},
3460 false,
nullptr,
nullptr,
3461 nullptr, {},
nullptr,
3472 const WsloopOperands &clauses) {
3475 builder, state, clauses.allocateVars, clauses.allocatorVars,
3478 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
3479 clauses.linearModifiers, clauses.nowait, clauses.order, clauses.orderMod,
3480 clauses.ordered, clauses.privateVars,
3481 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
3482 clauses.reductionMod, clauses.reductionVars,
3484 makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
3485 clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
3488LogicalResult WsloopOp::verify() {
3490 getOperation(), getAllocateVars(), getAllocatorVars(),
3491 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3492 getPrivateVars(), getPrivateSymsAttr())))
3498 if (getLinearVars().size() &&
3499 getLinearVarTypes().value().size() != getLinearVars().size())
3500 return emitError() <<
"Ill-formed type attributes for linear variables";
3506 getReductionByref());
3509LogicalResult WsloopOp::verifyRegions() {
3510 bool isCompositeChildLeaf =
3511 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3513 if (LoopWrapperInterface nested = getNestedWrapper()) {
3516 <<
"'omp.composite' attribute missing from composite wrapper";
3520 if (!isa<SimdOp>(nested))
3521 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3523 }
else if (isComposite() && !isCompositeChildLeaf) {
3525 <<
"'omp.composite' attribute present in non-composite wrapper";
3526 }
else if (!isComposite() && isCompositeChildLeaf) {
3528 <<
"'omp.composite' attribute missing from composite wrapper";
3539 const SimdOperands &clauses) {
3541 SimdOp::build(builder, state, clauses.alignedVars,
3543 clauses.linearVars, clauses.linearStepVars,
3544 clauses.linearVarTypes, clauses.linearModifiers,
3545 clauses.nontemporalVars, clauses.order, clauses.orderMod,
3546 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3547 clauses.privateNeedsBarrier, clauses.reductionMod,
3548 clauses.reductionVars,
3554LogicalResult SimdOp::verify() {
3555 if (getSimdlen().has_value() && getSafelen().has_value() &&
3556 getSimdlen().value() > getSafelen().value())
3558 <<
"simdlen clause and safelen clause are both present, but the "
3559 "simdlen value is not less than or equal to safelen value";
3571 bool isCompositeChildLeaf =
3572 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3574 if (!isComposite() && isCompositeChildLeaf)
3576 <<
"'omp.composite' attribute missing from composite wrapper";
3578 if (isComposite() && !isCompositeChildLeaf)
3580 <<
"'omp.composite' attribute present in non-composite wrapper";
3584 std::optional<ArrayAttr> privateSyms = getPrivateSyms();
3586 for (
const Attribute &sym : *privateSyms) {
3587 auto symRef = cast<SymbolRefAttr>(sym);
3588 omp::PrivateClauseOp privatizer =
3590 getOperation(), symRef);
3592 return emitError() <<
"Cannot find privatizer '" << symRef <<
"'";
3593 if (privatizer.getDataSharingType() ==
3594 DataSharingClauseType::FirstPrivate)
3595 return emitError() <<
"FIRSTPRIVATE cannot be used with SIMD";
3602 if (getLinearVars().size() &&
3603 getLinearVarTypes().value().size() != getLinearVars().size())
3604 return emitError() <<
"Ill-formed type attributes for linear variables";
3609 for (
Value var : getLinearVars()) {
3610 if (privateVars.contains(var) || reductionVars.contains(var))
3612 <<
"linear variables cannot appear in other data-sharing clauses";
3618LogicalResult SimdOp::verifyRegions() {
3619 if (getNestedWrapper())
3620 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
3630 const DistributeOperands &clauses) {
3631 DistributeOp::build(
3632 builder, state, clauses.allocateVars, clauses.allocatorVars,
3635 clauses.allocatePrivateIndices),
3636 clauses.distScheduleStatic, clauses.distScheduleChunkSize, clauses.order,
3637 clauses.orderMod, clauses.privateVars,
3639 clauses.privateNeedsBarrier);
3642LogicalResult DistributeOp::verify() {
3643 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
3645 "dist_schedule_static being present";
3648 getOperation(), getAllocateVars(), getAllocatorVars(),
3649 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3650 getPrivateVars(), getPrivateSymsAttr())))
3659LogicalResult DistributeOp::verifyRegions() {
3660 if (LoopWrapperInterface nested = getNestedWrapper()) {
3663 <<
"'omp.composite' attribute missing from composite wrapper";
3666 if (isa<WsloopOp>(nested)) {
3668 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
3669 !cast<ComposableOpInterface>(parentOp).isComposite()) {
3670 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
3671 "when a composite 'omp.parallel' is the direct "
3674 }
else if (!isa<SimdOp>(nested))
3675 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
3677 }
else if (isComposite()) {
3679 <<
"'omp.composite' attribute present in non-composite wrapper";
3690 const DeclareMapperInfoOperands &clauses) {
3691 DeclareMapperInfoOp::build(builder, state, clauses.mapVars,
3692 clauses.mapIterated);
3695LogicalResult DeclareMapperInfoOp::verify() {
3699LogicalResult DeclareMapperOp::verifyRegions() {
3700 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
3701 getRegion().getBlocks().front().getTerminator()))
3702 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
3711LogicalResult DeclareReductionOp::verifyRegions() {
3712 if (!getAllocRegion().empty()) {
3713 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
3714 if (yieldOp.getResults().size() != 1 ||
3715 yieldOp.getResults().getTypes()[0] !=
getType())
3716 return emitOpError() <<
"expects alloc region to yield a value "
3717 "of the reduction type";
3721 if (getInitializerRegion().empty())
3722 return emitOpError() <<
"expects non-empty initializer region";
3723 Block &initializerEntryBlock = getInitializerRegion().
front();
3726 if (!getAllocRegion().empty())
3727 return emitOpError() <<
"expects two arguments to the initializer region "
3728 "when an allocation region is used";
3730 if (getAllocRegion().empty())
3731 return emitOpError() <<
"expects one argument to the initializer region "
3732 "when no allocation region is used";
3735 <<
"expects one or two arguments to the initializer region";
3739 if (arg.getType() !=
getType())
3740 return emitOpError() <<
"expects initializer region argument to match "
3741 "the reduction type";
3743 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
3744 if (yieldOp.getResults().size() != 1 ||
3745 yieldOp.getResults().getTypes()[0] !=
getType())
3746 return emitOpError() <<
"expects initializer region to yield a value "
3747 "of the reduction type";
3750 if (getReductionRegion().empty())
3751 return emitOpError() <<
"expects non-empty reduction region";
3752 Block &reductionEntryBlock = getReductionRegion().
front();
3757 return emitOpError() <<
"expects reduction region with two arguments of "
3758 "the reduction type";
3759 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
3760 if (yieldOp.getResults().size() != 1 ||
3761 yieldOp.getResults().getTypes()[0] !=
getType())
3762 return emitOpError() <<
"expects reduction region to yield a value "
3763 "of the reduction type";
3766 if (!getAtomicReductionRegion().empty()) {
3767 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
3771 return emitOpError() <<
"expects atomic reduction region with two "
3772 "arguments of the same type";
3773 auto ptrType = llvm::dyn_cast<PointerLikeType>(
3776 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
3777 return emitOpError() <<
"expects atomic reduction region arguments to "
3778 "be accumulators containing the reduction type";
3781 if (getCleanupRegion().empty())
3783 Block &cleanupEntryBlock = getCleanupRegion().
front();
3786 return emitOpError() <<
"expects cleanup region with one argument "
3787 "of the reduction type";
3797 const TaskOperands &clauses) {
3800 builder, state, clauses.iterated, clauses.affinityVars,
3801 clauses.allocateVars, clauses.allocatorVars,
3804 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
3805 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
3806 clauses.final, clauses.ifExpr, clauses.inReductionVars,
3808 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3809 clauses.priority, clauses.privateVars,
3811 clauses.privateNeedsBarrier, clauses.untied, clauses.eventHandle);
3814LogicalResult TaskOp::verify() {
3816 getOperation(), getAllocateVars(), getAllocatorVars(),
3817 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3818 getPrivateVars(), getPrivateSymsAttr())))
3821 LogicalResult verifyDependVars =
3823 getDependIteratedKinds(), getDependIterated());
3824 if (
failed(verifyDependVars))
3825 return verifyDependVars;
3831 getInReductionVars(), getInReductionByref());
3839 const TaskgroupOperands &clauses) {
3841 TaskgroupOp::build(builder, state, clauses.allocateVars,
3842 clauses.allocatorVars,
3845 clauses.taskReductionVars,
3850LogicalResult TaskgroupOp::verify() {
3852 getOperation(), getAllocateVars(), getAllocatorVars(),
3853 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr())))
3857 getTaskReductionVars(),
3858 getTaskReductionByref());
3866 const TaskloopContextOperands &clauses) {
3868 TaskloopContextOp::build(
3869 builder, state, clauses.allocateVars, clauses.allocatorVars,
3872 clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
3873 clauses.inReductionVars,
3875 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3876 clauses.nogroup, clauses.numTasksMod, clauses.numTasks, clauses.priority,
3877 clauses.privateVars,
3879 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3882 state.
addAttribute(
"omp.combined", UnitAttr::get(ctx));
3885TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
3886 return cast<TaskloopWrapperOp>(
3888 return isa<TaskloopWrapperOp>(op);
3892LogicalResult TaskloopContextOp::verify() {
3896 getOperation(), getAllocateVars(), getAllocatorVars(),
3897 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3898 getPrivateVars(), getPrivateSymsAttr())))
3902 getReductionVars(), getReductionByref())) ||
3904 getInReductionVars(),
3905 getInReductionByref())))
3908 if (!getReductionVars().empty() && getNogroup())
3909 return emitError(
"if a reduction clause is present on the taskloop "
3910 "directive, the nogroup clause must not be specified");
3911 for (
auto var : getReductionVars()) {
3912 if (llvm::is_contained(getInReductionVars(), var))
3913 return emitError(
"the same list item cannot appear in both a reduction "
3914 "and an in_reduction clause");
3917 if (getGrainsize() && getNumTasks()) {
3919 "the grainsize clause and num_tasks clause are mutually exclusive and "
3920 "may not appear on the same taskloop directive");
3928 return emitOpError(
"must always contain the 'omp.combined' attribute");
3933LogicalResult TaskloopContextOp::verifyRegions() {
3934 Region ®ion = getRegion();
3936 return isa<TaskloopWrapperOp>(op);
3938 if (loopWrapperIt == region.
front().
end())
3940 <<
"expected a TaskloopWrapperOp directly nested in the region";
3942 auto loopWrapperOp = cast<TaskloopWrapperOp>(*loopWrapperIt);
3943 auto loopNestOp = dyn_cast<LoopNestOp>(loopWrapperOp.getWrappedLoop());
3949 std::function<
bool(
Value)> isValidBoundValue = [&](
Value value) ->
bool {
3950 Region *valueRegion = value.getParentRegion();
3956 Operation *defOp = value.getDefiningOp();
3960 return llvm::all_of(defOp->
getOperands(), isValidBoundValue);
3962 auto hasUnsupportedTaskloopLocalBound = [&](
OperandRange range) ->
bool {
3963 return llvm::any_of(range,
3964 [&](
Value value) {
return !isValidBoundValue(value); });
3967 if (hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopLowerBounds()) ||
3968 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopUpperBounds()) ||
3969 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopSteps())) {
3971 <<
"expects loop bounds and steps to be defined outside of the "
3972 "taskloop.context region or by pure, regionless operations "
3973 "that do not depend on block arguments";
3984 const TaskloopWrapperOperands &clauses) {
3985 TaskloopWrapperOp::build(builder, state);
3988TaskloopContextOp TaskloopWrapperOp::getTaskloopContext() {
3989 return dyn_cast<TaskloopContextOp>(getOperation()->getParentOp());
3992LogicalResult TaskloopWrapperOp::verify() {
3993 TaskloopContextOp context = getTaskloopContext();
3995 return emitOpError() <<
"expected to be nested in a taskloop context op";
3999LogicalResult TaskloopWrapperOp::verifyRegions() {
4000 if (LoopWrapperInterface nested = getNestedWrapper()) {
4003 <<
"'omp.composite' attribute missing from composite wrapper";
4007 if (!isa<SimdOp>(nested))
4008 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
4009 }
else if (isComposite()) {
4011 <<
"'omp.composite' attribute present in non-composite wrapper";
4035 for (
auto &iv : ivs)
4036 iv.type = loopVarType;
4041 result.addAttribute(
"loop_inclusive", UnitAttr::get(ctx));
4057 "collapse_num_loops",
4062 auto parseTiles = [&]() -> ParseResult {
4066 tiles.push_back(
tile);
4075 if (tiles.size() > 0)
4094 Region ®ion = getRegion();
4096 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
4097 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
4098 if (getLoopInclusive())
4100 p <<
"step (" << getLoopSteps() <<
") ";
4101 if (
int64_t numCollapse = getCollapseNumLoops())
4102 if (numCollapse > 1)
4103 p <<
"collapse(" << numCollapse <<
") ";
4106 p <<
"tiles(" << tiles.value() <<
") ";
4112 const LoopNestOperands &clauses) {
4114 LoopNestOp::build(builder, state, clauses.collapseNumLoops,
4115 clauses.loopLowerBounds, clauses.loopUpperBounds,
4116 clauses.loopSteps, clauses.loopInclusive,
4120LogicalResult LoopNestOp::verify() {
4121 if (getLoopLowerBounds().empty())
4122 return emitOpError() <<
"must represent at least one loop";
4124 if (getLoopLowerBounds().size() != getIVs().size())
4125 return emitOpError() <<
"number of range arguments and IVs do not match";
4127 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
4128 if (lb.getType() != iv.getType())
4130 <<
"range argument type does not match corresponding IV type";
4133 uint64_t numIVs = getIVs().size();
4135 if (
const auto &numCollapse = getCollapseNumLoops())
4136 if (numCollapse > numIVs)
4138 <<
"collapse value is larger than the number of loops";
4141 if (tiles.value().size() > numIVs)
4142 return emitOpError() <<
"too few canonical loops for tile dimensions";
4144 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
4145 return emitOpError() <<
"expects parent op to be a loop wrapper";
4150void LoopNestOp::gatherWrappers(
4153 while (
auto wrapper =
4154 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
4155 wrappers.push_back(wrapper);
4164std::tuple<NewCliOp, OpOperand *, OpOperand *>
4170 return {{},
nullptr,
nullptr};
4173 "Unexpected type of cli");
4179 auto op = cast<LoopTransformationInterface>(use.getOwner());
4181 unsigned opnum = use.getOperandNumber();
4182 if (op.isGeneratee(opnum)) {
4183 assert(!gen &&
"Each CLI may have at most one def");
4185 }
else if (op.isApplyee(opnum)) {
4186 assert(!cons &&
"Each CLI may have at most one consumer");
4189 llvm_unreachable(
"Unexpected operand for a CLI");
4193 return {create, gen, cons};
4199 case llvm::omp::ProcBindKind::OMP_PROC_BIND_close:
4200 return ClauseProcBindKind::Close;
4201 case llvm::omp::ProcBindKind::OMP_PROC_BIND_master:
4202 return ClauseProcBindKind::Master;
4203 case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary:
4204 return ClauseProcBindKind::Primary;
4205 case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread:
4206 return ClauseProcBindKind::Spread;
4207 case llvm::omp::ProcBindKind::OMP_PROC_BIND_default:
4208 case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown:
4211 llvm_unreachable(
"unexpected proc-bind kind");
4234 std::string cliName{
"cli"};
4238 .Case([&](CanonicalLoopOp op) {
4241 .Case([&](UnrollHeuristicOp op) -> std::string {
4242 llvm_unreachable(
"heuristic unrolling does not generate a loop");
4244 .Case([&](FuseOp op) -> std::string {
4245 unsigned opnum =
generator->getOperandNumber();
4248 if (op.getFirst().has_value() && opnum != op.getFirst().value())
4249 return "canonloop_fuse";
4253 .Case([&](TileOp op) -> std::string {
4254 auto [generateesFirst, generateesCount] =
4255 op.getGenerateesODSOperandIndexAndLength();
4256 unsigned firstGrid = generateesFirst;
4257 unsigned firstIntratile = generateesFirst + generateesCount / 2;
4258 unsigned end = generateesFirst + generateesCount;
4259 unsigned opnum =
generator->getOperandNumber();
4261 if (firstGrid <= opnum && opnum < firstIntratile) {
4262 unsigned gridnum = opnum - firstGrid + 1;
4263 return (
"grid" + Twine(gridnum)).str();
4265 if (firstIntratile <= opnum && opnum < end) {
4266 unsigned intratilenum = opnum - firstIntratile + 1;
4267 return (
"intratile" + Twine(intratilenum)).str();
4269 llvm_unreachable(
"Unexpected generatee argument");
4271 .DefaultUnreachable(
"TODO: Custom name for this operation");
4274 setNameFn(
result, cliName);
4277LogicalResult NewCliOp::verify() {
4278 Value cli = getResult();
4281 "Unexpected type of cli");
4287 auto op = cast<mlir::omp::LoopTransformationInterface>(use.getOwner());
4289 unsigned opnum = use.getOperandNumber();
4290 if (op.isGeneratee(opnum)) {
4293 emitOpError(
"CLI must have at most one generator");
4295 .
append(
"first generator here:");
4297 .
append(
"second generator here:");
4302 }
else if (op.isApplyee(opnum)) {
4305 emitOpError(
"CLI must have at most one consumer");
4307 .
append(
"first consumer here:")
4311 .
append(
"second consumer here:")
4318 llvm_unreachable(
"Unexpected operand for a CLI");
4326 .
append(
"see consumer here: ")
4349 setNameFn(&getRegion().front(),
"body_entry");
4352void CanonicalLoopOp::getAsmBlockArgumentNames(
Region ®ion,
4360 p <<
'(' << getCli() <<
')';
4361 p <<
' ' << getInductionVar() <<
" : " << getInductionVar().getType()
4362 <<
" in range(" << getTripCount() <<
") ";
4372 CanonicalLoopInfoType cliType =
4373 CanonicalLoopInfoType::get(parser.
getContext());
4398 if (parser.
parseRegion(*region, {inductionVariable}))
4403 result.operands.append(cliOperand);
4409 return mlir::success();
4412LogicalResult CanonicalLoopOp::verify() {
4415 if (!getRegion().empty()) {
4416 Region ®ion = getRegion();
4419 "Canonical loop region must have exactly one argument");
4423 "Region argument must be the same type as the trip count");
4429Value CanonicalLoopOp::getInductionVar() {
return getRegion().getArgument(0); }
4431std::pair<unsigned, unsigned>
4432CanonicalLoopOp::getApplyeesODSOperandIndexAndLength() {
4437std::pair<unsigned, unsigned>
4438CanonicalLoopOp::getGenerateesODSOperandIndexAndLength() {
4439 return getODSOperandIndexAndLength(odsIndex_cli);
4453 p <<
'(' << getApplyee() <<
')';
4460 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4483 return mlir::success();
4486std::pair<unsigned, unsigned>
4487UnrollHeuristicOp ::getApplyeesODSOperandIndexAndLength() {
4488 return getODSOperandIndexAndLength(odsIndex_applyee);
4491std::pair<unsigned, unsigned>
4492UnrollHeuristicOp::getGenerateesODSOperandIndexAndLength() {
4502 uint64_t unrollFactor) {
4509 p <<
'(' << getApplyee() <<
')';
4516 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4533 return mlir::success();
4536std::pair<unsigned, unsigned>
4537UnrollPartialOp::getApplyeesODSOperandIndexAndLength() {
4538 return getODSOperandIndexAndLength(odsIndex_applyee);
4541std::pair<unsigned, unsigned>
4542UnrollPartialOp::getGenerateesODSOperandIndexAndLength() {
4553 if (!generatees.empty())
4554 p <<
'(' << llvm::interleaved(generatees) <<
')';
4556 if (!applyees.empty())
4557 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4599 bool isOnlyCanonLoops =
true;
4601 for (
Value applyee : op.getApplyees()) {
4602 auto [create, gen, cons] =
decodeCli(applyee);
4605 return op.emitOpError() <<
"applyee CLI has no generator";
4607 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4608 canonLoops.push_back(loop);
4610 isOnlyCanonLoops =
false;
4615 if (!isOnlyCanonLoops)
4619 for (
auto i : llvm::seq<int>(1, canonLoops.size())) {
4620 auto parentLoop = canonLoops[i - 1];
4621 auto loop = canonLoops[i];
4623 if (parentLoop.getOperation() != loop.getOperation()->getParentOp())
4624 return op.emitOpError()
4625 <<
"tiled loop nest must be nested within each other";
4627 parentIVs.insert(parentLoop.getInductionVar());
4632 bool isPerfectlyNested = [&]() {
4633 auto &parentBody = parentLoop.getRegion();
4634 if (!parentBody.hasOneBlock())
4636 auto &parentBlock = parentBody.getBlocks().
front();
4638 auto nestedLoopIt = parentBlock.
begin();
4639 if (nestedLoopIt == parentBlock.
end() ||
4640 (&*nestedLoopIt != loop.getOperation()))
4643 auto termIt = std::next(nestedLoopIt);
4644 if (termIt == parentBlock.
end() || !isa<TerminatorOp>(termIt))
4647 if (std::next(termIt) != parentBlock.
end())
4652 if (!isPerfectlyNested)
4653 return op.emitOpError() <<
"tiled loop nest must be perfectly nested";
4655 if (parentIVs.contains(loop.getTripCount()))
4656 return op.emitOpError() <<
"tiled loop nest must be rectangular";
4673LogicalResult TileOp::verify() {
4674 if (getApplyees().empty())
4675 return emitOpError() <<
"must apply to at least one loop";
4677 if (getSizes().size() != getApplyees().size())
4678 return emitOpError() <<
"there must be one tile size for each applyee";
4680 if (!getGeneratees().empty() &&
4681 2 * getSizes().size() != getGeneratees().size())
4683 <<
"expecting two times the number of generatees than applyees";
4688std::pair<unsigned, unsigned> TileOp ::getApplyeesODSOperandIndexAndLength() {
4689 return getODSOperandIndexAndLength(odsIndex_applyees);
4692std::pair<unsigned, unsigned> TileOp::getGenerateesODSOperandIndexAndLength() {
4693 return getODSOperandIndexAndLength(odsIndex_generatees);
4703 if (!generatees.empty())
4704 p <<
'(' << llvm::interleaved(generatees) <<
')';
4706 if (!applyees.empty())
4707 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4710LogicalResult FuseOp::verify() {
4711 if (getApplyees().size() < 2)
4712 return emitOpError() <<
"must apply to at least two loops";
4714 if (getFirst().has_value() && getCount().has_value()) {
4715 int64_t first = getFirst().value();
4716 int64_t count = getCount().value();
4717 if ((
unsigned)(first + count - 1) > getApplyees().size())
4718 return emitOpError() <<
"the numbers of applyees must be at least first "
4719 "minus one plus count attributes";
4720 if (!getGeneratees().empty() &&
4721 getGeneratees().size() != getApplyees().size() + 1 - count)
4722 return emitOpError() <<
"the number of generatees must be the number of "
4723 "aplyees plus one minus count";
4726 if (!getGeneratees().empty() && getGeneratees().size() != 1)
4728 <<
"in a complete fuse the number of generatees must be exactly 1";
4730 for (
auto &&applyee : getApplyees()) {
4731 auto [create, gen, cons] =
decodeCli(applyee);
4734 return emitOpError() <<
"applyee CLI has no generator";
4735 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4738 <<
"currently only supports omp.canonical_loop as applyee";
4742std::pair<unsigned, unsigned> FuseOp::getApplyeesODSOperandIndexAndLength() {
4743 return getODSOperandIndexAndLength(odsIndex_applyees);
4746std::pair<unsigned, unsigned> FuseOp::getGenerateesODSOperandIndexAndLength() {
4747 return getODSOperandIndexAndLength(odsIndex_generatees);
4755 const CriticalDeclareOperands &clauses) {
4756 CriticalDeclareOp::build(builder, state, clauses.symName, clauses.hint);
4759LogicalResult CriticalDeclareOp::verify() {
4764 if (getNameAttr()) {
4765 SymbolRefAttr symbolRef = getNameAttr();
4769 return emitOpError() <<
"expected symbol reference " << symbolRef
4770 <<
" to point to a critical declaration";
4781LogicalResult ErrorOp::verify() {
4782 if (getMessage() && getMessageExpr())
4783 return emitOpError() <<
"the message must be provided either as a constant "
4784 "`message` attribute or as a `message_expr` "
4785 "operand, but not both";
4802 return op.
emitOpError() <<
"must be nested inside of a loop";
4806 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
4807 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
4809 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
4810 "have an ordered clause";
4812 if (hasRegion && orderedAttr.getInt() != 0)
4813 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
4814 "have a parameter present";
4816 if (!hasRegion && orderedAttr.getInt() == 0)
4817 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
4818 "have a parameter present";
4819 }
else if (!isa<SimdOp>(wrapper)) {
4820 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
4821 "or worksharing simd loop";
4827 const OrderedOperands &clauses) {
4828 OrderedOp::build(builder, state, clauses.doacrossDependType,
4829 clauses.doacrossNumLoops, clauses.doacrossDependVars);
4832LogicalResult OrderedOp::verify() {
4836 auto wrapper = (*this)->getParentOfType<WsloopOp>();
4837 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
4838 return emitOpError() <<
"number of variables in depend clause does not "
4839 <<
"match number of iteration variables in the "
4846 const OrderedRegionOperands &clauses) {
4847 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
4857 const TaskwaitOperands &clauses) {
4873LogicalResult AtomicReadOp::verify() {
4874 if (verifyCommon().
failed())
4875 return mlir::failure();
4878 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4879 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4880 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4882 if (
auto mo = getMemoryOrder()) {
4883 if (*mo == ClauseMemoryOrderKind::Release) {
4884 return emitError(
"memory-order must not be release for atomic reads");
4886 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
4889 return emitError(
"memory-order must not be acq_rel for atomic reads");
4899LogicalResult AtomicWriteOp::verify() {
4900 if (verifyCommon().
failed())
4901 return mlir::failure();
4904 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4905 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4906 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4908 if (
auto mo = getMemoryOrder()) {
4909 if (*mo == ClauseMemoryOrderKind::Acquire) {
4910 return emitError(
"memory-order must not be acquire for atomic writes");
4912 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
4915 return emitError(
"memory-order must not be acq_rel for atomic writes");
4925LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
4931 if (
Value writeVal = op.getWriteOpVal()) {
4933 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
4939LogicalResult AtomicUpdateOp::verify() {
4940 if (verifyCommon().
failed())
4941 return mlir::failure();
4944 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
4945 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
4946 version = llvm::cast<VersionAttr>(verAttr).getVersion();
4948 if (
auto mo = getMemoryOrder()) {
4949 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
4950 *mo == ClauseMemoryOrderKind::Acquire) {
4954 "memory-order must not be acq_rel or acquire for atomic updates");
4961LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
4967AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
4968 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
4970 return dyn_cast<AtomicReadOp>(getSecondOp());
4973AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
4974 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
4976 return dyn_cast<AtomicWriteOp>(getSecondOp());
4979AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
4980 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
4982 return dyn_cast<AtomicUpdateOp>(getSecondOp());
4985LogicalResult AtomicCaptureOp::verify() {
4989LogicalResult AtomicCaptureOp::verifyRegions() {
4990 if (verifyRegionsCommon().
failed())
4991 return mlir::failure();
4993 if (getFirstOp()->getAttr(
"hint") || getSecondOp()->getAttr(
"hint"))
4995 "operations inside capture region must not have hint clause");
4997 if (getFirstOp()->getAttr(
"memory_order") ||
4998 getSecondOp()->getAttr(
"memory_order"))
5000 "operations inside capture region must not have memory_order clause");
5008LogicalResult AtomicCompareOp::verify() {
5009 if (verifyCommon().
failed())
5010 return mlir::failure();
5014LogicalResult AtomicCompareOp::verifyRegions() {
5015 if (verifyRegionsCommon().
failed())
5016 return mlir::failure();
5018 if (verifyOperator().
failed())
5019 return mlir::failure();
5024 if (!terminator || !isa<YieldOp>(terminator))
5025 return emitOpError(
"region must be terminated with omp.yield");
5035 const CancelOperands &clauses) {
5036 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
5049LogicalResult CancelOp::verify() {
5050 ClauseCancellationConstructType cct = getCancelDirective();
5053 if (!structuralParent)
5054 return emitOpError() <<
"Orphaned cancel construct";
5056 if ((cct == ClauseCancellationConstructType::Parallel) &&
5057 !mlir::isa<ParallelOp>(structuralParent)) {
5058 return emitOpError() <<
"cancel parallel must appear "
5059 <<
"inside a parallel region";
5061 if (cct == ClauseCancellationConstructType::Loop) {
5064 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
5068 <<
"cancel loop must appear inside a worksharing-loop region";
5070 if (wsloopOp.getNowaitAttr()) {
5071 return emitError() <<
"A worksharing construct that is canceled "
5072 <<
"must not have a nowait clause";
5074 if (wsloopOp.getOrderedAttr()) {
5075 return emitError() <<
"A worksharing construct that is canceled "
5076 <<
"must not have an ordered clause";
5079 }
else if (cct == ClauseCancellationConstructType::Sections) {
5083 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
5085 return emitOpError() <<
"cancel sections must appear "
5086 <<
"inside a sections region";
5088 if (sectionsOp.getNowait()) {
5089 return emitError() <<
"A sections construct that is canceled "
5090 <<
"must not have a nowait clause";
5093 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5094 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5095 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5096 return emitOpError() <<
"cancel taskgroup must appear "
5097 <<
"inside a task region";
5107 const CancellationPointOperands &clauses) {
5108 CancellationPointOp::build(builder, state, clauses.cancelDirective);
5111LogicalResult CancellationPointOp::verify() {
5112 ClauseCancellationConstructType cct = getCancelDirective();
5115 if (!structuralParent)
5116 return emitOpError() <<
"Orphaned cancellation point";
5118 if ((cct == ClauseCancellationConstructType::Parallel) &&
5119 !mlir::isa<ParallelOp>(structuralParent)) {
5120 return emitOpError() <<
"cancellation point parallel must appear "
5121 <<
"inside a parallel region";
5125 if ((cct == ClauseCancellationConstructType::Loop) &&
5126 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
5127 return emitOpError() <<
"cancellation point loop must appear "
5128 <<
"inside a worksharing-loop region";
5130 if ((cct == ClauseCancellationConstructType::Sections) &&
5131 !mlir::isa<omp::SectionOp>(structuralParent)) {
5132 return emitOpError() <<
"cancellation point sections must appear "
5133 <<
"inside a sections region";
5135 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5136 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5137 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5138 return emitOpError() <<
"cancellation point taskgroup must appear "
5139 <<
"inside a task region";
5148LogicalResult MapBoundsOp::verify() {
5149 auto extent = getExtent();
5151 if (!extent && !upperbound)
5152 return emitError(
"expected extent or upperbound.");
5159 PrivateClauseOp::build(
5160 odsBuilder, odsState, symName, type,
5161 DataSharingClauseTypeAttr::get(odsBuilder.
getContext(),
5162 DataSharingClauseType::Private));
5165LogicalResult PrivateClauseOp::verifyRegions() {
5166 Type argType = getArgType();
5167 auto verifyTerminator = [&](
Operation *terminator,
5168 bool yieldsValue) -> LogicalResult {
5172 if (!llvm::isa<YieldOp>(terminator))
5174 <<
"expected exit block terminator to be an `omp.yield` op.";
5176 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
5177 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
5180 if (yieldedTypes.empty())
5184 <<
"Did not expect any values to be yielded.";
5187 if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)
5191 <<
"Invalid yielded value. Expected type: " << argType
5194 if (yieldedTypes.empty())
5197 error << yieldedTypes;
5203 StringRef regionName,
5204 bool yieldsValue) -> LogicalResult {
5205 assert(!region.
empty());
5209 <<
"`" << regionName <<
"`: " <<
"expected " << expectedNumArgs
5212 for (
Block &block : region) {
5225 for (
Region *region : getRegions())
5226 for (
Type ty : region->getArgumentTypes())
5228 return emitError() <<
"Region argument type mismatch: got " << ty
5229 <<
" expected " << argType <<
".";
5232 if (!initRegion.
empty() &&
5237 DataSharingClauseType dsType = getDataSharingType();
5239 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
5240 return emitError(
"`private` clauses do not require a `copy` region.");
5242 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
5244 "`firstprivate` clauses require at least a `copy` region.");
5246 if (dsType == DataSharingClauseType::FirstPrivate &&
5251 if (!getDeallocRegion().empty() &&
5264 const MaskedOperands &clauses) {
5265 MaskedOp::build(builder, state, clauses.filteredThreadId);
5273 const ScanOperands &clauses) {
5274 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
5277LogicalResult ScanOp::verify() {
5278 if (hasExclusiveVars() == hasInclusiveVars())
5280 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
5281 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
5282 if (parentWsLoopOp.getReductionModAttr() &&
5283 parentWsLoopOp.getReductionModAttr().getValue() ==
5284 ReductionModifier::inscan)
5287 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
5288 if (parentSimdOp.getReductionModAttr() &&
5289 parentSimdOp.getReductionModAttr().getValue() ==
5290 ReductionModifier::inscan)
5293 return emitError(
"SCAN directive needs to be enclosed within a parent "
5294 "worksharing loop construct or SIMD construct with INSCAN "
5295 "reduction modifier");
5300 std::optional<uint64_t> alignment) {
5301 if (alignment.has_value()) {
5302 if ((alignment.value() != 0) && !llvm::has_single_bit(alignment.value()))
5304 <<
"ALIGN value : " << alignment.value() <<
" must be power of 2";
5309LogicalResult AllocateDirOp::verify() {
5317LogicalResult AllocSharedMemOp::verify() {
5325LogicalResult FreeSharedMemOp::verify() {
5333LogicalResult WorkdistributeOp::verify() {
5335 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
5338 Region ®ion = getRegion();
5343 if (entryBlock.
empty())
5344 return emitOpError(
"region must contain a structured block");
5346 bool hasTerminator =
false;
5347 for (
Block &block : region) {
5348 if (isa<TerminatorOp>(block.
back())) {
5349 if (hasTerminator) {
5350 return emitOpError(
"region must have exactly one terminator");
5352 hasTerminator =
true;
5355 if (!hasTerminator) {
5356 return emitOpError(
"region must be terminated with omp.terminator");
5360 if (isa<BarrierOp>(op)) {
5362 "explicit barriers are not allowed in workdistribute region");
5365 if (isa<ParallelOp>(op)) {
5367 "nested parallel constructs not allowed in workdistribute");
5369 if (isa<TeamsOp>(op)) {
5371 "nested teams constructs not allowed in workdistribute");
5375 if (walkResult.wasInterrupted())
5379 if (!llvm::dyn_cast<TeamsOp>(parentOp))
5380 return emitOpError(
"workdistribute must be nested under teams");
5388LogicalResult DeclareSimdOp::verify() {
5391 dyn_cast_if_present<mlir::FunctionOpInterface>((*this)->getParentOp());
5393 return emitOpError() <<
"must be nested inside a function";
5395 if (getInbranch() && getNotinbranch())
5396 return emitOpError(
"cannot have both 'inbranch' and 'notinbranch'");
5406 const DeclareSimdOperands &clauses) {
5408 DeclareSimdOp::build(odsBuilder, odsState, clauses.alignedVars,
5410 clauses.linearVars, clauses.linearStepVars,
5411 clauses.linearVarTypes, clauses.linearModifiers,
5412 clauses.notinbranch, clauses.simdlen,
5413 clauses.uniformVars);
5430 return mlir::failure();
5431 return mlir::success();
5438 for (
unsigned i = 0; i < uniformVars.size(); ++i) {
5441 p << uniformVars[i] <<
" : " << uniformTypes[i];
5456 parser, iterated, iteratedTypes, affinityVars, affinityVarTypes,
5457 [&]() -> ParseResult {
return success(); })))
5491 OpAsmParser::Argument &arg = ivArgs.emplace_back();
5492 if (parser.parseArgument(arg))
5496 if (succeeded(parser.parseOptionalColon())) {
5497 if (parser.parseType(arg.type))
5500 arg.type = parser.getBuilder().getIndexType();
5512 OpAsmParser::UnresolvedOperand lb, ub, st;
5513 if (parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
5514 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
5515 parser.parseOperand(st))
5520 steps.push_back(st);
5528 if (ivArgs.size() != lbs.size())
5530 <<
"mismatch: " << ivArgs.size() <<
" variables but " << lbs.size()
5533 for (
auto &arg : ivArgs) {
5534 lbTypes.push_back(arg.type);
5535 ubTypes.push_back(arg.type);
5536 stepTypes.push_back(arg.type);
5556 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
5559 p << lbs[i] <<
" to " << ubs[i] <<
" step " << steps[i];
5567LogicalResult IteratorOp::verify() {
5568 auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().
getType());
5570 return emitOpError() <<
"result must be omp.iterated<entry_ty>";
5572 for (
auto [lb,
ub, step] : llvm::zip_equal(
5573 getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
5575 return emitOpError() <<
"loop step must not be zero";
5579 IntegerAttr stepAttr;
5585 const APInt &lbVal = lbAttr.getValue();
5586 const APInt &ubVal = ubAttr.getValue();
5587 const APInt &stepVal = stepAttr.getValue();
5588 if (stepVal.isStrictlyPositive() && lbVal.sgt(ubVal))
5589 return emitOpError() <<
"positive loop step requires lower bound to be "
5590 "less than or equal to upper bound";
5591 if (stepVal.isNegative() && lbVal.slt(ubVal))
5592 return emitOpError() <<
"negative loop step requires lower bound to be "
5593 "greater than or equal to upper bound";
5596 Block &
b = getRegion().front();
5597 auto yield = llvm::dyn_cast<omp::YieldOp>(
b.getTerminator());
5600 return emitOpError() <<
"region must be terminated by omp.yield";
5602 if (yield.getNumOperands() != 1)
5604 <<
"omp.yield in omp.iterator region must yield exactly one value";
5606 mlir::Type yieldedTy = yield.getOperand(0).getType();
5607 mlir::Type elemTy = iteratedTy.getElementType();
5609 if (yieldedTy != elemTy)
5610 return emitOpError() <<
"omp.iterated element type (" << elemTy
5611 <<
") does not match omp.yield operand type ("
5612 << yieldedTy <<
")";
5625 return emitOpError() <<
"expected symbol reference '" << getSymName()
5626 <<
"' to point to a global variable";
5628 if (isa<FunctionOpInterface>(symbol))
5629 return emitOpError() <<
"expected symbol reference '" << getSymName()
5630 <<
"' to point to a global variable, not a function";
5635#define GET_ATTRDEF_CLASSES
5636#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
5638#define GET_OP_CLASSES
5639#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
5641#define GET_TYPEDEF_CLASSES
5642#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 LogicalResult verifyAllocateClause(Operation *op, ValueRange allocateVars, ValueRange allocatorVars, DenseI64ArrayAttr allocateAlignments, DenseI64ArrayAttr allocatePrivateIndices, ValueRange privateVars={}, ArrayAttr privateSyms=nullptr, bool requirePrivateIndices=false)
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.