[Mlir-commits] [mlir] bc4bedd - [mlir][debug] Handle DIImportedEntity. (#103055)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Aug 27 03:10:15 PDT 2024
Author: Abid Qadeer
Date: 2024-08-27T11:10:11+01:00
New Revision: bc4bedd5ed2c8d9f1a648c72d38e17361aff8a30
URL: https://github.com/llvm/llvm-project/commit/bc4bedd5ed2c8d9f1a648c72d38e17361aff8a30
DIFF: https://github.com/llvm/llvm-project/commit/bc4bedd5ed2c8d9f1a648c72d38e17361aff8a30.diff
LOG: [mlir][debug] Handle DIImportedEntity. (#103055)
The `DIImporedEntity` can be used to represent imported entities like
C++'s namespace with using directive or fortran's moudule with use
statement.
This PR adds `DIImportedEntityAttr` and 2-way translation from
`DIImportedEntity` to `DIImportedEntityAttr` and vice versa.
When an entity is imported in a function, the `retainedNodes` field of
the `DISubprogram` contains all the imported nodes. See the C++ code and
the LLVM IR below.
```
void test() {
using namespace n1;
...
}
!2 = !DINamespace(name: "n1", scope: null)
!16 = distinct !DISubprogram(name: "test", ..., retainedNodes: !19) !19 = !{!20}
!20 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !16, entity: !2 ...)
```
This PR makes sure that the translation from mlir to `retainedNodes`
field happens correctly both ways.
To side step the cyclic dependency between `DISubprogramAttr` and `DIImportedEntityAttr`,
we have decided to not have `scope` field in the `DIImportedEntityAttr` and it is inferred
from the entity which hold the list of `DIImportedEntityAttr`. A `retainedNodes` field has been
added in the `DISubprogramAttr` which contains the list of `DIImportedEntityAttr` for that
function.
This PR currently does not handle entities imported in a global scope
but that should be easy to handle in a subsequent PR.
Added:
Modified:
flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
mlir/include/mlir-c/Dialect/LLVM.h
mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
mlir/lib/CAPI/Dialect/LLVM.cpp
mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
mlir/lib/Target/LLVMIR/DebugImporter.cpp
mlir/lib/Target/LLVMIR/DebugImporter.h
mlir/lib/Target/LLVMIR/DebugTranslation.cpp
mlir/lib/Target/LLVMIR/DebugTranslation.h
mlir/test/CAPI/llvm.c
mlir/test/Target/LLVMIR/Import/debug-info.ll
mlir/test/Target/LLVMIR/llvmir-debug.mlir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index fb637684d374a5..46fc40b714aac7 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -301,7 +301,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
- line, line, subprogramFlags, subTypeAttr);
+ line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{});
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
// Don't process variables if user asked for line tables only.
diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h
index 631b5646183204..5eb96a86e472d6 100644
--- a/mlir/include/mlir-c/Dialect/LLVM.h
+++ b/mlir/include/mlir-c/Dialect/LLVM.h
@@ -316,7 +316,8 @@ 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);
+ uint64_t subprogramFlags, MlirAttribute type, intptr_t nRetainedNodes,
+ MlirAttribute const *retainedNodes);
/// Gets the scope from this DISubprogramAttr.
MLIR_CAPI_EXPORTED MlirAttribute
@@ -353,6 +354,12 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIModuleAttrGet(
MlirAttribute name, MlirAttribute configMacros, MlirAttribute includePath,
MlirAttribute apinotes, unsigned int line, bool isDecl);
+/// 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);
+
/// Gets the scope of this DIModuleAttr.
MLIR_CAPI_EXPORTED MlirAttribute
mlirLLVMDIModuleAttrGetScope(MlirAttribute diModule);
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 5d96f506342588..e57be7f760d380 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -565,19 +565,21 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
OptionalParameter<"unsigned">:$line,
OptionalParameter<"unsigned">:$scopeLine,
OptionalParameter<"DISubprogramFlags">:$subprogramFlags,
- OptionalParameter<"DISubroutineTypeAttr">:$type
+ OptionalParameter<"DISubroutineTypeAttr">:$type,
+ OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes
);
let builders = [
AttrBuilderWithInferredContext<(ins
"DistinctAttr":$id, "DICompileUnitAttr":$compileUnit,
"DIScopeAttr":$scope, "StringRef":$name, "StringRef":$linkageName,
"DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine,
- "DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type
+ "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);
+ scopeLine, subprogramFlags, type, retainedNodes);
}]>
];
@@ -619,6 +621,29 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace",
let assemblyFormat = "`<` struct(params) `>`";
}
+//===----------------------------------------------------------------------===//
+// DIImportedEntityAttr
+//===----------------------------------------------------------------------===//
+
+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,
+ "DINodeAttr":$entity,
+ OptionalParameter<"DIFileAttr">:$file,
+ OptionalParameter<"unsigned">:$line,
+ OptionalParameter<"StringAttr">:$name,
+ OptionalArrayRefParameter<"DINodeAttr">:$elements
+ );
+
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
//===----------------------------------------------------------------------===//
// DISubrangeAttr
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index 03e2f2be2156af..13341f0c4de881 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -293,14 +293,20 @@ 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) {
+ 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)),
cast<DICompileUnitAttr>(unwrap(compileUnit)),
cast<DIScopeAttr>(unwrap(scope)), cast<StringAttr>(unwrap(name)),
cast<StringAttr>(unwrap(linkageName)), cast<DIFileAttr>(unwrap(file)),
line, scopeLine, DISubprogramFlags(subprogramFlags),
- cast<DISubroutineTypeAttr>(unwrap(type))));
+ cast<DISubroutineTypeAttr>(unwrap(type)),
+ llvm::map_to_vector(
+ unwrapList(nRetainedNodes, retainedNodes, nodesStorage),
+ [](Attribute a) { return cast<DINodeAttr>(a); })));
}
MlirAttribute mlirLLVMDISubprogramAttrGetScope(MlirAttribute diSubprogram) {
@@ -345,3 +351,16 @@ MlirAttribute mlirLLVMDIModuleAttrGet(MlirContext ctx, MlirAttribute file,
MlirAttribute mlirLLVMDIModuleAttrGetScope(MlirAttribute diModule) {
return wrap(cast<DIModuleAttr>(unwrap(diModule)).getScope());
}
+
+MlirAttribute mlirLLVMDIImportedEntityAttrGet(
+ MlirContext ctx, unsigned int tag, 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)),
+ 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 963a4be25079e3..98a9659735e7e6 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -58,10 +58,11 @@ void LLVMDialect::registerAttributes() {
bool DINodeAttr::classof(Attribute attr) {
return llvm::isa<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
- DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr,
- DILocalVariableAttr, DIModuleAttr, DINamespaceAttr,
- DINullTypeAttr, DIStringTypeAttr, DISubprogramAttr,
- DISubrangeAttr, DISubroutineTypeAttr>(attr);
+ DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
+ DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
+ DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
+ DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
+ attr);
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index 395ff6ed1e48ea..758700c9272bc8 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -79,7 +79,8 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
context, id, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr,
fileAttr,
/*line=*/line,
- /*scopeline=*/col, subprogramFlags, subroutineTypeAttr);
+ /*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 1817c1271b43ee..ce3643f513d34a 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -208,6 +208,20 @@ DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
node->getExportSymbols());
}
+DIImportedEntityAttr
+DebugImporter::translateImpl(llvm::DIImportedEntity *node) {
+ SmallVector<DINodeAttr> elements;
+ for (llvm::DINode *element : node->getElements()) {
+ assert(element && "expected a non-null element type");
+ elements.push_back(translate(element));
+ }
+
+ return DIImportedEntityAttr::get(
+ context, node->getTag(), translate(node->getEntity()),
+ translate(node->getFile()), node->getLine(),
+ getStringAttrOrNull(node->getRawName()), elements);
+}
+
DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
// Only definitions require a distinct identifier.
mlir::DistinctAttr id;
@@ -223,11 +237,17 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
DISubroutineTypeAttr type = translate(node->getType());
if (node->getType() && !type)
return nullptr;
+
+ SmallVector<DINodeAttr> retainedNodes;
+ for (llvm::DINode *retainedNode : node->getRetainedNodes())
+ retainedNodes.push_back(translate(retainedNode));
+
return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
getStringAttrOrNull(node->getRawName()),
getStringAttrOrNull(node->getRawLinkageName()),
translate(node->getFile()), node->getLine(),
- node->getScopeLine(), *subprogramFlags, type);
+ node->getScopeLine(), *subprogramFlags, type,
+ retainedNodes);
}
DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {
@@ -308,6 +328,8 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
return translateImpl(casted);
if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DIImportedEntity>(node))
+ return translateImpl(casted);
if (auto *casted = dyn_cast<llvm::DILabel>(node))
return translateImpl(casted);
if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.h b/mlir/lib/Target/LLVMIR/DebugImporter.h
index 0e040891ba6c02..cb796676759c39 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.h
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.h
@@ -75,6 +75,7 @@ class DebugImporter {
DIVariableAttr translateImpl(llvm::DIVariable *node);
DIModuleAttr translateImpl(llvm::DIModule *node);
DINamespaceAttr translateImpl(llvm::DINamespace *node);
+ DIImportedEntityAttr translateImpl(llvm::DIImportedEntity *node);
DIScopeAttr translateImpl(llvm::DIScope *node);
DISubprogramAttr translateImpl(llvm::DISubprogram *node);
DISubrangeAttr translateImpl(llvm::DISubrange *node);
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 95b37e47d04612..042e015f107fea 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -306,6 +306,19 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) {
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));
+
if (attr.getId())
distinctAttrToNode.try_emplace(attr.getId(), node);
return node;
@@ -326,6 +339,18 @@ 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));
+
+ return llvm::DIImportedEntity::get(
+ llvmCtx, attr.getTag(), scope, translate(attr.getEntity()),
+ translate(attr.getFile()), attr.getLine(),
+ getMDStringOrNull(attr.getName()), llvm::MDNode::get(llvmCtx, elements));
+}
+
llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) {
auto getMetadataOrNull = [&](Attribute attr) -> llvm::Metadata * {
if (!attr)
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h
index 16a853736226da..37b985acf8541e 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.h
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h
@@ -90,6 +90,12 @@ 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>)`:
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index d3054aa6a0d93d..da28a96f89691d 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -312,9 +312,15 @@ static void testDebugInfoAttributes(MlirContext ctx) {
// CHECK: #llvm.di_subroutine_type<{{.*}}>
mlirAttributeDump(subroutine_type);
- MlirAttribute di_subprogram =
- mlirLLVMDISubprogramAttrGet(ctx, id, compile_unit, compile_unit, foo, bar,
- file, 1, 2, 0, subroutine_type);
+ MlirAttribute di_imported_entity = mlirLLVMDIImportedEntityAttrGet(
+ ctx, 0, 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);
// CHECK: #llvm.di_subprogram<{{.*}}>
mlirAttributeDump(di_subprogram);
diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll
index 03c3855a9a324c..bb03da37c0d097 100644
--- a/mlir/test/Target/LLVMIR/Import/debug-info.ll
+++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll
@@ -792,3 +792,28 @@ define void @string_type(ptr %arg1) {
; CHECK-SAME: stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>
; CHECK-SAME: stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>>
; CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "str", file = #di_file, type = #di_string_type, flags = Artificial>
+
+; // -----
+
+; Test that imported entities for a functions are handled correctly.
+
+define void @imp_fn() !dbg !12 {
+ ret void
+}
+
+!llvm.module.flags = !{!10}
+!llvm.dbg.cu = !{!4}
+
+!2 = !DIModule(scope: !4, name: "mod1", file: !3, line: 1)
+!3 = !DIFile(filename: "test.f90", directory: "")
+!4 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3)
+!8 = !DIModule(scope: !4, name: "mod1", file: !3, line: 5)
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!12 = distinct !DISubprogram(name: "imp_fn", linkageName: "imp_fn", scope: !3, file: !3, line: 10, type: !14, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !16)
+!14 = !DISubroutineType(cc: DW_CC_program, types: !15)
+!15 = !{}
+!16 = !{!17}
+!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]]{{.*}}>>
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index 1a9a8561de00dc..30b2ba5e9bad1f 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -366,6 +366,36 @@ llvm.func @fn_with_gl() {
// -----
+// Test that imported entries correctly generates 'retainedNodes' in the
+// subprogram.
+
+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,
+ 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>>
+#loc1 = loc("test.f90":12:14)
+#loc2 = loc(fused<#SP>[#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: ![[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"{{.*}})
+// CHECK-DAG: ![[MOD2]] = !DIModule({{.*}}name: "mod2"{{.*}})
+
+// -----
+
// Nameless and scopeless global constant.
// CHECK-LABEL: @.str.1 = external constant [10 x i8]
More information about the Mlir-commits
mailing list