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<
351 if (!isa<DeclareTargetInterface>(op))
352 return op->
emitError() <<
"omp.declare_target can only be applied to "
353 "DeclareTargetInterface ops";
355 auto declareTargetAttr = dyn_cast<DeclareTargetAttr>(attr);
356 if (!declareTargetAttr)
358 <<
"omp.declare_target must be an #omp.declaretarget attribute";
360 if (isa<mlir::FunctionOpInterface>(op)) {
361 if (declareTargetAttr.getAutomap())
363 <<
"omp.declare_target 'automap' is not valid on functions";
366 if (declareTargetAttr.getCaptureClause() ==
367 mlir::omp::DeclareTargetCaptureClause::link)
369 <<
"omp.declare_target 'link' is not valid on functions";
372 if (declareTargetAttr.getImplicit())
374 <<
"omp.declare_target 'implicit' is only valid on functions";
380OpenMPDialect::verifyOperationAttribute(
Operation *op,
382 if (attribute.
getName() ==
"omp.declare_target")
410 allocatorVars.push_back(operand);
411 allocatorTypes.push_back(type);
417 allocateVars.push_back(operand);
418 allocateTypes.push_back(type);
429 for (
unsigned i = 0; i < allocateVars.size(); ++i) {
430 std::string separator = i == allocateVars.size() - 1 ?
"" :
", ";
431 p << allocatorVars[i] <<
" : " << allocatorTypes[i] <<
" -> ";
432 p << allocateVars[i] <<
" : " << allocateTypes[i] << separator;
440template <
typename ClauseAttr>
442 using ClauseT =
decltype(std::declval<ClauseAttr>().getValue());
447 if (std::optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
448 attr = ClauseAttr::get(parser.
getContext(), *enumValue);
451 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
454template <
typename ClauseAttr>
456 p << stringifyEnum(attr.getValue());
481 std::optional<omp::LinearModifier> linearModifier;
483 linearModifier = omp::LinearModifier::val;
485 linearModifier = omp::LinearModifier::ref;
487 linearModifier = omp::LinearModifier::uval;
490 bool hasLinearModifierParens = linearModifier.has_value();
491 if (hasLinearModifierParens && parser.
parseLParen())
499 if (hasLinearModifierParens && parser.
parseRParen())
502 linearVars.push_back(var);
503 linearTypes.push_back(type);
504 linearStepVars.push_back(stepVar);
505 linearStepTypes.push_back(stepType);
506 if (linearModifier) {
508 omp::LinearModifierAttr::get(parser.
getContext(), *linearModifier));
510 modifiers.push_back(UnitAttr::get(parser.
getContext()));
516 linearModifiers = ArrayAttr::get(parser.
getContext(), modifiers);
525 size_t linearVarsSize = linearVars.size();
526 for (
unsigned i = 0; i < linearVarsSize; ++i) {
530 Attribute modAttr = linearModifiers ? linearModifiers[i] :
nullptr;
531 auto mod = modAttr ? dyn_cast<omp::LinearModifierAttr>(modAttr) :
nullptr;
533 p << omp::stringifyLinearModifier(mod.getValue()) <<
"(";
535 p << linearVars[i] <<
" : " << linearTypes[i];
536 p <<
" = " << linearStepVars[i] <<
" : " << stepVarTypes[i];
552 if (!linearModifiers)
554 if (linearModifiers->size() != linearVars.size())
556 <<
"expected as many linear modifiers as linear variables";
557 if (!isDeclareSimd) {
558 for (
Attribute attr : *linearModifiers) {
561 auto modAttr = dyn_cast<omp::LinearModifierAttr>(attr);
564 omp::LinearModifier mod = modAttr.getValue();
565 if (mod == omp::LinearModifier::ref || mod == omp::LinearModifier::uval)
567 <<
"linear modifier '" << omp::stringifyLinearModifier(mod)
568 <<
"' may only be specified on a declare simd directive";
583 for (
const auto &it : nontemporalVars)
584 if (!nontemporalItems.insert(it).second)
585 return op->
emitOpError() <<
"nontemporal variable used more than once";
594 std::optional<ArrayAttr> alignments,
597 if (!alignedVars.empty()) {
598 if (!alignments || alignments->size() != alignedVars.size())
600 <<
"expected as many alignment values as aligned variables";
603 return op->
emitOpError() <<
"unexpected alignment values attribute";
609 for (
auto it : alignedVars)
610 if (!alignedItems.insert(it).second)
611 return op->
emitOpError() <<
"aligned variable used more than once";
617 for (
unsigned i = 0; i < (*alignments).size(); ++i) {
618 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>((*alignments)[i])) {
619 if (intAttr.getValue().sle(0))
620 return op->
emitOpError() <<
"alignment should be greater than 0";
622 return op->
emitOpError() <<
"expected integer alignment";
639 if (parser.parseOperand(alignedVars.emplace_back()) ||
640 parser.parseColonType(alignedTypes.emplace_back()) ||
641 parser.parseArrow() ||
642 parser.parseAttribute(alignmentVec.emplace_back())) {
649 alignmentsAttr = ArrayAttr::get(parser.getContext(), alignments);
656 std::optional<ArrayAttr> alignments) {
657 for (
unsigned i = 0; i < alignedVars.size(); ++i) {
660 p << alignedVars[i] <<
" : " << alignedVars[i].
getType();
661 p <<
" -> " << (*alignments)[i];
669 ArrayAttr privateSyms =
nullptr,
bool requirePrivateIndices =
false) {
670 if (allocateVars.size() != allocatorVars.size())
672 "expected equal sizes for allocate and allocator variables");
674 if (allocateVars.empty()) {
675 if (allocateAlignments)
677 "unexpected allocate alignments without allocate variables");
678 if (allocatePrivateIndices)
680 "unexpected allocate private indices without allocate variables");
684 if (allocateAlignments) {
686 if (alignments.size() != allocateVars.size())
688 "expected as many allocate alignments as allocate variables");
689 for (
int64_t alignment : alignments) {
691 return op->
emitError(
"expected non-negative allocate alignments");
692 if (alignment != 0 && (alignment & (alignment - 1)) != 0)
694 "expected positive allocate alignments to be powers of two");
698 if (!allocatePrivateIndices) {
699 if (requirePrivateIndices)
701 "expected an allocate private index for each allocate variable");
706 if (
indices.size() != allocateVars.size())
708 "expected as many allocate private indices as allocate variables");
711 for (
auto [allocateVar, privateIndex] :
712 llvm::zip_equal(allocateVars,
indices)) {
713 if (privateIndex < 0 ||
714 static_cast<uint64_t
>(privateIndex) >= privateVars.size())
715 return op->
emitError(
"allocate private index is out of range");
716 if (!usedPrivateSlots.insert(privateIndex).second)
718 "allocate private index refers to a private variable more than once");
720 Value privateVar = privateVars[privateIndex];
721 if (allocateVar.getType() != privateVar.
getType())
723 <<
"type mismatch between allocate variable and private variable "
728 static_cast<uint64_t
>(privateIndex) >= privateSyms.size())
730 "allocate private index does not have a privatizer symbol");
732 auto privateSym = dyn_cast<SymbolRefAttr>(privateSyms[privateIndex]);
735 "allocate private index does not reference a privatizer symbol");
736 PrivateClauseOp privatizer =
739 return op->
emitError() <<
"failed to lookup privatizer op with symbol: '"
740 << privateSym <<
"'";
741 if (privatizer.getDataSharingType() != DataSharingClauseType::Private &&
742 privatizer.getDataSharingType() != DataSharingClauseType::FirstPrivate)
744 "allocate private index must refer to private or firstprivate "
758 if (modifiers.size() > 2)
760 for (
const auto &mod : modifiers) {
763 auto symbol = symbolizeScheduleModifier(mod);
766 <<
" unknown modifier type: " << mod;
771 if (modifiers.size() == 1) {
772 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
773 modifiers.push_back(modifiers[0]);
774 modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
776 }
else if (modifiers.size() == 2) {
779 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
780 symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
782 <<
" incorrect modifier order";
798 ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd,
799 std::optional<OpAsmParser::UnresolvedOperand> &chunkSize,
804 std::optional<mlir::omp::ClauseScheduleKind> schedule =
805 symbolizeClauseScheduleKind(keyword);
809 scheduleAttr = ClauseScheduleKindAttr::get(parser.
getContext(), *schedule);
811 case ClauseScheduleKind::Static:
812 case ClauseScheduleKind::Dynamic:
813 case ClauseScheduleKind::Guided:
819 chunkSize = std::nullopt;
822 case ClauseScheduleKind::Auto:
823 case ClauseScheduleKind::Runtime:
824 case ClauseScheduleKind::Distribute:
825 chunkSize = std::nullopt;
834 modifiers.push_back(mod);
840 if (!modifiers.empty()) {
842 if (std::optional<ScheduleModifier> mod =
843 symbolizeScheduleModifier(modifiers[0])) {
844 scheduleMod = ScheduleModifierAttr::get(parser.
getContext(), *mod);
846 return parser.
emitError(loc,
"invalid schedule modifier");
849 if (modifiers.size() > 1) {
850 assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
860 ClauseScheduleKindAttr scheduleKind,
861 ScheduleModifierAttr scheduleMod,
862 UnitAttr scheduleSimd,
Value scheduleChunk,
863 Type scheduleChunkType) {
864 p << stringifyClauseScheduleKind(scheduleKind.getValue());
866 p <<
" = " << scheduleChunk <<
" : " << scheduleChunk.
getType();
868 p <<
", " << stringifyScheduleModifier(scheduleMod.getValue());
880 ClauseOrderKindAttr &order,
881 OrderModifierAttr &orderMod) {
886 if (std::optional<OrderModifier> enumValue =
887 symbolizeOrderModifier(enumStr)) {
888 orderMod = OrderModifierAttr::get(parser.
getContext(), *enumValue);
895 if (std::optional<ClauseOrderKind> enumValue =
896 symbolizeClauseOrderKind(enumStr)) {
897 order = ClauseOrderKindAttr::get(parser.
getContext(), *enumValue);
900 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
904 ClauseOrderKindAttr order,
905 OrderModifierAttr orderMod) {
907 p << stringifyOrderModifier(orderMod.getValue()) <<
":";
909 p << stringifyClauseOrderKind(order.getValue());
912template <
typename ClauseTypeAttr,
typename ClauseType>
915 std::optional<OpAsmParser::UnresolvedOperand> &operand,
917 std::optional<ClauseType> (*symbolizeClause)(StringRef),
918 StringRef clauseName) {
921 if (std::optional<ClauseType> enumValue = symbolizeClause(enumStr)) {
922 prescriptiveness = ClauseTypeAttr::get(parser.
getContext(), *enumValue);
927 <<
"invalid " << clauseName <<
" modifier : '" << enumStr <<
"'";
937 <<
"expected " << clauseName <<
" operand";
940 if (operand.has_value()) {
948template <
typename ClauseTypeAttr,
typename ClauseType>
951 ClauseTypeAttr prescriptiveness,
Value operand,
953 StringRef (*stringifyClauseType)(ClauseType)) {
955 if (prescriptiveness)
956 p << stringifyClauseType(prescriptiveness.getValue()) <<
", ";
959 p << operand <<
": " << operandType;
969 std::optional<OpAsmParser::UnresolvedOperand> &grainsize,
970 Type &grainsizeType) {
972 parser, grainsizeMod, grainsize, grainsizeType,
973 &symbolizeClauseGrainsizeType,
"grainsize");
977 ClauseGrainsizeTypeAttr grainsizeMod,
980 p, op, grainsizeMod, grainsize, grainsizeType,
981 &stringifyClauseGrainsizeType);
991 std::optional<OpAsmParser::UnresolvedOperand> &numTasks,
992 Type &numTasksType) {
994 parser, numTasksMod, numTasks, numTasksType, &symbolizeClauseNumTasksType,
999 ClauseNumTasksTypeAttr numTasksMod,
1002 p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
1018 return mlir::failure();
1019 inTypeAttr = TypeAttr::get(inType);
1048 if (!typeparams.empty()) {
1049 p <<
'(' << typeparams <<
" : " << typeparamsTypes <<
')';
1051 for (
auto sh :
shape) {
1063 FallbackModifierAttr fallback,
1064 Value dynGroupprivateSize) {
1065 if (!dynGroupprivateSize && (accessGroup || fallback))
1066 return op->
emitOpError(
"dyn_groupprivate modifiers require a size operand");
1072 OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr,
1073 FallbackModifierAttr &fallbackAttr,
1074 std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
1077 bool parsedAccessGroup =
false;
1078 bool parsedFallback =
false;
1079 bool parsedSize =
false;
1084 if (parsedAccessGroup)
1086 "duplicate access group modifier");
1087 accessGroupAttr = AccessGroupModifierAttr::get(
1088 parser.
getContext(), AccessGroupModifier::cgroup);
1089 parsedAccessGroup =
true;
1096 "duplicate fallback modifier");
1099 "expected '(' after 'fallback'");
1100 llvm::StringRef fbKind;
1104 "expected fallback modifier (abort/null/default_mem)");
1105 std::optional<FallbackModifier> fbEnum;
1106 if (fbKind ==
"abort")
1107 fbEnum = FallbackModifier::abort;
1108 else if (fbKind ==
"null")
1109 fbEnum = FallbackModifier::null;
1110 else if (fbKind ==
"default_mem")
1111 fbEnum = FallbackModifier::default_mem;
1114 "invalid fallback modifier '" + fbKind +
"'");
1115 fallbackAttr = FallbackModifierAttr::get(parser.
getContext(), *fbEnum);
1118 "expected ')' after fallback modifier");
1119 parsedFallback =
true;
1127 "duplicate size operand");
1128 dynGroupprivateSize = operand;
1132 "expected ':' and type after size operand");
1136 "expected dyn_groupprivate_size operand");
1141 AccessGroupModifierAttr modifierFirst,
1142 FallbackModifierAttr modifierSecond,
1143 Value dynGroupprivateSize,
1146 bool needsComma =
false;
1148 if (modifierFirst) {
1149 printer << modifierFirst.getValue();
1153 if (modifierSecond) {
1156 printer <<
"fallback(";
1157 printer << modifierSecond.getValue();
1162 if (dynGroupprivateSize) {
1165 printer << dynGroupprivateSize <<
" : " << sizeType;
1185 isByRefVec.push_back(parser.parseOptionalKeyword(
"byref").succeeded());
1186 if (parser.parseAttribute(symbolVec.emplace_back()) ||
1187 parser.parseOperand(inReductionVars.emplace_back()))
1197 [&]() { return parser.parseType(inReductionTypes.emplace_back()); }))
1200 if (inReductionVars.size() != inReductionTypes.size())
1205 inReductionSyms = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1222 syms = ArrayAttr::get(ctx, values);
1231 llvm::interleaveComma(
1232 llvm::zip_equal(inReductionVars, syms.getValue(), byref.
asArrayRef()), p,
1234 auto [var, sym, isByRef] = t;
1242 llvm::interleaveComma(inReductionTypes, p);
1250struct MapParseArgs {
1251 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1252 SmallVectorImpl<Type> &types;
1253 MapParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1254 SmallVectorImpl<Type> &types)
1255 : vars(vars), types(types) {}
1257struct PrivateParseArgs {
1258 llvm::SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1259 llvm::SmallVectorImpl<Type> &types;
1261 UnitAttr &needsBarrier;
1263 PrivateParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1264 SmallVectorImpl<Type> &types,
ArrayAttr &syms,
1265 UnitAttr &needsBarrier,
1267 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1268 mapIndices(mapIndices) {}
1271struct ReductionParseArgs {
1272 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1273 SmallVectorImpl<Type> &types;
1276 ReductionModifierAttr *modifier;
1277 ReductionParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1279 ArrayAttr &syms, ReductionModifierAttr *mod =
nullptr)
1280 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1283struct AllRegionParseArgs {
1284 std::optional<MapParseArgs> hasDeviceAddrArgs;
1285 std::optional<MapParseArgs> hostEvalArgs;
1286 std::optional<ReductionParseArgs> inReductionArgs;
1287 std::optional<MapParseArgs> mapArgs;
1288 std::optional<PrivateParseArgs> privateArgs;
1289 std::optional<ReductionParseArgs> reductionArgs;
1290 std::optional<ReductionParseArgs> taskReductionArgs;
1291 std::optional<MapParseArgs> useDeviceAddrArgs;
1292 std::optional<MapParseArgs> useDevicePtrArgs;
1297 return "private_barrier";
1307 ReductionModifierAttr *modifier =
nullptr,
1308 UnitAttr *needsBarrier =
nullptr) {
1312 unsigned regionArgOffset = regionPrivateArgs.size();
1322 std::optional<ReductionModifier> enumValue =
1323 symbolizeReductionModifier(enumStr);
1324 if (!enumValue.has_value())
1326 *modifier = ReductionModifierAttr::get(parser.
getContext(), *enumValue);
1333 isByRefVec.push_back(
1334 parser.parseOptionalKeyword(
"byref").succeeded());
1336 if (symbols && parser.parseAttribute(symbolVec.emplace_back()))
1339 if (parser.parseOperand(operands.emplace_back()) ||
1340 parser.parseArrow() ||
1341 parser.parseArgument(regionPrivateArgs.emplace_back()))
1345 if (parser.parseOptionalLSquare().succeeded()) {
1346 if (parser.parseKeyword(
"map_idx") || parser.parseEqual() ||
1347 parser.parseInteger(mapIndicesVec.emplace_back()) ||
1348 parser.parseRSquare())
1351 mapIndicesVec.push_back(-1);
1363 if (parser.parseType(types.emplace_back()))
1370 if (operands.size() != types.size())
1379 *needsBarrier = mlir::UnitAttr::get(parser.
getContext());
1382 auto *argsBegin = regionPrivateArgs.begin();
1384 argsBegin + regionArgOffset + types.size());
1385 for (
auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
1391 *symbols = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1394 if (!mapIndicesVec.empty())
1407 StringRef keyword, std::optional<MapParseArgs> mapArgs) {
1422 StringRef keyword, std::optional<PrivateParseArgs> privateArgs) {
1428 parser, privateArgs->vars, privateArgs->types, entryBlockArgs,
1429 &privateArgs->syms, privateArgs->mapIndices,
nullptr,
1430 nullptr, &privateArgs->needsBarrier)))
1439 StringRef keyword, std::optional<ReductionParseArgs> reductionArgs) {
1444 parser, reductionArgs->vars, reductionArgs->types, entryBlockArgs,
1445 &reductionArgs->syms,
nullptr, &reductionArgs->byref,
1446 reductionArgs->modifier)))
1453 AllRegionParseArgs args) {
1457 args.hasDeviceAddrArgs)))
1459 <<
"invalid `has_device_addr` format";
1462 args.hostEvalArgs)))
1464 <<
"invalid `host_eval` format";
1467 args.inReductionArgs)))
1469 <<
"invalid `in_reduction` format";
1474 <<
"invalid `map_entries` format";
1479 <<
"invalid `private` format";
1482 args.reductionArgs)))
1484 <<
"invalid `reduction` format";
1487 args.taskReductionArgs)))
1489 <<
"invalid `task_reduction` format";
1492 args.useDeviceAddrArgs)))
1494 <<
"invalid `use_device_addr` format";
1497 args.useDevicePtrArgs)))
1499 <<
"invalid `use_device_addr` format";
1501 return parser.
parseRegion(region, entryBlockArgs);
1517 AllRegionParseArgs args;
1518 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1519 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1520 args.mapArgs.emplace(mapVars, mapTypes);
1521 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1522 privateNeedsBarrier, &privateMaps);
1533 UnitAttr &privateNeedsBarrier) {
1534 AllRegionParseArgs args;
1535 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1536 inReductionByref, inReductionSyms);
1537 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1538 privateNeedsBarrier);
1549 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1553 AllRegionParseArgs args;
1554 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1555 inReductionByref, inReductionSyms);
1556 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1557 privateNeedsBarrier);
1558 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1559 reductionSyms, &reductionMod);
1567 UnitAttr &privateNeedsBarrier) {
1568 AllRegionParseArgs args;
1569 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1570 privateNeedsBarrier);
1578 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1582 AllRegionParseArgs args;
1583 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1584 privateNeedsBarrier);
1585 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1586 reductionSyms, &reductionMod);
1595 AllRegionParseArgs args;
1596 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1597 taskReductionByref, taskReductionSyms);
1607 AllRegionParseArgs args;
1608 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1609 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1618struct MapPrintArgs {
1623struct PrivatePrintArgs {
1627 UnitAttr needsBarrier;
1631 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1632 mapIndices(mapIndices) {}
1634struct ReductionPrintArgs {
1639 ReductionModifierAttr modifier;
1641 ArrayAttr syms, ReductionModifierAttr mod =
nullptr)
1642 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1644struct AllRegionPrintArgs {
1645 std::optional<MapPrintArgs> hasDeviceAddrArgs;
1646 std::optional<MapPrintArgs> hostEvalArgs;
1647 std::optional<ReductionPrintArgs> inReductionArgs;
1648 std::optional<MapPrintArgs> mapArgs;
1649 std::optional<PrivatePrintArgs> privateArgs;
1650 std::optional<ReductionPrintArgs> reductionArgs;
1651 std::optional<ReductionPrintArgs> taskReductionArgs;
1652 std::optional<MapPrintArgs> useDeviceAddrArgs;
1653 std::optional<MapPrintArgs> useDevicePtrArgs;
1662 ReductionModifierAttr modifier =
nullptr, UnitAttr needsBarrier =
nullptr) {
1663 if (argsSubrange.empty())
1666 p << clauseName <<
"(";
1669 p <<
"mod: " << stringifyReductionModifier(modifier.getValue()) <<
", ";
1673 symbols = ArrayAttr::get(ctx, values);
1686 llvm::interleaveComma(llvm::zip_equal(operands, argsSubrange, symbols,
1687 mapIndices.asArrayRef(),
1688 byref.asArrayRef()),
1690 auto [op, arg, sym, map, isByRef] = t;
1696 p << op <<
" -> " << arg;
1699 p <<
" [map_idx=" << map <<
"]";
1702 llvm::interleaveComma(types, p);
1710 StringRef clauseName,
ValueRange argsSubrange,
1711 std::optional<MapPrintArgs> mapArgs) {
1718 StringRef clauseName,
ValueRange argsSubrange,
1719 std::optional<PrivatePrintArgs> privateArgs) {
1722 p, ctx, clauseName, argsSubrange, privateArgs->vars, privateArgs->types,
1723 privateArgs->syms, privateArgs->mapIndices,
nullptr,
1724 nullptr, privateArgs->needsBarrier);
1730 std::optional<ReductionPrintArgs> reductionArgs) {
1733 reductionArgs->vars, reductionArgs->types,
1734 reductionArgs->syms,
nullptr,
1735 reductionArgs->byref, reductionArgs->modifier);
1739 const AllRegionPrintArgs &args) {
1740 auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op);
1744 iface.getHasDeviceAddrBlockArgs(),
1745 args.hasDeviceAddrArgs);
1749 args.inReductionArgs);
1755 args.reductionArgs);
1757 iface.getTaskReductionBlockArgs(),
1758 args.taskReductionArgs);
1760 iface.getUseDeviceAddrBlockArgs(),
1761 args.useDeviceAddrArgs);
1763 iface.getUseDevicePtrBlockArgs(), args.useDevicePtrArgs);
1777 UnitAttr privateNeedsBarrier,
1779 AllRegionPrintArgs args;
1780 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1781 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1782 args.mapArgs.emplace(mapVars, mapTypes);
1783 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1784 privateNeedsBarrier, privateMaps);
1792 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier) {
1793 AllRegionPrintArgs args;
1794 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1795 inReductionByref, inReductionSyms);
1796 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1797 privateNeedsBarrier,
1806 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier,
1807 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1810 AllRegionPrintArgs args;
1811 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1812 inReductionByref, inReductionSyms);
1813 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1814 privateNeedsBarrier,
1816 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1817 reductionSyms, reductionMod);
1824 UnitAttr privateNeedsBarrier) {
1825 AllRegionPrintArgs args;
1826 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1827 privateNeedsBarrier,
1835 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1838 AllRegionPrintArgs args;
1839 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1840 privateNeedsBarrier,
1842 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1843 reductionSyms, reductionMod);
1853 AllRegionPrintArgs args;
1854 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1855 taskReductionByref, taskReductionSyms);
1865 AllRegionPrintArgs args;
1866 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1867 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1871template <
typename ParsePrefixFn>
1880 if (failed(parsePrefix()))
1888 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
1889 iteratedVars.push_back(v);
1890 iteratedTypes.push_back(ty);
1892 plainVars.push_back(v);
1893 plainTypes.push_back(ty);
1899template <
typename Pr
intPrefixFn>
1903 PrintPrefixFn &&printPrefixForPlain,
1904 PrintPrefixFn &&printPrefixForIterated) {
1911 p << v <<
" : " << t;
1915 for (
unsigned i = 0; i < iteratedVars.size(); ++i)
1916 emit(iteratedVars[i], iteratedTypes[i], printPrefixForIterated);
1917 for (
unsigned i = 0; i < plainVars.size(); ++i)
1918 emit(plainVars[i], plainTypes[i], printPrefixForPlain);
1926 if (!reductionVars.empty()) {
1927 if (!reductionSyms || reductionSyms->size() != reductionVars.size())
1929 <<
"expected as many reduction symbol references "
1930 "as reduction variables";
1931 if (reductionByref && reductionByref->size() != reductionVars.size())
1932 return op->
emitError() <<
"expected as many reduction variable by "
1933 "reference attributes as reduction variables";
1936 return op->
emitOpError() <<
"unexpected reduction symbol references";
1943 for (
auto args : llvm::zip(reductionVars, *reductionSyms)) {
1944 Value accum = std::get<0>(args);
1946 if (!accumulators.insert(accum).second)
1947 return op->
emitOpError() <<
"accumulator variable used more than once";
1950 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
1954 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
1955 <<
" to point to a reduction declaration";
1957 if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
1959 <<
"expected accumulator (" << varType
1960 <<
") to be the same type as reduction declaration ("
1961 << decl.getAccumulatorType() <<
")";
1980 if (parser.parseOperand(copyprivateVars.emplace_back()) ||
1981 parser.parseArrow() ||
1982 parser.parseAttribute(symsVec.emplace_back()) ||
1983 parser.parseColonType(copyprivateTypes.emplace_back()))
1989 copyprivateSyms = ArrayAttr::get(parser.
getContext(), syms);
1997 std::optional<ArrayAttr> copyprivateSyms) {
1998 if (!copyprivateSyms.has_value())
2000 llvm::interleaveComma(
2001 llvm::zip(copyprivateVars, *copyprivateSyms, copyprivateTypes), p,
2002 [&](
const auto &args) {
2003 p << std::get<0>(args) <<
" -> " << std::get<1>(args) <<
" : "
2004 << std::get<2>(args);
2011 std::optional<ArrayAttr> copyprivateSyms) {
2012 size_t copyprivateSymsSize =
2013 copyprivateSyms.has_value() ? copyprivateSyms->size() : 0;
2014 if (copyprivateSymsSize != copyprivateVars.size())
2015 return op->
emitOpError() <<
"inconsistent number of copyprivate vars (= "
2016 << copyprivateVars.size()
2017 <<
") and functions (= " << copyprivateSymsSize
2018 <<
"), both must be equal";
2019 if (!copyprivateSyms.has_value())
2022 for (
auto copyprivateVarAndSym :
2023 llvm::zip(copyprivateVars, *copyprivateSyms)) {
2025 llvm::cast<SymbolRefAttr>(std::get<1>(copyprivateVarAndSym));
2026 std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
2028 if (mlir::func::FuncOp mlirFuncOp =
2031 funcOp = mlirFuncOp;
2032 else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
2035 funcOp = llvmFuncOp;
2037 auto getNumArguments = [&] {
2038 return std::visit([](
auto &f) {
return f.getNumArguments(); }, *funcOp);
2041 auto getArgumentType = [&](
unsigned i) {
2042 return std::visit([i](
auto &f) {
return f.getArgumentTypes()[i]; },
2047 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
2048 <<
" to point to a copy function";
2050 if (getNumArguments() != 2)
2052 <<
"expected copy function " << symbolRef <<
" to have 2 operands";
2054 Type argTy = getArgumentType(0);
2055 if (argTy != getArgumentType(1))
2056 return op->
emitOpError() <<
"expected copy function " << symbolRef
2057 <<
" arguments to have the same type";
2059 Type varType = std::get<0>(copyprivateVarAndSym).getType();
2060 if (argTy != varType)
2062 <<
"expected copy function arguments' type (" << argTy
2063 <<
") to be the same as copyprivate variable's type (" << varType
2088 OpAsmParser::UnresolvedOperand operand;
2090 if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
2091 parser.parseOperand(operand) || parser.parseColonType(ty))
2093 std::optional<ClauseTaskDepend> keywordDepend =
2094 symbolizeClauseTaskDepend(keyword);
2098 ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend);
2099 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
2100 iteratedVars.push_back(operand);
2101 iteratedTypes.push_back(ty);
2102 iterKindsVec.push_back(kindAttr);
2104 dependVars.push_back(operand);
2105 dependTypes.push_back(ty);
2106 kindsVec.push_back(kindAttr);
2112 dependKinds = ArrayAttr::get(parser.
getContext(), kinds);
2114 iteratedKinds = ArrayAttr::get(parser.
getContext(), iterKinds);
2121 std::optional<ArrayAttr> dependKinds,
2124 std::optional<ArrayAttr> iteratedKinds) {
2127 std::optional<ArrayAttr> kinds) {
2128 for (
unsigned i = 0, e = vars.size(); i < e; ++i) {
2131 p << stringifyClauseTaskDepend(
2132 llvm::cast<mlir::omp::ClauseTaskDependAttr>((*kinds)[i])
2134 <<
" -> " << vars[i] <<
" : " << types[i];
2138 printEntries(dependVars, dependTypes, dependKinds);
2139 printEntries(iteratedVars, iteratedTypes, iteratedKinds);
2144 std::optional<ArrayAttr> dependKinds,
2146 std::optional<ArrayAttr> iteratedKinds,
2148 if (!dependVars.empty()) {
2149 if (!dependKinds || dependKinds->size() != dependVars.size())
2150 return op->
emitOpError() <<
"expected as many depend values"
2151 " as depend variables";
2153 if (dependKinds && !dependKinds->empty())
2154 return op->
emitOpError() <<
"unexpected depend values";
2157 if (!iteratedVars.empty()) {
2158 if (!iteratedKinds || iteratedKinds->size() != iteratedVars.size())
2159 return op->
emitOpError() <<
"expected as many depend iterated values"
2160 " as depend iterated variables";
2162 if (iteratedKinds && !iteratedKinds->empty())
2163 return op->
emitOpError() <<
"unexpected depend iterated values";
2178 IntegerAttr &hintAttr) {
2179 StringRef hintKeyword;
2185 auto parseKeyword = [&]() -> ParseResult {
2188 if (hintKeyword ==
"uncontended")
2190 else if (hintKeyword ==
"contended")
2192 else if (hintKeyword ==
"nonspeculative")
2194 else if (hintKeyword ==
"speculative")
2198 << hintKeyword <<
" is not a valid hint";
2209 IntegerAttr hintAttr) {
2210 int64_t hint = hintAttr.getInt();
2218 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2220 bool uncontended = bitn(hint, 0);
2221 bool contended = bitn(hint, 1);
2222 bool nonspeculative = bitn(hint, 2);
2223 bool speculative = bitn(hint, 3);
2227 hints.push_back(
"uncontended");
2229 hints.push_back(
"contended");
2231 hints.push_back(
"nonspeculative");
2233 hints.push_back(
"speculative");
2235 llvm::interleaveComma(hints, p);
2242 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2244 bool uncontended = bitn(hint, 0);
2245 bool contended = bitn(hint, 1);
2246 bool nonspeculative = bitn(hint, 2);
2247 bool speculative = bitn(hint, 3);
2249 if (uncontended && contended)
2250 return op->
emitOpError() <<
"the hints omp_sync_hint_uncontended and "
2251 "omp_sync_hint_contended cannot be combined";
2252 if (nonspeculative && speculative)
2253 return op->
emitOpError() <<
"the hints omp_sync_hint_nonspeculative and "
2254 "omp_sync_hint_speculative cannot be combined.";
2265 return (value & flag) == flag;
2273static ParseResult parseMapClause(
OpAsmParser &parser,
2274 ClauseMapFlagsAttr &mapType) {
2275 ClauseMapFlags mapTypeBits = ClauseMapFlags::none;
2278 auto parseTypeAndMod = [&]() -> ParseResult {
2279 StringRef mapTypeMod;
2283 if (mapTypeMod ==
"always")
2284 mapTypeBits |= ClauseMapFlags::always;
2286 if (mapTypeMod ==
"implicit")
2287 mapTypeBits |= ClauseMapFlags::implicit;
2289 if (mapTypeMod ==
"ompx_hold")
2290 mapTypeBits |= ClauseMapFlags::ompx_hold;
2292 if (mapTypeMod ==
"close")
2293 mapTypeBits |= ClauseMapFlags::close;
2295 if (mapTypeMod ==
"present")
2296 mapTypeBits |= ClauseMapFlags::present;
2298 if (mapTypeMod ==
"to")
2299 mapTypeBits |= ClauseMapFlags::to;
2301 if (mapTypeMod ==
"from")
2302 mapTypeBits |= ClauseMapFlags::from;
2304 if (mapTypeMod ==
"tofrom")
2305 mapTypeBits |= ClauseMapFlags::to | ClauseMapFlags::from;
2307 if (mapTypeMod ==
"delete")
2308 mapTypeBits |= ClauseMapFlags::del;
2310 if (mapTypeMod ==
"storage")
2311 mapTypeBits |= ClauseMapFlags::storage;
2313 if (mapTypeMod ==
"return_param")
2314 mapTypeBits |= ClauseMapFlags::return_param;
2316 if (mapTypeMod ==
"private")
2317 mapTypeBits |= ClauseMapFlags::priv;
2319 if (mapTypeMod ==
"literal")
2320 mapTypeBits |= ClauseMapFlags::literal;
2322 if (mapTypeMod ==
"attach")
2323 mapTypeBits |= ClauseMapFlags::attach;
2325 if (mapTypeMod ==
"attach_always")
2326 mapTypeBits |= ClauseMapFlags::attach_always;
2328 if (mapTypeMod ==
"attach_never")
2329 mapTypeBits |= ClauseMapFlags::attach_never;
2331 if (mapTypeMod ==
"attach_auto")
2332 mapTypeBits |= ClauseMapFlags::attach_auto;
2334 if (mapTypeMod ==
"ref_ptr")
2335 mapTypeBits |= ClauseMapFlags::ref_ptr;
2337 if (mapTypeMod ==
"ref_ptee")
2338 mapTypeBits |= ClauseMapFlags::ref_ptee;
2340 if (mapTypeMod ==
"is_device_ptr")
2341 mapTypeBits |= ClauseMapFlags::is_device_ptr;
2343 if (mapTypeMod ==
"target_param")
2344 mapTypeBits |= ClauseMapFlags::target_param;
2361 ClauseMapFlagsAttr mapType) {
2363 ClauseMapFlags mapFlags = mapType.getValue();
2368 mapTypeStrs.push_back(
"always");
2370 mapTypeStrs.push_back(
"implicit");
2372 mapTypeStrs.push_back(
"ompx_hold");
2374 mapTypeStrs.push_back(
"close");
2376 mapTypeStrs.push_back(
"present");
2378 mapTypeStrs.push_back(
"target_param");
2387 mapTypeStrs.push_back(
"tofrom");
2389 mapTypeStrs.push_back(
"from");
2391 mapTypeStrs.push_back(
"to");
2394 mapTypeStrs.push_back(
"delete");
2396 mapTypeStrs.push_back(
"return_param");
2398 mapTypeStrs.push_back(
"storage");
2400 mapTypeStrs.push_back(
"private");
2402 mapTypeStrs.push_back(
"literal");
2404 mapTypeStrs.push_back(
"attach");
2406 mapTypeStrs.push_back(
"attach_always");
2408 mapTypeStrs.push_back(
"attach_never");
2410 mapTypeStrs.push_back(
"attach_auto");
2412 mapTypeStrs.push_back(
"ref_ptr");
2414 mapTypeStrs.push_back(
"ref_ptee");
2416 mapTypeStrs.push_back(
"is_device_ptr");
2417 if (mapFlags == ClauseMapFlags::none)
2418 mapTypeStrs.push_back(
"none");
2420 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
2421 p << mapTypeStrs[i];
2422 if (i + 1 < mapTypeStrs.size()) {
2428static ParseResult parseMembersIndex(
OpAsmParser &parser,
2432 auto parseIndices = [&]() -> ParseResult {
2437 APInt(64, value,
false)));
2451 memberIdxs.push_back(ArrayAttr::get(parser.
getContext(), values));
2455 if (!memberIdxs.empty())
2456 membersIdx = ArrayAttr::get(parser.
getContext(), memberIdxs);
2466 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
2468 auto memberIdx = cast<ArrayAttr>(v);
2469 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
2470 p << cast<IntegerAttr>(v2).getInt();
2477 VariableCaptureKindAttr mapCaptureType) {
2478 std::string typeCapStr;
2479 llvm::raw_string_ostream typeCap(typeCapStr);
2480 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
2482 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
2483 typeCap <<
"ByCopy";
2484 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
2485 typeCap <<
"VLAType";
2486 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
2492 VariableCaptureKindAttr &mapCaptureType) {
2493 StringRef mapCaptureKey;
2497 if (mapCaptureKey ==
"This")
2498 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2499 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
2500 if (mapCaptureKey ==
"ByRef")
2501 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2502 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
2503 if (mapCaptureKey ==
"ByCopy")
2504 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2505 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
2506 if (mapCaptureKey ==
"VLAType")
2507 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2508 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
2514 Operation *op, mlir::omp::MapInfoOp mapInfoOp,
2518 mlir::omp::ClauseMapFlags mapTypeBits = mapInfoOp.getMapType();
2521 bool from =
mapTypeToBool(mapTypeBits, ClauseMapFlags::from);
2524 bool always =
mapTypeToBool(mapTypeBits, ClauseMapFlags::always);
2525 bool close =
mapTypeToBool(mapTypeBits, ClauseMapFlags::close);
2526 bool implicit =
mapTypeToBool(mapTypeBits, ClauseMapFlags::implicit);
2527 bool attach =
mapTypeToBool(mapTypeBits, ClauseMapFlags::attach);
2529 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
2531 "to, from, tofrom and alloc map types are permitted");
2533 if (isa<TargetEnterDataOp>(op) && (from || del))
2534 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
2536 if (isa<TargetExitDataOp>(op) && to)
2538 "from, release and delete map types are permitted");
2540 if (isa<TargetUpdateOp>(op)) {
2543 "at least one of to or from map types must be "
2544 "specified, other map types are not permitted");
2547 if (!to && !from && !attach) {
2549 "at least one of to or from or attach map types must be "
2550 "specified, other map types are not permitted");
2553 auto updateVar = mapInfoOp.getVarPtr();
2555 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
2556 (from && updateToVars.contains(updateVar))) {
2559 "either to or from map types can be specified, not both");
2562 if (always || close || implicit) {
2565 "present, mapper and iterator map type modifiers are permitted");
2571 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
2575 if ((mapInfoOp.getVarPtrPtr() && !mapInfoOp.getVarPtrPtrType()) ||
2576 (!mapInfoOp.getVarPtrPtr() && mapInfoOp.getVarPtrPtrType())) {
2578 "if varPtrPtr or varPtrPtrType is specified, then both "
2590 for (
auto mapOp : mapVars) {
2591 if (!mapOp.getDefiningOp())
2594 if (
auto mapInfoOp = mapOp.getDefiningOp<mlir::omp::MapInfoOp>()) {
2598 }
else if (!isa<DeclareMapperInfoOp>(op)) {
2600 "map argument is not a map entry operation");
2605 for (
auto iterVal : mapIterated) {
2606 auto iterOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
2608 return op->
emitOpError() <<
"'map_iterated' arguments must be defined by "
2609 "'omp.iterator' ops";
2613 cast<mlir::omp::YieldOp>(iterOp.getRegion().front().getTerminator());
2614 auto yieldedMapInfo =
2615 yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
2616 if (!yieldedMapInfo)
2617 return op->
emitOpError() <<
"'map_iterated' iterator body must yield "
2618 "a value defined by 'omp.map.info'";
2628template <
typename OpType>
2632 std::optional<DenseI64ArrayAttr> privateMapIndices =
2633 targetOp.getPrivateMapsAttr();
2636 if (!privateMapIndices.has_value() || !privateMapIndices.value())
2641 if (privateMapIndices.value().size() !=
2642 static_cast<int64_t>(privateVars.size()))
2643 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
2644 "`private_maps` attribute mismatch");
2654 StringRef clauseName,
2656 for (
Value var : vars)
2657 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
2659 <<
"'" << clauseName
2660 <<
"' arguments must be defined by 'omp.map.info' ops";
2664LogicalResult MapInfoOp::verify() {
2665 if (getMapperId() &&
2667 *
this, getMapperIdAttr())) {
2682 const TargetDataOperands &clauses) {
2683 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
2684 clauses.mapVars, clauses.mapIterated,
2685 clauses.useDeviceAddrVars, clauses.useDevicePtrVars);
2688LogicalResult TargetDataOp::verify() {
2689 if (getMapVars().empty() && getMapIterated().empty() &&
2690 getUseDevicePtrVars().empty() && getUseDeviceAddrVars().empty()) {
2691 return ::emitError(this->getLoc(),
2692 "At least one of map, use_device_ptr_vars, or "
2693 "use_device_addr_vars operand must be present");
2697 getUseDevicePtrVars())))
2701 getUseDeviceAddrVars())))
2711void TargetEnterDataOp::build(
2715 TargetEnterDataOp::build(
2717 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2718 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2719 clauses.mapIterated, clauses.nowait);
2722LogicalResult TargetEnterDataOp::verify() {
2723 LogicalResult verifyDependVars =
2725 getDependIteratedKinds(), getDependIterated());
2726 return failed(verifyDependVars)
2738 TargetExitDataOp::build(
2740 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2741 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2742 clauses.mapIterated, clauses.nowait);
2745LogicalResult TargetExitDataOp::verify() {
2746 LogicalResult verifyDependVars =
2748 getDependIteratedKinds(), getDependIterated());
2749 return failed(verifyDependVars)
2761 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
2764 clauses.dependIterated, clauses.device, clauses.ifExpr,
2765 clauses.mapVars, clauses.mapIterated, clauses.nowait);
2768LogicalResult TargetUpdateOp::verify() {
2769 LogicalResult verifyDependVars =
2771 getDependIteratedKinds(), getDependIterated());
2772 return failed(verifyDependVars)
2785 builder, state, clauses.allocateVars, clauses.allocatorVars,
2788 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2789 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
2790 clauses.device, clauses.dynGroupprivateAccessGroup,
2791 clauses.dynGroupprivateFallback, clauses.dynGroupprivateSize,
2792 clauses.hasDeviceAddrVars, clauses.hostEvalVars, clauses.ifExpr,
2793 clauses.inReductionVars,
2795 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.isDevicePtrVars,
2796 clauses.mapVars, clauses.mapIterated, clauses.nowait, clauses.privateVars,
2797 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
2798 clauses.threadLimitVars,
nullptr, clauses.
kernelType);
2801bool TargetOp::hasHostEvalTripCount() {
2802 TargetExecMode mode = getKernelType();
2803 if (mode == TargetExecMode::spmd || mode == TargetExecMode::spmd_no_loop)
2806 if (mode == TargetExecMode::bare)
2812 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2813 if (
auto loopNestOp = dyn_cast_if_present<LoopNestOp>(capturedOp)) {
2815 loopNestOp.gatherWrappers(loopWrappers);
2817 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2818 if (isa<SimdOp>(innermostWrapper))
2819 innermostWrapper = std::next(innermostWrapper);
2821 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2822 if (numWrappers != 1)
2825 if (!isa<DistributeOp>(innermostWrapper))
2829 if (isa_and_present<TeamsOp>(parentOp) &&
2845 if (mapVarPtr == inReductionVar)
2851LogicalResult TargetOp::verify() {
2853 getOperation(), getAllocateVars(), getAllocatorVars(),
2854 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
2855 getPrivateVars(), getPrivateSymsAttr())))
2858 if (getKernelType() == TargetExecMode::bare && !isCombined())
2859 return emitOpError() <<
"bare kernel requires 'omp.combined'";
2862 getDependIteratedKinds(),
2863 getDependIterated())))
2867 getHasDeviceAddrVars())))
2874 *
this, getDynGroupprivateAccessGroupAttr(),
2875 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
2882 getInReductionVars(),
2883 getInReductionByref())))
2891 for (
Value inReductionVar : getInReductionVars()) {
2892 bool captured =
false;
2893 for (
Value mapVar : getMapVars()) {
2894 auto mapInfo = mapVar.getDefiningOp<MapInfoOp>();
2901 return emitOpError() <<
"in_reduction variable must be captured by a "
2902 "matching map_entries entry";
2908LogicalResult TargetOp::verifyRegions() {
2909 auto teamsOps = getOps<TeamsOp>();
2910 auto numNestedTeams = std::distance(teamsOps.begin(), teamsOps.end());
2911 if (numNestedTeams > 1)
2912 return emitError(
"target containing multiple 'omp.teams' nested ops");
2914 if (numNestedTeams == 0) {
2915 switch (getKernelType()) {
2916 case TargetExecMode::bare:
2917 return emitOpError()
2918 <<
"bare kernel must contain a nested 'omp.teams' operation";
2919 case TargetExecMode::spmd_no_loop:
2920 return emitOpError() <<
"spmd_no_loop kernel must contain a nested "
2921 "'omp.teams' operation";
2928 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2929 if ((getKernelType() == TargetExecMode::spmd ||
2930 getKernelType() == TargetExecMode::spmd_no_loop) &&
2931 !isa_and_present<LoopNestOp>(capturedOp))
2932 return emitOpError()
2933 <<
"SPMD kernel must capture an 'omp.loop_nest' operation";
2935 bool isTargetDevice =
false;
2936 if (
auto offloadMod = (*this)->getParentOfType<OffloadModuleInterface>())
2937 if (offloadMod.getIsTargetDevice())
2938 isTargetDevice =
true;
2942 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs();
2944 bool hostEvalTripCount = hasHostEvalTripCount();
2945 for (
Value hostEvalArg : hostEvalBlockArgs) {
2947 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
2949 if (hostEvalArg == teamsOp.getNumTeamsLower() ||
2950 llvm::is_contained(teamsOp.getNumTeamsUpperVars(), hostEvalArg) ||
2951 llvm::is_contained(teamsOp.getThreadLimitVars(), hostEvalArg))
2954 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
2955 "and 'thread_limit' in 'omp.teams'";
2957 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
2958 if (llvm::is_contained(parallelOp.getNumThreadsVars(), hostEvalArg))
2961 return emitOpError()
2962 <<
"host_eval argument only legal as 'num_threads' in "
2965 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
2966 if (hostEvalTripCount &&
2967 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
2968 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
2969 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
2972 return emitOpError() <<
"host_eval argument only legal as loop bounds "
2973 "and steps in 'omp.loop_nest' when trip count "
2974 "must be evaluated in the host";
2977 return emitOpError() <<
"host_eval argument illegal use in '"
2978 << user->getName() <<
"' operation";
2982 if (hostEvalTripCount && !isTargetDevice) {
2983 auto loopOp = cast<LoopNestOp>(capturedOp);
2984 for (
auto arg : llvm::concat<Value>(loopOp.getLoopLowerBounds(),
2985 loopOp.getLoopUpperBounds(),
2986 loopOp.getLoopSteps())) {
2987 if (!llvm::is_contained(hostEvalBlockArgs, arg))
2988 return emitOpError() <<
"nested 'omp.loop_nest' bounds expected to "
2989 "be host-evaluated";
3002 ParallelOp::build(builder, state,
ValueRange(),
3016 const ParallelOperands &clauses) {
3018 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3021 clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
3023 clauses.privateNeedsBarrier, clauses.procBindKind,
3024 clauses.reductionMod, clauses.reductionVars,
3029template <
typename OpType>
3031 auto privateVars = op.getPrivateVars();
3032 auto privateSyms = op.getPrivateSymsAttr();
3034 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
3037 auto numPrivateVars = privateVars.size();
3038 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
3040 if (numPrivateVars != numPrivateSyms)
3041 return op.emitError() <<
"inconsistent number of private variables and "
3042 "privatizer op symbols, private vars: "
3044 <<
" vs. privatizer op symbols: " << numPrivateSyms;
3046 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
3047 Type varType = std::get<0>(privateVarInfo).getType();
3048 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
3049 PrivateClauseOp privatizerOp =
3052 if (privatizerOp ==
nullptr)
3053 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
3054 << privateSym <<
"'";
3056 Type privatizerType = privatizerOp.getArgType();
3058 if (privatizerType && (varType != privatizerType))
3059 return op.emitError()
3060 <<
"type mismatch between a "
3061 << (privatizerOp.getDataSharingType() ==
3062 DataSharingClauseType::Private
3065 <<
" variable and its privatizer op, var type: " << varType
3066 <<
" vs. privatizer op type: " << privatizerType;
3072LogicalResult ParallelOp::verify() {
3076 getOperation(), getAllocateVars(), getAllocatorVars(),
3077 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3078 getPrivateVars(), getPrivateSymsAttr(),
3083 getReductionByref());
3086LogicalResult ParallelOp::verifyRegions() {
3087 auto distChildOps = getOps<DistributeOp>();
3088 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
3089 if (numDistChildOps > 1)
3091 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
3093 if (numDistChildOps == 1) {
3096 <<
"'omp.composite' attribute missing from composite operation";
3098 auto *ompDialect =
getContext()->getLoadedDialect<OpenMPDialect>();
3099 Operation &distributeOp = **distChildOps.begin();
3101 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
3105 return emitError() <<
"unexpected OpenMP operation inside of composite "
3107 << childOp.getName();
3109 }
else if (isComposite()) {
3111 <<
"'omp.composite' attribute present in non-composite operation";
3128 const TeamsOperands &clauses) {
3132 builder, state, clauses.allocateVars, clauses.allocatorVars,
3135 clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
3136 clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
3137 clauses.numTeamsUpperVars, {},
nullptr,
3138 nullptr, clauses.reductionMod,
3139 clauses.reductionVars,
3141 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
3148 if (numTeamsLower) {
3149 if (numTeamsUpperVars.size() != 1)
3151 "expected exactly one num_teams upper bound when lower bound is "
3155 "expected num_teams upper bound and lower bound to be "
3162LogicalResult TeamsOp::verify() {
3169 auto parentTarget = llvm::dyn_cast_if_present<TargetOp>(op->
getParentOp());
3171 return emitError(
"expected to be nested inside of omp.target or not nested "
3172 "in any OpenMP dialect operations");
3176 this->getNumTeamsUpperVars())))
3180 parentTarget.getKernelType() == TargetExecMode::spmd_no_loop &&
3181 (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
3182 return emitOpError() <<
"'num_teams' not allowed in SPMD-no-loop kernels";
3185 getOperation(), getAllocateVars(), getAllocatorVars(),
3186 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3187 getPrivateVars(), getPrivateSymsAttr())))
3191 op, getDynGroupprivateAccessGroupAttr(),
3192 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3199 getReductionByref());
3207 return getParentOp().getPrivateVars();
3211 return getParentOp().getReductionVars();
3219 const SectionsOperands &clauses) {
3222 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3227 clauses.reductionMod, clauses.reductionVars,
3232LogicalResult SectionsOp::verify() {
3234 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3237 getOperation(), getAllocateVars(), getAllocatorVars(),
3238 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3239 getPrivateVars(), getPrivateSymsAttr())))
3243 getReductionByref());
3246LogicalResult SectionsOp::verifyRegions() {
3247 for (
auto &inst : *getRegion().begin()) {
3248 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
3249 return emitOpError()
3250 <<
"expected omp.section op or terminator op inside region";
3262 const ScopeOperands &clauses) {
3264 ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3267 clauses.nowait, clauses.privateVars,
3269 clauses.privateNeedsBarrier, clauses.reductionMod,
3270 clauses.reductionVars,
3275LogicalResult ScopeOp::verify() {
3277 getOperation(), getAllocateVars(), getAllocatorVars(),
3278 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3279 getPrivateVars(), getPrivateSymsAttr())))
3286 getReductionByref());
3294 const SingleOperands &clauses) {
3297 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3300 clauses.copyprivateVars,
3301 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
3306LogicalResult SingleOp::verify() {
3308 getOperation(), getAllocateVars(), getAllocatorVars(),
3309 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3310 getPrivateVars(), getPrivateSymsAttr())))
3314 getCopyprivateSyms());
3322 const WorkshareOperands &clauses) {
3323 WorkshareOp::build(builder, state, clauses.nowait);
3326LogicalResult WorkshareOp::verify() {
3328 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3337LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
3338 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3340 return emitOpError() <<
"expected to be a standalone loop wrapper";
3349LogicalResult LoopWrapperInterface::verifyImpl() {
3353 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
3354 "and `SingleBlock` traits";
3357 return emitOpError() <<
"loop wrapper does not contain exactly one region";
3360 if (range_size(region.
getOps()) != 1)
3361 return emitOpError()
3362 <<
"loop wrapper does not contain exactly one nested op";
3365 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
3366 return emitOpError() <<
"nested in loop wrapper is not another loop "
3367 "wrapper or `omp.loop_nest`";
3376Operation *ComposableOpInterface::findCapturedOp() {
3380 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(op))
3381 return wrapperOp.getWrappedLoop();
3386 if (!isCombined() && !isComposite())
3391 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(&nestedOp))
3392 return wrapperOp.getWrappedLoop();
3394 if (
auto composableOp = dyn_cast<ComposableOpInterface>(&nestedOp))
3395 return composableOp.findCapturedOp();
3404LogicalResult ComposableOpInterface::verifyImpl() {
3408 return emitOpError() <<
"composable ops must have a single region";
3410 if (isComposite() && !isa<LoopWrapperInterface, ParallelOp>(op))
3411 return emitOpError() <<
"non-loop wrapper cannot be composite";
3417 auto count = llvm::count_if(
3419 if (isa<ComposableOpInterface, LoopWrapperInterface>(op)) {
3440 return emitOpError()
3441 <<
"multiple eligible child ops found in combined op";
3452 if (successor->isReachable(parentBlock))
3453 return emitOpError() <<
"nested combined child op is part of a loop";
3457 !domInfo.
dominates(parentBlock, &block))
3458 return emitOpError()
3459 <<
"nested combined child op doesn't unconditionally execute";
3469 const LoopOperands &clauses) {
3472 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
3474 clauses.privateNeedsBarrier, clauses.order, clauses.orderMod,
3475 clauses.reductionMod, clauses.reductionVars,
3480LogicalResult LoopOp::verify() {
3485 getReductionByref());
3488LogicalResult LoopOp::verifyRegions() {
3489 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3491 return emitOpError() <<
"expected to be a standalone loop wrapper";
3502 build(builder, state, {}, {},
3507 false,
nullptr,
nullptr,
3508 nullptr, {},
nullptr,
3519 const WsloopOperands &clauses) {
3522 builder, state, clauses.allocateVars, clauses.allocatorVars,
3525 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
3526 clauses.linearModifiers, clauses.nowait, clauses.order, clauses.orderMod,
3527 clauses.ordered, clauses.privateVars,
3528 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
3529 clauses.reductionMod, clauses.reductionVars,
3531 makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
3532 clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
3535LogicalResult WsloopOp::verify() {
3537 getOperation(), getAllocateVars(), getAllocatorVars(),
3538 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3539 getPrivateVars(), getPrivateSymsAttr())))
3545 if (getLinearVars().size() &&
3546 getLinearVarTypes().value().size() != getLinearVars().size())
3547 return emitError() <<
"Ill-formed type attributes for linear variables";
3553 getReductionByref());
3556LogicalResult WsloopOp::verifyRegions() {
3557 bool isCompositeChildLeaf =
3558 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3560 if (LoopWrapperInterface nested = getNestedWrapper()) {
3563 <<
"'omp.composite' attribute missing from composite wrapper";
3567 if (!isa<SimdOp>(nested))
3568 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3570 }
else if (isComposite() && !isCompositeChildLeaf) {
3572 <<
"'omp.composite' attribute present in non-composite wrapper";
3573 }
else if (!isComposite() && isCompositeChildLeaf) {
3575 <<
"'omp.composite' attribute missing from composite wrapper";
3586 const SimdOperands &clauses) {
3588 SimdOp::build(builder, state, clauses.alignedVars,
3590 clauses.linearVars, clauses.linearStepVars,
3591 clauses.linearVarTypes, clauses.linearModifiers,
3592 clauses.nontemporalVars, clauses.order, clauses.orderMod,
3593 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3594 clauses.privateNeedsBarrier, clauses.reductionMod,
3595 clauses.reductionVars,
3601LogicalResult SimdOp::verify() {
3602 if (getSimdlen().has_value() && getSafelen().has_value() &&
3603 getSimdlen().value() > getSafelen().value())
3604 return emitOpError()
3605 <<
"simdlen clause and safelen clause are both present, but the "
3606 "simdlen value is not less than or equal to safelen value";
3618 bool isCompositeChildLeaf =
3619 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3621 if (!isComposite() && isCompositeChildLeaf)
3623 <<
"'omp.composite' attribute missing from composite wrapper";
3625 if (isComposite() && !isCompositeChildLeaf)
3627 <<
"'omp.composite' attribute present in non-composite wrapper";
3631 std::optional<ArrayAttr> privateSyms = getPrivateSyms();
3633 for (
const Attribute &sym : *privateSyms) {
3634 auto symRef = cast<SymbolRefAttr>(sym);
3635 omp::PrivateClauseOp privatizer =
3637 getOperation(), symRef);
3639 return emitError() <<
"Cannot find privatizer '" << symRef <<
"'";
3640 if (privatizer.getDataSharingType() ==
3641 DataSharingClauseType::FirstPrivate)
3642 return emitError() <<
"FIRSTPRIVATE cannot be used with SIMD";
3649 if (getLinearVars().size() &&
3650 getLinearVarTypes().value().size() != getLinearVars().size())
3651 return emitError() <<
"Ill-formed type attributes for linear variables";
3656 for (
Value var : getLinearVars()) {
3657 if (privateVars.contains(var) || reductionVars.contains(var))
3658 return emitOpError()
3659 <<
"linear variables cannot appear in other data-sharing clauses";
3665LogicalResult SimdOp::verifyRegions() {
3666 if (getNestedWrapper())
3667 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
3677 const DistributeOperands &clauses) {
3678 DistributeOp::build(
3679 builder, state, clauses.allocateVars, clauses.allocatorVars,
3682 clauses.allocatePrivateIndices),
3683 clauses.distScheduleStatic, clauses.distScheduleChunkSize, clauses.order,
3684 clauses.orderMod, clauses.privateVars,
3686 clauses.privateNeedsBarrier);
3689LogicalResult DistributeOp::verify() {
3690 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
3691 return emitOpError() <<
"chunk size set without "
3692 "dist_schedule_static being present";
3695 getOperation(), getAllocateVars(), getAllocatorVars(),
3696 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3697 getPrivateVars(), getPrivateSymsAttr())))
3706LogicalResult DistributeOp::verifyRegions() {
3707 if (LoopWrapperInterface nested = getNestedWrapper()) {
3710 <<
"'omp.composite' attribute missing from composite wrapper";
3713 if (isa<WsloopOp>(nested)) {
3715 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
3716 !cast<ComposableOpInterface>(parentOp).isComposite()) {
3717 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
3718 "when a composite 'omp.parallel' is the direct "
3721 }
else if (!isa<SimdOp>(nested))
3722 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
3724 }
else if (isComposite()) {
3726 <<
"'omp.composite' attribute present in non-composite wrapper";
3737 const DeclareMapperInfoOperands &clauses) {
3738 DeclareMapperInfoOp::build(builder, state, clauses.mapVars,
3739 clauses.mapIterated);
3742LogicalResult DeclareMapperInfoOp::verify() {
3746LogicalResult DeclareMapperOp::verifyRegions() {
3747 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
3748 getRegion().getBlocks().front().getTerminator()))
3749 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
3758LogicalResult DeclareReductionOp::verifyRegions() {
3759 if (!getAllocRegion().empty()) {
3760 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
3761 if (yieldOp.getResults().size() != 1 ||
3762 yieldOp.getResults().getTypes()[0] !=
getType())
3763 return emitOpError() <<
"expects alloc region to yield a value "
3764 "of the reduction type";
3768 if (getInitializerRegion().empty())
3769 return emitOpError() <<
"expects non-empty initializer region";
3770 Block &initializerEntryBlock = getInitializerRegion().
front();
3773 if (!getAllocRegion().empty())
3774 return emitOpError() <<
"expects two arguments to the initializer region "
3775 "when an allocation region is used";
3777 if (getAllocRegion().empty())
3778 return emitOpError() <<
"expects one argument to the initializer region "
3779 "when no allocation region is used";
3781 return emitOpError()
3782 <<
"expects one or two arguments to the initializer region";
3786 if (arg.getType() !=
getType())
3787 return emitOpError() <<
"expects initializer region argument to match "
3788 "the reduction type";
3790 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
3791 if (yieldOp.getResults().size() != 1 ||
3792 yieldOp.getResults().getTypes()[0] !=
getType())
3793 return emitOpError() <<
"expects initializer region to yield a value "
3794 "of the reduction type";
3797 if (getReductionRegion().empty())
3798 return emitOpError() <<
"expects non-empty reduction region";
3799 Block &reductionEntryBlock = getReductionRegion().
front();
3804 return emitOpError() <<
"expects reduction region with two arguments of "
3805 "the reduction type";
3806 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
3807 if (yieldOp.getResults().size() != 1 ||
3808 yieldOp.getResults().getTypes()[0] !=
getType())
3809 return emitOpError() <<
"expects reduction region to yield a value "
3810 "of the reduction type";
3813 if (!getAtomicReductionRegion().empty()) {
3814 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
3818 return emitOpError() <<
"expects atomic reduction region with two "
3819 "arguments of the same type";
3820 auto ptrType = llvm::dyn_cast<PointerLikeType>(
3823 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
3824 return emitOpError() <<
"expects atomic reduction region arguments to "
3825 "be accumulators containing the reduction type";
3828 if (getCleanupRegion().empty())
3830 Block &cleanupEntryBlock = getCleanupRegion().
front();
3833 return emitOpError() <<
"expects cleanup region with one argument "
3834 "of the reduction type";
3844 const TaskOperands &clauses) {
3846 TaskOp::build(builder, state, clauses.iterated, clauses.affinityVars,
3847 clauses.allocateVars, clauses.allocatorVars,
3850 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
3852 clauses.dependIterated, clauses.final, clauses.ifExpr,
3853 clauses.inReductionVars,
3855 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3856 clauses.priority, clauses.privateVars,
3858 clauses.privateNeedsBarrier, clauses.threadset, clauses.untied,
3859 clauses.eventHandle);
3862LogicalResult TaskOp::verify() {
3864 getOperation(), getAllocateVars(), getAllocatorVars(),
3865 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3866 getPrivateVars(), getPrivateSymsAttr())))
3869 LogicalResult verifyDependVars =
3871 getDependIteratedKinds(), getDependIterated());
3872 if (
failed(verifyDependVars))
3873 return verifyDependVars;
3879 getInReductionVars(), getInReductionByref());
3887 const TaskgroupOperands &clauses) {
3889 TaskgroupOp::build(builder, state, clauses.allocateVars,
3890 clauses.allocatorVars,
3893 clauses.taskReductionVars,
3898LogicalResult TaskgroupOp::verify() {
3900 getOperation(), getAllocateVars(), getAllocatorVars(),
3901 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr())))
3905 getTaskReductionVars(),
3906 getTaskReductionByref());
3914 const TaskloopContextOperands &clauses) {
3916 TaskloopContextOp::build(
3917 builder, state, clauses.allocateVars, clauses.allocatorVars,
3920 clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
3921 clauses.inReductionVars,
3923 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3924 clauses.nogroup, clauses.numTasksMod, clauses.numTasks, clauses.priority,
3925 clauses.privateVars,
3927 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3929 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadset,
3931 state.
addAttribute(
"omp.combined", UnitAttr::get(ctx));
3934TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
3935 return cast<TaskloopWrapperOp>(
3937 return isa<TaskloopWrapperOp>(op);
3941LogicalResult TaskloopContextOp::verify() {
3945 getOperation(), getAllocateVars(), getAllocatorVars(),
3946 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3947 getPrivateVars(), getPrivateSymsAttr())))
3951 getReductionVars(), getReductionByref())) ||
3953 getInReductionVars(),
3954 getInReductionByref())))
3957 if (!getReductionVars().empty() && getNogroup())
3958 return emitError(
"if a reduction clause is present on the taskloop "
3959 "directive, the nogroup clause must not be specified");
3960 for (
auto var : getReductionVars()) {
3961 if (llvm::is_contained(getInReductionVars(), var))
3962 return emitError(
"the same list item cannot appear in both a reduction "
3963 "and an in_reduction clause");
3966 if (getGrainsize() && getNumTasks()) {
3968 "the grainsize clause and num_tasks clause are mutually exclusive and "
3969 "may not appear on the same taskloop directive");
3977 return emitOpError(
"must always contain the 'omp.combined' attribute");
3982LogicalResult TaskloopContextOp::verifyRegions() {
3983 Region ®ion = getRegion();
3985 return isa<TaskloopWrapperOp>(op);
3987 if (loopWrapperIt == region.
front().
end())
3988 return emitOpError()
3989 <<
"expected a TaskloopWrapperOp directly nested in the region";
3991 auto loopWrapperOp = cast<TaskloopWrapperOp>(*loopWrapperIt);
3992 auto loopNestOp = dyn_cast<LoopNestOp>(loopWrapperOp.getWrappedLoop());
3998 std::function<
bool(
Value)> isValidBoundValue = [&](
Value value) ->
bool {
3999 Region *valueRegion = value.getParentRegion();
4005 Operation *defOp = value.getDefiningOp();
4009 return llvm::all_of(defOp->
getOperands(), isValidBoundValue);
4011 auto hasUnsupportedTaskloopLocalBound = [&](
OperandRange range) ->
bool {
4012 return llvm::any_of(range,
4013 [&](
Value value) {
return !isValidBoundValue(value); });
4016 if (hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopLowerBounds()) ||
4017 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopUpperBounds()) ||
4018 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopSteps())) {
4019 return emitOpError()
4020 <<
"expects loop bounds and steps to be defined outside of the "
4021 "taskloop.context region or by pure, regionless operations "
4022 "that do not depend on block arguments";
4033 const TaskloopWrapperOperands &clauses) {
4034 TaskloopWrapperOp::build(builder, state);
4037TaskloopContextOp TaskloopWrapperOp::getTaskloopContext() {
4038 return dyn_cast<TaskloopContextOp>(getOperation()->getParentOp());
4041LogicalResult TaskloopWrapperOp::verify() {
4042 TaskloopContextOp context = getTaskloopContext();
4044 return emitOpError() <<
"expected to be nested in a taskloop context op";
4048LogicalResult TaskloopWrapperOp::verifyRegions() {
4049 if (LoopWrapperInterface nested = getNestedWrapper()) {
4052 <<
"'omp.composite' attribute missing from composite wrapper";
4056 if (!isa<SimdOp>(nested))
4057 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
4058 }
else if (isComposite()) {
4060 <<
"'omp.composite' attribute present in non-composite wrapper";
4084 for (
auto &iv : ivs)
4085 iv.type = loopVarType;
4090 result.addAttribute(
"loop_inclusive", UnitAttr::get(ctx));
4106 "collapse_num_loops",
4111 auto parseTiles = [&]() -> ParseResult {
4115 tiles.push_back(
tile);
4124 if (tiles.size() > 0)
4143 Region ®ion = getRegion();
4145 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
4146 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
4147 if (getLoopInclusive())
4149 p <<
"step (" << getLoopSteps() <<
") ";
4150 if (
int64_t numCollapse = getCollapseNumLoops())
4151 if (numCollapse > 1)
4152 p <<
"collapse(" << numCollapse <<
") ";
4155 p <<
"tiles(" << tiles.value() <<
") ";
4161 const LoopNestOperands &clauses) {
4163 LoopNestOp::build(builder, state, clauses.collapseNumLoops,
4164 clauses.loopLowerBounds, clauses.loopUpperBounds,
4165 clauses.loopSteps, clauses.loopInclusive,
4169LogicalResult LoopNestOp::verify() {
4170 if (getLoopLowerBounds().empty())
4171 return emitOpError() <<
"must represent at least one loop";
4173 if (getLoopLowerBounds().size() != getIVs().size())
4174 return emitOpError() <<
"number of range arguments and IVs do not match";
4176 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
4177 if (lb.getType() != iv.getType())
4178 return emitOpError()
4179 <<
"range argument type does not match corresponding IV type";
4182 uint64_t numIVs = getIVs().size();
4184 if (
const auto &numCollapse = getCollapseNumLoops())
4185 if (numCollapse > numIVs)
4186 return emitOpError()
4187 <<
"collapse value is larger than the number of loops";
4190 if (tiles.value().size() > numIVs)
4191 return emitOpError() <<
"too few canonical loops for tile dimensions";
4193 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
4194 return emitOpError() <<
"expects parent op to be a loop wrapper";
4199void LoopNestOp::gatherWrappers(
4202 while (
auto wrapper =
4203 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
4204 wrappers.push_back(wrapper);
4213std::tuple<NewCliOp, OpOperand *, OpOperand *>
4219 return {{},
nullptr,
nullptr};
4222 "Unexpected type of cli");
4228 auto op = cast<LoopTransformationInterface>(use.getOwner());
4230 unsigned opnum = use.getOperandNumber();
4231 if (op.isGeneratee(opnum)) {
4232 assert(!gen &&
"Each CLI may have at most one def");
4234 }
else if (op.isApplyee(opnum)) {
4235 assert(!cons &&
"Each CLI may have at most one consumer");
4238 llvm_unreachable(
"Unexpected operand for a CLI");
4242 return {create, gen, cons};
4248 case llvm::omp::ProcBindKind::OMP_PROC_BIND_close:
4249 return ClauseProcBindKind::Close;
4250 case llvm::omp::ProcBindKind::OMP_PROC_BIND_master:
4251 return ClauseProcBindKind::Master;
4252 case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary:
4253 return ClauseProcBindKind::Primary;
4254 case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread:
4255 return ClauseProcBindKind::Spread;
4256 case llvm::omp::ProcBindKind::OMP_PROC_BIND_default:
4257 case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown:
4260 llvm_unreachable(
"unexpected proc-bind kind");
4283 std::string cliName{
"cli"};
4287 .Case([&](CanonicalLoopOp op) {
4290 .Case([&](UnrollHeuristicOp op) -> std::string {
4291 llvm_unreachable(
"heuristic unrolling does not generate a loop");
4293 .Case([&](FuseOp op) -> std::string {
4294 unsigned opnum =
generator->getOperandNumber();
4297 if (op.getFirst().has_value() && opnum != op.getFirst().value())
4298 return "canonloop_fuse";
4302 .Case([&](TileOp op) -> std::string {
4303 auto [generateesFirst, generateesCount] =
4304 op.getGenerateesODSOperandIndexAndLength();
4305 unsigned firstGrid = generateesFirst;
4306 unsigned firstIntratile = generateesFirst + generateesCount / 2;
4307 unsigned end = generateesFirst + generateesCount;
4308 unsigned opnum =
generator->getOperandNumber();
4310 if (firstGrid <= opnum && opnum < firstIntratile) {
4311 unsigned gridnum = opnum - firstGrid + 1;
4312 return (
"grid" + Twine(gridnum)).str();
4314 if (firstIntratile <= opnum && opnum < end) {
4315 unsigned intratilenum = opnum - firstIntratile + 1;
4316 return (
"intratile" + Twine(intratilenum)).str();
4318 llvm_unreachable(
"Unexpected generatee argument");
4320 .DefaultUnreachable(
"TODO: Custom name for this operation");
4323 setNameFn(
result, cliName);
4326LogicalResult NewCliOp::verify() {
4327 Value cli = getResult();
4330 "Unexpected type of cli");
4336 auto op = cast<mlir::omp::LoopTransformationInterface>(use.getOwner());
4338 unsigned opnum = use.getOperandNumber();
4339 if (op.isGeneratee(opnum)) {
4342 emitOpError(
"CLI must have at most one generator");
4344 .
append(
"first generator here:");
4346 .
append(
"second generator here:");
4351 }
else if (op.isApplyee(opnum)) {
4354 emitOpError(
"CLI must have at most one consumer");
4356 .
append(
"first consumer here:")
4360 .
append(
"second consumer here:")
4367 llvm_unreachable(
"Unexpected operand for a CLI");
4375 .
append(
"see consumer here: ")
4398 setNameFn(&getRegion().front(),
"body_entry");
4401void CanonicalLoopOp::getAsmBlockArgumentNames(
Region ®ion,
4409 p <<
'(' << getCli() <<
')';
4410 p <<
' ' << getInductionVar() <<
" : " << getInductionVar().getType()
4411 <<
" in range(" << getTripCount() <<
") ";
4421 CanonicalLoopInfoType cliType =
4422 CanonicalLoopInfoType::get(parser.
getContext());
4447 if (parser.
parseRegion(*region, {inductionVariable}))
4452 result.operands.append(cliOperand);
4458 return mlir::success();
4461LogicalResult CanonicalLoopOp::verify() {
4464 if (!getRegion().empty()) {
4465 Region ®ion = getRegion();
4468 "Canonical loop region must have exactly one argument");
4472 "Region argument must be the same type as the trip count");
4478Value CanonicalLoopOp::getInductionVar() {
return getRegion().getArgument(0); }
4480std::pair<unsigned, unsigned>
4481CanonicalLoopOp::getApplyeesODSOperandIndexAndLength() {
4486std::pair<unsigned, unsigned>
4487CanonicalLoopOp::getGenerateesODSOperandIndexAndLength() {
4488 return getODSOperandIndexAndLength(odsIndex_cli);
4502 p <<
'(' << getApplyee() <<
')';
4509 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4532 return mlir::success();
4535std::pair<unsigned, unsigned>
4536UnrollHeuristicOp ::getApplyeesODSOperandIndexAndLength() {
4537 return getODSOperandIndexAndLength(odsIndex_applyee);
4540std::pair<unsigned, unsigned>
4541UnrollHeuristicOp::getGenerateesODSOperandIndexAndLength() {
4555 p <<
'(' << getApplyee() <<
')';
4562 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4585 return mlir::success();
4588std::pair<unsigned, unsigned>
4589UnrollFullOp::getApplyeesODSOperandIndexAndLength() {
4590 return getODSOperandIndexAndLength(odsIndex_applyee);
4593std::pair<unsigned, unsigned>
4594UnrollFullOp::getGenerateesODSOperandIndexAndLength() {
4598LogicalResult UnrollFullOp::verify() {
4599 auto [create, gen, cons] =
decodeCli(getApplyee());
4601 return emitOpError() <<
"applyee CLI has no generator";
4605 if (
auto loop = dyn_cast<CanonicalLoopOp>(gen->getOwner())) {
4607 return emitOpError() <<
"applyee loop must have a constant trip count";
4619 uint64_t unrollFactor) {
4626 p <<
'(' << getApplyee() <<
')';
4629 attrs.emplace_back(getUnrollFactorAttrName(), getUnrollFactorAttr());
4636 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4653 return mlir::success();
4656std::pair<unsigned, unsigned>
4657UnrollPartialOp::getApplyeesODSOperandIndexAndLength() {
4658 return getODSOperandIndexAndLength(odsIndex_applyee);
4661std::pair<unsigned, unsigned>
4662UnrollPartialOp::getGenerateesODSOperandIndexAndLength() {
4673 if (!generatees.empty())
4674 p <<
'(' << llvm::interleaved(generatees) <<
')';
4676 if (!applyees.empty())
4677 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4719 bool isOnlyCanonLoops =
true;
4721 for (
Value applyee : op.getApplyees()) {
4722 auto [create, gen, cons] =
decodeCli(applyee);
4725 return op.emitOpError() <<
"applyee CLI has no generator";
4727 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4728 canonLoops.push_back(loop);
4730 isOnlyCanonLoops =
false;
4735 if (!isOnlyCanonLoops)
4739 for (
auto i : llvm::seq<int>(1, canonLoops.size())) {
4740 auto parentLoop = canonLoops[i - 1];
4741 auto loop = canonLoops[i];
4743 if (parentLoop.getOperation() != loop.getOperation()->getParentOp())
4744 return op.emitOpError()
4745 <<
"tiled loop nest must be nested within each other";
4747 parentIVs.insert(parentLoop.getInductionVar());
4752 bool isPerfectlyNested = [&]() {
4753 auto &parentBody = parentLoop.getRegion();
4754 if (!parentBody.hasOneBlock())
4756 auto &parentBlock = parentBody.getBlocks().
front();
4758 auto nestedLoopIt = parentBlock.
begin();
4759 if (nestedLoopIt == parentBlock.
end() ||
4760 (&*nestedLoopIt != loop.getOperation()))
4763 auto termIt = std::next(nestedLoopIt);
4764 if (termIt == parentBlock.
end() || !isa<TerminatorOp>(termIt))
4767 if (std::next(termIt) != parentBlock.
end())
4772 if (!isPerfectlyNested)
4773 return op.emitOpError() <<
"tiled loop nest must be perfectly nested";
4775 if (parentIVs.contains(loop.getTripCount()))
4776 return op.emitOpError() <<
"tiled loop nest must be rectangular";
4793LogicalResult TileOp::verify() {
4794 if (getApplyees().empty())
4795 return emitOpError() <<
"must apply to at least one loop";
4797 if (getSizes().size() != getApplyees().size())
4798 return emitOpError() <<
"there must be one tile size for each applyee";
4800 if (!getGeneratees().empty() &&
4801 2 * getSizes().size() != getGeneratees().size())
4802 return emitOpError()
4803 <<
"expecting two times the number of generatees than applyees";
4808std::pair<unsigned, unsigned> TileOp ::getApplyeesODSOperandIndexAndLength() {
4809 return getODSOperandIndexAndLength(odsIndex_applyees);
4812std::pair<unsigned, unsigned> TileOp::getGenerateesODSOperandIndexAndLength() {
4813 return getODSOperandIndexAndLength(odsIndex_generatees);
4823 if (!generatees.empty())
4824 p <<
'(' << llvm::interleaved(generatees) <<
')';
4826 if (!applyees.empty())
4827 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4830LogicalResult FuseOp::verify() {
4831 if (getApplyees().size() < 2)
4832 return emitOpError() <<
"must apply to at least two loops";
4834 if (getFirst().has_value() && getCount().has_value()) {
4835 int64_t first = getFirst().value();
4836 int64_t count = getCount().value();
4837 if ((
unsigned)(first + count - 1) > getApplyees().size())
4838 return emitOpError() <<
"the numbers of applyees must be at least first "
4839 "minus one plus count attributes";
4840 if (!getGeneratees().empty() &&
4841 getGeneratees().size() != getApplyees().size() + 1 - count)
4842 return emitOpError() <<
"the number of generatees must be the number of "
4843 "aplyees plus one minus count";
4846 if (!getGeneratees().empty() && getGeneratees().size() != 1)
4847 return emitOpError()
4848 <<
"in a complete fuse the number of generatees must be exactly 1";
4850 for (
auto &&applyee : getApplyees()) {
4851 auto [create, gen, cons] =
decodeCli(applyee);
4854 return emitOpError() <<
"applyee CLI has no generator";
4855 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4857 return emitOpError()
4858 <<
"currently only supports omp.canonical_loop as applyee";
4862std::pair<unsigned, unsigned> FuseOp::getApplyeesODSOperandIndexAndLength() {
4863 return getODSOperandIndexAndLength(odsIndex_applyees);
4866std::pair<unsigned, unsigned> FuseOp::getGenerateesODSOperandIndexAndLength() {
4867 return getODSOperandIndexAndLength(odsIndex_generatees);
4875 const CriticalDeclareOperands &clauses) {
4876 CriticalDeclareOp::build(builder, state, clauses.symName,
4877 clauses.symVisibility, clauses.hint);
4880LogicalResult CriticalDeclareOp::verify() {
4884LogicalResult CriticalOp::verify() {
4885 SymbolRefAttr currentName = getNameAttr();
4887 CriticalOp parentCritical = (*this)->getParentOfType<CriticalOp>();
4889 while (parentCritical) {
4890 SymbolRefAttr parentName = parentCritical.getNameAttr();
4892 if (currentName == parentName) {
4894 return emitOpError() <<
"cannot be nested inside another omp.critical "
4895 "region with the same name ("
4896 << currentName <<
")";
4898 return emitOpError() <<
"cannot be nested inside another unnamed "
4899 "omp.critical region";
4903 parentCritical = parentCritical->getParentOfType<CriticalOp>();
4910 if (getNameAttr()) {
4911 SymbolRefAttr symbolRef = getNameAttr();
4915 return emitOpError() <<
"expected symbol reference " << symbolRef
4916 <<
" to point to a critical declaration";
4927LogicalResult ErrorOp::verify() {
4928 if (getMessage() && getMessageExpr())
4929 return emitOpError() <<
"the message must be provided either as a constant "
4930 "`message` attribute or as a `message_expr` "
4931 "operand, but not both";
4948 return op.
emitOpError() <<
"must be nested inside of a loop";
4952 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
4953 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
4955 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
4956 "have an ordered clause";
4958 if (hasRegion && orderedAttr.getInt() != 0)
4959 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
4960 "have a parameter present";
4962 if (!hasRegion && orderedAttr.getInt() == 0)
4963 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
4964 "have a parameter present";
4965 }
else if (!isa<SimdOp>(wrapper)) {
4966 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
4967 "or worksharing simd loop";
4973 const OrderedOperands &clauses) {
4974 OrderedOp::build(builder, state, clauses.doacrossDependType,
4975 clauses.doacrossNumLoops, clauses.doacrossDependVars);
4978LogicalResult OrderedOp::verify() {
4982 auto wrapper = (*this)->getParentOfType<WsloopOp>();
4983 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
4984 return emitOpError() <<
"number of variables in depend clause does not "
4985 <<
"match number of iteration variables in the "
4992 const OrderedRegionOperands &clauses) {
4993 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
5003 const TaskwaitOperands &clauses) {
5019LogicalResult AtomicReadOp::verify() {
5020 if (verifyCommon().
failed())
5021 return mlir::failure();
5024 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5025 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5026 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5028 if (
auto mo = getMemoryOrder()) {
5029 if (*mo == ClauseMemoryOrderKind::Release) {
5030 return emitError(
"memory-order must not be release for atomic reads");
5032 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5035 return emitError(
"memory-order must not be acq_rel for atomic reads");
5045LogicalResult AtomicWriteOp::verify() {
5046 if (verifyCommon().
failed())
5047 return mlir::failure();
5050 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5051 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5052 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5054 if (
auto mo = getMemoryOrder()) {
5055 if (*mo == ClauseMemoryOrderKind::Acquire) {
5056 return emitError(
"memory-order must not be acquire for atomic writes");
5058 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5061 return emitError(
"memory-order must not be acq_rel for atomic writes");
5071LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
5077 if (
Value writeVal = op.getWriteOpVal()) {
5079 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
5085LogicalResult AtomicUpdateOp::verify() {
5086 if (verifyCommon().
failed())
5087 return mlir::failure();
5090 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5091 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5092 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5094 if (
auto mo = getMemoryOrder()) {
5095 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
5096 *mo == ClauseMemoryOrderKind::Acquire) {
5100 "memory-order must not be acq_rel or acquire for atomic updates");
5107LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
5113AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
5114 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
5116 return dyn_cast<AtomicReadOp>(getSecondOp());
5119AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
5120 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
5122 return dyn_cast<AtomicWriteOp>(getSecondOp());
5125AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
5126 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
5128 return dyn_cast<AtomicUpdateOp>(getSecondOp());
5131AtomicCompareOp AtomicCaptureOp::getAtomicCompareOp() {
5132 if (
auto op = dyn_cast<AtomicCompareOp>(getFirstOp()))
5134 return dyn_cast<AtomicCompareOp>(getSecondOp());
5137LogicalResult AtomicCaptureOp::verify() {
5141LogicalResult AtomicCaptureOp::verifyRegions() {
5142 if (verifyRegionsCommon().
failed())
5143 return mlir::failure();
5145 if (getFirstOp()->getInherentAttr(
"hint").value_or(
Attribute{}) ||
5146 getSecondOp()->getInherentAttr(
"hint").value_or(
Attribute{}))
5148 "operations inside capture region must not have hint clause");
5150 if (getFirstOp()->getInherentAttr(
"memory_order").value_or(
Attribute{}) ||
5151 getSecondOp()->getInherentAttr(
"memory_order").value_or(
Attribute{}))
5153 "operations inside capture region must not have memory_order clause");
5161LogicalResult AtomicCompareOp::verify() {
5162 if (verifyCommon().
failed())
5163 return mlir::failure();
5167 if (
auto failOrder = getFailMemoryOrder()) {
5168 if (*failOrder != ClauseMemoryOrderKind::Seq_cst &&
5169 *failOrder != ClauseMemoryOrderKind::Acquire &&
5170 *failOrder != ClauseMemoryOrderKind::Relaxed)
5172 "fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'");
5177LogicalResult AtomicCompareOp::verifyRegions() {
5178 if (verifyRegionsCommon().
failed())
5179 return mlir::failure();
5181 if (verifyOperator().
failed())
5182 return mlir::failure();
5187 if (!terminator || !isa<YieldOp>(terminator))
5188 return emitOpError(
"region must be terminated with omp.yield");
5198 const CancelOperands &clauses) {
5199 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
5212LogicalResult CancelOp::verify() {
5213 ClauseCancellationConstructType cct = getCancelDirective();
5216 if (!structuralParent)
5217 return emitOpError() <<
"Orphaned cancel construct";
5219 if ((cct == ClauseCancellationConstructType::Parallel) &&
5220 !mlir::isa<ParallelOp>(structuralParent)) {
5221 return emitOpError() <<
"cancel parallel must appear "
5222 <<
"inside a parallel region";
5224 if (cct == ClauseCancellationConstructType::Loop) {
5227 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
5230 return emitOpError()
5231 <<
"cancel loop must appear inside a worksharing-loop region";
5233 if (wsloopOp.getNowaitAttr()) {
5234 return emitError() <<
"A worksharing construct that is canceled "
5235 <<
"must not have a nowait clause";
5237 if (wsloopOp.getOrderedAttr()) {
5238 return emitError() <<
"A worksharing construct that is canceled "
5239 <<
"must not have an ordered clause";
5242 }
else if (cct == ClauseCancellationConstructType::Sections) {
5246 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
5248 return emitOpError() <<
"cancel sections must appear "
5249 <<
"inside a sections region";
5251 if (sectionsOp.getNowait()) {
5252 return emitError() <<
"A sections construct that is canceled "
5253 <<
"must not have a nowait clause";
5256 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5257 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5258 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5259 return emitOpError() <<
"cancel taskgroup must appear "
5260 <<
"inside a task region";
5270 const CancellationPointOperands &clauses) {
5271 CancellationPointOp::build(builder, state, clauses.cancelDirective);
5274LogicalResult CancellationPointOp::verify() {
5275 ClauseCancellationConstructType cct = getCancelDirective();
5278 if (!structuralParent)
5279 return emitOpError() <<
"Orphaned cancellation point";
5281 if ((cct == ClauseCancellationConstructType::Parallel) &&
5282 !mlir::isa<ParallelOp>(structuralParent)) {
5283 return emitOpError() <<
"cancellation point parallel must appear "
5284 <<
"inside a parallel region";
5288 if ((cct == ClauseCancellationConstructType::Loop) &&
5289 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
5290 return emitOpError() <<
"cancellation point loop must appear "
5291 <<
"inside a worksharing-loop region";
5293 if ((cct == ClauseCancellationConstructType::Sections) &&
5294 !mlir::isa<omp::SectionOp>(structuralParent)) {
5295 return emitOpError() <<
"cancellation point sections must appear "
5296 <<
"inside a sections region";
5298 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5299 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5300 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5301 return emitOpError() <<
"cancellation point taskgroup must appear "
5302 <<
"inside a task region";
5311LogicalResult MapBoundsOp::verify() {
5312 auto extent = getExtent();
5314 if (!extent && !upperbound)
5315 return emitError(
"expected extent or upperbound.");
5322 PrivateClauseOp::build(
5323 odsBuilder, odsState, symName,
nullptr, type,
5324 DataSharingClauseTypeAttr::get(odsBuilder.
getContext(),
5325 DataSharingClauseType::Private));
5328LogicalResult PrivateClauseOp::verifyRegions() {
5329 Type argType = getArgType();
5330 auto verifyTerminator = [&](
Operation *terminator,
5331 bool yieldsValue) -> LogicalResult {
5335 if (!llvm::isa<YieldOp>(terminator))
5337 <<
"expected exit block terminator to be an `omp.yield` op.";
5339 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
5340 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
5343 if (yieldedTypes.empty())
5347 <<
"Did not expect any values to be yielded.";
5350 if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)
5354 <<
"Invalid yielded value. Expected type: " << argType
5357 if (yieldedTypes.empty())
5360 error << yieldedTypes;
5366 StringRef regionName,
5367 bool yieldsValue) -> LogicalResult {
5368 assert(!region.
empty());
5372 <<
"`" << regionName <<
"`: " <<
"expected " << expectedNumArgs
5375 for (
Block &block : region) {
5388 for (
Region *region : getRegions())
5389 for (
Type ty : region->getArgumentTypes())
5391 return emitError() <<
"Region argument type mismatch: got " << ty
5392 <<
" expected " << argType <<
".";
5395 if (!initRegion.
empty() &&
5400 DataSharingClauseType dsType = getDataSharingType();
5402 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
5403 return emitError(
"`private` clauses do not require a `copy` region.");
5405 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
5407 "`firstprivate` clauses require at least a `copy` region.");
5409 if (dsType == DataSharingClauseType::FirstPrivate &&
5414 if (!getDeallocRegion().empty() &&
5427 const MaskedOperands &clauses) {
5428 MaskedOp::build(builder, state, clauses.filteredThreadId);
5436 const ScanOperands &clauses) {
5437 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
5440LogicalResult ScanOp::verify() {
5441 if (hasExclusiveVars() == hasInclusiveVars())
5443 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
5444 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
5445 if (parentWsLoopOp.getReductionModAttr() &&
5446 parentWsLoopOp.getReductionModAttr().getValue() ==
5447 ReductionModifier::inscan)
5450 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
5451 if (parentSimdOp.getReductionModAttr() &&
5452 parentSimdOp.getReductionModAttr().getValue() ==
5453 ReductionModifier::inscan)
5456 return emitError(
"SCAN directive needs to be enclosed within a parent "
5457 "worksharing loop construct or SIMD construct with INSCAN "
5458 "reduction modifier");
5463 std::optional<uint64_t> alignment) {
5464 if (alignment.has_value()) {
5465 if ((alignment.value() != 0) && !llvm::has_single_bit(alignment.value()))
5467 <<
"ALIGN value : " << alignment.value() <<
" must be power of 2";
5472LogicalResult AllocateDirOp::verify() {
5480LogicalResult AllocSharedMemOp::verify() {
5488LogicalResult FreeSharedMemOp::verify() {
5496LogicalResult WorkdistributeOp::verify() {
5498 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
5501 Region ®ion = getRegion();
5503 return emitOpError(
"region cannot be empty");
5506 if (entryBlock.
empty())
5507 return emitOpError(
"region must contain a structured block");
5509 bool hasTerminator =
false;
5510 for (
Block &block : region) {
5511 if (isa<TerminatorOp>(block.
back())) {
5512 if (hasTerminator) {
5513 return emitOpError(
"region must have exactly one terminator");
5515 hasTerminator =
true;
5518 if (!hasTerminator) {
5519 return emitOpError(
"region must be terminated with omp.terminator");
5523 if (isa<BarrierOp>(op)) {
5525 "explicit barriers are not allowed in workdistribute region");
5528 if (isa<ParallelOp>(op)) {
5530 "nested parallel constructs not allowed in workdistribute");
5532 if (isa<TeamsOp>(op)) {
5534 "nested teams constructs not allowed in workdistribute");
5538 if (walkResult.wasInterrupted())
5542 if (!llvm::dyn_cast<TeamsOp>(parentOp))
5543 return emitOpError(
"workdistribute must be nested under teams");
5551LogicalResult DeclareSimdOp::verify() {
5554 dyn_cast_if_present<mlir::FunctionOpInterface>((*this)->getParentOp());
5556 return emitOpError() <<
"must be nested inside a function";
5558 if (getInbranch() && getNotinbranch())
5559 return emitOpError(
"cannot have both 'inbranch' and 'notinbranch'");
5569 const DeclareSimdOperands &clauses) {
5571 DeclareSimdOp::build(odsBuilder, odsState, clauses.alignedVars,
5573 clauses.linearVars, clauses.linearStepVars,
5574 clauses.linearVarTypes, clauses.linearModifiers,
5575 clauses.notinbranch, clauses.simdlen,
5576 clauses.uniformVars);
5593 return mlir::failure();
5594 return mlir::success();
5601 for (
unsigned i = 0; i < uniformVars.size(); ++i) {
5604 p << uniformVars[i] <<
" : " << uniformTypes[i];
5619 parser, iterated, iteratedTypes, affinityVars, affinityVarTypes,
5620 [&]() -> ParseResult {
return success(); })))
5654 OpAsmParser::Argument &arg = ivArgs.emplace_back();
5655 if (parser.parseArgument(arg))
5659 if (succeeded(parser.parseOptionalColon())) {
5660 if (parser.parseType(arg.type))
5663 arg.type = parser.getBuilder().getIndexType();
5675 OpAsmParser::UnresolvedOperand lb, ub, st;
5676 if (parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
5677 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
5678 parser.parseOperand(st))
5683 steps.push_back(st);
5691 if (ivArgs.size() != lbs.size())
5693 <<
"mismatch: " << ivArgs.size() <<
" variables but " << lbs.size()
5696 for (
auto &arg : ivArgs) {
5697 lbTypes.push_back(arg.type);
5698 ubTypes.push_back(arg.type);
5699 stepTypes.push_back(arg.type);
5719 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
5722 p << lbs[i] <<
" to " << ubs[i] <<
" step " << steps[i];
5730LogicalResult IteratorOp::verify() {
5731 auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().
getType());
5733 return emitOpError() <<
"result must be omp.iterated<entry_ty>";
5735 for (
auto [lb,
ub, step] : llvm::zip_equal(
5736 getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
5738 return emitOpError() <<
"loop step must not be zero";
5742 IntegerAttr stepAttr;
5748 const APInt &lbVal = lbAttr.getValue();
5749 const APInt &ubVal = ubAttr.getValue();
5750 const APInt &stepVal = stepAttr.getValue();
5751 if (stepVal.isStrictlyPositive() && lbVal.sgt(ubVal))
5752 return emitOpError() <<
"positive loop step requires lower bound to be "
5753 "less than or equal to upper bound";
5754 if (stepVal.isNegative() && lbVal.slt(ubVal))
5755 return emitOpError() <<
"negative loop step requires lower bound to be "
5756 "greater than or equal to upper bound";
5759 Block &
b = getRegion().front();
5760 auto yield = llvm::dyn_cast<omp::YieldOp>(
b.getTerminator());
5763 return emitOpError() <<
"region must be terminated by omp.yield";
5765 if (yield.getNumOperands() != 1)
5766 return emitOpError()
5767 <<
"omp.yield in omp.iterator region must yield exactly one value";
5769 mlir::Type yieldedTy = yield.getOperand(0).getType();
5770 mlir::Type elemTy = iteratedTy.getElementType();
5772 if (yieldedTy != elemTy)
5773 return emitOpError() <<
"omp.iterated element type (" << elemTy
5774 <<
") does not match omp.yield operand type ("
5775 << yieldedTy <<
")";
5788 return emitOpError() <<
"expected symbol reference '" << getSymName()
5789 <<
"' to point to a global variable";
5791 if (isa<FunctionOpInterface>(symbol))
5792 return emitOpError() <<
"expected symbol reference '" << getSymName()
5793 <<
"' to point to a global variable, not a function";
5798#define GET_ATTRDEF_CLASSES
5799#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
5801#define GET_OP_CLASSES
5802#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
5804#define GET_TYPEDEF_CLASSES
5805#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, const Twine &name)
static 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 LogicalResult verifyDeclareTargetAttr(Operation *op, Attribute attr)
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 Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static 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.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
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.