@@ -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 ;
@@ -179,14 +174,14 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
179
174
// Only definitions require a distinct identifier.
180
175
mlir::DistinctAttr id;
181
176
if (node->isDistinct ())
182
- id = DistinctAttr::create ( UnitAttr::get (context) );
177
+ id = getOrCreateDistinctID (node );
183
178
std::optional<DISubprogramFlags> subprogramFlags =
184
179
symbolizeDISubprogramFlags (node->getSubprogram ()->getSPFlags ());
185
- // Return nullptr if the scope or type is a cyclic dependency .
186
- DIScopeAttr scope = translate (node->getScope ());
180
+ // Return nullptr if the scope or type is invalid .
181
+ DIScopeAttr scope = cast<DIScopeAttr>( translate (node->getScope () ));
187
182
if (node->getScope () && !scope)
188
183
return nullptr ;
189
- DISubroutineTypeAttr type = translate (node->getType ());
184
+ DIRecursiveTypeAttrOf< DISubroutineTypeAttr> type = translate (node->getType ());
190
185
if (node->getType () && !type)
191
186
return nullptr ;
192
187
return DISubprogramAttr::get (context, id, translate (node->getUnit ()), scope,
@@ -229,7 +224,7 @@ DebugImporter::translateImpl(llvm::DISubroutineType *node) {
229
224
}
230
225
types.push_back (translate (type));
231
226
}
232
- // Return nullptr if any of the types is a cyclic dependency .
227
+ // Return nullptr if any of the types is invalid .
233
228
if (llvm::is_contained (types, nullptr ))
234
229
return nullptr ;
235
230
return DISubroutineTypeAttr::get (context, node->getCC (), types);
@@ -247,12 +242,47 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
247
242
if (DINodeAttr attr = nodeToAttr.lookup (node))
248
243
return attr;
249
244
250
- // Return nullptr if a cyclic dependency is detected since the same node is
251
- // being traversed twice. This check avoids infinite recursion if the debug
252
- // metadata contains cycles.
253
- if (!translationStack.insert (node))
254
- return nullptr ;
255
- auto guard = llvm::make_scope_exit ([&]() { translationStack.pop_back (); });
245
+ // If a cyclic dependency is detected since the same node is being traversed
246
+ // twice, emit a recursive self type, and mark the duplicate node on the
247
+ // translationStack so it can emit a recursive decl type.
248
+ auto *typeNode = dyn_cast<llvm::DIType>(node);
249
+ if (typeNode) {
250
+ auto [iter, inserted] = typeTranslationStack.try_emplace (typeNode, nullptr );
251
+ if (!inserted) {
252
+ // The original node may have already been assigned a recursive ID from
253
+ // a different self-reference. Use that if possible.
254
+ DistinctAttr recId = iter->second ;
255
+ if (!recId) {
256
+ recId = DistinctAttr::create (UnitAttr::get (context));
257
+ iter->second = recId;
258
+ }
259
+ unboundRecursiveSelfRefs.back ().insert (recId);
260
+ return DIRecursiveTypeAttr::get (recId);
261
+ }
262
+ } else {
263
+ bool inserted =
264
+ nonTypeTranslationStack.insert ({node, typeTranslationStack.size ()});
265
+ assert (inserted && " recursion is only supported via DITypes" );
266
+ }
267
+
268
+ unboundRecursiveSelfRefs.emplace_back ();
269
+
270
+ auto guard = llvm::make_scope_exit ([&]() {
271
+ if (typeNode)
272
+ typeTranslationStack.pop_back ();
273
+ else
274
+ nonTypeTranslationStack.pop_back ();
275
+
276
+ // Copy unboundRecursiveSelfRefs down to the previous level.
277
+ if (unboundRecursiveSelfRefs.size () == 1 )
278
+ assert (unboundRecursiveSelfRefs.back ().empty () &&
279
+ " internal error: unbound recursive self reference at top level." );
280
+ else
281
+ unboundRecursiveSelfRefs[unboundRecursiveSelfRefs.size () - 2 ].insert (
282
+ unboundRecursiveSelfRefs.back ().begin (),
283
+ unboundRecursiveSelfRefs.back ().end ());
284
+ unboundRecursiveSelfRefs.pop_back ();
285
+ });
256
286
257
287
// Convert the debug metadata if possible.
258
288
auto translateNode = [this ](llvm::DINode *node) -> DINodeAttr {
@@ -289,7 +319,21 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
289
319
return nullptr ;
290
320
};
291
321
if (DINodeAttr attr = translateNode (node)) {
292
- nodeToAttr.insert ({node, attr});
322
+ // If this node was marked as recursive, wrap with a recursive type.
323
+ if (typeNode) {
324
+ if (DistinctAttr id = typeTranslationStack.lookup (typeNode)) {
325
+ DITypeAttr typeAttr = cast<DITypeAttr>(attr);
326
+ attr = DIRecursiveTypeAttr::get (context, id, typeAttr);
327
+
328
+ // Remove the unbound recursive attr.
329
+ AttrTypeReplacer replacer;
330
+ unboundRecursiveSelfRefs.back ().erase (id);
331
+ }
332
+ }
333
+
334
+ // Only cache fully self-contained nodes.
335
+ if (unboundRecursiveSelfRefs.back ().empty ())
336
+ nodeToAttr.try_emplace (node, attr);
293
337
return attr;
294
338
}
295
339
return nullptr ;
@@ -346,3 +390,10 @@ StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) {
346
390
return StringAttr ();
347
391
return StringAttr::get (context, stringNode->getString ());
348
392
}
393
+
394
+ DistinctAttr DebugImporter::getOrCreateDistinctID (llvm::DINode *node) {
395
+ DistinctAttr &id = nodeToDistinctAttr[node];
396
+ if (!id)
397
+ id = DistinctAttr::create (UnitAttr::get (context));
398
+ return id;
399
+ }
0 commit comments