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(), /*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  symbolizeDIFlags(node->getFlags()).value_or(DIFlags::Zero));
185 }
186 
187 DIVariableAttr DebugImporter::translateImpl(llvm::DIVariable *node) {
188  return cast<DIVariableAttr>(translate(static_cast<llvm::DINode *>(node)));
189 }
190 
191 DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) {
192  return cast<DIScopeAttr>(translate(static_cast<llvm::DINode *>(node)));
193 }
194 
195 DIModuleAttr DebugImporter::translateImpl(llvm::DIModule *node) {
196  return DIModuleAttr::get(
197  context, translate(node->getFile()), translate(node->getScope()),
198  getStringAttrOrNull(node->getRawName()),
199  getStringAttrOrNull(node->getRawConfigurationMacros()),
200  getStringAttrOrNull(node->getRawIncludePath()),
201  getStringAttrOrNull(node->getRawAPINotesFile()), node->getLineNo(),
202  node->getIsDecl());
203 }
204 
205 DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
206  return DINamespaceAttr::get(context, getStringAttrOrNull(node->getRawName()),
207  translate(node->getScope()),
208  node->getExportSymbols());
209 }
210 
211 DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
212  // Only definitions require a distinct identifier.
214  if (node->isDistinct())
215  id = getOrCreateDistinctID(node);
216  // Return nullptr if the scope or type is invalid.
217  DIScopeAttr scope = translate(node->getScope());
218  if (node->getScope() && !scope)
219  return nullptr;
220  std::optional<DISubprogramFlags> subprogramFlags =
221  symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags());
222  assert(subprogramFlags && "expected valid subprogram flags");
223  DISubroutineTypeAttr type = translate(node->getType());
224  if (node->getType() && !type)
225  return nullptr;
226  return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
227  getStringAttrOrNull(node->getRawName()),
228  getStringAttrOrNull(node->getRawLinkageName()),
229  translate(node->getFile()), node->getLine(),
230  node->getScopeLine(), *subprogramFlags, type);
231 }
232 
233 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
234  auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute {
235  if (data.isNull())
236  return nullptr;
237  if (auto *constInt = dyn_cast<llvm::ConstantInt *>(data))
238  return IntegerAttr::get(IntegerType::get(context, 64),
239  constInt->getSExtValue());
240  if (auto *expr = dyn_cast<llvm::DIExpression *>(data))
241  return translateExpression(expr);
242  if (auto *var = dyn_cast<llvm::DIVariable *>(data)) {
243  if (auto *local = dyn_cast<llvm::DILocalVariable>(var))
244  return translate(local);
245  if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var))
246  return translate(global);
247  return nullptr;
248  }
249  return nullptr;
250  };
251  Attribute count = getAttrOrNull(node->getCount());
252  Attribute upperBound = getAttrOrNull(node->getUpperBound());
253  // Either count or the upper bound needs to be present. Otherwise, the
254  // metadata is invalid. The conversion might fail due to unsupported DI nodes.
255  if (!count && !upperBound)
256  return {};
257  return DISubrangeAttr::get(context, count,
258  getAttrOrNull(node->getLowerBound()), upperBound,
259  getAttrOrNull(node->getStride()));
260 }
261 
262 DISubroutineTypeAttr
263 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
265  for (llvm::DIType *type : node->getTypeArray()) {
266  if (!type) {
267  // A nullptr entry may appear at the beginning or the end of the
268  // subroutine types list modeling either a void result type or the type of
269  // a variadic argument. Translate the nullptr to an explicit
270  // DINullTypeAttr since the attribute list cannot contain a nullptr entry.
271  types.push_back(DINullTypeAttr::get(context));
272  continue;
273  }
274  types.push_back(translate(type));
275  }
276  // Return nullptr if any of the types is invalid.
277  if (llvm::is_contained(types, nullptr))
278  return nullptr;
279  return DISubroutineTypeAttr::get(context, node->getCC(), types);
280 }
281 
282 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
283  return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
284 }
285 
287  if (!node)
288  return nullptr;
289 
290  // Check for a cached instance.
291  auto cacheEntry = cache.lookupOrInit(node);
292  if (std::optional<DINodeAttr> result = cacheEntry.get())
293  return *result;
294 
295  // Convert the debug metadata if possible.
296  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {
297  if (auto *casted = dyn_cast<llvm::DIBasicType>(node))
298  return translateImpl(casted);
299  if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
300  return translateImpl(casted);
301  if (auto *casted = dyn_cast<llvm::DICompositeType>(node))
302  return translateImpl(casted);
303  if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))
304  return translateImpl(casted);
305  if (auto *casted = dyn_cast<llvm::DIStringType>(node))
306  return translateImpl(casted);
307  if (auto *casted = dyn_cast<llvm::DIFile>(node))
308  return translateImpl(casted);
309  if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
310  return translateImpl(casted);
311  if (auto *casted = dyn_cast<llvm::DILabel>(node))
312  return translateImpl(casted);
313  if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
314  return translateImpl(casted);
315  if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))
316  return translateImpl(casted);
317  if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))
318  return translateImpl(casted);
319  if (auto *casted = dyn_cast<llvm::DIModule>(node))
320  return translateImpl(casted);
321  if (auto *casted = dyn_cast<llvm::DINamespace>(node))
322  return translateImpl(casted);
323  if (auto *casted = dyn_cast<llvm::DISubprogram>(node))
324  return translateImpl(casted);
325  if (auto *casted = dyn_cast<llvm::DISubrange>(node))
326  return translateImpl(casted);
327  if (auto *casted = dyn_cast<llvm::DISubroutineType>(node))
328  return translateImpl(casted);
329  return nullptr;
330  };
331  if (DINodeAttr attr = translateNode(node)) {
332  // If this node was repeated, lookup its recursive ID and assign it to the
333  // base result.
334  if (cacheEntry.wasRepeated()) {
335  DistinctAttr recId = nodeToRecId.lookup(node);
336  auto recType = cast<DIRecursiveTypeAttrInterface>(attr);
337  attr = cast<DINodeAttr>(recType.withRecId(recId));
338  }
339  cacheEntry.resolve(attr);
340  return attr;
341  }
342  cacheEntry.resolve(nullptr);
343  return nullptr;
344 }
345 
346 /// Get the `getRecSelf` constructor for the translated type of `node` if its
347 /// translated DITypeAttr supports recursion. Otherwise, returns nullptr.
348 static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>
349 getRecSelfConstructor(llvm::DINode *node) {
350  using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>;
352  .Case([&](llvm::DICompositeType *) {
353  return CtorType(DICompositeTypeAttr::getRecSelf);
354  })
355  .Default(CtorType());
356 }
357 
358 std::optional<DINodeAttr> DebugImporter::createRecSelf(llvm::DINode *node) {
359  auto recSelfCtor = getRecSelfConstructor(node);
360  if (!recSelfCtor)
361  return std::nullopt;
362 
363  // The original node may have already been assigned a recursive ID from
364  // a different self-reference. Use that if possible.
365  DistinctAttr recId = nodeToRecId.lookup(node);
366  if (!recId) {
367  recId = DistinctAttr::create(UnitAttr::get(context));
368  nodeToRecId[node] = recId;
369  }
370  DIRecursiveTypeAttrInterface recSelf = recSelfCtor(recId);
371  return cast<DINodeAttr>(recSelf);
372 }
373 
374 //===----------------------------------------------------------------------===//
375 // Locations
376 //===----------------------------------------------------------------------===//
377 
378 Location DebugImporter::translateLoc(llvm::DILocation *loc) {
379  if (!loc)
380  return UnknownLoc::get(context);
381 
382  // Get the file location of the instruction.
383  Location result = FileLineColLoc::get(context, loc->getFilename(),
384  loc->getLine(), loc->getColumn());
385 
386  // Add scope information.
387  assert(loc->getScope() && "expected non-null scope");
388  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
389  context);
390 
391  // Add call site information, if available.
392  if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
393  result = CallSiteLoc::get(result, translateLoc(inlinedAt));
394 
395  return result;
396 }
397 
398 DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) {
399  if (!node)
400  return nullptr;
401 
403 
404  // Begin processing the operations.
405  for (const llvm::DIExpression::ExprOperand &op : node->expr_ops()) {
406  SmallVector<uint64_t> operands;
407  operands.reserve(op.getNumArgs());
408  for (const auto &i : llvm::seq(op.getNumArgs()))
409  operands.push_back(op.getArg(i));
410  const auto attr = DIExpressionElemAttr::get(context, op.getOp(), operands);
411  ops.push_back(attr);
412  }
413  return DIExpressionAttr::get(context, ops);
414 }
415 
417  llvm::DIGlobalVariableExpression *node) {
419  context, translate(node->getVariable()),
420  translateExpression(node->getExpression()));
421 }
422 
423 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
424  if (!stringNode)
425  return StringAttr();
426  return StringAttr::get(context, stringNode->getString());
427 }
428 
429 DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {
430  DistinctAttr &id = nodeToDistinctAttr[node];
431  if (!id)
432  id = DistinctAttr::create(UnitAttr::get(context));
433  return id;
434 }
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
Include the generated interface declarations.
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...