Skip to content
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

[flang][debug] Set scope of internal functions correctly. #99531

Merged
merged 3 commits into from
Jul 25, 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
181 changes: 106 additions & 75 deletions flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
void handleGlobalOp(fir::GlobalOp glocalOp, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DIScopeAttr scope,
mlir::SymbolTable *symbolTable);
void handleFuncOp(mlir::func::FuncOp funcOp, mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DICompileUnitAttr cuAttr,
mlir::SymbolTable *symbolTable);
};

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

void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
mlir::LLVM::DIFileAttr fileAttr,
mlir::LLVM::DICompileUnitAttr cuAttr,
mlir::SymbolTable *symbolTable) {
mlir::Location l = funcOp->getLoc();
// If fused location has already been created then nothing to do
// Otherwise, create a fused location.
if (debugInfoIsAlreadySet(l))
return;

mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
llvm::StringRef fileName(fileAttr.getName());
llvm::StringRef filePath(fileAttr.getDirectory());
unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
? llvm::dwarf::getCallingConvention("DW_CC_program")
: llvm::dwarf::getCallingConvention("DW_CC_normal");

if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
}

mlir::StringAttr fullName = mlir::StringAttr::get(context, funcOp.getName());
mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
mlir::StringAttr funcName =
(attr) ? mlir::cast<mlir::StringAttr>(attr)
: mlir::StringAttr::get(context, funcOp.getName());

auto result = fir::NameUniquer::deconstruct(funcName);
funcName = mlir::StringAttr::get(context, result.second.name);

llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
fir::DebugTypeGenerator typeGen(module);
for (auto resTy : funcOp.getResultTypes()) {
auto tyAttr = typeGen.convertType(resTy, fileAttr, cuAttr, funcOp.getLoc());
types.push_back(tyAttr);
}
for (auto inTy : funcOp.getArgumentTypes()) {
auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr,
cuAttr, funcOp.getLoc());
types.push_back(tyAttr);
}

mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
mlir::LLVM::DIFileAttr funcFileAttr =
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);

// Only definitions need a distinct identifier and a compilation unit.
mlir::DistinctAttr id;
mlir::LLVM::DIScopeAttr Scope = fileAttr;
mlir::LLVM::DICompileUnitAttr compilationUnit;
mlir::LLVM::DISubprogramFlags subprogramFlags =
mlir::LLVM::DISubprogramFlags{};
if (isOptimized)
subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
if (!funcOp.isExternal()) {
id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
compilationUnit = cuAttr;
subprogramFlags =
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
}
unsigned line = getLineFromLoc(l);
if (fir::isInternalProcedure(funcOp)) {
// For contained functions, the scope is the parent subroutine.
mlir::SymbolRefAttr sym = mlir::cast<mlir::SymbolRefAttr>(
funcOp->getAttr(fir::getHostSymbolAttrName()));
if (sym) {
if (auto func =
symbolTable->lookup<mlir::func::FuncOp>(sym.getLeafReference())) {
// Make sure that parent is processed.
handleFuncOp(func, fileAttr, cuAttr, symbolTable);
if (auto fusedLoc =
mlir::dyn_cast_if_present<mlir::FusedLoc>(func.getLoc())) {
if (auto spAttr =
mlir::dyn_cast_if_present<mlir::LLVM::DISubprogramAttr>(
fusedLoc.getMetadata()))
Scope = spAttr;
}
}
}
} else if (!result.second.modules.empty()) {
Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
line - 1, false);
}

auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
line, line, subprogramFlags, subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));

// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
return;

funcOp.walk([&](fir::cg::XDeclareOp declOp) {
handleDeclareOp(declOp, fileAttr, spAttr, typeGen, symbolTable);
});
}

void AddDebugInfoPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
mlir::SymbolTable symbolTable(module);
mlir::OpBuilder builder(context);
llvm::StringRef fileName;
std::string filePath;
// We need 2 type of file paths here.
Expand Down Expand Up @@ -248,80 +352,7 @@ void AddDebugInfoPass::runOnOperation() {
isOptimized, debugLevel);

module.walk([&](mlir::func::FuncOp funcOp) {
mlir::Location l = funcOp->getLoc();
// If fused location has already been created then nothing to do
// Otherwise, create a fused location.
if (debugInfoIsAlreadySet(l))
return;

unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
? llvm::dwarf::getCallingConvention("DW_CC_program")
: llvm::dwarf::getCallingConvention("DW_CC_normal");

if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
}

mlir::StringAttr fullName =
mlir::StringAttr::get(context, funcOp.getName());
mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
mlir::StringAttr funcName =
(attr) ? mlir::cast<mlir::StringAttr>(attr)
: mlir::StringAttr::get(context, funcOp.getName());

auto result = fir::NameUniquer::deconstruct(funcName);
funcName = mlir::StringAttr::get(context, result.second.name);

llvm::SmallVector<mlir::LLVM::DITypeAttr> types;
fir::DebugTypeGenerator typeGen(module);
for (auto resTy : funcOp.getResultTypes()) {
auto tyAttr =
typeGen.convertType(resTy, fileAttr, cuAttr, funcOp.getLoc());
types.push_back(tyAttr);
}
for (auto inTy : funcOp.getArgumentTypes()) {
auto tyAttr = typeGen.convertType(fir::unwrapRefType(inTy), fileAttr,
cuAttr, funcOp.getLoc());
types.push_back(tyAttr);
}

mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
mlir::LLVM::DIFileAttr funcFileAttr =
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);

// Only definitions need a distinct identifier and a compilation unit.
mlir::DistinctAttr id;
mlir::LLVM::DIScopeAttr Scope = fileAttr;
mlir::LLVM::DICompileUnitAttr compilationUnit;
mlir::LLVM::DISubprogramFlags subprogramFlags =
mlir::LLVM::DISubprogramFlags{};
if (isOptimized)
subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
if (!funcOp.isExternal()) {
id = mlir::DistinctAttr::create(mlir::UnitAttr::get(context));
compilationUnit = cuAttr;
subprogramFlags =
subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
}
unsigned line = getLineFromLoc(l);
if (!result.second.modules.empty())
Scope = getOrCreateModuleAttr(result.second.modules[0], fileAttr, cuAttr,
line - 1, false);

auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, Scope, funcName, fullName, funcFileAttr,
line, line, subprogramFlags, subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));

// Don't process variables if user asked for line tables only.
if (debugLevel == mlir::LLVM::DIEmissionKind::LineTablesOnly)
return;

funcOp.walk([&](fir::cg::XDeclareOp declOp) {
handleDeclareOp(declOp, fileAttr, spAttr, typeGen, &symbolTable);
});
handleFuncOp(funcOp, fileAttr, cuAttr, &symbolTable);
});
// Process any global which was not processed through DeclareOp.
if (debugLevel == mlir::LLVM::DIEmissionKind::Full) {
Expand Down
26 changes: 26 additions & 0 deletions flang/test/Transforms/debug-96314.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s -o - | FileCheck %s

module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
func.func @_QMhelperPmod_sub(%arg0: !fir.ref<i32> {fir.bindc_name = "a"} ) {
return
} loc(#loc1)
func.func private @_QMhelperFmod_subPchild1(%arg0: !fir.ref<i32> {fir.bindc_name = "b"} ) attributes {fir.host_symbol = @_QMhelperPmod_sub, llvm.linkage = #llvm.linkage<internal>} {
return
} loc(#loc2)
func.func @global_sub_(%arg0: !fir.ref<i32> {fir.bindc_name = "n"} ) attributes {fir.internal_name = "_QPglobal_sub"} {
return
} loc(#loc3)
func.func private @_QFglobal_subPchild2(%arg0: !fir.ref<i32> {fir.bindc_name = "c"}) attributes {fir.host_symbol = @global_sub_, llvm.linkage = #llvm.linkage<internal>} {
return
} loc(#loc4)
}

#loc1 = loc("test.f90":5:1)
#loc2 = loc("test.f90":15:1)
#loc3 = loc("test.f90":25:1)
#loc4 = loc("test.f90":35:1)

// CHECK-DAG: #[[SP1:.*]] = #llvm.di_subprogram<{{.*}}name = "mod_sub"{{.*}}>
// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP1]], name = "child1"{{.*}}>
// CHECK-DAG: #[[SP2:.*]] = #llvm.di_subprogram<{{.*}}linkageName = "global_sub_"{{.*}}>
// CHECK-DAG: #llvm.di_subprogram<{{.*}}scope = #[[SP2]], name = "child2"{{.*}}>
Loading