xref: /llvm-project/mlir/lib/Target/LLVMIR/DebugImporter.cpp (revision 89f2d50cda2462d744e2ef08d662265a8d598e2a)
1 //===- DebugImporter.cpp - LLVM to MLIR Debug conversion ------------------===//
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 
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"
24 
25 using namespace mlir;
26 using namespace mlir::LLVM;
27 using namespace mlir::LLVM::detail;
28 
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) {}
34 
35 Location DebugImporter::translateFuncLocation(llvm::Function *func) {
36   llvm::DISubprogram *subprogram = func->getSubprogram();
37   if (!subprogram)
38     return UnknownLoc::get(context);
39 
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);
47 }
48 
49 //===----------------------------------------------------------------------===//
50 // Attributes
51 //===----------------------------------------------------------------------===//
52 
53 DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) {
54   return DIBasicTypeAttr::get(context, node->getTag(), node->getName(),
55                               node->getSizeInBits(), node->getEncoding());
56 }
57 
58 DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {
59   std::optional<DIEmissionKind> emissionKind =
60       symbolizeDIEmissionKind(node->getEmissionKind());
61   std::optional<DINameTableKind> nameTableKind = symbolizeDINameTableKind(
62       static_cast<
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());
69 }
70 
71 DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
72   std::optional<DIFlags> flags = symbolizeDIFlags(node->getFlags());
73   SmallVector<DINodeAttr> elements;
74 
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));
81     }
82   }
83   // Drop the elements parameter if any of the elements are invalid.
84   if (llvm::is_contained(elements, nullptr))
85     elements.clear();
86   DITypeAttr baseType = translate(node->getBaseType());
87   // Arrays require a base type, otherwise the debug metadata is considered to
88   // be malformed.
89   if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType)
90     return nullptr;
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()));
100 }
101 
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)
106     return nullptr;
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);
113 }
114 
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());
122 }
123 
124 DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {
125   return DIFileAttr::get(context, node->getFilename(), node->getDirectory());
126 }
127 
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)
132     return nullptr;
133   return DILabelAttr::get(context, scope,
134                           getStringAttrOrNull(node->getRawName()),
135                           translate(node->getFile()), node->getLine());
136 }
137 
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)
142     return nullptr;
143   return DILexicalBlockAttr::get(context, scope, translate(node->getFile()),
144                                  node->getLine(), node->getColumn());
145 }
146 
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)
152     return nullptr;
153   return DILexicalBlockFileAttr::get(context, scope, translate(node->getFile()),
154                                      node->getDiscriminator());
155 }
156 
157 DIGlobalVariableAttr
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 {
162     if (name.empty())
163       return {};
164     return StringAttr::get(context, node->getName());
165   };
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());
172 }
173 
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)
178     return nullptr;
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));
184 }
185 
186 DIVariableAttr DebugImporter::translateImpl(llvm::DIVariable *node) {
187   return cast<DIVariableAttr>(translate(static_cast<llvm::DINode *>(node)));
188 }
189 
190 DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) {
191   return cast<DIScopeAttr>(translate(static_cast<llvm::DINode *>(node)));
192 }
193 
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(),
201       node->getIsDecl());
202 }
203 
204 DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
205   return DINamespaceAttr::get(context, getStringAttrOrNull(node->getRawName()),
206                               translate(node->getScope()),
207                               node->getExportSymbols());
208 }
209 
210 DIImportedEntityAttr
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));
216   }
217 
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);
222 }
223 
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);
229 
230   // Return nullptr if the scope or type is invalid.
231   DIScopeAttr scope = translate(node->getScope());
232   if (node->getScope() && !scope)
233     return nullptr;
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)
239     return nullptr;
240 
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();
247 
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)
256         continue;
257       const llvm::MDString *name = cast<llvm::MDString>(tuple->getOperand(0));
258       const llvm::MDString *value =
259           dyn_cast<llvm::MDString>(tuple->getOperand(1));
260       if (name && value) {
261         annotations.push_back(DIAnnotationAttr::get(
262             context, StringAttr::get(context, name->getString()),
263             StringAttr::get(context, value->getString())));
264       }
265     }
266   }
267 
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);
274 }
275 
276 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
277   auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute {
278     if (data.isNull())
279       return nullptr;
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);
290       return nullptr;
291     }
292     return nullptr;
293   };
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)
299     return {};
300   return DISubrangeAttr::get(context, count,
301                              getAttrOrNull(node->getLowerBound()), upperBound,
302                              getAttrOrNull(node->getStride()));
303 }
304 
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());
310 }
311 
312 DIGenericSubrangeAttr
313 DebugImporter::translateImpl(llvm::DIGenericSubrange *node) {
314   auto getAttrOrNull =
315       [&](llvm::DIGenericSubrange::BoundType data) -> Attribute {
316     if (data.isNull())
317       return nullptr;
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);
325       return nullptr;
326     }
327     return nullptr;
328   };
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)
336     return {};
337   return DIGenericSubrangeAttr::get(context, count, lowerBound, upperBound,
338                                     stride);
339 }
340 
341 DISubroutineTypeAttr
342 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
343   SmallVector<DITypeAttr> types;
344   for (llvm::DIType *type : node->getTypeArray()) {
345     if (!type) {
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));
351       continue;
352     }
353     types.push_back(translate(type));
354   }
355   // Return nullptr if any of the types is invalid.
356   if (llvm::is_contained(types, nullptr))
357     return nullptr;
358   return DISubroutineTypeAttr::get(context, node->getCC(), types);
359 }
360 
361 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
362   return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
363 }
364 
365 DINodeAttr DebugImporter::translate(llvm::DINode *node) {
366   if (!node)
367     return nullptr;
368 
369   // Check for a cached instance.
370   auto cacheEntry = cache.lookupOrInit(node);
371   if (std::optional<DINodeAttr> result = cacheEntry.get())
372     return *result;
373 
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);
414     return nullptr;
415   };
416   if (DINodeAttr attr = translateNode(node)) {
417     // If this node was repeated, lookup its recursive ID and assign it to the
418     // base result.
419     if (cacheEntry.wasRepeated()) {
420       DistinctAttr recId = nodeToRecId.lookup(node);
421       auto recType = cast<DIRecursiveTypeAttrInterface>(attr);
422       attr = cast<DINodeAttr>(recType.withRecId(recId));
423     }
424     cacheEntry.resolve(attr);
425     return attr;
426   }
427   cacheEntry.resolve(nullptr);
428   return nullptr;
429 }
430 
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);
439       })
440       .Case([&](llvm::DISubprogram *) {
441         return CtorType(DISubprogramAttr::getRecSelf);
442       })
443       .Default(CtorType());
444 }
445 
446 std::optional<DINodeAttr> DebugImporter::createRecSelf(llvm::DINode *node) {
447   auto recSelfCtor = getRecSelfConstructor(node);
448   if (!recSelfCtor)
449     return std::nullopt;
450 
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);
454   if (!recId) {
455     recId = DistinctAttr::create(UnitAttr::get(context));
456     nodeToRecId[node] = recId;
457   }
458   DIRecursiveTypeAttrInterface recSelf = recSelfCtor(recId);
459   return cast<DINodeAttr>(recSelf);
460 }
461 
462 //===----------------------------------------------------------------------===//
463 // Locations
464 //===----------------------------------------------------------------------===//
465 
466 Location DebugImporter::translateLoc(llvm::DILocation *loc) {
467   if (!loc)
468     return UnknownLoc::get(context);
469 
470   // Get the file location of the instruction.
471   Location result = FileLineColLoc::get(context, loc->getFilename(),
472                                         loc->getLine(), loc->getColumn());
473 
474   // Add scope information.
475   assert(loc->getScope() && "expected non-null scope");
476   result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
477                                           context);
478 
479   // Add call site information, if available.
480   if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
481     result = CallSiteLoc::get(result, translateLoc(inlinedAt));
482 
483   return result;
484 }
485 
486 DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) {
487   if (!node)
488     return nullptr;
489 
490   SmallVector<DIExpressionElemAttr> ops;
491 
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);
499     ops.push_back(attr);
500   }
501   return DIExpressionAttr::get(context, ops);
502 }
503 
504 DIGlobalVariableExpressionAttr DebugImporter::translateGlobalVariableExpression(
505     llvm::DIGlobalVariableExpression *node) {
506   return DIGlobalVariableExpressionAttr::get(
507       context, translate(node->getVariable()),
508       translateExpression(node->getExpression()));
509 }
510 
511 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
512   if (!stringNode)
513     return StringAttr();
514   return StringAttr::get(context, stringNode->getString());
515 }
516 
517 DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {
518   DistinctAttr &id = nodeToDistinctAttr[node];
519   if (!id)
520     id = DistinctAttr::create(UnitAttr::get(context));
521   return id;
522 }
523