MLIR  18.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/IR/Constants.h"
17 #include "llvm/IR/DebugInfoMetadata.h"
18 #include "llvm/IR/Metadata.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/ErrorHandling.h"
21 
22 using namespace mlir;
23 using namespace mlir::LLVM;
24 using namespace mlir::LLVM::detail;
25 
27  if (!func->getSubprogram())
28  return UnknownLoc::get(context);
29 
30  // Add a fused location to link the subprogram information.
31  StringAttr name = StringAttr::get(context, func->getSubprogram()->getName());
33  {NameLoc::get(name)}, translate(func->getSubprogram()), context);
34 }
35 
36 //===----------------------------------------------------------------------===//
37 // Attributes
38 //===----------------------------------------------------------------------===//
39 
40 DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) {
41  return DIBasicTypeAttr::get(context, node->getTag(), node->getName(),
42  node->getSizeInBits(), node->getEncoding());
43 }
44 
45 DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {
46  std::optional<DIEmissionKind> emissionKind =
47  symbolizeDIEmissionKind(node->getEmissionKind());
48  return DICompileUnitAttr::get(context, node->getSourceLanguage(),
49  translate(node->getFile()),
50  getStringAttrOrNull(node->getRawProducer()),
51  node->isOptimized(), emissionKind.value());
52 }
53 
54 DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
55  std::optional<DIFlags> flags = symbolizeDIFlags(node->getFlags());
56  SmallVector<DINodeAttr> elements;
57  for (llvm::DINode *element : node->getElements()) {
58  assert(element && "expected a non-null element type");
59  elements.push_back(translate(element));
60  }
61  // Drop the elements parameter if a cyclic dependency is detected. We
62  // currently cannot model these cycles and thus drop the parameter if
63  // required. A cyclic dependency is detected if one of the element nodes
64  // translates to a nullptr since the node is already on the translation stack.
65  // TODO: Support debug metadata with cyclic dependencies.
66  if (llvm::is_contained(elements, nullptr))
67  elements.clear();
69  context, node->getTag(), getStringAttrOrNull(node->getRawName()),
70  translate(node->getFile()), node->getLine(), translate(node->getScope()),
71  translate(node->getBaseType()), flags.value_or(DIFlags::Zero),
72  node->getSizeInBits(), node->getAlignInBits(), elements);
73 }
74 
75 DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) {
76  // Return nullptr if the base type is a cyclic dependency.
77  DITypeAttr baseType = translate(node->getBaseType());
78  if (node->getBaseType() && !baseType)
79  return nullptr;
81  context, node->getTag(), getStringAttrOrNull(node->getRawName()),
82  baseType, node->getSizeInBits(), node->getAlignInBits(),
83  node->getOffsetInBits());
84 }
85 
86 DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {
87  return DIFileAttr::get(context, node->getFilename(), node->getDirectory());
88 }
89 
90 DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) {
91  return DILabelAttr::get(context, translate(node->getScope()),
92  getStringAttrOrNull(node->getRawName()),
93  translate(node->getFile()), node->getLine());
94 }
95 
96 DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) {
97  return DILexicalBlockAttr::get(context, translate(node->getScope()),
98  translate(node->getFile()), node->getLine(),
99  node->getColumn());
100 }
101 
102 DILexicalBlockFileAttr
103 DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) {
104  return DILexicalBlockFileAttr::get(context, translate(node->getScope()),
105  translate(node->getFile()),
106  node->getDiscriminator());
107 }
108 
109 DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) {
110  return DILocalVariableAttr::get(context, translate(node->getScope()),
111  getStringAttrOrNull(node->getRawName()),
112  translate(node->getFile()), node->getLine(),
113  node->getArg(), node->getAlignInBits(),
114  translate(node->getType()));
115 }
116 
117 DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) {
118  return cast<DIScopeAttr>(translate(static_cast<llvm::DINode *>(node)));
119 }
120 
121 DIModuleAttr DebugImporter::translateImpl(llvm::DIModule *node) {
122  return DIModuleAttr::get(
123  context, translate(node->getFile()), translate(node->getScope()),
124  getStringAttrOrNull(node->getRawName()),
125  getStringAttrOrNull(node->getRawConfigurationMacros()),
126  getStringAttrOrNull(node->getRawIncludePath()),
127  getStringAttrOrNull(node->getRawAPINotesFile()), node->getLineNo(),
128  node->getIsDecl());
129 }
130 
131 DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
132  return DINamespaceAttr::get(context, getStringAttrOrNull(node->getRawName()),
133  translate(node->getScope()),
134  node->getExportSymbols());
135 }
136 
137 DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
138  std::optional<DISubprogramFlags> subprogramFlags =
139  symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags());
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  DISubroutineTypeAttr type = translate(node->getType());
145  if (node->getType() && !type)
146  return nullptr;
147  return DISubprogramAttr::get(context, translate(node->getUnit()), scope,
148  getStringAttrOrNull(node->getRawName()),
149  getStringAttrOrNull(node->getRawLinkageName()),
150  translate(node->getFile()), node->getLine(),
151  node->getScopeLine(), subprogramFlags.value(),
152  type);
153 }
154 
155 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
156  auto getIntegerAttrOrNull = [&](llvm::DISubrange::BoundType data) {
157  if (auto *constInt = llvm::dyn_cast_or_null<llvm::ConstantInt *>(data))
158  return IntegerAttr::get(IntegerType::get(context, 64),
159  constInt->getSExtValue());
160  return IntegerAttr();
161  };
162  IntegerAttr count = getIntegerAttrOrNull(node->getCount());
163  IntegerAttr upperBound = getIntegerAttrOrNull(node->getUpperBound());
164  // Either count or the upper bound needs to be present. Otherwise, the
165  // metadata is invalid. The conversion might fail due to unsupported DI nodes.
166  if (!count && !upperBound)
167  return {};
168  return DISubrangeAttr::get(
169  context, count, getIntegerAttrOrNull(node->getLowerBound()), upperBound,
170  getIntegerAttrOrNull(node->getStride()));
171 }
172 
173 DISubroutineTypeAttr
174 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
176  for (llvm::DIType *type : node->getTypeArray()) {
177  if (!type) {
178  // A nullptr entry may appear at the beginning or the end of the
179  // subroutine types list modeling either a void result type or the type of
180  // a variadic argument. Translate the nullptr to an explicit
181  // DINullTypeAttr since the attribute list cannot contain a nullptr entry.
182  types.push_back(DINullTypeAttr::get(context));
183  continue;
184  }
185  types.push_back(translate(type));
186  }
187  // Return nullptr if any of the types is a cyclic dependency.
188  if (llvm::is_contained(types, nullptr))
189  return nullptr;
190  return DISubroutineTypeAttr::get(context, node->getCC(), types);
191 }
192 
193 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
194  return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
195 }
196 
198  if (!node)
199  return nullptr;
200 
201  // Check for a cached instance.
202  if (DINodeAttr attr = nodeToAttr.lookup(node))
203  return attr;
204 
205  // Return nullptr if a cyclic dependency is detected since the same node is
206  // being traversed twice. This check avoids infinite recursion if the debug
207  // metadata contains cycles.
208  if (!translationStack.insert(node))
209  return nullptr;
210  auto guard = llvm::make_scope_exit([&]() { translationStack.pop_back(); });
211 
212  // Convert the debug metadata if possible.
213  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {
214  if (auto *casted = dyn_cast<llvm::DIBasicType>(node))
215  return translateImpl(casted);
216  if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
217  return translateImpl(casted);
218  if (auto *casted = dyn_cast<llvm::DICompositeType>(node))
219  return translateImpl(casted);
220  if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))
221  return translateImpl(casted);
222  if (auto *casted = dyn_cast<llvm::DIFile>(node))
223  return translateImpl(casted);
224  if (auto *casted = dyn_cast<llvm::DILabel>(node))
225  return translateImpl(casted);
226  if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
227  return translateImpl(casted);
228  if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))
229  return translateImpl(casted);
230  if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))
231  return translateImpl(casted);
232  if (auto *casted = dyn_cast<llvm::DIModule>(node))
233  return translateImpl(casted);
234  if (auto *casted = dyn_cast<llvm::DINamespace>(node))
235  return translateImpl(casted);
236  if (auto *casted = dyn_cast<llvm::DISubprogram>(node))
237  return translateImpl(casted);
238  if (auto *casted = dyn_cast<llvm::DISubrange>(node))
239  return translateImpl(casted);
240  if (auto *casted = dyn_cast<llvm::DISubroutineType>(node))
241  return translateImpl(casted);
242  return nullptr;
243  };
244  if (DINodeAttr attr = translateNode(node)) {
245  nodeToAttr.insert({node, attr});
246  return attr;
247  }
248  return nullptr;
249 }
250 
251 //===----------------------------------------------------------------------===//
252 // Locations
253 //===----------------------------------------------------------------------===//
254 
255 Location DebugImporter::translateLoc(llvm::DILocation *loc) {
256  if (!loc)
257  return UnknownLoc::get(context);
258 
259  // Get the file location of the instruction.
260  Location result = FileLineColLoc::get(context, loc->getFilename(),
261  loc->getLine(), loc->getColumn());
262 
263  // Add call site information, if available.
264  if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
265  result = CallSiteLoc::get(result, translateLoc(inlinedAt));
266 
267  // Add scope information.
268  assert(loc->getScope() && "expected non-null scope");
269  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
270  context);
271  return result;
272 }
273 
274 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
275  if (!stringNode)
276  return StringAttr();
277  return StringAttr::get(context, stringNode->getString());
278 }
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.
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.
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.
This header declares functions that assist transformations in the MemRef dialect.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...