Skip to content
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
4 changes: 3 additions & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace fir {
#define GEN_PASS_DECL_ALGEBRAICSIMPLIFICATION
#define GEN_PASS_DECL_POLYMORPHICOPCONVERSION
#define GEN_PASS_DECL_OPENACCDATAOPERANDCONVERSION
#define GEN_PASS_DECL_ADDDEBUGINFO
#include "flang/Optimizer/Transforms/Passes.h.inc"

std::unique_ptr<mlir::Pass> createAbstractResultOnFuncOptPass();
Expand All @@ -67,7 +68,8 @@ std::unique_ptr<mlir::Pass> createMemoryAllocationPass();
std::unique_ptr<mlir::Pass> createStackArraysPass();
std::unique_ptr<mlir::Pass> createAliasTagsPass();
std::unique_ptr<mlir::Pass> createSimplifyIntrinsicsPass();
std::unique_ptr<mlir::Pass> createAddDebugInfoPass();
std::unique_ptr<mlir::Pass>
createAddDebugInfoPass(fir::AddDebugInfoOptions options = {});
std::unique_ptr<mlir::Pass> createLoopVersioningPass();

std::unique_ptr<mlir::Pass>
Expand Down
19 changes: 19 additions & 0 deletions flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ def AddDebugInfo : Pass<"add-debug-info", "mlir::ModuleOp"> {
let dependentDialects = [
"fir::FIROpsDialect", "mlir::func::FuncDialect", "mlir::LLVM::LLVMDialect"
];
let options = [
Option<"debugLevel", "debug-level",
"mlir::LLVM::DIEmissionKind",
/*default=*/"mlir::LLVM::DIEmissionKind::Full",
"debug level",
[{::llvm::cl::values(
clEnumValN(mlir::LLVM::DIEmissionKind::Full, "Full", "Emit full debug info"),
clEnumValN(mlir::LLVM::DIEmissionKind::LineTablesOnly, "LineTablesOnly", "Emit line tables only"),
clEnumValN(mlir::LLVM::DIEmissionKind::None, "None", "Emit no debug information")
)}]
>,
Option<"isOptimized", "is-optimized",
"bool", /*default=*/"false",
"is optimized.">,
Option<"inputFilename", "file-name",
"std::string",
/*default=*/"std::string{}",
"name of the input source file">,
];
}

// This needs to be a "mlir::ModuleOp" pass, because it inserts simplified
Expand Down
58 changes: 33 additions & 25 deletions flang/include/flang/Tools/CLOptions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,27 @@ inline void addTargetRewritePass(mlir::PassManager &pm) {
});
}

inline void addDebugInfoPass(mlir::PassManager &pm) {
addPassConditionally(
pm, disableDebugInfo, [&]() { return fir::createAddDebugInfoPass(); });
inline mlir::LLVM::DIEmissionKind getEmissionKind(
llvm::codegenoptions::DebugInfoKind kind) {
switch (kind) {
case llvm::codegenoptions::DebugInfoKind::FullDebugInfo:
return mlir::LLVM::DIEmissionKind::Full;
case llvm::codegenoptions::DebugInfoKind::DebugLineTablesOnly:
return mlir::LLVM::DIEmissionKind::LineTablesOnly;
default:
return mlir::LLVM::DIEmissionKind::None;
}
}

inline void addDebugInfoPass(mlir::PassManager &pm,
llvm::codegenoptions::DebugInfoKind debugLevel,
llvm::OptimizationLevel optLevel, llvm::StringRef inputFilename) {
fir::AddDebugInfoOptions options;
options.debugLevel = getEmissionKind(debugLevel);
options.isOptimized = optLevel != llvm::OptimizationLevel::O0;
options.inputFilename = inputFilename;
addPassConditionally(pm, disableDebugInfo,
[&]() { return fir::createAddDebugInfoPass(options); });
}

inline void addFIRToLLVMPass(
Expand Down Expand Up @@ -283,34 +301,23 @@ inline void createOpenMPFIRPassPipeline(
}

#if !defined(FLANG_EXCLUDE_CODEGEN)
inline void createDebugPasses(
mlir::PassManager &pm, llvm::codegenoptions::DebugInfoKind debugLevel) {
// Currently only -g1, -g, -gline-tables-only supported
switch (debugLevel) {
case llvm::codegenoptions::DebugLineTablesOnly:
addDebugInfoPass(pm);
return;
case llvm::codegenoptions::NoDebugInfo:
return;
default:
// TODO: Add cases and passes for other debug options.
// All other debug options not implemented yet, currently emits warning
// and generates as much debug information as possible.
addDebugInfoPass(pm);
return;
}
inline void createDebugPasses(mlir::PassManager &pm,
llvm::codegenoptions::DebugInfoKind debugLevel,
llvm::OptimizationLevel OptLevel, llvm::StringRef inputFilename) {
if (debugLevel != llvm::codegenoptions::NoDebugInfo)
addDebugInfoPass(pm, debugLevel, OptLevel, inputFilename);
}

inline void createDefaultFIRCodeGenPassPipeline(
mlir::PassManager &pm, MLIRToLLVMPassPipelineConfig config) {
inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
MLIRToLLVMPassPipelineConfig config, llvm::StringRef inputFilename = {}) {
fir::addBoxedProcedurePass(pm);
pm.addNestedPass<mlir::func::FuncOp>(
fir::createAbstractResultOnFuncOptPass());
pm.addNestedPass<fir::GlobalOp>(fir::createAbstractResultOnGlobalOptPass());
fir::addCodeGenRewritePass(pm);
fir::addTargetRewritePass(pm);
fir::addExternalNameConversionPass(pm, config.Underscoring);
fir::createDebugPasses(pm, config.DebugInfo);
fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);

if (config.VScaleMin != 0)
pm.addPass(fir::createVScaleAttrPass({config.VScaleMin, config.VScaleMax}));
Expand Down Expand Up @@ -344,15 +351,16 @@ inline void createDefaultFIRCodeGenPassPipeline(
/// \param pm - MLIR pass manager that will hold the pipeline definition
/// \param optLevel - optimization level used for creating FIR optimization
/// passes pipeline
inline void createMLIRToLLVMPassPipeline(
mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm,
const MLIRToLLVMPassPipelineConfig &config,
llvm::StringRef inputFilename = {}) {
fir::createHLFIRToFIRPassPipeline(pm, config.OptLevel);

// Add default optimizer pass pipeline.
fir::createDefaultFIROptimizerPassPipeline(pm, config);

// Add codegen pass pipeline.
fir::createDefaultFIRCodeGenPassPipeline(pm, config);
fir::createDefaultFIRCodeGenPassPipeline(pm, config, inputFilename);
}
#undef FLANG_EXCLUDE_CODEGEN
#endif
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ void CodeGenAction::generateLLVMIR() {
}

// Create the pass pipeline
fir::createMLIRToLLVMPassPipeline(pm, config);
fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
(void)mlir::applyPassManagerCLOptions(pm);

// run the pass manager
Expand Down
84 changes: 56 additions & 28 deletions flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
/// This pass populates some debug information for the module and functions.
//===----------------------------------------------------------------------===//

#include "flang/Common/Version.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Transforms/Passes.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
Expand All @@ -28,12 +30,12 @@
#include "mlir/Transforms/RegionUtils.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

namespace fir {
#define GEN_PASS_DEF_ADDDEBUGINFO
#define GEN_PASS_DECL_ADDDEBUGINFO
#include "flang/Optimizer/Transforms/Passes.h.inc"
} // namespace fir

Expand All @@ -43,6 +45,7 @@ namespace {

class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
public:
AddDebugInfoPass(fir::AddDebugInfoOptions options) : Base(options) {}
void runOnOperation() override;
};

Expand All @@ -52,21 +55,40 @@ void AddDebugInfoPass::runOnOperation() {
mlir::ModuleOp module = getOperation();
mlir::MLIRContext *context = &getContext();
mlir::OpBuilder builder(context);
std::string inputFilePath("-");
if (auto fileLoc = module.getLoc().dyn_cast<mlir::FileLineColLoc>())
inputFilePath = fileLoc.getFilename().getValue();
llvm::StringRef fileName;
std::string filePath;
Comment on lines +58 to +59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does DWARF support paths with wide characters?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

DWARF has DW_AT_use_UTF8 attribute which can be used to say that program entities and filenames use UTF-8 representation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see that some of the functions in llvm::sys::fs represent paths as Twines so I guess a std::string should be good enough for now. Off the top of my head, I can't think of a reason why a std::string can't store a UTF8 string (::size() might be confusing, but that shouldn't matter here).

// We need 2 type of file paths here.
// 1. Name of the file as was presented to compiler. This can be absolute
// or relative to 2.
// 2. Current working directory
//
// We are also dealing with 2 different situations below. One is normal
// compilation where we will have a value in 'inputFilename' and we can
// obtain the current directory using 'current_path'.
// The 2nd case is when this pass is invoked directly from 'fir-opt' tool.
// In that case, 'inputFilename' may be empty. Location embedded in the
// module will be used to get file name and its directory.
Comment on lines +65 to +70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not always using the module location since it must have been provided?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In ideal case, we would like it to be the current working directory as I explained above. But we don't have that information in 2nd case so using parent directory is sort of a compromise.

if (inputFilename.empty()) {
if (auto fileLoc = module.getLoc().dyn_cast<mlir::FileLineColLoc>()) {
fileName = llvm::sys::path::filename(fileLoc.getFilename().getValue());
filePath = llvm::sys::path::parent_path(fileLoc.getFilename().getValue());
} else
fileName = "-";
} else {
fileName = inputFilename;
llvm::SmallString<256> cwd;
if (!llvm::sys::fs::current_path(cwd))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isn't current_path the working directory where the compiler is being run? If so, that could be different from the file directory.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As I explained in my earlier comment, DWARF requires working directory.

filePath = cwd.str();
}

auto getFileAttr = [context](llvm::StringRef path) -> mlir::LLVM::DIFileAttr {
return mlir::LLVM::DIFileAttr::get(context, llvm::sys::path::filename(path),
llvm::sys::path::parent_path(path));
};

mlir::LLVM::DIFileAttr fileAttr = getFileAttr(inputFilePath);
mlir::StringAttr producer = mlir::StringAttr::get(context, "Flang");
mlir::LLVM::DIFileAttr fileAttr =
mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
mlir::StringAttr producer =
mlir::StringAttr::get(context, Fortran::common::getFlangFullVersion());
mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get(
mlir::DistinctAttr::create(mlir::UnitAttr::get(context)),
llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, producer,
/*isOptimized=*/false, mlir::LLVM::DIEmissionKind::LineTablesOnly);
isOptimized, debugLevel);

module.walk([&](mlir::func::FuncOp funcOp) {
mlir::Location l = funcOp->getLoc();
Expand All @@ -75,43 +97,49 @@ void AddDebugInfoPass::runOnOperation() {
if (l.dyn_cast<mlir::FusedLoc>())
return;

llvm::StringRef funcFilePath;
if (l.dyn_cast<mlir::FileLineColLoc>())
funcFilePath =
l.dyn_cast<mlir::FileLineColLoc>().getFilename().getValue();
else
funcFilePath = inputFilePath;
unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
? llvm::dwarf::getCallingConvention("DW_CC_program")
: llvm::dwarf::getCallingConvention("DW_CC_normal");

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

mlir::StringAttr funcName =
mlir::StringAttr::get(context, funcOp.getName());
mlir::LLVM::DIBasicTypeAttr bT = mlir::LLVM::DIBasicTypeAttr::get(
context, llvm::dwarf::DW_TAG_base_type, "void", /*sizeInBits=*/0,
/*encoding=*/1);
// FIXME: Provide proper type for subroutine
mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
mlir::LLVM::DISubroutineTypeAttr::get(
context, llvm::dwarf::getCallingConvention("DW_CC_normal"),
{bT, bT});
mlir::LLVM::DIFileAttr funcFileAttr = getFileAttr(funcFilePath);
mlir::LLVM::DISubroutineTypeAttr::get(context, CC, {bT, bT});
Comment thread
abidh marked this conversation as resolved.
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::DICompileUnitAttr compilationUnit;
auto subprogramFlags = mlir::LLVM::DISubprogramFlags::Optimized;
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;
}
// FIXME: Provide proper line and scopeline.
auto spAttr = mlir::LLVM::DISubprogramAttr::get(
context, id, compilationUnit, fileAttr, funcName, funcName,
funcFileAttr,
/*line=*/1,
/*scopeline=*/1, subprogramFlags, subTypeAttr);
funcFileAttr, /*line=*/1, /*scopeline=*/1, subprogramFlags,
Comment thread
abidh marked this conversation as resolved.
subTypeAttr);
funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr));
});
}

std::unique_ptr<mlir::Pass> fir::createAddDebugInfoPass() {
return std::make_unique<AddDebugInfoPass>();
std::unique_ptr<mlir::Pass>
fir::createAddDebugInfoPass(fir::AddDebugInfoOptions options) {
return std::make_unique<AddDebugInfoPass>(options);
}
1 change: 1 addition & 0 deletions flang/lib/Optimizer/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_flang_library(FIRTransforms
FIRDialect
FIRDialectSupport
FIRSupport
FortranCommon
HLFIRDialect
MLIRAffineUtils
MLIRFuncDialect
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Transforms/debug-line-table-inc-file.fir
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
// RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s
// REQUIRES: system-linux

// Test for included functions that have a different debug location than the current file
Expand Down Expand Up @@ -30,7 +30,7 @@ module attributes {} {
// CHECK: #[[MODULE_LOC]] = loc("{{.*}}simple.f90":0:0)
// CHECK: #[[LOC_INC_FILE:.*]] = loc("{{.*}}inc.f90":1:1)
// CHECK: #[[LOC_FILE:.*]] = loc("{{.*}}simple.f90":3:1)
// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
// CHECK: #[[DI_CU:.*]] = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #[[DI_FILE]], producer = "flang{{.*}}", isOptimized = false, emissionKind = LineTablesOnly>
// CHECK: #[[DI_SP_INC:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QPsinc", linkageName = "_QPsinc", file = #[[DI_INC_FILE]], {{.*}}>
// CHECK: #[[DI_SP:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #[[DI_CU]], scope = #[[DI_FILE]], name = "_QQmain", linkageName = "_QQmain", file = #[[DI_FILE]], {{.*}}>
// CHECK: #[[FUSED_LOC_INC_FILE]] = loc(fused<#[[DI_SP_INC]]>[#[[LOC_INC_FILE]]])
Expand Down
8 changes: 6 additions & 2 deletions flang/test/Transforms/debug-line-table.fir
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
// RUN: fir-opt --add-debug-info="debug-level=Full" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=FULL
// RUN: fir-opt --add-debug-info="debug-level=LineTablesOnly" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=LINETABLE
// RUN: fir-opt --add-debug-info="is-optimized=true" --mlir-print-debuginfo %s | FileCheck %s --check-prefix=OPT

module attributes { fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", llvm.target_triple = "aarch64-unknown-linux-gnu"} {
func.func @_QPsb() {
Expand All @@ -22,7 +24,9 @@ module attributes { fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.dat
// CHECK: #[[MODULE_LOC]] = loc("[[DIR_NAME]]/[[FILE_NAME]]":1:1)
// CHECK: #[[SB_LOC]] = loc("./simple.f90":2:1)
// CHECK: #[[DECL_LOC:.*]] = loc("./simple.f90":10:1)
// CHECK: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "Flang", isOptimized = false, emissionKind = LineTablesOnly>
// FULL: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang{{.*}}", isOptimized = false, emissionKind = Full>
// OPT: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang{{.*}}", isOptimized = true, emissionKind = Full>
// LINETABLE: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_Fortran95, file = #di_file, producer = "flang{{.*}}", isOptimized = false, emissionKind = LineTablesOnly>
// CHECK: #di_subroutine_type = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, types = #di_basic_type, #di_basic_type>
// 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|Optimized", type = #di_subroutine_type>
// CHECK: #[[DECL_SUBPROGRAM:.*]] = #llvm.di_subprogram<scope = #di_file, name = "[[DECL_NAME]]", linkageName = "[[DECL_NAME]]", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = Optimized, type = #di_subroutine_type>
Expand Down