10#include "llvm/ADT/ScopeExit.h"
11#include "llvm/ADT/SmallPtrSet.h"
12#include "llvm/IR/Constants.h"
20struct LoopMetadataConversion {
22 static LoopAnnotationAttr convert(
const llvm::MDNode *node, Location loc,
23 LoopAnnotationImporter &importer);
26 LoopMetadataConversion(
27 const llvm::MDNode *node, Location loc, DistinctAttr
id,
28 LoopAnnotationImporter &loopAnnotationImporter,
29 llvm::SmallPtrSetImpl<const llvm::MDNode *> &activeNodes)
30 : node(node), loc(loc), id(id),
31 loopAnnotationImporter(loopAnnotationImporter), ctx(loc->
getContext()),
32 activeNodes(activeNodes) {}
35 LoopAnnotationAttr convertFollowup(
const llvm::MDNode *followup);
38 LoopAnnotationAttr convertProperties();
41 LogicalResult initConversionState();
44 const llvm::MDNode *lookupAndEraseProperty(StringRef name);
49 FailureOr<BoolAttr> lookupUnitNode(StringRef name);
50 FailureOr<BoolAttr> lookupBoolNode(StringRef name,
bool negated =
false);
51 FailureOr<BoolAttr> lookupIntNodeAsBoolAttr(StringRef name);
52 FailureOr<IntegerAttr> lookupIntNode(StringRef name);
53 FailureOr<uint32_t> lookupUInt32Node(StringRef name);
54 FailureOr<SmallVector<llvm::MDNode *>> lookupMDNodes(StringRef name);
55 FailureOr<LoopAnnotationAttr> lookupFollowupNode(StringRef name);
56 FailureOr<BoolAttr> lookupBooleanUnitNode(StringRef enableName,
57 StringRef disableName,
58 bool negated =
false);
61 FailureOr<LoopVectorizeAttr> convertVectorizeAttr();
62 FailureOr<LoopInterleaveAttr> convertInterleaveAttr();
63 FailureOr<LoopUnrollAttr> convertUnrollAttr();
64 FailureOr<LoopUnrollAndJamAttr> convertUnrollAndJamAttr();
65 FailureOr<LoopLICMAttr> convertLICMAttr();
66 FailureOr<LoopDistributeAttr> convertDistributeAttr();
67 FailureOr<LoopPipelineAttr> convertPipelineAttr();
68 FailureOr<LoopPeeledAttr> convertPeeledAttr();
69 FailureOr<LoopUnswitchAttr> convertUnswitchAttr();
70 FailureOr<SmallVector<AccessGroupAttr>> convertParallelAccesses();
71 FusedLoc convertStartLoc();
72 FailureOr<FusedLoc> convertEndLoc();
74 llvm::SmallVector<llvm::DILocation *, 2> locations;
75 llvm::StringMap<const llvm::MDNode *> propertyMap;
76 const llvm::MDNode *node;
79 LoopAnnotationImporter &loopAnnotationImporter;
81 llvm::SmallPtrSetImpl<const llvm::MDNode *> &activeNodes;
85LogicalResult LoopMetadataConversion::initConversionState() {
86 for (
const llvm::MDOperand &operand : llvm::drop_begin(node->operands())) {
87 if (
auto *diLoc = dyn_cast<llvm::DILocation>(operand)) {
88 locations.push_back(diLoc);
92 auto *
property = dyn_cast<llvm::MDNode>(operand);
94 return emitWarning(loc) <<
"expected all loop properties to be either "
95 "debug locations or metadata nodes";
97 if (property->getNumOperands() == 0)
98 return emitWarning(loc) <<
"cannot import empty loop property";
100 auto *nameNode = dyn_cast<llvm::MDString>(property->getOperand(0));
102 return emitWarning(loc) <<
"cannot import loop property without a name";
103 StringRef name = nameNode->getString();
105 bool succ = propertyMap.try_emplace(name, property).second;
108 <<
"cannot import loop properties with duplicated names " << name;
115LoopMetadataConversion::lookupAndEraseProperty(StringRef name) {
116 auto it = propertyMap.find(name);
117 if (it == propertyMap.end())
119 const llvm::MDNode *
property = it->getValue();
120 propertyMap.erase(it);
124FailureOr<BoolAttr> LoopMetadataConversion::lookupUnitNode(StringRef name) {
125 const llvm::MDNode *
property = lookupAndEraseProperty(name);
127 return BoolAttr(
nullptr);
129 if (property->getNumOperands() != 1)
131 <<
"expected metadata node " << name <<
" to hold no value";
136FailureOr<BoolAttr> LoopMetadataConversion::lookupBooleanUnitNode(
137 StringRef enableName, StringRef disableName,
bool negated) {
138 auto enable = lookupUnitNode(enableName);
139 auto disable = lookupUnitNode(disableName);
143 if (*enable && *disable)
145 <<
"expected metadata nodes " << enableName <<
" and " << disableName
146 <<
" to be mutually exclusive.";
153 return BoolAttr(
nullptr);
156FailureOr<BoolAttr> LoopMetadataConversion::lookupBoolNode(StringRef name,
158 const llvm::MDNode *
property = lookupAndEraseProperty(name);
160 return BoolAttr(
nullptr);
162 auto emitNodeWarning = [&]() {
164 <<
"expected metadata node " << name <<
" to hold a boolean value";
167 if (property->getNumOperands() != 2)
168 return emitNodeWarning();
169 llvm::ConstantInt *val =
170 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
171 if (!val || val->getBitWidth() != 1)
172 return emitNodeWarning();
174 return BoolAttr::get(ctx, val->getValue().getLimitedValue(1) ^ negated);
178LoopMetadataConversion::lookupIntNodeAsBoolAttr(StringRef name) {
179 const llvm::MDNode *
property = lookupAndEraseProperty(name);
181 return BoolAttr(
nullptr);
183 auto emitNodeWarning = [&]() {
185 <<
"expected metadata node " << name <<
" to hold an integer value";
188 if (property->getNumOperands() != 2)
189 return emitNodeWarning();
190 llvm::ConstantInt *val =
191 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
192 if (!val || val->getBitWidth() != 32)
193 return emitNodeWarning();
195 return BoolAttr::get(ctx, val->getValue().getLimitedValue(1));
199FailureOr<uint32_t> LoopMetadataConversion::lookupUInt32Node(StringRef name) {
200 FailureOr<IntegerAttr> attr = lookupIntNode(name);
203 return *attr ? uint32_t(attr->getValue().getZExtValue()) : uint32_t(0);
206FailureOr<IntegerAttr> LoopMetadataConversion::lookupIntNode(StringRef name) {
207 const llvm::MDNode *
property = lookupAndEraseProperty(name);
209 return IntegerAttr(
nullptr);
211 auto emitNodeWarning = [&]() {
213 <<
"expected metadata node " << name <<
" to hold an i32 value";
216 if (property->getNumOperands() != 2)
217 return emitNodeWarning();
219 llvm::ConstantInt *val =
220 llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
221 if (!val || val->getBitWidth() != 32)
222 return emitNodeWarning();
224 return IntegerAttr::get(IntegerType::get(ctx, 32),
225 val->getValue().getLimitedValue());
228FailureOr<SmallVector<llvm::MDNode *>>
229LoopMetadataConversion::lookupMDNodes(StringRef name) {
230 const llvm::MDNode *
property = lookupAndEraseProperty(name);
231 SmallVector<llvm::MDNode *> res;
235 auto emitNodeWarning = [&]() {
236 return emitWarning(loc) <<
"expected metadata node " << name
237 <<
" to hold one or multiple MDNodes";
240 if (property->getNumOperands() < 2)
241 return emitNodeWarning();
243 for (
unsigned i = 1, e = property->getNumOperands(); i < e; ++i) {
244 auto *node = dyn_cast<llvm::MDNode>(property->getOperand(i));
246 return emitNodeWarning();
253FailureOr<LoopAnnotationAttr>
254LoopMetadataConversion::lookupFollowupNode(StringRef name) {
255 const llvm::MDNode *followup = lookupAndEraseProperty(name);
257 return LoopAnnotationAttr(
nullptr);
259 LoopAnnotationAttr attr = convertFollowup(followup);
276template <
typename... P>
278 bool anyFailed = (failed(args) || ...);
287template <
typename T,
typename... P>
292 return T::get(ctx, *args...);
295FailureOr<LoopVectorizeAttr> LoopMetadataConversion::convertVectorizeAttr() {
296 FailureOr<BoolAttr> enable = lookupBooleanUnitNode(
297 "llvm.loop.vectorize.enable",
"llvm.loop.vectorize.disable",
299 FailureOr<BoolAttr> predicateEnable =
300 lookupBooleanUnitNode(
"llvm.loop.vectorize.predicate.enable",
301 "llvm.loop.vectorize.predicate.disable");
302 FailureOr<BoolAttr> scalableEnable =
303 lookupBooleanUnitNode(
"llvm.loop.vectorize.scalable.enable",
304 "llvm.loop.vectorize.scalable.disable");
305 FailureOr<IntegerAttr> width = lookupIntNode(
"llvm.loop.vectorize.width");
306 FailureOr<LoopAnnotationAttr> followupVec =
307 lookupFollowupNode(
"llvm.loop.vectorize.followup_vectorized");
308 FailureOr<LoopAnnotationAttr> followupEpi =
309 lookupFollowupNode(
"llvm.loop.vectorize.followup_epilogue");
310 FailureOr<LoopAnnotationAttr> followupAll =
311 lookupFollowupNode(
"llvm.loop.vectorize.followup_all");
314 scalableEnable, width, followupVec,
315 followupEpi, followupAll);
318FailureOr<LoopInterleaveAttr> LoopMetadataConversion::convertInterleaveAttr() {
319 FailureOr<IntegerAttr> count = lookupIntNode(
"llvm.loop.interleave.count");
323FailureOr<LoopUnrollAttr> LoopMetadataConversion::convertUnrollAttr() {
324 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
325 "llvm.loop.unroll.enable",
"llvm.loop.unroll.disable",
true);
326 FailureOr<IntegerAttr> count = lookupIntNode(
"llvm.loop.unroll.count");
327 FailureOr<BoolAttr> runtimeDisable =
328 lookupUnitNode(
"llvm.loop.unroll.runtime.disable");
329 FailureOr<BoolAttr> full = lookupUnitNode(
"llvm.loop.unroll.full");
330 FailureOr<LoopAnnotationAttr> followupUnrolled =
331 lookupFollowupNode(
"llvm.loop.unroll.followup_unrolled");
332 FailureOr<LoopAnnotationAttr> followupRemainder =
333 lookupFollowupNode(
"llvm.loop.unroll.followup_remainder");
334 FailureOr<LoopAnnotationAttr> followupAll =
335 lookupFollowupNode(
"llvm.loop.unroll.followup_all");
338 full, followupUnrolled,
339 followupRemainder, followupAll);
342FailureOr<LoopUnrollAndJamAttr>
343LoopMetadataConversion::convertUnrollAndJamAttr() {
344 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
345 "llvm.loop.unroll_and_jam.enable",
"llvm.loop.unroll_and_jam.disable",
347 FailureOr<IntegerAttr> count =
348 lookupIntNode(
"llvm.loop.unroll_and_jam.count");
349 FailureOr<LoopAnnotationAttr> followupOuter =
350 lookupFollowupNode(
"llvm.loop.unroll_and_jam.followup_outer");
351 FailureOr<LoopAnnotationAttr> followupInner =
352 lookupFollowupNode(
"llvm.loop.unroll_and_jam.followup_inner");
353 FailureOr<LoopAnnotationAttr> followupRemainderOuter =
354 lookupFollowupNode(
"llvm.loop.unroll_and_jam.followup_remainder_outer");
355 FailureOr<LoopAnnotationAttr> followupRemainderInner =
356 lookupFollowupNode(
"llvm.loop.unroll_and_jam.followup_remainder_inner");
357 FailureOr<LoopAnnotationAttr> followupAll =
358 lookupFollowupNode(
"llvm.loop.unroll_and_jam.followup_all");
360 ctx, disable, count, followupOuter, followupInner, followupRemainderOuter,
361 followupRemainderInner, followupAll);
364FailureOr<LoopLICMAttr> LoopMetadataConversion::convertLICMAttr() {
365 FailureOr<BoolAttr> disable = lookupUnitNode(
"llvm.licm.disable");
366 FailureOr<BoolAttr> versioningDisable =
367 lookupUnitNode(
"llvm.loop.licm_versioning.disable");
371FailureOr<LoopDistributeAttr> LoopMetadataConversion::convertDistributeAttr() {
372 FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
373 "llvm.loop.distribute.enable",
"llvm.loop.distribute.disable",
375 FailureOr<LoopAnnotationAttr> followupCoincident =
376 lookupFollowupNode(
"llvm.loop.distribute.followup_coincident");
377 FailureOr<LoopAnnotationAttr> followupSequential =
378 lookupFollowupNode(
"llvm.loop.distribute.followup_sequential");
379 FailureOr<LoopAnnotationAttr> followupFallback =
380 lookupFollowupNode(
"llvm.loop.distribute.followup_fallback");
381 FailureOr<LoopAnnotationAttr> followupAll =
382 lookupFollowupNode(
"llvm.loop.distribute.followup_all");
385 followupFallback, followupAll);
388FailureOr<LoopPipelineAttr> LoopMetadataConversion::convertPipelineAttr() {
389 FailureOr<BoolAttr> disable = lookupBoolNode(
"llvm.loop.pipeline.disable");
390 FailureOr<IntegerAttr> initiationinterval =
391 lookupIntNode(
"llvm.loop.pipeline.initiationinterval");
395FailureOr<LoopPeeledAttr> LoopMetadataConversion::convertPeeledAttr() {
396 FailureOr<IntegerAttr> count = lookupIntNode(
"llvm.loop.peeled.count");
400FailureOr<LoopUnswitchAttr> LoopMetadataConversion::convertUnswitchAttr() {
401 FailureOr<BoolAttr> partialDisable =
402 lookupUnitNode(
"llvm.loop.unswitch.partial.disable");
406FailureOr<SmallVector<AccessGroupAttr>>
407LoopMetadataConversion::convertParallelAccesses() {
408 FailureOr<SmallVector<llvm::MDNode *>> nodes =
409 lookupMDNodes(
"llvm.loop.parallel_accesses");
412 SmallVector<AccessGroupAttr> refs;
413 for (llvm::MDNode *node : *nodes) {
414 FailureOr<SmallVector<AccessGroupAttr>> accessGroups =
416 if (
failed(accessGroups)) {
417 emitWarning(loc) <<
"could not lookup access group";
420 llvm::append_range(refs, *accessGroups);
425FusedLoc LoopMetadataConversion::convertStartLoc() {
426 if (locations.empty())
428 return dyn_cast<FusedLoc>(
432FailureOr<FusedLoc> LoopMetadataConversion::convertEndLoc() {
433 if (locations.size() < 2)
435 if (locations.size() > 2)
437 <<
"expected loop metadata to have at most two DILocations";
438 return dyn_cast<FusedLoc>(
443LoopMetadataConversion::convert(
const llvm::MDNode *node, Location loc,
444 LoopAnnotationImporter &importer) {
445 if (node->getNumOperands() == 0 ||
446 dyn_cast<llvm::MDNode>(node->getOperand(0)) != node) {
451 llvm::SmallPtrSet<const llvm::MDNode *, 4> activeNodes;
453 return LoopMetadataConversion(node, loc,
id, importer, activeNodes)
454 .convertProperties();
458LoopMetadataConversion::convertFollowup(
const llvm::MDNode *followup) {
459 if (followup->getNumOperands() == 0 ||
460 !isa<llvm::MDString>(followup->getOperand(0))) {
466 if (followup->getNumOperands() == 1)
467 return LoopAnnotationAttr::get(ctx, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},
468 {}, {}, {}, {}, {}, {}, {});
470 return LoopMetadataConversion(followup, loc, {},
471 loopAnnotationImporter, activeNodes)
472 .convertProperties();
475LoopAnnotationAttr LoopMetadataConversion::convertProperties() {
476 if (!activeNodes.insert(node).second) {
477 emitWarning(loc) <<
"cannot import cyclic loop annotation";
480 llvm::scope_exit guard([&] { activeNodes.erase(node); });
482 if (
failed(initConversionState()))
485 FailureOr<BoolAttr> disableNonForced =
486 lookupUnitNode(
"llvm.loop.disable_nonforced");
487 FailureOr<LoopVectorizeAttr> vecAttr = convertVectorizeAttr();
488 FailureOr<LoopInterleaveAttr> interleaveAttr = convertInterleaveAttr();
489 FailureOr<LoopUnrollAttr> unrollAttr = convertUnrollAttr();
490 FailureOr<LoopUnrollAndJamAttr> unrollAndJamAttr = convertUnrollAndJamAttr();
491 FailureOr<LoopLICMAttr> licmAttr = convertLICMAttr();
492 FailureOr<LoopDistributeAttr> distributeAttr = convertDistributeAttr();
493 FailureOr<LoopPipelineAttr> pipelineAttr = convertPipelineAttr();
494 FailureOr<LoopPeeledAttr> peeledAttr = convertPeeledAttr();
495 FailureOr<LoopUnswitchAttr> unswitchAttr = convertUnswitchAttr();
496 FailureOr<BoolAttr> mustProgress = lookupUnitNode(
"llvm.loop.mustprogress");
497 FailureOr<BoolAttr> isVectorized =
498 lookupIntNodeAsBoolAttr(
"llvm.loop.isvectorized");
499 FailureOr<uint32_t> align = lookupUInt32Node(
"llvm.loop.align");
500 FailureOr<SmallVector<AccessGroupAttr>> parallelAccesses =
501 convertParallelAccesses();
504 if (!propertyMap.empty()) {
505 for (
auto name : propertyMap.keys())
506 emitWarning(loc) <<
"unknown loop annotation " << name;
510 FailureOr<FusedLoc> startLoc = convertStartLoc();
511 FailureOr<FusedLoc> endLoc = convertEndLoc();
515 unrollAndJamAttr, licmAttr, distributeAttr,
516 pipelineAttr, peeledAttr, unswitchAttr, mustProgress,
517 isVectorized, align, startLoc, endLoc,
521 return LoopAnnotationAttr::get(
522 ctx,
id, *disableNonForced, *vecAttr, *interleaveAttr, *unrollAttr,
523 *unrollAndJamAttr, *licmAttr, *distributeAttr, *pipelineAttr, *peeledAttr,
524 *unswitchAttr, *mustProgress, *isVectorized, *align, *startLoc, *endLoc,
536 auto it = loopMetadataMapping.find(node);
537 if (it != loopMetadataMapping.end())
538 return it->getSecond();
540 LoopAnnotationAttr attr = LoopMetadataConversion::convert(node, loc, *
this);
542 mapLoopMetadata(node, attr);
550 if (!node->getNumOperands())
551 accessGroups.push_back(node);
552 for (
const llvm::MDOperand &operand : node->operands()) {
553 auto *childNode = dyn_cast<llvm::MDNode>(operand);
556 accessGroups.push_back(cast<llvm::MDNode>(operand.get()));
560 for (
const llvm::MDNode *accessGroup : accessGroups) {
561 if (accessGroupMapping.count(accessGroup))
564 if (accessGroup->getNumOperands() != 0 || !accessGroup->isDistinct())
566 <<
"expected an access group node to be empty and distinct";
569 accessGroupMapping[accessGroup] = builder.getAttr<AccessGroupAttr>();
574FailureOr<SmallVector<AccessGroupAttr>>
579 if (!node->getNumOperands())
580 accessGroups.push_back(accessGroupMapping.lookup(node));
581 for (
const llvm::MDOperand &operand : node->operands()) {
582 auto *node = cast<llvm::MDNode>(operand.get());
583 accessGroups.push_back(accessGroupMapping.lookup(node));
586 if (llvm::is_contained(accessGroups,
nullptr))
static T createIfNonNull(MLIRContext *ctx, const P &...args)
Helper function that only creates and attribute of type T if all argument conversion were successfull...
static bool isEmptyOrNull(const Attribute attr)
static bool anyFailedOrAllEmpty(const P &...args)
Helper function that returns true if any of the argument conversions failed or if all of them are nul...
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
static BoolAttr get(MLIRContext *context, bool value)
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
Location translateLoc(llvm::DILocation *loc)
Translates the debug location.
LoopAnnotationAttr translateLoopAnnotation(const llvm::MDNode *node, Location loc)
LogicalResult translateAccessGroup(const llvm::MDNode *node, Location loc)
Converts all LLVM access groups starting from node to MLIR access group attributes.
ModuleImport & moduleImport
The ModuleImport owning this instance.
FailureOr< SmallVector< AccessGroupAttr > > lookupAccessGroupAttrs(const llvm::MDNode *node) const
Returns the access group attribute that map to the access group nodes starting from the access group ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.