Skip to content

Commit 2918e77

Browse files
[mlir][debuginfo] Add support for subprogram annotations (#110946)
LLVM already supports `DW_TAG_LLVM_annotation` entries for subprograms, but this hasn't been surfaced to the LLVM dialect. I'm doing the minimal amount of work to support string-based annotations, which is useful for attaching metadata to functions, which is useful for debuggers to offer features beyond basic DWARF. As LLVM already supports this, this patch is not controversial.
1 parent 75103aa commit 2918e77

File tree

12 files changed

+127
-24
lines changed

12 files changed

+127
-24
lines changed

flang/lib/Optimizer/Transforms/AddDebugInfo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
344344
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly) {
345345
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
346346
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
347-
line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{});
347+
line, line, subprogramFlags, subTypeAttr, /*retainedNodes=*/{},
348+
/*annotations=*/{});
348349
funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
349350
return;
350351
}
@@ -368,7 +369,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
368369
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
369370
context, recId, /*isRecSelf=*/true, id, compilationUnit, Scope, funcName,
370371
fullName, funcFileAttr, line, line, subprogramFlags, subTypeAttr,
371-
/*retainedNodes=*/{});
372+
/*retainedNodes=*/{}, /*annotations=*/{});
372373

373374
// There is no direct information in the IR for any 'use' statement in the
374375
// function. We have to extract that information from the DeclareOp. We do
@@ -401,7 +402,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
401402
spAttr = mlir::LLVM::DISubprogramAttr::get(
402403
context, recId, /*isRecSelf=*/false, id2, compilationUnit, Scope,
403404
funcName, fullName, funcFileAttr, line, line, subprogramFlags,
404-
subTypeAttr, entities);
405+
subTypeAttr, entities, /*annotations=*/{});
405406
funcOp->setLoc(builder.getFusedLoc({l}, spAttr));
406407

407408
funcOp.walk([&](fir::cg::XDeclareOp declOp) {

mlir/include/mlir-c/Dialect/LLVM.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,12 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDISubprogramAttrGet(
325325
MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name,
326326
MlirAttribute linkageName, MlirAttribute file, unsigned int line,
327327
unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type,
328-
intptr_t nRetainedNodes, MlirAttribute const *retainedNodes);
328+
intptr_t nRetainedNodes, MlirAttribute const *retainedNodes,
329+
intptr_t nAnnotations, MlirAttribute const *annotations);
330+
331+
/// Creates a LLVM DIAnnotation attribute.
332+
MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIAnnotationAttrGet(
333+
MlirContext ctx, MlirAttribute name, MlirAttribute value);
329334

330335
/// Gets the scope from this DISubprogramAttr.
331336
MLIR_CAPI_EXPORTED MlirAttribute

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,19 +586,20 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
586586
OptionalParameter<"unsigned">:$scopeLine,
587587
OptionalParameter<"DISubprogramFlags">:$subprogramFlags,
588588
OptionalParameter<"DISubroutineTypeAttr">:$type,
589-
OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes
589+
OptionalArrayRefParameter<"DINodeAttr">:$retainedNodes,
590+
OptionalArrayRefParameter<"DINodeAttr">:$annotations
590591
);
591592
let builders = [
592593
AttrBuilder<(ins
593594
"DistinctAttr":$id, "DICompileUnitAttr":$compileUnit,
594595
"DIScopeAttr":$scope, "StringAttr":$name, "StringAttr":$linkageName,
595596
"DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine,
596597
"DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type,
597-
"ArrayRef<DINodeAttr>":$retainedNodes
598+
"ArrayRef<DINodeAttr>":$retainedNodes, "ArrayRef<DINodeAttr>":$annotations
598599
), [{
599600
return $_get($_ctxt, /*recId=*/nullptr, /*isRecSelf=*/false, id, compileUnit,
600601
scope, name, linkageName, file, line, scopeLine,
601-
subprogramFlags, type, retainedNodes);
602+
subprogramFlags, type, retainedNodes, annotations);
602603
}]>
603604
];
604605
let assemblyFormat = "`<` struct(params) `>`";
@@ -670,6 +671,21 @@ def LLVM_DIImportedEntityAttr : LLVM_Attr<"DIImportedEntity", "di_imported_entit
670671
let assemblyFormat = "`<` struct(params) `>`";
671672
}
672673

674+
//===----------------------------------------------------------------------===//
675+
// DIAnnotationAttr
676+
//===----------------------------------------------------------------------===//
677+
678+
def LLVM_DIAnnotationAttr : LLVM_Attr<"DIAnnotation",
679+
"di_annotation",
680+
/*traits=*/[], "DINodeAttr"> {
681+
let parameters = (ins
682+
"StringAttr":$name,
683+
"StringAttr":$value
684+
);
685+
686+
let assemblyFormat = "`<` struct(params) `>`";
687+
}
688+
673689
//===----------------------------------------------------------------------===//
674690
// DISubrangeAttr
675691
//===----------------------------------------------------------------------===//

mlir/lib/CAPI/Dialect/LLVM.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,14 @@ MlirAttribute mlirLLVMDISubprogramAttrGet(
303303
MlirAttribute compileUnit, MlirAttribute scope, MlirAttribute name,
304304
MlirAttribute linkageName, MlirAttribute file, unsigned int line,
305305
unsigned int scopeLine, uint64_t subprogramFlags, MlirAttribute type,
306-
intptr_t nRetainedNodes, MlirAttribute const *retainedNodes) {
306+
intptr_t nRetainedNodes, MlirAttribute const *retainedNodes,
307+
intptr_t nAnnotations, MlirAttribute const *annotations) {
307308
SmallVector<Attribute> nodesStorage;
308309
nodesStorage.reserve(nRetainedNodes);
310+
311+
SmallVector<Attribute> annotationsStorage;
312+
annotationsStorage.reserve(nAnnotations);
313+
309314
return wrap(DISubprogramAttr::get(
310315
unwrap(ctx), cast<DistinctAttr>(unwrap(recId)), isRecSelf,
311316
cast<DistinctAttr>(unwrap(id)),
@@ -316,6 +321,9 @@ MlirAttribute mlirLLVMDISubprogramAttrGet(
316321
cast<DISubroutineTypeAttr>(unwrap(type)),
317322
llvm::map_to_vector(
318323
unwrapList(nRetainedNodes, retainedNodes, nodesStorage),
324+
[](Attribute a) { return cast<DINodeAttr>(a); }),
325+
llvm::map_to_vector(
326+
unwrapList(nAnnotations, annotations, annotationsStorage),
319327
[](Attribute a) { return cast<DINodeAttr>(a); })));
320328
}
321329

@@ -375,3 +383,9 @@ MlirAttribute mlirLLVMDIImportedEntityAttrGet(
375383
llvm::map_to_vector(unwrapList(nElements, elements, elementsStorage),
376384
[](Attribute a) { return cast<DINodeAttr>(a); })));
377385
}
386+
387+
MlirAttribute mlirLLVMDIAnnotationAttrGet(MlirContext ctx, MlirAttribute name,
388+
MlirAttribute value) {
389+
return wrap(DIAnnotationAttr::get(unwrap(ctx), cast<StringAttr>(unwrap(name)),
390+
cast<StringAttr>(unwrap(value))));
391+
}

mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ bool DINodeAttr::classof(Attribute attr) {
6060
DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
6161
DIImportedEntityAttr, DILabelAttr, DILexicalBlockAttr,
6262
DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
63-
DINamespaceAttr, DINullTypeAttr, DIStringTypeAttr,
64-
DISubprogramAttr, DISubrangeAttr, DISubroutineTypeAttr>(
65-
attr);
63+
DINamespaceAttr, DINullTypeAttr, DIAnnotationAttr,
64+
DIStringTypeAttr, DISubprogramAttr, DISubrangeAttr,
65+
DISubroutineTypeAttr>(attr);
6666
}
6767

6868
//===----------------------------------------------------------------------===//
@@ -221,15 +221,16 @@ DICompositeTypeAttr::getRecSelf(DistinctAttr recId) {
221221
//===----------------------------------------------------------------------===//
222222

223223
DIRecursiveTypeAttrInterface DISubprogramAttr::withRecId(DistinctAttr recId) {
224-
return DISubprogramAttr::get(
225-
getContext(), recId, getIsRecSelf(), getId(), getCompileUnit(),
226-
getScope(), getName(), getLinkageName(), getFile(), getLine(),
227-
getScopeLine(), getSubprogramFlags(), getType(), getRetainedNodes());
224+
return DISubprogramAttr::get(getContext(), recId, getIsRecSelf(), getId(),
225+
getCompileUnit(), getScope(), getName(),
226+
getLinkageName(), getFile(), getLine(),
227+
getScopeLine(), getSubprogramFlags(), getType(),
228+
getRetainedNodes(), getAnnotations());
228229
}
229230

230231
DIRecursiveTypeAttrInterface DISubprogramAttr::getRecSelf(DistinctAttr recId) {
231232
return DISubprogramAttr::get(recId.getContext(), recId, /*isRecSelf=*/true,
232-
{}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {});
233+
{}, {}, {}, {}, {}, 0, 0, {}, {}, {}, {}, {});
233234
}
234235

235236
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
7878
auto subprogramAttr = LLVM::DISubprogramAttr::get(
7979
context, id, compileUnitAttr, fileAttr, funcName, funcName, fileAttr,
8080
/*line=*/line, /*scopeline=*/col, subprogramFlags, subroutineTypeAttr,
81-
/*retainedNodes=*/{});
81+
/*retainedNodes=*/{}, /*annotations=*/{});
8282
llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
8383
}
8484

mlir/lib/Target/LLVMIR/DebugImporter.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,32 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
245245
if (llvm::is_contained(retainedNodes, nullptr))
246246
retainedNodes.clear();
247247

248+
SmallVector<DINodeAttr> annotations;
249+
// We currently only support `string` values for annotations on the MLIR side.
250+
// Theoretically we could support other primitives, but LLVM is not using
251+
// other types in practice.
252+
if (llvm::DINodeArray rawAnns = node->getAnnotations(); rawAnns) {
253+
for (size_t i = 0, e = rawAnns->getNumOperands(); i < e; ++i) {
254+
const llvm::MDTuple *tuple = cast<llvm::MDTuple>(rawAnns->getOperand(i));
255+
if (tuple->getNumOperands() != 2)
256+
continue;
257+
const llvm::MDString *name = cast<llvm::MDString>(tuple->getOperand(0));
258+
const llvm::MDString *value =
259+
dyn_cast<llvm::MDString>(tuple->getOperand(1));
260+
if (name && value) {
261+
annotations.push_back(DIAnnotationAttr::get(
262+
context, StringAttr::get(context, name->getString()),
263+
StringAttr::get(context, value->getString())));
264+
}
265+
}
266+
}
267+
248268
return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
249269
getStringAttrOrNull(node->getRawName()),
250270
getStringAttrOrNull(node->getRawLinkageName()),
251271
translate(node->getFile()), node->getLine(),
252272
node->getScopeLine(), *subprogramFlags, type,
253-
retainedNodes);
273+
retainedNodes, annotations);
254274
}
255275

256276
DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) {

mlir/lib/Target/LLVMIR/DebugTranslation.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ DebugTranslation::getMDTupleOrNull(ArrayRef<DINodeAttr> elements) {
102102
return nullptr;
103103
SmallVector<llvm::Metadata *> llvmElements = llvm::to_vector(
104104
llvm::map_range(elements, [&](DINodeAttr attr) -> llvm::Metadata * {
105+
if (DIAnnotationAttr annAttr = dyn_cast<DIAnnotationAttr>(attr)) {
106+
llvm::Metadata *ops[2] = {
107+
llvm::MDString::get(llvmCtx, annAttr.getName()),
108+
llvm::MDString::get(llvmCtx, annAttr.getValue())};
109+
return llvm::MDNode::get(llvmCtx, ops);
110+
}
105111
return translate(attr);
106112
}));
107113
return llvm::MDNode::get(llvmCtx, llvmElements);
@@ -332,7 +338,8 @@ llvm::DISubprogram *DebugTranslation::translateImpl(DISubprogramAttr attr) {
332338
/*ThisAdjustment=*/0, llvm::DINode::FlagZero,
333339
static_cast<llvm::DISubprogram::DISPFlags>(attr.getSubprogramFlags()),
334340
compileUnit, /*TemplateParams=*/nullptr, /*Declaration=*/nullptr,
335-
getMDTupleOrNull(attr.getRetainedNodes()));
341+
getMDTupleOrNull(attr.getRetainedNodes()), nullptr,
342+
getMDTupleOrNull(attr.getAnnotations()));
336343
if (attr.getId())
337344
distinctAttrToNode.try_emplace(attr.getId(), node);
338345
return node;

mlir/test/CAPI/llvm.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,16 @@ static void testDebugInfoAttributes(MlirContext ctx) {
324324
mlirAttributeDump(di_imported_entity);
325325
// CHECK: #llvm.di_imported_entity<{{.*}}>
326326

327+
MlirAttribute di_annotation = mlirLLVMDIAnnotationAttrGet(
328+
ctx, mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("foo")),
329+
mlirStringAttrGet(ctx, mlirStringRefCreateFromCString("bar")));
330+
331+
mlirAttributeDump(di_annotation);
332+
// CHECK: #llvm.di_annotation<{{.*}}>
333+
327334
MlirAttribute di_subprogram = mlirLLVMDISubprogramAttrGet(
328335
ctx, recId0, false, id, compile_unit, compile_unit, foo, bar, file, 1, 2,
329-
0, subroutine_type, 1, &di_imported_entity);
336+
0, subroutine_type, 1, &di_imported_entity, 1, &di_annotation);
330337
// CHECK: #llvm.di_subprogram<{{.*}}>
331338
mlirAttributeDump(di_subprogram);
332339

mlir/test/Dialect/LLVMIR/debuginfo.mlir

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,11 @@
116116
apinotes = "/", line = 42, isDecl = true
117117
>
118118

119-
// CHECK-DAG: #[[SP2:.*]] = #llvm.di_subprogram<compileUnit = #[[CU]], scope = #[[MODULE]], name = "value", file = #[[FILE]], subprogramFlags = Definition, type = #[[SPTYPE2]]>
119+
// CHECK-DAG: #[[SP2:.*]] = #llvm.di_subprogram<compileUnit = #[[CU]], scope = #[[MODULE]], name = "value", file = #[[FILE]], subprogramFlags = Definition, type = #[[SPTYPE2]], annotations = #llvm.di_annotation<name = "foo", value = "bar">
120120
#sp2 = #llvm.di_subprogram<
121121
compileUnit = #cu, scope = #module, name = "value",
122-
file = #file, subprogramFlags = "Definition", type = #spType2
122+
file = #file, subprogramFlags = "Definition", type = #spType2,
123+
annotations = #llvm.di_annotation<name = "foo", value = "bar">
123124
>
124125

125126
// CHECK-DAG: #[[BLOCK0:.*]] = #llvm.di_lexical_block<scope = #[[SP0]], line = 1, column = 2>

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,3 +816,30 @@ define void @imp_fn() !dbg !12 {
816816
; CHECK-DAG: #[[SP_REC:.+]] = #llvm.di_subprogram<recId = distinct{{.*}}<>, isRecSelf = true>
817817
; CHECK-DAG: #[[IE:.+]] = #llvm.di_imported_entity<tag = DW_TAG_imported_module, scope = #[[SP_REC]], entity = #[[M]]{{.*}}>
818818
; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<{{.*}}name = "imp_fn"{{.*}}retainedNodes = #[[IE]]>
819+
820+
; // -----
821+
822+
; Test that annotations are handled correctly
823+
824+
; CHECK-LABEL: @fn_with_annotations
825+
826+
define void @fn_with_annotations() !dbg !12 {
827+
ret void
828+
}
829+
830+
!llvm.module.flags = !{!10}
831+
!llvm.dbg.cu = !{!4}
832+
833+
!2 = !DIModule(scope: !4, name: "mod1", file: !3, line: 1)
834+
!3 = !DIFile(filename: "test.f90", directory: "")
835+
!4 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3)
836+
!8 = !DIModule(scope: !4, name: "mod1", file: !3, line: 5)
837+
!10 = !{i32 2, !"Debug Info Version", i32 3}
838+
!12 = distinct !DISubprogram(name: "fn_with_annotations", linkageName: "fn_with_annotations", scope: !3, file: !3, line: 10, type: !14, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !4, annotations: !16)
839+
!14 = !DISubroutineType(cc: DW_CC_program, types: !15)
840+
!15 = !{}
841+
!16 = !{!17}
842+
!17 = !{!"foo", !"bar"}
843+
844+
845+
; CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "fn_with_annotations"{{.*}}annotations = #llvm.di_annotation<name = "foo", value = "bar">>

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ llvm.func @func_no_debug() {
8989
#spType1 = #llvm.di_subroutine_type<callingConvention = DW_CC_normal>
9090
#sp1 = #llvm.di_subprogram<
9191
compileUnit = #cu, scope = #module, name = "empty_types",
92-
file = #file, subprogramFlags = "Definition", type = #spType1
92+
file = #file, subprogramFlags = "Definition", type = #spType1,
93+
annotations = #llvm.di_annotation<name = "foo", value = "bar">
9394
>
9495

9596
// CHECK-LABEL: define void @func_with_debug(
@@ -177,11 +178,14 @@ llvm.func @empty_types() {
177178
// CHECK: ![[CALLEE_ARGS]] = !{![[ARG_TYPE:.*]], ![[ARG_TYPE:.*]]}
178179
// CHECK: ![[INLINE_LOC]] = !DILocation(line: 28, column: 5,
179180

180-
// CHECK: ![[EMPTY_TYPES_LOC]] = distinct !DISubprogram(name: "empty_types", scope: ![[MODULE:.*]], file: ![[CU_FILE_LOC]], type: ![[EMPTY_TYPES_TYPE:.*]], spFlags: DISPFlagDefinition
181+
// CHECK: ![[EMPTY_TYPES_LOC]] = distinct !DISubprogram(name: "empty_types", scope: ![[MODULE:.*]], file: ![[CU_FILE_LOC]], type: ![[EMPTY_TYPES_TYPE:.*]], spFlags: DISPFlagDefinition, unit: ![[CU_LOC]], annotations: ![[ANNOTATIONS:.*]])
181182
// CHECK: ![[MODULE]] = !DIModule(scope: ![[CU_FILE_LOC]], name: "module", configMacros: "bar", includePath: "/", apinotes: "/", file: ![[CU_FILE_LOC]], line: 42, isDecl: true)
182183
// CHECK: ![[EMPTY_TYPES_TYPE]] = !DISubroutineType(cc: DW_CC_normal, types: ![[EMPTY_TYPES_ARGS:.*]])
183184
// CHECK: ![[EMPTY_TYPES_ARGS]] = !{}
184185

186+
// CHECK: ![[ANNOTATIONS]] = !{![[ANNOTATION:.*]]}
187+
// CHECK: ![[ANNOTATION]] = !{!"foo", !"bar"}
188+
185189
// -----
186190

187191
#di_file = #llvm.di_file<"foo.mlir" in "/test/">

0 commit comments

Comments
 (0)