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"
30 bool dropDICompositeTypeElements)
32 context(mlirModule.
getContext()), mlirModule(mlirModule),
33 dropDICompositeTypeElements(dropDICompositeTypeElements) {}
36 llvm::DISubprogram *subprogram = func->getSubprogram();
42 StringAttr fileName =
StringAttr::get(context, subprogram->getFilename());
53 DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) {
55 node->getSizeInBits(), node->getEncoding());
58 DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {
59 std::optional<DIEmissionKind> emissionKind =
60 symbolizeDIEmissionKind(node->getEmissionKind());
61 std::optional<DINameTableKind> nameTableKind = symbolizeDINameTableKind(
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());
71 DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
72 std::optional<DIFlags> flags = symbolizeDIFlags(node->getFlags());
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");
84 if (llvm::is_contained(elements,
nullptr))
89 if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType)
92 context, node->getTag(), {},
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);
99 DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) {
102 if (node->getBaseType() && !baseType)
105 translate(dyn_cast_or_null<llvm::DINode>(node->getExtraData()));
107 context, node->getTag(), getStringAttrOrNull(node->getRawName()),
108 baseType, node->getSizeInBits(), node->getAlignInBits(),
109 node->getOffsetInBits(), extraData);
112 DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {
113 return DIFileAttr::get(context, node->getFilename(), node->getDirectory());
116 DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) {
119 if (node->getScope() && !scope)
122 getStringAttrOrNull(node->getRawName()),
123 translate(node->getFile()), node->getLine());
126 DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) {
129 if (node->getScope() && !scope)
132 node->getLine(), node->getColumn());
135 DILexicalBlockFileAttr
136 DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) {
139 if (node->getScope() && !scope)
142 node->getDiscriminator());
146 DebugImporter::translateImpl(llvm::DIGlobalVariable *node) {
149 auto convertToStringAttr = [&](StringRef name) -> StringAttr {
156 convertToStringAttr(node->getName()),
157 convertToStringAttr(node->getLinkageName()),
translate(node->getFile()),
158 node->getLine(),
translate(node->getType()), node->isLocalToUnit(),
159 node->isDefinition(), node->getAlignInBits());
162 DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) {
165 if (node->getScope() && !scope)
168 context, scope, getStringAttrOrNull(node->getRawName()),
169 translate(node->getFile()), node->getLine(), node->getArg(),
170 node->getAlignInBits(),
translate(node->getType()));
173 DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) {
174 return cast<DIScopeAttr>(
translate(
static_cast<llvm::DINode *
>(node)));
177 DIModuleAttr DebugImporter::translateImpl(llvm::DIModule *node) {
180 getStringAttrOrNull(node->getRawName()),
181 getStringAttrOrNull(node->getRawConfigurationMacros()),
182 getStringAttrOrNull(node->getRawIncludePath()),
183 getStringAttrOrNull(node->getRawAPINotesFile()), node->getLineNo(),
187 DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
190 node->getExportSymbols());
193 DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
196 if (node->isDistinct())
197 id = getOrCreateDistinctID(node);
200 if (node->getScope() && !scope)
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)
209 getStringAttrOrNull(node->getRawName()),
210 getStringAttrOrNull(node->getRawLinkageName()),
211 translate(node->getFile()), node->getLine(),
212 node->getScopeLine(), *subprogramFlags, type);
215 DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
217 if (
auto *constInt = llvm::dyn_cast_or_null<llvm::ConstantInt *>(data))
219 constInt->getSExtValue());
220 return IntegerAttr();
222 IntegerAttr count = getIntegerAttrOrNull(node->getCount());
223 IntegerAttr upperBound = getIntegerAttrOrNull(node->getUpperBound());
226 if (!count && !upperBound)
229 context, count, getIntegerAttrOrNull(node->getLowerBound()), upperBound,
230 getIntegerAttrOrNull(node->getStride()));
234 DebugImporter::translateImpl(llvm::DISubroutineType *node) {
236 for (llvm::DIType *type : node->getTypeArray()) {
248 if (llvm::is_contained(types,
nullptr))
253 DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
254 return cast<DITypeAttr>(
translate(
static_cast<llvm::DINode *
>(node)));
262 if (
DINodeAttr attr = nodeToAttr.lookup(node))
267 if (
DINodeAttr attr = recursionPruner.pruneOrPushTranslationStack(node))
270 auto guard = llvm::make_scope_exit(
271 [&]() { recursionPruner.popTranslationStack(node); });
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);
308 auto [result, isSelfContained] =
309 recursionPruner.finalizeTranslation(node, attr);
312 nodeToAttr.try_emplace(node, result);
328 .Case([&](llvm::DICompositeType *) {
329 return CtorType(DICompositeTypeAttr::getRecSelf);
331 .Default(CtorType());
334 DINodeAttr DebugImporter::RecursionPruner::pruneOrPushTranslationStack(
335 llvm::DINode *node) {
343 auto [iter, inserted] = translationStack.try_emplace(node);
347 DIRecursiveTypeAttrInterface recSelf = iter->second.recSelf;
352 nodeToRecId[node] = recId;
354 recSelf = recSelfCtor(recId);
355 iter->second.recSelf = recSelf;
358 translationStack.back().second.unboundSelfRefs.insert(recSelf);
359 return cast<DINodeAttr>(recSelf);
366 std::pair<DINodeAttr, bool>
367 DebugImporter::RecursionPruner::finalizeTranslation(llvm::DINode *node,
371 if (translationStack.empty())
372 return {result,
true};
373 if (translationStack.back().first != node)
374 return {result, translationStack.back().second.unboundSelfRefs.empty()};
376 TranslationState &state = translationStack.back().second;
379 if (DIRecursiveTypeAttrInterface recSelf = state.recSelf) {
380 auto recType = cast<DIRecursiveTypeAttrInterface>(result);
381 result = cast<DINodeAttr>(recType.withRecId(recSelf.getRecId()));
383 state.unboundSelfRefs.erase(recSelf);
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};
393 return {result,
true};
396 void DebugImporter::RecursionPruner::popTranslationStack(llvm::DINode *node) {
399 if (translationStack.empty() || translationStack.back().first != node)
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();
413 TranslationState &nextLayerState = (++translationStack.rbegin())->second;
414 nextLayerState.unboundSelfRefs.insert(currLayerState.unboundSelfRefs.begin(),
415 currLayerState.unboundSelfRefs.end());
416 translationStack.pop_back();
419 DINodeAttr DebugImporter::RecursionPruner::lookup(llvm::DINode *node) {
420 auto cacheIter = dependentCache.find(node);
421 if (cacheIter == dependentCache.end())
424 DependentTranslation &entry = cacheIter->second;
425 if (llvm::set_is_subset(entry.unboundSelfRefs,
426 translationStack.back().second.unboundSelfRefs))
430 dependentCache.erase(cacheIter);
444 loc->getLine(), loc->getColumn());
447 assert(loc->getScope() &&
"expected non-null scope");
452 if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
462 for (
const llvm::DIExpression::ExprOperand &op : node->expr_ops()) {
464 operands.reserve(op.getNumArgs());
465 for (
const auto &i : llvm::seq(op.getNumArgs()))
466 operands.push_back(op.getArg(i));
474 llvm::DIGlobalVariableExpression *node) {
480 StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
486 DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) {
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.
This class represents a LLVM attribute that describes a debug info scope.
This class represents a LLVM attribute that describes a debug info type.
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...
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...