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

Abid Qadeer llvmlistbot at llvm.org
Wed Apr 8 14:50:15 PDT 2026


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

>From 0eee735c6f3f82647c83bd00286c74764233f31d Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Tue, 7 Apr 2026 16:40:23 +0100
Subject: [PATCH 1/2] [mlir][debug] Make DICompileUnitAttr recursive.

This PR add DIRecursiveTypeAttrInterface to DICompileUnitAttr. It should fix the circular dependency problem we have since imports field was added.
---
 mlir/include/mlir-c/Dialect/LLVM.h            | 15 +++++---
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 28 ++++++++++++---
 .../Dialect/LLVMIR/LLVMDialectBytecode.td     |  4 ++-
 mlir/lib/CAPI/Dialect/LLVM.cpp                | 22 ++++++++----
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 23 ++++++++++++
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      | 11 ++++--
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   | 35 +++++++++++++++++++
 mlir/lib/Target/LLVMIR/DebugTranslation.h     |  1 +
 mlir/test/CAPI/llvm.c                         |  6 +++-
 .../compile-unit-imported-entity-cycle.ll     | 30 ++++++++++++++++
 10 files changed, 154 insertions(+), 21 deletions(-)
 create mode 100644 mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll

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}

>From 660400c694a50b5e30a8409594501cc07eae9a9d Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Wed, 8 Apr 2026 22:29:03 +0100
Subject: [PATCH 2/2] Handle review comments.

Also adjusted some testcases after as many fields are now optional and printed output could be a little different.
---
 .../Transforms/debug-line-table-inc-file.fir  |  2 +-
 flang/test/Transforms/debug-line-table.fir    |  4 +--
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       |  8 ++---
 .../Dialect/LLVMIR/LLVMDialectBytecode.td     |  2 +-
 mlir/lib/CAPI/Dialect/LLVM.cpp                |  8 ++---
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 13 ++++----
 mlir/test/CAPI/llvm.c                         |  5 ++-
 .../compile-unit-imported-entity-cycle.ll     | 30 -----------------
 mlir/test/Target/LLVMIR/Import/debug-info.ll  | 31 +++++++++++++++++-
 .../Target/LLVMIR/Import/global-variables.ll  |  2 +-
 mlir/test/Target/LLVMIR/llvmir-debug.mlir     | 32 +++++++++++++++++++
 11 files changed, 81 insertions(+), 56 deletions(-)
 delete mode 100644 mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll

diff --git a/flang/test/Transforms/debug-line-table-inc-file.fir b/flang/test/Transforms/debug-line-table-inc-file.fir
index d29e2fd6683b6..9e623dde153b7 100644
--- a/flang/test/Transforms/debug-line-table-inc-file.fir
+++ b/flang/test/Transforms/debug-line-table-inc-file.fir
@@ -30,7 +30,7 @@ module {
 // CHECK: #[[MODULE_LOC]] = loc("{{.*}}simple.f90":0:0)
 // CHECK: #[[LOC_INC_FILE:.*]] = loc("{{.*}}inc.f90":1:1)
 // CHECK: #[[LOC_FILE:.*]] = loc("{{.*}}simple.f90":3:1)
-// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "{{.*}}flang{{.*}}", isOptimized = false, emissionKind = LineTablesOnly>
+// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "{{.*}}flang{{.*}}", emissionKind = LineTablesOnly>
 // CHECK: #[[DI_SP_INC:.*]] = #llvm.di_subprogram<{{.*}}id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "sinc", linkageName = "_QPsinc", file = #[[DI_INC_FILE]], {{.*}}>
 // CHECK: #[[DI_SP:.*]] = #llvm.di_subprogram<{{.*}}id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QQmain", linkageName = "_QQmain", file = #[[DI_FILE]], {{.*}}>
 // CHECK: #[[FUSED_LOC_INC_FILE]] = loc(fused<#[[DI_SP_INC]]>[#[[LOC_INC_FILE]]])
diff --git a/flang/test/Transforms/debug-line-table.fir b/flang/test/Transforms/debug-line-table.fir
index 81aebf026882a..7cec163c22c5e 100644
--- a/flang/test/Transforms/debug-line-table.fir
+++ b/flang/test/Transforms/debug-line-table.fir
@@ -24,9 +24,9 @@ module {
 // CHECK: #[[MODULE_LOC]] = loc("[[DIR_NAME]]/[[FILE_NAME]]":1:1)
 // CHECK: #[[SB_LOC]] = loc("./simple.f90":2:1)
 // CHECK: #[[DECL_LOC:.*]] = loc("./simple.f90":10:1)
-// FULL: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "{{.*}}flang{{.*}}", isOptimized = false, emissionKind = Full>
+// FULL: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "{{.*}}flang{{.*}}", emissionKind = Full>
 // OPT: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "{{.*}}flang{{.*}}", isOptimized = true, emissionKind = Full>
-// LINETABLE: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "{{.*}}flang{{.*}}", isOptimized = false, emissionKind = LineTablesOnly>
+// LINETABLE: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "{{.*}}flang{{.*}}", emissionKind = LineTablesOnly>
 // CHECK: #di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_basic_type, #di_basic_type>
 // CHECK: #[[SB_SUBPROGRAM:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "[[SB_NAME]]", linkageName = "[[SB_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
 // CHECK: #[[DECL_SUBPROGRAM:.*]] = #llvm.di_subprogram<scope = #di_file, name = "[[DECL_NAME]]", linkageName = "[[DECL_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = Optimized, type = #di_subroutine_type>
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index dfedee9420465..22face8b9d4b0 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -335,7 +335,7 @@ def LLVM_DIEncodingParameter : LLVM_DIParameter<
 >;
 
 def LLVM_DILanguageParameter : LLVM_DIParameter<
-  "language", /*default=*/"", "Language", /*errorCase=*/"0"
+  "language", /*default=*/"0", "Language", /*errorCase=*/"0"
 >;
 
 def LLVM_DITagParameter : LLVM_DIParameter<
@@ -426,10 +426,10 @@ def LLVM_DICompileUnitAttr : LLVM_Attr<"DICompileUnit", "di_compile_unit",
     // DICompileUnitAttr specific parameters.
     OptionalParameter<"DistinctAttr">:$id,
     LLVM_DILanguageParameter:$sourceLanguage,
-    "DIFileAttr":$file,
+    OptionalParameter<"DIFileAttr">:$file,
     OptionalParameter<"StringAttr">:$producer,
-    "bool":$isOptimized,
-    "DIEmissionKind":$emissionKind,
+    OptionalParameter<"bool">:$isOptimized,
+    OptionalParameter<"DIEmissionKind">:$emissionKind,
     OptionalParameter<"bool">:$isDebugInfoForProfiling,
     OptionalParameter<"DINameTableKind">:$nameTableKind,
     OptionalParameter<"StringAttr">:$splitDebugFilename,
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index 989db9cfcbf41..05b88b428102c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -133,7 +133,7 @@ def DICompileUnitAttr : DialectAttribute<(attr
   Bool:$isRecSelf,
   OptionalAttribute<"DistinctAttr">:$id,
   VarInt:$sourceLanguage,
-  Attr<"DIFileAttr">:$file,
+  OptionalAttribute<"DIFileAttr">:$file,
   OptionalAttribute<"StringAttr">:$producer,
   Bool:$isOptimized,
   EnumClassFlag<"DIEmissionKind", "getEmissionKind()">:$_rawEmissionKind,
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index 99f2702462002..f690af2cdb8a1 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -355,13 +355,9 @@ MlirAttribute mlirLLVMDICompileUnitAttrGet(
     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), recIdAttr, isRecSelf, idAttr, sourceLanguage,
+      unwrap(ctx), cast<DistinctAttr>(unwrap(recId)), isRecSelf,
+      cast<DistinctAttr>(unwrap(id)), 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 932880548335d..18fb2e7aadfe2 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -343,14 +343,13 @@ DIRecursiveTypeAttrInterface DICompileUnitAttr::withRecId(DistinctAttr recId) {
 }
 
 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=*/{});
+      recId.getContext(), recId, /*isRecSelf=*/true, /*id=*/{},
+      /*sourceLanguage=*/0u, /*file=*/{}, /*producer=*/{},
+      /*isOptimized=*/false, DIEmissionKind::None,
+      /*isDebugInfoForProfiling=*/false, DINameTableKind::Default,
+      /*splitDebugFilename=*/{}, /*importedEntities=*/{});
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index 291c30556dc15..fe48ec5568168 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -276,16 +276,15 @@ static void testDebugInfoAttributes(MlirContext ctx) {
   // CHECK: #llvm.di_file<"foo" in "bar">
   mlirAttributeDump(file);
 
-  MlirAttribute nullAttr = {0};
   MlirAttribute compile_unit = mlirLLVMDICompileUnitAttrGet(
-      ctx, nullAttr, false, id, LLVMDWARFSourceLanguageC99, file, foo, false,
+      ctx, recId0, 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{{.*}}>
+  // CHECK: #llvm.di_compile_unit<recId = {{.*}}, isRecSelf = true>
   mlirAttributeDump(mlirLLVMDICompileUnitAttrGetRecSelf(recId1));
 
   MlirAttribute di_module = mlirLLVMDIModuleAttrGet(
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
deleted file mode 100644
index bac508f0e01cf..0000000000000
--- a/mlir/test/Target/LLVMIR/Import/compile-unit-imported-entity-cycle.ll
+++ /dev/null
@@ -1,30 +0,0 @@
-; 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}
diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll
index d6e24d0c3dfbc..f87313367a54b 100644
--- a/mlir/test/Target/LLVMIR/Import/debug-info.ll
+++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll
@@ -218,7 +218,7 @@ define void @composite_type() !dbg !3 {
 ; // -----
 
 ; CHECK-DAG: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
-; CHECK-DAG: #[[CU:.+]] = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #[[FILE]], isOptimized = false, emissionKind = None, isDebugInfoForProfiling = true, nameTableKind = None, splitDebugFilename = "test.dwo">
+; CHECK-DAG: #[[CU:.+]] = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #[[FILE]], isDebugInfoForProfiling = true, nameTableKind = None, splitDebugFilename = "test.dwo">
 ; Verify an empty subroutine types list is supported.
 ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
 ; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #[[CU]], scope = #[[FILE]], name = "subprogram", linkageName = "subprogram", file = #[[FILE]], line = 42, scopeLine = 42, subprogramFlags = Definition, type = #[[SP_TYPE]]>
@@ -918,3 +918,32 @@ define void @test() !dbg !3 {
 ; CHECK: #[[EXP1:.+]] =  #llvm.di_global_variable_expression<var = #[[VAR1]], expr = <>>
 ; CHECK: #[[EXP2:.+]] =  #llvm.di_global_variable_expression<var = #[[VAR2]], expr = <>>
 ; CHECK: llvm.mlir.global external @data() {{{.*}}dbg_exprs = [#[[EXP1]], #[[EXP2]]]} : i64
+
+; // -----
+
+; CU references itself through an imported entity (recId / isRecSelf cycle).
+
+; CHECK-DAG: #[[CU_SELF:.+]] = #llvm.di_compile_unit<recId = distinct[[REC_ID:.+]]<>{{.*}}isRecSelf = true{{.*}}>
+; CHECK-DAG: #llvm.di_imported_entity<{{.*}}tag = DW_TAG_imported_declaration{{.*}}scope = #[[CU_SELF]]{{.*}}>
+; CHECK-DAG: #llvm.di_compile_unit<{{.*}}recId = distinct[[REC_ID]]<>{{.*}}id = distinct[{{[0-9]+}}]<>{{.*}}importedEntities{{.*}}>
+
+ 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}
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index 102162aaae9c2..6ecead10e6327 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -281,7 +281,7 @@ define void @foo() {
 
 ; CHECK-DAG: #[[TYPE:.*]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "int", sizeInBits = 32, encoding = DW_ATE_signed>
 ; CHECK-DAG: #[[FILE:.*]] = #llvm.di_file<"source.c" in "/path/to/file">
-; CHECK-DAG: #[[CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_C99, file = #[[FILE]], isOptimized = false, emissionKind = None>
+; CHECK-DAG: #[[CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_C99, file = #[[FILE]]>
 ; CHECK-DAG: #[[SPROG:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, scope = #[[CU]], name = "foo", file = #[[FILE]], line = 5, subprogramFlags = Definition>
 ; CHECK-DAG: #[[GVAR0:.*]] = #llvm.di_global_variable<scope = #[[SPROG]], name = "foo", linkageName = "foo", file = #[[FILE]], line = 7, type = #[[TYPE]], isLocalToUnit = true>
 ; CHECK-DAG: #[[GVAR1:.*]] = #llvm.di_global_variable<scope = #[[SPROG]], name = "bar", linkageName = "bar", file = #[[FILE]], line = 8, type = #[[TYPE]], isLocalToUnit = true>
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index 95895e3e56a05..9b1dad2910dba 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -770,3 +770,35 @@ llvm.func @fn_cu_imports() {
 // CHECK-DAG: ![[IE:[0-9]+]] = !DIImportedEntity(tag: DW_TAG_imported_module{{.*}}entity: ![[NS]]{{.*}})
 // CHECK-DAG: ![[IMP_LIST:[0-9]+]] = !{![[IE]]}
 // CHECK-DAG: !DICompileUnit({{.*}}imports: ![[IMP_LIST]])
+
+// -----
+
+#file = #llvm.di_file<"m.cpp" in "/">
+#ns = #llvm.di_namespace<name = "n", exportSymbols = false>
+#self = #llvm.di_compile_unit<
+  recId = distinct[0]<>, isRecSelf = true, sourceLanguage = DW_LANG_C
+>
+#ie = #llvm.di_imported_entity<
+  tag = DW_TAG_imported_module, scope = #self,
+  entity = #ns, file = #file
+>
+#cu = #llvm.di_compile_unit<
+  recId = distinct[0]<>, id = distinct[2]<>,
+  sourceLanguage = DW_LANG_C, file = #file,
+  producer = "p", isOptimized = false, emissionKind = Full,
+  importedEntities = #ie
+>
+#sp_ty = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
+#sp = #llvm.di_subprogram<
+  compileUnit = #cu, scope = #file, name = "fn_cu_import_cycle",
+  file = #file, line = 1, scopeLine = 1, subprogramFlags = Definition,
+  type = #sp_ty
+>
+
+// CHECK-LABEL: define void @fn_cu_import_cycle()
+llvm.func @fn_cu_import_cycle() {
+  llvm.return
+} loc(fused<#sp>["m.mlir":1:1])
+
+// CHECK-DAG: !DIImportedEntity(tag: DW_TAG_imported_module{{.*}})
+// CHECK-DAG: !DICompileUnit({{.*}}imports:



More information about the Mlir-commits mailing list