Skip to content

Commit 39baae1

Browse files
committed
[MLIR][LLVM] Add distinct identifier to the DISubprogram attribute
This commit adds an optional distinct attribute parameter to the DISubprogramAttr. This enables modeling of distinct subprograms, as required for LLVM IR. This change is required to avoid accidential uniquing of subprograms on functions that would lead to invalid LLVM IR post export.
1 parent b3037ae commit 39baae1

File tree

9 files changed

+104
-40
lines changed

9 files changed

+104
-40
lines changed

flang/lib/Optimizer/Transforms/AddDebugFoundation.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,24 @@ void AddDebugFoundationPass::runOnOperation() {
9393
context, llvm::dwarf::getCallingConvention("DW_CC_normal"),
9494
{bT, bT});
9595
mlir::LLVM::DIFileAttr funcFileAttr = getFileAttr(funcFilePath);
96-
mlir::LLVM::DISubprogramAttr spAttr = mlir::LLVM::DISubprogramAttr::get(
97-
context, cuAttr, fileAttr, funcName, funcName, funcFileAttr, /*line=*/1,
98-
/*scopeline=*/1, mlir::LLVM::DISubprogramFlags::Definition,
99-
subTypeAttr);
96+
mlir::LLVM::DISubprogramAttr spAttr;
97+
// Only definitions need a distinct identifier and a compilation unit.
98+
if (!funcOp.isExternal()) {
99+
auto id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
100+
spAttr = mlir::LLVM::DISubprogramAttr::get(
101+
context, id, cuAttr, fileAttr, funcName, funcName, funcFileAttr,
102+
/*line=*/1,
103+
/*scopeline=*/1, mlir::LLVM::DISubprogramFlags::Definition,
104+
subTypeAttr);
105+
} else {
106+
// TODO: Fix the subprogram flags once their modeling has been fixed.
107+
spAttr = mlir::LLVM::DISubprogramAttr::get(
108+
context, mlir::DistinctAttr(), mlir::LLVM::DICompileUnitAttr(),
109+
fileAttr, funcName, funcName, funcFileAttr,
110+
/*line=*/1,
111+
/*scopeline=*/1, mlir::LLVM::DISubprogramFlags::Definition,
112+
subTypeAttr);
113+
}
100114
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
101115
});
102116
}

flang/test/Transforms/debug-line-table-inc-file.fir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ module attributes {} {
3030
// CHECK: #[[MODULE_LOC]] = loc("{{.*}}simple.f90":0:0)
3131
// CHECK: #[[LOC_INC_FILE:.*]] = loc("{{.*}}inc.f90":1:1)
3232
// CHECK: #[[LOC_FILE:.*]] = loc("{{.*}}simple.f90":3:1)
33-
// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
34-
// CHECK: #[[DI_SP_INC:.*]] = #llvm.di_subprogram<compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QPsinc", linkageName = "_QPsinc", file = #[[DI_INC_FILE]], {{.*}}>
35-
// CHECK: #[[DI_SP:.*]] = #llvm.di_subprogram<compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QQmain", linkageName = "_QQmain", file = #[[DI_FILE]], {{.*}}>
33+
// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
34+
// CHECK: #[[DI_SP_INC:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QPsinc", linkageName = "_QPsinc", file = #[[DI_INC_FILE]], {{.*}}>
35+
// CHECK: #[[DI_SP:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QQmain", linkageName = "_QQmain", file = #[[DI_FILE]], {{.*}}>
3636
// CHECK: #[[FUSED_LOC_INC_FILE]] = loc(fused<#[[DI_SP_INC]]>[#[[LOC_INC_FILE]]])
3737
// CHECK: #[[FUSED_LOC_FILE]] = loc(fused<#[[DI_SP]]>[#[[LOC_FILE]]])

flang/test/Transforms/debug-line-table.fir

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,26 @@ module attributes { fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.dat
55
func.func @_QPsb() {
66
return loc(#loc_sb)
77
} loc(#loc_sb)
8+
func.func private @decl() -> i32 loc(#loc_decl)
89
} loc(#loc_module)
910
#loc_module = loc("./simple.f90":1:1)
1011
#loc_sb = loc("./simple.f90":2:1)
12+
#loc_decl = loc("./simple.f90":10:1)
1113

1214
// CHECK: module attributes
1315
// CHECK: func.func @[[SB_NAME:.*]]() {
1416
// CHECK: return loc(#[[SB_LOC:.*]])
1517
// CHECK: } loc(#[[FUSED_SB_LOC:.*]])
18+
// CHECK: func.func private @[[DECL_NAME:.*]]() -> i32 loc(#[[FUSED_DECL_LOC:.*]])
1619
// CHECK: } loc(#[[MODULE_LOC:.*]])
1720
// CHECK: #di_basic_type = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "void", encoding = DW_ATE_address>
1821
// CHECK: #di_file = #llvm.di_file<"[[FILE_NAME:.*]]" in "[[DIR_NAME:.*]]">
1922
// CHECK: #[[MODULE_LOC]] = loc("[[DIR_NAME]]/[[FILE_NAME]]":1:1)
2023
// CHECK: #[[SB_LOC]] = loc("./simple.f90":2:1)
21-
// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
24+
// CHECK: #[[DECL_LOC:.*]] = loc("./simple.f90":10:1)
25+
// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
2226
// CHECK: #di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_basic_type, #di_basic_type>
23-
// CHECK: #di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "[[SB_NAME]]", linkageName = "[[SB_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = Definition, type = #di_subroutine_type>
24-
// CHECK: #[[FUSED_SB_LOC]] = loc(fused<#di_subprogram>[#[[SB_LOC]]])
27+
// CHECK: #[[SB_SUBPROGRAM:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "[[SB_NAME]]", linkageName = "[[SB_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = Definition, type = #di_subroutine_type>
28+
// CHECK: #[[DECL_SUBPROGRAM:.*]] = #llvm.di_subprogram<scope = #di_file, name = "[[DECL_NAME]]", linkageName = "[[DECL_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = Definition, type = #di_subroutine_type>
29+
// CHECK: #[[FUSED_SB_LOC]] = loc(fused<#[[SB_SUBPROGRAM]]>[#[[SB_LOC]]])
30+
// CHECK: #[[FUSED_DECL_LOC]] = loc(fused<#[[DECL_SUBPROGRAM]]>[#[[DECL_LOC]]])

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable",
517517
def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
518518
/*traits=*/[], "DIScopeAttr"> {
519519
let parameters = (ins
520+
OptionalParameter<"DistinctAttr">:$id,
520521
OptionalParameter<"DICompileUnitAttr">:$compileUnit,
521522
"DIScopeAttr":$scope,
522523
OptionalParameter<"StringAttr">:$name,
@@ -529,13 +530,13 @@ def LLVM_DISubprogramAttr : LLVM_Attr<"DISubprogram", "di_subprogram",
529530
);
530531
let builders = [
531532
AttrBuilderWithInferredContext<(ins
532-
"DICompileUnitAttr":$compileUnit, "DIScopeAttr":$scope, "StringRef":$name,
533-
"StringRef":$linkageName, "DIFileAttr":$file, "unsigned":$line,
534-
"unsigned":$scopeLine, "DISubprogramFlags":$subprogramFlags,
535-
"DISubroutineTypeAttr":$type
533+
"DistinctAttr":$id, "DICompileUnitAttr":$compileUnit,
534+
"DIScopeAttr":$scope, "StringRef":$name, "StringRef":$linkageName,
535+
"DIFileAttr":$file, "unsigned":$line, "unsigned":$scopeLine,
536+
"DISubprogramFlags":$subprogramFlags, "DISubroutineTypeAttr":$type
536537
), [{
537538
MLIRContext *ctx = file.getContext();
538-
return $_get(ctx, compileUnit, scope, StringAttr::get(ctx, name),
539+
return $_get(ctx, id, compileUnit, scope, StringAttr::get(ctx, name),
539540
StringAttr::get(ctx, linkageName), file, line,
540541
scopeLine, subprogramFlags, type);
541542
}]>

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,28 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
6666
LLVM::DISubroutineTypeAttr::get(context, llvm::dwarf::DW_CC_normal, {});
6767

6868
StringAttr funcNameAttr = llvmFunc.getNameAttr();
69-
auto subprogramAttr = LLVM::DISubprogramAttr::get(
70-
context, compileUnitAttr, fileAttr, funcNameAttr, funcNameAttr, fileAttr,
71-
/*line=*/line,
72-
/*scopeline=*/col,
73-
LLVM::DISubprogramFlags::Definition | LLVM::DISubprogramFlags::Optimized,
74-
subroutineTypeAttr);
69+
mlir::LLVM::DISubprogramAttr subprogramAttr;
70+
// Only definitions need a distinct identifier and a compilation unit.
71+
if (!llvmFunc.isExternal()) {
72+
auto id = DistinctAttr::create(UnitAttr::get(context));
73+
subprogramAttr =
74+
LLVM::DISubprogramAttr::get(context, id, compileUnitAttr, fileAttr,
75+
funcNameAttr, funcNameAttr, fileAttr,
76+
/*line=*/line,
77+
/*scopeline=*/col,
78+
LLVM::DISubprogramFlags::Definition |
79+
LLVM::DISubprogramFlags::Optimized,
80+
subroutineTypeAttr);
81+
} else {
82+
subprogramAttr = LLVM::DISubprogramAttr::get(
83+
context, DistinctAttr(), LLVM::DICompileUnitAttr(), fileAttr,
84+
funcNameAttr, funcNameAttr, fileAttr,
85+
/*line=*/line,
86+
/*scopeline=*/col,
87+
LLVM::DISubprogramFlags::Definition |
88+
LLVM::DISubprogramFlags::Optimized,
89+
subroutineTypeAttr);
90+
}
7591
llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
7692
}
7793

mlir/lib/Target/LLVMIR/DebugImporter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) {
163163
}
164164

165165
DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
166+
// Only definitions require a distinct identifier.
167+
mlir::DistinctAttr id;
168+
if (node->isDistinct())
169+
id = DistinctAttr::create(UnitAttr::get(context));
166170
std::optional<DISubprogramFlags> subprogramFlags =
167171
symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags());
168172
// Return nullptr if the scope or type is a cyclic dependency.
@@ -172,7 +176,7 @@ DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
172176
DISubroutineTypeAttr type = translate(node->getType());
173177
if (node->getType() && !type)
174178
return nullptr;
175-
return DISubprogramAttr::get(context, translate(node->getUnit()), scope,
179+
return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope,
176180
getStringAttrOrNull(node->getRawName()),
177181
getStringAttrOrNull(node->getRawLinkageName()),
178182
translate(node->getFile()), node->getLine(),

mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// CHECK: llvm.return loc(#loc
55
// CHECK: loc(#loc[[LOC:[0-9]+]])
66
// CHECK: #di_file = #llvm.di_file<"<unknown>" in "">
7-
// CHECK: #di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "func_no_debug", linkageName = "func_no_debug", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
7+
// CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_no_debug", linkageName = "func_no_debug", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
88
// CHECK: #loc[[LOC]] = loc(fused<#di_subprogram>
99
module {
1010
llvm.func @func_no_debug() {
@@ -14,12 +14,22 @@ module {
1414

1515
// -----
1616

17+
// Test that the declarations subprogram is not made distinct.
18+
// CHECK-LABEL: llvm.func @func_decl_no_debug()
19+
// CHECK: #di_subprogram = #llvm.di_subprogram<
20+
// CHECK-NOT: id = distinct
21+
module {
22+
llvm.func @func_decl_no_debug() loc(unknown)
23+
} loc(unknown)
24+
25+
// -----
26+
1727
// Test that existing debug info is not overwritten.
1828
// CHECK-LABEL: llvm.func @func_with_debug()
1929
// CHECK: llvm.return loc(#loc
2030
// CHECK: loc(#loc[[LOC:[0-9]+]])
2131
// CHECK: #di_file = #llvm.di_file<"<unknown>" in "">
22-
// CHECK: #di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "func_with_debug", linkageName = "func_with_debug", file = #di_file, line = 42, scopeLine = 42, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
32+
// CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_with_debug", linkageName = "func_with_debug", file = #di_file, line = 42, scopeLine = 42, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
2333
// CHECK: #loc[[LOC]] = loc(fused<#di_subprogram>
2434
module {
2535
llvm.func @func_with_debug() {
@@ -31,7 +41,7 @@ module {
3141
#loc = loc("foo":0:0)
3242
#loc1 = loc(unknown)
3343
#di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #di_file, producer = "MLIR", isOptimized = true, emissionKind = LineTablesOnly>
34-
#di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "func_with_debug", linkageName = "func_with_debug", file = #di_file, line = 42, scopeLine = 42, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
44+
#di_subprogram = #llvm.di_subprogram<id = distinct[1]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_with_debug", linkageName = "func_with_debug", file = #di_file, line = 42, scopeLine = 42, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
3545
#loc2 = loc(fused<#di_subprogram>[#loc1])
3646

3747
// -----
@@ -44,8 +54,8 @@ module {
4454
// CHECK-DAG: #[[DI_FILE_MODULE:.+]] = #llvm.di_file<"bar.mlir" in "baz">
4555
// CHECK-DAG: #[[DI_FILE_FUNC:.+]] = #llvm.di_file<"file.mlir" in "">
4656
// CHECK-DAG: #loc[[FUNCFILELOC:[0-9]+]] = loc("file.mlir":9:8)
47-
// CHECK-DAG: #di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #[[DI_FILE_MODULE]], producer = "MLIR", isOptimized = true, emissionKind = LineTablesOnly>
48-
// CHECK-DAG: #di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #[[DI_FILE_FUNC]], name = "propagate_compile_unit", linkageName = "propagate_compile_unit", file = #[[DI_FILE_FUNC]], line = 9, scopeLine = 8, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
57+
// CHECK-DAG: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_C, file = #[[DI_FILE_MODULE]], producer = "MLIR", isOptimized = true, emissionKind = LineTablesOnly>
58+
// CHECK-DAG: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #[[DI_FILE_FUNC]], name = "propagate_compile_unit", linkageName = "propagate_compile_unit", file = #[[DI_FILE_FUNC]], line = 9, scopeLine = 8, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
4959
// CHECK-DAG: #loc[[MODULELOC]] = loc(fused<#di_compile_unit>[#loc])
5060
// CHECK-DAG: #loc[[FUNCLOC]] = loc(fused<#di_subprogram>[#loc[[FUNCFILELOC]]
5161
module {

0 commit comments

Comments
 (0)