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