[flang-commits] [flang] [mlir] Reapply "[MLIR][LLVM] Make DISubprogramAttr cyclic" (#106571) with fixes (PR #106947)

Tobias Gysi via flang-commits flang-commits at lists.llvm.org
Mon Sep 2 01:22:35 PDT 2024


https://github.com/gysit created https://github.com/llvm/llvm-project/pull/106947

This reverts commit fa93be4, restoring
commit d884b77, with fixes that ensure the CAPI declarations are exported properly.

This commit implements LLVM_DIRecursiveTypeAttrInterface for the DISubprogramAttr to ensure cyclic subprograms can be imported properly. In the process multiple shortcuts around the recently introduced DIImportedEntityAttr can be removed.

>From 1a212380ac0bda85baf6e30af15a15f71f05d371 Mon Sep 17 00:00:00 2001
From: Tobias Gysi <tobias.gysi at nextsilicon.com>
Date: Thu, 29 Aug 2024 15:29:10 +0000
Subject: [PATCH] Reapply "[MLIR][LLVM] Make DISubprogramAttr cyclic" (#106571)
 with fixes

This reverts commit fa93be4, restoring
commit d884b77, with fixes that ensure the CAPI declarations are
exported properly.

This commit implements LLVM_DIRecursiveTypeAttrInterface for the
DISubprogramAttr to ensure cyclic subprograms can be imported properly.
In the process multiple shortcuts around the recently introduced
DIImportedEntityAttr can be removed.
---
 .../Transforms/DebugTypeGenerator.cpp         | 10 +-
 mlir/include/mlir-c/Dialect/LLVM.h            | 28 ++++--
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 68 +++++++++----
 .../mlir/Dialect/LLVMIR/LLVMInterfaces.td     |  2 +-
 mlir/lib/CAPI/Dialect/LLVM.cpp                | 39 +++++---
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 29 ++++--
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |  6 +-
 .../Transforms/DIScopeForLLVMFuncOp.cpp       |  8 +-
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      | 18 ++--
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   | 98 ++++++++++---------
 mlir/lib/Target/LLVMIR/DebugTranslation.h     | 18 ++--
 mlir/test/CAPI/llvm.c                         | 23 +++--
 mlir/test/Target/LLVMIR/Import/debug-info.ll  | 53 +++++-----
 mlir/test/Target/LLVMIR/llvmir-debug.mlir     | 41 ++++----
 14 files changed, 265 insertions(+), 176 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index 54f2a12d800085..029d3776bcc0b8 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -146,8 +146,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertBoxedSequenceType(
     elements.push_back(subrangeTy);
   }
   return mlir::LLVM::DICompositeTypeAttr::get(
-      context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{},
-      /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
+      context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr,
+      /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
       mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements,
       dataLocation, /*rank=*/nullptr, allocated, associated);
 }
@@ -188,7 +188,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
   }
 
   return mlir::LLVM::DICompositeTypeAttr::get(
-      context, llvm::dwarf::DW_TAG_structure_type, /*recursive_id=*/{},
+      context, llvm::dwarf::DW_TAG_structure_type,
       mlir::StringAttr::get(context, result.second.name), fileAttr, line, scope,
       /*baseType=*/nullptr, mlir::LLVM::DIFlags::Zero, offset * 8,
       /*alignInBits=*/0, elements, /*dataLocation=*/nullptr, /*rank=*/nullptr,
@@ -236,8 +236,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType(
   // have been set to some valid default values.
 
   return mlir::LLVM::DICompositeTypeAttr::get(
-      context, llvm::dwarf::DW_TAG_array_type, /*recursive_id=*/{},
-      /*name=*/nullptr, /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
+      context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr,
+      /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy,
       mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, elements,
       /*dataLocation=*/nullptr, /*rank=*/nullptr, /*allocated=*/nullptr,
       /*associated=*/nullptr);
diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h
index 5eb96a86e472d6..d6062bed5c0c0f 100644
--- a/mlir/include/mlir-c/Dialect/LLVM.h
+++ b/mlir/include/mlir-c/Dialect/LLVM.h
@@ -234,10 +234,14 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIBasicTypeAttrGet(
     MlirContext ctx, unsigned int tag, MlirAttribute name, uint64_t sizeInBits,
     MlirLLVMTypeEncoding encoding);
 
+/// Creates a self-referencing LLVM DICompositeType attribute.
+MLIR_CAPI_EXPORTED MlirAttribute
+mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId);
+
 /// Creates a LLVM DICompositeType attribute.
 MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDICompositeTypeAttrGet(
-    MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name,
-    MlirAttribute file, uint32_t line, MlirAttribute scope,
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag,
+    MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope,
     MlirAttribute baseType, int64_t flags, uint64_t sizeInBits,
     uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements,
     MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated,
@@ -311,13 +315,17 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDILocalVariableAttrGet(
     MlirAttribute diFile, unsigned int line, unsigned int arg,
     unsigned int alignInBits, MlirAttribute diType, int64_t flags);
 
+/// Creates a self-referencing LLVM DISubprogramAttr attribute.
+MLIR_CAPI_EXPORTED MlirAttribute
+mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId);
+
 /// Creates a LLVM DISubprogramAttr attribute.
 MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDISubprogramAttrGet(
-    MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit,
-    MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName,
-    MlirAttribute file, unsigned int line, unsigned int scopeLine,
-    uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes,
-    MlirAttribute const *retainedNodes);
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id,
+    MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name,
+    MlirAttribute linkageName, MlirAttribute file, unsigned int line,
+    unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type,
+    intptr_t nRetainedNodes, MlirAttribute const *retainedNodes);
 
 /// Gets the scope from this DISubprogramAttr.
 MLIR_CAPI_EXPORTED MlirAttribute
@@ -356,9 +364,9 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIModuleAttrGet(
 
 /// Creates a LLVM DIImportedEntityAttr attribute.
 MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIImportedEntityAttrGet(
-    MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file,
-    unsigned int line, MlirAttribute name, intptr_t nElements,
-    MlirAttribute const *elements);
+    MlirContext ctx, unsigned int tag, MlirAttribute scope,
+    MlirAttribute entity, MlirAttribute file, unsigned int line,
+    MlirAttribute name, intptr_t nElements, MlirAttribute const *elements);
 
 /// Gets the scope of this DIModuleAttr.
 MLIR_CAPI_EXPORTED MlirAttribute
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index e57be7f760d380..49e54df3436ff3 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -271,7 +271,7 @@ def LLVM_DILanguageParameter : LLVM_DIParameter<
 >;
 
 def LLVM_DITagParameter : LLVM_DIParameter<
-  "tag", /*default=*/"", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid"
+  "tag", /*default=*/"0", "Tag", /*errorCase=*/"llvm::dwarf::DW_TAG_invalid"
 >;
 
 def LLVM_DIOperationEncodingParameter : LLVM_DIParameter<
@@ -375,14 +375,17 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
                                          [LLVM_DIRecursiveTypeAttrInterface],
                                          "DITypeAttr"> {
   let parameters = (ins
-    LLVM_DITagParameter:$tag,
+    // DIRecursiveTypeAttrInterface specific parameters.
     OptionalParameter<"DistinctAttr">:$recId,
+    OptionalParameter<"bool">:$isRecSelf,
+    // DICompositeType specific parameters.
+    LLVM_DITagParameter:$tag,
     OptionalParameter<"StringAttr">:$name,
     OptionalParameter<"DIFileAttr">:$file,
     OptionalParameter<"uint32_t">:$line,
     OptionalParameter<"DIScopeAttr">:$scope,
     OptionalParameter<"DITypeAttr">:$baseType,
-    OptionalParameter<"DIFlags", "DIFlags::Zero">:$flags,
+    OptionalParameter<"DIFlags">:$flags,
     OptionalParameter<"uint64_t">:$sizeInBits,
     OptionalParameter<"uint64_t">:$alignInBits,
     OptionalArrayRefParameter<"DINodeAttr">:$elements,
@@ -391,14 +394,26 @@ def LLVM_DICompositeTypeAttr : LLVM_Attr<"DICompositeType", "di_composite_type",
     OptionalParameter<"DIExpressionAttr">:$allocated,
     OptionalParameter<"DIExpressionAttr">:$associated
   );
+  let builders = [
+    AttrBuilder<(ins
+      "unsigned":$tag, "StringAttr":$name, "DIFileAttr":$file,
+      "uint32_t":$line, "DIScopeAttr":$scope, "DITypeAttr":$baseType,
+      "DIFlags":$flags, "uint64_t":$sizeInBits, "uint64_t":$alignInBits,
+      "ArrayRef<DINodeAttr>":$elements, "DIExpressionAttr":$dataLocation,
+      "DIExpressionAttr":$rank, "DIExpressionAttr":$allocated,
+      "DIExpressionAttr":$associated
+    ), [{
+      return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/nullptr,
+                   tag, name, file, line, scope, baseType, flags, sizeInBits,
+                   alignInBits, elements, dataLocation, rank, allocated,
+                   associated);
+    }]>
+  ];
   let assemblyFormat = "`<` struct(params) `>`";
   let extraClassDeclaration = [{
     /// Requirements of DIRecursiveTypeAttrInterface.
     /// @{
 
-    /// Get whether this attr describes a recursive self reference.
-    bool isRecSelf() { return getTag() == 0; }
-
     /// Get a copy of this type attr but with the recursive ID set to `recId`.
     DIRecursiveTypeAttrInterface withRecId(DistinctAttr recId);
 
@@ -554,14 +569,19 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable",
 //===----------------------------------------------------------------------===//
 
 def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
-                                      /*traits=*/[], "DIScopeAttr"> {
+                                      [LLVM_DIRecursiveTypeAttrInterface],
+                                      "DIScopeAttr"> {
   let parameters = (ins
+    // DIRecursiveTypeAttrInterface specific parameters.
+    OptionalParameter<"DistinctAttr">:$recId,
+    OptionalParameter<"bool">:$isRecSelf,
+    // DISubprogramAttr specific parameters.
     OptionalParameter<"DistinctAttr">:$id,
     OptionalParameter<"DICompileUnitAttr">:$compileUnit,
-    "DIScopeAttr":$scope,
+    OptionalParameter<"DIScopeAttr">:$scope,
     OptionalParameter<"StringAttr">:$name,
     OptionalParameter<"StringAttr">:$linkageName,
-    "DIFileAttr":$file,
+    OptionalParameter<"DIFileAttr">:$file,
     OptionalParameter<"unsigned">:$line,
     OptionalParameter<"unsigned">:$scopeLine,
     OptionalParameter<"DISubprogramFlags">:$subprogramFlags,
@@ -569,21 +589,31 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
     OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes
   );
   let builders = [
-    AttrBuilderWithInferredContext<(ins
+    AttrBuilder<(ins
       "DistinctAttr":$id, "DICompileUnitAttr":$compileUnit,
-      "DIScopeAttr":$scope, "StringRef":$name, "StringRef":$linkageName,
+      "DIScopeAttr":$scope, "StringAttr":$name, "StringAttr":$linkageName,
       "DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine,
       "DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type,
       "ArrayRef<DINodeAttr>":$retainedNodes
     ), [{
-      MLIRContext *ctx = file.getContext();
-      return $_get(ctx, id, compileUnit, scope, StringAttr::get(ctx, name),
-                   StringAttr::get(ctx, linkageName), file, line,
-                   scopeLine, subprogramFlags, type, retainedNodes);
+      return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/false, id, compileUnit,
+                   scope, name, linkageName, file, line, scopeLine,
+                   subprogramFlags, type, retainedNodes);
     }]>
   ];
-
   let assemblyFormat = "`<` struct(params) `>`";
+  let extraClassDeclaration = [{
+    /// Requirements of DIRecursiveTypeAttrInterface.
+    /// @{
+
+    /// Get a copy of this type 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);
+
+    /// @}
+  }];
 }
 
 //===----------------------------------------------------------------------===//
@@ -627,13 +657,9 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace",
 
 def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entity",
                                            /*traits=*/[], "DINodeAttr"> {
-  /// TODO: DIImportedEntity has a 'scope' field which represents the scope where
-  /// this entity is imported. Currently, we are not adding a 'scope' field in
-  /// DIImportedEntityAttr to avoid cyclic dependency. As DIImportedEntityAttr
-  /// entries will be contained inside a scope entity (e.g. DISubprogramAttr),
-  /// the scope can easily be inferred.
   let parameters = (ins
     LLVM_DITagParameter:$tag,
+    "DIScopeAttr":$scope,
     "DINodeAttr":$entity,
     OptionalParameter<"DIFileAttr">:$file,
     OptionalParameter<"unsigned">:$line,
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
index 7085f81e203a1e..e2180410a8f04e 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td
@@ -406,7 +406,7 @@ def LLVM_DIRecursiveTypeAttrInterface
   let methods = [
     InterfaceMethod<[{
       Get whether this attr describes a recursive self reference.
-    }], "bool", "isRecSelf", (ins)>,
+    }], "bool", "getIsRecSelf", (ins)>,
     InterfaceMethod<[{
       Get the recursive ID used for matching "rec-decl" with "rec-self".
       If this attr instance is not recursive, return a null attribute.
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index 13341f0c4de881..03b536d7aad98f 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -159,9 +159,14 @@ MlirAttribute mlirLLVMDIBasicTypeAttrGet(MlirContext ctx, unsigned int tag,
       unwrap(ctx), tag, cast<StringAttr>(unwrap(name)), sizeInBits, encoding));
 }
 
+MlirAttribute mlirLLVMDICompositeTypeAttrGetRecSelf(MlirAttribute recId) {
+  return wrap(
+      DICompositeTypeAttr::getRecSelf(cast<DistinctAttr>(unwrap(recId))));
+}
+
 MlirAttribute mlirLLVMDICompositeTypeAttrGet(
-    MlirContext ctx, unsigned int tag, MlirAttribute recId, MlirAttribute name,
-    MlirAttribute file, uint32_t line, MlirAttribute scope,
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, unsigned int tag,
+    MlirAttribute name, MlirAttribute file, uint32_t line, MlirAttribute scope,
     MlirAttribute baseType, int64_t flags, uint64_t sizeInBits,
     uint64_t alignInBits, intptr_t nElements, MlirAttribute const *elements,
     MlirAttribute dataLocation, MlirAttribute rank, MlirAttribute allocated,
@@ -170,7 +175,7 @@ MlirAttribute mlirLLVMDICompositeTypeAttrGet(
   elementsStorage.reserve(nElements);
 
   return wrap(DICompositeTypeAttr::get(
-      unwrap(ctx), tag, cast<DistinctAttr>(unwrap(recId)),
+      unwrap(ctx), cast<DistinctAttr>(unwrap(recId)), isRecSelf, tag,
       cast<StringAttr>(unwrap(name)), cast<DIFileAttr>(unwrap(file)), line,
       cast<DIScopeAttr>(unwrap(scope)), cast<DITypeAttr>(unwrap(baseType)),
       DIFlags(flags), sizeInBits, alignInBits,
@@ -289,16 +294,21 @@ MlirAttribute mlirLLVMDISubroutineTypeAttrGet(MlirContext ctx,
                           [](Attribute a) { return cast<DITypeAttr>(a); })));
 }
 
+MlirAttribute mlirLLVMDISubprogramAttrGetRecSelf(MlirAttribute recId) {
+  return wrap(DISubprogramAttr::getRecSelf(cast<DistinctAttr>(unwrap(recId))));
+}
+
 MlirAttribute mlirLLVMDISubprogramAttrGet(
-    MlirContext ctx, MlirAttribute id, MlirAttribute compileUnit,
-    MlirAttribute scope, MlirAttribute name, MlirAttribute linkageName,
-    MlirAttribute file, unsigned int line, unsigned int scopeLine,
-    uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes,
-    MlirAttribute const *retainedNodes) {
+    MlirContext ctx, MlirAttribute recId, bool isRecSelf, MlirAttribute id,
+    MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name,
+    MlirAttribute linkageName, MlirAttribute file, unsigned int line,
+    unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type,
+    intptr_t nRetainedNodes, MlirAttribute const *retainedNodes) {
   SmallVector<Attribute> nodesStorage;
   nodesStorage.reserve(nRetainedNodes);
   return wrap(DISubprogramAttr::get(
-      unwrap(ctx), cast<DistinctAttr>(unwrap(id)),
+      unwrap(ctx), cast<DistinctAttr>(unwrap(recId)), isRecSelf,
+      cast<DistinctAttr>(unwrap(id)),
       cast<DICompileUnitAttr>(unwrap(compileUnit)),
       cast<DIScopeAttr>(unwrap(scope)), cast<StringAttr>(unwrap(name)),
       cast<StringAttr>(unwrap(linkageName)), cast<DIFileAttr>(unwrap(file)),
@@ -353,14 +363,15 @@ MlirAttribute mlirLLVMDIModuleAttrGetScope(MlirAttribute diModule) {
 }
 
 MlirAttribute mlirLLVMDIImportedEntityAttrGet(
-    MlirContext ctx, unsigned int tag, MlirAttribute entity, MlirAttribute file,
-    unsigned int line, MlirAttribute name, intptr_t nElements,
-    MlirAttribute const *elements) {
+    MlirContext ctx, unsigned int tag, MlirAttribute scope,
+    MlirAttribute entity, MlirAttribute file, unsigned int line,
+    MlirAttribute name, intptr_t nElements, MlirAttribute const *elements) {
   SmallVector<Attribute> elementsStorage;
   elementsStorage.reserve(nElements);
   return wrap(DIImportedEntityAttr::get(
-      unwrap(ctx), tag, cast<DINodeAttr>(unwrap(entity)),
-      cast<DIFileAttr>(unwrap(file)), line, cast<StringAttr>(unwrap(name)),
+      unwrap(ctx), tag, cast<DIScopeAttr>(unwrap(scope)),
+      cast<DINodeAttr>(unwrap(entity)), cast<DIFileAttr>(unwrap(file)), line,
+      cast<StringAttr>(unwrap(name)),
       llvm::map_to_vector(unwrapList(nElements, elements, elementsStorage),
                           [](Attribute a) { return cast<DINodeAttr>(a); })));
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 98a9659735e7e6..491dcc7f01e73d 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -203,16 +203,33 @@ void printExpressionArg(AsmPrinter &printer, uint64_t opcode,
 DIRecursiveTypeAttrInterface
 DICompositeTypeAttr::withRecId(DistinctAttr recId) {
   return DICompositeTypeAttr::get(
-      getContext(), getTag(), recId, getName(), getFile(), getLine(),
-      getScope(), getBaseType(), getFlags(), getSizeInBits(), getAlignInBits(),
-      getElements(), getDataLocation(), getRank(), getAllocated(),
-      getAssociated());
+      getContext(), recId, getIsRecSelf(), getTag(), getName(), getFile(),
+      getLine(), getScope(), getBaseType(), getFlags(), getSizeInBits(),
+      getAlignInBits(), getElements(), getDataLocation(), getRank(),
+      getAllocated(), getAssociated());
 }
 
 DIRecursiveTypeAttrInterface
 DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
-  return DICompositeTypeAttr::get(recId.getContext(), 0, recId, {}, {}, 0, {},
-                                  {}, DIFlags(), 0, 0, {}, {}, {}, {}, {});
+  return DICompositeTypeAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
+                                  0, {}, {}, 0, {}, {}, DIFlags(), 0, 0, {}, {},
+                                  {}, {}, {});
+}
+
+//===----------------------------------------------------------------------===//
+// DISubprogramAttr
+//===----------------------------------------------------------------------===//
+
+DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
+  return DISubprogramAttr::get(
+      getContext(), recId, getIsRecSelf(), getId(), getCompileUnit(),
+      getScope(), getName(), getLinkageName(), getFile(), getLine(),
+      getScopeLine(), getSubprogramFlags(), getType(), getRetainedNodes());
+}
+
+DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
+  return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
+                               {}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 3870aab52f199d..6e4a964f1fc93c 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3155,9 +3155,9 @@ struct LLVMOpAsmDialectInterface : public OpAsmDialectInterface {
         .Case<AccessGroupAttr, AliasScopeAttr, AliasScopeDomainAttr,
               DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
               DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
-              DIGlobalVariableExpressionAttr, DILabelAttr, DILexicalBlockAttr,
-              DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
-              DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
+              DIGlobalVariableExpressionAttr, DIImportedEntityAttr, DILabelAttr,
+              DILexicalBlockAttr, DILexicalBlockFileAttr, DILocalVariableAttr,
+              DIModuleAttr, DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
               DISubprogramAttr, DISubroutineTypeAttr, LoopAnnotationAttr,
               LoopVectorizeAttr, LoopInterleaveAttr, LoopUnrollAttr,
               LoopUnrollAndJamAttr, LoopLICMAttr, LoopDistributeAttr,
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index c75f44bf3976a9..2cfaffa7c8efce 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -65,7 +65,6 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
   auto subroutineTypeAttr =
       LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
 
-  StringAttr funcNameAttr = llvmFunc.getNameAttr();
   // Only definitions need a distinct identifier and a compilation unit.
   DistinctAttr id;
   auto subprogramFlags = LLVM::DISubprogramFlags::Optimized;
@@ -75,11 +74,10 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
   } else {
     compileUnitAttr = {};
   }
+  auto funcName = StringAttr::get(context, llvmFunc.getName());
   auto subprogramAttr = LLVM::DISubprogramAttr::get(
-      context, id, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr,
-      fileAttr,
-      /*line=*/line,
-      /*scopeline=*/col, subprogramFlags, subroutineTypeAttr,
+      context, id, compileUnitAttr, fileAttr, funcName, funcName, fileAttr,
+      /*line=*/line, /*scopeline=*/col, subprogramFlags, subroutineTypeAttr,
       /*retainedNodes=*/{});
   llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
 }
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index ce3643f513d34a..8c6f32f6bb0cd0 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -89,10 +89,9 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
   if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType)
     return nullptr;
   return DICompositeTypeAttr::get(
-      context, node->getTag(), /*recId=*/{},
-      getStringAttrOrNull(node->getRawName()), translate(node->getFile()),
-      node->getLine(), translate(node->getScope()), baseType,
-      flags.value_or(DIFlags::Zero), node->getSizeInBits(),
+      context, node->getTag(), getStringAttrOrNull(node->getRawName()),
+      translate(node->getFile()), node->getLine(), translate(node->getScope()),
+      baseType, flags.value_or(DIFlags::Zero), node->getSizeInBits(),
       node->getAlignInBits(), elements,
       translateExpression(node->getDataLocationExp()),
       translateExpression(node->getRankExp()),
@@ -217,8 +216,8 @@ DebugImporter::translateImpl(llvm::DIImportedEntity *node) {
   }
 
   return DIImportedEntityAttr::get(
-      context, node->getTag(), translate(node->getEntity()),
-      translate(node->getFile()), node->getLine(),
+      context, node->getTag(), translate(node->getScope()),
+      translate(node->getEntity()), translate(node->getFile()), node->getLine(),
       getStringAttrOrNull(node->getRawName()), elements);
 }
 
@@ -227,6 +226,7 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
   mlir::DistinctAttr id;
   if (node->isDistinct())
     id = getOrCreateDistinctID(node);
+
   // Return nullptr if the scope or type is invalid.
   DIScopeAttr scope = translate(node->getScope());
   if (node->getScope() && !scope)
@@ -238,9 +238,12 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
   if (node->getType() && !type)
     return nullptr;
 
+  // Convert the retained nodes but drop all of them if one of them is invalid.
   SmallVector<DINodeAttr> retainedNodes;
   for (llvm::DINode *retainedNode : node->getRetainedNodes())
     retainedNodes.push_back(translate(retainedNode));
+  if (llvm::is_contained(retainedNodes, nullptr))
+    retainedNodes.clear();
 
   return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
                                getStringAttrOrNull(node->getRawName()),
@@ -374,6 +377,9 @@ getRecSelfConstructor(llvm::DINode *node) {
       .Case([&](llvm::DICompositeType *) {
         return CtorType(DICompositeTypeAttr::getRecSelf);
       })
+      .Case([&](llvm::DISubprogram *) {
+        return CtorType(DISubprogramAttr::getRecSelf);
+      })
       .Default(CtorType());
 }
 
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 042e015f107fea..8ca3beca6b66f7 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -96,6 +96,17 @@ llvm::MDString *DebugTranslation::getMDStringOrNull(StringAttr stringAttr) {
   return llvm::MDString::get(llvmCtx, stringAttr);
 }
 
+llvm::MDTuple *
+DebugTranslation::getMDTupleOrNull(ArrayRef<DINodeAttr> elements) {
+  if (elements.empty())
+    return nullptr;
+  SmallVector<llvm::Metadata *> llvmElements = llvm::to_vector(
+      llvm::map_range(elements, [&](DINodeAttr attr) -> llvm::Metadata * {
+        return translate(attr);
+      }));
+  return llvm::MDNode::get(llvmCtx, llvmElements);
+}
+
 llvm::DIBasicType *DebugTranslation::translateImpl(DIBasicTypeAttr attr) {
   return llvm::DIBasicType::get(
       llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),
@@ -138,6 +149,17 @@ DebugTranslation::translateTemporaryImpl(DICompositeTypeAttr attr) {
       /*VTableHolder=*/nullptr);
 }
 
+llvm::TempDISubprogram
+DebugTranslation::translateTemporaryImpl(DISubprogramAttr attr) {
+  return llvm::DISubprogram::getTemporary(
+      llvmCtx, /*Scope=*/nullptr, /*Name=*/{}, /*LinkageName=*/{},
+      /*File=*/nullptr, attr.getLine(), /*Type=*/nullptr,
+      /*ScopeLine=*/0, /*ContainingType=*/nullptr, /*VirtualIndex=*/0,
+      /*ThisAdjustment=*/0, llvm::DINode::FlagZero,
+      static_cast<llvm::DISubprogram::DISPFlags>(attr.getSubprogramFlags()),
+      /*Unit=*/nullptr);
+}
+
 llvm::DICompositeType *
 DebugTranslation::translateImpl(DICompositeTypeAttr attr) {
   // TODO: Use distinct attributes to model this, once they have landed.
@@ -151,10 +173,6 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) {
     isDistinct = true;
   }
 
-  SmallVector<llvm::Metadata *> elements;
-  for (DINodeAttr member : attr.getElements())
-    elements.push_back(translate(member));
-
   return getDistinctOrUnique<llvm::DICompositeType>(
       isDistinct, llvmCtx, attr.getTag(), getMDStringOrNull(attr.getName()),
       translate(attr.getFile()), attr.getLine(), translate(attr.getScope()),
@@ -162,7 +180,7 @@ DebugTranslation::translateImpl(DICompositeTypeAttr attr) {
       attr.getAlignInBits(),
       /*OffsetInBits=*/0,
       /*Flags=*/static_cast<llvm::DINode::DIFlags>(attr.getFlags()),
-      llvm::MDNode::get(llvmCtx, elements),
+      getMDTupleOrNull(attr.getElements()),
       /*RuntimeLang=*/0, /*VTableHolder=*/nullptr,
       /*TemplateParams=*/nullptr, /*Identifier=*/nullptr,
       /*Discriminator=*/nullptr,
@@ -242,22 +260,21 @@ DebugTranslation::translateImpl(DIGlobalVariableAttr attr) {
       attr.getIsDefined(), nullptr, nullptr, attr.getAlignInBits(), nullptr);
 }
 
-llvm::DIType *
+llvm::DINode *
 DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) {
   DistinctAttr recursiveId = attr.getRecId();
-  if (auto *iter = recursiveTypeMap.find(recursiveId);
-      iter != recursiveTypeMap.end()) {
+  if (auto *iter = recursiveNodeMap.find(recursiveId);
+      iter != recursiveNodeMap.end()) {
     return iter->second;
-  } else {
-    assert(!attr.isRecSelf() && "unbound DI recursive self type");
   }
+  assert(!attr.getIsRecSelf() && "unbound DI recursive self reference");
 
-  auto setRecursivePlaceholder = [&](llvm::DIType *placeholder) {
-    recursiveTypeMap.try_emplace(recursiveId, placeholder);
+  auto setRecursivePlaceholder = [&](llvm::DINode *placeholder) {
+    recursiveNodeMap.try_emplace(recursiveId, placeholder);
   };
 
-  llvm::DIType *result =
-      TypeSwitch<DIRecursiveTypeAttrInterface, llvm::DIType *>(attr)
+  llvm::DINode *result =
+      TypeSwitch<DIRecursiveTypeAttrInterface, llvm::DINode *>(attr)
           .Case<DICompositeTypeAttr>([&](auto attr) {
             auto temporary = translateTemporaryImpl(attr);
             setRecursivePlaceholder(temporary.get());
@@ -266,11 +283,20 @@ DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) {
             auto *concrete = translateImpl(attr);
             temporary->replaceAllUsesWith(concrete);
             return concrete;
+          })
+          .Case<DISubprogramAttr>([&](auto attr) {
+            auto temporary = translateTemporaryImpl(attr);
+            setRecursivePlaceholder(temporary.get());
+            // Must call `translateImpl` directly instead of `translate` to
+            // avoid handling the recursive interface again.
+            auto *concrete = translateImpl(attr);
+            temporary->replaceAllUsesWith(concrete);
+            return concrete;
           });
 
-  assert(recursiveTypeMap.back().first == recursiveId &&
+  assert(recursiveNodeMap.back().first == recursiveId &&
          "internal inconsistency: unexpected recursive translation stack");
-  recursiveTypeMap.pop_back();
+  recursiveNodeMap.pop_back();
 
   return result;
 }
@@ -297,6 +323,7 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) {
 
   bool isDefinition = static_cast<bool>(attr.getSubprogramFlags() &
                                         LLVM::DISubprogramFlags::Definition);
+
   llvm::DISubprogram *node = getDistinctOrUnique<llvm::DISubprogram>(
       isDefinition, llvmCtx, scope, getMDStringOrNull(attr.getName()),
       getMDStringOrNull(attr.getLinkageName()), file, attr.getLine(), type,
@@ -304,21 +331,8 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) {
       /*ContainingType=*/nullptr, /*VirtualIndex=*/0,
       /*ThisAdjustment=*/0, llvm::DINode::FlagZero,
       static_cast<llvm::DISubprogram::DISPFlags>(attr.getSubprogramFlags()),
-      compileUnit);
-
-  // DIImportedEntity requires scope information which DIImportedEntityAttr does
-  // not have. This is why we translate DIImportedEntityAttr after we have
-  // created DISubprogram as we can use it as the scope.
-  SmallVector<llvm::Metadata *> retainedNodes;
-  for (DINodeAttr nodeAttr : attr.getRetainedNodes()) {
-    if (auto importedAttr = dyn_cast<DIImportedEntityAttr>(nodeAttr)) {
-      llvm::DINode *dn = translate(importedAttr, node);
-      retainedNodes.push_back(dn);
-    }
-  }
-  if (!retainedNodes.empty())
-    node->replaceRetainedNodes(llvm::MDTuple::get(llvmCtx, retainedNodes));
-
+      compileUnit, /*TemplateParams=*/nullptr, /*Declaration=*/nullptr,
+      getMDTupleOrNull(attr.getRetainedNodes()));
   if (attr.getId())
     distinctAttrToNode.try_emplace(attr.getId(), node);
   return node;
@@ -339,16 +353,12 @@ llvm::DINamespace *DebugTranslation::translateImpl(DINamespaceAttr attr) {
                                 attr.getExportSymbols());
 }
 
-llvm::DIImportedEntity *DebugTranslation::translate(DIImportedEntityAttr attr,
-                                                    llvm::DIScope *scope) {
-  SmallVector<llvm::Metadata *> elements;
-  for (DINodeAttr member : attr.getElements())
-    elements.push_back(translate(member));
-
+llvm::DIImportedEntity *
+DebugTranslation::translateImpl(DIImportedEntityAttr attr) {
   return llvm::DIImportedEntity::get(
-      llvmCtx, attr.getTag(), scope, translate(attr.getEntity()),
-      translate(attr.getFile()), attr.getLine(),
-      getMDStringOrNull(attr.getName()), llvm::MDNode::get(llvmCtx, elements));
+      llvmCtx, attr.getTag(), translate(attr.getScope()),
+      translate(attr.getEntity()), translate(attr.getFile()), attr.getLine(),
+      getMDStringOrNull(attr.getName()), getMDTupleOrNull(attr.getElements()));
 }
 
 llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) {
@@ -413,10 +423,10 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) {
     node = TypeSwitch<DINodeAttr, llvm::DINode *>(attr)
                .Case<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
                      DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
-                     DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr,
-                     DILocalVariableAttr, DIModuleAttr, DINamespaceAttr,
-                     DINullTypeAttr, DIStringTypeAttr, DISubprogramAttr,
-                     DISubrangeAttr, DISubroutineTypeAttr>(
+                     DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
+                     DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
+                     DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
+                     DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
                    [&](auto attr) { return translateImpl(attr); });
 
   if (node && !node->isTemporary())
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h
index 37b985acf8541e..422aa34e28f3c9 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.h
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h
@@ -75,6 +75,7 @@ class DebugTranslation {
   llvm::DIDerivedType *translateImpl(DIDerivedTypeAttr attr);
   llvm::DIStringType *translateImpl(DIStringTypeAttr attr);
   llvm::DIFile *translateImpl(DIFileAttr attr);
+  llvm::DIImportedEntity *translateImpl(DIImportedEntityAttr attr);
   llvm::DILabel *translateImpl(DILabelAttr attr);
   llvm::DILexicalBlock *translateImpl(DILexicalBlockAttr attr);
   llvm::DILexicalBlockFile *translateImpl(DILexicalBlockFileAttr attr);
@@ -90,27 +91,26 @@ class DebugTranslation {
   llvm::DISubroutineType *translateImpl(DISubroutineTypeAttr attr);
   llvm::DIType *translateImpl(DITypeAttr attr);
 
-  /// Currently, DIImportedEntityAttr does not have a scope field to avoid a
-  /// cyclic dependency.  The scope information is obtained from the entity
-  /// which holds the list of DIImportedEntityAttr. This requires that scope
-  /// information be passed to translate function.
-  llvm::DIImportedEntity *translate(DIImportedEntityAttr attr, llvm::DIScope *);
-
   /// Attributes that support self recursion need to implement an additional
   /// method to hook into `translateRecursive`.
   /// - `<temp llvm type> translateTemporaryImpl(<mlir type>)`:
   ///   Create a temporary translation of the DI attr without recursively
   ///   translating any nested DI attrs.
-  llvm::DIType *translateRecursive(DIRecursiveTypeAttrInterface attr);
+  llvm::DINode *translateRecursive(DIRecursiveTypeAttrInterface attr);
 
   /// Translate the given attribute to a temporary llvm debug metadata of the
   /// corresponding type.
   llvm::TempDICompositeType translateTemporaryImpl(DICompositeTypeAttr attr);
+  llvm::TempDISubprogram translateTemporaryImpl(DISubprogramAttr attr);
 
   /// Constructs a string metadata node from the string attribute. Returns
   /// nullptr if `stringAttr` is null or contains and empty string.
   llvm::MDString *getMDStringOrNull(StringAttr stringAttr);
 
+  /// Constructs a tuple metadata node from the `elements`. Returns nullptr if
+  /// `elements` is empty.
+  llvm::MDTuple *getMDTupleOrNull(ArrayRef<DINodeAttr> elements);
+
   /// Constructs a DIExpression metadata node from the DIExpressionAttr. Returns
   /// nullptr if `DIExpressionAttr` is null.
   llvm::DIExpression *getExpressionAttrOrNull(DIExpressionAttr attr);
@@ -125,8 +125,8 @@ class DebugTranslation {
   /// metadata.
   DenseMap<Attribute, llvm::DINode *> attrToNode;
 
-  /// A mapping between recursive ID and the translated DIType.
-  llvm::MapVector<DistinctAttr, llvm::DIType *> recursiveTypeMap;
+  /// A mapping between recursive ID and the translated DINode.
+  llvm::MapVector<DistinctAttr, llvm::DINode *> recursiveNodeMap;
 
   /// A mapping between a distinct ID and the translated LLVM metadata node.
   /// This helps identify attrs that should translate into the same LLVM debug
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index da28a96f89691d..36277122801de4 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -248,12 +248,16 @@ static void testDebugInfoAttributes(MlirContext ctx) {
       mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("foo"));
   MlirAttribute bar =
       mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("bar"));
-  MlirAttribute id = mlirDisctinctAttrCreate(foo);
+
+  MlirAttribute none = mlirUnitAttrGet(ctx);
+  MlirAttribute id = mlirDisctinctAttrCreate(none);
+  MlirAttribute recId0 = mlirDisctinctAttrCreate(none);
+  MlirAttribute recId1 = mlirDisctinctAttrCreate(none);
 
   // CHECK: #llvm.di_null_type
   mlirAttributeDump(mlirLLVMDINullTypeAttrGet(ctx));
 
-  // CHECK: #llvm.di_basic_type<tag = DW_TAG_null, name = "foo", sizeInBits =
+  // CHECK: #llvm.di_basic_type<name = "foo", sizeInBits =
   // CHECK-SAME: 64, encoding = DW_ATE_signed>
   MlirAttribute di_type =
       mlirLLVMDIBasicTypeAttrGet(ctx, 0, foo, 64, MlirLLVMTypeEncodingSigned);
@@ -312,15 +316,17 @@ static void testDebugInfoAttributes(MlirContext ctx) {
   // CHECK: #llvm.di_subroutine_type<{{.*}}>
   mlirAttributeDump(subroutine_type);
 
+  MlirAttribute di_subprogram_self_rec =
+      mlirLLVMDISubprogramAttrGetRecSelf(recId0);
   MlirAttribute di_imported_entity = mlirLLVMDIImportedEntityAttrGet(
-      ctx, 0, di_module, file, 1, foo, 1, &local_var);
+      ctx, 0, di_subprogram_self_rec, di_module, file, 1, foo, 1, &local_var);
 
   mlirAttributeDump(di_imported_entity);
   // CHECK: #llvm.di_imported_entity<{{.*}}>
 
   MlirAttribute di_subprogram = mlirLLVMDISubprogramAttrGet(
-      ctx, id, compile_unit, compile_unit, foo, bar, file, 1, 2, 0,
-      subroutine_type, 1, &di_imported_entity);
+      ctx, recId0, false, id, compile_unit, compile_unit, foo, bar, file, 1, 2,
+      0, subroutine_type, 1, &di_imported_entity);
   // CHECK: #llvm.di_subprogram<{{.*}}>
   mlirAttributeDump(di_subprogram);
 
@@ -350,10 +356,13 @@ static void testDebugInfoAttributes(MlirContext ctx) {
   // CHECK: #llvm.di_string_type<{{.*}}>
   mlirAttributeDump(string_type);
 
+  // CHECK: #llvm.di_composite_type<recId = {{.*}}, isRecSelf = true>
+  mlirAttributeDump(mlirLLVMDICompositeTypeAttrGetRecSelf(recId1));
+
   // CHECK: #llvm.di_composite_type<{{.*}}>
   mlirAttributeDump(mlirLLVMDICompositeTypeAttrGet(
-      ctx, 0, id, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1, &di_type,
-      expression, expression, expression, expression));
+      ctx, recId1, false, 0, foo, file, 1, compile_unit, di_type, 0, 64, 8, 1,
+      &di_type, expression, expression, expression, expression));
 }
 
 int main(void) {
diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll
index bb03da37c0d097..02e35ae7f0ee9d 100644
--- a/mlir/test/Target/LLVMIR/Import/debug-info.ll
+++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll
@@ -307,17 +307,13 @@ define void @class_method() {
   ret void, !dbg !9
 }
 
-; Verify the cyclic composite type is identified, even though conversion begins from the subprogram type.
-; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type<tag = DW_TAG_null, recId = [[REC_ID:.+]]>
-; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP_SELF]], sizeInBits = 64>
+; Verify the cyclic subprogram is handled correctly.
+; CHECK-DAG: #[[SP_SELF:.+]] = #llvm.di_subprogram<recId = [[REC_ID:.+]], isRecSelf = true>
+; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type<tag = DW_TAG_class_type, name = "class_name", file = #{{.*}}, line = 42, flags = "TypePassByReference|NonTrivial", elements = #[[SP_SELF]]>
+; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP]], sizeInBits = 64>
 ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type<types = #{{.*}}, #[[COMP_PTR]]>
-; CHECK-DAG: #[[SP_INNER:.+]] = #llvm.di_subprogram<id = [[SP_ID:.+]], compileUnit = #{{.*}}, scope = #[[COMP_SELF]], name = "class_method", file = #{{.*}}, subprogramFlags = Definition, type = #[[SP_TYPE]]>
-; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type<tag = DW_TAG_class_type, recId = [[REC_ID]], name = "class_name", file = #{{.*}}, line = 42, flags = "TypePassByReference|NonTrivial", elements = #[[SP_INNER]]>
-
-; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP]], sizeInBits = 64>
-; CHECK-DAG: #[[SP_TYPE_OUTER:.+]] = #llvm.di_subroutine_type<types = #{{.*}}, #[[COMP_PTR_OUTER]]>
-; CHECK-DAG: #[[SP_OUTER:.+]] = #llvm.di_subprogram<id = [[SP_ID]], compileUnit = #{{.*}}, scope = #[[COMP]], name = "class_method", file = #{{.*}}, subprogramFlags = Definition, type = #[[SP_TYPE_OUTER]]>
-; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP_OUTER]]>
+; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<recId = [[REC_ID]], id = [[SP_ID:.+]], compileUnit = #{{.*}}, scope = #[[COMP]], name = "class_method", file = #{{.*}}, subprogramFlags = Definition, type = #[[SP_TYPE]]>
+; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -335,10 +331,10 @@ define void @class_method() {
 ; // -----
 
 ; Verify the cyclic composite type is handled correctly.
-; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type<tag = DW_TAG_null, recId = [[REC_ID:.+]]>
+; CHECK-DAG: #[[COMP_SELF:.+]] = #llvm.di_composite_type<recId = [[REC_ID:.+]], isRecSelf = true>
 ; CHECK-DAG: #[[COMP_PTR_INNER:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP_SELF]]>
 ; CHECK-DAG: #[[FIELD:.+]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "call_field", baseType = #[[COMP_PTR_INNER]]>
-; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type<tag = DW_TAG_class_type, recId = [[REC_ID]], name = "class_field", file = #{{.*}}, line = 42, flags = "TypePassByReference|NonTrivial", elements = #[[FIELD]]>
+; CHECK-DAG: #[[COMP:.+]] = #llvm.di_composite_type<recId = [[REC_ID]], tag = DW_TAG_class_type, name = "class_field", file = #{{.*}}, line = 42, flags = "TypePassByReference|NonTrivial", elements = #[[FIELD]]>
 ; CHECK-DAG: #[[COMP_PTR_OUTER:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP]]>
 ; CHECK-DAG: #[[VAR0:.+]] = #llvm.di_local_variable<scope = #{{.*}}, name = "class_field", file = #{{.*}}, type = #[[COMP_PTR_OUTER]]>
 
@@ -610,9 +606,10 @@ define void @distinct_cu_func1() !dbg !5 {
 ; CHECK-LABEL: @declaration
 declare !dbg !1 void @declaration()
 
-; CHECK: #di_subprogram = #llvm.di_subprogram<
+; CHECK: #[[SP:.+]] = #llvm.di_subprogram<
 ; CHECK-NOT: id = distinct
 ; CHECK-NOT: subprogramFlags =
+; CHECK: loc(fused<#[[SP]]>
 
 !llvm.module.flags = !{!0}
 !0 = !{i32 2, !"Debug Info Version", i32 3}
@@ -633,14 +630,14 @@ declare !dbg !1 void @declaration()
 
 ; CHECK-DAG: #[[B1_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B1", baseType = #[[B_SELF:.+]]>
 ; CHECK-DAG: #[[B2_INNER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_SELF]]>
-; CHECK-DAG: #[[B_INNER:.+]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B1_INNER]], #[[B2_INNER]]
+; CHECK-DAG: #[[B_INNER:.+]] = #llvm.di_composite_type<recId = [[B_RECID:.+]], tag = DW_TAG_class_type, name = "B", {{.*}}elements = #[[B1_INNER]], #[[B2_INNER]]
 
 ; CHECK-DAG: #[[B1_OUTER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B1", baseType = #[[B_INNER]]>
 ; CHECK-DAG: #[[B2_OUTER:.+]] = #llvm.di_derived_type<{{.*}}name = "B:B2", baseType = #[[B_INNER]]>
-; CHECK-DAG: #[[A_OUTER:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[B1_OUTER]], #[[B2_OUTER]]
+; CHECK-DAG: #[[A_OUTER:.+]] = #llvm.di_composite_type<recId = [[A_RECID:.+]], tag = DW_TAG_class_type, name = "A", {{.*}}elements = #[[B1_OUTER]], #[[B2_OUTER]]
 
-; CHECK-DAG: #[[A_SELF:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID]]
-; CHECK-DAG: #[[B_SELF:.+]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]
+; CHECK-DAG: #[[A_SELF:.+]] = #llvm.di_composite_type<recId = [[A_RECID]]
+; CHECK-DAG: #[[B_SELF:.+]] = #llvm.di_composite_type<recId = [[B_RECID]]
 
 ; CHECK: #llvm.di_subprogram<{{.*}}scope = #[[A_OUTER]]
 
@@ -678,11 +675,11 @@ define void @class_field(ptr %arg1) !dbg !18 {
 ; CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[A]],
 
 ; CHECK-DAG: #[[TO_B_OUTER]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_OUTER:.+]]>
-; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[TO_C_INNER:.+]]>
+; CHECK-DAG: #[[B_OUTER]] = #llvm.di_composite_type<recId = [[B_RECID:.+]], tag = DW_TAG_class_type, name = "B", {{.*}}elements = #[[TO_C_INNER:.+]]>
 ; CHECK-DAG: #[[TO_C_INNER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_INNER:.+]]>
 ; CHECK-DAG: #[[C_INNER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_SELF:.+]]>
 ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]>
-; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]>
+; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<recId = [[B_RECID]], isRecSelf = true>
 
 ; CHECK-DAG: #[[TO_C_OUTER]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_OUTER:.+]]>
 ; CHECK-DAG: #[[C_OUTER]] = #llvm.di_composite_type<{{.*}}name = "C", {{.*}}elements = #[[TO_B_OUTER]]>
@@ -718,23 +715,23 @@ define void @class_field(ptr %arg1) !dbg !18 {
 ; ^             ^
 ; +-------------+
 
-; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID:.+]], {{.*}}name = "A", {{.*}}elements = #[[A_TO_B:.+]], #[[A_TO_C:.+]]>
+; CHECK-DAG: #[[A:.+]] = #llvm.di_composite_type<recId = [[A_RECID:.+]], tag = DW_TAG_class_type, name = "A", {{.*}}elements = #[[A_TO_B:.+]], #[[A_TO_C:.+]]>
 ; CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[A]],
 ; CHECK-DAG: #[[A_TO_B]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_FROM_A:.+]]>
 ; CHECK-DAG: #[[A_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_A:.+]]>
 
-; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID:.+]], {{.*}}name = "B", {{.*}}elements = #[[B_TO_C:.+]]>
+; CHECK-DAG: #[[B_FROM_A]] = #llvm.di_composite_type<recId = [[B_RECID:.+]], tag = DW_TAG_class_type, name = "B", {{.*}}elements = #[[B_TO_C:.+]]>
 ; CHECK-DAG: #[[B_TO_C]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_FROM_B:.+]]>
-; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID:.+]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF:.+]], #[[TO_B_SELF:.+]], #[[TO_C_SELF:.+]]>
+; CHECK-DAG: #[[C_FROM_B]] = #llvm.di_composite_type<recId = [[C_RECID:.+]], tag = DW_TAG_class_type, name = "C", {{.*}}elements = #[[TO_A_SELF:.+]], #[[TO_B_SELF:.+]], #[[TO_C_SELF:.+]]>
 
-; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]], {{.*}}name = "C", {{.*}}elements = #[[TO_A_SELF]], #[[A_TO_B:.+]], #[[TO_C_SELF]]
+; CHECK-DAG: #[[C_FROM_A]] = #llvm.di_composite_type<recId = [[C_RECID]], tag = DW_TAG_class_type, name = "C", {{.*}}elements = #[[TO_A_SELF]], #[[A_TO_B:.+]], #[[TO_C_SELF]]
 
 ; CHECK-DAG: #[[TO_A_SELF]] = #llvm.di_derived_type<{{.*}}name = "->A", {{.*}}baseType = #[[A_SELF:.+]]>
 ; CHECK-DAG: #[[TO_B_SELF]] = #llvm.di_derived_type<{{.*}}name = "->B", {{.*}}baseType = #[[B_SELF:.+]]>
 ; CHECK-DAG: #[[TO_C_SELF]] = #llvm.di_derived_type<{{.*}}name = "->C", {{.*}}baseType = #[[C_SELF:.+]]>
-; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[A_RECID]]>
-; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[B_RECID]]>
-; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type<{{.*}}recId = [[C_RECID]]>
+; CHECK-DAG: #[[A_SELF]] = #llvm.di_composite_type<recId = [[A_RECID]], isRecSelf = true>
+; CHECK-DAG: #[[B_SELF]] = #llvm.di_composite_type<recId = [[B_RECID]], isRecSelf = true>
+; CHECK-DAG: #[[C_SELF]] = #llvm.di_composite_type<recId = [[C_RECID]], isRecSelf = true>
 
 define void @class_field(ptr %arg1) !dbg !18 {
   ret void
@@ -816,4 +813,6 @@ define void @imp_fn() !dbg !12 {
 !17 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !12, entity: !8, file: !3, line: 1, elements: !15)
 
 ; CHECK-DAG: #[[M:.+]] = #llvm.di_module<{{.*}}name = "mod1"{{.*}}>
-; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #llvm.di_imported_entity<tag = DW_TAG_imported_module, entity = #[[M]]{{.*}}>>
+; CHECK-DAG:  #[[SP_REC:.+]] = #llvm.di_subprogram<recId = distinct{{.*}}<>, isRecSelf = true>
+; CHECK-DAG: #[[IE:.+]] = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #[[SP_REC]], entity = #[[M]]{{.*}}>
+; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #[[IE]]>
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index 30b2ba5e9bad1f..01194df5047742 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -372,23 +372,28 @@ llvm.func @fn_with_gl() {
 llvm.func @imp_fn() {
   llvm.return
 } loc(#loc2)
-#file = #llvm.di_file<"test.f90" in "">
-#SP_TY = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
-#CU = #llvm.di_compile_unit<id = distinct[0]<>,
-  sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false,
+
+#di_file = #llvm.di_file<"test.f90" in "">
+#di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
+#di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>,
+  sourceLanguage = DW_LANG_Fortran95, file = #di_file, isOptimized = false,
   emissionKind = Full>
-#MOD = #llvm.di_module<file = #file, scope = #CU, name = "mod1">
-#MOD1 = #llvm.di_module<file = #file, scope = #CU, name = "mod2">
-#SP = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #CU, scope = #file,
-  name = "imp_fn", file = #file, subprogramFlags = Definition, type = #SP_TY,
-  retainedNodes = #llvm.di_imported_entity<tag = DW_TAG_imported_module,
-  entity = #MOD1, file = #file, line = 1>, #llvm.di_imported_entity<tag
-  = DW_TAG_imported_module, entity = #MOD, file = #file, line = 1>>
+#di_module_1 = #llvm.di_module<file = #di_file, scope = #di_compile_unit, name = "mod1">
+#di_module_2 = #llvm.di_module<file = #di_file, scope = #di_compile_unit, name = "mod2">
+#di_subprogram_self_rec = #llvm.di_subprogram<recId = distinct[1]<>>
+#di_imported_entity_1 = #llvm.di_imported_entity<tag = DW_TAG_imported_module,
+  scope = #di_subprogram_self_rec, entity = #di_module_1, file = #di_file, line = 1>
+#di_imported_entity_2 = #llvm.di_imported_entity<tag = DW_TAG_imported_module,
+  scope = #di_subprogram_self_rec, entity = #di_module_2, file = #di_file, line = 1>
+#di_subprogram = #llvm.di_subprogram<id = distinct[2]<>, recId = distinct[1]<>,
+  compileUnit = #di_compile_unit, scope = #di_file, name = "imp_fn",
+  file = #di_file, subprogramFlags = Definition, type = #di_subroutine_type,
+  retainedNodes = #di_imported_entity_1, #di_imported_entity_2>
 #loc1 = loc("test.f90":12:14)
-#loc2 = loc(fused<#SP>[#loc1])
+#loc2 = loc(fused<#di_subprogram>[#loc1])
 
 // CHECK-DAG: ![[SP:[0-9]+]] = {{.*}}!DISubprogram(name: "imp_fn"{{.*}}retainedNodes: ![[NODES:[0-9]+]])
-// CHECK-DAG: ![[NODES]] = !{![[NODE2:[0-9]+]], ![[NODE1:[0-9]+]]}
+// CHECK-DAG: ![[NODES]] = !{![[NODE1:[0-9]+]], ![[NODE2:[0-9]+]]}
 // CHECK-DAG: ![[NODE1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD1:[0-9]+]]{{.*}})
 // CHECK-DAG: ![[NODE2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD2:[0-9]+]]{{.*}})
 // CHECK-DAG: ![[MOD1]] = !DIModule({{.*}}name: "mod1"{{.*}})
@@ -443,7 +448,7 @@ llvm.func @func_debug_directives() {
 #di_compile_unit = #llvm.di_compile_unit<id = distinct[1]<>, sourceLanguage = DW_LANG_C, file = #di_file, isOptimized = false, emissionKind = None>
 
 // Recursive type itself.
-#di_struct_self = #llvm.di_composite_type<tag = DW_TAG_null, recId = distinct[0]<>>
+#di_struct_self = #llvm.di_composite_type<recId = distinct[0]<>, isRecSelf = true>
 #di_ptr_inner = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #di_struct_self, sizeInBits = 64>
 #di_subroutine_inner = #llvm.di_subroutine_type<types = #di_null_type, #di_ptr_inner>
 #di_subprogram_inner = #llvm.di_subprogram<
@@ -497,7 +502,7 @@ llvm.func @class_method() {
 
 // Ensures composite types with a recursive scope work.
 
-#di_composite_type_self = #llvm.di_composite_type<tag = DW_TAG_null, recId = distinct[0]<>>
+#di_composite_type_self = #llvm.di_composite_type<recId = distinct[0]<>, isRecSelf = true>
 #di_file = #llvm.di_file<"test.mlir" in "/">
 #di_subroutine_type = #llvm.di_subroutine_type<types = #di_composite_type_self>
 #di_subprogram = #llvm.di_subprogram<scope = #di_file, file = #di_file, subprogramFlags = Optimized, type = #di_subroutine_type>
@@ -508,7 +513,7 @@ llvm.func @class_method() {
 llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression} : !llvm.struct<()>
 
 // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[COMP:[0-9]+]],
-// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]],
+// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]]
 // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]],
 // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]])
 // CHECK: ![[SR_TYPES]] = !{![[COMP]]}
@@ -520,7 +525,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression}
 // replaced with the recursive self reference.
 
 #di_file = #llvm.di_file<"test.mlir" in "/">
-#di_composite_type_self = #llvm.di_composite_type<tag = DW_TAG_null, recId = distinct[0]<>>
+#di_composite_type_self = #llvm.di_composite_type<recId = distinct[0]<>, isRecSelf = true>
 
 #di_subroutine_type_inner = #llvm.di_subroutine_type<types = #di_composite_type_self>
 #di_subprogram_inner = #llvm.di_subprogram<scope = #di_file, file = #di_file, subprogramFlags = Optimized, type = #di_subroutine_type_inner>
@@ -540,7 +545,7 @@ llvm.mlir.global @global_variable() {dbg_expr = #di_global_variable_expression}
 // CHECK: distinct !DIGlobalVariable({{.*}}type: ![[VAR:[0-9]+]],
 // CHECK: ![[VAR]] = !DISubroutineType(types: ![[COMPS:[0-9]+]])
 // CHECK: ![[COMPS]] = !{![[COMP:[0-9]+]],
-// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]],
+// CHECK: ![[COMP]] = distinct !DICompositeType({{.*}}scope: ![[SCOPE:[0-9]+]]
 // CHECK: ![[SCOPE]] = !DISubprogram({{.*}}type: ![[SUBROUTINE:[0-9]+]],
 // CHECK: ![[SUBROUTINE]] = !DISubroutineType(types: ![[SR_TYPES:[0-9]+]])
 // CHECK: ![[SR_TYPES]] = !{![[COMP]]}



More information about the flang-commits mailing list