Skip to content

Commit bf76290

Browse files
authored
[flang][debug] Set scope of internal functions correctly. (#99531)
The functions internal to subroutine should have the scope set to the parent function. This allows a user to evaluate local variables of parent function when control is stopped in the child. Fixes #96314
1 parent af1d2b9 commit bf76290

File tree

2 files changed

+132
-75
lines changed

2 files changed

+132
-75
lines changed

flang/lib/Optimizer/Transforms/AddDebugInfo.cpp

+106-75
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
6666
void handleGlobalOp(fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr,
6767
mlir::LLVM::DIScopeAttr scope,
6868
mlir::SymbolTable *symbolTable);
69+
void handleFuncOp(mlir::func::FuncOp funcOp, mlir::LLVM::DIFileAttr fileAttr,
70+
mlir::LLVM::DICompileUnitAttr cuAttr,
71+
mlir::SymbolTable *symbolTable);
6972
};
7073

7174
static uint32_t getLineFromLoc(mlir::Location loc) {
@@ -207,11 +210,112 @@ void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
207210
globalOp->setLoc(builder.getFusedLoc({globalOp->getLoc()}, gvAttr));
208211
}
209212

213+
void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
214+
mlir::LLVM::DIFileAttr fileAttr,
215+
mlir::LLVM::DICompileUnitAttr cuAttr,
216+
mlir::SymbolTable *symbolTable) {
217+
mlir::Location l = funcOp->getLoc();
218+
// If fused location has already been created then nothing to do
219+
// Otherwise, create a fused location.
220+
if (debugInfoIsAlreadySet(l))
221+
return;
222+
223+
mlir::ModuleOp module = getOperation();
224+
mlir::MLIRContext *context = &getContext();
225+
mlir::OpBuilder builder(context);
226+
llvm::StringRef fileName(fileAttr.getName());
227+
llvm::StringRef filePath(fileAttr.getDirectory());
228+
unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
229+
? llvm::dwarf::getCallingConvention("DW_CC_program")
230+
: llvm::dwarf::getCallingConvention("DW_CC_normal");
231+
232+
if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
233+
fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
234+
filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
235+
}
236+
237+
mlir::StringAttr fullName = mlir::StringAttr::get(context, funcOp.getName());
238+
mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
239+
mlir::StringAttr funcName =
240+
(attr) ? mlir::cast<mlir::StringAttr>(attr)
241+
: mlir::StringAttr::get(context, funcOp.getName());
242+
243+
auto result = fir::NameUniquer::deconstruct(funcName);
244+
funcName = mlir::StringAttr::get(context, result.second.name);
245+
246+
llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
247+
fir::DebugTypeGenerator typeGen(module);
248+
for (auto resTy : funcOp.getResultTypes()) {
249+
auto tyAttr = typeGen.convertType(resTy, fileAttr, cuAttr, funcOp.getLoc());
250+
types.push_back(tyAttr);
251+
}
252+
for (auto inTy : funcOp.getArgumentTypes()) {
253+
auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr,
254+
cuAttr, funcOp.getLoc());
255+
types.push_back(tyAttr);
256+
}
257+
258+
mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
259+
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
260+
mlir::LLVM::DIFileAttr funcFileAttr =
261+
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
262+
263+
// Only definitions need a distinct identifier and a compilation unit.
264+
mlir::DistinctAttr id;
265+
mlir::LLVM::DIScopeAttr Scope = fileAttr;
266+
mlir::LLVM::DICompileUnitAttr compilationUnit;
267+
mlir::LLVM::DISubprogramFlags subprogramFlags =
268+
mlir::LLVM::DISubprogramFlags{};
269+
if (isOptimized)
270+
subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
271+
if (!funcOp.isExternal()) {
272+
id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
273+
compilationUnit = cuAttr;
274+
subprogramFlags =
275+
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
276+
}
277+
unsigned line = getLineFromLoc(l);
278+
if (fir::isInternalProcedure(funcOp)) {
279+
// For contained functions, the scope is the parent subroutine.
280+
mlir::SymbolRefAttr sym = mlir::cast<mlir::SymbolRefAttr>(
281+
funcOp->getAttr(fir::getHostSymbolAttrName()));
282+
if (sym) {
283+
if (auto func =
284+
symbolTable->lookup<mlir::func::FuncOp>(sym.getLeafReference())) {
285+
// Make sure that parent is processed.
286+
handleFuncOp(func, fileAttr, cuAttr, symbolTable);
287+
if (auto fusedLoc =
288+
mlir::dyn_cast_if_present<mlir::FusedLoc>(func.getLoc())) {
289+
if (auto spAttr =
290+
mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(
291+
fusedLoc.getMetadata()))
292+
Scope = spAttr;
293+
}
294+
}
295+
}
296+
} else if (!result.second.modules.empty()) {
297+
Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
298+
line - 1, false);
299+
}
300+
301+
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
302+
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
303+
line, line, subprogramFlags, subTypeAttr);
304+
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
305+
306+
// Don't process variables if user asked for line tables only.
307+
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
308+
return;
309+
310+
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
311+
handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable);
312+
});
313+
}
314+
210315
void AddDebugInfoPass::runOnOperation() {
211316
mlir::ModuleOp module = getOperation();
212317
mlir::MLIRContext *context = &getContext();
213318
mlir::SymbolTable symbolTable(module);
214-
mlir::OpBuilder builder(context);
215319
llvm::StringRef fileName;
216320
std::string filePath;
217321
// We need 2 type of file paths here.
@@ -248,80 +352,7 @@ void AddDebugInfoPass::runOnOperation() {
248352
isOptimized, debugLevel);
249353

250354
module.walk([&](mlir::func::FuncOp funcOp) {
251-
mlir::Location l = funcOp->getLoc();
252-
// If fused location has already been created then nothing to do
253-
// Otherwise, create a fused location.
254-
if (debugInfoIsAlreadySet(l))
255-
return;
256-
257-
unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
258-
? llvm::dwarf::getCallingConvention("DW_CC_program")
259-
: llvm::dwarf::getCallingConvention("DW_CC_normal");
260-
261-
if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
262-
fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
263-
filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
264-
}
265-
266-
mlir::StringAttr fullName =
267-
mlir::StringAttr::get(context, funcOp.getName());
268-
mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
269-
mlir::StringAttr funcName =
270-
(attr) ? mlir::cast<mlir::StringAttr>(attr)
271-
: mlir::StringAttr::get(context, funcOp.getName());
272-
273-
auto result = fir::NameUniquer::deconstruct(funcName);
274-
funcName = mlir::StringAttr::get(context, result.second.name);
275-
276-
llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
277-
fir::DebugTypeGenerator typeGen(module);
278-
for (auto resTy : funcOp.getResultTypes()) {
279-
auto tyAttr =
280-
typeGen.convertType(resTy, fileAttr, cuAttr, funcOp.getLoc());
281-
types.push_back(tyAttr);
282-
}
283-
for (auto inTy : funcOp.getArgumentTypes()) {
284-
auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr,
285-
cuAttr, funcOp.getLoc());
286-
types.push_back(tyAttr);
287-
}
288-
289-
mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
290-
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
291-
mlir::LLVM::DIFileAttr funcFileAttr =
292-
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
293-
294-
// Only definitions need a distinct identifier and a compilation unit.
295-
mlir::DistinctAttr id;
296-
mlir::LLVM::DIScopeAttr Scope = fileAttr;
297-
mlir::LLVM::DICompileUnitAttr compilationUnit;
298-
mlir::LLVM::DISubprogramFlags subprogramFlags =
299-
mlir::LLVM::DISubprogramFlags{};
300-
if (isOptimized)
301-
subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
302-
if (!funcOp.isExternal()) {
303-
id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
304-
compilationUnit = cuAttr;
305-
subprogramFlags =
306-
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
307-
}
308-
unsigned line = getLineFromLoc(l);
309-
if (!result.second.modules.empty())
310-
Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
311-
line - 1, false);
312-
313-
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
314-
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
315-
line, line, subprogramFlags, subTypeAttr);
316-
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
317-
318-
// Don't process variables if user asked for line tables only.
319-
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
320-
return;
321-
322-
funcOp.walk([&](fir::cg::XDeclareOp declOp) {
323-
handleDeclareOp(declOp, fileAttr, spAttr, typeGen, &symbolTable);
324-
});
355+
handleFuncOp(funcOp, fileAttr, cuAttr, &symbolTable);
325356
});
326357
// Process any global which was not processed through DeclareOp.
327358
if (debugLevel == mlir::LLVM::DIEmissionKind::Full) {

flang/test/Transforms/debug-96314.fir

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s -o - | FileCheck %s
2+
3+
module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
4+
func.func @_QMhelperPmod_sub(%arg0: !fir.ref<i32> {fir.bindc_name = "a"} ) {
5+
return
6+
} loc(#loc1)
7+
func.func private @_QMhelperFmod_subPchild1(%arg0: !fir.ref<i32> {fir.bindc_name = "b"} ) attributes {fir.host_symbol = @_QMhelperPmod_sub, llvm.linkage = #llvm.linkage<internal>} {
8+
return
9+
} loc(#loc2)
10+
func.func @global_sub_(%arg0: !fir.ref<i32> {fir.bindc_name = "n"} ) attributes {fir.internal_name = "_QPglobal_sub"} {
11+
return
12+
} loc(#loc3)
13+
func.func private @_QFglobal_subPchild2(%arg0: !fir.ref<i32> {fir.bindc_name = "c"}) attributes {fir.host_symbol = @global_sub_, llvm.linkage = #llvm.linkage<internal>} {
14+
return
15+
} loc(#loc4)
16+
}
17+
18+
#loc1 = loc("test.f90":5:1)
19+
#loc2 = loc("test.f90":15:1)
20+
#loc3 = loc("test.f90":25:1)
21+
#loc4 = loc("test.f90":35:1)
22+
23+
// CHECK-DAG: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "mod_sub"{{.*}}>
24+
// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP1]], name = "child1"{{.*}}>
25+
// CHECK-DAG: #[[SP2:.*]] = #llvm.di_subprogram<{{.*}}linkageName = "global_sub_"{{.*}}>
26+
// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP2]], name = "child2"{{.*}}>

0 commit comments

Comments
 (0)