Skip to content

Commit 9db38e2

Browse files
committed
[mlir][debug] Handle DIImportedEntity.
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. There was no obvious place where I could place the `DIImportedEntityAttr` in the mlir. I have decided to piggy back on the `FusedLoc` of `FuncOp` which is already used to carry `DISubprogramAttr`. I am open to other ideas here. This PR currently does not handle entities imported in a global scope but that should be easy to handle in a subsequent PR.
1 parent 00a1a45 commit 9db38e2

File tree

7 files changed

+141
-6
lines changed

7 files changed

+141
-6
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,25 @@ def LLVM_DINamespaceAttr : LLVM_Attr<"DINamespace", "di_namespace",
619619
let assemblyFormat = "`<` struct(params) `>`";
620620
}
621621

622+
//===----------------------------------------------------------------------===//
623+
// DIImportedEntityAttr
624+
//===----------------------------------------------------------------------===//
625+
626+
def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entity",
627+
/*traits=*/[], "DINodeAttr"> {
628+
let parameters = (ins
629+
LLVM_DITagParameter:$tag,
630+
OptionalParameter<"DIScopeAttr">:$scope,
631+
OptionalParameter<"DINodeAttr">:$entity,
632+
OptionalParameter<"DIFileAttr">:$file,
633+
OptionalParameter<"unsigned">:$line,
634+
OptionalParameter<"StringAttr">:$name,
635+
OptionalArrayRefParameter<"DINodeAttr">:$elements
636+
);
637+
638+
let assemblyFormat = "`<` struct(params) `>`";
639+
}
640+
622641
//===----------------------------------------------------------------------===//
623642
// DISubrangeAttr
624643
//===----------------------------------------------------------------------===//

mlir/lib/Target/LLVMIR/DebugImporter.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,18 @@ Location DebugImporter::translateFuncLocation(llvm::Function *func) {
4040
// Add a fused location to link the subprogram information.
4141
StringAttr funcName = StringAttr::get(context, subprogram->getName());
4242
StringAttr fileName = StringAttr::get(context, subprogram->getFilename());
43-
return FusedLocWith<DISubprogramAttr>::get(
43+
auto loc = FusedLocWith<DISubprogramAttr>::get(
4444
{NameLoc::get(funcName),
4545
FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0)},
4646
translate(subprogram), context);
47+
if (subprogram->getRetainedNodes().empty())
48+
return loc;
49+
llvm::SmallVector<mlir::Attribute> entities;
50+
for (auto node : subprogram->getRetainedNodes())
51+
entities.push_back(translate(node));
52+
53+
auto entitiesAttr = mlir::ArrayAttr::get(context, entities);
54+
return FusedLocWith<mlir::ArrayAttr>::get(loc, entitiesAttr, context);
4755
}
4856

4957
//===----------------------------------------------------------------------===//
@@ -208,6 +216,21 @@ DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
208216
node->getExportSymbols());
209217
}
210218

219+
DIImportedEntityAttr
220+
DebugImporter::translateImpl(llvm::DIImportedEntity *node) {
221+
SmallVector<DINodeAttr> elements;
222+
223+
for (llvm::DINode *element : node->getElements()) {
224+
assert(element && "expected a non-null element type");
225+
elements.push_back(translate(element));
226+
}
227+
228+
return DIImportedEntityAttr::get(
229+
context, node->getTag(), translate(node->getScope()),
230+
translate(node->getEntity()), translate(node->getFile()), node->getLine(),
231+
getStringAttrOrNull(node->getRawName()), elements);
232+
}
233+
211234
DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
212235
// Only definitions require a distinct identifier.
213236
mlir::DistinctAttr id;
@@ -308,6 +331,8 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
308331
return translateImpl(casted);
309332
if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
310333
return translateImpl(casted);
334+
if (auto *casted = dyn_cast<llvm::DIImportedEntity>(node))
335+
return translateImpl(casted);
311336
if (auto *casted = dyn_cast<llvm::DILabel>(node))
312337
return translateImpl(casted);
313338
if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))

mlir/lib/Target/LLVMIR/DebugImporter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class DebugImporter {
7575
DIVariableAttr translateImpl(llvm::DIVariable *node);
7676
DIModuleAttr translateImpl(llvm::DIModule *node);
7777
DINamespaceAttr translateImpl(llvm::DINamespace *node);
78+
DIImportedEntityAttr translateImpl(llvm::DIImportedEntity *node);
7879
DIScopeAttr translateImpl(llvm::DIScope *node);
7980
DISubprogramAttr translateImpl(llvm::DISubprogram *node);
8081
DISubrangeAttr translateImpl(llvm::DISubrange *node);

mlir/lib/Target/LLVMIR/DebugTranslation.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,25 @@ void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {
6767
func.getLoc()->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>();
6868
if (!spLoc)
6969
return;
70-
llvmFunc.setSubprogram(translate(spLoc.getMetadata()));
70+
llvm::DISubprogram *sp = translate(spLoc.getMetadata());
71+
llvmFunc.setSubprogram(sp);
72+
73+
// Look for any entities that are imported in this function.
74+
auto entityLoc =
75+
func.getLoc()->findInstanceOf<FusedLocWith<mlir::ArrayAttr>>();
76+
if (!entityLoc)
77+
return;
78+
79+
SmallVector<llvm::Metadata *> imported;
80+
if (mlir::ArrayAttr arrayAttr = entityLoc.getMetadata()) {
81+
for (mlir::Attribute attr : arrayAttr.getValue()) {
82+
if (auto ent = dyn_cast_if_present<LLVM::DIImportedEntityAttr>(attr)) {
83+
llvm::DINode *node = translate(ent);
84+
imported.push_back(node);
85+
}
86+
}
87+
}
88+
sp->replaceRetainedNodes(llvm::MDTuple::get(llvmFunc.getContext(), imported));
7189
}
7290

7391
//===----------------------------------------------------------------------===//
@@ -326,6 +344,18 @@ llvm::DINamespace *DebugTranslation::translateImpl(DINamespaceAttr attr) {
326344
attr.getExportSymbols());
327345
}
328346

347+
llvm::DIImportedEntity *
348+
DebugTranslation::translateImpl(DIImportedEntityAttr attr) {
349+
SmallVector<llvm::Metadata *> elements;
350+
for (DINodeAttr member : attr.getElements())
351+
elements.push_back(translate(member));
352+
353+
return llvm::DIImportedEntity::get(
354+
llvmCtx, attr.getTag(), translate(attr.getScope()),
355+
translate(attr.getEntity()), translate(attr.getFile()), attr.getLine(),
356+
getMDStringOrNull(attr.getName()), llvm::MDNode::get(llvmCtx, elements));
357+
}
358+
329359
llvm::DISubrange *DebugTranslation::translateImpl(DISubrangeAttr attr) {
330360
auto getMetadataOrNull = [&](Attribute attr) -> llvm::Metadata * {
331361
if (!attr)
@@ -388,10 +418,10 @@ llvm::DINode *DebugTranslation::translate(DINodeAttr attr) {
388418
node = TypeSwitch<DINodeAttr, llvm::DINode *>(attr)
389419
.Case<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
390420
DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
391-
DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr,
392-
DILocalVariableAttr, DIModuleAttr, DINamespaceAttr,
393-
DINullTypeAttr, DIStringTypeAttr, DISubprogramAttr,
394-
DISubrangeAttr, DISubroutineTypeAttr>(
421+
DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
422+
DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
423+
DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
424+
DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
395425
[&](auto attr) { return translateImpl(attr); });
396426

397427
if (node && !node->isTemporary())

mlir/lib/Target/LLVMIR/DebugTranslation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class DebugTranslation {
8484
llvm::DIVariable *translateImpl(DIVariableAttr attr);
8585
llvm::DIModule *translateImpl(DIModuleAttr attr);
8686
llvm::DINamespace *translateImpl(DINamespaceAttr attr);
87+
llvm::DIImportedEntity *translateImpl(DIImportedEntityAttr attr);
8788
llvm::DIScope *translateImpl(DIScopeAttr attr);
8889
llvm::DISubprogram *translateImpl(DISubprogramAttr attr);
8990
llvm::DISubrange *translateImpl(DISubrangeAttr attr);

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,3 +792,29 @@ define void @string_type(ptr %arg1) {
792792
; CHECK-SAME: stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>
793793
; CHECK-SAME: stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>>
794794
; CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "str", file = #di_file, type = #di_string_type, flags = Artificial>
795+
796+
; // -----
797+
798+
; Test that imported entities for a functions are handled correctly.
799+
800+
define void @imp_fn() !dbg !12 {
801+
ret void
802+
}
803+
804+
!llvm.module.flags = !{!10}
805+
!llvm.dbg.cu = !{!4}
806+
807+
!2 = !DIModule(scope: !4, name: "mod1", file: !3, line: 1)
808+
!3 = !DIFile(filename: "test.f90", directory: "")
809+
!4 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3)
810+
!8 = !DIModule(scope: !4, name: "mod1", file: !3, line: 5)
811+
!10 = !{i32 2, !"Debug Info Version", i32 3}
812+
!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)
813+
!14 = !DISubroutineType(cc: DW_CC_program, types: !15)
814+
!15 = !{}
815+
!16 = !{!17}
816+
!17 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !12, entity: !8, file: !3, line: 1, elements: !15)
817+
818+
; CHECK-DAG: #[[M:.+]] = #llvm.di_module<{{.*}}name = "mod1"{{.*}}>
819+
; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}>
820+
; CHECK-DAG: llvm.di_imported_entity{{.*}}tag = DW_TAG_imported_module, scope = #[[SP]], entity = #[[M]]

mlir/test/Target/LLVMIR/llvmir-debug.mlir

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,39 @@ llvm.func @fn_with_gl() {
366366

367367
// -----
368368

369+
// Test that imported entries correctly generates 'retainedNodes' in the
370+
// subprogram.
371+
372+
llvm.func @imp_fn() {
373+
llvm.return
374+
} loc(#loc3)
375+
#file = #llvm.di_file<"test.f90" in "">
376+
#SP_TY = #llvm.di_subroutine_type<callingConvention = DW_CC_program>
377+
#CU = #llvm.di_compile_unit<id = distinct[0]<>,
378+
sourceLanguage = DW_LANG_Fortran95, file = #file, isOptimized = false,
379+
emissionKind = Full>
380+
#MOD = #llvm.di_module<file = #file, scope = #CU, name = "mod1">
381+
#MOD1 = #llvm.di_module<file = #file, scope = #CU, name = "mod2">
382+
#SP = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #CU, scope = #file,
383+
name = "imp_fn", file = #file, subprogramFlags = Definition, type = #SP_TY>
384+
#ENT1 = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #SP,
385+
entity = #MOD1, file = #file>
386+
#ENT2 = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #SP,
387+
entity = #MOD, file = #file>
388+
#loc1 = loc("test.f90":12:14)
389+
#loc2 = loc(fused<#SP>[#loc1])
390+
#loc3 = loc(fused<[#ENT1, #ENT2]>[#loc2])
391+
392+
393+
// CHECK-DAG: ![[SP:[0-9]+]] = {{.*}}!DISubprogram(name: "imp_fn"{{.*}}retainedNodes: ![[NODES:[0-9]+]])
394+
// CHECK-DAG: ![[NODES]] = !{![[NODE2:[0-9]+]], ![[NODE1:[0-9]+]]}
395+
// CHECK-DAG: ![[NODE1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD1:[0-9]+]]{{.*}})
396+
// CHECK-DAG: ![[NODE2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: ![[SP]], entity: ![[MOD2:[0-9]+]]{{.*}})
397+
// CHECK-DAG: ![[MOD1]] = !DIModule({{.*}}name: "mod1"{{.*}})
398+
// CHECK-DAG: ![[MOD2]] = !DIModule({{.*}}name: "mod2"{{.*}})
399+
400+
// -----
401+
369402
// Nameless and scopeless global constant.
370403

371404
// CHECK-LABEL: @.str.1 = external constant [10 x i8]

0 commit comments

Comments
 (0)