MLIR  19.0.0git
DebugImporter.cpp
Go to the documentation of this file.
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"
11 #include "mlir/IR/Attributes.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  : recursionPruner(mlirModule.getContext()),
32  context(mlirModule.getContext()), mlirModule(mlirModule),
33  dropDICompositeTypeElements(dropDICompositeTypeElements) {}
34 
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());
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()));
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;
92  context, node->getTag(), /*recId=*/{},
93  getStringAttrOrNull(node->getRawName()), translate(node->getFile()),
94  node->getLine(), translate(node->getScope()), baseType,
95  flags.value_or(DIFlags::Zero), node->getSizeInBits(),
96  node->getAlignInBits(), elements,
97  translateExpression(node->getDataLocationExp()),
98  translateExpression(node->getRankExp()),
99  translateExpression(node->getAllocatedExp()),
100  translateExpression(node->getAssociatedExp()));
101 }
102 
103 DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) {
104  // Return nullptr if the base type is invalid.
105  DITypeAttr baseType = translate(node->getBaseType());
106  if (node->getBaseType() && !baseType)
107  return nullptr;
108  DINodeAttr extraData =
109  translate(dyn_cast_or_null<llvm::DINode>(node->getExtraData()));
110  return DIDerivedTypeAttr::get(
111  context, node->getTag(), getStringAttrOrNull(node->getRawName()),
112  baseType, node->getSizeInBits(), node->getAlignInBits(),
113  node->getOffsetInBits(), node->getDWARFAddressSpace(), extraData);
114 }
115 
116 DIStringTypeAttr DebugImporter::translateImpl(llvm::DIStringType *node) {
117  return DIStringTypeAttr::get(
118  context, node->getTag(), getStringAttrOrNull(node->getRawName()),
119  node->getSizeInBits(), node->getAlignInBits(),
120  translate(node->getStringLength()),
121  translateExpression(node->getStringLengthExp()),
122  translateExpression(node->getStringLocationExp()), node->getEncoding());
123 }
124 
125 DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {
126  return DIFileAttr::get(context, node->getFilename(), node->getDirectory());
127 }
128 
129 DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) {
130  // Return nullptr if the scope or type is a cyclic dependency.
131  DIScopeAttr scope = translate(node->getScope());
132  if (node->getScope() && !scope)
133  return nullptr;
134  return DILabelAttr::get(context, scope,
135  getStringAttrOrNull(node->getRawName()),
136  translate(node->getFile()), node->getLine());
137 }
138 
139 DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) {
140  // Return nullptr if the scope or type is a cyclic dependency.
141  DIScopeAttr scope = translate(node->getScope());
142  if (node->getScope() && !scope)
143  return nullptr;
144  return DILexicalBlockAttr::get(context, scope, translate(node->getFile()),
145  node->getLine(), node->getColumn());
146 }
147 
148 DILexicalBlockFileAttr
149 DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) {
150  // Return nullptr if the scope or type is a cyclic dependency.
151  DIScopeAttr scope = translate(node->getScope());
152  if (node->getScope() && !scope)
153  return nullptr;
154  return DILexicalBlockFileAttr::get(context, scope, translate(node->getFile()),
155  node->getDiscriminator());
156 }
157 
158 DIGlobalVariableAttr
159 DebugImporter::translateImpl(llvm::DIGlobalVariable *node) {
160  // Names of DIGlobalVariables can be empty. MLIR models them as null, instead
161  // of empty strings, so this special handling is necessary.
162  auto convertToStringAttr = [&](StringRef name) -> StringAttr {
163  if (name.empty())
164  return {};
165  return StringAttr::get(context, node->getName());
166  };
168  context, translate(node->getScope()),
169  convertToStringAttr(node->getName()),
170  convertToStringAttr(node->getLinkageName()), translate(node->getFile()),
171  node->getLine(), translate(node->getType()), node->isLocalToUnit(),
172  node->isDefinition(), node->getAlignInBits());
173 }
174 
175 DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) {
176  // Return nullptr if the scope or type is a cyclic dependency.
177  DIScopeAttr scope = translate(node->getScope());
178  if (node->getScope() && !scope)
179  return nullptr;
181  context, scope, getStringAttrOrNull(node->getRawName()),
182  translate(node->getFile()), node->getLine(), node->getArg(),
183  node->getAlignInBits(), translate(node->getType()));
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 DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
211  // Only definitions require a distinct identifier.
213  if (node->isDistinct())
214  id = getOrCreateDistinctID(node);
215  // Return nullptr if the scope or type is invalid.
216  DIScopeAttr scope = translate(node->getScope());
217  if (node->getScope() && !scope)
218  return nullptr;
219  std::optional<DISubprogramFlags> subprogramFlags =
220  symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags());
221  assert(subprogramFlags && "expected valid subprogram flags");
222  DISubroutineTypeAttr type = translate(node->getType());
223  if (node->getType() && !type)
224  return nullptr;
225  return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
226  getStringAttrOrNull(node->getRawName()),
227  getStringAttrOrNull(node->getRawLinkageName()),
228  translate(node->getFile()), node->getLine(),
229  node->getScopeLine(), *subprogramFlags, type);
230 }
231 
232 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
233  auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute {
234  if (data.isNull())
235  return nullptr;
236  if (auto *constInt = dyn_cast<llvm::ConstantInt *>(data))
237  return IntegerAttr::get(IntegerType::get(context, 64),
238  constInt->getSExtValue());
239  if (auto *expr = dyn_cast<llvm::DIExpression *>(data))
240  return translateExpression(expr);
241  if (auto *var = dyn_cast<llvm::DIVariable *>(data)) {
242  if (auto *local = dyn_cast<llvm::DILocalVariable>(var))
243  return translate(local);
244  if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var))
245  return translate(global);
246  return nullptr;
247  }
248  return nullptr;
249  };
250  Attribute count = getAttrOrNull(node->getCount());
251  Attribute upperBound = getAttrOrNull(node->getUpperBound());
252  // Either count or the upper bound needs to be present. Otherwise, the
253  // metadata is invalid. The conversion might fail due to unsupported DI nodes.
254  if (!count && !upperBound)
255  return {};
256  return DISubrangeAttr::get(context, count,
257  getAttrOrNull(node->getLowerBound()), upperBound,
258  getAttrOrNull(node->getStride()));
259 }
260 
261 DISubroutineTypeAttr
262 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
264  for (llvm::DIType *type : node->getTypeArray()) {
265  if (!type) {
266  // A nullptr entry may appear at the beginning or the end of the
267  // subroutine types list modeling either a void result type or the type of
268  // a variadic argument. Translate the nullptr to an explicit
269  // DINullTypeAttr since the attribute list cannot contain a nullptr entry.
270  types.push_back(DINullTypeAttr::get(context));
271  continue;
272  }
273  types.push_back(translate(type));
274  }
275  // Return nullptr if any of the types is invalid.
276  if (llvm::is_contained(types, nullptr))
277  return nullptr;
278  return DISubroutineTypeAttr::get(context, node->getCC(), types);
279 }
280 
281 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
282  return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
283 }
284 
286  if (!node)
287  return nullptr;
288 
289  // Check for a cached instance.
290  if (DINodeAttr attr = nodeToAttr.lookup(node))
291  return attr;
292 
293  // Register with the recursive translator. If it can be handled without
294  // recursing into it, return the result immediately.
295  if (DINodeAttr attr = recursionPruner.pruneOrPushTranslationStack(node))
296  return attr;
297 
298  auto guard = llvm::make_scope_exit(
299  [&]() { recursionPruner.popTranslationStack(node); });
300 
301  // Convert the debug metadata if possible.
302  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {
303  if (auto *casted = dyn_cast<llvm::DIBasicType>(node))
304  return translateImpl(casted);
305  if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
306  return translateImpl(casted);
307  if (auto *casted = dyn_cast<llvm::DICompositeType>(node))
308  return translateImpl(casted);
309  if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))
310  return translateImpl(casted);
311  if (auto *casted = dyn_cast<llvm::DIStringType>(node))
312  return translateImpl(casted);
313  if (auto *casted = dyn_cast<llvm::DIFile>(node))
314  return translateImpl(casted);
315  if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
316  return translateImpl(casted);
317  if (auto *casted = dyn_cast<llvm::DILabel>(node))
318  return translateImpl(casted);
319  if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
320  return translateImpl(casted);
321  if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))
322  return translateImpl(casted);
323  if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))
324  return translateImpl(casted);
325  if (auto *casted = dyn_cast<llvm::DIModule>(node))
326  return translateImpl(casted);
327  if (auto *casted = dyn_cast<llvm::DINamespace>(node))
328  return translateImpl(casted);
329  if (auto *casted = dyn_cast<llvm::DISubprogram>(node))
330  return translateImpl(casted);
331  if (auto *casted = dyn_cast<llvm::DISubrange>(node))
332  return translateImpl(casted);
333  if (auto *casted = dyn_cast<llvm::DISubroutineType>(node))
334  return translateImpl(casted);
335  return nullptr;
336  };
337  if (DINodeAttr attr = translateNode(node)) {
338  auto [result, isSelfContained] =
339  recursionPruner.finalizeTranslation(node, attr);
340  // Only cache fully self-contained nodes.
341  if (isSelfContained)
342  nodeToAttr.try_emplace(node, result);
343  return result;
344  }
345  return nullptr;
346 }
347 
348 //===----------------------------------------------------------------------===//
349 // RecursionPruner
350 //===----------------------------------------------------------------------===//
351 
352 /// Get the `getRecSelf` constructor for the translated type of `node` if its
353 /// translated DITypeAttr supports recursion. Otherwise, returns nullptr.
354 static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>
355 getRecSelfConstructor(llvm::DINode *node) {
356  using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>;
358  .Case([&](llvm::DICompositeType *) {
359  return CtorType(DICompositeTypeAttr::getRecSelf);
360  })
361  .Default(CtorType());
362 }
363 
364 DINodeAttr DebugImporter::RecursionPruner::pruneOrPushTranslationStack(
365  llvm::DINode *node) {
366  // If the node type is capable of being recursive, check if it's seen
367  // before.
368  auto recSelfCtor = getRecSelfConstructor(node);
369  if (recSelfCtor) {
370  // If a cyclic dependency is detected since the same node is being
371  // traversed twice, emit a recursive self type, and mark the duplicate
372  // node on the translationStack so it can emit a recursive decl type.
373  auto [iter, inserted] = translationStack.try_emplace(node);
374  if (!inserted) {
375  // The original node may have already been assigned a recursive ID from
376  // a different self-reference. Use that if possible.
377  DIRecursiveTypeAttrInterface recSelf = iter->second.recSelf;
378  if (!recSelf) {
379  DistinctAttr recId = nodeToRecId.lookup(node);
380  if (!recId) {
381  recId = DistinctAttr::create(UnitAttr::get(context));
382  nodeToRecId[node] = recId;
383  }
384  recSelf = recSelfCtor(recId);
385  iter->second.recSelf = recSelf;
386  }
387  // Inject the self-ref into the previous layer.
388  translationStack.back().second.unboundSelfRefs.insert(recSelf);
389  return cast<DINodeAttr>(recSelf);
390  }
391  }
392 
393  return lookup(node);
394 }
395 
396 std::pair<DINodeAttr, bool>
397 DebugImporter::RecursionPruner::finalizeTranslation(llvm::DINode *node,
398  DINodeAttr result) {
399  // If `node` is not a potentially recursive type, it will not be on the
400  // translation stack. Nothing to set in this case.
401  if (translationStack.empty())
402  return {result, true};
403  if (translationStack.back().first != node)
404  return {result, translationStack.back().second.unboundSelfRefs.empty()};
405 
406  TranslationState &state = translationStack.back().second;
407 
408  // If this node is actually recursive, set the recId onto `result`.
409  if (DIRecursiveTypeAttrInterface recSelf = state.recSelf) {
410  auto recType = cast<DIRecursiveTypeAttrInterface>(result);
411  result = cast<DINodeAttr>(recType.withRecId(recSelf.getRecId()));
412  // Remove this recSelf from the set of unbound selfRefs.
413  state.unboundSelfRefs.erase(recSelf);
414  }
415 
416  // Insert the result into our internal cache if it's not self-contained.
417  if (!state.unboundSelfRefs.empty()) {
418  [[maybe_unused]] auto [_, inserted] = dependentCache.try_emplace(
419  node, DependentTranslation{result, state.unboundSelfRefs});
420  assert(inserted && "invalid state: caching the same DINode twice");
421  return {result, false};
422  }
423  return {result, true};
424 }
425 
426 void DebugImporter::RecursionPruner::popTranslationStack(llvm::DINode *node) {
427  // If `node` is not a potentially recursive type, it will not be on the
428  // translation stack. Nothing to handle in this case.
429  if (translationStack.empty() || translationStack.back().first != node)
430  return;
431 
432  // At the end of the stack, all unbound self-refs must be resolved already,
433  // and the entire cache should be accounted for.
434  TranslationState &currLayerState = translationStack.back().second;
435  if (translationStack.size() == 1) {
436  assert(currLayerState.unboundSelfRefs.empty() &&
437  "internal error: unbound recursive self reference at top level.");
438  translationStack.pop_back();
439  return;
440  }
441 
442  // Copy unboundSelfRefs down to the previous level.
443  TranslationState &nextLayerState = (++translationStack.rbegin())->second;
444  nextLayerState.unboundSelfRefs.insert(currLayerState.unboundSelfRefs.begin(),
445  currLayerState.unboundSelfRefs.end());
446  translationStack.pop_back();
447 }
448 
449 DINodeAttr DebugImporter::RecursionPruner::lookup(llvm::DINode *node) {
450  auto cacheIter = dependentCache.find(node);
451  if (cacheIter == dependentCache.end())
452  return {};
453 
454  DependentTranslation &entry = cacheIter->second;
455  if (llvm::set_is_subset(entry.unboundSelfRefs,
456  translationStack.back().second.unboundSelfRefs))
457  return entry.attr;
458 
459  // Stale cache entry.
460  dependentCache.erase(cacheIter);
461  return {};
462 }
463 
464 //===----------------------------------------------------------------------===//
465 // Locations
466 //===----------------------------------------------------------------------===//
467 
468 Location DebugImporter::translateLoc(llvm::DILocation *loc) {
469  if (!loc)
470  return UnknownLoc::get(context);
471 
472  // Get the file location of the instruction.
473  Location result = FileLineColLoc::get(context, loc->getFilename(),
474  loc->getLine(), loc->getColumn());
475 
476  // Add scope information.
477  assert(loc->getScope() && "expected non-null scope");
478  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
479  context);
480 
481  // Add call site information, if available.
482  if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
483  result = CallSiteLoc::get(result, translateLoc(inlinedAt));
484 
485  return result;
486 }
487 
488 DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) {
489  if (!node)
490  return nullptr;
491 
493 
494  // Begin processing the operations.
495  for (const llvm::DIExpression::ExprOperand &op : node->expr_ops()) {
496  SmallVector<uint64_t> operands;
497  operands.reserve(op.getNumArgs());
498  for (const auto &i : llvm::seq(op.getNumArgs()))
499  operands.push_back(op.getArg(i));
500  const auto attr = DIExpressionElemAttr::get(context, op.getOp(), operands);
501  ops.push_back(attr);
502  }
503  return DIExpressionAttr::get(context, ops);
504 }
505 
507  llvm::DIGlobalVariableExpression *node) {
509  context, translate(node->getVariable()),
510  translateExpression(node->getExpression()));
511 }
512 
513 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
514  if (!stringNode)
515  return StringAttr();
516  return StringAttr::get(context, stringNode->getString());
517 }
518 
519 DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {
520  DistinctAttr &id = nodeToDistinctAttr[node];
521  if (!id)
522  id = DistinctAttr::create(UnitAttr::get(context));
523  return id;
524 }
static function_ref< DIRecursiveTypeAttrInterface(DistinctAttr)> getRecSelfConstructor(llvm::DINode *node)
Get the getRecSelf constructor for the translated type of node if its translated DITypeAttr supports ...
static MLIRContext * getContext(OpFoldResult val)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
An attribute that associates a referenced attribute with a unique identifier.
static DistinctAttr create(Attribute referencedAttr)
Creates a distinct attribute that associates a referenced attribute with a unique identifier.
This class represents the base attribute for all debug info attributes.
Definition: LLVMAttrs.h:27
This class represents a LLVM attribute that describes a debug info scope.
Definition: LLVMAttrs.h:36
This class represents a LLVM attribute that describes a debug info type.
Definition: LLVMAttrs.h:55
This class represents a LLVM attribute that describes a debug info variable.
Definition: LLVMAttrs.h:64
DINodeAttr translate(llvm::DINode *node)
Translates the given LLVM debug metadata to MLIR.
DIExpressionAttr translateExpression(llvm::DIExpression *node)
Translates the LLVM DWARF expression metadata to MLIR.
DIGlobalVariableExpressionAttr translateGlobalVariableExpression(llvm::DIGlobalVariableExpression *node)
Translates the LLVM DWARF global variable expression metadata to MLIR.
Location translateLoc(llvm::DILocation *loc)
Translates the given LLVM debug location to an MLIR location.
Location translateFuncLocation(llvm::Function *func)
Translates the debug information for the given function into a Location.
DebugImporter(ModuleOp mlirModule, bool dropDICompositeTypeElements)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
BoundType
The type of bound: equal, lower bound or upper bound.
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...