28#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/PostOrderIterator.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/STLForwardCompat.h"
32#include "llvm/ADT/SmallString.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/ADT/TypeSwitch.h"
36#include "llvm/ADT/bit.h"
37#include "llvm/Support/InterleavedRange.h"
43#include "mlir/Dialect/OpenMP/OpenMPOpsDialect.cpp.inc"
44#include "mlir/Dialect/OpenMP/OpenMPOpsEnums.cpp.inc"
45#include "mlir/Dialect/OpenMP/OpenMPOpsInterfaces.cpp.inc"
46#include "mlir/Dialect/OpenMP/OpenMPTypeInterfaces.cpp.inc"
53 return attrs.empty() ?
nullptr : ArrayAttr::get(context, attrs);
67struct MemRefPointerLikeModel
68 :
public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
71 return llvm::cast<MemRefType>(pointer).getElementType();
75struct LLVMPointerPointerLikeModel
76 :
public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
77 LLVM::LLVMPointerType> {
102 bool isRegionArgOfOp;
112 assert(isRegionArgOfOp &&
"Must describe a region operand");
115 size_t &getArgIdx() {
116 assert(isRegionArgOfOp &&
"Must describe a region operand");
121 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
125 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
128 bool isLoopOp()
const {
129 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
130 return isa<CanonicalLoopOp>(op);
132 Region *&getParentRegion() {
133 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
136 size_t &getLoopDepth() {
137 assert(!isRegionArgOfOp &&
"Must describe a operation of a region");
141 void skipIf(
bool v =
true) { skip = skip || v; }
159 llvm::ReversePostOrderTraversal<Block *> traversal(&r->
getBlocks().front());
162 size_t sequentialIdx = -1;
163 bool isOnlyContainerOp =
true;
164 for (
Block *
b : traversal) {
166 if (&op == o && !found) {
170 if (op.getNumRegions()) {
173 isOnlyContainerOp =
false;
175 if (found && !isOnlyContainerOp)
180 Component &containerOpInRegion = components.emplace_back();
181 containerOpInRegion.isRegionArgOfOp =
false;
182 containerOpInRegion.isUnique = isOnlyContainerOp;
183 containerOpInRegion.getContainerOp() = o;
184 containerOpInRegion.getOpPos() = sequentialIdx;
185 containerOpInRegion.getParentRegion() = r;
190 Component ®ionArgOfOperation = components.emplace_back();
191 regionArgOfOperation.isRegionArgOfOp =
true;
192 regionArgOfOperation.isUnique =
true;
193 regionArgOfOperation.getArgIdx() = 0;
194 regionArgOfOperation.getOwnerOp() = parent;
206 for (
auto [idx, region] : llvm::enumerate(o->
getRegions())) {
210 llvm_unreachable(
"Region not child of its parent operation");
212 regionArgOfOperation.isUnique =
false;
213 regionArgOfOperation.getArgIdx() = getRegionIndex(parent, r);
221 for (Component &c : components)
222 c.skipIf(c.isRegionArgOfOp && c.isUnique);
225 size_t numSurroundingLoops = 0;
226 for (Component &c : llvm::reverse(components)) {
231 if (c.isRegionArgOfOp) {
232 numSurroundingLoops = 0;
239 numSurroundingLoops = 0;
241 c.getLoopDepth() = numSurroundingLoops;
244 if (isa<CanonicalLoopOp>(c.getContainerOp()))
245 numSurroundingLoops += 1;
250 bool isLoopNest =
false;
251 for (Component &c : components) {
252 if (c.skip || c.isRegionArgOfOp)
255 if (!isLoopNest && c.getLoopDepth() >= 1) {
258 }
else if (isLoopNest) {
260 c.skipIf(c.isUnique);
264 if (c.getLoopDepth() == 0)
271 for (Component &c : components)
272 c.skipIf(!c.isRegionArgOfOp && c.isUnique &&
273 !isa<CanonicalLoopOp>(c.getContainerOp()));
277 bool newRegion =
true;
278 for (Component &c : llvm::reverse(components)) {
279 c.skipIf(newRegion && c.isUnique);
286 if (!c.isRegionArgOfOp && c.getContainerOp())
292 llvm::raw_svector_ostream NameOS(Name);
293 for (
auto &c : llvm::reverse(components)) {
297 if (c.isRegionArgOfOp)
298 NameOS <<
"_r" << c.getArgIdx();
299 else if (c.getLoopDepth() >= 1)
300 NameOS <<
"_d" << c.getLoopDepth();
302 NameOS <<
"_s" << c.getOpPos();
305 return NameOS.str().str();
308void OpenMPDialect::initialize() {
311#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
314#define GET_ATTRDEF_LIST
315#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
318#define GET_TYPEDEF_LIST
319#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
322 declarePromisedInterface<ConvertToLLVMPatternInterface, OpenMPDialect>();
324 MemRefType::attachInterface<MemRefPointerLikeModel>(*
getContext());
325 LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
330 mlir::ModuleOp::attachInterface<mlir::omp::OffloadModuleDefaultModel>(
336 mlir::LLVM::GlobalOp::attachInterface<
339 mlir::LLVM::LLVMFuncOp::attachInterface<
342 mlir::func::FuncOp::attachInterface<
351 if (!isa<DeclareTargetInterface>(op))
352 return op->
emitError() <<
"omp.declare_target can only be applied to "
353 "DeclareTargetInterface ops";
355 auto declareTargetAttr = dyn_cast<DeclareTargetAttr>(attr);
356 if (!declareTargetAttr)
358 <<
"omp.declare_target must be an #omp.declaretarget attribute";
360 if (isa<mlir::FunctionOpInterface>(op)) {
361 if (declareTargetAttr.getAutomap())
363 <<
"omp.declare_target 'automap' is not valid on functions";
366 if (declareTargetAttr.getCaptureClause() ==
367 mlir::omp::DeclareTargetCaptureClause::link)
369 <<
"omp.declare_target 'link' is not valid on functions";
372 if (declareTargetAttr.getImplicit())
374 <<
"omp.declare_target 'implicit' is only valid on functions";
380OpenMPDialect::verifyOperationAttribute(
Operation *op,
382 if (attribute.
getName() ==
"omp.declare_target")
410 allocatorVars.push_back(operand);
411 allocatorTypes.push_back(type);
417 allocateVars.push_back(operand);
418 allocateTypes.push_back(type);
429 for (
unsigned i = 0; i < allocateVars.size(); ++i) {
430 std::string separator = i == allocateVars.size() - 1 ?
"" :
", ";
431 p << allocatorVars[i] <<
" : " << allocatorTypes[i] <<
" -> ";
432 p << allocateVars[i] <<
" : " << allocateTypes[i] << separator;
440template <
typename ClauseAttr>
442 using ClauseT =
decltype(std::declval<ClauseAttr>().getValue());
447 if (std::optional<ClauseT> enumValue = symbolizeEnum<ClauseT>(enumStr)) {
448 attr = ClauseAttr::get(parser.
getContext(), *enumValue);
451 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
454template <
typename ClauseAttr>
456 p << stringifyEnum(attr.getValue());
482 std::optional<omp::LinearModifier> linearModifier;
484 linearModifier = omp::LinearModifier::val;
486 linearModifier = omp::LinearModifier::ref;
488 linearModifier = omp::LinearModifier::uval;
491 bool hasLinearModifierParens = linearModifier.has_value();
492 if (hasLinearModifierParens && parser.
parseLParen())
500 if (hasLinearModifierParens && parser.
parseRParen())
503 linearVars.push_back(var);
504 linearTypes.push_back(type);
505 linearStepVars.push_back(stepVar);
506 linearStepTypes.push_back(stepType);
507 if (linearModifier) {
509 omp::LinearModifierAttr::get(parser.
getContext(), *linearModifier));
511 modifiers.push_back(UnitAttr::get(parser.
getContext()));
517 linearModifiers = ArrayAttr::get(parser.
getContext(), modifiers);
527 size_t linearVarsSize = linearVars.size();
528 for (
unsigned i = 0; i < linearVarsSize; ++i) {
532 Attribute modAttr = linearModifiers ? linearModifiers[i] :
nullptr;
533 auto mod = modAttr ? dyn_cast<omp::LinearModifierAttr>(modAttr) :
nullptr;
535 p << omp::stringifyLinearModifier(mod.getValue()) <<
"(";
537 p << linearVars[i] <<
" : " << linearTypes[i];
538 p <<
" = " << linearStepVars[i] <<
" : " << stepVarTypes[i];
554 if (!linearModifiers)
556 if (linearModifiers->size() != linearVars.size())
558 <<
"expected as many linear modifiers as linear variables";
559 if (!isDeclareSimd) {
560 for (
Attribute attr : *linearModifiers) {
563 auto modAttr = dyn_cast<omp::LinearModifierAttr>(attr);
566 omp::LinearModifier mod = modAttr.getValue();
567 if (mod == omp::LinearModifier::ref || mod == omp::LinearModifier::uval)
569 <<
"linear modifier '" << omp::stringifyLinearModifier(mod)
570 <<
"' may only be specified on a declare simd directive";
585 for (
const auto &it : nontemporalVars)
586 if (!nontemporalItems.insert(it).second)
587 return op->
emitOpError() <<
"nontemporal variable used more than once";
596 std::optional<ArrayAttr> alignments,
599 if (!alignedVars.empty()) {
600 if (!alignments || alignments->size() != alignedVars.size())
602 <<
"expected as many alignment values as aligned variables";
605 return op->
emitOpError() <<
"unexpected alignment values attribute";
611 for (
auto it : alignedVars)
612 if (!alignedItems.insert(it).second)
613 return op->
emitOpError() <<
"aligned variable used more than once";
619 for (
unsigned i = 0; i < (*alignments).size(); ++i) {
620 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>((*alignments)[i])) {
621 if (intAttr.getValue().sle(0))
622 return op->
emitOpError() <<
"alignment should be greater than 0";
624 return op->
emitOpError() <<
"expected integer alignment";
641 if (parser.parseOperand(alignedVars.emplace_back()) ||
642 parser.parseColonType(alignedTypes.emplace_back()) ||
643 parser.parseArrow() ||
644 parser.parseAttribute(alignmentVec.emplace_back())) {
651 alignmentsAttr = ArrayAttr::get(parser.getContext(), alignments);
658 std::optional<ArrayAttr> alignments) {
659 for (
unsigned i = 0; i < alignedVars.size(); ++i) {
662 p << alignedVars[i] <<
" : " << alignedVars[i].
getType();
663 p <<
" -> " << (*alignments)[i];
671 ArrayAttr privateSyms =
nullptr,
bool requirePrivateIndices =
false) {
672 if (allocateVars.size() != allocatorVars.size())
674 "expected equal sizes for allocate and allocator variables");
676 if (allocateVars.empty()) {
677 if (allocateAlignments)
679 "unexpected allocate alignments without allocate variables");
680 if (allocatePrivateIndices)
682 "unexpected allocate private indices without allocate variables");
686 if (allocateAlignments) {
688 if (alignments.size() != allocateVars.size())
690 "expected as many allocate alignments as allocate variables");
691 for (
int64_t alignment : alignments) {
693 return op->
emitError(
"expected non-negative allocate alignments");
694 if (alignment != 0 && (alignment & (alignment - 1)) != 0)
696 "expected positive allocate alignments to be powers of two");
700 if (!allocatePrivateIndices) {
701 if (requirePrivateIndices)
703 "expected an allocate private index for each allocate variable");
708 if (
indices.size() != allocateVars.size())
710 "expected as many allocate private indices as allocate variables");
713 for (
auto [allocateVar, privateIndex] :
714 llvm::zip_equal(allocateVars,
indices)) {
715 if (privateIndex < 0 ||
716 static_cast<uint64_t
>(privateIndex) >= privateVars.size())
717 return op->
emitError(
"allocate private index is out of range");
718 if (!usedPrivateSlots.insert(privateIndex).second)
720 "allocate private index refers to a private variable more than once");
722 Value privateVar = privateVars[privateIndex];
723 if (allocateVar.getType() != privateVar.
getType())
725 <<
"type mismatch between allocate variable and private variable "
728 if (allocateVar != privateVar)
730 <<
"allocate variable does not match private variable at index "
734 static_cast<uint64_t
>(privateIndex) >= privateSyms.size())
736 "allocate private index does not have a privatizer symbol");
738 auto privateSym = dyn_cast<SymbolRefAttr>(privateSyms[privateIndex]);
741 "allocate private index does not reference a privatizer symbol");
742 PrivateClauseOp privatizer =
745 return op->
emitError() <<
"failed to lookup privatizer op with symbol: '"
746 << privateSym <<
"'";
747 if (privatizer.getDataSharingType() != DataSharingClauseType::Private &&
748 privatizer.getDataSharingType() != DataSharingClauseType::FirstPrivate)
750 "allocate private index must refer to private or firstprivate "
764 if (modifiers.size() > 2)
766 for (
const auto &mod : modifiers) {
769 auto symbol = symbolizeScheduleModifier(mod);
772 <<
" unknown modifier type: " << mod;
777 if (modifiers.size() == 1) {
778 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd) {
779 modifiers.push_back(modifiers[0]);
780 modifiers[0] = stringifyScheduleModifier(ScheduleModifier::none);
782 }
else if (modifiers.size() == 2) {
785 if (symbolizeScheduleModifier(modifiers[0]) == ScheduleModifier::simd ||
786 symbolizeScheduleModifier(modifiers[1]) != ScheduleModifier::simd)
788 <<
" incorrect modifier order";
804 ScheduleModifierAttr &scheduleMod, UnitAttr &scheduleSimd,
805 std::optional<OpAsmParser::UnresolvedOperand> &chunkSize,
810 std::optional<mlir::omp::ClauseScheduleKind> schedule =
811 symbolizeClauseScheduleKind(keyword);
815 scheduleAttr = ClauseScheduleKindAttr::get(parser.
getContext(), *schedule);
817 case ClauseScheduleKind::Static:
818 case ClauseScheduleKind::Dynamic:
819 case ClauseScheduleKind::Guided:
825 chunkSize = std::nullopt;
828 case ClauseScheduleKind::Auto:
829 case ClauseScheduleKind::Runtime:
830 case ClauseScheduleKind::Distribute:
831 chunkSize = std::nullopt;
840 modifiers.push_back(mod);
846 if (!modifiers.empty()) {
848 if (std::optional<ScheduleModifier> mod =
849 symbolizeScheduleModifier(modifiers[0])) {
850 scheduleMod = ScheduleModifierAttr::get(parser.
getContext(), *mod);
852 return parser.
emitError(loc,
"invalid schedule modifier");
855 if (modifiers.size() > 1) {
856 assert(symbolizeScheduleModifier(modifiers[1]) == ScheduleModifier::simd);
866 ClauseScheduleKindAttr scheduleKind,
867 ScheduleModifierAttr scheduleMod,
868 UnitAttr scheduleSimd,
Value scheduleChunk,
869 Type scheduleChunkType) {
870 p << stringifyClauseScheduleKind(scheduleKind.getValue());
872 p <<
" = " << scheduleChunk <<
" : " << scheduleChunk.
getType();
874 p <<
", " << stringifyScheduleModifier(scheduleMod.getValue());
886 ClauseOrderKindAttr &order,
887 OrderModifierAttr &orderMod) {
892 if (std::optional<OrderModifier> enumValue =
893 symbolizeOrderModifier(enumStr)) {
894 orderMod = OrderModifierAttr::get(parser.
getContext(), *enumValue);
901 if (std::optional<ClauseOrderKind> enumValue =
902 symbolizeClauseOrderKind(enumStr)) {
903 order = ClauseOrderKindAttr::get(parser.
getContext(), *enumValue);
906 return parser.
emitError(loc,
"invalid clause value: '") << enumStr <<
"'";
910 ClauseOrderKindAttr order,
911 OrderModifierAttr orderMod) {
913 p << stringifyOrderModifier(orderMod.getValue()) <<
":";
915 p << stringifyClauseOrderKind(order.getValue());
918template <
typename ClauseTypeAttr,
typename ClauseType>
921 std::optional<OpAsmParser::UnresolvedOperand> &operand,
923 std::optional<ClauseType> (*symbolizeClause)(StringRef),
924 StringRef clauseName) {
927 if (std::optional<ClauseType> enumValue = symbolizeClause(enumStr)) {
928 prescriptiveness = ClauseTypeAttr::get(parser.
getContext(), *enumValue);
933 <<
"invalid " << clauseName <<
" modifier : '" << enumStr <<
"'";
943 <<
"expected " << clauseName <<
" operand";
946 if (operand.has_value()) {
954template <
typename ClauseTypeAttr,
typename ClauseType>
957 ClauseTypeAttr prescriptiveness,
Value operand,
959 StringRef (*stringifyClauseType)(ClauseType)) {
961 if (prescriptiveness)
962 p << stringifyClauseType(prescriptiveness.getValue()) <<
", ";
965 p << operand <<
": " << operandType;
975 std::optional<OpAsmParser::UnresolvedOperand> &grainsize,
976 Type &grainsizeType) {
978 parser, grainsizeMod, grainsize, grainsizeType,
979 &symbolizeClauseGrainsizeType,
"grainsize");
983 ClauseGrainsizeTypeAttr grainsizeMod,
986 p, op, grainsizeMod, grainsize, grainsizeType,
987 &stringifyClauseGrainsizeType);
997 std::optional<OpAsmParser::UnresolvedOperand> &numTasks,
998 Type &numTasksType) {
1000 parser, numTasksMod, numTasks, numTasksType, &symbolizeClauseNumTasksType,
1005 ClauseNumTasksTypeAttr numTasksMod,
1008 p, op, numTasksMod, numTasks, numTasksType, &stringifyClauseNumTasksType);
1024 return mlir::failure();
1025 inTypeAttr = TypeAttr::get(inType);
1054 if (!typeparams.empty()) {
1055 p <<
'(' << typeparams <<
" : " << typeparamsTypes <<
')';
1057 for (
auto sh :
shape) {
1069 FallbackModifierAttr fallback,
1070 Value dynGroupprivateSize) {
1071 if (!dynGroupprivateSize && (accessGroup || fallback))
1072 return op->
emitOpError(
"dyn_groupprivate modifiers require a size operand");
1078 OpAsmParser &parser, AccessGroupModifierAttr &accessGroupAttr,
1079 FallbackModifierAttr &fallbackAttr,
1080 std::optional<OpAsmParser::UnresolvedOperand> &dynGroupprivateSize,
1083 bool parsedAccessGroup =
false;
1084 bool parsedFallback =
false;
1085 bool parsedSize =
false;
1090 if (parsedAccessGroup)
1092 "duplicate access group modifier");
1093 accessGroupAttr = AccessGroupModifierAttr::get(
1094 parser.
getContext(), AccessGroupModifier::cgroup);
1095 parsedAccessGroup =
true;
1102 "duplicate fallback modifier");
1105 "expected '(' after 'fallback'");
1106 llvm::StringRef fbKind;
1110 "expected fallback modifier (abort/null/default_mem)");
1111 std::optional<FallbackModifier> fbEnum;
1112 if (fbKind ==
"abort")
1113 fbEnum = FallbackModifier::abort;
1114 else if (fbKind ==
"null")
1115 fbEnum = FallbackModifier::null;
1116 else if (fbKind ==
"default_mem")
1117 fbEnum = FallbackModifier::default_mem;
1120 "invalid fallback modifier '" + fbKind +
"'");
1121 fallbackAttr = FallbackModifierAttr::get(parser.
getContext(), *fbEnum);
1124 "expected ')' after fallback modifier");
1125 parsedFallback =
true;
1133 "duplicate size operand");
1134 dynGroupprivateSize = operand;
1138 "expected ':' and type after size operand");
1142 "expected dyn_groupprivate_size operand");
1147 AccessGroupModifierAttr modifierFirst,
1148 FallbackModifierAttr modifierSecond,
1149 Value dynGroupprivateSize,
1152 bool needsComma =
false;
1154 if (modifierFirst) {
1155 printer << modifierFirst.getValue();
1159 if (modifierSecond) {
1162 printer <<
"fallback(";
1163 printer << modifierSecond.getValue();
1168 if (dynGroupprivateSize) {
1171 printer << dynGroupprivateSize <<
" : " << sizeType;
1191 isByRefVec.push_back(parser.parseOptionalKeyword(
"byref").succeeded());
1192 if (parser.parseAttribute(symbolVec.emplace_back()) ||
1193 parser.parseOperand(inReductionVars.emplace_back()))
1203 [&]() { return parser.parseType(inReductionTypes.emplace_back()); }))
1206 if (inReductionVars.size() != inReductionTypes.size())
1211 inReductionSyms = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1228 syms = ArrayAttr::get(ctx, values);
1237 llvm::interleaveComma(
1238 llvm::zip_equal(inReductionVars, syms.getValue(), byref.
asArrayRef()), p,
1240 auto [var, sym, isByRef] = t;
1248 llvm::interleaveComma(inReductionTypes, p);
1256struct MapParseArgs {
1257 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1258 SmallVectorImpl<Type> &types;
1259 MapParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1260 SmallVectorImpl<Type> &types)
1261 : vars(vars), types(types) {}
1263struct PrivateParseArgs {
1264 llvm::SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1265 llvm::SmallVectorImpl<Type> &types;
1267 UnitAttr &needsBarrier;
1269 PrivateParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1270 SmallVectorImpl<Type> &types,
ArrayAttr &syms,
1271 UnitAttr &needsBarrier,
1273 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1274 mapIndices(mapIndices) {}
1277struct LinearParseArgs {
1278 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1279 SmallVectorImpl<Type> &types;
1280 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &stepVars;
1281 SmallVectorImpl<Type> &stepTypes;
1285 LinearParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1286 SmallVectorImpl<Type> &types,
1287 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &stepVars,
1288 SmallVectorImpl<Type> &stepTypes,
ArrayAttr &varTypes,
1290 : vars(vars), types(types), stepVars(stepVars), stepTypes(stepTypes),
1291 varTypes(varTypes), modifiers(modifiers), syms(syms) {}
1294struct ReductionParseArgs {
1295 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars;
1296 SmallVectorImpl<Type> &types;
1299 ReductionModifierAttr *modifier;
1300 ReductionParseArgs(SmallVectorImpl<OpAsmParser::UnresolvedOperand> &vars,
1302 ArrayAttr &syms, ReductionModifierAttr *mod =
nullptr)
1303 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1306struct AllRegionParseArgs {
1307 std::optional<MapParseArgs> hasDeviceAddrArgs;
1308 std::optional<MapParseArgs> hostEvalArgs;
1309 std::optional<ReductionParseArgs> inReductionArgs;
1310 std::optional<LinearParseArgs> linearArgs;
1311 std::optional<MapParseArgs> mapArgs;
1312 std::optional<PrivateParseArgs> privateArgs;
1313 std::optional<ReductionParseArgs> reductionArgs;
1314 std::optional<ReductionParseArgs> taskReductionArgs;
1315 std::optional<MapParseArgs> useDeviceAddrArgs;
1316 std::optional<MapParseArgs> useDevicePtrArgs;
1321 return "private_barrier";
1331 ReductionModifierAttr *modifier =
nullptr,
1332 UnitAttr *needsBarrier =
nullptr) {
1336 unsigned regionArgOffset = regionPrivateArgs.size();
1346 std::optional<ReductionModifier> enumValue =
1347 symbolizeReductionModifier(enumStr);
1348 if (!enumValue.has_value())
1350 *modifier = ReductionModifierAttr::get(parser.
getContext(), *enumValue);
1357 isByRefVec.push_back(
1358 parser.parseOptionalKeyword(
"byref").succeeded());
1360 if (symbols && parser.parseAttribute(symbolVec.emplace_back()))
1363 if (parser.parseOperand(operands.emplace_back()) ||
1364 parser.parseArrow() ||
1365 parser.parseArgument(regionPrivateArgs.emplace_back()))
1369 if (parser.parseOptionalLSquare().succeeded()) {
1370 if (parser.parseKeyword(
"map_idx") || parser.parseEqual() ||
1371 parser.parseInteger(mapIndicesVec.emplace_back()) ||
1372 parser.parseRSquare())
1375 mapIndicesVec.push_back(-1);
1387 if (parser.parseType(types.emplace_back()))
1394 if (operands.size() != types.size())
1403 *needsBarrier = mlir::UnitAttr::get(parser.
getContext());
1406 auto *argsBegin = regionPrivateArgs.begin();
1408 argsBegin + regionArgOffset + types.size());
1409 for (
auto [prv, type] : llvm::zip_equal(argsSubrange, types)) {
1415 *symbols = ArrayAttr::get(parser.
getContext(), symbolAttrs);
1418 if (!mapIndicesVec.empty())
1431 StringRef keyword, std::optional<MapParseArgs> mapArgs) {
1446 StringRef keyword, std::optional<PrivateParseArgs> privateArgs) {
1452 parser, privateArgs->vars, privateArgs->types, entryBlockArgs,
1453 &privateArgs->syms, privateArgs->mapIndices,
nullptr,
1454 nullptr, &privateArgs->needsBarrier)))
1463 StringRef keyword, std::optional<ReductionParseArgs> reductionArgs) {
1468 parser, reductionArgs->vars, reductionArgs->types, entryBlockArgs,
1469 &reductionArgs->syms,
nullptr, &reductionArgs->byref,
1470 reductionArgs->modifier)))
1481 StringRef keyword, std::optional<LinearParseArgs> linearArgs) {
1489 std::optional<LinearModifier> modifier;
1490 if (succeeded(parser.parseOptionalKeyword(
"val")))
1491 modifier = LinearModifier::val;
1492 else if (succeeded(parser.parseOptionalKeyword(
"ref")))
1493 modifier = LinearModifier::ref;
1494 else if (succeeded(parser.parseOptionalKeyword(
"uval")))
1495 modifier = LinearModifier::uval;
1496 if (modifier && parser.parseLParen())
1500 OpAsmParser::Argument &arg = entryBlockArgs.emplace_back();
1501 if (parser.parseAttribute(sym) ||
1502 parser.parseOperand(linearArgs->vars.emplace_back()) ||
1503 parser.parseArrow() || parser.parseArgument(arg) ||
1504 parser.parseColonType(linearArgs->types.emplace_back()) ||
1505 parser.parseEqual() ||
1506 parser.parseOperand(linearArgs->stepVars.emplace_back()) ||
1507 parser.parseColonType(linearArgs->stepTypes.emplace_back()))
1509 arg.type = linearArgs->types.back();
1511 if (modifier && parser.parseRParen())
1514 syms.push_back(sym);
1515 modifiers.push_back(
1516 modifier ? Attribute(LinearModifierAttr::get(ctx, *modifier))
1517 : Attribute(UnitAttr::get(ctx)));
1523 linearArgs->syms = ArrayAttr::get(ctx, syms);
1524 linearArgs->modifiers = ArrayAttr::get(ctx, modifiers);
1534 AllRegionParseArgs args) {
1538 args.hasDeviceAddrArgs)))
1540 <<
"invalid `has_device_addr` format";
1543 args.hostEvalArgs)))
1545 <<
"invalid `host_eval` format";
1548 args.inReductionArgs)))
1550 <<
"invalid `in_reduction` format";
1555 <<
"invalid `linear` format";
1560 <<
"invalid `map_entries` format";
1565 <<
"invalid `private` format";
1568 args.reductionArgs)))
1570 <<
"invalid `reduction` format";
1573 args.taskReductionArgs)))
1575 <<
"invalid `task_reduction` format";
1578 args.useDeviceAddrArgs)))
1580 <<
"invalid `use_device_addr` format";
1583 args.useDevicePtrArgs)))
1585 <<
"invalid `use_device_addr` format";
1587 return parser.
parseRegion(region, entryBlockArgs);
1603 AllRegionParseArgs args;
1604 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1605 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1606 args.mapArgs.emplace(mapVars, mapTypes);
1607 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1608 privateNeedsBarrier, &privateMaps);
1619 UnitAttr &privateNeedsBarrier) {
1620 AllRegionParseArgs args;
1621 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1622 inReductionByref, inReductionSyms);
1623 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1624 privateNeedsBarrier);
1635 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1639 AllRegionParseArgs args;
1640 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1641 inReductionByref, inReductionSyms);
1642 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1643 privateNeedsBarrier);
1644 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1645 reductionSyms, &reductionMod);
1653 UnitAttr &privateNeedsBarrier) {
1654 AllRegionParseArgs args;
1655 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1656 privateNeedsBarrier);
1664 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1668 AllRegionParseArgs args;
1669 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1670 privateNeedsBarrier);
1671 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1672 reductionSyms, &reductionMod);
1685 UnitAttr &privateNeedsBarrier, ReductionModifierAttr &reductionMod,
1689 AllRegionParseArgs args;
1690 args.linearArgs.emplace(linearVars, linearTypes, linearStepVars,
1691 linearStepTypes, linearVarTypes, linearModifiers,
1693 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1694 privateNeedsBarrier);
1695 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1696 reductionSyms, &reductionMod);
1705 AllRegionParseArgs args;
1706 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
1707 taskReductionByref, taskReductionSyms);
1717 AllRegionParseArgs args;
1718 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
1719 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
1728struct MapPrintArgs {
1733struct PrivatePrintArgs {
1737 UnitAttr needsBarrier;
1741 : vars(vars), types(types), syms(syms), needsBarrier(needsBarrier),
1742 mapIndices(mapIndices) {}
1744struct LinearPrintArgs {
1755 : vars(vars), types(types), stepVars(stepVars), stepTypes(stepTypes),
1756 varTypes(varTypes), modifiers(modifiers), syms(syms) {}
1758struct ReductionPrintArgs {
1763 ReductionModifierAttr modifier;
1765 ArrayAttr syms, ReductionModifierAttr mod =
nullptr)
1766 : vars(vars), types(types), byref(byref), syms(syms), modifier(mod) {}
1768struct AllRegionPrintArgs {
1769 std::optional<MapPrintArgs> hasDeviceAddrArgs;
1770 std::optional<MapPrintArgs> hostEvalArgs;
1771 std::optional<ReductionPrintArgs> inReductionArgs;
1772 std::optional<LinearPrintArgs> linearArgs;
1773 std::optional<MapPrintArgs> mapArgs;
1774 std::optional<PrivatePrintArgs> privateArgs;
1775 std::optional<ReductionPrintArgs> reductionArgs;
1776 std::optional<ReductionPrintArgs> taskReductionArgs;
1777 std::optional<MapPrintArgs> useDeviceAddrArgs;
1778 std::optional<MapPrintArgs> useDevicePtrArgs;
1787 ReductionModifierAttr modifier =
nullptr, UnitAttr needsBarrier =
nullptr) {
1788 if (argsSubrange.empty())
1791 p << clauseName <<
"(";
1794 p <<
"mod: " << stringifyReductionModifier(modifier.getValue()) <<
", ";
1798 symbols = ArrayAttr::get(ctx, values);
1811 llvm::interleaveComma(llvm::zip_equal(operands, argsSubrange, symbols,
1812 mapIndices.asArrayRef(),
1813 byref.asArrayRef()),
1815 auto [op, arg, sym, map, isByRef] = t;
1821 p << op <<
" -> " << arg;
1824 p <<
" [map_idx=" << map <<
"]";
1827 llvm::interleaveComma(types, p);
1835 StringRef clauseName,
ValueRange argsSubrange,
1836 std::optional<MapPrintArgs> mapArgs) {
1843 StringRef clauseName,
ValueRange argsSubrange,
1844 std::optional<PrivatePrintArgs> privateArgs) {
1847 p, ctx, clauseName, argsSubrange, privateArgs->vars, privateArgs->types,
1848 privateArgs->syms, privateArgs->mapIndices,
nullptr,
1849 nullptr, privateArgs->needsBarrier);
1855 std::optional<ReductionPrintArgs> reductionArgs) {
1858 reductionArgs->vars, reductionArgs->types,
1859 reductionArgs->syms,
nullptr,
1860 reductionArgs->byref, reductionArgs->modifier);
1864 StringRef clauseName,
ValueRange argsSubrange,
1865 std::optional<LinearPrintArgs> linearArgs) {
1866 if (!linearArgs || argsSubrange.empty())
1869 p << clauseName <<
"(";
1870 for (
auto [i, var] : llvm::enumerate(linearArgs->vars)) {
1874 linearArgs->modifiers
1875 ? dyn_cast_if_present<LinearModifierAttr>(linearArgs->modifiers[i])
1878 p << stringifyLinearModifier(modifier.getValue()) <<
"(";
1879 if (linearArgs->syms)
1880 p << linearArgs->syms[i] <<
" ";
1881 p << var <<
" -> " << argsSubrange[i] <<
" : " << linearArgs->types[i]
1882 <<
" = " << linearArgs->stepVars[i] <<
" : " << linearArgs->stepTypes[i];
1888 if (linearArgs->varTypes)
1889 p <<
"linear_var_types(" << linearArgs->varTypes <<
") ";
1893 const AllRegionPrintArgs &args) {
1894 auto iface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(op);
1898 iface.getHasDeviceAddrBlockArgs(),
1899 args.hasDeviceAddrArgs);
1903 args.inReductionArgs);
1911 args.reductionArgs);
1913 iface.getTaskReductionBlockArgs(),
1914 args.taskReductionArgs);
1916 iface.getUseDeviceAddrBlockArgs(),
1917 args.useDeviceAddrArgs);
1919 iface.getUseDevicePtrBlockArgs(), args.useDevicePtrArgs);
1933 UnitAttr privateNeedsBarrier,
1935 AllRegionPrintArgs args;
1936 args.hasDeviceAddrArgs.emplace(hasDeviceAddrVars, hasDeviceAddrTypes);
1937 args.hostEvalArgs.emplace(hostEvalVars, hostEvalTypes);
1938 args.mapArgs.emplace(mapVars, mapTypes);
1939 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1940 privateNeedsBarrier, privateMaps);
1948 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier) {
1949 AllRegionPrintArgs args;
1950 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1951 inReductionByref, inReductionSyms);
1952 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1953 privateNeedsBarrier,
1962 ArrayAttr privateSyms, UnitAttr privateNeedsBarrier,
1963 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1966 AllRegionPrintArgs args;
1967 args.inReductionArgs.emplace(inReductionVars, inReductionTypes,
1968 inReductionByref, inReductionSyms);
1969 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1970 privateNeedsBarrier,
1972 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1973 reductionSyms, reductionMod);
1980 UnitAttr privateNeedsBarrier) {
1981 AllRegionPrintArgs args;
1982 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1983 privateNeedsBarrier,
1991 ReductionModifierAttr reductionMod,
ValueRange reductionVars,
1994 AllRegionPrintArgs args;
1995 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
1996 privateNeedsBarrier,
1998 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
1999 reductionSyms, reductionMod);
2008 UnitAttr privateNeedsBarrier, ReductionModifierAttr reductionMod,
2011 AllRegionPrintArgs args;
2012 args.linearArgs.emplace(linearVars, linearTypes, linearStepVars,
2013 linearStepTypes, linearVarTypes, linearModifiers,
2015 args.privateArgs.emplace(privateVars, privateTypes, privateSyms,
2016 privateNeedsBarrier,
2018 args.reductionArgs.emplace(reductionVars, reductionTypes, reductionByref,
2019 reductionSyms, reductionMod);
2029 AllRegionPrintArgs args;
2030 args.taskReductionArgs.emplace(taskReductionVars, taskReductionTypes,
2031 taskReductionByref, taskReductionSyms);
2041 AllRegionPrintArgs args;
2042 args.useDeviceAddrArgs.emplace(useDeviceAddrVars, useDeviceAddrTypes);
2043 args.useDevicePtrArgs.emplace(useDevicePtrVars, useDevicePtrTypes);
2047template <
typename ParsePrefixFn>
2056 if (failed(parsePrefix()))
2064 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
2065 iteratedVars.push_back(v);
2066 iteratedTypes.push_back(ty);
2068 plainVars.push_back(v);
2069 plainTypes.push_back(ty);
2075template <
typename Pr
intPrefixFn>
2079 PrintPrefixFn &&printPrefixForPlain,
2080 PrintPrefixFn &&printPrefixForIterated) {
2087 p << v <<
" : " << t;
2091 for (
unsigned i = 0; i < iteratedVars.size(); ++i)
2092 emit(iteratedVars[i], iteratedTypes[i], printPrefixForIterated);
2093 for (
unsigned i = 0; i < plainVars.size(); ++i)
2094 emit(plainVars[i], plainTypes[i], printPrefixForPlain);
2102 if (!reductionVars.empty()) {
2103 if (!reductionSyms || reductionSyms->size() != reductionVars.size())
2105 <<
"expected as many reduction symbol references "
2106 "as reduction variables";
2107 if (reductionByref && reductionByref->size() != reductionVars.size())
2108 return op->
emitError() <<
"expected as many reduction variable by "
2109 "reference attributes as reduction variables";
2112 return op->
emitOpError() <<
"unexpected reduction symbol references";
2119 for (
auto args : llvm::zip(reductionVars, *reductionSyms)) {
2120 Value accum = std::get<0>(args);
2122 if (!accumulators.insert(accum).second)
2123 return op->
emitOpError() <<
"accumulator variable used more than once";
2126 auto symbolRef = llvm::cast<SymbolRefAttr>(std::get<1>(args));
2130 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
2131 <<
" to point to a reduction declaration";
2133 if (decl.getAccumulatorType() && decl.getAccumulatorType() != varType)
2135 <<
"expected accumulator (" << varType
2136 <<
") to be the same type as reduction declaration ("
2137 << decl.getAccumulatorType() <<
")";
2156 if (parser.parseOperand(copyprivateVars.emplace_back()) ||
2157 parser.parseArrow() ||
2158 parser.parseAttribute(symsVec.emplace_back()) ||
2159 parser.parseColonType(copyprivateTypes.emplace_back()))
2165 copyprivateSyms = ArrayAttr::get(parser.
getContext(), syms);
2173 std::optional<ArrayAttr> copyprivateSyms) {
2174 if (!copyprivateSyms.has_value())
2176 llvm::interleaveComma(
2177 llvm::zip(copyprivateVars, *copyprivateSyms, copyprivateTypes), p,
2178 [&](
const auto &args) {
2179 p << std::get<0>(args) <<
" -> " << std::get<1>(args) <<
" : "
2180 << std::get<2>(args);
2187 std::optional<ArrayAttr> copyprivateSyms) {
2188 size_t copyprivateSymsSize =
2189 copyprivateSyms.has_value() ? copyprivateSyms->size() : 0;
2190 if (copyprivateSymsSize != copyprivateVars.size())
2191 return op->
emitOpError() <<
"inconsistent number of copyprivate vars (= "
2192 << copyprivateVars.size()
2193 <<
") and functions (= " << copyprivateSymsSize
2194 <<
"), both must be equal";
2195 if (!copyprivateSyms.has_value())
2198 for (
auto copyprivateVarAndSym :
2199 llvm::zip(copyprivateVars, *copyprivateSyms)) {
2201 llvm::cast<SymbolRefAttr>(std::get<1>(copyprivateVarAndSym));
2202 std::optional<std::variant<mlir::func::FuncOp, mlir::LLVM::LLVMFuncOp>>
2204 if (mlir::func::FuncOp mlirFuncOp =
2207 funcOp = mlirFuncOp;
2208 else if (mlir::LLVM::LLVMFuncOp llvmFuncOp =
2211 funcOp = llvmFuncOp;
2213 auto getNumArguments = [&] {
2214 return std::visit([](
auto &f) {
return f.getNumArguments(); }, *funcOp);
2217 auto getArgumentType = [&](
unsigned i) {
2218 return std::visit([i](
auto &f) {
return f.getArgumentTypes()[i]; },
2223 return op->
emitOpError() <<
"expected symbol reference " << symbolRef
2224 <<
" to point to a copy function";
2226 if (getNumArguments() != 2)
2228 <<
"expected copy function " << symbolRef <<
" to have 2 operands";
2230 Type argTy = getArgumentType(0);
2231 if (argTy != getArgumentType(1))
2232 return op->
emitOpError() <<
"expected copy function " << symbolRef
2233 <<
" arguments to have the same type";
2235 Type varType = std::get<0>(copyprivateVarAndSym).getType();
2236 if (argTy != varType)
2238 <<
"expected copy function arguments' type (" << argTy
2239 <<
") to be the same as copyprivate variable's type (" << varType
2264 OpAsmParser::UnresolvedOperand operand;
2266 if (parser.parseKeyword(&keyword) || parser.parseArrow() ||
2267 parser.parseOperand(operand) || parser.parseColonType(ty))
2269 std::optional<ClauseTaskDepend> keywordDepend =
2270 symbolizeClauseTaskDepend(keyword);
2274 ClauseTaskDependAttr::get(parser.getContext(), *keywordDepend);
2275 if (llvm::isa<mlir::omp::IteratedType>(ty)) {
2276 iteratedVars.push_back(operand);
2277 iteratedTypes.push_back(ty);
2278 iterKindsVec.push_back(kindAttr);
2280 dependVars.push_back(operand);
2281 dependTypes.push_back(ty);
2282 kindsVec.push_back(kindAttr);
2288 dependKinds = ArrayAttr::get(parser.
getContext(), kinds);
2290 iteratedKinds = ArrayAttr::get(parser.
getContext(), iterKinds);
2297 std::optional<ArrayAttr> dependKinds,
2300 std::optional<ArrayAttr> iteratedKinds) {
2303 std::optional<ArrayAttr> kinds) {
2304 for (
unsigned i = 0, e = vars.size(); i < e; ++i) {
2307 p << stringifyClauseTaskDepend(
2308 llvm::cast<mlir::omp::ClauseTaskDependAttr>((*kinds)[i])
2310 <<
" -> " << vars[i] <<
" : " << types[i];
2314 printEntries(dependVars, dependTypes, dependKinds);
2315 printEntries(iteratedVars, iteratedTypes, iteratedKinds);
2320 std::optional<ArrayAttr> dependKinds,
2322 std::optional<ArrayAttr> iteratedKinds,
2324 if (!dependVars.empty()) {
2325 if (!dependKinds || dependKinds->size() != dependVars.size())
2326 return op->
emitOpError() <<
"expected as many depend values"
2327 " as depend variables";
2329 if (dependKinds && !dependKinds->empty())
2330 return op->
emitOpError() <<
"unexpected depend values";
2333 if (!iteratedVars.empty()) {
2334 if (!iteratedKinds || iteratedKinds->size() != iteratedVars.size())
2335 return op->
emitOpError() <<
"expected as many depend iterated values"
2336 " as depend iterated variables";
2338 if (iteratedKinds && !iteratedKinds->empty())
2339 return op->
emitOpError() <<
"unexpected depend iterated values";
2354 IntegerAttr &hintAttr) {
2355 StringRef hintKeyword;
2361 auto parseKeyword = [&]() -> ParseResult {
2364 if (hintKeyword ==
"uncontended")
2366 else if (hintKeyword ==
"contended")
2368 else if (hintKeyword ==
"nonspeculative")
2370 else if (hintKeyword ==
"speculative")
2374 << hintKeyword <<
" is not a valid hint";
2385 IntegerAttr hintAttr) {
2386 int64_t hint = hintAttr.getInt();
2394 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2396 bool uncontended = bitn(hint, 0);
2397 bool contended = bitn(hint, 1);
2398 bool nonspeculative = bitn(hint, 2);
2399 bool speculative = bitn(hint, 3);
2403 hints.push_back(
"uncontended");
2405 hints.push_back(
"contended");
2407 hints.push_back(
"nonspeculative");
2409 hints.push_back(
"speculative");
2411 llvm::interleaveComma(hints, p);
2418 auto bitn = [](
int value,
int n) ->
bool {
return value & (1 << n); };
2420 bool uncontended = bitn(hint, 0);
2421 bool contended = bitn(hint, 1);
2422 bool nonspeculative = bitn(hint, 2);
2423 bool speculative = bitn(hint, 3);
2425 if (uncontended && contended)
2426 return op->
emitOpError() <<
"the hints omp_sync_hint_uncontended and "
2427 "omp_sync_hint_contended cannot be combined";
2428 if (nonspeculative && speculative)
2429 return op->
emitOpError() <<
"the hints omp_sync_hint_nonspeculative and "
2430 "omp_sync_hint_speculative cannot be combined.";
2441 return (value & flag) == flag;
2449static ParseResult parseMapClause(
OpAsmParser &parser,
2450 ClauseMapFlagsAttr &mapType) {
2451 ClauseMapFlags mapTypeBits = ClauseMapFlags::none;
2454 auto parseTypeAndMod = [&]() -> ParseResult {
2455 StringRef mapTypeMod;
2459 if (mapTypeMod ==
"always")
2460 mapTypeBits |= ClauseMapFlags::always;
2462 if (mapTypeMod ==
"implicit")
2463 mapTypeBits |= ClauseMapFlags::implicit;
2465 if (mapTypeMod ==
"ompx_hold")
2466 mapTypeBits |= ClauseMapFlags::ompx_hold;
2468 if (mapTypeMod ==
"close")
2469 mapTypeBits |= ClauseMapFlags::close;
2471 if (mapTypeMod ==
"present")
2472 mapTypeBits |= ClauseMapFlags::present;
2474 if (mapTypeMod ==
"to")
2475 mapTypeBits |= ClauseMapFlags::to;
2477 if (mapTypeMod ==
"from")
2478 mapTypeBits |= ClauseMapFlags::from;
2480 if (mapTypeMod ==
"tofrom")
2481 mapTypeBits |= ClauseMapFlags::to | ClauseMapFlags::from;
2483 if (mapTypeMod ==
"delete")
2484 mapTypeBits |= ClauseMapFlags::del;
2486 if (mapTypeMod ==
"storage")
2487 mapTypeBits |= ClauseMapFlags::storage;
2489 if (mapTypeMod ==
"return_param")
2490 mapTypeBits |= ClauseMapFlags::return_param;
2492 if (mapTypeMod ==
"private")
2493 mapTypeBits |= ClauseMapFlags::priv;
2495 if (mapTypeMod ==
"literal")
2496 mapTypeBits |= ClauseMapFlags::literal;
2498 if (mapTypeMod ==
"attach")
2499 mapTypeBits |= ClauseMapFlags::attach;
2501 if (mapTypeMod ==
"attach_always")
2502 mapTypeBits |= ClauseMapFlags::attach_always;
2504 if (mapTypeMod ==
"attach_never")
2505 mapTypeBits |= ClauseMapFlags::attach_never;
2507 if (mapTypeMod ==
"attach_auto")
2508 mapTypeBits |= ClauseMapFlags::attach_auto;
2510 if (mapTypeMod ==
"ref_ptr")
2511 mapTypeBits |= ClauseMapFlags::ref_ptr;
2513 if (mapTypeMod ==
"ref_ptee")
2514 mapTypeBits |= ClauseMapFlags::ref_ptee;
2516 if (mapTypeMod ==
"is_device_ptr")
2517 mapTypeBits |= ClauseMapFlags::is_device_ptr;
2519 if (mapTypeMod ==
"target_param")
2520 mapTypeBits |= ClauseMapFlags::target_param;
2537 ClauseMapFlagsAttr mapType) {
2539 ClauseMapFlags mapFlags = mapType.getValue();
2544 mapTypeStrs.push_back(
"always");
2546 mapTypeStrs.push_back(
"implicit");
2548 mapTypeStrs.push_back(
"ompx_hold");
2550 mapTypeStrs.push_back(
"close");
2552 mapTypeStrs.push_back(
"present");
2554 mapTypeStrs.push_back(
"target_param");
2563 mapTypeStrs.push_back(
"tofrom");
2565 mapTypeStrs.push_back(
"from");
2567 mapTypeStrs.push_back(
"to");
2570 mapTypeStrs.push_back(
"delete");
2572 mapTypeStrs.push_back(
"return_param");
2574 mapTypeStrs.push_back(
"storage");
2576 mapTypeStrs.push_back(
"private");
2578 mapTypeStrs.push_back(
"literal");
2580 mapTypeStrs.push_back(
"attach");
2582 mapTypeStrs.push_back(
"attach_always");
2584 mapTypeStrs.push_back(
"attach_never");
2586 mapTypeStrs.push_back(
"attach_auto");
2588 mapTypeStrs.push_back(
"ref_ptr");
2590 mapTypeStrs.push_back(
"ref_ptee");
2592 mapTypeStrs.push_back(
"is_device_ptr");
2593 if (mapFlags == ClauseMapFlags::none)
2594 mapTypeStrs.push_back(
"none");
2596 for (
unsigned int i = 0; i < mapTypeStrs.size(); ++i) {
2597 p << mapTypeStrs[i];
2598 if (i + 1 < mapTypeStrs.size()) {
2604static ParseResult parseMembersIndex(
OpAsmParser &parser,
2608 auto parseIndices = [&]() -> ParseResult {
2613 APInt(64, value,
false)));
2627 memberIdxs.push_back(ArrayAttr::get(parser.
getContext(), values));
2631 if (!memberIdxs.empty())
2632 membersIdx = ArrayAttr::get(parser.
getContext(), memberIdxs);
2642 llvm::interleaveComma(membersIdx, p, [&p](
Attribute v) {
2644 auto memberIdx = cast<ArrayAttr>(v);
2645 llvm::interleaveComma(memberIdx.getValue(), p, [&p](
Attribute v2) {
2646 p << cast<IntegerAttr>(v2).getInt();
2653 VariableCaptureKindAttr mapCaptureType) {
2654 std::string typeCapStr;
2655 llvm::raw_string_ostream typeCap(typeCapStr);
2656 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByRef)
2658 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::ByCopy)
2659 typeCap <<
"ByCopy";
2660 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::VLAType)
2661 typeCap <<
"VLAType";
2662 if (mapCaptureType.getValue() == mlir::omp::VariableCaptureKind::This)
2668 VariableCaptureKindAttr &mapCaptureType) {
2669 StringRef mapCaptureKey;
2673 if (mapCaptureKey ==
"This")
2674 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2675 parser.
getContext(), mlir::omp::VariableCaptureKind::This);
2676 if (mapCaptureKey ==
"ByRef")
2677 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2678 parser.
getContext(), mlir::omp::VariableCaptureKind::ByRef);
2679 if (mapCaptureKey ==
"ByCopy")
2680 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2681 parser.
getContext(), mlir::omp::VariableCaptureKind::ByCopy);
2682 if (mapCaptureKey ==
"VLAType")
2683 mapCaptureType = mlir::omp::VariableCaptureKindAttr::get(
2684 parser.
getContext(), mlir::omp::VariableCaptureKind::VLAType);
2690 Operation *op, mlir::omp::MapInfoOp mapInfoOp,
2694 mlir::omp::ClauseMapFlags mapTypeBits = mapInfoOp.getMapType();
2697 bool from =
mapTypeToBool(mapTypeBits, ClauseMapFlags::from);
2700 bool always =
mapTypeToBool(mapTypeBits, ClauseMapFlags::always);
2701 bool close =
mapTypeToBool(mapTypeBits, ClauseMapFlags::close);
2702 bool implicit =
mapTypeToBool(mapTypeBits, ClauseMapFlags::implicit);
2703 bool attach =
mapTypeToBool(mapTypeBits, ClauseMapFlags::attach);
2705 if ((isa<TargetDataOp>(op) || isa<TargetOp>(op)) && del)
2707 "to, from, tofrom and alloc map types are permitted");
2709 if (isa<TargetEnterDataOp>(op) && (from || del))
2710 return emitError(op->
getLoc(),
"to and alloc map types are permitted");
2712 if (isa<TargetExitDataOp>(op) && to)
2714 "from, release and delete map types are permitted");
2716 if (isa<TargetUpdateOp>(op)) {
2719 "at least one of to or from map types must be "
2720 "specified, other map types are not permitted");
2723 if (!to && !from && !attach) {
2725 "at least one of to or from or attach map types must be "
2726 "specified, other map types are not permitted");
2729 auto updateVar = mapInfoOp.getVarPtr();
2731 if ((to && from) || (to && updateFromVars.contains(updateVar)) ||
2732 (from && updateToVars.contains(updateVar))) {
2735 "either to or from map types can be specified, not both");
2738 if (always || close || implicit) {
2741 "present, mapper and iterator map type modifiers are permitted");
2747 to ? updateToVars.insert(updateVar) : updateFromVars.insert(updateVar);
2751 if ((mapInfoOp.getVarPtrPtr() && !mapInfoOp.getVarPtrPtrType()) ||
2752 (!mapInfoOp.getVarPtrPtr() && mapInfoOp.getVarPtrPtrType())) {
2754 "if varPtrPtr or varPtrPtrType is specified, then both "
2766 for (
auto mapOp : mapVars) {
2767 if (!mapOp.getDefiningOp())
2770 if (
auto mapInfoOp = mapOp.getDefiningOp<mlir::omp::MapInfoOp>()) {
2774 }
else if (!isa<DeclareMapperInfoOp>(op)) {
2776 "map argument is not a map entry operation");
2781 for (
auto iterVal : mapIterated) {
2782 auto iterOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
2784 return op->
emitOpError() <<
"'map_iterated' arguments must be defined by "
2785 "'omp.iterator' ops";
2788 mlir::omp::YieldOp yieldOp = iterOp.getYieldOp();
2789 auto yieldedMapInfo =
2790 yieldOp && yieldOp.getNumOperands() == 1
2791 ? yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>()
2793 if (!yieldedMapInfo)
2794 return op->
emitOpError() <<
"'map_iterated' iterator body must yield "
2795 "a value defined by 'omp.map.info'";
2805template <
typename OpType>
2809 std::optional<DenseI64ArrayAttr> privateMapIndices =
2810 targetOp.getPrivateMapsAttr();
2813 if (!privateMapIndices.has_value() || !privateMapIndices.value())
2818 if (privateMapIndices.value().size() !=
2819 static_cast<int64_t>(privateVars.size()))
2820 return emitError(targetOp.getLoc(),
"sizes of `private` operand range and "
2821 "`private_maps` attribute mismatch");
2831 StringRef clauseName,
2833 for (
Value var : vars)
2834 if (!llvm::isa_and_present<MapInfoOp>(var.getDefiningOp()))
2836 <<
"'" << clauseName
2837 <<
"' arguments must be defined by 'omp.map.info' ops";
2841LogicalResult MapInfoOp::verify() {
2842 if (getMapperId() &&
2844 *
this, getMapperIdAttr())) {
2859 const TargetDataOperands &clauses) {
2860 TargetDataOp::build(builder, state, clauses.device, clauses.ifExpr,
2861 clauses.mapVars, clauses.mapIterated,
2862 clauses.useDeviceAddrVars, clauses.useDevicePtrVars);
2865LogicalResult TargetDataOp::verify() {
2866 if (getMapVars().empty() && getMapIterated().empty() &&
2867 getUseDevicePtrVars().empty() && getUseDeviceAddrVars().empty()) {
2868 return ::emitError(this->getLoc(),
2869 "At least one of map, use_device_ptr_vars, or "
2870 "use_device_addr_vars operand must be present");
2874 getUseDevicePtrVars())))
2878 getUseDeviceAddrVars())))
2888void TargetEnterDataOp::build(
2892 TargetEnterDataOp::build(
2894 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2895 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2896 clauses.mapIterated, clauses.nowait);
2899LogicalResult TargetEnterDataOp::verify() {
2900 LogicalResult verifyDependVars =
2902 getDependIteratedKinds(), getDependIterated());
2903 return failed(verifyDependVars)
2915 TargetExitDataOp::build(
2917 clauses.dependVars,
makeArrayAttr(ctx, clauses.dependIteratedKinds),
2918 clauses.dependIterated, clauses.device, clauses.ifExpr, clauses.mapVars,
2919 clauses.mapIterated, clauses.nowait);
2922LogicalResult TargetExitDataOp::verify() {
2923 LogicalResult verifyDependVars =
2925 getDependIteratedKinds(), getDependIterated());
2926 return failed(verifyDependVars)
2938 TargetUpdateOp::build(builder, state,
makeArrayAttr(ctx, clauses.dependKinds),
2941 clauses.dependIterated, clauses.device, clauses.ifExpr,
2942 clauses.mapVars, clauses.mapIterated, clauses.nowait);
2945LogicalResult TargetUpdateOp::verify() {
2946 LogicalResult verifyDependVars =
2948 getDependIteratedKinds(), getDependIterated());
2949 return failed(verifyDependVars)
2962 builder, state, clauses.allocateVars, clauses.allocatorVars,
2965 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
2966 makeArrayAttr(ctx, clauses.dependIteratedKinds), clauses.dependIterated,
2967 clauses.device, clauses.dynGroupprivateAccessGroup,
2968 clauses.dynGroupprivateFallback, clauses.dynGroupprivateSize,
2969 clauses.hasDeviceAddrVars, clauses.hostEvalVars, clauses.ifExpr,
2970 clauses.inReductionVars,
2972 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.isDevicePtrVars,
2973 clauses.mapVars, clauses.mapIterated, clauses.nowait, clauses.privateVars,
2974 makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
2975 clauses.threadLimitVars,
nullptr, clauses.
kernelType);
2978bool TargetOp::hasHostEvalTripCount() {
2979 TargetExecMode mode = getKernelType();
2980 if (mode == TargetExecMode::spmd || mode == TargetExecMode::spmd_no_loop)
2983 if (mode == TargetExecMode::bare)
2989 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
2990 if (
auto loopNestOp = dyn_cast_if_present<LoopNestOp>(capturedOp)) {
2992 loopNestOp.gatherWrappers(loopWrappers);
2994 LoopWrapperInterface *innermostWrapper = loopWrappers.begin();
2995 if (isa<SimdOp>(innermostWrapper))
2996 innermostWrapper = std::next(innermostWrapper);
2998 auto numWrappers = std::distance(innermostWrapper, loopWrappers.end());
2999 if (numWrappers != 1)
3002 if (!isa<DistributeOp>(innermostWrapper))
3006 if (isa_and_present<TeamsOp>(parentOp) &&
3022 if (mapVarPtr == inReductionVar)
3028LogicalResult TargetOp::verify() {
3030 getOperation(), getAllocateVars(), getAllocatorVars(),
3031 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3032 getPrivateVars(), getPrivateSymsAttr())))
3035 if (getKernelType() == TargetExecMode::bare && !isCombined())
3036 return emitOpError() <<
"bare kernel requires 'omp.combined'";
3039 getDependIteratedKinds(),
3040 getDependIterated())))
3044 getHasDeviceAddrVars())))
3051 *
this, getDynGroupprivateAccessGroupAttr(),
3052 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3059 getInReductionVars(),
3060 getInReductionByref())))
3068 for (
Value inReductionVar : getInReductionVars()) {
3069 bool captured =
false;
3070 for (
Value mapVar : getMapVars()) {
3071 auto mapInfo = mapVar.getDefiningOp<MapInfoOp>();
3078 return emitOpError() <<
"in_reduction variable must be captured by a "
3079 "matching map_entries entry";
3085LogicalResult TargetOp::verifyRegions() {
3086 auto teamsOps = getOps<TeamsOp>();
3087 auto numNestedTeams = std::distance(teamsOps.begin(), teamsOps.end());
3088 if (numNestedTeams > 1)
3089 return emitError(
"target containing multiple 'omp.teams' nested ops");
3091 if (numNestedTeams == 0) {
3092 switch (getKernelType()) {
3093 case TargetExecMode::bare:
3094 return emitOpError()
3095 <<
"bare kernel must contain a nested 'omp.teams' operation";
3096 case TargetExecMode::spmd_no_loop:
3097 return emitOpError() <<
"spmd_no_loop kernel must contain a nested "
3098 "'omp.teams' operation";
3105 cast<ComposableOpInterface>(getOperation()).findCapturedOp();
3106 if ((getKernelType() == TargetExecMode::spmd ||
3107 getKernelType() == TargetExecMode::spmd_no_loop) &&
3108 !isa_and_present<LoopNestOp>(capturedOp))
3109 return emitOpError()
3110 <<
"SPMD kernel must capture an 'omp.loop_nest' operation";
3112 bool isTargetDevice =
false;
3113 if (
auto offloadMod = (*this)->getParentOfType<OffloadModuleInterface>())
3114 if (offloadMod.getIsTargetDevice())
3115 isTargetDevice =
true;
3119 cast<BlockArgOpenMPOpInterface>(getOperation()).getHostEvalBlockArgs();
3121 bool hostEvalTripCount = hasHostEvalTripCount();
3122 for (
Value hostEvalArg : hostEvalBlockArgs) {
3124 if (
auto teamsOp = dyn_cast<TeamsOp>(user)) {
3126 if (hostEvalArg == teamsOp.getNumTeamsLower() ||
3127 llvm::is_contained(teamsOp.getNumTeamsUpperVars(), hostEvalArg) ||
3128 llvm::is_contained(teamsOp.getThreadLimitVars(), hostEvalArg))
3131 return emitOpError() <<
"host_eval argument only legal as 'num_teams' "
3132 "and 'thread_limit' in 'omp.teams'";
3134 if (
auto parallelOp = dyn_cast<ParallelOp>(user)) {
3135 if (llvm::is_contained(parallelOp.getNumThreadsVars(), hostEvalArg))
3138 return emitOpError()
3139 <<
"host_eval argument only legal as 'num_threads' in "
3142 if (
auto loopNestOp = dyn_cast<LoopNestOp>(user)) {
3143 if (hostEvalTripCount &&
3144 (llvm::is_contained(loopNestOp.getLoopLowerBounds(), hostEvalArg) ||
3145 llvm::is_contained(loopNestOp.getLoopUpperBounds(), hostEvalArg) ||
3146 llvm::is_contained(loopNestOp.getLoopSteps(), hostEvalArg)))
3149 return emitOpError() <<
"host_eval argument only legal as loop bounds "
3150 "and steps in 'omp.loop_nest' when trip count "
3151 "must be evaluated in the host";
3154 return emitOpError() <<
"host_eval argument illegal use in '"
3155 << user->getName() <<
"' operation";
3159 if (hostEvalTripCount && !isTargetDevice) {
3160 auto loopOp = cast<LoopNestOp>(capturedOp);
3161 for (
auto arg : llvm::concat<Value>(loopOp.getLoopLowerBounds(),
3162 loopOp.getLoopUpperBounds(),
3163 loopOp.getLoopSteps())) {
3164 if (!llvm::is_contained(hostEvalBlockArgs, arg))
3165 return emitOpError() <<
"nested 'omp.loop_nest' bounds expected to "
3166 "be host-evaluated";
3179 ParallelOp::build(builder, state,
ValueRange(),
3193 const ParallelOperands &clauses) {
3195 ParallelOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3198 clauses.ifExpr, clauses.numThreadsVars, clauses.privateVars,
3200 clauses.privateNeedsBarrier, clauses.procBindKind,
3201 clauses.reductionMod, clauses.reductionVars,
3206template <
typename OpType>
3208 auto privateVars = op.getPrivateVars();
3209 auto privateSyms = op.getPrivateSymsAttr();
3211 if (privateVars.empty() && (privateSyms ==
nullptr || privateSyms.empty()))
3214 auto numPrivateVars = privateVars.size();
3215 auto numPrivateSyms = (privateSyms ==
nullptr) ? 0 : privateSyms.size();
3217 if (numPrivateVars != numPrivateSyms)
3218 return op.emitError() <<
"inconsistent number of private variables and "
3219 "privatizer op symbols, private vars: "
3221 <<
" vs. privatizer op symbols: " << numPrivateSyms;
3223 for (
auto privateVarInfo : llvm::zip_equal(privateVars, privateSyms)) {
3224 Type varType = std::get<0>(privateVarInfo).getType();
3225 SymbolRefAttr privateSym = cast<SymbolRefAttr>(std::get<1>(privateVarInfo));
3226 PrivateClauseOp privatizerOp =
3229 if (privatizerOp ==
nullptr)
3230 return op.emitError() <<
"failed to lookup privatizer op with symbol: '"
3231 << privateSym <<
"'";
3233 Type privatizerType = privatizerOp.getArgType();
3235 if (privatizerType && (varType != privatizerType))
3236 return op.emitError()
3237 <<
"type mismatch between a "
3238 << stringifyDataSharingClauseType(
3239 privatizerOp.getDataSharingType())
3240 <<
" variable and its privatizer op, var type: " << varType
3241 <<
" vs. privatizer op type: " << privatizerType;
3243 if (privatizerOp.getDataSharingType() == DataSharingClauseType::Linear)
3244 return op.emitError() <<
"`linear` privatizer '" << privateSym
3245 <<
"' can only be used in a `linear` clause";
3252template <
typename OpType>
3255 std::optional<ArrayAttr> linearSyms = op.getLinearSyms();
3256 if (linearVars.empty() && (!linearSyms || linearSyms->empty()))
3259 if (!linearSyms || linearSyms->size() != linearVars.size())
3260 return op.emitOpError()
3261 <<
"expected as many linear privatizers as linear variables";
3263 for (
auto [var, sym] : llvm::zip_equal(linearVars, *linearSyms)) {
3264 auto symRef = cast<SymbolRefAttr>(sym);
3268 return op.emitOpError() <<
"failed to lookup privatizer op with symbol: '"
3270 if (privatizer.getDataSharingType() != DataSharingClauseType::Linear)
3271 return op.emitOpError() <<
"privatizer '" << symRef
3272 <<
"' of a linear variable must be `linear`";
3273 Type argType = privatizer.getArgType();
3274 if (argType && argType != var.getType())
3275 return op.emitOpError()
3276 <<
"type mismatch between a linear variable and its privatizer "
3278 << var.getType() <<
" vs. privatizer op type: " << argType;
3283LogicalResult ParallelOp::verify() {
3287 getOperation(), getAllocateVars(), getAllocatorVars(),
3288 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3289 getPrivateVars(), getPrivateSymsAttr(),
3294 getReductionByref());
3297LogicalResult ParallelOp::verifyRegions() {
3298 auto distChildOps = getOps<DistributeOp>();
3299 int numDistChildOps = std::distance(distChildOps.begin(), distChildOps.end());
3300 if (numDistChildOps > 1)
3302 <<
"multiple 'omp.distribute' nested inside of 'omp.parallel'";
3304 if (numDistChildOps == 1) {
3307 <<
"'omp.composite' attribute missing from composite operation";
3309 auto *ompDialect =
getContext()->getLoadedDialect<OpenMPDialect>();
3310 Operation &distributeOp = **distChildOps.begin();
3312 if (&childOp == &distributeOp || ompDialect != childOp.getDialect())
3316 return emitError() <<
"unexpected OpenMP operation inside of composite "
3318 << childOp.getName();
3320 }
else if (isComposite()) {
3322 <<
"'omp.composite' attribute present in non-composite operation";
3339 const TeamsOperands &clauses) {
3343 builder, state, clauses.allocateVars, clauses.allocatorVars,
3346 clauses.dynGroupprivateAccessGroup, clauses.dynGroupprivateFallback,
3347 clauses.dynGroupprivateSize, clauses.ifExpr, clauses.numTeamsLower,
3348 clauses.numTeamsUpperVars, {},
nullptr,
3349 false, clauses.reductionMod,
3350 clauses.reductionVars,
3352 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadLimitVars);
3359 if (numTeamsLower) {
3360 if (numTeamsUpperVars.size() != 1)
3362 "expected exactly one num_teams upper bound when lower bound is "
3366 "expected num_teams upper bound and lower bound to be "
3373LogicalResult TeamsOp::verify() {
3380 auto parentTarget = llvm::dyn_cast_if_present<TargetOp>(op->
getParentOp());
3382 return emitError(
"expected to be nested inside of omp.target or not nested "
3383 "in any OpenMP dialect operations");
3387 this->getNumTeamsUpperVars())))
3391 parentTarget.getKernelType() == TargetExecMode::spmd_no_loop &&
3392 (getNumTeamsLower() || !getNumTeamsUpperVars().empty()))
3393 return emitOpError() <<
"'num_teams' not allowed in SPMD-no-loop kernels";
3396 getOperation(), getAllocateVars(), getAllocatorVars(),
3397 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3398 getPrivateVars(), getPrivateSymsAttr())))
3402 op, getDynGroupprivateAccessGroupAttr(),
3403 getDynGroupprivateFallbackAttr(), getDynGroupprivateSize())))
3410 getReductionByref());
3418 return getParentOp().getPrivateVars();
3422 return getParentOp().getReductionVars();
3430 const SectionsOperands &clauses) {
3433 SectionsOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3438 clauses.reductionMod, clauses.reductionVars,
3443LogicalResult SectionsOp::verify() {
3445 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3448 getOperation(), getAllocateVars(), getAllocatorVars(),
3449 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3450 getPrivateVars(), getPrivateSymsAttr())))
3454 getReductionByref());
3457LogicalResult SectionsOp::verifyRegions() {
3458 for (
auto &inst : *getRegion().begin()) {
3459 if (!(isa<SectionOp>(inst) || isa<TerminatorOp>(inst))) {
3460 return emitOpError()
3461 <<
"expected omp.section op or terminator op inside region";
3473 const ScopeOperands &clauses) {
3475 ScopeOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3478 clauses.nowait, clauses.privateVars,
3480 clauses.privateNeedsBarrier, clauses.reductionMod,
3481 clauses.reductionVars,
3486LogicalResult ScopeOp::verify() {
3488 getOperation(), getAllocateVars(), getAllocatorVars(),
3489 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3490 getPrivateVars(), getPrivateSymsAttr(),
3498 getReductionByref());
3506 const SingleOperands &clauses) {
3509 SingleOp::build(builder, state, clauses.allocateVars, clauses.allocatorVars,
3512 clauses.copyprivateVars,
3513 makeArrayAttr(ctx, clauses.copyprivateSyms), clauses.nowait,
3518LogicalResult SingleOp::verify() {
3520 getOperation(), getAllocateVars(), getAllocatorVars(),
3521 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3522 getPrivateVars(), getPrivateSymsAttr())))
3526 getCopyprivateSyms());
3534 const WorkshareOperands &clauses) {
3535 WorkshareOp::build(builder, state, clauses.nowait);
3538LogicalResult WorkshareOp::verify() {
3540 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
3549LogicalResult WorkshareLoopWrapperOp::verifyRegions() {
3550 if (isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3552 return emitOpError() <<
"expected to be a standalone loop wrapper";
3561LogicalResult LoopWrapperInterface::verifyImpl() {
3565 return emitOpError() <<
"loop wrapper must also have the `NoTerminator` "
3566 "and `SingleBlock` traits";
3569 return emitOpError() <<
"loop wrapper does not contain exactly one region";
3572 if (range_size(region.
getOps()) != 1)
3573 return emitOpError()
3574 <<
"loop wrapper does not contain exactly one nested op";
3577 if (!isa<LoopNestOp, LoopWrapperInterface>(firstOp))
3578 return emitOpError() <<
"nested in loop wrapper is not another loop "
3579 "wrapper or `omp.loop_nest`";
3588Operation *ComposableOpInterface::findCapturedOp() {
3592 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(op))
3593 return wrapperOp.getWrappedLoop();
3598 if (!isCombined() && !isComposite())
3603 if (
auto wrapperOp = dyn_cast<LoopWrapperInterface>(&nestedOp))
3604 return wrapperOp.getWrappedLoop();
3606 if (
auto composableOp = dyn_cast<ComposableOpInterface>(&nestedOp))
3607 return composableOp.findCapturedOp();
3616LogicalResult ComposableOpInterface::verifyImpl() {
3620 return emitOpError() <<
"composable ops must have a single region";
3622 if (isComposite() && !isa<LoopWrapperInterface, ParallelOp>(op))
3623 return emitOpError() <<
"non-loop wrapper cannot be composite";
3629 auto count = llvm::count_if(
3631 if (isa<ComposableOpInterface, LoopWrapperInterface>(op)) {
3652 return emitOpError()
3653 <<
"multiple eligible child ops found in combined op";
3664 if (successor->isReachable(parentBlock))
3665 return emitOpError() <<
"nested combined child op is part of a loop";
3669 !domInfo.
dominates(parentBlock, &block))
3670 return emitOpError()
3671 <<
"nested combined child op doesn't unconditionally execute";
3681 const LoopOperands &clauses) {
3684 LoopOp::build(builder, state, clauses.bindKind, clauses.privateVars,
3686 clauses.privateNeedsBarrier, clauses.order, clauses.orderMod,
3687 clauses.reductionMod, clauses.reductionVars,
3692LogicalResult LoopOp::verify() {
3697 getReductionByref());
3700LogicalResult LoopOp::verifyRegions() {
3701 if (llvm::isa_and_nonnull<LoopWrapperInterface>((*this)->getParentOp()) ||
3703 return emitOpError() <<
"expected to be a standalone loop wrapper";
3714 build(builder, state, {}, {},
3719 nullptr,
false,
nullptr,
3721 nullptr, {},
nullptr,
3732 const WsloopOperands &clauses) {
3735 builder, state, clauses.allocateVars, clauses.allocatorVars,
3738 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
3739 clauses.linearModifiers,
makeArrayAttr(ctx, clauses.linearSyms),
3740 clauses.nowait, clauses.order, clauses.orderMod, clauses.ordered,
3741 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3742 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3744 makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
3745 clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
3748LogicalResult WsloopOp::verify() {
3750 getOperation(), getAllocateVars(), getAllocatorVars(),
3751 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3752 getPrivateVars(), getPrivateSymsAttr())))
3758 if (getLinearVars().size() &&
3759 getLinearVarTypes().value().size() != getLinearVars().size())
3760 return emitError() <<
"Ill-formed type attributes for linear variables";
3766 getReductionByref());
3769LogicalResult WsloopOp::verifyRegions() {
3770 bool isCompositeChildLeaf =
3771 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3773 if (LoopWrapperInterface nested = getNestedWrapper()) {
3776 <<
"'omp.composite' attribute missing from composite wrapper";
3780 if (!isa<SimdOp>(nested))
3781 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
3783 }
else if (isComposite() && !isCompositeChildLeaf) {
3785 <<
"'omp.composite' attribute present in non-composite wrapper";
3786 }
else if (!isComposite() && isCompositeChildLeaf) {
3788 <<
"'omp.composite' attribute missing from composite wrapper";
3799 const SimdOperands &clauses) {
3802 builder, state, clauses.alignedVars,
3804 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
3805 clauses.linearModifiers,
makeArrayAttr(ctx, clauses.linearSyms),
3806 clauses.nontemporalVars, clauses.order, clauses.orderMod,
3807 clauses.privateVars,
makeArrayAttr(ctx, clauses.privateSyms),
3808 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
3814LogicalResult SimdOp::verify() {
3815 if (getSimdlen().has_value() && getSafelen().has_value() &&
3816 getSimdlen().value() > getSafelen().value())
3817 return emitOpError()
3818 <<
"simdlen clause and safelen clause are both present, but the "
3819 "simdlen value is not less than or equal to safelen value";
3831 bool isCompositeChildLeaf =
3832 llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
3834 if (!isComposite() && isCompositeChildLeaf)
3836 <<
"'omp.composite' attribute missing from composite wrapper";
3838 if (isComposite() && !isCompositeChildLeaf)
3840 <<
"'omp.composite' attribute present in non-composite wrapper";
3844 std::optional<ArrayAttr> privateSyms = getPrivateSyms();
3846 for (
const Attribute &sym : *privateSyms) {
3847 auto symRef = cast<SymbolRefAttr>(sym);
3848 omp::PrivateClauseOp privatizer =
3850 getOperation(), symRef);
3852 return emitError() <<
"Cannot find privatizer '" << symRef <<
"'";
3853 if (privatizer.getDataSharingType() ==
3854 DataSharingClauseType::FirstPrivate)
3855 return emitError() <<
"FIRSTPRIVATE cannot be used with SIMD";
3862 if (getLinearVars().size() &&
3863 getLinearVarTypes().value().size() != getLinearVars().size())
3864 return emitError() <<
"Ill-formed type attributes for linear variables";
3872 for (
Value var : getLinearVars()) {
3873 if (privateVars.contains(var) || reductionVars.contains(var))
3874 return emitOpError()
3875 <<
"linear variables cannot appear in other data-sharing clauses";
3881LogicalResult SimdOp::verifyRegions() {
3882 if (getNestedWrapper())
3883 return emitOpError() <<
"must wrap an 'omp.loop_nest' directly";
3893 const DistributeOperands &clauses) {
3894 DistributeOp::build(
3895 builder, state, clauses.allocateVars, clauses.allocatorVars,
3898 clauses.allocatePrivateIndices),
3899 clauses.distScheduleStatic, clauses.distScheduleChunkSize, clauses.order,
3900 clauses.orderMod, clauses.privateVars,
3902 clauses.privateNeedsBarrier);
3905LogicalResult DistributeOp::verify() {
3906 if (this->getDistScheduleChunkSize() && !this->getDistScheduleStatic())
3907 return emitOpError() <<
"chunk size set without "
3908 "dist_schedule_static being present";
3911 getOperation(), getAllocateVars(), getAllocatorVars(),
3912 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
3913 getPrivateVars(), getPrivateSymsAttr())))
3922LogicalResult DistributeOp::verifyRegions() {
3923 if (LoopWrapperInterface nested = getNestedWrapper()) {
3926 <<
"'omp.composite' attribute missing from composite wrapper";
3929 if (isa<WsloopOp>(nested)) {
3931 if (!llvm::dyn_cast_if_present<ParallelOp>(parentOp) ||
3932 !cast<ComposableOpInterface>(parentOp).isComposite()) {
3933 return emitError() <<
"an 'omp.wsloop' nested wrapper is only allowed "
3934 "when a composite 'omp.parallel' is the direct "
3937 }
else if (!isa<SimdOp>(nested))
3938 return emitError() <<
"only supported nested wrappers are 'omp.simd' and "
3940 }
else if (isComposite()) {
3942 <<
"'omp.composite' attribute present in non-composite wrapper";
3953 const DeclareMapperInfoOperands &clauses) {
3954 DeclareMapperInfoOp::build(builder, state, clauses.mapVars,
3955 clauses.mapIterated);
3958LogicalResult DeclareMapperInfoOp::verify() {
3962LogicalResult DeclareMapperOp::verifyRegions() {
3963 if (!llvm::isa_and_present<DeclareMapperInfoOp>(
3964 getRegion().getBlocks().front().getTerminator()))
3965 return emitOpError() <<
"expected terminator to be a DeclareMapperInfoOp";
3974LogicalResult DeclareReductionOp::verifyRegions() {
3975 if (!getAllocRegion().empty()) {
3976 for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {
3977 if (yieldOp.getResults().size() != 1 ||
3978 yieldOp.getResults().getTypes()[0] !=
getType())
3979 return emitOpError() <<
"expects alloc region to yield a value "
3980 "of the reduction type";
3984 if (getInitializerRegion().empty())
3985 return emitOpError() <<
"expects non-empty initializer region";
3986 Block &initializerEntryBlock = getInitializerRegion().
front();
3989 if (!getAllocRegion().empty())
3990 return emitOpError() <<
"expects two arguments to the initializer region "
3991 "when an allocation region is used";
3993 if (getAllocRegion().empty())
3994 return emitOpError() <<
"expects one argument to the initializer region "
3995 "when no allocation region is used";
3997 return emitOpError()
3998 <<
"expects one or two arguments to the initializer region";
4002 if (arg.getType() !=
getType())
4003 return emitOpError() <<
"expects initializer region argument to match "
4004 "the reduction type";
4006 for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {
4007 if (yieldOp.getResults().size() != 1 ||
4008 yieldOp.getResults().getTypes()[0] !=
getType())
4009 return emitOpError() <<
"expects initializer region to yield a value "
4010 "of the reduction type";
4013 if (getReductionRegion().empty())
4014 return emitOpError() <<
"expects non-empty reduction region";
4015 Block &reductionEntryBlock = getReductionRegion().
front();
4020 return emitOpError() <<
"expects reduction region with two arguments of "
4021 "the reduction type";
4022 for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {
4023 if (yieldOp.getResults().size() != 1 ||
4024 yieldOp.getResults().getTypes()[0] !=
getType())
4025 return emitOpError() <<
"expects reduction region to yield a value "
4026 "of the reduction type";
4029 if (!getAtomicReductionRegion().empty()) {
4030 Block &atomicReductionEntryBlock = getAtomicReductionRegion().
front();
4034 return emitOpError() <<
"expects atomic reduction region with two "
4035 "arguments of the same type";
4036 auto ptrType = llvm::dyn_cast<PointerLikeType>(
4039 (ptrType.getElementType() && ptrType.getElementType() !=
getType()))
4040 return emitOpError() <<
"expects atomic reduction region arguments to "
4041 "be accumulators containing the reduction type";
4044 if (getCleanupRegion().empty())
4046 Block &cleanupEntryBlock = getCleanupRegion().
front();
4049 return emitOpError() <<
"expects cleanup region with one argument "
4050 "of the reduction type";
4060 const TaskOperands &clauses) {
4062 TaskOp::build(builder, state, clauses.iterated, clauses.affinityVars,
4063 clauses.allocateVars, clauses.allocatorVars,
4066 makeArrayAttr(ctx, clauses.dependKinds), clauses.dependVars,
4068 clauses.dependIterated, clauses.final, clauses.ifExpr,
4069 clauses.inReductionVars,
4071 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
4072 clauses.priority, clauses.privateVars,
4074 clauses.privateNeedsBarrier, clauses.threadset, clauses.untied,
4075 clauses.eventHandle);
4078LogicalResult TaskOp::verify() {
4080 getOperation(), getAllocateVars(), getAllocatorVars(),
4081 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
4082 getPrivateVars(), getPrivateSymsAttr())))
4085 LogicalResult verifyDependVars =
4087 getDependIteratedKinds(), getDependIterated());
4088 if (
failed(verifyDependVars))
4089 return verifyDependVars;
4095 getInReductionVars(), getInReductionByref());
4103 const TaskgroupOperands &clauses) {
4105 TaskgroupOp::build(builder, state, clauses.allocateVars,
4106 clauses.allocatorVars,
4109 clauses.taskReductionVars,
4114LogicalResult TaskgroupOp::verify() {
4116 getOperation(), getAllocateVars(), getAllocatorVars(),
4117 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr())))
4121 getTaskReductionVars(),
4122 getTaskReductionByref());
4130 const TaskloopContextOperands &clauses) {
4132 TaskloopContextOp::build(
4133 builder, state, clauses.allocateVars, clauses.allocatorVars,
4136 clauses.grainsizeMod, clauses.grainsize, clauses.ifExpr,
4137 clauses.inReductionVars,
4139 makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable,
4140 clauses.nogroup, clauses.numTasksMod, clauses.numTasks, clauses.priority,
4141 clauses.privateVars,
4143 clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
4145 makeArrayAttr(ctx, clauses.reductionSyms), clauses.threadset,
4147 state.
addAttribute(
"omp.combined", UnitAttr::get(ctx));
4150TaskloopWrapperOp TaskloopContextOp::getLoopOp() {
4151 return cast<TaskloopWrapperOp>(
4153 return isa<TaskloopWrapperOp>(op);
4157LogicalResult TaskloopContextOp::verify() {
4161 getOperation(), getAllocateVars(), getAllocatorVars(),
4162 getAllocateAlignmentsAttr(), getAllocatePrivateIndicesAttr(),
4163 getPrivateVars(), getPrivateSymsAttr())))
4167 getReductionVars(), getReductionByref())) ||
4169 getInReductionVars(),
4170 getInReductionByref())))
4173 if (!getReductionVars().empty() && getNogroup())
4174 return emitError(
"if a reduction clause is present on the taskloop "
4175 "directive, the nogroup clause must not be specified");
4176 for (
auto var : getReductionVars()) {
4177 if (llvm::is_contained(getInReductionVars(), var))
4178 return emitError(
"the same list item cannot appear in both a reduction "
4179 "and an in_reduction clause");
4182 if (getGrainsize() && getNumTasks()) {
4184 "the grainsize clause and num_tasks clause are mutually exclusive and "
4185 "may not appear on the same taskloop directive");
4193 return emitOpError(
"must always contain the 'omp.combined' attribute");
4198LogicalResult TaskloopContextOp::verifyRegions() {
4199 Region ®ion = getRegion();
4201 return isa<TaskloopWrapperOp>(op);
4203 if (loopWrapperIt == region.
front().
end())
4204 return emitOpError()
4205 <<
"expected a TaskloopWrapperOp directly nested in the region";
4207 auto loopWrapperOp = cast<TaskloopWrapperOp>(*loopWrapperIt);
4208 auto loopNestOp = dyn_cast<LoopNestOp>(loopWrapperOp.getWrappedLoop());
4214 std::function<
bool(
Value)> isValidBoundValue = [&](
Value value) ->
bool {
4215 Region *valueRegion = value.getParentRegion();
4221 Operation *defOp = value.getDefiningOp();
4225 return llvm::all_of(defOp->
getOperands(), isValidBoundValue);
4227 auto hasUnsupportedTaskloopLocalBound = [&](
OperandRange range) ->
bool {
4228 return llvm::any_of(range,
4229 [&](
Value value) {
return !isValidBoundValue(value); });
4232 if (hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopLowerBounds()) ||
4233 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopUpperBounds()) ||
4234 hasUnsupportedTaskloopLocalBound(loopNestOp.getLoopSteps())) {
4235 return emitOpError()
4236 <<
"expects loop bounds and steps to be defined outside of the "
4237 "taskloop.context region or by pure, regionless operations "
4238 "that do not depend on block arguments";
4249 const TaskloopWrapperOperands &clauses) {
4250 TaskloopWrapperOp::build(builder, state);
4253TaskloopContextOp TaskloopWrapperOp::getTaskloopContext() {
4254 return dyn_cast<TaskloopContextOp>(getOperation()->getParentOp());
4257LogicalResult TaskloopWrapperOp::verify() {
4258 TaskloopContextOp context = getTaskloopContext();
4260 return emitOpError() <<
"expected to be nested in a taskloop context op";
4264LogicalResult TaskloopWrapperOp::verifyRegions() {
4265 if (LoopWrapperInterface nested = getNestedWrapper()) {
4268 <<
"'omp.composite' attribute missing from composite wrapper";
4272 if (!isa<SimdOp>(nested))
4273 return emitError() <<
"only supported nested wrapper is 'omp.simd'";
4274 }
else if (isComposite()) {
4276 <<
"'omp.composite' attribute present in non-composite wrapper";
4300 for (
auto &iv : ivs)
4301 iv.type = loopVarType;
4306 result.addAttribute(
"loop_inclusive", UnitAttr::get(ctx));
4322 "collapse_num_loops",
4327 auto parseTiles = [&]() -> ParseResult {
4331 tiles.push_back(
tile);
4340 if (tiles.size() > 0)
4359 Region ®ion = getRegion();
4361 p <<
" (" << args <<
") : " << args[0].getType() <<
" = ("
4362 << getLoopLowerBounds() <<
") to (" << getLoopUpperBounds() <<
") ";
4363 if (getLoopInclusive())
4365 p <<
"step (" << getLoopSteps() <<
") ";
4366 if (
int64_t numCollapse = getCollapseNumLoops())
4367 if (numCollapse > 1)
4368 p <<
"collapse(" << numCollapse <<
") ";
4371 p <<
"tiles(" << tiles.value() <<
") ";
4377 const LoopNestOperands &clauses) {
4379 LoopNestOp::build(builder, state, clauses.collapseNumLoops,
4380 clauses.loopLowerBounds, clauses.loopUpperBounds,
4381 clauses.loopSteps, clauses.loopInclusive,
4385LogicalResult LoopNestOp::verify() {
4386 if (getLoopLowerBounds().empty())
4387 return emitOpError() <<
"must represent at least one loop";
4389 if (getLoopLowerBounds().size() != getIVs().size())
4390 return emitOpError() <<
"number of range arguments and IVs do not match";
4392 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), getIVs())) {
4393 if (lb.getType() != iv.getType())
4394 return emitOpError()
4395 <<
"range argument type does not match corresponding IV type";
4398 uint64_t numIVs = getIVs().size();
4400 if (
const auto &numCollapse = getCollapseNumLoops())
4401 if (numCollapse > numIVs)
4402 return emitOpError()
4403 <<
"collapse value is larger than the number of loops";
4406 if (tiles.value().size() > numIVs)
4407 return emitOpError() <<
"too few canonical loops for tile dimensions";
4409 if (!llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp()))
4410 return emitOpError() <<
"expects parent op to be a loop wrapper";
4415void LoopNestOp::gatherWrappers(
4418 while (
auto wrapper =
4419 llvm::dyn_cast_if_present<LoopWrapperInterface>(parent)) {
4420 wrappers.push_back(wrapper);
4429std::tuple<NewCliOp, OpOperand *, OpOperand *>
4435 return {{},
nullptr,
nullptr};
4438 "Unexpected type of cli");
4444 auto op = cast<LoopTransformationInterface>(use.getOwner());
4446 unsigned opnum = use.getOperandNumber();
4447 if (op.isGeneratee(opnum)) {
4448 assert(!gen &&
"Each CLI may have at most one def");
4450 }
else if (op.isApplyee(opnum)) {
4451 assert(!cons &&
"Each CLI may have at most one consumer");
4454 llvm_unreachable(
"Unexpected operand for a CLI");
4458 return {create, gen, cons};
4464 case llvm::omp::ProcBindKind::OMP_PROC_BIND_close:
4465 return ClauseProcBindKind::Close;
4466 case llvm::omp::ProcBindKind::OMP_PROC_BIND_master:
4467 return ClauseProcBindKind::Master;
4468 case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary:
4469 return ClauseProcBindKind::Primary;
4470 case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread:
4471 return ClauseProcBindKind::Spread;
4472 case llvm::omp::ProcBindKind::OMP_PROC_BIND_default:
4473 case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown:
4476 llvm_unreachable(
"unexpected proc-bind kind");
4499 std::string cliName{
"cli"};
4503 .Case([&](CanonicalLoopOp op) {
4506 .Case([&](UnrollHeuristicOp op) -> std::string {
4507 llvm_unreachable(
"heuristic unrolling does not generate a loop");
4509 .Case([&](FuseOp op) -> std::string {
4510 unsigned opnum =
generator->getOperandNumber();
4513 if (op.getFirst().has_value() && opnum != op.getFirst().value())
4514 return "canonloop_fuse";
4518 .Case([&](TileOp op) -> std::string {
4519 auto [generateesFirst, generateesCount] =
4520 op.getGenerateesODSOperandIndexAndLength();
4521 unsigned firstGrid = generateesFirst;
4522 unsigned firstIntratile = generateesFirst + generateesCount / 2;
4523 unsigned end = generateesFirst + generateesCount;
4524 unsigned opnum =
generator->getOperandNumber();
4526 if (firstGrid <= opnum && opnum < firstIntratile) {
4527 unsigned gridnum = opnum - firstGrid + 1;
4528 return (
"grid" + Twine(gridnum)).str();
4530 if (firstIntratile <= opnum && opnum < end) {
4531 unsigned intratilenum = opnum - firstIntratile + 1;
4532 return (
"intratile" + Twine(intratilenum)).str();
4534 llvm_unreachable(
"Unexpected generatee argument");
4536 .DefaultUnreachable(
"TODO: Custom name for this operation");
4539 setNameFn(
result, cliName);
4542LogicalResult NewCliOp::verify() {
4543 Value cli = getResult();
4546 "Unexpected type of cli");
4552 auto op = cast<mlir::omp::LoopTransformationInterface>(use.getOwner());
4554 unsigned opnum = use.getOperandNumber();
4555 if (op.isGeneratee(opnum)) {
4558 emitOpError(
"CLI must have at most one generator");
4560 .
append(
"first generator here:");
4562 .
append(
"second generator here:");
4567 }
else if (op.isApplyee(opnum)) {
4570 emitOpError(
"CLI must have at most one consumer");
4572 .
append(
"first consumer here:")
4576 .
append(
"second consumer here:")
4583 llvm_unreachable(
"Unexpected operand for a CLI");
4591 .
append(
"see consumer here: ")
4614 setNameFn(&getRegion().front(),
"body_entry");
4617void CanonicalLoopOp::getAsmBlockArgumentNames(
Region ®ion,
4625 p <<
'(' << getCli() <<
')';
4626 p <<
' ' << getInductionVar() <<
" : " << getInductionVar().getType()
4627 <<
" in range(" << getTripCount() <<
") ";
4637 CanonicalLoopInfoType cliType =
4638 CanonicalLoopInfoType::get(parser.
getContext());
4663 if (parser.
parseRegion(*region, {inductionVariable}))
4668 result.operands.append(cliOperand);
4674 return mlir::success();
4677LogicalResult CanonicalLoopOp::verify() {
4680 if (!getRegion().empty()) {
4681 Region ®ion = getRegion();
4684 "Canonical loop region must have exactly one argument");
4688 "Region argument must be the same type as the trip count");
4694Value CanonicalLoopOp::getInductionVar() {
return getRegion().getArgument(0); }
4696std::pair<unsigned, unsigned>
4697CanonicalLoopOp::getApplyeesODSOperandIndexAndLength() {
4702std::pair<unsigned, unsigned>
4703CanonicalLoopOp::getGenerateesODSOperandIndexAndLength() {
4704 return getODSOperandIndexAndLength(odsIndex_cli);
4718 p <<
'(' << getApplyee() <<
')';
4725 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4748 return mlir::success();
4751std::pair<unsigned, unsigned>
4752UnrollHeuristicOp ::getApplyeesODSOperandIndexAndLength() {
4753 return getODSOperandIndexAndLength(odsIndex_applyee);
4756std::pair<unsigned, unsigned>
4757UnrollHeuristicOp::getGenerateesODSOperandIndexAndLength() {
4771 p <<
'(' << getApplyee() <<
')';
4778 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4801 return mlir::success();
4804std::pair<unsigned, unsigned>
4805UnrollFullOp::getApplyeesODSOperandIndexAndLength() {
4806 return getODSOperandIndexAndLength(odsIndex_applyee);
4809std::pair<unsigned, unsigned>
4810UnrollFullOp::getGenerateesODSOperandIndexAndLength() {
4814LogicalResult UnrollFullOp::verify() {
4815 auto [create, gen, cons] =
decodeCli(getApplyee());
4817 return emitOpError() <<
"applyee CLI has no generator";
4821 if (
auto loop = dyn_cast<CanonicalLoopOp>(gen->getOwner())) {
4823 return emitOpError() <<
"applyee loop must have a constant trip count";
4835 uint64_t unrollFactor) {
4842 p <<
'(' << getApplyee() <<
')';
4845 attrs.emplace_back(getUnrollFactorAttrName(), getUnrollFactorAttr());
4852 auto cliType = CanonicalLoopInfoType::get(parser.
getContext());
4869 return mlir::success();
4872std::pair<unsigned, unsigned>
4873UnrollPartialOp::getApplyeesODSOperandIndexAndLength() {
4874 return getODSOperandIndexAndLength(odsIndex_applyee);
4877std::pair<unsigned, unsigned>
4878UnrollPartialOp::getGenerateesODSOperandIndexAndLength() {
4889 if (!generatees.empty())
4890 p <<
'(' << llvm::interleaved(generatees) <<
')';
4892 if (!applyees.empty())
4893 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
4935 bool isOnlyCanonLoops =
true;
4937 for (
Value applyee : op.getApplyees()) {
4938 auto [create, gen, cons] =
decodeCli(applyee);
4941 return op.emitOpError() <<
"applyee CLI has no generator";
4943 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
4944 canonLoops.push_back(loop);
4946 isOnlyCanonLoops =
false;
4951 if (!isOnlyCanonLoops)
4955 for (
auto i : llvm::seq<int>(1, canonLoops.size())) {
4956 auto parentLoop = canonLoops[i - 1];
4957 auto loop = canonLoops[i];
4959 if (parentLoop.getOperation() != loop.getOperation()->getParentOp())
4960 return op.emitOpError()
4961 <<
"tiled loop nest must be nested within each other";
4963 parentIVs.insert(parentLoop.getInductionVar());
4968 bool isPerfectlyNested = [&]() {
4969 auto &parentBody = parentLoop.getRegion();
4970 if (!parentBody.hasOneBlock())
4972 auto &parentBlock = parentBody.getBlocks().
front();
4974 auto nestedLoopIt = parentBlock.
begin();
4975 if (nestedLoopIt == parentBlock.
end() ||
4976 (&*nestedLoopIt != loop.getOperation()))
4979 auto termIt = std::next(nestedLoopIt);
4980 if (termIt == parentBlock.
end() || !isa<TerminatorOp>(termIt))
4983 if (std::next(termIt) != parentBlock.
end())
4988 if (!isPerfectlyNested)
4989 return op.emitOpError() <<
"tiled loop nest must be perfectly nested";
4991 if (parentIVs.contains(loop.getTripCount()))
4992 return op.emitOpError() <<
"tiled loop nest must be rectangular";
5009LogicalResult TileOp::verify() {
5010 if (getApplyees().empty())
5011 return emitOpError() <<
"must apply to at least one loop";
5013 if (getSizes().size() != getApplyees().size())
5014 return emitOpError() <<
"there must be one tile size for each applyee";
5016 if (!getGeneratees().empty() &&
5017 2 * getSizes().size() != getGeneratees().size())
5018 return emitOpError()
5019 <<
"expecting two times the number of generatees than applyees";
5024std::pair<unsigned, unsigned> TileOp ::getApplyeesODSOperandIndexAndLength() {
5025 return getODSOperandIndexAndLength(odsIndex_applyees);
5028std::pair<unsigned, unsigned> TileOp::getGenerateesODSOperandIndexAndLength() {
5029 return getODSOperandIndexAndLength(odsIndex_generatees);
5039 if (!generatees.empty())
5040 p <<
'(' << llvm::interleaved(generatees) <<
')';
5042 if (!applyees.empty())
5043 p <<
" <- (" << llvm::interleaved(applyees) <<
')';
5046LogicalResult FuseOp::verify() {
5047 if (getApplyees().size() < 2)
5048 return emitOpError() <<
"must apply to at least two loops";
5050 if (getFirst().has_value() && getCount().has_value()) {
5051 int64_t first = getFirst().value();
5052 int64_t count = getCount().value();
5053 if ((
unsigned)(first + count - 1) > getApplyees().size())
5054 return emitOpError() <<
"the numbers of applyees must be at least first "
5055 "minus one plus count attributes";
5056 if (!getGeneratees().empty() &&
5057 getGeneratees().size() != getApplyees().size() + 1 - count)
5058 return emitOpError() <<
"the number of generatees must be the number of "
5059 "aplyees plus one minus count";
5062 if (!getGeneratees().empty() && getGeneratees().size() != 1)
5063 return emitOpError()
5064 <<
"in a complete fuse the number of generatees must be exactly 1";
5066 for (
auto &&applyee : getApplyees()) {
5067 auto [create, gen, cons] =
decodeCli(applyee);
5070 return emitOpError() <<
"applyee CLI has no generator";
5071 auto loop = dyn_cast_or_null<CanonicalLoopOp>(gen->getOwner());
5073 return emitOpError()
5074 <<
"currently only supports omp.canonical_loop as applyee";
5078std::pair<unsigned, unsigned> FuseOp::getApplyeesODSOperandIndexAndLength() {
5079 return getODSOperandIndexAndLength(odsIndex_applyees);
5082std::pair<unsigned, unsigned> FuseOp::getGenerateesODSOperandIndexAndLength() {
5083 return getODSOperandIndexAndLength(odsIndex_generatees);
5091 const CriticalDeclareOperands &clauses) {
5092 CriticalDeclareOp::build(builder, state, clauses.symName,
5093 clauses.symVisibility, clauses.hint);
5096LogicalResult CriticalDeclareOp::verify() {
5100LogicalResult CriticalOp::verify() {
5101 SymbolRefAttr currentName = getNameAttr();
5103 CriticalOp parentCritical = (*this)->getParentOfType<CriticalOp>();
5105 while (parentCritical) {
5106 SymbolRefAttr parentName = parentCritical.getNameAttr();
5108 if (currentName == parentName) {
5110 return emitOpError() <<
"cannot be nested inside another omp.critical "
5111 "region with the same name ("
5112 << currentName <<
")";
5114 return emitOpError() <<
"cannot be nested inside another unnamed "
5115 "omp.critical region";
5119 parentCritical = parentCritical->getParentOfType<CriticalOp>();
5126 if (getNameAttr()) {
5127 SymbolRefAttr symbolRef = getNameAttr();
5131 return emitOpError() <<
"expected symbol reference " << symbolRef
5132 <<
" to point to a critical declaration";
5143LogicalResult ErrorOp::verify() {
5144 if (getMessage() && getMessageExpr())
5145 return emitOpError() <<
"the message must be provided either as a constant "
5146 "`message` attribute or as a `message_expr` "
5147 "operand, but not both";
5164 return op.
emitOpError() <<
"must be nested inside of a loop";
5168 if (
auto wsloopOp = dyn_cast<WsloopOp>(wrapper)) {
5169 IntegerAttr orderedAttr = wsloopOp.getOrderedAttr();
5171 return op.
emitOpError() <<
"the enclosing worksharing-loop region must "
5172 "have an ordered clause";
5174 if (hasRegion && orderedAttr.getInt() != 0)
5175 return op.
emitOpError() <<
"the enclosing loop's ordered clause must not "
5176 "have a parameter present";
5178 if (!hasRegion && orderedAttr.getInt() == 0)
5179 return op.
emitOpError() <<
"the enclosing loop's ordered clause must "
5180 "have a parameter present";
5181 }
else if (!isa<SimdOp>(wrapper)) {
5182 return op.
emitOpError() <<
"must be nested inside of a worksharing, simd "
5183 "or worksharing simd loop";
5189 const OrderedOperands &clauses) {
5190 OrderedOp::build(builder, state, clauses.doacrossDependType,
5191 clauses.doacrossNumLoops, clauses.doacrossDependVars);
5194LogicalResult OrderedOp::verify() {
5198 auto wrapper = (*this)->getParentOfType<WsloopOp>();
5199 if (!wrapper || *wrapper.getOrdered() != *getDoacrossNumLoops())
5200 return emitOpError() <<
"number of variables in depend clause does not "
5201 <<
"match number of iteration variables in the "
5208 const OrderedRegionOperands &clauses) {
5209 OrderedRegionOp::build(builder, state, clauses.parLevelSimd);
5219 const TaskwaitOperands &clauses) {
5235LogicalResult AtomicReadOp::verify() {
5236 if (verifyCommon().
failed())
5237 return mlir::failure();
5240 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5241 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5242 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5244 if (
auto mo = getMemoryOrder()) {
5245 if (*mo == ClauseMemoryOrderKind::Release) {
5246 return emitError(
"memory-order must not be release for atomic reads");
5248 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5251 return emitError(
"memory-order must not be acq_rel for atomic reads");
5261LogicalResult AtomicWriteOp::verify() {
5262 if (verifyCommon().
failed())
5263 return mlir::failure();
5266 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5267 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5268 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5270 if (
auto mo = getMemoryOrder()) {
5271 if (*mo == ClauseMemoryOrderKind::Acquire) {
5272 return emitError(
"memory-order must not be acquire for atomic writes");
5274 if (*mo == ClauseMemoryOrderKind::Acq_rel) {
5277 return emitError(
"memory-order must not be acq_rel for atomic writes");
5287LogicalResult AtomicUpdateOp::canonicalize(AtomicUpdateOp op,
5293 if (
Value writeVal = op.getWriteOpVal()) {
5295 op, op.getX(), writeVal, op.getHintAttr(), op.getMemoryOrderAttr());
5301LogicalResult AtomicUpdateOp::verify() {
5302 if (verifyCommon().
failed())
5303 return mlir::failure();
5306 if (
auto moduleOp = getOperation()->getParentOfType<ModuleOp>())
5307 if (
Attribute verAttr = moduleOp->getDiscardableAttr(
"omp.version"))
5308 version = llvm::cast<VersionAttr>(verAttr).getVersion();
5310 if (
auto mo = getMemoryOrder()) {
5311 if (*mo == ClauseMemoryOrderKind::Acq_rel ||
5312 *mo == ClauseMemoryOrderKind::Acquire) {
5316 "memory-order must not be acq_rel or acquire for atomic updates");
5323LogicalResult AtomicUpdateOp::verifyRegions() {
return verifyRegionsCommon(); }
5329AtomicReadOp AtomicCaptureOp::getAtomicReadOp() {
5330 if (
auto op = dyn_cast<AtomicReadOp>(getFirstOp()))
5332 return dyn_cast<AtomicReadOp>(getSecondOp());
5335AtomicWriteOp AtomicCaptureOp::getAtomicWriteOp() {
5336 if (
auto op = dyn_cast<AtomicWriteOp>(getFirstOp()))
5338 return dyn_cast<AtomicWriteOp>(getSecondOp());
5341AtomicUpdateOp AtomicCaptureOp::getAtomicUpdateOp() {
5342 if (
auto op = dyn_cast<AtomicUpdateOp>(getFirstOp()))
5344 return dyn_cast<AtomicUpdateOp>(getSecondOp());
5347AtomicCompareOp AtomicCaptureOp::getAtomicCompareOp() {
5348 if (
auto op = dyn_cast<AtomicCompareOp>(getFirstOp()))
5350 return dyn_cast<AtomicCompareOp>(getSecondOp());
5353LogicalResult AtomicCaptureOp::verify() {
5357LogicalResult AtomicCaptureOp::verifyRegions() {
5358 if (verifyRegionsCommon().
failed())
5359 return mlir::failure();
5361 if (getFirstOp()->getInherentAttr(
"hint").value_or(
Attribute{}) ||
5362 getSecondOp()->getInherentAttr(
"hint").value_or(
Attribute{}))
5364 "operations inside capture region must not have hint clause");
5366 if (getFirstOp()->getInherentAttr(
"memory_order").value_or(
Attribute{}) ||
5367 getSecondOp()->getInherentAttr(
"memory_order").value_or(
Attribute{}))
5369 "operations inside capture region must not have memory_order clause");
5377LogicalResult AtomicCompareOp::verify() {
5378 if (verifyCommon().
failed())
5379 return mlir::failure();
5383 if (
auto failOrder = getFailMemoryOrder()) {
5384 if (*failOrder != ClauseMemoryOrderKind::Seq_cst &&
5385 *failOrder != ClauseMemoryOrderKind::Acquire &&
5386 *failOrder != ClauseMemoryOrderKind::Relaxed)
5388 "fail_memory_order must be 'seq_cst', 'acquire' or 'relaxed'");
5393LogicalResult AtomicCompareOp::verifyRegions() {
5394 if (verifyRegionsCommon().
failed())
5395 return mlir::failure();
5397 if (verifyOperator().
failed())
5398 return mlir::failure();
5403 if (!terminator || !isa<YieldOp>(terminator))
5404 return emitOpError(
"region must be terminated with omp.yield");
5414 const CancelOperands &clauses) {
5415 CancelOp::build(builder, state, clauses.cancelDirective, clauses.ifExpr);
5428LogicalResult CancelOp::verify() {
5429 ClauseCancellationConstructType cct = getCancelDirective();
5432 if (!structuralParent)
5433 return emitOpError() <<
"Orphaned cancel construct";
5435 if ((cct == ClauseCancellationConstructType::Parallel) &&
5436 !mlir::isa<ParallelOp>(structuralParent)) {
5437 return emitOpError() <<
"cancel parallel must appear "
5438 <<
"inside a parallel region";
5440 if (cct == ClauseCancellationConstructType::Loop) {
5443 auto wsloopOp = mlir::dyn_cast<WsloopOp>(structuralParent->
getParentOp());
5446 return emitOpError()
5447 <<
"cancel loop must appear inside a worksharing-loop region";
5449 if (wsloopOp.getNowaitAttr()) {
5450 return emitError() <<
"A worksharing construct that is canceled "
5451 <<
"must not have a nowait clause";
5453 if (wsloopOp.getOrderedAttr()) {
5454 return emitError() <<
"A worksharing construct that is canceled "
5455 <<
"must not have an ordered clause";
5458 }
else if (cct == ClauseCancellationConstructType::Sections) {
5462 mlir::dyn_cast<SectionsOp>(structuralParent->
getParentOp());
5464 return emitOpError() <<
"cancel sections must appear "
5465 <<
"inside a sections region";
5467 if (sectionsOp.getNowait()) {
5468 return emitError() <<
"A sections construct that is canceled "
5469 <<
"must not have a nowait clause";
5472 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5473 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5474 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5475 return emitOpError() <<
"cancel taskgroup must appear "
5476 <<
"inside a task region";
5486 const CancellationPointOperands &clauses) {
5487 CancellationPointOp::build(builder, state, clauses.cancelDirective);
5490LogicalResult CancellationPointOp::verify() {
5491 ClauseCancellationConstructType cct = getCancelDirective();
5494 if (!structuralParent)
5495 return emitOpError() <<
"Orphaned cancellation point";
5497 if ((cct == ClauseCancellationConstructType::Parallel) &&
5498 !mlir::isa<ParallelOp>(structuralParent)) {
5499 return emitOpError() <<
"cancellation point parallel must appear "
5500 <<
"inside a parallel region";
5504 if ((cct == ClauseCancellationConstructType::Loop) &&
5505 !mlir::isa<WsloopOp>(structuralParent->
getParentOp())) {
5506 return emitOpError() <<
"cancellation point loop must appear "
5507 <<
"inside a worksharing-loop region";
5509 if ((cct == ClauseCancellationConstructType::Sections) &&
5510 !mlir::isa<omp::SectionOp>(structuralParent)) {
5511 return emitOpError() <<
"cancellation point sections must appear "
5512 <<
"inside a sections region";
5514 if ((cct == ClauseCancellationConstructType::Taskgroup) &&
5515 (!mlir::isa<omp::TaskOp>(structuralParent) &&
5516 !mlir::isa<omp::TaskloopWrapperOp>(structuralParent->
getParentOp()))) {
5517 return emitOpError() <<
"cancellation point taskgroup must appear "
5518 <<
"inside a task region";
5527LogicalResult MapBoundsOp::verify() {
5528 auto extent = getExtent();
5530 if (!extent && !upperbound)
5531 return emitError(
"expected extent or upperbound.");
5538 PrivateClauseOp::build(
5539 odsBuilder, odsState, symName,
nullptr, type,
5540 DataSharingClauseTypeAttr::get(odsBuilder.
getContext(),
5541 DataSharingClauseType::Private));
5544LogicalResult PrivateClauseOp::verifyRegions() {
5545 Type argType = getArgType();
5546 auto verifyTerminator = [&](
Operation *terminator,
bool yieldsValue,
5547 bool yieldsAnyType) -> LogicalResult {
5551 if (!llvm::isa<YieldOp>(terminator))
5553 <<
"expected exit block terminator to be an `omp.yield` op.";
5555 YieldOp yieldOp = llvm::cast<YieldOp>(terminator);
5556 TypeRange yieldedTypes = yieldOp.getResults().getTypes();
5559 if (yieldedTypes.empty())
5563 <<
"Did not expect any values to be yielded.";
5566 if (yieldedTypes.size() == 1 &&
5567 (yieldsAnyType || yieldedTypes.front() == argType))
5571 <<
"Invalid yielded value. Expected ";
5573 error <<
"a single value";
5575 error <<
"type: " << argType;
5578 if (yieldedTypes.empty())
5581 error << yieldedTypes;
5587 StringRef regionName,
bool yieldsValue,
5588 bool yieldsAnyType =
false) -> LogicalResult {
5589 assert(!region.
empty());
5593 <<
"`" << regionName <<
"`: " <<
"expected " << expectedNumArgs
5596 for (
Block &block : region) {
5610 for (
Region *region : getRegions())
5611 for (
Type ty : region->getArgumentTypes())
5613 return emitError() <<
"Region argument type mismatch: got " << ty
5614 <<
" expected " << argType <<
".";
5617 if (!initRegion.
empty() &&
5622 DataSharingClauseType dsType = getDataSharingType();
5624 if (dsType == DataSharingClauseType::Private && !getCopyRegion().empty())
5625 return emitError(
"`private` clauses do not require a `copy` region.");
5627 if (dsType == DataSharingClauseType::FirstPrivate && getCopyRegion().empty())
5629 "`firstprivate` clauses require at least a `copy` region.");
5631 if (dsType == DataSharingClauseType::FirstPrivate &&
5636 if (dsType == DataSharingClauseType::Linear && !getCopyRegion().empty())
5637 return emitError(
"`linear` clauses do not require a `copy` region.");
5639 if (!getDataAddressRegion().empty()) {
5640 if (dsType != DataSharingClauseType::Linear)
5642 "only `linear` clauses can have a `data_address` region.");
5644 "data_address",
true,
5649 if (!getDeallocRegion().empty() &&
5662 const MaskedOperands &clauses) {
5663 MaskedOp::build(builder, state, clauses.filteredThreadId);
5671 const DispatchOperands &clauses) {
5672 DispatchOp::build(builder, state, clauses.nocontext, clauses.novariants,
5681 const ScanOperands &clauses) {
5682 ScanOp::build(builder, state, clauses.inclusiveVars, clauses.exclusiveVars);
5685LogicalResult ScanOp::verify() {
5686 if (hasExclusiveVars() == hasInclusiveVars())
5688 "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected");
5689 if (WsloopOp parentWsLoopOp = (*this)->getParentOfType<WsloopOp>()) {
5690 if (parentWsLoopOp.getReductionModAttr() &&
5691 parentWsLoopOp.getReductionModAttr().getValue() ==
5692 ReductionModifier::inscan)
5695 if (SimdOp parentSimdOp = (*this)->getParentOfType<SimdOp>()) {
5696 if (parentSimdOp.getReductionModAttr() &&
5697 parentSimdOp.getReductionModAttr().getValue() ==
5698 ReductionModifier::inscan)
5701 return emitError(
"SCAN directive needs to be enclosed within a parent "
5702 "worksharing loop construct or SIMD construct with INSCAN "
5703 "reduction modifier");
5708 std::optional<uint64_t> alignment) {
5709 if (alignment.has_value()) {
5710 if ((alignment.value() != 0) && !llvm::has_single_bit(alignment.value()))
5712 <<
"ALIGN value : " << alignment.value() <<
" must be power of 2";
5717LogicalResult AllocateDirOp::verify() {
5725LogicalResult AllocSharedMemOp::verify() {
5733LogicalResult FreeSharedMemOp::verify() {
5741LogicalResult WorkdistributeOp::verify() {
5743 return emitOpError() <<
"cannot be a non-innermost combined construct leaf";
5746 Region ®ion = getRegion();
5748 return emitOpError(
"region cannot be empty");
5751 if (entryBlock.
empty())
5752 return emitOpError(
"region must contain a structured block");
5754 bool hasTerminator =
false;
5755 for (
Block &block : region) {
5756 if (isa<TerminatorOp>(block.
back())) {
5757 if (hasTerminator) {
5758 return emitOpError(
"region must have exactly one terminator");
5760 hasTerminator =
true;
5763 if (!hasTerminator) {
5764 return emitOpError(
"region must be terminated with omp.terminator");
5768 if (isa<BarrierOp>(op)) {
5770 "explicit barriers are not allowed in workdistribute region");
5773 if (isa<ParallelOp>(op)) {
5775 "nested parallel constructs not allowed in workdistribute");
5777 if (isa<TeamsOp>(op)) {
5779 "nested teams constructs not allowed in workdistribute");
5783 if (walkResult.wasInterrupted())
5787 if (!llvm::dyn_cast<TeamsOp>(parentOp))
5788 return emitOpError(
"workdistribute must be nested under teams");
5796LogicalResult DeclareSimdOp::verify() {
5799 dyn_cast_if_present<mlir::FunctionOpInterface>((*this)->getParentOp());
5801 return emitOpError() <<
"must be nested inside a function";
5803 if (getInbranch() && getNotinbranch())
5804 return emitOpError(
"cannot have both 'inbranch' and 'notinbranch'");
5810 if (getLinearSyms())
5811 return emitOpError(
"linear privatizers are not allowed");
5817 const DeclareSimdOperands &clauses) {
5819 DeclareSimdOp::build(
5820 odsBuilder, odsState, clauses.alignedVars,
5822 clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
5823 clauses.linearModifiers,
makeArrayAttr(ctx, clauses.linearSyms),
5824 clauses.notinbranch, clauses.simdlen, clauses.uniformVars);
5841 return mlir::failure();
5842 return mlir::success();
5849 for (
unsigned i = 0; i < uniformVars.size(); ++i) {
5852 p << uniformVars[i] <<
" : " << uniformTypes[i];
5867 parser, iterated, iteratedTypes, affinityVars, affinityVarTypes,
5868 [&]() -> ParseResult {
return success(); })))
5902 OpAsmParser::Argument &arg = ivArgs.emplace_back();
5903 if (parser.parseArgument(arg))
5907 if (succeeded(parser.parseOptionalColon())) {
5908 if (parser.parseType(arg.type))
5911 arg.type = parser.getBuilder().getIndexType();
5923 OpAsmParser::UnresolvedOperand lb, ub, st;
5924 if (parser.parseOperand(lb) || parser.parseKeyword(
"to") ||
5925 parser.parseOperand(ub) || parser.parseKeyword(
"step") ||
5926 parser.parseOperand(st))
5931 steps.push_back(st);
5939 if (ivArgs.size() != lbs.size())
5941 <<
"mismatch: " << ivArgs.size() <<
" variables but " << lbs.size()
5944 for (
auto &arg : ivArgs) {
5945 lbTypes.push_back(arg.type);
5946 ubTypes.push_back(arg.type);
5947 stepTypes.push_back(arg.type);
5967 for (
unsigned i = 0, e = lbs.size(); i < e; ++i) {
5970 p << lbs[i] <<
" to " << ubs[i] <<
" step " << steps[i];
5978YieldOp IteratorOp::getYieldOp() {
5980 for (
Block &block : getRegion()) {
5982 dyn_cast_if_present<YieldOp>(block.
empty() ?
nullptr : &block.
back());
5992LogicalResult IteratorOp::verify() {
5993 auto iteratedTy = llvm::dyn_cast<omp::IteratedType>(getIterated().
getType());
5995 return emitOpError() <<
"result must be omp.iterated<entry_ty>";
5998 if (getLoopLowerBounds().size() != ivs.size())
5999 return emitOpError() <<
"number of range arguments and IVs do not match";
6001 for (
auto [lb, iv] : llvm::zip_equal(getLoopLowerBounds(), ivs)) {
6002 if (lb.getType() != iv.getType())
6003 return emitOpError()
6004 <<
"range argument type does not match corresponding IV type";
6007 for (
Value step : getLoopSteps()) {
6009 return emitOpError() <<
"loop step must not be zero";
6012 YieldOp yield = getYieldOp();
6014 bool hasYield = llvm::any_of(getRegion(), [](
Block &block) {
6015 return !block.
empty() && isa<YieldOp>(block.
back());
6018 return emitOpError() <<
"region must contain exactly one omp.yield";
6019 return emitOpError() <<
"region must be terminated by omp.yield";
6022 if (yield.getNumOperands() != 1)
6023 return emitOpError()
6024 <<
"omp.yield in omp.iterator region must yield exactly one value";
6026 mlir::Type yieldedTy = yield.getOperand(0).getType();
6027 mlir::Type elemTy = iteratedTy.getElementType();
6029 if (yieldedTy != elemTy)
6030 return emitOpError() <<
"omp.iterated element type (" << elemTy
6031 <<
") does not match omp.yield operand type ("
6032 << yieldedTy <<
")";
6037LogicalResult IteratorOp::verifyRegions() {
6039 for (
Block &block : getRegion()) {
6043 <<
"expected exit block terminator to be an `omp.yield` op.";
6056 return emitOpError() <<
"expected symbol reference '" << getSymName()
6057 <<
"' to point to a global variable";
6059 if (isa<FunctionOpInterface>(symbol))
6060 return emitOpError() <<
"expected symbol reference '" << getSymName()
6061 <<
"' to point to a global variable, not a function";
6066#define GET_ATTRDEF_CLASSES
6067#include "mlir/Dialect/OpenMP/OpenMPOpsAttributes.cpp.inc"
6069#define GET_OP_CLASSES
6070#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
6072#define GET_TYPEDEF_CLASSES
6073#include "mlir/Dialect/OpenMP/OpenMPOpsTypes.cpp.inc"
static std::optional< int64_t > getUpperBound(Value iv)
Gets the constant upper bound on an affine.for iv.
static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion, const Twine &name)
static const mlir::GenInfo * generator
static void printLinearPrivateReductionRegion(OpAsmPrinter &p, Operation *op, Region ®ion, ValueRange linearVars, TypeRange linearTypes, ValueRange linearStepVars, TypeRange linearStepTypes, ArrayAttr linearVarTypes, ArrayAttr linearModifiers, ArrayAttr linearSyms, ValueRange privateVars, TypeRange privateTypes, ArrayAttr privateSyms, UnitAttr privateNeedsBarrier, ReductionModifierAttr reductionMod, ValueRange reductionVars, TypeRange reductionTypes, DenseBoolArrayAttr reductionByref, ArrayAttr reductionSyms)
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 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 printLinearClause(OpAsmPrinter &p, Operation *op, ValueRange linearVars, TypeRange linearTypes, ValueRange linearStepVars, TypeRange stepVarTypes, ArrayAttr linearModifiers, ArrayAttr linearSyms)
Print Linear 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 ParseResult parseLinearPrivateReductionRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearVars, SmallVectorImpl< Type > &linearTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearStepVars, SmallVectorImpl< Type > &linearStepTypes, ArrayAttr &linearVarTypes, ArrayAttr &linearModifiers, ArrayAttr &linearSyms, 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 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 LogicalResult verifyLinearSyms(OpType op)
Verifies that each linear variable has a linear privatizer.
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 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 ParseResult parseLinearClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearVars, SmallVectorImpl< Type > &linearTypes, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &linearStepVars, SmallVectorImpl< Type > &linearStepTypes, ArrayAttr &linearModifiers, ArrayAttr &linearSyms)
linear ::= linear ( linear-list ) linear-list := linear-val | linear-val linear-list linear-val := ss...
static LogicalResult checkApplyeesNesting(TileOp op)
Check properties of the loop nest consisting of the transformation's applyees:
static ParseResult parseCaptureType(OpAsmParser &parser, VariableCaptureKindAttr &mapCaptureType)
static ParseResult parseTaskReductionRegion(OpAsmParser &parser, Region ®ion, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &taskReductionVars, SmallVectorImpl< Type > &taskReductionTypes, DenseBoolArrayAttr &taskReductionByref, ArrayAttr &taskReductionSyms)
static ParseResult parseGrainsizeClause(OpAsmParser &parser, ClauseGrainsizeTypeAttr &grainsizeMod, std::optional< OpAsmParser::UnresolvedOperand > &grainsize, Type &grainsizeType)
static ParseResult parseCopyprivate(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > ©privateVars, SmallVectorImpl< Type > ©privateTypes, ArrayAttr ©privateSyms)
copyprivate-entry-list ::= copyprivate-entry | copyprivate-entry-list , copyprivate-entry copyprivate...
static ParseResult parseInReductionClause(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &inReductionVars, SmallVectorImpl< Type > &inReductionTypes, DenseBoolArrayAttr &inReductionByref, ArrayAttr &inReductionSyms)
Parses an in_reduction clause for an operation that does not give its list items entry block argument...
static LogicalResult verifyMapInfoDefinedArgs(Operation *op, StringRef clauseName, OperandRange vars)
static void printGrainsizeClause(OpAsmPrinter &p, Operation *op, ClauseGrainsizeTypeAttr grainsizeMod, Value grainsize, mlir::Type grainsizeType)
static ParseResult verifyScheduleModifiers(OpAsmParser &parser, SmallVectorImpl< SmallString< 12 > > &modifiers)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static bool isUnique(It begin, It end)
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
static SmallVector< Value > getTileSizes(Location loc, x86::amx::TileType tType, RewriterBase &rewriter)
Maps the 2-dim vector shape to the two 16-bit tile sizes.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseMinus()=0
Parse a '-' token.
@ Paren
Parens surrounding zero or more operands.
@ None
Zero or more operands with no delimiters.
virtual ParseResult parseColonTypeList(SmallVectorImpl< Type > &result)=0
Parse a colon followed by a type list, which must have at least one type.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalEqual()=0
Parse a = token if present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseOptionalColon()=0
Parse a : token if present.
virtual ParseResult parseLSquare()=0
Parse a [ token.
virtual ParseResult parseRSquare()=0
Parse a ] token.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseOptionalArrow()=0
Parse a '->' token if present.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual ParseResult parseColonType(Type &result)=0
Parse a colon followed by a type.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseOptionalLess()=0
Parse a '<' token if present.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLParen()=0
Parse a ( token if present.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
MutableArrayRef< BlockArgument > BlockArgListType
ValueTypeRange< BlockArgListType > getArgumentTypes()
Return a range containing the types of the arguments for this block.
unsigned getNumSuccessors()
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.