MLIR  20.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  : cache([&](llvm::DINode *node) { return createRecSelf(node); }),
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(), 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  };
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;
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 
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.
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  return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
249  getStringAttrOrNull(node->getRawName()),
250  getStringAttrOrNull(node->getRawLinkageName()),
251  translate(node->getFile()), node->getLine(),
252  node->getScopeLine(), *subprogramFlags, type,
253  retainedNodes);
254 }
255 
256 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
257  auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute {
258  if (data.isNull())
259  return nullptr;
260  if (auto *constInt = dyn_cast<llvm::ConstantInt *>(data))
261  return IntegerAttr::get(IntegerType::get(context, 64),
262  constInt->getSExtValue());
263  if (auto *expr = dyn_cast<llvm::DIExpression *>(data))
264  return translateExpression(expr);
265  if (auto *var = dyn_cast<llvm::DIVariable *>(data)) {
266  if (auto *local = dyn_cast<llvm::DILocalVariable>(var))
267  return translate(local);
268  if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var))
269  return translate(global);
270  return nullptr;
271  }
272  return nullptr;
273  };
274  Attribute count = getAttrOrNull(node->getCount());
275  Attribute upperBound = getAttrOrNull(node->getUpperBound());
276  // Either count or the upper bound needs to be present. Otherwise, the
277  // metadata is invalid. The conversion might fail due to unsupported DI nodes.
278  if (!count && !upperBound)
279  return {};
280  return DISubrangeAttr::get(context, count,
281  getAttrOrNull(node->getLowerBound()), upperBound,
282  getAttrOrNull(node->getStride()));
283 }
284 
285 DISubroutineTypeAttr
286 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
288  for (llvm::DIType *type : node->getTypeArray()) {
289  if (!type) {
290  // A nullptr entry may appear at the beginning or the end of the
291  // subroutine types list modeling either a void result type or the type of
292  // a variadic argument. Translate the nullptr to an explicit
293  // DINullTypeAttr since the attribute list cannot contain a nullptr entry.
294  types.push_back(DINullTypeAttr::get(context));
295  continue;
296  }
297  types.push_back(translate(type));
298  }
299  // Return nullptr if any of the types is invalid.
300  if (llvm::is_contained(types, nullptr))
301  return nullptr;
302  return DISubroutineTypeAttr::get(context, node->getCC(), types);
303 }
304 
305 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
306  return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
307 }
308 
310  if (!node)
311  return nullptr;
312 
313  // Check for a cached instance.
314  auto cacheEntry = cache.lookupOrInit(node);
315  if (std::optional<DINodeAttr> result = cacheEntry.get())
316  return *result;
317 
318  // Convert the debug metadata if possible.
319  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {
320  if (auto *casted = dyn_cast<llvm::DIBasicType>(node))
321  return translateImpl(casted);
322  if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
323  return translateImpl(casted);
324  if (auto *casted = dyn_cast<llvm::DICompositeType>(node))
325  return translateImpl(casted);
326  if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))
327  return translateImpl(casted);
328  if (auto *casted = dyn_cast<llvm::DIStringType>(node))
329  return translateImpl(casted);
330  if (auto *casted = dyn_cast<llvm::DIFile>(node))
331  return translateImpl(casted);
332  if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
333  return translateImpl(casted);
334  if (auto *casted = dyn_cast<llvm::DIImportedEntity>(node))
335  return translateImpl(casted);
336  if (auto *casted = dyn_cast<llvm::DILabel>(node))
337  return translateImpl(casted);
338  if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
339  return translateImpl(casted);
340  if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))
341  return translateImpl(casted);
342  if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))
343  return translateImpl(casted);
344  if (auto *casted = dyn_cast<llvm::DIModule>(node))
345  return translateImpl(casted);
346  if (auto *casted = dyn_cast<llvm::DINamespace>(node))
347  return translateImpl(casted);
348  if (auto *casted = dyn_cast<llvm::DISubprogram>(node))
349  return translateImpl(casted);
350  if (auto *casted = dyn_cast<llvm::DISubrange>(node))
351  return translateImpl(casted);
352  if (auto *casted = dyn_cast<llvm::DISubroutineType>(node))
353  return translateImpl(casted);
354  return nullptr;
355  };
356  if (DINodeAttr attr = translateNode(node)) {
357  // If this node was repeated, lookup its recursive ID and assign it to the
358  // base result.
359  if (cacheEntry.wasRepeated()) {
360  DistinctAttr recId = nodeToRecId.lookup(node);
361  auto recType = cast<DIRecursiveTypeAttrInterface>(attr);
362  attr = cast<DINodeAttr>(recType.withRecId(recId));
363  }
364  cacheEntry.resolve(attr);
365  return attr;
366  }
367  cacheEntry.resolve(nullptr);
368  return nullptr;
369 }
370 
371 /// Get the `getRecSelf` constructor for the translated type of `node` if its
372 /// translated DITypeAttr supports recursion. Otherwise, returns nullptr.
373 static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>
374 getRecSelfConstructor(llvm::DINode *node) {
375  using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>;
377  .Case([&](llvm::DICompositeType *) {
378  return CtorType(DICompositeTypeAttr::getRecSelf);
379  })
380  .Case([&](llvm::DISubprogram *) {
381  return CtorType(DISubprogramAttr::getRecSelf);
382  })
383  .Default(CtorType());
384 }
385 
386 std::optional<DINodeAttr> DebugImporter::createRecSelf(llvm::DINode *node) {
387  auto recSelfCtor = getRecSelfConstructor(node);
388  if (!recSelfCtor)
389  return std::nullopt;
390 
391  // The original node may have already been assigned a recursive ID from
392  // a different self-reference. Use that if possible.
393  DistinctAttr recId = nodeToRecId.lookup(node);
394  if (!recId) {
395  recId = DistinctAttr::create(UnitAttr::get(context));
396  nodeToRecId[node] = recId;
397  }
398  DIRecursiveTypeAttrInterface recSelf = recSelfCtor(recId);
399  return cast<DINodeAttr>(recSelf);
400 }
401 
402 //===----------------------------------------------------------------------===//
403 // Locations
404 //===----------------------------------------------------------------------===//
405 
406 Location DebugImporter::translateLoc(llvm::DILocation *loc) {
407  if (!loc)
408  return UnknownLoc::get(context);
409 
410  // Get the file location of the instruction.
411  Location result = FileLineColLoc::get(context, loc->getFilename(),
412  loc->getLine(), loc->getColumn());
413 
414  // Add scope information.
415  assert(loc->getScope() && "expected non-null scope");
416  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
417  context);
418 
419  // Add call site information, if available.
420  if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
421  result = CallSiteLoc::get(result, translateLoc(inlinedAt));
422 
423  return result;
424 }
425 
426 DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) {
427  if (!node)
428  return nullptr;
429 
431 
432  // Begin processing the operations.
433  for (const llvm::DIExpression::ExprOperand &op : node->expr_ops()) {
434  SmallVector<uint64_t> operands;
435  operands.reserve(op.getNumArgs());
436  for (const auto &i : llvm::seq(op.getNumArgs()))
437  operands.push_back(op.getArg(i));
438  const auto attr = DIExpressionElemAttr::get(context, op.getOp(), operands);
439  ops.push_back(attr);
440  }
441  return DIExpressionAttr::get(context, ops);
442 }
443 
445  llvm::DIGlobalVariableExpression *node) {
447  context, translate(node->getVariable()),
448  translateExpression(node->getExpression()));
449 }
450 
451 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
452  if (!stringNode)
453  return StringAttr();
454  return StringAttr::get(context, stringNode->getString());
455 }
456 
457 DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {
458  DistinctAttr &id = nodeToDistinctAttr[node];
459  if (!id)
460  id = DistinctAttr::create(UnitAttr::get(context));
461  return id;
462 }
static function_ref< DIRecursiveTypeAttrInterface(DistinctAttr)> getRecSelfConstructor(llvm::DINode *node)
Get the getRecSelf constructor for the translated type of node if its translated DITypeAttr supports ...
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
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
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...