MLIR 24.0.0git
LoopAnnotationTranslation.cpp
Go to the documentation of this file.
1//===- LoopAnnotationTranslation.cpp - Loop annotation export -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/IR/DebugInfoMetadata.h"
11
12using namespace mlir;
13using namespace mlir::LLVM;
14using namespace mlir::LLVM::detail;
15
16namespace {
17/// Helper class that keeps the state of one attribute to metadata conversion.
18struct LoopAnnotationConversion {
19 LoopAnnotationConversion(LoopAnnotationAttr attr, Operation *op,
20 LoopAnnotationTranslation &loopAnnotationTranslation,
21 llvm::LLVMContext &ctx)
22 : attr(attr), op(op),
23 loopAnnotationTranslation(loopAnnotationTranslation), ctx(ctx) {}
24
25 /// Converts this struct's loop annotation into a corresponding LLVMIR
26 /// metadata representation.
27 llvm::MDNode *convert();
28
29 /// Conversion functions for different payload attribute kinds.
30 void addUnitNode(StringRef name);
31 void addUnitNode(StringRef name, BoolAttr attr);
32 void addI32NodeWithVal(StringRef name, uint32_t val);
33 void convertBoolNode(StringRef name, BoolAttr attr, bool negated = false);
34 void convertBooleanUnitNode(StringRef enableName, StringRef disableName,
35 BoolAttr attr, bool negated = false);
36 void convertI32Node(StringRef name, IntegerAttr attr);
37 void convertFollowupNode(StringRef name, LoopAnnotationAttr attr);
38 void convertLocation(FusedLoc attr);
39
40 /// Conversion functions for each for each loop annotation sub-attribute.
41 void convertLoopOptions(LoopVectorizeAttr options);
42 void convertLoopOptions(LoopInterleaveAttr options);
43 void convertLoopOptions(LoopUnrollAttr options);
44 void convertLoopOptions(LoopUnrollAndJamAttr options);
45 void convertLoopOptions(LoopLICMAttr options);
46 void convertLoopOptions(LoopDistributeAttr options);
47 void convertLoopOptions(LoopPipelineAttr options);
48 void convertLoopOptions(LoopPeeledAttr options);
49 void convertLoopOptions(LoopUnswitchAttr options);
50
51 LoopAnnotationAttr attr;
52 Operation *op;
53 LoopAnnotationTranslation &loopAnnotationTranslation;
54 llvm::LLVMContext &ctx;
55 llvm::SmallVector<llvm::Metadata *> metadataNodes;
56};
57} // namespace
58
59void LoopAnnotationConversion::addUnitNode(StringRef name) {
60 metadataNodes.push_back(
61 llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name)}));
62}
63
64void LoopAnnotationConversion::addUnitNode(StringRef name, BoolAttr attr) {
65 if (attr && attr.getValue())
66 addUnitNode(name);
67}
68
69void LoopAnnotationConversion::addI32NodeWithVal(StringRef name, uint32_t val) {
70 llvm::Constant *cstValue = llvm::ConstantInt::get(
71 llvm::IntegerType::get(ctx, /*NumBits=*/32), val, /*isSigned=*/false);
72 metadataNodes.push_back(
73 llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name),
74 llvm::ConstantAsMetadata::get(cstValue)}));
75}
76
77void LoopAnnotationConversion::convertBoolNode(StringRef name, BoolAttr attr,
78 bool negated) {
79 if (!attr)
80 return;
81 bool val = negated ^ attr.getValue();
82 llvm::Constant *cstValue = llvm::ConstantInt::getBool(ctx, val);
83 metadataNodes.push_back(
84 llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name),
85 llvm::ConstantAsMetadata::get(cstValue)}));
86}
87
88/// Emits the single-operand node of an enable/disable pair. As in
89/// convertBoolNode, the attribute is tri-state: a null \p attr emits no node
90/// at all, otherwise \p negated ^ the attribute value is the enable bit and
91/// selects which of the two names is emitted.
92void LoopAnnotationConversion::convertBooleanUnitNode(StringRef enableName,
93 StringRef disableName,
94 BoolAttr attr,
95 bool negated) {
96 if (!attr)
97 return;
98 addUnitNode((negated ^ attr.getValue()) ? enableName : disableName);
99}
100
101void LoopAnnotationConversion::convertI32Node(StringRef name,
102 IntegerAttr attr) {
103 if (!attr)
104 return;
105 addI32NodeWithVal(name, attr.getInt());
106}
107
108void LoopAnnotationConversion::convertFollowupNode(StringRef name,
109 LoopAnnotationAttr attr) {
110 if (!attr)
111 return;
112
113 llvm::MDNode *node =
114 loopAnnotationTranslation.translateLoopAnnotation(attr, op);
115
116 metadataNodes.push_back(
117 llvm::MDNode::get(ctx, {llvm::MDString::get(ctx, name), node}));
118}
119
120void LoopAnnotationConversion::convertLoopOptions(LoopVectorizeAttr options) {
121 convertBooleanUnitNode("llvm.loop.vectorize.enable",
122 "llvm.loop.vectorize.disable", options.getDisable(),
123 /*negated=*/true);
124 convertBooleanUnitNode("llvm.loop.vectorize.predicate.enable",
125 "llvm.loop.vectorize.predicate.disable",
126 options.getPredicateEnable());
127 convertBooleanUnitNode("llvm.loop.vectorize.scalable.enable",
128 "llvm.loop.vectorize.scalable.disable",
129 options.getScalableEnable());
130 convertI32Node("llvm.loop.vectorize.width", options.getWidth());
131 convertFollowupNode("llvm.loop.vectorize.followup_vectorized",
132 options.getFollowupVectorized());
133 convertFollowupNode("llvm.loop.vectorize.followup_epilogue",
134 options.getFollowupEpilogue());
135 convertFollowupNode("llvm.loop.vectorize.followup_all",
136 options.getFollowupAll());
137}
138
139void LoopAnnotationConversion::convertLoopOptions(LoopInterleaveAttr options) {
140 convertI32Node("llvm.loop.interleave.count", options.getCount());
141}
142
143void LoopAnnotationConversion::convertLoopOptions(LoopUnrollAttr options) {
144 if (auto disable = options.getDisable())
145 addUnitNode(disable.getValue() ? "llvm.loop.unroll.disable"
146 : "llvm.loop.unroll.enable");
147 convertI32Node("llvm.loop.unroll.count", options.getCount());
148 convertBoolNode("llvm.loop.unroll.runtime.disable",
149 options.getRuntimeDisable());
150 addUnitNode("llvm.loop.unroll.full", options.getFull());
151 convertFollowupNode("llvm.loop.unroll.followup_unrolled",
152 options.getFollowupUnrolled());
153 convertFollowupNode("llvm.loop.unroll.followup_remainder",
154 options.getFollowupRemainder());
155 convertFollowupNode("llvm.loop.unroll.followup_all",
156 options.getFollowupAll());
157}
158
159void LoopAnnotationConversion::convertLoopOptions(
160 LoopUnrollAndJamAttr options) {
161 if (auto disable = options.getDisable())
162 addUnitNode(disable.getValue() ? "llvm.loop.unroll_and_jam.disable"
163 : "llvm.loop.unroll_and_jam.enable");
164 convertI32Node("llvm.loop.unroll_and_jam.count", options.getCount());
165 convertFollowupNode("llvm.loop.unroll_and_jam.followup_outer",
166 options.getFollowupOuter());
167 convertFollowupNode("llvm.loop.unroll_and_jam.followup_inner",
168 options.getFollowupInner());
169 convertFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_outer",
170 options.getFollowupRemainderOuter());
171 convertFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_inner",
172 options.getFollowupRemainderInner());
173 convertFollowupNode("llvm.loop.unroll_and_jam.followup_all",
174 options.getFollowupAll());
175}
176
177void LoopAnnotationConversion::convertLoopOptions(LoopLICMAttr options) {
178 addUnitNode("llvm.licm.disable", options.getDisable());
179 addUnitNode("llvm.loop.licm_versioning.disable",
180 options.getVersioningDisable());
181}
182
183void LoopAnnotationConversion::convertLoopOptions(LoopDistributeAttr options) {
184 convertBooleanUnitNode("llvm.loop.distribute.enable",
185 "llvm.loop.distribute.disable", options.getDisable(),
186 /*negated=*/true);
187 convertFollowupNode("llvm.loop.distribute.followup_coincident",
188 options.getFollowupCoincident());
189 convertFollowupNode("llvm.loop.distribute.followup_sequential",
190 options.getFollowupSequential());
191 convertFollowupNode("llvm.loop.distribute.followup_fallback",
192 options.getFollowupFallback());
193 convertFollowupNode("llvm.loop.distribute.followup_all",
194 options.getFollowupAll());
195}
196
197void LoopAnnotationConversion::convertLoopOptions(LoopPipelineAttr options) {
198 convertBoolNode("llvm.loop.pipeline.disable", options.getDisable());
199 convertI32Node("llvm.loop.pipeline.initiationinterval",
200 options.getInitiationinterval());
201}
202
203void LoopAnnotationConversion::convertLoopOptions(LoopPeeledAttr options) {
204 convertI32Node("llvm.loop.peeled.count", options.getCount());
205}
206
207void LoopAnnotationConversion::convertLoopOptions(LoopUnswitchAttr options) {
208 addUnitNode("llvm.loop.unswitch.partial.disable",
209 options.getPartialDisable());
210}
211
212void LoopAnnotationConversion::convertLocation(FusedLoc location) {
213 auto localScopeAttr =
214 dyn_cast_or_null<DILocalScopeAttr>(location.getMetadata());
215 if (!localScopeAttr)
216 return;
217 auto *localScope = dyn_cast<llvm::DILocalScope>(
218 loopAnnotationTranslation.moduleTranslation.translateDebugInfo(
219 localScopeAttr));
220 if (!localScope)
221 return;
222 llvm::Metadata *loc =
223 loopAnnotationTranslation.moduleTranslation.translateLoc(location,
224 localScope);
225 metadataNodes.push_back(loc);
226}
227
228llvm::MDNode *LoopAnnotationConversion::convert() {
229 // Reserve operand 0 for loop id self reference.
230 auto dummy = llvm::MDNode::getTemporary(ctx, {});
231 metadataNodes.push_back(dummy.get());
232
233 if (FusedLoc startLoc = attr.getStartLoc())
234 convertLocation(startLoc);
235
236 if (FusedLoc endLoc = attr.getEndLoc())
237 convertLocation(endLoc);
238
239 addUnitNode("llvm.loop.disable_nonforced", attr.getDisableNonforced());
240 addUnitNode("llvm.loop.mustprogress", attr.getMustProgress());
241 // "isvectorized" is encoded as an i32 value.
242 if (BoolAttr isVectorized = attr.getIsVectorized())
243 addI32NodeWithVal("llvm.loop.isvectorized", isVectorized.getValue());
244
245 if (auto options = attr.getVectorize())
246 convertLoopOptions(options);
247 if (auto options = attr.getInterleave())
248 convertLoopOptions(options);
249 if (auto options = attr.getUnroll())
250 convertLoopOptions(options);
251 if (auto options = attr.getUnrollAndJam())
252 convertLoopOptions(options);
253 if (auto options = attr.getLicm())
254 convertLoopOptions(options);
255 if (auto options = attr.getDistribute())
256 convertLoopOptions(options);
257 if (auto options = attr.getPipeline())
258 convertLoopOptions(options);
259 if (auto options = attr.getPeeled())
260 convertLoopOptions(options);
261 if (auto options = attr.getUnswitch())
262 convertLoopOptions(options);
263
264 ArrayRef<AccessGroupAttr> parallelAccessGroups = attr.getParallelAccesses();
265 if (!parallelAccessGroups.empty()) {
266 SmallVector<llvm::Metadata *> parallelAccess;
267 parallelAccess.push_back(
268 llvm::MDString::get(ctx, "llvm.loop.parallel_accesses"));
269 for (AccessGroupAttr accessGroupAttr : parallelAccessGroups)
270 parallelAccess.push_back(
271 loopAnnotationTranslation.getAccessGroup(accessGroupAttr));
272 metadataNodes.push_back(llvm::MDNode::get(ctx, parallelAccess));
273 }
274
275 // Create loop options and set the first operand to itself.
276 llvm::MDNode *loopMD = llvm::MDNode::get(ctx, metadataNodes);
277 loopMD->replaceOperandWith(0, loopMD);
278
279 return loopMD;
280}
281
282llvm::MDNode *
284 Operation *op) {
285 if (!attr)
286 return nullptr;
287
288 llvm::MDNode *loopMD = lookupLoopMetadata(attr);
289 if (loopMD)
290 return loopMD;
291
292 loopMD =
293 LoopAnnotationConversion(attr, op, *this, this->llvmModule.getContext())
294 .convert();
295 // Store a map from this Attribute to the LLVM metadata in case we
296 // encounter it again.
297 mapLoopMetadata(attr, loopMD);
298 return loopMD;
299}
300
301llvm::MDNode *
302LoopAnnotationTranslation::getAccessGroup(AccessGroupAttr accessGroupAttr) {
303 auto [result, inserted] =
304 accessGroupMetadataMapping.try_emplace(accessGroupAttr);
305 if (inserted)
306 result->second = llvm::MDNode::getDistinct(llvmModule.getContext(), {});
307 return result->second;
308}
309
310llvm::MDNode *
312 ArrayAttr accessGroups = op.getAccessGroupsOrNull();
313 if (!accessGroups || accessGroups.empty())
314 return nullptr;
315
317 for (AccessGroupAttr group : accessGroups.getAsRange<AccessGroupAttr>())
318 groupMDs.push_back(getAccessGroup(group));
319 if (groupMDs.size() == 1)
320 return llvm::cast<llvm::MDNode>(groupMDs.front());
321 return llvm::MDNode::get(llvmModule.getContext(), groupMDs);
322}
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
static llvm::ManagedStatic< PassManagerOptions > options
bool getValue() const
Return the boolean value of this attribute.
llvm::DILocation * translateLoc(Location loc, llvm::DILocalScope *scope)
Translates the given location.
llvm::Metadata * translateDebugInfo(LLVM::DINodeAttr attr)
Translates the given LLVM debug info metadata.
llvm::MDNode * translateLoopAnnotation(LoopAnnotationAttr attr, Operation *op)
llvm::MDNode * getAccessGroups(AccessGroupOpInterface op)
Returns the LLVM metadata corresponding to the access group attribute referenced by the AccessGroupOp...
ModuleTranslation & moduleTranslation
The ModuleTranslation owning this instance.
llvm::MDNode * getAccessGroup(AccessGroupAttr accessGroupAttr)
Returns the LLVM metadata corresponding to an mlir LLVM dialect access group attribute.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
MLIRContext * getContext()
Return the context this operation is associated with.
Definition Operation.h:233
Include the generated interface declarations.