1 //===- DebugImporter.cpp - LLVM to MLIR Debug conversion ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DebugImporter.h"
10 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
11 #include "mlir/IR/Attributes.h"
12 #include "mlir/IR/BuiltinAttributes.h"
13 #include "mlir/IR/Location.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/ScopeExit.h"
16 #include "llvm/ADT/SetOperations.h"
17 #include "llvm/ADT/TypeSwitch.h"
18 #include "llvm/BinaryFormat/Dwarf.h"
19 #include "llvm/IR/Constants.h"
20 #include "llvm/IR/DebugInfoMetadata.h"
21 #include "llvm/IR/Metadata.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/ErrorHandling.h"
26 using namespace mlir::LLVM
;
27 using namespace mlir::LLVM::detail
;
29 DebugImporter::DebugImporter(ModuleOp mlirModule
,
30 bool dropDICompositeTypeElements
)
31 : cache([&](llvm::DINode
*node
) { return createRecSelf(node
); }),
32 context(mlirModule
.getContext()), mlirModule(mlirModule
),
33 dropDICompositeTypeElements(dropDICompositeTypeElements
) {}
35 Location
DebugImporter::translateFuncLocation(llvm::Function
*func
) {
36 llvm::DISubprogram
*subprogram
= func
->getSubprogram();
38 return UnknownLoc::get(context
);
40 // Add a fused location to link the subprogram information.
41 StringAttr funcName
= StringAttr::get(context
, subprogram
->getName());
42 StringAttr fileName
= StringAttr::get(context
, subprogram
->getFilename());
43 return FusedLocWith
<DISubprogramAttr
>::get(
44 {NameLoc::get(funcName
),
45 FileLineColLoc::get(fileName
, subprogram
->getLine(), /*column=*/0)},
46 translate(subprogram
), context
);
49 //===----------------------------------------------------------------------===//
51 //===----------------------------------------------------------------------===//
53 DIBasicTypeAttr
DebugImporter::translateImpl(llvm::DIBasicType
*node
) {
54 return DIBasicTypeAttr::get(context
, node
->getTag(), node
->getName(),
55 node
->getSizeInBits(), node
->getEncoding());
58 DICompileUnitAttr
DebugImporter::translateImpl(llvm::DICompileUnit
*node
) {
59 std::optional
<DIEmissionKind
> emissionKind
=
60 symbolizeDIEmissionKind(node
->getEmissionKind());
61 std::optional
<DINameTableKind
> nameTableKind
= symbolizeDINameTableKind(
63 std::underlying_type_t
<llvm::DICompileUnit::DebugNameTableKind
>>(
64 node
->getNameTableKind()));
65 return DICompileUnitAttr::get(
66 context
, getOrCreateDistinctID(node
), node
->getSourceLanguage(),
67 translate(node
->getFile()), getStringAttrOrNull(node
->getRawProducer()),
68 node
->isOptimized(), emissionKind
.value(), nameTableKind
.value());
71 DICompositeTypeAttr
DebugImporter::translateImpl(llvm::DICompositeType
*node
) {
72 std::optional
<DIFlags
> flags
= symbolizeDIFlags(node
->getFlags());
73 SmallVector
<DINodeAttr
> elements
;
75 // A vector always requires an element.
76 bool isVectorType
= flags
&& bitEnumContainsAll(*flags
, DIFlags::Vector
);
77 if (isVectorType
|| !dropDICompositeTypeElements
) {
78 for (llvm::DINode
*element
: node
->getElements()) {
79 assert(element
&& "expected a non-null element type");
80 elements
.push_back(translate(element
));
83 // Drop the elements parameter if any of the elements are invalid.
84 if (llvm::is_contained(elements
, nullptr))
86 DITypeAttr baseType
= translate(node
->getBaseType());
87 // Arrays require a base type, otherwise the debug metadata is considered to
89 if (node
->getTag() == llvm::dwarf::DW_TAG_array_type
&& !baseType
)
91 return DICompositeTypeAttr::get(
92 context
, node
->getTag(), getStringAttrOrNull(node
->getRawName()),
93 translate(node
->getFile()), node
->getLine(), translate(node
->getScope()),
94 baseType
, flags
.value_or(DIFlags::Zero
), node
->getSizeInBits(),
95 node
->getAlignInBits(), elements
,
96 translateExpression(node
->getDataLocationExp()),
97 translateExpression(node
->getRankExp()),
98 translateExpression(node
->getAllocatedExp()),
99 translateExpression(node
->getAssociatedExp()));
102 DIDerivedTypeAttr
DebugImporter::translateImpl(llvm::DIDerivedType
*node
) {
103 // Return nullptr if the base type is invalid.
104 DITypeAttr baseType
= translate(node
->getBaseType());
105 if (node
->getBaseType() && !baseType
)
107 DINodeAttr extraData
=
108 translate(dyn_cast_or_null
<llvm::DINode
>(node
->getExtraData()));
109 return DIDerivedTypeAttr::get(
110 context
, node
->getTag(), getStringAttrOrNull(node
->getRawName()),
111 baseType
, node
->getSizeInBits(), node
->getAlignInBits(),
112 node
->getOffsetInBits(), node
->getDWARFAddressSpace(), extraData
);
115 DIStringTypeAttr
DebugImporter::translateImpl(llvm::DIStringType
*node
) {
116 return DIStringTypeAttr::get(
117 context
, node
->getTag(), getStringAttrOrNull(node
->getRawName()),
118 node
->getSizeInBits(), node
->getAlignInBits(),
119 translate(node
->getStringLength()),
120 translateExpression(node
->getStringLengthExp()),
121 translateExpression(node
->getStringLocationExp()), node
->getEncoding());
124 DIFileAttr
DebugImporter::translateImpl(llvm::DIFile
*node
) {
125 return DIFileAttr::get(context
, node
->getFilename(), node
->getDirectory());
128 DILabelAttr
DebugImporter::translateImpl(llvm::DILabel
*node
) {
129 // Return nullptr if the scope or type is a cyclic dependency.
130 DIScopeAttr scope
= translate(node
->getScope());
131 if (node
->getScope() && !scope
)
133 return DILabelAttr::get(context
, scope
,
134 getStringAttrOrNull(node
->getRawName()),
135 translate(node
->getFile()), node
->getLine());
138 DILexicalBlockAttr
DebugImporter::translateImpl(llvm::DILexicalBlock
*node
) {
139 // Return nullptr if the scope or type is a cyclic dependency.
140 DIScopeAttr scope
= translate(node
->getScope());
141 if (node
->getScope() && !scope
)
143 return DILexicalBlockAttr::get(context
, scope
, translate(node
->getFile()),
144 node
->getLine(), node
->getColumn());
147 DILexicalBlockFileAttr
148 DebugImporter::translateImpl(llvm::DILexicalBlockFile
*node
) {
149 // Return nullptr if the scope or type is a cyclic dependency.
150 DIScopeAttr scope
= translate(node
->getScope());
151 if (node
->getScope() && !scope
)
153 return DILexicalBlockFileAttr::get(context
, scope
, translate(node
->getFile()),
154 node
->getDiscriminator());
158 DebugImporter::translateImpl(llvm::DIGlobalVariable
*node
) {
159 // Names of DIGlobalVariables can be empty. MLIR models them as null, instead
160 // of empty strings, so this special handling is necessary.
161 auto convertToStringAttr
= [&](StringRef name
) -> StringAttr
{
164 return StringAttr::get(context
, node
->getName());
166 return DIGlobalVariableAttr::get(
167 context
, translate(node
->getScope()),
168 convertToStringAttr(node
->getName()),
169 convertToStringAttr(node
->getLinkageName()), translate(node
->getFile()),
170 node
->getLine(), translate(node
->getType()), node
->isLocalToUnit(),
171 node
->isDefinition(), node
->getAlignInBits());
174 DILocalVariableAttr
DebugImporter::translateImpl(llvm::DILocalVariable
*node
) {
175 // Return nullptr if the scope or type is a cyclic dependency.
176 DIScopeAttr scope
= translate(node
->getScope());
177 if (node
->getScope() && !scope
)
179 return DILocalVariableAttr::get(
180 context
, scope
, getStringAttrOrNull(node
->getRawName()),
181 translate(node
->getFile()), node
->getLine(), node
->getArg(),
182 node
->getAlignInBits(), translate(node
->getType()),
183 symbolizeDIFlags(node
->getFlags()).value_or(DIFlags::Zero
));
186 DIVariableAttr
DebugImporter::translateImpl(llvm::DIVariable
*node
) {
187 return cast
<DIVariableAttr
>(translate(static_cast<llvm::DINode
*>(node
)));
190 DIScopeAttr
DebugImporter::translateImpl(llvm::DIScope
*node
) {
191 return cast
<DIScopeAttr
>(translate(static_cast<llvm::DINode
*>(node
)));
194 DIModuleAttr
DebugImporter::translateImpl(llvm::DIModule
*node
) {
195 return DIModuleAttr::get(
196 context
, translate(node
->getFile()), translate(node
->getScope()),
197 getStringAttrOrNull(node
->getRawName()),
198 getStringAttrOrNull(node
->getRawConfigurationMacros()),
199 getStringAttrOrNull(node
->getRawIncludePath()),
200 getStringAttrOrNull(node
->getRawAPINotesFile()), node
->getLineNo(),
204 DINamespaceAttr
DebugImporter::translateImpl(llvm::DINamespace
*node
) {
205 return DINamespaceAttr::get(context
, getStringAttrOrNull(node
->getRawName()),
206 translate(node
->getScope()),
207 node
->getExportSymbols());
211 DebugImporter::translateImpl(llvm::DIImportedEntity
*node
) {
212 SmallVector
<DINodeAttr
> elements
;
213 for (llvm::DINode
*element
: node
->getElements()) {
214 assert(element
&& "expected a non-null element type");
215 elements
.push_back(translate(element
));
218 return DIImportedEntityAttr::get(
219 context
, node
->getTag(), translate(node
->getScope()),
220 translate(node
->getEntity()), translate(node
->getFile()), node
->getLine(),
221 getStringAttrOrNull(node
->getRawName()), elements
);
224 DISubprogramAttr
DebugImporter::translateImpl(llvm::DISubprogram
*node
) {
225 // Only definitions require a distinct identifier.
226 mlir::DistinctAttr id
;
227 if (node
->isDistinct())
228 id
= getOrCreateDistinctID(node
);
230 // Return nullptr if the scope or type is invalid.
231 DIScopeAttr scope
= translate(node
->getScope());
232 if (node
->getScope() && !scope
)
234 std::optional
<DISubprogramFlags
> subprogramFlags
=
235 symbolizeDISubprogramFlags(node
->getSubprogram()->getSPFlags());
236 assert(subprogramFlags
&& "expected valid subprogram flags");
237 DISubroutineTypeAttr type
= translate(node
->getType());
238 if (node
->getType() && !type
)
241 // Convert the retained nodes but drop all of them if one of them is invalid.
242 SmallVector
<DINodeAttr
> retainedNodes
;
243 for (llvm::DINode
*retainedNode
: node
->getRetainedNodes())
244 retainedNodes
.push_back(translate(retainedNode
));
245 if (llvm::is_contained(retainedNodes
, nullptr))
246 retainedNodes
.clear();
248 SmallVector
<DINodeAttr
> annotations
;
249 // We currently only support `string` values for annotations on the MLIR side.
250 // Theoretically we could support other primitives, but LLVM is not using
251 // other types in practice.
252 if (llvm::DINodeArray rawAnns
= node
->getAnnotations(); rawAnns
) {
253 for (size_t i
= 0, e
= rawAnns
->getNumOperands(); i
< e
; ++i
) {
254 const llvm::MDTuple
*tuple
= cast
<llvm::MDTuple
>(rawAnns
->getOperand(i
));
255 if (tuple
->getNumOperands() != 2)
257 const llvm::MDString
*name
= cast
<llvm::MDString
>(tuple
->getOperand(0));
258 const llvm::MDString
*value
=
259 dyn_cast
<llvm::MDString
>(tuple
->getOperand(1));
261 annotations
.push_back(DIAnnotationAttr::get(
262 context
, StringAttr::get(context
, name
->getString()),
263 StringAttr::get(context
, value
->getString())));
268 return DISubprogramAttr::get(context
, id
, translate(node
->getUnit()), scope
,
269 getStringAttrOrNull(node
->getRawName()),
270 getStringAttrOrNull(node
->getRawLinkageName()),
271 translate(node
->getFile()), node
->getLine(),
272 node
->getScopeLine(), *subprogramFlags
, type
,
273 retainedNodes
, annotations
);
276 DISubrangeAttr
DebugImporter::translateImpl(llvm::DISubrange
*node
) {
277 auto getAttrOrNull
= [&](llvm::DISubrange::BoundType data
) -> Attribute
{
280 if (auto *constInt
= dyn_cast
<llvm::ConstantInt
*>(data
))
281 return IntegerAttr::get(IntegerType::get(context
, 64),
282 constInt
->getSExtValue());
283 if (auto *expr
= dyn_cast
<llvm::DIExpression
*>(data
))
284 return translateExpression(expr
);
285 if (auto *var
= dyn_cast
<llvm::DIVariable
*>(data
)) {
286 if (auto *local
= dyn_cast
<llvm::DILocalVariable
>(var
))
287 return translate(local
);
288 if (auto *global
= dyn_cast
<llvm::DIGlobalVariable
>(var
))
289 return translate(global
);
294 Attribute count
= getAttrOrNull(node
->getCount());
295 Attribute upperBound
= getAttrOrNull(node
->getUpperBound());
296 // Either count or the upper bound needs to be present. Otherwise, the
297 // metadata is invalid. The conversion might fail due to unsupported DI nodes.
298 if (!count
&& !upperBound
)
300 return DISubrangeAttr::get(context
, count
,
301 getAttrOrNull(node
->getLowerBound()), upperBound
,
302 getAttrOrNull(node
->getStride()));
305 DICommonBlockAttr
DebugImporter::translateImpl(llvm::DICommonBlock
*node
) {
306 return DICommonBlockAttr::get(context
, translate(node
->getScope()),
307 translate(node
->getDecl()),
308 getStringAttrOrNull(node
->getRawName()),
309 translate(node
->getFile()), node
->getLineNo());
312 DIGenericSubrangeAttr
313 DebugImporter::translateImpl(llvm::DIGenericSubrange
*node
) {
315 [&](llvm::DIGenericSubrange::BoundType data
) -> Attribute
{
318 if (auto *expr
= dyn_cast
<llvm::DIExpression
*>(data
))
319 return translateExpression(expr
);
320 if (auto *var
= dyn_cast
<llvm::DIVariable
*>(data
)) {
321 if (auto *local
= dyn_cast
<llvm::DILocalVariable
>(var
))
322 return translate(local
);
323 if (auto *global
= dyn_cast
<llvm::DIGlobalVariable
>(var
))
324 return translate(global
);
329 Attribute count
= getAttrOrNull(node
->getCount());
330 Attribute upperBound
= getAttrOrNull(node
->getUpperBound());
331 Attribute lowerBound
= getAttrOrNull(node
->getLowerBound());
332 Attribute stride
= getAttrOrNull(node
->getStride());
333 // Either count or the upper bound needs to be present. Otherwise, the
334 // metadata is invalid.
335 if (!count
&& !upperBound
)
337 return DIGenericSubrangeAttr::get(context
, count
, lowerBound
, upperBound
,
342 DebugImporter::translateImpl(llvm::DISubroutineType
*node
) {
343 SmallVector
<DITypeAttr
> types
;
344 for (llvm::DIType
*type
: node
->getTypeArray()) {
346 // A nullptr entry may appear at the beginning or the end of the
347 // subroutine types list modeling either a void result type or the type of
348 // a variadic argument. Translate the nullptr to an explicit
349 // DINullTypeAttr since the attribute list cannot contain a nullptr entry.
350 types
.push_back(DINullTypeAttr::get(context
));
353 types
.push_back(translate(type
));
355 // Return nullptr if any of the types is invalid.
356 if (llvm::is_contained(types
, nullptr))
358 return DISubroutineTypeAttr::get(context
, node
->getCC(), types
);
361 DITypeAttr
DebugImporter::translateImpl(llvm::DIType
*node
) {
362 return cast
<DITypeAttr
>(translate(static_cast<llvm::DINode
*>(node
)));
365 DINodeAttr
DebugImporter::translate(llvm::DINode
*node
) {
369 // Check for a cached instance.
370 auto cacheEntry
= cache
.lookupOrInit(node
);
371 if (std::optional
<DINodeAttr
> result
= cacheEntry
.get())
374 // Convert the debug metadata if possible.
375 auto translateNode
= [this](llvm::DINode
*node
) -> DINodeAttr
{
376 if (auto *casted
= dyn_cast
<llvm::DIBasicType
>(node
))
377 return translateImpl(casted
);
378 if (auto *casted
= dyn_cast
<llvm::DICommonBlock
>(node
))
379 return translateImpl(casted
);
380 if (auto *casted
= dyn_cast
<llvm::DICompileUnit
>(node
))
381 return translateImpl(casted
);
382 if (auto *casted
= dyn_cast
<llvm::DICompositeType
>(node
))
383 return translateImpl(casted
);
384 if (auto *casted
= dyn_cast
<llvm::DIDerivedType
>(node
))
385 return translateImpl(casted
);
386 if (auto *casted
= dyn_cast
<llvm::DIStringType
>(node
))
387 return translateImpl(casted
);
388 if (auto *casted
= dyn_cast
<llvm::DIFile
>(node
))
389 return translateImpl(casted
);
390 if (auto *casted
= dyn_cast
<llvm::DIGlobalVariable
>(node
))
391 return translateImpl(casted
);
392 if (auto *casted
= dyn_cast
<llvm::DIImportedEntity
>(node
))
393 return translateImpl(casted
);
394 if (auto *casted
= dyn_cast
<llvm::DILabel
>(node
))
395 return translateImpl(casted
);
396 if (auto *casted
= dyn_cast
<llvm::DILexicalBlock
>(node
))
397 return translateImpl(casted
);
398 if (auto *casted
= dyn_cast
<llvm::DILexicalBlockFile
>(node
))
399 return translateImpl(casted
);
400 if (auto *casted
= dyn_cast
<llvm::DILocalVariable
>(node
))
401 return translateImpl(casted
);
402 if (auto *casted
= dyn_cast
<llvm::DIModule
>(node
))
403 return translateImpl(casted
);
404 if (auto *casted
= dyn_cast
<llvm::DINamespace
>(node
))
405 return translateImpl(casted
);
406 if (auto *casted
= dyn_cast
<llvm::DISubprogram
>(node
))
407 return translateImpl(casted
);
408 if (auto *casted
= dyn_cast
<llvm::DISubrange
>(node
))
409 return translateImpl(casted
);
410 if (auto *casted
= dyn_cast
<llvm::DIGenericSubrange
>(node
))
411 return translateImpl(casted
);
412 if (auto *casted
= dyn_cast
<llvm::DISubroutineType
>(node
))
413 return translateImpl(casted
);
416 if (DINodeAttr attr
= translateNode(node
)) {
417 // If this node was repeated, lookup its recursive ID and assign it to the
419 if (cacheEntry
.wasRepeated()) {
420 DistinctAttr recId
= nodeToRecId
.lookup(node
);
421 auto recType
= cast
<DIRecursiveTypeAttrInterface
>(attr
);
422 attr
= cast
<DINodeAttr
>(recType
.withRecId(recId
));
424 cacheEntry
.resolve(attr
);
427 cacheEntry
.resolve(nullptr);
431 /// Get the `getRecSelf` constructor for the translated type of `node` if its
432 /// translated DITypeAttr supports recursion. Otherwise, returns nullptr.
433 static function_ref
<DIRecursiveTypeAttrInterface(DistinctAttr
)>
434 getRecSelfConstructor(llvm::DINode
*node
) {
435 using CtorType
= function_ref
<DIRecursiveTypeAttrInterface(DistinctAttr
)>;
436 return TypeSwitch
<llvm::DINode
*, CtorType
>(node
)
437 .Case([&](llvm::DICompositeType
*) {
438 return CtorType(DICompositeTypeAttr::getRecSelf
);
440 .Case([&](llvm::DISubprogram
*) {
441 return CtorType(DISubprogramAttr::getRecSelf
);
443 .Default(CtorType());
446 std::optional
<DINodeAttr
> DebugImporter::createRecSelf(llvm::DINode
*node
) {
447 auto recSelfCtor
= getRecSelfConstructor(node
);
451 // The original node may have already been assigned a recursive ID from
452 // a different self-reference. Use that if possible.
453 DistinctAttr recId
= nodeToRecId
.lookup(node
);
455 recId
= DistinctAttr::create(UnitAttr::get(context
));
456 nodeToRecId
[node
] = recId
;
458 DIRecursiveTypeAttrInterface recSelf
= recSelfCtor(recId
);
459 return cast
<DINodeAttr
>(recSelf
);
462 //===----------------------------------------------------------------------===//
464 //===----------------------------------------------------------------------===//
466 Location
DebugImporter::translateLoc(llvm::DILocation
*loc
) {
468 return UnknownLoc::get(context
);
470 // Get the file location of the instruction.
471 Location result
= FileLineColLoc::get(context
, loc
->getFilename(),
472 loc
->getLine(), loc
->getColumn());
474 // Add scope information.
475 assert(loc
->getScope() && "expected non-null scope");
476 result
= FusedLocWith
<DIScopeAttr
>::get({result
}, translate(loc
->getScope()),
479 // Add call site information, if available.
480 if (llvm::DILocation
*inlinedAt
= loc
->getInlinedAt())
481 result
= CallSiteLoc::get(result
, translateLoc(inlinedAt
));
486 DIExpressionAttr
DebugImporter::translateExpression(llvm::DIExpression
*node
) {
490 SmallVector
<DIExpressionElemAttr
> ops
;
492 // Begin processing the operations.
493 for (const llvm::DIExpression::ExprOperand
&op
: node
->expr_ops()) {
494 SmallVector
<uint64_t> operands
;
495 operands
.reserve(op
.getNumArgs());
496 for (const auto &i
: llvm::seq(op
.getNumArgs()))
497 operands
.push_back(op
.getArg(i
));
498 const auto attr
= DIExpressionElemAttr::get(context
, op
.getOp(), operands
);
501 return DIExpressionAttr::get(context
, ops
);
504 DIGlobalVariableExpressionAttr
DebugImporter::translateGlobalVariableExpression(
505 llvm::DIGlobalVariableExpression
*node
) {
506 return DIGlobalVariableExpressionAttr::get(
507 context
, translate(node
->getVariable()),
508 translateExpression(node
->getExpression()));
511 StringAttr
DebugImporter::getStringAttrOrNull(llvm::MDString
*stringNode
) {
514 return StringAttr::get(context
, stringNode
->getString());
517 DistinctAttr
DebugImporter::getOrCreateDistinctID(llvm::DINode
*node
) {
518 DistinctAttr
&id
= nodeToDistinctAttr
[node
];
520 id
= DistinctAttr::create(UnitAttr::get(context
));