Skip to content

[mlir][debug] Handle DIImportedEntity. #103055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,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.
Expand Down
9 changes: 8 additions & 1 deletion mlir/include/mlir-c/Dialect/LLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
31 changes: 28 additions & 3 deletions mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}]>
];

Expand Down Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
23 changes: 21 additions & 2 deletions mlir/lib/CAPI/Dialect/LLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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); })));
}
9 changes: 5 additions & 4 deletions mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

//===----------------------------------------------------------------------===//
Expand Down
3 changes: 2 additions & 1 deletion mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
24 changes: 23 additions & 1 deletion mlir/lib/Target/LLVMIR/DebugImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,20 @@ DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
node->getExportSymbols());
}

DIImportedEntityAttr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires a clear TODO comment that we drop this information that also explains why it is dropped. Ultimately, we would want to import even the cyclic structures, but this can wait for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a brief comment on the attribute itself why there is no scope field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment on the attribute.

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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions mlir/lib/Target/LLVMIR/DebugImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions mlir/lib/Target/LLVMIR/DebugTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Add a comment on why this is done in a delayed manner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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;
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions mlir/lib/Target/LLVMIR/DebugTranslation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This needs a comment, given that it does something non-obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


/// Attributes that support self recursion need to implement an additional
/// method to hook into `translateRecursive`.
/// - `<temp llvm type> translateTemporaryImpl(<mlir type>)`:
Expand Down
12 changes: 9 additions & 3 deletions mlir/test/CAPI/llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
25 changes: 25 additions & 0 deletions mlir/test/Target/LLVMIR/Import/debug-info.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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]]{{.*}}>>
30 changes: 30 additions & 0 deletions mlir/test/Target/LLVMIR/llvmir-debug.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Loading