Skip to content

Commit d49b5ea

Browse files
committed
handle mutual recursion replacement
1 parent dbed5a6 commit d49b5ea

File tree

2 files changed

+124
-12
lines changed

2 files changed

+124
-12
lines changed

mlir/lib/Target/LLVMIR/DebugImporter.cpp

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,75 @@ getRecSelfConstructor(llvm::DINode *node) {
318318
.Default(CtorType());
319319
}
320320

321+
/// An attribute replacer that replaces nested recursive decls with recursive
322+
/// self-references instead.
323+
///
324+
/// - Recurses down the attribute tree while replacing attributes based on the
325+
/// provided replacement map.
326+
/// - Keeps track of the currently open recursive declarations, and upon
327+
/// encountering a duplicate declaration, replace with a self-ref instead.
328+
static Attribute replaceAndPruneRecursiveTypesImpl(
329+
Attribute node,
330+
const DenseMap<DIRecursiveTypeAttrInterface, DINodeAttr> &mapping,
331+
DenseSet<DistinctAttr> &openDecls) {
332+
DistinctAttr recId;
333+
if (auto recType = dyn_cast<DIRecursiveTypeAttrInterface>(node)) {
334+
recId = recType.getRecId();
335+
336+
// Configure context.
337+
if (recId) {
338+
if (recType.isRecSelf()) {
339+
// Replace selfRef based on the provided mapping.
340+
if (DINodeAttr replacement = mapping.lookup(recType))
341+
return replaceAndPruneRecursiveTypesImpl(replacement, mapping,
342+
openDecls);
343+
return node;
344+
}
345+
346+
auto [_, inserted] = openDecls.insert(recId);
347+
if (!inserted) {
348+
// This is a nested decl. Replace with recSelf.
349+
return recType.getRecSelf(recId);
350+
}
351+
}
352+
}
353+
354+
// Collect sub attrs.
355+
SmallVector<Attribute> attrs;
356+
SmallVector<Type> types;
357+
node.walkImmediateSubElements(
358+
[&attrs](Attribute attr) { attrs.push_back(attr); },
359+
[&types](Type type) { types.push_back(type); });
360+
361+
// Recurse into attributes.
362+
bool changed = false;
363+
for (auto it = attrs.begin(); it != attrs.end(); it++) {
364+
Attribute replaced =
365+
replaceAndPruneRecursiveTypesImpl(*it, mapping, openDecls);
366+
if (replaced != *it) {
367+
*it = replaced;
368+
changed = true;
369+
}
370+
}
371+
372+
Attribute result = node;
373+
if (changed)
374+
result = result.replaceImmediateSubElements(attrs, types);
375+
376+
// Reset context.
377+
if (recId)
378+
openDecls.erase(recId);
379+
380+
return result;
381+
}
382+
383+
static Attribute replaceAndPruneRecursiveTypes(
384+
DINodeAttr node,
385+
const DenseMap<DIRecursiveTypeAttrInterface, DINodeAttr> &mapping) {
386+
DenseSet<DistinctAttr> openDecls;
387+
return replaceAndPruneRecursiveTypesImpl(node, mapping, openDecls);
388+
}
389+
321390
DINodeAttr DebugImporter::RecursionPruner::pruneOrPushTranslationStack(
322391
llvm::DINode *node) {
323392
// Lookup the cache first.
@@ -448,18 +517,8 @@ DebugImporter::RecursionPruner::lookup(llvm::DINode *node) {
448517
if (entry.pendingReplacements.empty())
449518
return std::make_pair(entry.attr, DenseSet<DIRecursiveTypeAttrInterface>{});
450519

451-
AttrTypeReplacer replacer;
452-
replacer.addReplacement(
453-
[&entry](DIRecursiveTypeAttrInterface attr)
454-
-> std::optional<std::pair<Attribute, WalkResult>> {
455-
if (auto replacement = entry.pendingReplacements.lookup(attr)) {
456-
// A replacement may contain additional unbound self-refs.
457-
return std::make_pair(replacement, mlir::WalkResult::advance());
458-
}
459-
return std::make_pair(attr, mlir::WalkResult::advance());
460-
});
461-
462-
Attribute replacedAttr = replacer.replace(entry.attr);
520+
Attribute replacedAttr =
521+
replaceAndPruneRecursiveTypes(entry.attr, entry.pendingReplacements);
463522
DINodeAttr result = cast<DINodeAttr>(replacedAttr);
464523

465524
// Update cache entry to save replaced version and remove already-applied

mlir/test/Target/LLVMIR/Import/debug-info.ll

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,3 +698,56 @@ define void @class_field(ptr %arg1) !dbg !18 {
698698
!10 = !{!8}
699699

700700
!18 = distinct !DISubprogram(name: "SP", scope: !3, file: !2, spFlags: DISPFlagDefinition, unit: !1)
701+
702+
; // -----
703+
704+
; Ensures that replacing a nested mutually recursive decl does not result in
705+
; nested duplicate recursive decls.
706+
;
707+
; A ---> B <--> C
708+
; ^ ^
709+
; +-------------+
710+
711+
; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[A_TO_B:.+]], #[[A_TO_C:.+]]>
712+
; CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[A]],
713+
; CHECK-DAG: #[[A_TO_B]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_FROM_A:.+]]>
714+
; CHECK-DAG: #[[A_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_A:.+]]>
715+
716+
; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B_TO_C:.+]]>
717+
; CHECK-DAG: #[[B_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_B:.+]]>
718+
; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID:.+]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF:.+]], #[[TO_B_SELF:.+]], #[[TO_C_SELF:.+]]>
719+
720+
; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF]], #[[TO_B_INNER:.+]], #[[TO_C_SELF]]
721+
; CHECK-DAG: #[[TO_B_INNER]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_INNER:.+]]>
722+
; CHECK-DAG: #[[B_INNER]] = #llvm.di_composite_type<{{.*}}name = "B", {{.*}}elements = #[[TO_C_SELF]]>
723+
724+
; CHECK-DAG: #[[TO_A_SELF]] = #llvm.di_derived_type<{{.*}}name = "->A", {{.*}}baseType = #[[A_SELF:.+]]>
725+
; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]>
726+
; CHECK-DAG: #[[TO_C_SELF]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_SELF:.+]]>
727+
; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID]]>
728+
; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]>
729+
; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]]>
730+
731+
define void @class_field(ptr %arg1) !dbg !18 {
732+
ret void
733+
}
734+
735+
!llvm.dbg.cu = !{!1}
736+
!llvm.module.flags = !{!0}
737+
!0 = !{i32 2, !"Debug Info Version", i32 3}
738+
!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2)
739+
!2 = !DIFile(filename: "debug-info.ll", directory: "/")
740+
741+
!3 = !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !2, line: 42, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !9)
742+
!4 = !DICompositeType(tag: DW_TAG_class_type, name: "B", file: !2, line: 42, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !10)
743+
!5 = !DICompositeType(tag: DW_TAG_class_type, name: "C", file: !2, line: 42, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !11)
744+
745+
!6 = !DIDerivedType(tag: DW_TAG_member, name: "->A", file: !2, baseType: !3)
746+
!7 = !DIDerivedType(tag: DW_TAG_member, name: "->B", file: !2, baseType: !4)
747+
!8 = !DIDerivedType(tag: DW_TAG_member, name: "->C", file: !2, baseType: !5)
748+
749+
!9 = !{!7, !8} ; A -> B, C
750+
!10 = !{!8} ; B -> C
751+
!11 = !{!6, !7, !8} ; C -> A, B, C
752+
753+
!18 = distinct !DISubprogram(name: "SP", scope: !3, file: !2, spFlags: DISPFlagDefinition, unit: !1)

0 commit comments

Comments
 (0)