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