[Mlir-commits] [mlir] [mlir][debug] Make DICompileUnitAttr recursive. (PR #190808)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Apr 7 08:50:12 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Abid Qadeer (abidh)

<details>
<summary>Changes</summary>

This PR add `DIRecursiveTypeAttrInterface` to `DICompileUnitAttr`. It should fix the circular dependency problem we have since `importedEntities` field was added.

---
Full diff: https://github.com/llvm/llvm-project/pull/190808.diff


10 Files Affected:

- (modified) mlir/include/mlir-c/Dialect/LLVM.h (+10-5) 
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td (+23-5) 
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td (+3-1) 
- (modified) mlir/lib/CAPI/Dialect/LLVM.cpp (+16-6) 
- (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp (+23) 
- (modified) mlir/lib/Target/LLVMIR/DebugImporter.cpp (+8-3) 
- (modified) mlir/lib/Target/LLVMIR/DebugTranslation.cpp (+35) 
- (modified) mlir/lib/Target/LLVMIR/DebugTranslation.h (+1) 
- (modified) mlir/test/CAPI/llvm.c (+5-1) 
- (added) mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll (+30) 


``````````diff
diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h
index 90ef9305145a8..5170f01a2f621 100644
--- a/mlir/include/mlir-c/Dialect/LLVM.h
+++ b/mlir/include/mlir-c/Dialect/LLVM.h
@@ -362,13 +362,18 @@ enum MlirLLVMDINameTableKind {
 
 typedef enum MlirLLVMDINameTableKind MlirLLVMDINameTableKind;
 
+/// Creates a self-referencing LLVM DICompileUnitAttr attribute.
+MLIR_CAPI_EXPORTED MlirAttribute
+mlirLLVMDICompileUnitAttrGetRecSelf(MlirAttribute recId);
+
 /// Creates a LLVM DICompileUnit attribute.
 MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDICompileUnitAttrGet(
-    MlirContext ctx, MlirAttribute id, unsigned int sourceLanguage,
-    MlirAttribute file, MlirAttribute producer, bool isOptimized,
-    MlirLLVMDIEmissionKind emissionKind, bool isDebugInfoForProfiling,
-    MlirLLVMDINameTableKind nameTableKind, MlirAttribute splitDebugFilename,
-    intptr_t nImportedEntities, MlirAttribute const *importedEntities);
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id,
+    unsigned int sourceLanguage, MlirAttribute file, MlirAttribute producer,
+    bool isOptimized, MlirLLVMDIEmissionKind emissionKind,
+    bool isDebugInfoForProfiling, MlirLLVMDINameTableKind nameTableKind,
+    MlirAttribute splitDebugFilename, intptr_t nImportedEntities,
+    MlirAttribute const *importedEntities);
 
 MLIR_CAPI_EXPORTED MlirStringRef mlirLLVMDICompileUnitAttrGetName(void);
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index d53f522e646fb..dfedee9420465 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -417,9 +417,14 @@ def LLVM_DIBasicTypeAttr : LLVM_Attr<"DIBasicType", "di_basic_type",
 //===----------------------------------------------------------------------===//
 
 def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
-                                       /*traits=*/[], "DIScopeAttr"> {
+                                       [LLVM_DIRecursiveTypeAttrInterface],
+                                       "DIScopeAttr"> {
   let parameters = (ins
-    "DistinctAttr":$id,
+    // DIRecursiveTypeAttrInterface specific parameters.
+    OptionalParameter<"DistinctAttr">:$recId,
+    OptionalParameter<"bool">:$isRecSelf,
+    // DICompileUnitAttr specific parameters.
+    OptionalParameter<"DistinctAttr">:$id,
     LLVM_DILanguageParameter:$sourceLanguage,
     "DIFileAttr":$file,
     OptionalParameter<"StringAttr">:$producer,
@@ -440,12 +445,25 @@ def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
       CArg<"StringAttr", "{}">:$splitDebugFilename,
       CArg<"ArrayRef<DINodeAttr>", "{}">:$importedEntities
     ), [{
-      return $_get(id.getContext(), id, sourceLanguage, file, producer,
-                   isOptimized, emissionKind, isDebugInfoForProfiling,
-                   nameTableKind, splitDebugFilename, importedEntities);
+      return $_get(id.getContext(), /*recId=*/nullptr, /*isRecSelf=*/false, id,
+                   sourceLanguage, file, producer, isOptimized, emissionKind,
+                   isDebugInfoForProfiling, nameTableKind, splitDebugFilename,
+                   importedEntities);
     }]>
   ];
   let assemblyFormat = "`<` struct(params) `>`";
+  let extraClassDeclaration = [{
+    /// Requirements of DIRecursiveTypeAttrInterface.
+    /// @{
+
+    /// Get a copy of this attr but with the recursive ID set to `recId`.
+    DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId);
+
+    /// Build a rec-self instance using the provided `recId`.
+    static DIRecursiveTypeAttrInterface getRecSelf(DistinctAttr recId);
+
+    /// @}
+  }];
 
   // Generate mnemonic alias for the attribute.
   let genMnemonicAlias = 1;
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index d4e1450d2f516..989db9cfcbf41 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -129,7 +129,9 @@ def DISubroutineTypeAttr : DialectAttribute<(attr
 //===----------------------------------------------------------------------===//
 
 def DICompileUnitAttr : DialectAttribute<(attr
-  Attr<"DistinctAttr">:$id,
+  OptionalAttribute<"DistinctAttr">:$recId,
+  Bool:$isRecSelf,
+  OptionalAttribute<"DistinctAttr">:$id,
   VarInt:$sourceLanguage,
   Attr<"DIFileAttr">:$file,
   OptionalAttribute<"StringAttr">:$producer,
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index dbd4b1213491b..99f2702462002 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -342,16 +342,26 @@ MlirAttribute mlirLLVMDIFileAttrGet(MlirContext ctx, MlirAttribute name,
 
 MlirStringRef mlirLLVMDIFileAttrGetName(void) { return wrap(DIFileAttr::name); }
 
+MlirAttribute mlirLLVMDICompileUnitAttrGetRecSelf(MlirAttribute recId) {
+  return wrap(DICompileUnitAttr::getRecSelf(cast<DistinctAttr>(unwrap(recId))));
+}
+
 MlirAttribute mlirLLVMDICompileUnitAttrGet(
-    MlirContext ctx, MlirAttribute id, unsigned int sourceLanguage,
-    MlirAttribute file, MlirAttribute producer, bool isOptimized,
-    MlirLLVMDIEmissionKind emissionKind, bool isDebugInfoForProfiling,
-    MlirLLVMDINameTableKind nameTableKind, MlirAttribute splitDebugFilename,
-    intptr_t nImportedEntities, MlirAttribute const *importedEntities) {
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id,
+    unsigned int sourceLanguage, MlirAttribute file, MlirAttribute producer,
+    bool isOptimized, MlirLLVMDIEmissionKind emissionKind,
+    bool isDebugInfoForProfiling, MlirLLVMDINameTableKind nameTableKind,
+    MlirAttribute splitDebugFilename, intptr_t nImportedEntities,
+    MlirAttribute const *importedEntities) {
   SmallVector<Attribute> importsStorage;
   importsStorage.reserve(nImportedEntities);
+  DistinctAttr recIdAttr = mlirAttributeIsNull(recId)
+                               ? DistinctAttr{}
+                               : cast<DistinctAttr>(unwrap(recId));
+  DistinctAttr idAttr =
+      mlirAttributeIsNull(id) ? DistinctAttr{} : cast<DistinctAttr>(unwrap(id));
   return wrap(DICompileUnitAttr::get(
-      unwrap(ctx), cast<DistinctAttr>(unwrap(id)), sourceLanguage,
+      unwrap(ctx), recIdAttr, isRecSelf, idAttr, sourceLanguage,
       cast<DIFileAttr>(unwrap(file)), cast<StringAttr>(unwrap(producer)),
       isOptimized, DIEmissionKind(emissionKind), isDebugInfoForProfiling,
       DINameTableKind(nameTableKind),
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 9f87e502a0bf1..932880548335d 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -330,6 +330,29 @@ DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
                                   {}, {}, {});
 }
 
+//===----------------------------------------------------------------------===//
+// DICompileUnitAttr
+//===----------------------------------------------------------------------===//
+
+DIRecursiveTypeAttrInterface DICompileUnitAttr::withRecId(DistinctAttr recId) {
+  return DICompileUnitAttr::get(
+      getContext(), recId, getIsRecSelf(), getId(), getSourceLanguage(),
+      getFile(), getProducer(), getIsOptimized(), getEmissionKind(),
+      getIsDebugInfoForProfiling(), getNameTableKind(), getSplitDebugFilename(),
+      getImportedEntities());
+}
+
+DIRecursiveTypeAttrInterface DICompileUnitAttr::getRecSelf(DistinctAttr recId) {
+  MLIRContext *ctx = recId.getContext();
+  auto emptyStr = StringAttr::get(ctx, "");
+  return DICompileUnitAttr::get(
+      ctx, recId, /*isRecSelf=*/true, /*id=*/DistinctAttr{},
+      llvm::dwarf::DW_LANG_C89, DIFileAttr::get(ctx, "<rec>", ""), emptyStr,
+      /*isOptimized=*/false, DIEmissionKind::Full,
+      /*isDebugInfoForProfiling=*/false, DINameTableKind::Default, emptyStr,
+      /*importedEntities=*/{});
+}
+
 //===----------------------------------------------------------------------===//
 // DISubprogramAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index 1a6703fd4056a..ab37c21fdacf8 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -65,7 +65,8 @@ DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) {
         imports.push_back(nodeAttr);
   }
   return DICompileUnitAttr::get(
-      context, getOrCreateDistinctID(node),
+      context, /*recId=*/DistinctAttr{}, /*isRecSelf=*/false,
+      getOrCreateDistinctID(node),
       node->getSourceLanguage().getUnversionedName(),
       translate(node->getFile()), getStringAttrOrNull(node->getRawProducer()),
       node->isOptimized(), emissionKind.value(),
@@ -434,8 +435,9 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
   return nullptr;
 }
 
-/// Get the `getRecSelf` constructor for the translated type of `node` if its
-/// translated DITypeAttr supports recursion. Otherwise, returns nullptr.
+/// Get the `getRecSelf` constructor for the translated node if it participates
+/// in CyclicReplacerCache cycle breaking (recursive composite types,
+/// subprograms, or compile units).
 static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>
 getRecSelfConstructor(llvm::DINode *node) {
   using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>;
@@ -446,6 +448,9 @@ getRecSelfConstructor(llvm::DINode *node) {
       .Case([&](llvm::DISubprogram *) {
         return CtorType(DISubprogramAttr::getRecSelf);
       })
+      .Case([&](llvm::DICompileUnit *) {
+        return CtorType(DICompileUnitAttr::getRecSelf);
+      })
       .Default(CtorType());
 }
 
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index dce5806d48034..db9bc874314bb 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -119,7 +119,32 @@ llvm::DIBasicType *DebugTranslation::translateImpl(DIBasicTypeAttr attr) {
       /*AlignInBits=*/0, attr.getEncoding(), llvm::DINode::FlagZero);
 }
 
+llvm::TempDICompileUnit
+DebugTranslation::translateTemporaryImpl(DICompileUnitAttr attr) {
+  return llvm::DICompileUnit::getTemporary(
+      llvmCtx,
+      static_cast<llvm::DISourceLanguageName>(attr.getSourceLanguage()),
+      /*File=*/nullptr, "", attr.getIsOptimized(),
+      /*Flags=*/"", /*RuntimeVersion=*/0,
+      /*splitDebugFileName=*/"",
+      static_cast<llvm::DICompileUnit::DebugEmissionKind>(
+          attr.getEmissionKind()),
+      /*EnumTypes=*/nullptr, /*RetainedTypes=*/nullptr,
+      /*GlobalVariables=*/nullptr, /*ImportedEntities=*/nullptr,
+      /*Macros=*/nullptr,
+      /*DWOId=*/0, /*SplitDebugInlining=*/true,
+      attr.getIsDebugInfoForProfiling(),
+      static_cast<llvm::DICompileUnit::DebugNameTableKind>(
+          attr.getNameTableKind()),
+      /*RangesBaseAddress=*/false, /*SysRoot=*/"", /*SDK=*/"");
+}
+
 llvm::DICompileUnit *DebugTranslation::translateImpl(DICompileUnitAttr attr) {
+  if (attr.getId())
+    if (auto iter = distinctAttrToNode.find(attr.getId());
+        iter != distinctAttrToNode.end())
+      return cast<llvm::DICompileUnit>(iter->second);
+
   llvm::DIBuilder builder(llvmModule);
   llvm::DICompileUnit *cu = builder.createCompileUnit(
       attr.getSourceLanguage(), translate(attr.getFile()),
@@ -140,6 +165,9 @@ llvm::DICompileUnit *DebugTranslation::translateImpl(DICompileUnitAttr attr) {
   if (!importNodes.empty())
     cu->replaceImportedEntities(llvm::MDTuple::get(llvmCtx, importNodes));
 
+  if (attr.getId())
+    distinctAttrToNode.try_emplace(attr.getId(), cu);
+
   return cu;
 }
 
@@ -310,6 +338,13 @@ DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) {
             auto *concrete = translateImpl(attr);
             temporary->replaceAllUsesWith(concrete);
             return concrete;
+          })
+          .Case([&](DICompileUnitAttr attr) {
+            auto temporary = translateTemporaryImpl(attr);
+            setRecursivePlaceholder(temporary.get());
+            auto *concrete = translateImpl(attr);
+            temporary->replaceAllUsesWith(concrete);
+            return concrete;
           });
 
   assert(recursiveNodeMap.back().first == recursiveId &&
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h
index b690d4820d7b0..c12ddb42fe238 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.h
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h
@@ -104,6 +104,7 @@ class DebugTranslation {
   /// corresponding type.
   llvm::TempDICompositeType translateTemporaryImpl(DICompositeTypeAttr attr);
   llvm::TempDISubprogram translateTemporaryImpl(DISubprogramAttr attr);
+  llvm::TempDICompileUnit translateTemporaryImpl(DICompileUnitAttr attr);
 
   /// Constructs a string metadata node from the string attribute. Returns
   /// nullptr if `stringAttr` is null or contains and empty string.
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index 205bdf19f733a..291c30556dc15 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -276,14 +276,18 @@ static void testDebugInfoAttributes(MlirContext ctx) {
   // CHECK: #llvm.di_file<"foo" in "bar">
   mlirAttributeDump(file);
 
+  MlirAttribute nullAttr = {0};
   MlirAttribute compile_unit = mlirLLVMDICompileUnitAttrGet(
-      ctx, id, LLVMDWARFSourceLanguageC99, file, foo, false,
+      ctx, nullAttr, false, id, LLVMDWARFSourceLanguageC99, file, foo, false,
       MlirLLVMDIEmissionKindFull, false, MlirLLVMDINameTableKindDefault, bar, 0,
       NULL);
 
   // CHECK: #llvm.di_compile_unit<{{.*}}>
   mlirAttributeDump(compile_unit);
 
+  // CHECK: #llvm.di_compile_unit<{{.*}}isRecSelf = true{{.*}}>
+  mlirAttributeDump(mlirLLVMDICompileUnitAttrGetRecSelf(recId1));
+
   MlirAttribute di_module = mlirLLVMDIModuleAttrGet(
       ctx, file, compile_unit, foo,
       mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("")), bar, foo, 1,
diff --git a/mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll b/mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll
new file mode 100644
index 0000000000000..bac508f0e01cf
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll
@@ -0,0 +1,30 @@
+; RUN: mlir-translate -import-llvm -mlir-print-debuginfo %s | FileCheck %s
+
+; CHECK-DAG: #[[CU_SELF:.+]] = #llvm.di_compile_unit<{{.*}}recId = distinct[{{[0-9]+}}]<>{{.*}}isRecSelf = true{{.*}}>
+; CHECK-DAG: #llvm.di_imported_entity<{{.*}}tag = DW_TAG_imported_declaration{{.*}}scope = #[[CU_SELF]]{{.*}}>
+; CHECK-DAG: #llvm.di_compile_unit<{{.*}}recId = distinct[{{[0-9]+}}]<>{{.*}}id = distinct[{{[0-9]+}}]<>{{.*}}importedEntities{{.*}}>
+
+source_filename = "compile-unit-imported-entity-cycle.ll"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f64:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32, !dbg !0
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!17}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !12, line: 7, type: !13, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !5, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "cu.cpp", directory: "/build")
+!4 = !{}
+!5 = !{!6}
+!6 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !2, entity: !7, file: !11, line: 10)
+!7 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "S", scope: !9, file: !8, line: 5, size: 32, flags: DIFlagTypePassByValue, elements: !4)
+!8 = !DIFile(filename: "hdr.hpp", directory: "/build")
+!9 = !DINamespace(name: "ns", scope: !10)
+!10 = !DINamespace(name: "outer", scope: null)
+!11 = !DIFile(filename: "import.hpp", directory: "/build")
+!12 = !DIFile(filename: "cu.hpp", directory: "/build")
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!17 = !{i32 2, !"Debug Info Version", i32 3}

``````````

</details>


https://github.com/llvm/llvm-project/pull/190808


More information about the Mlir-commits mailing list