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 *loopID =
114 loopAnnotationTranslation.translateLoopAnnotation(attr, op);
115
116 // Follow-ups contain properties directly, without the LoopID self-reference.
117 SmallVector<llvm::Metadata *> operands;
118 operands.push_back(llvm::MDString::get(ctx, name));
119 for (const llvm::MDOperand &operand : llvm::drop_begin(loopID->operands()))
120 operands.push_back(operand.get());
121 metadataNodes.push_back(llvm::MDNode::get(ctx, operands));
122}
123
124void LoopAnnotationConversion::convertLoopOptions(LoopVectorizeAttr options) {
125 convertBooleanUnitNode("llvm.loop.vectorize.enable",
126 "llvm.loop.vectorize.disable", options.getDisable(),
127 /*negated=*/true);
128 convertBooleanUnitNode("llvm.loop.vectorize.predicate.enable",
129 "llvm.loop.vectorize.predicate.disable",
130 options.getPredicateEnable());
131 convertBooleanUnitNode("llvm.loop.vectorize.scalable.enable",
132 "llvm.loop.vectorize.scalable.disable",
133 options.getScalableEnable());
134 convertI32Node("llvm.loop.vectorize.width", options.getWidth());
135 convertFollowupNode("llvm.loop.vectorize.followup_vectorized",
136 options.getFollowupVectorized());
137 convertFollowupNode("llvm.loop.vectorize.followup_epilogue",
138 options.getFollowupEpilogue());
139 convertFollowupNode("llvm.loop.vectorize.followup_all",
140 options.getFollowupAll());
141}
142
143void LoopAnnotationConversion::convertLoopOptions(LoopInterleaveAttr options) {
144 convertI32Node("llvm.loop.interleave.count", options.getCount());
145}
146
147void LoopAnnotationConversion::convertLoopOptions(LoopUnrollAttr options) {
148 if (auto disable = options.getDisable())
149 addUnitNode(disable.getValue() ? "llvm.loop.unroll.disable"
150 : "llvm.loop.unroll.enable");
151 convertI32Node("llvm.loop.unroll.count", options.getCount());
152 convertBoolNode("llvm.loop.unroll.runtime.disable",
153 options.getRuntimeDisable());
154 addUnitNode("llvm.loop.unroll.full", options.getFull());
155 convertFollowupNode("llvm.loop.unroll.followup_unrolled",
156 options.getFollowupUnrolled());
157 convertFollowupNode("llvm.loop.unroll.followup_remainder",
158 options.getFollowupRemainder());
159 convertFollowupNode("llvm.loop.unroll.followup_all",
160 options.getFollowupAll());
161}
162
163void LoopAnnotationConversion::convertLoopOptions(
164 LoopUnrollAndJamAttr options) {
165 if (auto disable = options.getDisable())
166 addUnitNode(disable.getValue() ? "llvm.loop.unroll_and_jam.disable"
167 : "llvm.loop.unroll_and_jam.enable");
168 convertI32Node("llvm.loop.unroll_and_jam.count", options.getCount());
169 convertFollowupNode("llvm.loop.unroll_and_jam.followup_outer",
170 options.getFollowupOuter());
171 convertFollowupNode("llvm.loop.unroll_and_jam.followup_inner",
172 options.getFollowupInner());
173 convertFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_outer",
174 options.getFollowupRemainderOuter());
175 convertFollowupNode("llvm.loop.unroll_and_jam.followup_remainder_inner",
176 options.getFollowupRemainderInner());
177 convertFollowupNode("llvm.loop.unroll_and_jam.followup_all",
178 options.getFollowupAll());
179}
180
181void LoopAnnotationConversion::convertLoopOptions(LoopLICMAttr options) {
182 addUnitNode("llvm.licm.disable", options.getDisable());
183 addUnitNode("llvm.loop.licm_versioning.disable",
184 options.getVersioningDisable());
185}
186
187void LoopAnnotationConversion::convertLoopOptions(LoopDistributeAttr options) {
188 convertBooleanUnitNode("llvm.loop.distribute.enable",
189 "llvm.loop.distribute.disable", options.getDisable(),
190 /*negated=*/true);
191 convertFollowupNode("llvm.loop.distribute.followup_coincident",
192 options.getFollowupCoincident());
193 convertFollowupNode("llvm.loop.distribute.followup_sequential",
194 options.getFollowupSequential());
195 convertFollowupNode("llvm.loop.distribute.followup_fallback",
196 options.getFollowupFallback());
197 convertFollowupNode("llvm.loop.distribute.followup_all",
198 options.getFollowupAll());
199}
200
201void LoopAnnotationConversion::convertLoopOptions(LoopPipelineAttr options) {
202 convertBoolNode("llvm.loop.pipeline.disable", options.getDisable());
203 convertI32Node("llvm.loop.pipeline.initiationinterval",
204 options.getInitiationinterval());
205}
206
207void LoopAnnotationConversion::convertLoopOptions(LoopPeeledAttr options) {
208 convertI32Node("llvm.loop.peeled.count", options.getCount());
209}
210
211void LoopAnnotationConversion::convertLoopOptions(LoopUnswitchAttr options) {
212 addUnitNode("llvm.loop.unswitch.partial.disable",
213 options.getPartialDisable());
214}
215
216void LoopAnnotationConversion::convertLocation(FusedLoc location) {
217 auto localScopeAttr =
218 dyn_cast_or_null<DILocalScopeAttr>(location.getMetadata());
219 if (!localScopeAttr)
220 return;
221 auto *localScope = dyn_cast<llvm::DILocalScope>(
222 loopAnnotationTranslation.moduleTranslation.translateDebugInfo(
223 localScopeAttr));
224 if (!localScope)
225 return;
226 llvm::Metadata *loc =
227 loopAnnotationTranslation.moduleTranslation.translateLoc(location,
228 localScope);
229 metadataNodes.push_back(loc);
230}
231
232llvm::MDNode *LoopAnnotationConversion::convert() {
233 // Reserve operand 0 for loop id self reference.
234 auto dummy = llvm::MDNode::getTemporary(ctx, {});
235 metadataNodes.push_back(dummy.get());
236
237 if (FusedLoc startLoc = attr.getStartLoc())
238 convertLocation(startLoc);
239
240 if (FusedLoc endLoc = attr.getEndLoc())
241 convertLocation(endLoc);
242
243 addUnitNode("llvm.loop.disable_nonforced", attr.getDisableNonforced());
244 addUnitNode("llvm.loop.mustprogress", attr.getMustProgress());
245 // "isvectorized" is encoded as an i32 value.
246 if (BoolAttr isVectorized = attr.getIsVectorized())
247 addI32NodeWithVal("llvm.loop.isvectorized", isVectorized.getValue());
248
249 if (auto options = attr.getVectorize())
250 convertLoopOptions(options);
251 if (auto options = attr.getInterleave())
252 convertLoopOptions(options);
253 if (auto options = attr.getUnroll())
254 convertLoopOptions(options);
255 if (auto options = attr.getUnrollAndJam())
256 convertLoopOptions(options);
257 if (auto options = attr.getLicm())
258 convertLoopOptions(options);
259 if (auto options = attr.getDistribute())
260 convertLoopOptions(options);
261 if (auto options = attr.getPipeline())
262 convertLoopOptions(options);
263 if (auto options = attr.getPeeled())
264 convertLoopOptions(options);
265 if (auto options = attr.getUnswitch())
266 convertLoopOptions(options);
267
268 ArrayRef<AccessGroupAttr> parallelAccessGroups = attr.getParallelAccesses();
269 if (!parallelAccessGroups.empty()) {
270 SmallVector<llvm::Metadata *> parallelAccess;
271 parallelAccess.push_back(
272 llvm::MDString::get(ctx, "llvm.loop.parallel_accesses"));
273 for (AccessGroupAttr accessGroupAttr : parallelAccessGroups)
274 parallelAccess.push_back(
275 loopAnnotationTranslation.getAccessGroup(accessGroupAttr));
276 metadataNodes.push_back(llvm::MDNode::get(ctx, parallelAccess));
277 }
278
279 // Create loop options and set the first operand to itself.
280 llvm::MDNode *loopMD = llvm::MDNode::get(ctx, metadataNodes);
281 loopMD->replaceOperandWith(0, loopMD);
282
283 return loopMD;
284}
285
286llvm::MDNode *
288 Operation *op) {
289 if (!attr)
290 return nullptr;
291
292 llvm::MDNode *loopMD = lookupLoopMetadata(attr);
293 if (loopMD)
294 return loopMD;
295
296 loopMD =
297 LoopAnnotationConversion(attr, op, *this, this->llvmModule.getContext())
298 .convert();
299 // Store a map from this Attribute to the LLVM metadata in case we
300 // encounter it again.
301 mapLoopMetadata(attr, loopMD);
302 return loopMD;
303}
304
305llvm::MDNode *
306LoopAnnotationTranslation::getAccessGroup(AccessGroupAttr accessGroupAttr) {
307 auto [result, inserted] =
308 accessGroupMetadataMapping.try_emplace(accessGroupAttr);
309 if (inserted)
310 result->second = llvm::MDNode::getDistinct(llvmModule.getContext(), {});
311 return result->second;
312}
313
314llvm::MDNode *
316 ArrayAttr accessGroups = op.getAccessGroupsOrNull();
317 if (!accessGroups || accessGroups.empty())
318 return nullptr;
319
321 for (AccessGroupAttr group : accessGroups.getAsRange<AccessGroupAttr>())
322 groupMDs.push_back(getAccessGroup(group));
323 if (groupMDs.size() == 1)
324 return llvm::cast<llvm::MDNode>(groupMDs.front());
325 return llvm::MDNode::get(llvmModule.getContext(), groupMDs);
326}
*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.