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().getValue() ==
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;
2358 ClauseMapFlagsAttr mapType) {
2360 ClauseMapFlags mapFlags = mapType.getValue();
2365 mapTypeStrs.push_back(
"always");
2367 mapTypeStrs.push_back(
"implicit");
2369 mapTypeStrs.push_back(
"ompx_hold");
2371 mapTypeStrs.push_back(
"close");
2373 mapTypeStrs.push_back(
"present");
2382 mapTypeStrs.push_back(
"tofrom");
2384 mapTypeStrs.push_back(
"from");
2386 mapTypeStrs.push_back(
"to");
2389 mapTypeStrs.push_back(
"delete");
2391 mapTypeStrs.push_back(
"return_param");
2393 mapTypeStrs.push_back(
"storage");
2395 mapTypeStrs.push_back(
"private");
2397 mapTypeStrs.push_back(
"literal");
2399 mapTypeStrs.push_back(
"attach");
2401 mapTypeStrs.push_back(
"attach_always");
2403 mapTypeStrs.push_back(
"attach_never");
2405 mapTypeStrs.push_back(
"attach_auto");
2407 mapTypeStrs.push_back(
"ref_ptr");
2409 mapTypeStrs.push_back(
"ref_ptee");
2411 mapTypeStrs.push_back(
"is_device_ptr");
2412 if (mapFlags == ClauseMapFlags::none)
2413 mapTypeStrs.push_back(
"none");
2415 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
2416 p << mapTypeStrs[i];
2417 if (i + 1 < mapTypeStrs.size()) {
2423static ParseResult parseMembersIndex(
OpAsmParser &parser,
2427 auto parseIndices = [&]() -> ParseResult {
2432 APInt(64, value,
false)));
2446 memberIdxs.push_back(ArrayAttr::get(parser.
getContext(), values));
2450 if (!memberIdxs.empty())
2451 membersIdx = ArrayAttr::get(parser.
getContext(), memberIdxs);
2461 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
2463 auto memberIdx = cast<ArrayAttr>(v);
2464 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
2465 p << cast<IntegerAttr>(v2).getInt();
2472 VariableCaptureKindAttr mapCaptureType) {
2473 std::string typeCapStr;
2474 llvm::raw_string_ostream typeCap(typeCapStr);
2475 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
2477 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
2478 typeCap <<
"ByCopy";
2479 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
2480 typeCap <<
"VLAType";
2481 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
2487 VariableCaptureKindAttr &mapCaptureType) {
2488 StringRef mapCaptureKey;
2492 if (mapCaptureKey ==
"This")
2493 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2494 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
2495 if (mapCaptureKey ==
"ByRef")
2496 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2497 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
2498 if (mapCaptureKey ==
"ByCopy")
2499 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2500 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
2501 if (mapCaptureKey ==
"VLAType")
2502 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2503 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
2509 Operation *op, mlir::omp::MapInfoOp mapInfoOp,
2513 mlir::omp::ClauseMapFlags mapTypeBits = mapInfoOp.getMapType();
2516 bool from =
mapTypeToBool(mapTypeBits, ClauseMapFlags::from);
2519 bool always =
mapTypeToBool(mapTypeBits, ClauseMapFlags::always);
2520 bool close =
mapTypeToBool(mapTypeBits, ClauseMapFlags::close);
2521 bool implicit =
mapTypeToBool(mapTypeBits, ClauseMapFlags::implicit);
2522 bool attach =
mapTypeToBool(mapTypeBits, ClauseMapFlags::attach);
2524 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
2526 "to, from, tofrom and alloc map types are permitted");
2528 if (isa<TargetEnterDataOp>(op) && (from || del))
2529 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
2531 if (isa<TargetExitDataOp>(op) && to)
2533 "from, release and delete map types are permitted");
2535 if (isa<TargetUpdateOp>(op)) {
2538 "at least one of to or from map types must be "
2539 "specified, other map types are not permitted");
2542 if (!to && !from && !attach) {
2544 "at least one of to or from or attach map types must be "
2545 "specified, other map types are not permitted");
2548 auto updateVar = mapInfoOp.getVarPtr();
2550 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
2551 (from && updateToVars.contains(updateVar))) {
2554 "either to or from map types can be specified, not both");
2557 if (always || close || implicit) {
2560 "present, mapper and iterator map type modifiers are permitted");
2566 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
2570 if ((mapInfoOp.getVarPtrPtr() && !mapInfoOp.getVarPtrPtrType()) ||
2571 (!mapInfoOp.getVarPtrPtr() && mapInfoOp.getVarPtrPtrType())) {
2573 "if varPtrPtr or varPtrPtrType is specified, then both "
2585 for (
auto mapOp : mapVars) {
2586 if (!mapOp.getDefiningOp())
2589 if (
auto mapInfoOp = mapOp.getDefiningOp<mlir::omp::MapInfoOp>()) {
2593 }
else if (!isa<DeclareMapperInfoOp>(op)) {
2595 "map argument is not a map entry operation");
2600 for (
auto iterVal : mapIterated) {
2601 auto iterOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
2603 return op->
emitOpError() <<
"'map_iterated' arguments must be defined by "
2604 "'omp.iterator' ops";
2608 cast<mlir::omp::YieldOp>(iterOp.getRegion().front().getTerminator());
2609 auto yieldedMapInfo =
2610 yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
2611 if (!yieldedMapInfo)
2612 return op->
emitOpError() <<
"'map_iterated' iterator body must yield "
2613 "a value defined by 'omp.map.info'";
2623template <
typename OpType>
2627 std::optional<DenseI64ArrayAttr> privateMapIndices =
2628 targetOp.getPrivateMapsAttr();
2631 if (!privateMapIndices.has_value() || !privateMapIndices.value())
2636 if (privateMapIndices.value().size() !=
2637 static_cast<int64_t>(privateVars.size()))
2638 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
2639 "`private_maps` attribute mismatch");
2649 StringRef clauseName,
2651 for (
Value var : vars)
2652 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
2654 <<
"'" << clauseName
2655 <<
"' arguments must be defined by 'omp.map.info' ops";
2659LogicalResult MapInfoOp::verify() {
2660 if (getMapperId() &&
2662 *
this, getMapperIdAttr())) {
2677 const TargetDataOperands &clauses) {
2678 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
2679 clauses.mapVars, clauses.mapIterated,
2680 clauses.useDeviceAddrVars, clauses.useDevicePtrVars);
2683LogicalResult TargetDataOp::verify() {
2684 if (getMapVars().empty() && getMapIterated().empty() &&
2685 getUseDevicePtrVars().empty() && getUseDeviceAddrVars().empty()) {
2686 return ::emitError(this->getLoc(),
2687 "At least one of map, use_device_ptr_vars, or "
2688 "use_device_addr_vars operand must be present");
2692 getUseDevicePtrVars())))
2696 getUseDeviceAddrVars())))
2706void TargetEnterDataOp::build(
2710 TargetEnterDataOp::build(
2712 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2713 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2714 clauses.mapIterated, clauses.nowait);
2717LogicalResult TargetEnterDataOp::verify() {
2718 LogicalResult verifyDependVars =
2720 getDependIteratedKinds(), getDependIterated());
2721 return failed(verifyDependVars)
2733 TargetExitDataOp::build(
2735 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2736 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2737 clauses.mapIterated, clauses.nowait);
2740LogicalResult TargetExitDataOp::verify() {
2741 LogicalResult verifyDependVars =
2743 getDependIteratedKinds(), getDependIterated());
2744 return failed(verifyDependVars)
2756 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
2759 clauses.dependIterated, clauses.device, clauses.ifExpr,
2760 clauses.mapVars, clauses.mapIterated, clauses.nowait);
2763LogicalResult TargetUpdateOp::verify() {
2764 LogicalResult verifyDependVars =
2766 getDependIteratedKinds(), getDependIterated());
2767 return failed(verifyDependVars)
2780 builder, state, clauses.allocateVars, clauses.allocatorVars,
2783 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2784 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
2785 clauses.device, clauses.dynGroupprivateAccessGroup,
2786 clauses.dynGroupprivateFallback, clauses.dynGroupprivateSize,
2787 clauses.hasDeviceAddrVars, clauses.hostEvalVars, clauses.ifExpr,
2788 clauses.inReductionVars,
2790 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.isDevicePtrVars,
2791 clauses.mapVars, clauses.mapIterated, clauses.nowait, clauses.privateVars,
2792 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
2793 clauses.threadLimitVars,
nullptr, clauses.
kernelType);
2796bool TargetOp::hasHostEvalTripCount() {
2797 TargetExecMode mode = getKernelType();
2798 if (mode == TargetExecMode::spmd || mode == TargetExecMode::spmd_no_loop)
2801 if (mode == TargetExecMode::bare)
2807 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2808 if (
auto loopNestOp = dyn_cast_if_present<LoopNestOp>(capturedOp)) {
2810 loopNestOp.gatherWrappers(loopWrappers);
2812 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2813 if (isa<SimdOp>(innermostWrapper))
2814 innermostWrapper = std::next(innermostWrapper);
2816 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2817 if (numWrappers != 1)
2820 if (!isa<DistributeOp>(innermostWrapper))
2824 if (isa_and_present<TeamsOp>(parentOp) &&
2840 if (mapVarPtr == inReductionVar)
2846LogicalResult TargetOp::verify() {
2848 getOperation(), getAllocateVars(), getAllocatorVars(),
2849 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
2850 getPrivateVars(), getPrivateSymsAttr())))
2853 if (getKernelType() == TargetExecMode::bare && !isCombined())
2854 return emitOpError() <<
"bare kernel requires 'omp.combined'";
2857 getDependIteratedKinds(),
2858 getDependIterated())))
2862 getHasDeviceAddrVars())))
2869 *
this, getDynGroupprivateAccessGroupAttr(),
2870 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
2877 getInReductionVars(),
2878 getInReductionByref())))
2886 for (
Value inReductionVar : getInReductionVars()) {
2887 bool captured =
false;
2888 for (
Value mapVar : getMapVars()) {
2889 auto mapInfo = mapVar.getDefiningOp<MapInfoOp>();
2896 return emitOpError() <<
"in_reduction variable must be captured by a "
2897 "matching map_entries entry";
2903LogicalResult TargetOp::verifyRegions() {
2904 auto teamsOps = getOps<TeamsOp>();
2905 auto numNestedTeams = std::distance(teamsOps.begin(), teamsOps.end());
2906 if (numNestedTeams > 1)
2907 return emitError(
"target containing multiple 'omp.teams' nested ops");
2909 if (numNestedTeams == 0) {
2910 switch (getKernelType()) {
2911 case TargetExecMode::bare:
2913 <<
"bare kernel must contain a nested 'omp.teams' operation";
2914 case TargetExecMode::spmd_no_loop:
2915 return emitOpError() <<
"spmd_no_loop kernel must contain a nested "
2916 "'omp.teams' operation";
2923 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2924 if ((getKernelType() == TargetExecMode::spmd ||
2925 getKernelType() == TargetExecMode::spmd_no_loop) &&
2926 !isa_and_present<LoopNestOp>(capturedOp))
2928 <<
"SPMD kernel must capture an 'omp.loop_nest' operation";
2930 bool isTargetDevice =
false;
2931 if (
auto offloadMod = (*this)->getParentOfType<OffloadModuleInterface>())
2932 if (offloadMod.getIsTargetDevice())
2933 isTargetDevice =
true;
2937 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs();
2939 bool hostEvalTripCount = hasHostEvalTripCount();
2940 for (
Value hostEvalArg : hostEvalBlockArgs) {
2942 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
2944 if (hostEvalArg == teamsOp.getNumTeamsLower() ||
2945 llvm::is_contained(teamsOp.getNumTeamsUpperVars(), hostEvalArg) ||
2946 llvm::is_contained(teamsOp.getThreadLimitVars(), hostEvalArg))
2949 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
2950 "and 'thread_limit' in 'omp.teams'";
2952 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
2953 if (llvm::is_contained(parallelOp.getNumThreadsVars(), hostEvalArg))
2957 <<
"host_eval argument only legal as 'num_threads' in "
2960 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
2961 if (hostEvalTripCount &&
2962 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
2963 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
2964 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
2967 return emitOpError() <<
"host_eval argument only legal as loop bounds "
2968 "and steps in 'omp.loop_nest' when trip count "
2969 "must be evaluated in the host";
2972 return emitOpError() <<
"host_eval argument illegal use in '"
2973 << user->getName() <<
"' operation";
2977 if (hostEvalTripCount && !isTargetDevice) {
2978 auto loopOp = cast<LoopNestOp>(capturedOp);
2979 for (
auto arg : llvm::concat<Value>(loopOp.getLoopLowerBounds(),
2980 loopOp.getLoopUpperBounds(),
2981 loopOp.getLoopSteps())) {
2982 if (!llvm::is_contained(hostEvalBlockArgs, arg))
2983 return emitOpError() <<
"nested 'omp.loop_nest' bounds expected to "
2984 "be host-evaluated";
2997 ParallelOp::build(builder, state,
ValueRange(),
3011 const ParallelOperands &clauses) {
3013 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3016 clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
3018 clauses.privateNeedsBarrier, clauses.procBindKind,
3019 clauses.reductionMod, clauses.reductionVars,
3024template <
typename OpType>
3026 auto privateVars = op.getPrivateVars();
3027 auto privateSyms = op.getPrivateSymsAttr();
3029 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
3032 auto numPrivateVars = privateVars.size();
3033 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
3035 if (numPrivateVars != numPrivateSyms)
3036 return op.emitError() <<
"inconsistent number of private variables and "
3037 "privatizer op symbols, private vars: "
3039 <<
" vs. privatizer op symbols: " << numPrivateSyms;
3041 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
3042 Type varType = std::get<0>(privateVarInfo).getType();
3043 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
3044 PrivateClauseOp privatizerOp =
3047 if (privatizerOp ==
nullptr)
3048 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
3049 << privateSym <<
"'";
3051 Type privatizerType = privatizerOp.getArgType();
3053 if (privatizerType && (varType != privatizerType))
3054 return op.emitError()
3055 <<
"type mismatch between a "
3056 << (privatizerOp.getDataSharingType() ==
3057 DataSharingClauseType::Private
3060 <<
" variable and its privatizer op, var type: " << varType
3061 <<
" vs. privatizer op type: " << privatizerType;
3067LogicalResult ParallelOp::verify() {
3071 getOperation(), getAllocateVars(), getAllocatorVars(),
3072 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3073 getPrivateVars(), getPrivateSymsAttr(),
3078 getReductionByref());
3081LogicalResult ParallelOp::verifyRegions() {
3082 auto distChildOps = getOps<DistributeOp>();
3083 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
3084 if (numDistChildOps > 1)
3086 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
3088 if (numDistChildOps == 1) {
3091 <<
"'omp.composite' attribute missing from composite operation";
3093 auto *ompDialect =
getContext()->getLoadedDialect<OpenMPDialect>();
3094 Operation &distributeOp = **distChildOps.begin();
3096 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
3100 return emitError() <<
"unexpected OpenMP operation inside of composite "
3102 << childOp.getName();
3104 }
else if (isComposite()) {
3106 <<
"'omp.composite' attribute present in non-composite operation";
3123 const TeamsOperands &clauses) {
3127 builder, state, clauses.allocateVars, clauses.allocatorVars,
3130 clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
3131 clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
3132 clauses.numTeamsUpperVars, {},
nullptr,
3133 nullptr, clauses.reductionMod,
3134 clauses.reductionVars,
3136 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
3143 if (numTeamsLower) {
3144 if (numTeamsUpperVars.size() != 1)
3146 "expected exactly one num_teams upper bound when lower bound is "
3150 "expected num_teams upper bound and lower bound to be "
3157LogicalResult TeamsOp::verify() {
3164 auto parentTarget = llvm::dyn_cast_if_present<TargetOp>(op->
getParentOp());
3166 return emitError(
"expected to be nested inside of omp.target or not nested "
3167 "in any OpenMP dialect operations");
3171 this->getNumTeamsUpperVars())))
3175 parentTarget.getKernelType() == TargetExecMode::spmd_no_loop &&
3176 (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
3177 return emitOpError() <<
"'num_teams' not allowed in SPMD-no-loop kernels";
3180 getOperation(), getAllocateVars(), getAllocatorVars(),
3181 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3182 getPrivateVars(), getPrivateSymsAttr())))
3186 op, getDynGroupprivateAccessGroupAttr(),
3187 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3194 getReductionByref());
3202 return getParentOp().getPrivateVars();
3206 return getParentOp().getReductionVars();
3214 const SectionsOperands &clauses) {
3217 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3222 clauses.reductionMod, clauses.reductionVars,
3227LogicalResult SectionsOp::verify() {
3229 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3232 getOperation(), getAllocateVars(), getAllocatorVars(),
3233 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3234 getPrivateVars(), getPrivateSymsAttr())))
3238 getReductionByref());
3241LogicalResult SectionsOp::verifyRegions() {
3242 for (
auto &inst : *getRegion().begin()) {
3243 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
3245 <<
"expected omp.section op or terminator op inside region";
3257 const ScopeOperands &clauses) {
3259 ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3262 clauses.nowait, clauses.privateVars,
3264 clauses.privateNeedsBarrier, clauses.reductionMod,
3265 clauses.reductionVars,
3270LogicalResult ScopeOp::verify() {
3272 getOperation(), getAllocateVars(), getAllocatorVars(),
3273 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3274 getPrivateVars(), getPrivateSymsAttr())))
3281 getReductionByref());
3289 const SingleOperands &clauses) {
3292 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3295 clauses.copyprivateVars,
3296 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
3301LogicalResult SingleOp::verify() {
3303 getOperation(), getAllocateVars(), getAllocatorVars(),
3304 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3305 getPrivateVars(), getPrivateSymsAttr())))
3309 getCopyprivateSyms());
3317 const WorkshareOperands &clauses) {
3318 WorkshareOp::build(builder, state, clauses.nowait);
3321LogicalResult WorkshareOp::verify() {
3323 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3332LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
3333 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3335 return emitOpError() <<
"expected to be a standalone loop wrapper";
3344LogicalResult LoopWrapperInterface::verifyImpl() {
3348 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
3349 "and `SingleBlock` traits";
3352 return emitOpError() <<
"loop wrapper does not contain exactly one region";
3355 if (range_size(region.
getOps()) != 1)
3357 <<
"loop wrapper does not contain exactly one nested op";
3360 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
3361 return emitOpError() <<
"nested in loop wrapper is not another loop "
3362 "wrapper or `omp.loop_nest`";
3371Operation *ComposableOpInterface::findCapturedOp() {
3375 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(op))
3376 return wrapperOp.getWrappedLoop();
3381 if (!isCombined() && !isComposite())
3386 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(&nestedOp))
3387 return wrapperOp.getWrappedLoop();
3389 if (
auto composableOp = dyn_cast<ComposableOpInterface>(&nestedOp))
3390 return composableOp.findCapturedOp();
3399LogicalResult ComposableOpInterface::verifyImpl() {
3403 return emitOpError() <<
"composable ops must have a single region";
3405 if (isComposite() && !isa<LoopWrapperInterface, ParallelOp>(op))
3406 return emitOpError() <<
"non-loop wrapper cannot be composite";
3412 auto count = llvm::count_if(
3414 if (isa<ComposableOpInterface, LoopWrapperInterface>(op)) {
3436 <<
"multiple eligible child ops found in combined op";
3447 if (successor->isReachable(parentBlock))
3448 return emitOpError() <<
"nested combined child op is part of a loop";
3452 !domInfo.
dominates(parentBlock, &block))
3454 <<
"nested combined child op doesn't unconditionally execute";
3464 const LoopOperands &clauses) {
3467 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
3469 clauses.privateNeedsBarrier, clauses.order, clauses.orderMod,
3470 clauses.reductionMod, clauses.reductionVars,
3475LogicalResult LoopOp::verify() {
3480 getReductionByref());
3483LogicalResult LoopOp::verifyRegions() {
3484 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3486 return emitOpError() <<
"expected to be a standalone loop wrapper";
3497 build(builder, state, {}, {},
3502 false,
nullptr,
nullptr,
3503 nullptr, {},
nullptr,
3514 const WsloopOperands &clauses) {
3517 builder, state, clauses.allocateVars, clauses.allocatorVars,
3520 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
3521 clauses.linearModifiers, clauses.nowait, clauses.order, clauses.orderMod,
3522 clauses.ordered, clauses.privateVars,
3523 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
3524 clauses.reductionMod, clauses.reductionVars,
3526 makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
3527 clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
3530LogicalResult WsloopOp::verify() {
3532 getOperation(), getAllocateVars(), getAllocatorVars(),
3533 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3534 getPrivateVars(), getPrivateSymsAttr())))
3540 if (getLinearVars().size() &&
3541 getLinearVarTypes().value().size() != getLinearVars().size())
3542 return emitError() <<
"Ill-formed type attributes for linear variables";
3548 getReductionByref());
3551LogicalResult WsloopOp::verifyRegions() {
3552 bool isCompositeChildLeaf =
3553 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3555 if (LoopWrapperInterface nested = getNestedWrapper()) {
3558 <<
"'omp.composite' attribute missing from composite wrapper";
3562 if (!isa<SimdOp>(nested))
3563 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3565 }
else if (isComposite() && !isCompositeChildLeaf) {
3567 <<
"'omp.composite' attribute present in non-composite wrapper";
3568 }
else if (!isComposite() && isCompositeChildLeaf) {
3570 <<
"'omp.composite' attribute missing from composite wrapper";
3581 const SimdOperands &clauses) {
3583 SimdOp::build(builder, state, clauses.alignedVars,
3585 clauses.linearVars, clauses.linearStepVars,
3586 clauses.linearVarTypes, clauses.linearModifiers,
3587 clauses.nontemporalVars, clauses.order, clauses.orderMod,
3588 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3589 clauses.privateNeedsBarrier, clauses.reductionMod,
3590 clauses.reductionVars,
3596LogicalResult SimdOp::verify() {
3597 if (getSimdlen().has_value() && getSafelen().has_value() &&
3598 getSimdlen().value() > getSafelen().value())
3600 <<
"simdlen clause and safelen clause are both present, but the "
3601 "simdlen value is not less than or equal to safelen value";
3613 bool isCompositeChildLeaf =
3614 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3616 if (!isComposite() && isCompositeChildLeaf)
3618 <<
"'omp.composite' attribute missing from composite wrapper";
3620 if (isComposite() && !isCompositeChildLeaf)
3622 <<
"'omp.composite' attribute present in non-composite wrapper";
3626 std::optional<ArrayAttr> privateSyms = getPrivateSyms();
3628 for (
const Attribute &sym : *privateSyms) {
3629 auto symRef = cast<SymbolRefAttr>(sym);
3630 omp::PrivateClauseOp privatizer =
3632 getOperation(), symRef);
3634 return emitError() <<
"Cannot find privatizer '" << symRef <<
"'";
3635 if (privatizer.getDataSharingType() ==
3636 DataSharingClauseType::FirstPrivate)
3637 return emitError() <<
"FIRSTPRIVATE cannot be used with SIMD";
3644 if (getLinearVars().size() &&
3645 getLinearVarTypes().value().size() != getLinearVars().size())
3646 return emitError() <<
"Ill-formed type attributes for linear variables";
3651 for (
Value var : getLinearVars()) {
3652 if (privateVars.contains(var) || reductionVars.contains(var))
3654 <<
"linear variables cannot appear in other data-sharing clauses";
3660LogicalResult SimdOp::verifyRegions() {
3661 if (getNestedWrapper())
3662 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
3672 const DistributeOperands &clauses) {
3673 DistributeOp::build(
3674 builder, state, clauses.allocateVars, clauses.allocatorVars,
3677 clauses.allocatePrivateIndices),
3678 clauses.distScheduleStatic, clauses.distScheduleChunkSize, clauses.order,
3679 clauses.orderMod, clauses.privateVars,
3681 clauses.privateNeedsBarrier);
3684LogicalResult DistributeOp::verify() {
3685 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
3687 "dist_schedule_static being present";
3690 getOperation(), getAllocateVars(), getAllocatorVars(),
3691 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3692 getPrivateVars(), getPrivateSymsAttr())))
3701LogicalResult DistributeOp::verifyRegions() {
3702 if (LoopWrapperInterface nested = getNestedWrapper()) {
3705 <<
"'omp.composite' attribute missing from composite wrapper";
3708 if (isa<WsloopOp>(nested)) {
3710 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
3711 !cast<ComposableOpInterface>(parentOp).isComposite()) {
3712 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
3713 "when a composite 'omp.parallel' is the direct "
3716 }
else if (!isa<SimdOp>(nested))
3717 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
3719 }
else if (isComposite()) {
3721 <<
"'omp.composite' attribute present in non-composite wrapper";
3732 const DeclareMapperInfoOperands &clauses) {
3733 DeclareMapperInfoOp::build(builder, state, clauses.mapVars,
3734 clauses.mapIterated);
3737LogicalResult DeclareMapperInfoOp::verify() {
3741LogicalResult DeclareMapperOp::verifyRegions() {
3742 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
3743 getRegion().getBlocks().front().getTerminator()))
3744 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
3753LogicalResult DeclareReductionOp::verifyRegions() {
3754 if (!getAllocRegion().empty()) {
3755 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
3756 if (yieldOp.getResults().size() != 1 ||
3757 yieldOp.getResults().getTypes()[0] !=
getType())
3758 return emitOpError() <<
"expects alloc region to yield a value "
3759 "of the reduction type";
3763 if (getInitializerRegion().empty())
3764 return emitOpError() <<
"expects non-empty initializer region";
3765 Block &initializerEntryBlock = getInitializerRegion().
front();
3768 if (!getAllocRegion().empty())
3769 return emitOpError() <<
"expects two arguments to the initializer region "
3770 "when an allocation region is used";
3772 if (getAllocRegion().empty())
3773 return emitOpError() <<
"expects one argument to the initializer region "
3774 "when no allocation region is used";
3777 <<
"expects one or two arguments to the initializer region";
3781 if (arg.getType() !=
getType())
3782 return emitOpError() <<
"expects initializer region argument to match "
3783 "the reduction type";
3785 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
3786 if (yieldOp.getResults().size() != 1 ||
3787 yieldOp.getResults().getTypes()[0] !=
getType())
3788 return emitOpError() <<
"expects initializer region to yield a value "
3789 "of the reduction type";
3792 if (getReductionRegion().empty())
3793 return emitOpError() <<
"expects non-empty reduction region";
3794 Block &reductionEntryBlock = getReductionRegion().
front();
3799 return emitOpError() <<
"expects reduction region with two arguments of "
3800 "the reduction type";
3801 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
3802 if (yieldOp.getResults().size() != 1 ||
3803 yieldOp.getResults().getTypes()[0] !=
getType())
3804 return emitOpError() <<
"expects reduction region to yield a value "
3805 "of the reduction type";
3808 if (!getAtomicReductionRegion().empty()) {
3809 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
3813 return emitOpError() <<
"expects atomic reduction region with two "
3814 "arguments of the same type";
3815 auto ptrType = llvm::dyn_cast<PointerLikeType>(
3818 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
3819 return emitOpError() <<
"expects atomic reduction region arguments to "
3820 "be accumulators containing the reduction type";
3823 if (getCleanupRegion().empty())
3825 Block &cleanupEntryBlock = getCleanupRegion().
front();
3828 return emitOpError() <<
"expects cleanup region with one argument "
3829 "of the reduction type";
3839 const TaskOperands &clauses) {
3842 builder, state, clauses.iterated, clauses.affinityVars,
3843 clauses.allocateVars, clauses.allocatorVars,
3846 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
3847 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
3848 clauses.final, clauses.ifExpr, clauses.inReductionVars,
3850 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3851 clauses.priority, clauses.privateVars,
3853 clauses.privateNeedsBarrier, clauses.untied, clauses.eventHandle);
3856LogicalResult TaskOp::verify() {
3858 getOperation(), getAllocateVars(), getAllocatorVars(),
3859 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3860 getPrivateVars(), getPrivateSymsAttr())))
3863 LogicalResult verifyDependVars =
3865 getDependIteratedKinds(), getDependIterated());
3866 if (
failed(verifyDependVars))
3867 return verifyDependVars;
3873 getInReductionVars(), getInReductionByref());
3881 const TaskgroupOperands &clauses) {
3883 TaskgroupOp::build(builder, state, clauses.allocateVars,
3884 clauses.allocatorVars,
3887 clauses.taskReductionVars,
3892LogicalResult TaskgroupOp::verify() {
3894 getOperation(), getAllocateVars(), getAllocatorVars(),
3895 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr())))
3899 getTaskReductionVars(),
3900 getTaskReductionByref());
3908 const TaskloopContextOperands &clauses) {
3910 TaskloopContextOp::build(
3911 builder, state, clauses.allocateVars, clauses.allocatorVars,
3914 clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
3915 clauses.inReductionVars,
3917 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
3918 clauses.nogroup, clauses.numTasksMod, clauses.numTasks, clauses.priority,
3919 clauses.privateVars,
3921 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3924 state.
addAttribute(
"omp.combined", UnitAttr::get(ctx));
3927TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
3928 return cast<TaskloopWrapperOp>(
3930 return isa<TaskloopWrapperOp>(op);
3934LogicalResult TaskloopContextOp::verify() {
3938 getOperation(), getAllocateVars(), getAllocatorVars(),
3939 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3940 getPrivateVars(), getPrivateSymsAttr())))
3944 getReductionVars(), getReductionByref())) ||
3946 getInReductionVars(),
3947 getInReductionByref())))
3950 if (!getReductionVars().empty() && getNogroup())
3951 return emitError(
"if a reduction clause is present on the taskloop "
3952 "directive, the nogroup clause must not be specified");
3953 for (
auto var : getReductionVars()) {
3954 if (llvm::is_contained(getInReductionVars(), var))
3955 return emitError(
"the same list item cannot appear in both a reduction "
3956 "and an in_reduction clause");
3959 if (getGrainsize() && getNumTasks()) {
3961 "the grainsize clause and num_tasks clause are mutually exclusive and "
3962 "may not appear on the same taskloop directive");
3970 return emitOpError(
"must always contain the 'omp.combined' attribute");
3975LogicalResult TaskloopContextOp::verifyRegions() {
3976 Region ®ion = getRegion();
3978 return isa<TaskloopWrapperOp>(op);
3980 if (loopWrapperIt == region.
front().
end())
3982 <<
"expected a TaskloopWrapperOp directly nested in the region";
3984 auto loopWrapperOp = cast<TaskloopWrapperOp>(*loopWrapperIt);
3985 auto loopNestOp = dyn_cast<LoopNestOp>(loopWrapperOp.getWrappedLoop());
3991 std::function<
bool(
Value)> isValidBoundValue = [&](
Value value) ->
bool {
3992 Region *valueRegion = value.getParentRegion();
3998 Operation *defOp = value.getDefiningOp();
4002 return llvm::all_of(defOp->
getOperands(), isValidBoundValue);
4004 auto hasUnsupportedTaskloopLocalBound = [&](
OperandRange range) ->
bool {
4005 return llvm::any_of(range,
4006 [&](
Value value) {
return !isValidBoundValue(value); });
4009 if (hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopLowerBounds()) ||
4010 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopUpperBounds()) ||
4011 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopSteps())) {
4013 <<
"expects loop bounds and steps to be defined outside of the "
4014 "taskloop.context region or by pure, regionless operations "
4015 "that do not depend on block arguments";
4026 const TaskloopWrapperOperands &clauses) {
4027 TaskloopWrapperOp::build(builder, state);
4030TaskloopContextOp TaskloopWrapperOp::getTaskloopContext() {
4031 return dyn_cast<TaskloopContextOp>(getOperation()->getParentOp());
4034LogicalResult TaskloopWrapperOp::verify() {
4035 TaskloopContextOp context = getTaskloopContext();
4037 return emitOpError() <<
"expected to be nested in a taskloop context op";
4041LogicalResult TaskloopWrapperOp::verifyRegions() {
4042 if (LoopWrapperInterface nested = getNestedWrapper()) {
4045 <<
"'omp.composite' attribute missing from composite wrapper";
4049 if (!isa<SimdOp>(nested))
4050 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
4051 }
else if (isComposite()) {
4053 <<
"'omp.composite' attribute present in non-composite wrapper";
4077 for (
auto &iv : ivs)
4078 iv.type = loopVarType;
4083 result.addAttribute(
"loop_inclusive", UnitAttr::get(ctx));
4099 "collapse_num_loops",
4104 auto parseTiles = [&]() -> ParseResult {
4108 tiles.push_back(
tile);
4117 if (tiles.size() > 0)
4136 Region ®ion = getRegion();
4138 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
4139 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
4140 if (getLoopInclusive())
4142 p <<
"step (" << getLoopSteps() <<
") ";
4143 if (
int64_t numCollapse = getCollapseNumLoops())
4144 if (numCollapse > 1)
4145 p <<
"collapse(" << numCollapse <<
") ";
4148 p <<
"tiles(" << tiles.value() <<
") ";
4154 const LoopNestOperands &clauses) {
4156 LoopNestOp::build(builder, state, clauses.collapseNumLoops,
4157 clauses.loopLowerBounds, clauses.loopUpperBounds,
4158 clauses.loopSteps, clauses.loopInclusive,
4162LogicalResult LoopNestOp::verify() {
4163 if (getLoopLowerBounds().empty())
4164 return emitOpError() <<
"must represent at least one loop";
4166 if (getLoopLowerBounds().size() != getIVs().size())
4167 return emitOpError() <<
"number of range arguments and IVs do not match";
4169 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
4170 if (lb.getType() != iv.getType())
4172 <<
"range argument type does not match corresponding IV type";
4175 uint64_t numIVs = getIVs().size();
4177 if (
const auto &numCollapse = getCollapseNumLoops())
4178 if (numCollapse > numIVs)
4180 <<
"collapse value is larger than the number of loops";
4183 if (tiles.value().size() > numIVs)
4184 return emitOpError() <<
"too few canonical loops for tile dimensions";
4186 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
4187 return emitOpError() <<
"expects parent op to be a loop wrapper";
4192void LoopNestOp::gatherWrappers(
4195 while (
auto wrapper =
4196 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
4197 wrappers.push_back(wrapper);
4206std::tuple<NewCliOp, OpOperand *, OpOperand *>
4212 return {{},
nullptr,
nullptr};
4215 "Unexpected type of cli");
4221 auto op = cast<LoopTransformationInterface>(use.getOwner());
4223 unsigned opnum = use.getOperandNumber();
4224 if (op.isGeneratee(opnum)) {
4225 assert(!gen &&
"Each CLI may have at most one def");
4227 }
else if (op.isApplyee(opnum)) {
4228 assert(!cons &&
"Each CLI may have at most one consumer");
4231 llvm_unreachable(
"Unexpected operand for a CLI");
4235 return {create, gen, cons};
4241 case llvm::omp::ProcBindKind::OMP_PROC_BIND_close:
4242 return ClauseProcBindKind::Close;
4243 case llvm::omp::ProcBindKind::OMP_PROC_BIND_master:
4244 return ClauseProcBindKind::Master;
4245 case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary:
4246 return ClauseProcBindKind::Primary;
4247 case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread:
4248 return ClauseProcBindKind::Spread;
4249 case llvm::omp::ProcBindKind::OMP_PROC_BIND_default:
4250 case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown:
4253 llvm_unreachable(
"unexpected proc-bind kind");
4276 std::string cliName{
"cli"};
4280 .Case([&](CanonicalLoopOp op) {
4283 .Case([&](UnrollHeuristicOp op) -> std::string {
4284 llvm_unreachable(
"heuristic unrolling does not generate a loop");
4286 .Case([&](FuseOp op) -> std::string {
4287 unsigned opnum =
generator->getOperandNumber();
4290 if (op.getFirst().has_value() && opnum != op.getFirst().value())
4291 return "canonloop_fuse";
4295 .Case([&](TileOp op) -> std::string {
4296 auto [generateesFirst, generateesCount] =
4297 op.getGenerateesODSOperandIndexAndLength();
4298 unsigned firstGrid = generateesFirst;
4299 unsigned firstIntratile = generateesFirst + generateesCount / 2;
4300 unsigned end = generateesFirst + generateesCount;
4301 unsigned opnum =
generator->getOperandNumber();
4303 if (firstGrid <= opnum && opnum < firstIntratile) {
4304 unsigned gridnum = opnum - firstGrid + 1;
4305 return (
"grid" + Twine(gridnum)).str();
4307 if (firstIntratile <= opnum && opnum < end) {
4308 unsigned intratilenum = opnum - firstIntratile + 1;
4309 return (
"intratile" + Twine(intratilenum)).str();
4311 llvm_unreachable(
"Unexpected generatee argument");
4313 .DefaultUnreachable(
"TODO: Custom name for this operation");
4316 setNameFn(
result, cliName);
4319LogicalResult NewCliOp::verify() {
4320 Value cli = getResult();
4323 "Unexpected type of cli");
4329 auto op = cast<mlir::omp::LoopTransformationInterface>(use.getOwner());
4331 unsigned opnum = use.getOperandNumber();
4332 if (op.isGeneratee(opnum)) {
4335 emitOpError(
"CLI must have at most one generator");
4337 .
append(
"first generator here:");
4339 .
append(
"second generator here:");
4344 }
else if (op.isApplyee(opnum)) {
4347 emitOpError(
"CLI must have at most one consumer");
4349 .
append(
"first consumer here:")
4353 .
append(
"second consumer here:")
4360 llvm_unreachable(
"Unexpected operand for a CLI");
4368 .
append(
"see consumer here: ")
4391 setNameFn(&getRegion().front(),
"body_entry");
4394void CanonicalLoopOp::getAsmBlockArgumentNames(
Region ®ion,
4402 p <<
'(' << getCli() <<
')';
4403 p <<
' ' << getInductionVar() <<
" : " << getInductionVar().getType()
4404 <<
" in range(" << getTripCount() <<
") ";
4414 CanonicalLoopInfoType cliType =
4415 CanonicalLoopInfoType::get(parser.
getContext());
4440 if (parser.
parseRegion(*region, {inductionVariable}))
4445 result.operands.append(cliOperand);
4451 return mlir::success();
4454LogicalResult CanonicalLoopOp::verify() {
4457 if (!getRegion().empty()) {
4458 Region ®ion = getRegion();
4461 "Canonical loop region must have exactly one argument");
4465 "Region argument must be the same type as the trip count");
4471Value CanonicalLoopOp::getInductionVar() {
return getRegion().getArgument(0); }
4473std::pair<unsigned, unsigned>
4474CanonicalLoopOp::getApplyeesODSOperandIndexAndLength() {
4479std::pair<unsigned, unsigned>
4480CanonicalLoopOp::getGenerateesODSOperandIndexAndLength() {
4481 return getODSOperandIndexAndLength(odsIndex_cli);
4495 p <<
'(' << getApplyee() <<
')';
4502 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4525 return mlir::success();
4528std::pair<unsigned, unsigned>
4529UnrollHeuristicOp ::getApplyeesODSOperandIndexAndLength() {
4530 return getODSOperandIndexAndLength(odsIndex_applyee);
4533std::pair<unsigned, unsigned>
4534UnrollHeuristicOp::getGenerateesODSOperandIndexAndLength() {
4548 p <<
'(' << getApplyee() <<
')';
4555 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4578 return mlir::success();
4581std::pair<unsigned, unsigned>
4582UnrollFullOp::getApplyeesODSOperandIndexAndLength() {
4583 return getODSOperandIndexAndLength(odsIndex_applyee);
4586std::pair<unsigned, unsigned>
4587UnrollFullOp::getGenerateesODSOperandIndexAndLength() {
4591LogicalResult UnrollFullOp::verify() {
4592 auto [create, gen, cons] =
decodeCli(getApplyee());
4594 return emitOpError() <<
"applyee CLI has no generator";
4598 if (
auto loop = dyn_cast<CanonicalLoopOp>(gen->getOwner())) {
4600 return emitOpError() <<
"applyee loop must have a constant trip count";
4612 uint64_t unrollFactor) {
4619 p <<
'(' << getApplyee() <<
')';
4626 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4643 return mlir::success();
4646std::pair<unsigned, unsigned>
4647UnrollPartialOp::getApplyeesODSOperandIndexAndLength() {
4648 return getODSOperandIndexAndLength(odsIndex_applyee);
4651std::pair<unsigned, unsigned>
4652UnrollPartialOp::getGenerateesODSOperandIndexAndLength() {
4663 if (!generatees.empty())
4664 p <<
'(' << llvm::interleaved(generatees) <<
')';
4666 if (!applyees.empty())
4667 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4709 bool isOnlyCanonLoops =
true;
4711 for (
Value applyee : op.getApplyees()) {
4712 auto [create, gen, cons] =
decodeCli(applyee);
4715 return op.emitOpError() <<
"applyee CLI has no generator";
4717 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4718 canonLoops.push_back(loop);
4720 isOnlyCanonLoops =
false;
4725 if (!isOnlyCanonLoops)
4729 for (
auto i : llvm::seq<int>(1, canonLoops.size())) {
4730 auto parentLoop = canonLoops[i - 1];
4731 auto loop = canonLoops[i];
4733 if (parentLoop.getOperation() != loop.getOperation()->getParentOp())
4734 return op.emitOpError()
4735 <<
"tiled loop nest must be nested within each other";
4737 parentIVs.insert(parentLoop.getInductionVar());
4742 bool isPerfectlyNested = [&]() {
4743 auto &parentBody = parentLoop.getRegion();
4744 if (!parentBody.hasOneBlock())
4746 auto &parentBlock = parentBody.getBlocks().
front();
4748 auto nestedLoopIt = parentBlock.
begin();
4749 if (nestedLoopIt == parentBlock.
end() ||
4750 (&*nestedLoopIt != loop.getOperation()))
4753 auto termIt = std::next(nestedLoopIt);
4754 if (termIt == parentBlock.
end() || !isa<TerminatorOp>(termIt))
4757 if (std::next(termIt) != parentBlock.
end())
4762 if (!isPerfectlyNested)
4763 return op.emitOpError() <<
"tiled loop nest must be perfectly nested";
4765 if (parentIVs.contains(loop.getTripCount()))
4766 return op.emitOpError() <<
"tiled loop nest must be rectangular";
4783LogicalResult TileOp::verify() {
4784 if (getApplyees().empty())
4785 return emitOpError() <<
"must apply to at least one loop";
4787 if (getSizes().size() != getApplyees().size())
4788 return emitOpError() <<
"there must be one tile size for each applyee";
4790 if (!getGeneratees().empty() &&
4791 2 * getSizes().size() != getGeneratees().size())
4793 <<
"expecting two times the number of generatees than applyees";
4798std::pair<unsigned, unsigned> TileOp ::getApplyeesODSOperandIndexAndLength() {
4799 return getODSOperandIndexAndLength(odsIndex_applyees);
4802std::pair<unsigned, unsigned> TileOp::getGenerateesODSOperandIndexAndLength() {
4803 return getODSOperandIndexAndLength(odsIndex_generatees);
4813 if (!generatees.empty())
4814 p <<
'(' << llvm::interleaved(generatees) <<
')';
4816 if (!applyees.empty())
4817 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4820LogicalResult FuseOp::verify() {
4821 if (getApplyees().size() < 2)
4822 return emitOpError() <<
"must apply to at least two loops";
4824 if (getFirst().has_value() && getCount().has_value()) {
4825 int64_t first = getFirst().value();
4826 int64_t count = getCount().value();
4827 if ((
unsigned)(first + count - 1) > getApplyees().size())
4828 return emitOpError() <<
"the numbers of applyees must be at least first "
4829 "minus one plus count attributes";
4830 if (!getGeneratees().empty() &&
4831 getGeneratees().size() != getApplyees().size() + 1 - count)
4832 return emitOpError() <<
"the number of generatees must be the number of "
4833 "aplyees plus one minus count";
4836 if (!getGeneratees().empty() && getGeneratees().size() != 1)
4838 <<
"in a complete fuse the number of generatees must be exactly 1";
4840 for (
auto &&applyee : getApplyees()) {
4841 auto [create, gen, cons] =
decodeCli(applyee);
4844 return emitOpError() <<
"applyee CLI has no generator";
4845 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4848 <<
"currently only supports omp.canonical_loop as applyee";
4852std::pair<unsigned, unsigned> FuseOp::getApplyeesODSOperandIndexAndLength() {
4853 return getODSOperandIndexAndLength(odsIndex_applyees);
4856std::pair<unsigned, unsigned> FuseOp::getGenerateesODSOperandIndexAndLength() {
4857 return getODSOperandIndexAndLength(odsIndex_generatees);
4865 const CriticalDeclareOperands &clauses) {
4866 CriticalDeclareOp::build(builder, state, clauses.symName, clauses.hint);
4869LogicalResult CriticalDeclareOp::verify() {
4873LogicalResult CriticalOp::verify() {
4874 SymbolRefAttr currentName = getNameAttr();
4876 CriticalOp parentCritical = (*this)->getParentOfType<CriticalOp>();
4878 while (parentCritical) {
4879 SymbolRefAttr parentName = parentCritical.getNameAttr();
4881 if (currentName == parentName) {
4883 return emitOpError() <<
"cannot be nested inside another omp.critical "
4884 "region with the same name ("
4885 << currentName <<
")";
4887 return emitOpError() <<
"cannot be nested inside another unnamed "
4888 "omp.critical region";
4892 parentCritical = parentCritical->getParentOfType<CriticalOp>();
4899 if (getNameAttr()) {
4900 SymbolRefAttr symbolRef = getNameAttr();
4904 return emitOpError() <<
"expected symbol reference " << symbolRef
4905 <<
" to point to a critical declaration";
4916LogicalResult ErrorOp::verify() {
4917 if (getMessage() && getMessageExpr())
4918 return emitOpError() <<
"the message must be provided either as a constant "
4919 "`message` attribute or as a `message_expr` "
4920 "operand, but not both";
4937 return op.
emitOpError() <<
"must be nested inside of a loop";
4941 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
4942 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
4944 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
4945 "have an ordered clause";
4947 if (hasRegion && orderedAttr.getInt() != 0)
4948 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
4949 "have a parameter present";
4951 if (!hasRegion && orderedAttr.getInt() == 0)
4952 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
4953 "have a parameter present";
4954 }
else if (!isa<SimdOp>(wrapper)) {
4955 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
4956 "or worksharing simd loop";
4962 const OrderedOperands &clauses) {
4963 OrderedOp::build(builder, state, clauses.doacrossDependType,
4964 clauses.doacrossNumLoops, clauses.doacrossDependVars);
4967LogicalResult OrderedOp::verify() {
4971 auto wrapper = (*this)->getParentOfType<WsloopOp>();
4972 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
4973 return emitOpError() <<
"number of variables in depend clause does not "
4974 <<
"match number of iteration variables in the "
4981 const OrderedRegionOperands &clauses) {
4982 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
4992 const TaskwaitOperands &clauses) {
5008LogicalResult AtomicReadOp::verify() {
5009 if (verifyCommon().
failed())
5010 return mlir::failure();
5013 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5014 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
5015 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5017 if (
auto mo = getMemoryOrder()) {
5018 if (*mo == ClauseMemoryOrderKind::Release) {
5019 return emitError(
"memory-order must not be release for atomic reads");
5021 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5024 return emitError(
"memory-order must not be acq_rel for atomic reads");
5034LogicalResult AtomicWriteOp::verify() {
5035 if (verifyCommon().
failed())
5036 return mlir::failure();
5039 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5040 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
5041 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5043 if (
auto mo = getMemoryOrder()) {
5044 if (*mo == ClauseMemoryOrderKind::Acquire) {
5045 return emitError(
"memory-order must not be acquire for atomic writes");
5047 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5050 return emitError(
"memory-order must not be acq_rel for atomic writes");
5060LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
5066 if (
Value writeVal = op.getWriteOpVal()) {
5068 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
5074LogicalResult AtomicUpdateOp::verify() {
5075 if (verifyCommon().
failed())
5076 return mlir::failure();
5079 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5080 if (
Attribute verAttr = moduleOp->getAttr(
"omp.version"))
5081 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5083 if (
auto mo = getMemoryOrder()) {
5084 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
5085 *mo == ClauseMemoryOrderKind::Acquire) {
5089 "memory-order must not be acq_rel or acquire for atomic updates");
5096LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
5102AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
5103 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
5105 return dyn_cast<AtomicReadOp>(getSecondOp());
5108AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
5109 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
5111 return dyn_cast<AtomicWriteOp>(getSecondOp());
5114AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
5115 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
5117 return dyn_cast<AtomicUpdateOp>(getSecondOp());
5120AtomicCompareOp AtomicCaptureOp::getAtomicCompareOp() {
5121 if (
auto op = dyn_cast<AtomicCompareOp>(getFirstOp()))
5123 return dyn_cast<AtomicCompareOp>(getSecondOp());
5126LogicalResult AtomicCaptureOp::verify() {
5130LogicalResult AtomicCaptureOp::verifyRegions() {
5131 if (verifyRegionsCommon().
failed())
5132 return mlir::failure();
5134 if (getFirstOp()->getAttr(
"hint") || getSecondOp()->getAttr(
"hint"))
5136 "operations inside capture region must not have hint clause");
5138 if (getFirstOp()->getAttr(
"memory_order") ||
5139 getSecondOp()->getAttr(
"memory_order"))
5141 "operations inside capture region must not have memory_order clause");
5149LogicalResult AtomicCompareOp::verify() {
5150 if (verifyCommon().
failed())
5151 return mlir::failure();
5155 if (
auto failOrder = getFailMemoryOrder()) {
5156 if (*failOrder != ClauseMemoryOrderKind::Seq_cst &&
5157 *failOrder != ClauseMemoryOrderKind::Acquire &&
5158 *failOrder != ClauseMemoryOrderKind::Relaxed)
5160 "fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'");
5165LogicalResult AtomicCompareOp::verifyRegions() {
5166 if (verifyRegionsCommon().
failed())
5167 return mlir::failure();
5169 if (verifyOperator().
failed())
5170 return mlir::failure();
5175 if (!terminator || !isa<YieldOp>(terminator))
5176 return emitOpError(
"region must be terminated with omp.yield");
5186 const CancelOperands &clauses) {
5187 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
5200LogicalResult CancelOp::verify() {
5201 ClauseCancellationConstructType cct = getCancelDirective();
5204 if (!structuralParent)
5205 return emitOpError() <<
"Orphaned cancel construct";
5207 if ((cct == ClauseCancellationConstructType::Parallel) &&
5208 !mlir::isa<ParallelOp>(structuralParent)) {
5209 return emitOpError() <<
"cancel parallel must appear "
5210 <<
"inside a parallel region";
5212 if (cct == ClauseCancellationConstructType::Loop) {
5215 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
5219 <<
"cancel loop must appear inside a worksharing-loop region";
5221 if (wsloopOp.getNowaitAttr()) {
5222 return emitError() <<
"A worksharing construct that is canceled "
5223 <<
"must not have a nowait clause";
5225 if (wsloopOp.getOrderedAttr()) {
5226 return emitError() <<
"A worksharing construct that is canceled "
5227 <<
"must not have an ordered clause";
5230 }
else if (cct == ClauseCancellationConstructType::Sections) {
5234 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
5236 return emitOpError() <<
"cancel sections must appear "
5237 <<
"inside a sections region";
5239 if (sectionsOp.getNowait()) {
5240 return emitError() <<
"A sections construct that is canceled "
5241 <<
"must not have a nowait clause";
5244 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5245 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5246 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5247 return emitOpError() <<
"cancel taskgroup must appear "
5248 <<
"inside a task region";
5258 const CancellationPointOperands &clauses) {
5259 CancellationPointOp::build(builder, state, clauses.cancelDirective);
5262LogicalResult CancellationPointOp::verify() {
5263 ClauseCancellationConstructType cct = getCancelDirective();
5266 if (!structuralParent)
5267 return emitOpError() <<
"Orphaned cancellation point";
5269 if ((cct == ClauseCancellationConstructType::Parallel) &&
5270 !mlir::isa<ParallelOp>(structuralParent)) {
5271 return emitOpError() <<
"cancellation point parallel must appear "
5272 <<
"inside a parallel region";
5276 if ((cct == ClauseCancellationConstructType::Loop) &&
5277 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
5278 return emitOpError() <<
"cancellation point loop must appear "
5279 <<
"inside a worksharing-loop region";
5281 if ((cct == ClauseCancellationConstructType::Sections) &&
5282 !mlir::isa<omp::SectionOp>(structuralParent)) {
5283 return emitOpError() <<
"cancellation point sections must appear "
5284 <<
"inside a sections region";
5286 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5287 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5288 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5289 return emitOpError() <<
"cancellation point taskgroup must appear "
5290 <<
"inside a task region";
5299LogicalResult MapBoundsOp::verify() {
5300 auto extent = getExtent();
5302 if (!extent && !upperbound)
5303 return emitError(
"expected extent or upperbound.");
5310 PrivateClauseOp::build(
5311 odsBuilder, odsState, symName, type,
5312 DataSharingClauseTypeAttr::get(odsBuilder.
getContext(),
5313 DataSharingClauseType::Private));
5316LogicalResult PrivateClauseOp::verifyRegions() {
5317 Type argType = getArgType();
5318 auto verifyTerminator = [&](
Operation *terminator,
5319 bool yieldsValue) -> LogicalResult {
5323 if (!llvm::isa<YieldOp>(terminator))
5325 <<
"expected exit block terminator to be an `omp.yield` op.";
5327 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
5328 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
5331 if (yieldedTypes.empty())
5335 <<
"Did not expect any values to be yielded.";
5338 if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)
5342 <<
"Invalid yielded value. Expected type: " << argType
5345 if (yieldedTypes.empty())
5348 error << yieldedTypes;
5354 StringRef regionName,
5355 bool yieldsValue) -> LogicalResult {
5356 assert(!region.
empty());
5360 <<
"`" << regionName <<
"`: " <<
"expected " << expectedNumArgs
5363 for (
Block &block : region) {
5376 for (
Region *region : getRegions())
5377 for (
Type ty : region->getArgumentTypes())
5379 return emitError() <<
"Region argument type mismatch: got " << ty
5380 <<
" expected " << argType <<
".";
5383 if (!initRegion.
empty() &&
5388 DataSharingClauseType dsType = getDataSharingType();
5390 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
5391 return emitError(
"`private` clauses do not require a `copy` region.");
5393 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
5395 "`firstprivate` clauses require at least a `copy` region.");
5397 if (dsType == DataSharingClauseType::FirstPrivate &&
5402 if (!getDeallocRegion().empty() &&
5415 const MaskedOperands &clauses) {
5416 MaskedOp::build(builder, state, clauses.filteredThreadId);
5424 const ScanOperands &clauses) {
5425 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
5428LogicalResult ScanOp::verify() {
5429 if (hasExclusiveVars() == hasInclusiveVars())
5431 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
5432 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
5433 if (parentWsLoopOp.getReductionModAttr() &&
5434 parentWsLoopOp.getReductionModAttr().getValue() ==
5435 ReductionModifier::inscan)
5438 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
5439 if (parentSimdOp.getReductionModAttr() &&
5440 parentSimdOp.getReductionModAttr().getValue() ==
5441 ReductionModifier::inscan)
5444 return emitError(
"SCAN directive needs to be enclosed within a parent "
5445 "worksharing loop construct or SIMD construct with INSCAN "
5446 "reduction modifier");
5451 std::optional<uint64_t> alignment) {
5452 if (alignment.has_value()) {
5453 if ((alignment.value() != 0) && !llvm::has_single_bit(alignment.value()))
5455 <<
"ALIGN value : " << alignment.value() <<
" must be power of 2";
5460LogicalResult AllocateDirOp::verify() {
5468LogicalResult AllocSharedMemOp::verify() {
5476LogicalResult FreeSharedMemOp::verify() {
5484LogicalResult WorkdistributeOp::verify() {
5486 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
5489 Region ®ion = getRegion();
5494 if (entryBlock.
empty())
5495 return emitOpError(
"region must contain a structured block");
5497 bool hasTerminator =
false;
5498 for (
Block &block : region) {
5499 if (isa<TerminatorOp>(block.
back())) {
5500 if (hasTerminator) {
5501 return emitOpError(
"region must have exactly one terminator");
5503 hasTerminator =
true;
5506 if (!hasTerminator) {
5507 return emitOpError(
"region must be terminated with omp.terminator");
5511 if (isa<BarrierOp>(op)) {
5513 "explicit barriers are not allowed in workdistribute region");
5516 if (isa<ParallelOp>(op)) {
5518 "nested parallel constructs not allowed in workdistribute");
5520 if (isa<TeamsOp>(op)) {
5522 "nested teams constructs not allowed in workdistribute");
5526 if (walkResult.wasInterrupted())
5530 if (!llvm::dyn_cast<TeamsOp>(parentOp))
5531 return emitOpError(
"workdistribute must be nested under teams");
5539LogicalResult DeclareSimdOp::verify() {
5542 dyn_cast_if_present<mlir::FunctionOpInterface>((*this)->getParentOp());
5544 return emitOpError() <<
"must be nested inside a function";
5546 if (getInbranch() && getNotinbranch())
5547 return emitOpError(
"cannot have both 'inbranch' and 'notinbranch'");
5557 const DeclareSimdOperands &clauses) {
5559 DeclareSimdOp::build(odsBuilder, odsState, clauses.alignedVars,
5561 clauses.linearVars, clauses.linearStepVars,
5562 clauses.linearVarTypes, clauses.linearModifiers,
5563 clauses.notinbranch, clauses.simdlen,
5564 clauses.uniformVars);
5581 return mlir::failure();
5582 return mlir::success();
5589 for (
unsigned i = 0; i < uniformVars.size(); ++i) {
5592 p << uniformVars[i] <<
" : " << uniformTypes[i];
5607 parser, iterated, iteratedTypes, affinityVars, affinityVarTypes,
5608 [&]() -> ParseResult {
return success(); })))
5642 OpAsmParser::Argument &arg = ivArgs.emplace_back();
5643 if (parser.parseArgument(arg))
5647 if (succeeded(parser.parseOptionalColon())) {
5648 if (parser.parseType(arg.type))
5651 arg.type = parser.getBuilder().getIndexType();
5663 OpAsmParser::UnresolvedOperand lb, ub, st;
5664 if (parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
5665 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
5666 parser.parseOperand(st))
5671 steps.push_back(st);
5679 if (ivArgs.size() != lbs.size())
5681 <<
"mismatch: " << ivArgs.size() <<
" variables but " << lbs.size()
5684 for (
auto &arg : ivArgs) {
5685 lbTypes.push_back(arg.type);
5686 ubTypes.push_back(arg.type);
5687 stepTypes.push_back(arg.type);
5707 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
5710 p << lbs[i] <<
" to " << ubs[i] <<
" step " << steps[i];
5718LogicalResult IteratorOp::verify() {
5719 auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().
getType());
5721 return emitOpError() <<
"result must be omp.iterated<entry_ty>";
5723 for (
auto [lb,
ub, step] : llvm::zip_equal(
5724 getLoopLowerBounds(), getLoopUpperBounds(), getLoopSteps())) {
5726 return emitOpError() <<
"loop step must not be zero";
5730 IntegerAttr stepAttr;
5736 const APInt &lbVal = lbAttr.getValue();
5737 const APInt &ubVal = ubAttr.getValue();
5738 const APInt &stepVal = stepAttr.getValue();
5739 if (stepVal.isStrictlyPositive() && lbVal.sgt(ubVal))
5740 return emitOpError() <<
"positive loop step requires lower bound to be "
5741 "less than or equal to upper bound";
5742 if (stepVal.isNegative() && lbVal.slt(ubVal))
5743 return emitOpError() <<
"negative loop step requires lower bound to be "
5744 "greater than or equal to upper bound";
5747 Block &
b = getRegion().front();
5748 auto yield = llvm::dyn_cast<omp::YieldOp>(
b.getTerminator());
5751 return emitOpError() <<
"region must be terminated by omp.yield";
5753 if (yield.getNumOperands() != 1)
5755 <<
"omp.yield in omp.iterator region must yield exactly one value";
5757 mlir::Type yieldedTy = yield.getOperand(0).getType();
5758 mlir::Type elemTy = iteratedTy.getElementType();
5760 if (yieldedTy != elemTy)
5761 return emitOpError() <<
"omp.iterated element type (" << elemTy
5762 <<
") does not match omp.yield operand type ("
5763 << yieldedTy <<
")";
5776 return emitOpError() <<
"expected symbol reference '" << getSymName()
5777 <<
"' to point to a global variable";
5779 if (isa<FunctionOpInterface>(symbol))
5780 return emitOpError() <<
"expected symbol reference '" << getSymName()
5781 <<
"' to point to a global variable, not a function";
5786#define GET_ATTRDEF_CLASSES
5787#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
5789#define GET_OP_CLASSES
5790#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
5792#define GET_TYPEDEF_CLASSES
5793#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, const Twine &name)
static Type getElementType(Type type)
Determine the element type of type.
static const mlir::GenInfo * generator
static LogicalResult verifyNontemporalClause(Operation *op, OperandRange nontemporalVars)
static DenseI64ArrayAttr makeDenseI64ArrayAttr(MLIRContext *ctx, const ArrayRef< int64_t > intArray)
static void printDependVarList(OpAsmPrinter &p, Operation *op, OperandRange dependVars, TypeRange dependTypes, std::optional< ArrayAttr > dependKinds, OperandRange iteratedVars, TypeRange iteratedTypes, std::optional< ArrayAttr > iteratedKinds)
Print Depend clause.
static ParseResult parseTargetOpRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hasDeviceAddrVars, SmallVectorImpl< Type > &hasDeviceAddrTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &hostEvalVars, SmallVectorImpl< Type > &hostEvalTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &mapVars, SmallVectorImpl< Type > &mapTypes, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, UnitAttr &privateNeedsBarrier, DenseI64ArrayAttr &privateMaps)
static constexpr StringRef getPrivateNeedsBarrierSpelling()
static void printHeapAllocClause(OpAsmPrinter &p, Operation *op, TypeAttr inType, ValueRange typeparams, TypeRange typeparamsTypes, ValueRange shape, TypeRange shapeTypes)
static LogicalResult verifyReductionVarList(Operation *op, std::optional< ArrayAttr > reductionSyms, OperandRange reductionVars, std::optional< ArrayRef< bool > > reductionByref)
Verifies Reduction Clause.
static ParseResult parseLinearClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearVars, SmallVectorImpl< Type > &linearTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearStepVars, SmallVectorImpl< Type > &linearStepTypes, ArrayAttr &linearModifiers)
linear ::= linear ( linear-list ) linear-list := linear-val | linear-val linear-list linear-val := ss...
static ParseResult parseInReductionPrivateRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms, llvm::SmallVectorImpl< OpAsmParser::UnresolvedOperand > &privateVars, llvm::SmallVectorImpl< Type > &privateTypes, ArrayAttr &privateSyms, UnitAttr &privateNeedsBarrier)
static ArrayAttr makeArrayAttr(MLIRContext *context, llvm::ArrayRef< Attribute > attrs)
static ParseResult parseClauseAttr(AsmParser &parser, ClauseAttr &attr)
static void printDynGroupprivateClause(OpAsmPrinter &printer, Operation *op, AccessGroupModifierAttr modifierFirst, FallbackModifierAttr modifierSecond, Value dynGroupprivateSize, Type sizeType)
static void printAllocateAndAllocator(OpAsmPrinter &p, Operation *op, OperandRange allocateVars, TypeRange allocateTypes, OperandRange allocatorVars, TypeRange allocatorTypes)
Print allocate clause.
static DenseBoolArrayAttr makeDenseBoolArrayAttr(MLIRContext *ctx, const ArrayRef< bool > boolArray)
static std::string generateLoopNestingName(StringRef prefix, CanonicalLoopOp op)
Generate a name of a canonical loop nest of the format <prefix>(_r<idx>_s<idx>)*.
static ParseResult parseAffinityClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &iterated, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &affinityVars, SmallVectorImpl< Type > &iteratedTypes, SmallVectorImpl< Type > &affinityVarTypes)
static void printClauseWithRegionArgs(OpAsmPrinter &p, MLIRContext *ctx, StringRef clauseName, ValueRange argsSubrange, ValueRange operands, TypeRange types, ArrayAttr symbols=nullptr, DenseI64ArrayAttr mapIndices=nullptr, DenseBoolArrayAttr byref=nullptr, ReductionModifierAttr modifier=nullptr, UnitAttr needsBarrier=nullptr)
static void printSplitIteratedList(OpAsmPrinter &p, ValueRange iteratedVars, TypeRange iteratedTypes, ValueRange plainVars, TypeRange plainTypes, PrintPrefixFn &&printPrefixForPlain, PrintPrefixFn &&printPrefixForIterated)
static LogicalResult verifyDependVarList(Operation *op, std::optional< ArrayAttr > dependKinds, OperandRange dependVars, std::optional< ArrayAttr > iteratedKinds, OperandRange iteratedVars)
Verifies Depend clause.
static void printBlockArgClause(OpAsmPrinter &p, MLIRContext *ctx, StringRef clauseName, ValueRange argsSubrange, std::optional< MapPrintArgs > mapArgs)
static void printAffinityClause(OpAsmPrinter &p, Operation *op, ValueRange iterated, ValueRange affinityVars, TypeRange iteratedTypes, TypeRange affinityVarTypes)
static void printBlockArgRegion(OpAsmPrinter &p, Operation *op, Region ®ion, const AllRegionPrintArgs &args)
static ParseResult parseGranularityClause(OpAsmParser &parser, ClauseTypeAttr &prescriptiveness, std::optional< OpAsmParser::UnresolvedOperand > &operand, Type &operandType, std::optional< ClauseType >(*symbolizeClause)(StringRef), StringRef clauseName)
static void printIteratorHeader(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange lbs, ValueRange ubs, ValueRange steps, TypeRange, TypeRange, TypeRange)
static 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 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.