@@ -51,10 +51,9 @@ DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {
51
51
std::optional<DIEmissionKind> emissionKind =
52
52
symbolizeDIEmissionKind (node->getEmissionKind ());
53
53
return DICompileUnitAttr::get (
54
- context, DistinctAttr::create (UnitAttr::get (context)),
55
- node->getSourceLanguage (), translate (node->getFile ()),
56
- getStringAttrOrNull (node->getRawProducer ()), node->isOptimized (),
57
- emissionKind.value ());
54
+ context, getOrCreateDistinctID (node), node->getSourceLanguage (),
55
+ translate (node->getFile ()), getStringAttrOrNull (node->getRawProducer ()),
56
+ node->isOptimized (), emissionKind.value ());
58
57
}
59
58
60
59
DICompositeTypeAttr DebugImporter::translateImpl (llvm::DICompositeType *node) {
@@ -64,11 +63,7 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
64
63
assert (element && " expected a non-null element type" );
65
64
elements.push_back (translate (element));
66
65
}
67
- // Drop the elements parameter if a cyclic dependency is detected. We
68
- // currently cannot model these cycles and thus drop the parameter if
69
- // required. A cyclic dependency is detected if one of the element nodes
70
- // translates to a nullptr since the node is already on the translation stack.
71
- // TODO: Support debug metadata with cyclic dependencies.
66
+ // Drop the elements parameter if any of the elements are invalid.
72
67
if (llvm::is_contained (elements, nullptr ))
73
68
elements.clear ();
74
69
DITypeAttr baseType = translate (node->getBaseType ());
@@ -84,7 +79,7 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
84
79
}
85
80
86
81
DIDerivedTypeAttr DebugImporter::translateImpl (llvm::DIDerivedType *node) {
87
- // Return nullptr if the base type is a cyclic dependency .
82
+ // Return nullptr if the base type invalid .
88
83
DITypeAttr baseType = translate (node->getBaseType ());
89
84
if (node->getBaseType () && !baseType)
90
85
return nullptr ;
@@ -166,14 +161,14 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
166
161
// Only definitions require a distinct identifier.
167
162
mlir::DistinctAttr id;
168
163
if (node->isDistinct ())
169
- id = DistinctAttr::create ( UnitAttr::get (context) );
164
+ id = getOrCreateDistinctID (node );
170
165
std::optional<DISubprogramFlags> subprogramFlags =
171
166
symbolizeDISubprogramFlags (node->getSubprogram ()->getSPFlags ());
172
- // Return nullptr if the scope or type is a cyclic dependency .
173
- DIScopeAttr scope = translate (node->getScope ());
167
+ // Return nullptr if the scope or type is invalid .
168
+ DIScopeAttr scope = cast<DIScopeAttr>( translate (node->getScope () ));
174
169
if (node->getScope () && !scope)
175
170
return nullptr ;
176
- DISubroutineTypeAttr type = translate (node->getType ());
171
+ DIRecursiveTypeAttrOf< DISubroutineTypeAttr> type = translate (node->getType ());
177
172
if (node->getType () && !type)
178
173
return nullptr ;
179
174
return DISubprogramAttr::get (context, id, translate (node->getUnit ()), scope,
@@ -216,7 +211,7 @@ DebugImporter::translateImpl(llvm::DISubroutineType *node) {
216
211
}
217
212
types.push_back (translate (type));
218
213
}
219
- // Return nullptr if any of the types is a cyclic dependency .
214
+ // Return nullptr if any of the types is invalid .
220
215
if (llvm::is_contained (types, nullptr ))
221
216
return nullptr ;
222
217
return DISubroutineTypeAttr::get (context, node->getCC (), types);
@@ -234,12 +229,47 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
234
229
if (DINodeAttr attr = nodeToAttr.lookup (node))
235
230
return attr;
236
231
237
- // Return nullptr if a cyclic dependency is detected since the same node is
238
- // being traversed twice. This check avoids infinite recursion if the debug
239
- // metadata contains cycles.
240
- if (!translationStack.insert (node))
241
- return nullptr ;
242
- auto guard = llvm::make_scope_exit ([&]() { translationStack.pop_back (); });
232
+ // If a cyclic dependency is detected since the same node is being traversed
233
+ // twice, emit a recursive self type, and mark the duplicate node on the
234
+ // translationStack so it can emit a recursive decl type.
235
+ auto *typeNode = dyn_cast<llvm::DIType>(node);
236
+ if (typeNode) {
237
+ auto [iter, inserted] = typeTranslationStack.try_emplace (typeNode, nullptr );
238
+ if (!inserted) {
239
+ // The original node may have already been assigned a recursive ID from
240
+ // a different self-reference. Use that if possible.
241
+ DistinctAttr recId = iter->second ;
242
+ if (!recId) {
243
+ recId = DistinctAttr::create (UnitAttr::get (context));
244
+ iter->second = recId;
245
+ }
246
+ unboundRecursiveSelfRefs.back ().insert (recId);
247
+ return DIRecursiveTypeAttr::get (recId);
248
+ }
249
+ } else {
250
+ bool inserted =
251
+ nonTypeTranslationStack.insert ({node, typeTranslationStack.size ()});
252
+ assert (inserted && " recursion is only supported via DITypes" );
253
+ }
254
+
255
+ unboundRecursiveSelfRefs.emplace_back ();
256
+
257
+ auto guard = llvm::make_scope_exit ([&]() {
258
+ if (typeNode)
259
+ typeTranslationStack.pop_back ();
260
+ else
261
+ nonTypeTranslationStack.pop_back ();
262
+
263
+ // Copy unboundRecursiveSelfRefs down to the previous level.
264
+ if (unboundRecursiveSelfRefs.size () == 1 )
265
+ assert (unboundRecursiveSelfRefs.back ().empty () &&
266
+ " internal error: unbound recursive self reference at top level." );
267
+ else
268
+ unboundRecursiveSelfRefs[unboundRecursiveSelfRefs.size () - 2 ].insert (
269
+ unboundRecursiveSelfRefs.back ().begin (),
270
+ unboundRecursiveSelfRefs.back ().end ());
271
+ unboundRecursiveSelfRefs.pop_back ();
272
+ });
243
273
244
274
// Convert the debug metadata if possible.
245
275
auto translateNode = [this ](llvm::DINode *node) -> DINodeAttr {
@@ -276,7 +306,21 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
276
306
return nullptr ;
277
307
};
278
308
if (DINodeAttr attr = translateNode (node)) {
279
- nodeToAttr.insert ({node, attr});
309
+ // If this node was marked as recursive, wrap with a recursive type.
310
+ if (typeNode) {
311
+ if (DistinctAttr id = typeTranslationStack.lookup (typeNode)) {
312
+ DITypeAttr typeAttr = cast<DITypeAttr>(attr);
313
+ attr = DIRecursiveTypeAttr::get (context, id, typeAttr);
314
+
315
+ // Remove the unbound recursive attr.
316
+ AttrTypeReplacer replacer;
317
+ unboundRecursiveSelfRefs.back ().erase (id);
318
+ }
319
+ }
320
+
321
+ // Only cache fully self-contained nodes.
322
+ if (unboundRecursiveSelfRefs.back ().empty ())
323
+ nodeToAttr.try_emplace (node, attr);
280
324
return attr;
281
325
}
282
326
return nullptr ;
@@ -333,3 +377,10 @@ StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
333
377
return StringAttr ();
334
378
return StringAttr::get (context, stringNode->getString ());
335
379
}
380
+
381
+ DistinctAttr DebugImporter::getOrCreateDistinctID (llvm::DINode *node) {
382
+ DistinctAttr &id = nodeToDistinctAttr[node];
383
+ if (!id)
384
+ id = DistinctAttr::create (UnitAttr::get (context));
385
+ return id;
386
+ }
0 commit comments