xref: /llvm-project/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp (revision bd26ce47c820858856bd33f20b0c606973155f51)
1b83caa32SChristian Ulmann //===- LoopAnnotationImporter.cpp - Loop annotation import ----------------===//
2b83caa32SChristian Ulmann //
3b83caa32SChristian Ulmann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b83caa32SChristian Ulmann // See https://llvm.org/LICENSE.txt for license information.
5b83caa32SChristian Ulmann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b83caa32SChristian Ulmann //
7b83caa32SChristian Ulmann //===----------------------------------------------------------------------===//
8b83caa32SChristian Ulmann 
9b83caa32SChristian Ulmann #include "LoopAnnotationImporter.h"
10b83caa32SChristian Ulmann #include "llvm/IR/Constants.h"
11b83caa32SChristian Ulmann 
12b83caa32SChristian Ulmann using namespace mlir;
13b83caa32SChristian Ulmann using namespace mlir::LLVM;
14b83caa32SChristian Ulmann using namespace mlir::LLVM::detail;
15b83caa32SChristian Ulmann 
16b83caa32SChristian Ulmann namespace {
17b83caa32SChristian Ulmann /// Helper class that keeps the state of one metadata to attribute conversion.
18b83caa32SChristian Ulmann struct LoopMetadataConversion {
LoopMetadataConversion__anon269862de0111::LoopMetadataConversion19e630a502SChristian Ulmann   LoopMetadataConversion(const llvm::MDNode *node, Location loc,
20b83caa32SChristian Ulmann                          LoopAnnotationImporter &loopAnnotationImporter)
21e630a502SChristian Ulmann       : node(node), loc(loc), loopAnnotationImporter(loopAnnotationImporter),
22b83caa32SChristian Ulmann         ctx(loc->getContext()){};
23b83caa32SChristian Ulmann   /// Converts this structs loop metadata node into a LoopAnnotationAttr.
24b83caa32SChristian Ulmann   LoopAnnotationAttr convert();
25b83caa32SChristian Ulmann 
2662d7d94cSChristian Ulmann   /// Initializes the shared state for the conversion member functions.
2762d7d94cSChristian Ulmann   LogicalResult initConversionState();
28b83caa32SChristian Ulmann 
29b83caa32SChristian Ulmann   /// Helper function to get and erase a property.
30b83caa32SChristian Ulmann   const llvm::MDNode *lookupAndEraseProperty(StringRef name);
31b83caa32SChristian Ulmann 
32b83caa32SChristian Ulmann   /// Helper functions to lookup and convert MDNodes into a specifc attribute
33b83caa32SChristian Ulmann   /// kind. These functions return null-attributes if there is no node with the
34b83caa32SChristian Ulmann   /// specified name, or failure, if the node is ill-formatted.
35b83caa32SChristian Ulmann   FailureOr<BoolAttr> lookupUnitNode(StringRef name);
36b83caa32SChristian Ulmann   FailureOr<BoolAttr> lookupBoolNode(StringRef name, bool negated = false);
374d7c879dSChristian Ulmann   FailureOr<BoolAttr> lookupIntNodeAsBoolAttr(StringRef name);
38b83caa32SChristian Ulmann   FailureOr<IntegerAttr> lookupIntNode(StringRef name);
39b83caa32SChristian Ulmann   FailureOr<llvm::MDNode *> lookupMDNode(StringRef name);
40b83caa32SChristian Ulmann   FailureOr<SmallVector<llvm::MDNode *>> lookupMDNodes(StringRef name);
41b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> lookupFollowupNode(StringRef name);
42b83caa32SChristian Ulmann   FailureOr<BoolAttr> lookupBooleanUnitNode(StringRef enableName,
43b83caa32SChristian Ulmann                                             StringRef disableName,
44b83caa32SChristian Ulmann                                             bool negated = false);
45b83caa32SChristian Ulmann 
46b83caa32SChristian Ulmann   /// Conversion functions for sub-attributes.
47b83caa32SChristian Ulmann   FailureOr<LoopVectorizeAttr> convertVectorizeAttr();
48b83caa32SChristian Ulmann   FailureOr<LoopInterleaveAttr> convertInterleaveAttr();
49b83caa32SChristian Ulmann   FailureOr<LoopUnrollAttr> convertUnrollAttr();
50b83caa32SChristian Ulmann   FailureOr<LoopUnrollAndJamAttr> convertUnrollAndJamAttr();
51b83caa32SChristian Ulmann   FailureOr<LoopLICMAttr> convertLICMAttr();
52b83caa32SChristian Ulmann   FailureOr<LoopDistributeAttr> convertDistributeAttr();
53b83caa32SChristian Ulmann   FailureOr<LoopPipelineAttr> convertPipelineAttr();
547f249e45SChristian Ulmann   FailureOr<LoopPeeledAttr> convertPeeledAttr();
557f249e45SChristian Ulmann   FailureOr<LoopUnswitchAttr> convertUnswitchAttr();
569170fa58SMarkus Böck   FailureOr<SmallVector<AccessGroupAttr>> convertParallelAccesses();
5762d7d94cSChristian Ulmann   FusedLoc convertStartLoc();
5862d7d94cSChristian Ulmann   FailureOr<FusedLoc> convertEndLoc();
59b83caa32SChristian Ulmann 
6062d7d94cSChristian Ulmann   llvm::SmallVector<llvm::DILocation *, 2> locations;
61b83caa32SChristian Ulmann   llvm::StringMap<const llvm::MDNode *> propertyMap;
62b83caa32SChristian Ulmann   const llvm::MDNode *node;
63b83caa32SChristian Ulmann   Location loc;
64b83caa32SChristian Ulmann   LoopAnnotationImporter &loopAnnotationImporter;
65b83caa32SChristian Ulmann   MLIRContext *ctx;
66b83caa32SChristian Ulmann };
67b83caa32SChristian Ulmann } // namespace
68b83caa32SChristian Ulmann 
initConversionState()6962d7d94cSChristian Ulmann LogicalResult LoopMetadataConversion::initConversionState() {
70b83caa32SChristian Ulmann   // Check if it's a valid node.
71b83caa32SChristian Ulmann   if (node->getNumOperands() == 0 ||
72b83caa32SChristian Ulmann       dyn_cast<llvm::MDNode>(node->getOperand(0)) != node)
73b83caa32SChristian Ulmann     return emitWarning(loc) << "invalid loop node";
74b83caa32SChristian Ulmann 
75b83caa32SChristian Ulmann   for (const llvm::MDOperand &operand : llvm::drop_begin(node->operands())) {
7662d7d94cSChristian Ulmann     if (auto *diLoc = dyn_cast<llvm::DILocation>(operand)) {
7762d7d94cSChristian Ulmann       locations.push_back(diLoc);
78b83caa32SChristian Ulmann       continue;
7962d7d94cSChristian Ulmann     }
80b83caa32SChristian Ulmann 
81b83caa32SChristian Ulmann     auto *property = dyn_cast<llvm::MDNode>(operand);
82b83caa32SChristian Ulmann     if (!property)
83b83caa32SChristian Ulmann       return emitWarning(loc) << "expected all loop properties to be either "
84b83caa32SChristian Ulmann                                  "debug locations or metadata nodes";
85b83caa32SChristian Ulmann 
86b83caa32SChristian Ulmann     if (property->getNumOperands() == 0)
87b83caa32SChristian Ulmann       return emitWarning(loc) << "cannot import empty loop property";
88b83caa32SChristian Ulmann 
89b83caa32SChristian Ulmann     auto *nameNode = dyn_cast<llvm::MDString>(property->getOperand(0));
90b83caa32SChristian Ulmann     if (!nameNode)
91b83caa32SChristian Ulmann       return emitWarning(loc) << "cannot import loop property without a name";
92b83caa32SChristian Ulmann     StringRef name = nameNode->getString();
93b83caa32SChristian Ulmann 
94b83caa32SChristian Ulmann     bool succ = propertyMap.try_emplace(name, property).second;
95b83caa32SChristian Ulmann     if (!succ)
96b83caa32SChristian Ulmann       return emitWarning(loc)
97b83caa32SChristian Ulmann              << "cannot import loop properties with duplicated names " << name;
98b83caa32SChristian Ulmann   }
99b83caa32SChristian Ulmann 
100b83caa32SChristian Ulmann   return success();
101b83caa32SChristian Ulmann }
102b83caa32SChristian Ulmann 
103b83caa32SChristian Ulmann const llvm::MDNode *
lookupAndEraseProperty(StringRef name)104b83caa32SChristian Ulmann LoopMetadataConversion::lookupAndEraseProperty(StringRef name) {
105b83caa32SChristian Ulmann   auto it = propertyMap.find(name);
106b83caa32SChristian Ulmann   if (it == propertyMap.end())
107b83caa32SChristian Ulmann     return nullptr;
108b83caa32SChristian Ulmann   const llvm::MDNode *property = it->getValue();
109b83caa32SChristian Ulmann   propertyMap.erase(it);
110b83caa32SChristian Ulmann   return property;
111b83caa32SChristian Ulmann }
112b83caa32SChristian Ulmann 
lookupUnitNode(StringRef name)113b83caa32SChristian Ulmann FailureOr<BoolAttr> LoopMetadataConversion::lookupUnitNode(StringRef name) {
114b83caa32SChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
115b83caa32SChristian Ulmann   if (!property)
116b83caa32SChristian Ulmann     return BoolAttr(nullptr);
117b83caa32SChristian Ulmann 
118b83caa32SChristian Ulmann   if (property->getNumOperands() != 1)
119b83caa32SChristian Ulmann     return emitWarning(loc)
120b83caa32SChristian Ulmann            << "expected metadata node " << name << " to hold no value";
121b83caa32SChristian Ulmann 
122b83caa32SChristian Ulmann   return BoolAttr::get(ctx, true);
123b83caa32SChristian Ulmann }
124b83caa32SChristian Ulmann 
lookupBooleanUnitNode(StringRef enableName,StringRef disableName,bool negated)125b83caa32SChristian Ulmann FailureOr<BoolAttr> LoopMetadataConversion::lookupBooleanUnitNode(
126b83caa32SChristian Ulmann     StringRef enableName, StringRef disableName, bool negated) {
127b83caa32SChristian Ulmann   auto enable = lookupUnitNode(enableName);
128b83caa32SChristian Ulmann   auto disable = lookupUnitNode(disableName);
129b83caa32SChristian Ulmann   if (failed(enable) || failed(disable))
130b83caa32SChristian Ulmann     return failure();
131b83caa32SChristian Ulmann 
132b83caa32SChristian Ulmann   if (*enable && *disable)
133b83caa32SChristian Ulmann     return emitWarning(loc)
134b83caa32SChristian Ulmann            << "expected metadata nodes " << enableName << " and " << disableName
135b83caa32SChristian Ulmann            << " to be mutually exclusive.";
136b83caa32SChristian Ulmann 
137b83caa32SChristian Ulmann   if (*enable)
138b83caa32SChristian Ulmann     return BoolAttr::get(ctx, !negated);
139b83caa32SChristian Ulmann 
140b83caa32SChristian Ulmann   if (*disable)
141b83caa32SChristian Ulmann     return BoolAttr::get(ctx, negated);
142b83caa32SChristian Ulmann   return BoolAttr(nullptr);
143b83caa32SChristian Ulmann }
144b83caa32SChristian Ulmann 
lookupBoolNode(StringRef name,bool negated)145b83caa32SChristian Ulmann FailureOr<BoolAttr> LoopMetadataConversion::lookupBoolNode(StringRef name,
146b83caa32SChristian Ulmann                                                            bool negated) {
147b83caa32SChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
148b83caa32SChristian Ulmann   if (!property)
149b83caa32SChristian Ulmann     return BoolAttr(nullptr);
150b83caa32SChristian Ulmann 
151b83caa32SChristian Ulmann   auto emitNodeWarning = [&]() {
152b83caa32SChristian Ulmann     return emitWarning(loc)
153b83caa32SChristian Ulmann            << "expected metadata node " << name << " to hold a boolean value";
154b83caa32SChristian Ulmann   };
155b83caa32SChristian Ulmann 
156b83caa32SChristian Ulmann   if (property->getNumOperands() != 2)
157b83caa32SChristian Ulmann     return emitNodeWarning();
158b83caa32SChristian Ulmann   llvm::ConstantInt *val =
159b83caa32SChristian Ulmann       llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
160b83caa32SChristian Ulmann   if (!val || val->getBitWidth() != 1)
161b83caa32SChristian Ulmann     return emitNodeWarning();
162b83caa32SChristian Ulmann 
163b83caa32SChristian Ulmann   return BoolAttr::get(ctx, val->getValue().getLimitedValue(1) ^ negated);
164b83caa32SChristian Ulmann }
165b83caa32SChristian Ulmann 
1664d7c879dSChristian Ulmann FailureOr<BoolAttr>
lookupIntNodeAsBoolAttr(StringRef name)1674d7c879dSChristian Ulmann LoopMetadataConversion::lookupIntNodeAsBoolAttr(StringRef name) {
1684d7c879dSChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
1694d7c879dSChristian Ulmann   if (!property)
1704d7c879dSChristian Ulmann     return BoolAttr(nullptr);
1714d7c879dSChristian Ulmann 
1724d7c879dSChristian Ulmann   auto emitNodeWarning = [&]() {
1734d7c879dSChristian Ulmann     return emitWarning(loc)
1744d7c879dSChristian Ulmann            << "expected metadata node " << name << " to hold an integer value";
1754d7c879dSChristian Ulmann   };
1764d7c879dSChristian Ulmann 
1774d7c879dSChristian Ulmann   if (property->getNumOperands() != 2)
1784d7c879dSChristian Ulmann     return emitNodeWarning();
1794d7c879dSChristian Ulmann   llvm::ConstantInt *val =
1804d7c879dSChristian Ulmann       llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
1814d7c879dSChristian Ulmann   if (!val || val->getBitWidth() != 32)
1824d7c879dSChristian Ulmann     return emitNodeWarning();
1834d7c879dSChristian Ulmann 
1844d7c879dSChristian Ulmann   return BoolAttr::get(ctx, val->getValue().getLimitedValue(1));
1854d7c879dSChristian Ulmann }
1864d7c879dSChristian Ulmann 
lookupIntNode(StringRef name)187b83caa32SChristian Ulmann FailureOr<IntegerAttr> LoopMetadataConversion::lookupIntNode(StringRef name) {
188b83caa32SChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
189b83caa32SChristian Ulmann   if (!property)
190b83caa32SChristian Ulmann     return IntegerAttr(nullptr);
191b83caa32SChristian Ulmann 
192b83caa32SChristian Ulmann   auto emitNodeWarning = [&]() {
193b83caa32SChristian Ulmann     return emitWarning(loc)
194b83caa32SChristian Ulmann            << "expected metadata node " << name << " to hold an i32 value";
195b83caa32SChristian Ulmann   };
196b83caa32SChristian Ulmann 
197b83caa32SChristian Ulmann   if (property->getNumOperands() != 2)
198b83caa32SChristian Ulmann     return emitNodeWarning();
199b83caa32SChristian Ulmann 
200b83caa32SChristian Ulmann   llvm::ConstantInt *val =
201b83caa32SChristian Ulmann       llvm::mdconst::dyn_extract<llvm::ConstantInt>(property->getOperand(1));
202b83caa32SChristian Ulmann   if (!val || val->getBitWidth() != 32)
203b83caa32SChristian Ulmann     return emitNodeWarning();
204b83caa32SChristian Ulmann 
205b83caa32SChristian Ulmann   return IntegerAttr::get(IntegerType::get(ctx, 32),
206b83caa32SChristian Ulmann                           val->getValue().getLimitedValue());
207b83caa32SChristian Ulmann }
208b83caa32SChristian Ulmann 
lookupMDNode(StringRef name)209b83caa32SChristian Ulmann FailureOr<llvm::MDNode *> LoopMetadataConversion::lookupMDNode(StringRef name) {
210b83caa32SChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
211b83caa32SChristian Ulmann   if (!property)
212b83caa32SChristian Ulmann     return nullptr;
213b83caa32SChristian Ulmann 
214b83caa32SChristian Ulmann   auto emitNodeWarning = [&]() {
215b83caa32SChristian Ulmann     return emitWarning(loc)
216b83caa32SChristian Ulmann            << "expected metadata node " << name << " to hold an MDNode";
217b83caa32SChristian Ulmann   };
218b83caa32SChristian Ulmann 
219b83caa32SChristian Ulmann   if (property->getNumOperands() != 2)
220b83caa32SChristian Ulmann     return emitNodeWarning();
221b83caa32SChristian Ulmann 
222b83caa32SChristian Ulmann   auto *node = dyn_cast<llvm::MDNode>(property->getOperand(1));
223b83caa32SChristian Ulmann   if (!node)
224b83caa32SChristian Ulmann     return emitNodeWarning();
225b83caa32SChristian Ulmann 
226b83caa32SChristian Ulmann   return node;
227b83caa32SChristian Ulmann }
228b83caa32SChristian Ulmann 
229b83caa32SChristian Ulmann FailureOr<SmallVector<llvm::MDNode *>>
lookupMDNodes(StringRef name)230b83caa32SChristian Ulmann LoopMetadataConversion::lookupMDNodes(StringRef name) {
231b83caa32SChristian Ulmann   const llvm::MDNode *property = lookupAndEraseProperty(name);
232b83caa32SChristian Ulmann   SmallVector<llvm::MDNode *> res;
233b83caa32SChristian Ulmann   if (!property)
234b83caa32SChristian Ulmann     return res;
235b83caa32SChristian Ulmann 
236b83caa32SChristian Ulmann   auto emitNodeWarning = [&]() {
237b83caa32SChristian Ulmann     return emitWarning(loc) << "expected metadata node " << name
238b83caa32SChristian Ulmann                             << " to hold one or multiple MDNodes";
239b83caa32SChristian Ulmann   };
240b83caa32SChristian Ulmann 
241b83caa32SChristian Ulmann   if (property->getNumOperands() < 2)
242b83caa32SChristian Ulmann     return emitNodeWarning();
243b83caa32SChristian Ulmann 
244b83caa32SChristian Ulmann   for (unsigned i = 1, e = property->getNumOperands(); i < e; ++i) {
245b83caa32SChristian Ulmann     auto *node = dyn_cast<llvm::MDNode>(property->getOperand(i));
246b83caa32SChristian Ulmann     if (!node)
247b83caa32SChristian Ulmann       return emitNodeWarning();
248b83caa32SChristian Ulmann     res.push_back(node);
249b83caa32SChristian Ulmann   }
250b83caa32SChristian Ulmann 
251b83caa32SChristian Ulmann   return res;
252b83caa32SChristian Ulmann }
253b83caa32SChristian Ulmann 
254b83caa32SChristian Ulmann FailureOr<LoopAnnotationAttr>
lookupFollowupNode(StringRef name)255b83caa32SChristian Ulmann LoopMetadataConversion::lookupFollowupNode(StringRef name) {
256b83caa32SChristian Ulmann   auto node = lookupMDNode(name);
257b83caa32SChristian Ulmann   if (failed(node))
258b83caa32SChristian Ulmann     return failure();
259b83caa32SChristian Ulmann   if (*node == nullptr)
260b83caa32SChristian Ulmann     return LoopAnnotationAttr(nullptr);
261b83caa32SChristian Ulmann 
262e630a502SChristian Ulmann   return loopAnnotationImporter.translateLoopAnnotation(*node, loc);
263b83caa32SChristian Ulmann }
264b83caa32SChristian Ulmann 
isEmptyOrNull(const Attribute attr)265b83caa32SChristian Ulmann static bool isEmptyOrNull(const Attribute attr) { return !attr; }
266b83caa32SChristian Ulmann 
267b83caa32SChristian Ulmann template <typename T>
isEmptyOrNull(const SmallVectorImpl<T> & vec)268b83caa32SChristian Ulmann static bool isEmptyOrNull(const SmallVectorImpl<T> &vec) {
269b83caa32SChristian Ulmann   return vec.empty();
270b83caa32SChristian Ulmann }
271b83caa32SChristian Ulmann 
272b83caa32SChristian Ulmann /// Helper function that only creates and attribute of type T if all argument
273b83caa32SChristian Ulmann /// conversion were successfull and at least one of them holds a non-null value.
274b83caa32SChristian Ulmann template <typename T, typename... P>
createIfNonNull(MLIRContext * ctx,const P &...args)275b83caa32SChristian Ulmann static T createIfNonNull(MLIRContext *ctx, const P &...args) {
276b83caa32SChristian Ulmann   bool anyFailed = (failed(args) || ...);
277b83caa32SChristian Ulmann   if (anyFailed)
278b83caa32SChristian Ulmann     return {};
279b83caa32SChristian Ulmann 
280b83caa32SChristian Ulmann   bool allEmpty = (isEmptyOrNull(*args) && ...);
281b83caa32SChristian Ulmann   if (allEmpty)
282b83caa32SChristian Ulmann     return {};
283b83caa32SChristian Ulmann 
284b83caa32SChristian Ulmann   return T::get(ctx, *args...);
285b83caa32SChristian Ulmann }
286b83caa32SChristian Ulmann 
convertVectorizeAttr()287b83caa32SChristian Ulmann FailureOr<LoopVectorizeAttr> LoopMetadataConversion::convertVectorizeAttr() {
288b83caa32SChristian Ulmann   FailureOr<BoolAttr> enable =
289b83caa32SChristian Ulmann       lookupBoolNode("llvm.loop.vectorize.enable", true);
290b83caa32SChristian Ulmann   FailureOr<BoolAttr> predicateEnable =
291b83caa32SChristian Ulmann       lookupBoolNode("llvm.loop.vectorize.predicate.enable");
292b83caa32SChristian Ulmann   FailureOr<BoolAttr> scalableEnable =
293b83caa32SChristian Ulmann       lookupBoolNode("llvm.loop.vectorize.scalable.enable");
294b83caa32SChristian Ulmann   FailureOr<IntegerAttr> width = lookupIntNode("llvm.loop.vectorize.width");
295b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupVec =
296b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.vectorize.followup_vectorized");
297b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupEpi =
298b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.vectorize.followup_epilogue");
299b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupAll =
300b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.vectorize.followup_all");
301b83caa32SChristian Ulmann 
302b83caa32SChristian Ulmann   return createIfNonNull<LoopVectorizeAttr>(ctx, enable, predicateEnable,
303b83caa32SChristian Ulmann                                             scalableEnable, width, followupVec,
304b83caa32SChristian Ulmann                                             followupEpi, followupAll);
305b83caa32SChristian Ulmann }
306b83caa32SChristian Ulmann 
convertInterleaveAttr()307b83caa32SChristian Ulmann FailureOr<LoopInterleaveAttr> LoopMetadataConversion::convertInterleaveAttr() {
308b83caa32SChristian Ulmann   FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.interleave.count");
309b83caa32SChristian Ulmann   return createIfNonNull<LoopInterleaveAttr>(ctx, count);
310b83caa32SChristian Ulmann }
311b83caa32SChristian Ulmann 
convertUnrollAttr()312b83caa32SChristian Ulmann FailureOr<LoopUnrollAttr> LoopMetadataConversion::convertUnrollAttr() {
313b83caa32SChristian Ulmann   FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
314b83caa32SChristian Ulmann       "llvm.loop.unroll.enable", "llvm.loop.unroll.disable", /*negated=*/true);
315b83caa32SChristian Ulmann   FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.unroll.count");
316b83caa32SChristian Ulmann   FailureOr<BoolAttr> runtimeDisable =
317b83caa32SChristian Ulmann       lookupUnitNode("llvm.loop.unroll.runtime.disable");
318b83caa32SChristian Ulmann   FailureOr<BoolAttr> full = lookupUnitNode("llvm.loop.unroll.full");
3194d7c879dSChristian Ulmann   FailureOr<LoopAnnotationAttr> followupUnrolled =
3204d7c879dSChristian Ulmann       lookupFollowupNode("llvm.loop.unroll.followup_unrolled");
321b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupRemainder =
322b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll.followup_remainder");
3234d7c879dSChristian Ulmann   FailureOr<LoopAnnotationAttr> followupAll =
3244d7c879dSChristian Ulmann       lookupFollowupNode("llvm.loop.unroll.followup_all");
325b83caa32SChristian Ulmann 
326b83caa32SChristian Ulmann   return createIfNonNull<LoopUnrollAttr>(ctx, disable, count, runtimeDisable,
3274d7c879dSChristian Ulmann                                          full, followupUnrolled,
3284d7c879dSChristian Ulmann                                          followupRemainder, followupAll);
329b83caa32SChristian Ulmann }
330b83caa32SChristian Ulmann 
331b83caa32SChristian Ulmann FailureOr<LoopUnrollAndJamAttr>
convertUnrollAndJamAttr()332b83caa32SChristian Ulmann LoopMetadataConversion::convertUnrollAndJamAttr() {
333b83caa32SChristian Ulmann   FailureOr<BoolAttr> disable = lookupBooleanUnitNode(
334b83caa32SChristian Ulmann       "llvm.loop.unroll_and_jam.enable", "llvm.loop.unroll_and_jam.disable",
335b83caa32SChristian Ulmann       /*negated=*/true);
336b83caa32SChristian Ulmann   FailureOr<IntegerAttr> count =
337b83caa32SChristian Ulmann       lookupIntNode("llvm.loop.unroll_and_jam.count");
338b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupOuter =
339b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll_and_jam.followup_outer");
340b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupInner =
341b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll_and_jam.followup_inner");
342b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupRemainderOuter =
343b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_outer");
344b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupRemainderInner =
345b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_inner");
346b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupAll =
347b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.unroll_and_jam.followup_all");
348b83caa32SChristian Ulmann   return createIfNonNull<LoopUnrollAndJamAttr>(
349b83caa32SChristian Ulmann       ctx, disable, count, followupOuter, followupInner, followupRemainderOuter,
350b83caa32SChristian Ulmann       followupRemainderInner, followupAll);
351b83caa32SChristian Ulmann }
352b83caa32SChristian Ulmann 
convertLICMAttr()353b83caa32SChristian Ulmann FailureOr<LoopLICMAttr> LoopMetadataConversion::convertLICMAttr() {
354b83caa32SChristian Ulmann   FailureOr<BoolAttr> disable = lookupUnitNode("llvm.licm.disable");
355b83caa32SChristian Ulmann   FailureOr<BoolAttr> versioningDisable =
356b83caa32SChristian Ulmann       lookupUnitNode("llvm.loop.licm_versioning.disable");
357b83caa32SChristian Ulmann   return createIfNonNull<LoopLICMAttr>(ctx, disable, versioningDisable);
358b83caa32SChristian Ulmann }
359b83caa32SChristian Ulmann 
convertDistributeAttr()360b83caa32SChristian Ulmann FailureOr<LoopDistributeAttr> LoopMetadataConversion::convertDistributeAttr() {
361b83caa32SChristian Ulmann   FailureOr<BoolAttr> disable =
362b83caa32SChristian Ulmann       lookupBoolNode("llvm.loop.distribute.enable", true);
363b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupCoincident =
364b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.distribute.followup_coincident");
365b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupSequential =
366b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.distribute.followup_sequential");
367b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupFallback =
368b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.distribute.followup_fallback");
369b83caa32SChristian Ulmann   FailureOr<LoopAnnotationAttr> followupAll =
370b83caa32SChristian Ulmann       lookupFollowupNode("llvm.loop.distribute.followup_all");
371b83caa32SChristian Ulmann   return createIfNonNull<LoopDistributeAttr>(ctx, disable, followupCoincident,
372b83caa32SChristian Ulmann                                              followupSequential,
373b83caa32SChristian Ulmann                                              followupFallback, followupAll);
374b83caa32SChristian Ulmann }
375b83caa32SChristian Ulmann 
convertPipelineAttr()376b83caa32SChristian Ulmann FailureOr<LoopPipelineAttr> LoopMetadataConversion::convertPipelineAttr() {
377b83caa32SChristian Ulmann   FailureOr<BoolAttr> disable = lookupBoolNode("llvm.loop.pipeline.disable");
378b83caa32SChristian Ulmann   FailureOr<IntegerAttr> initiationinterval =
379b83caa32SChristian Ulmann       lookupIntNode("llvm.loop.pipeline.initiationinterval");
380b83caa32SChristian Ulmann   return createIfNonNull<LoopPipelineAttr>(ctx, disable, initiationinterval);
381b83caa32SChristian Ulmann }
382b83caa32SChristian Ulmann 
convertPeeledAttr()3837f249e45SChristian Ulmann FailureOr<LoopPeeledAttr> LoopMetadataConversion::convertPeeledAttr() {
3847f249e45SChristian Ulmann   FailureOr<IntegerAttr> count = lookupIntNode("llvm.loop.peeled.count");
3857f249e45SChristian Ulmann   return createIfNonNull<LoopPeeledAttr>(ctx, count);
3867f249e45SChristian Ulmann }
3877f249e45SChristian Ulmann 
convertUnswitchAttr()3887f249e45SChristian Ulmann FailureOr<LoopUnswitchAttr> LoopMetadataConversion::convertUnswitchAttr() {
3897f249e45SChristian Ulmann   FailureOr<BoolAttr> partialDisable =
3907f249e45SChristian Ulmann       lookupUnitNode("llvm.loop.unswitch.partial.disable");
3917f249e45SChristian Ulmann   return createIfNonNull<LoopUnswitchAttr>(ctx, partialDisable);
3927f249e45SChristian Ulmann }
3937f249e45SChristian Ulmann 
3949170fa58SMarkus Böck FailureOr<SmallVector<AccessGroupAttr>>
convertParallelAccesses()395b83caa32SChristian Ulmann LoopMetadataConversion::convertParallelAccesses() {
396b83caa32SChristian Ulmann   FailureOr<SmallVector<llvm::MDNode *>> nodes =
397b83caa32SChristian Ulmann       lookupMDNodes("llvm.loop.parallel_accesses");
398b83caa32SChristian Ulmann   if (failed(nodes))
399b83caa32SChristian Ulmann     return failure();
4009170fa58SMarkus Böck   SmallVector<AccessGroupAttr> refs;
401b83caa32SChristian Ulmann   for (llvm::MDNode *node : *nodes) {
4029170fa58SMarkus Böck     FailureOr<SmallVector<AccessGroupAttr>> accessGroups =
403e630a502SChristian Ulmann         loopAnnotationImporter.lookupAccessGroupAttrs(node);
4046600301cSTobias Gysi     if (failed(accessGroups)) {
4056600301cSTobias Gysi       emitWarning(loc) << "could not lookup access group";
4066600301cSTobias Gysi       continue;
4076600301cSTobias Gysi     }
408b83caa32SChristian Ulmann     llvm::append_range(refs, *accessGroups);
409b83caa32SChristian Ulmann   }
410b83caa32SChristian Ulmann   return refs;
411b83caa32SChristian Ulmann }
412b83caa32SChristian Ulmann 
convertStartLoc()41362d7d94cSChristian Ulmann FusedLoc LoopMetadataConversion::convertStartLoc() {
41462d7d94cSChristian Ulmann   if (locations.empty())
41562d7d94cSChristian Ulmann     return {};
41662d7d94cSChristian Ulmann   return dyn_cast<FusedLoc>(
41762d7d94cSChristian Ulmann       loopAnnotationImporter.moduleImport.translateLoc(locations[0]));
41862d7d94cSChristian Ulmann }
41962d7d94cSChristian Ulmann 
convertEndLoc()42062d7d94cSChristian Ulmann FailureOr<FusedLoc> LoopMetadataConversion::convertEndLoc() {
42162d7d94cSChristian Ulmann   if (locations.size() < 2)
42262d7d94cSChristian Ulmann     return FusedLoc();
42362d7d94cSChristian Ulmann   if (locations.size() > 2)
42462d7d94cSChristian Ulmann     return emitError(loc)
42562d7d94cSChristian Ulmann            << "expected loop metadata to have at most two DILocations";
42662d7d94cSChristian Ulmann   return dyn_cast<FusedLoc>(
42762d7d94cSChristian Ulmann       loopAnnotationImporter.moduleImport.translateLoc(locations[1]));
42862d7d94cSChristian Ulmann }
42962d7d94cSChristian Ulmann 
convert()430b83caa32SChristian Ulmann LoopAnnotationAttr LoopMetadataConversion::convert() {
43162d7d94cSChristian Ulmann   if (failed(initConversionState()))
432b83caa32SChristian Ulmann     return {};
433b83caa32SChristian Ulmann 
434b83caa32SChristian Ulmann   FailureOr<BoolAttr> disableNonForced =
435b83caa32SChristian Ulmann       lookupUnitNode("llvm.loop.disable_nonforced");
436b83caa32SChristian Ulmann   FailureOr<LoopVectorizeAttr> vecAttr = convertVectorizeAttr();
437b83caa32SChristian Ulmann   FailureOr<LoopInterleaveAttr> interleaveAttr = convertInterleaveAttr();
438b83caa32SChristian Ulmann   FailureOr<LoopUnrollAttr> unrollAttr = convertUnrollAttr();
439b83caa32SChristian Ulmann   FailureOr<LoopUnrollAndJamAttr> unrollAndJamAttr = convertUnrollAndJamAttr();
440b83caa32SChristian Ulmann   FailureOr<LoopLICMAttr> licmAttr = convertLICMAttr();
441b83caa32SChristian Ulmann   FailureOr<LoopDistributeAttr> distributeAttr = convertDistributeAttr();
442b83caa32SChristian Ulmann   FailureOr<LoopPipelineAttr> pipelineAttr = convertPipelineAttr();
4437f249e45SChristian Ulmann   FailureOr<LoopPeeledAttr> peeledAttr = convertPeeledAttr();
4447f249e45SChristian Ulmann   FailureOr<LoopUnswitchAttr> unswitchAttr = convertUnswitchAttr();
445b83caa32SChristian Ulmann   FailureOr<BoolAttr> mustProgress = lookupUnitNode("llvm.loop.mustprogress");
4464d7c879dSChristian Ulmann   FailureOr<BoolAttr> isVectorized =
4474d7c879dSChristian Ulmann       lookupIntNodeAsBoolAttr("llvm.loop.isvectorized");
4489170fa58SMarkus Böck   FailureOr<SmallVector<AccessGroupAttr>> parallelAccesses =
449b83caa32SChristian Ulmann       convertParallelAccesses();
450b83caa32SChristian Ulmann 
451b83caa32SChristian Ulmann   // Drop the metadata if there are parts that cannot be imported.
452b83caa32SChristian Ulmann   if (!propertyMap.empty()) {
453b83caa32SChristian Ulmann     for (auto name : propertyMap.keys())
454b83caa32SChristian Ulmann       emitWarning(loc) << "unknown loop annotation " << name;
455b83caa32SChristian Ulmann     return {};
456b83caa32SChristian Ulmann   }
457b83caa32SChristian Ulmann 
45862d7d94cSChristian Ulmann   FailureOr<FusedLoc> startLoc = convertStartLoc();
45962d7d94cSChristian Ulmann   FailureOr<FusedLoc> endLoc = convertEndLoc();
46062d7d94cSChristian Ulmann 
461b83caa32SChristian Ulmann   return createIfNonNull<LoopAnnotationAttr>(
462b83caa32SChristian Ulmann       ctx, disableNonForced, vecAttr, interleaveAttr, unrollAttr,
4637f249e45SChristian Ulmann       unrollAndJamAttr, licmAttr, distributeAttr, pipelineAttr, peeledAttr,
464*bd26ce47STobias Gysi       unswitchAttr, mustProgress, isVectorized, startLoc, endLoc,
465*bd26ce47STobias Gysi       parallelAccesses);
466b83caa32SChristian Ulmann }
467b83caa32SChristian Ulmann 
468e630a502SChristian Ulmann LoopAnnotationAttr
translateLoopAnnotation(const llvm::MDNode * node,Location loc)469e630a502SChristian Ulmann LoopAnnotationImporter::translateLoopAnnotation(const llvm::MDNode *node,
470b83caa32SChristian Ulmann                                                 Location loc) {
471b83caa32SChristian Ulmann   if (!node)
472b83caa32SChristian Ulmann     return {};
473b83caa32SChristian Ulmann 
474b83caa32SChristian Ulmann   // Note: This check is necessary to distinguish between failed translations
475b83caa32SChristian Ulmann   // and not yet attempted translations.
476b83caa32SChristian Ulmann   auto it = loopMetadataMapping.find(node);
477b83caa32SChristian Ulmann   if (it != loopMetadataMapping.end())
478b83caa32SChristian Ulmann     return it->getSecond();
479b83caa32SChristian Ulmann 
480e630a502SChristian Ulmann   LoopAnnotationAttr attr = LoopMetadataConversion(node, loc, *this).convert();
481b83caa32SChristian Ulmann 
482b83caa32SChristian Ulmann   mapLoopMetadata(node, attr);
483b83caa32SChristian Ulmann   return attr;
484b83caa32SChristian Ulmann }
485e630a502SChristian Ulmann 
4869170fa58SMarkus Böck LogicalResult
translateAccessGroup(const llvm::MDNode * node,Location loc)4879170fa58SMarkus Böck LoopAnnotationImporter::translateAccessGroup(const llvm::MDNode *node,
4889170fa58SMarkus Böck                                              Location loc) {
489e630a502SChristian Ulmann   SmallVector<const llvm::MDNode *> accessGroups;
490e630a502SChristian Ulmann   if (!node->getNumOperands())
491e630a502SChristian Ulmann     accessGroups.push_back(node);
492e630a502SChristian Ulmann   for (const llvm::MDOperand &operand : node->operands()) {
493e630a502SChristian Ulmann     auto *childNode = dyn_cast<llvm::MDNode>(operand);
494e630a502SChristian Ulmann     if (!childNode)
495bf91cd6eSChristian Ulmann       return failure();
496e630a502SChristian Ulmann     accessGroups.push_back(cast<llvm::MDNode>(operand.get()));
497e630a502SChristian Ulmann   }
498e630a502SChristian Ulmann 
499e630a502SChristian Ulmann   // Convert all entries of the access group list to access group operations.
500e630a502SChristian Ulmann   for (const llvm::MDNode *accessGroup : accessGroups) {
501e630a502SChristian Ulmann     if (accessGroupMapping.count(accessGroup))
502e630a502SChristian Ulmann       continue;
503e630a502SChristian Ulmann     // Verify the access group node is distinct and empty.
504e630a502SChristian Ulmann     if (accessGroup->getNumOperands() != 0 || !accessGroup->isDistinct())
505e630a502SChristian Ulmann       return emitWarning(loc)
506e630a502SChristian Ulmann              << "expected an access group node to be empty and distinct";
507e630a502SChristian Ulmann 
5089170fa58SMarkus Böck     // Add a mapping from the access group node to the newly created attribute.
5099170fa58SMarkus Böck     accessGroupMapping[accessGroup] = builder.getAttr<AccessGroupAttr>();
510e630a502SChristian Ulmann   }
511e630a502SChristian Ulmann   return success();
512e630a502SChristian Ulmann }
513e630a502SChristian Ulmann 
5149170fa58SMarkus Böck FailureOr<SmallVector<AccessGroupAttr>>
lookupAccessGroupAttrs(const llvm::MDNode * node) const515e630a502SChristian Ulmann LoopAnnotationImporter::lookupAccessGroupAttrs(const llvm::MDNode *node) const {
516e630a502SChristian Ulmann   // An access group node is either a single access group or an access group
517e630a502SChristian Ulmann   // list.
5189170fa58SMarkus Böck   SmallVector<AccessGroupAttr> accessGroups;
519e630a502SChristian Ulmann   if (!node->getNumOperands())
520e630a502SChristian Ulmann     accessGroups.push_back(accessGroupMapping.lookup(node));
521e630a502SChristian Ulmann   for (const llvm::MDOperand &operand : node->operands()) {
522e630a502SChristian Ulmann     auto *node = cast<llvm::MDNode>(operand.get());
523e630a502SChristian Ulmann     accessGroups.push_back(accessGroupMapping.lookup(node));
524e630a502SChristian Ulmann   }
525e630a502SChristian Ulmann   // Exit if one of the access group node lookups failed.
526e630a502SChristian Ulmann   if (llvm::is_contained(accessGroups, nullptr))
527e630a502SChristian Ulmann     return failure();
528e630a502SChristian Ulmann   return accessGroups;
529e630a502SChristian Ulmann }
530