From bff766437c512eac6ae53d889297b99df3160c02 Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Mon, 15 Sep 2025 14:46:00 +0100 Subject: [PATCH 1/2] [flang] Lowering support for -gdwarf-N flag. This PR builds on the https://github.com/llvm/llvm-project/pull/158314 and adds the lowering support for -gdwarf-N flag. The changes to pass the information to AddDebugInfo pass are mostly mechanical. The AddDebugInfo pass adds ModuleFlagsOp in the module. This gets translated to correct llvm metadata during mlir->llvmir translation. There is minor correction where the version is set to 0 in case no -debug-version flag is provided. Previously it was set to 2 in this case due to misreading of clang code. --- .../flang/Optimizer/Passes/Pipelines.h | 4 ++-- .../flang/Optimizer/Transforms/Passes.td | 4 ++++ flang/include/flang/Tools/CrossToolHelpers.h | 2 ++ flang/lib/Frontend/CompilerInvocation.cpp | 3 +-- flang/lib/Optimizer/Passes/Pipelines.cpp | 10 ++++---- .../lib/Optimizer/Transforms/AddDebugInfo.cpp | 14 ++++++++++- flang/test/Integration/debug-dwarf-flags.f90 | 24 +++++++++++++++++++ flang/test/Transforms/debug-dwarf-version.fir | 22 +++++++++++++++++ 8 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 flang/test/Integration/debug-dwarf-flags.f90 create mode 100644 flang/test/Transforms/debug-dwarf-version.fir diff --git a/flang/include/flang/Optimizer/Passes/Pipelines.h b/flang/include/flang/Optimizer/Passes/Pipelines.h index fd8c43cc88a19..f9c41b382abe5 100644 --- a/flang/include/flang/Optimizer/Passes/Pipelines.h +++ b/flang/include/flang/Optimizer/Passes/Pipelines.h @@ -102,7 +102,7 @@ void addCompilerGeneratedNamesConversionPass(mlir::PassManager &pm); void addDebugInfoPass(mlir::PassManager &pm, llvm::codegenoptions::DebugInfoKind debugLevel, llvm::OptimizationLevel optLevel, - llvm::StringRef inputFilename); + llvm::StringRef inputFilename, int32_t dwarfVersion); void addFIRToLLVMPass(mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config); @@ -158,7 +158,7 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm, void createDebugPasses(mlir::PassManager &pm, llvm::codegenoptions::DebugInfoKind debugLevel, llvm::OptimizationLevel OptLevel, - llvm::StringRef inputFilename); + llvm::StringRef inputFilename, int32_t dwarfVersion); void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, MLIRToLLVMPassPipelineConfig config, diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index e3001454cdf19..b7fa0ca5f5719 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -242,6 +242,10 @@ def AddDebugInfo : Pass<"add-debug-info", "mlir::ModuleOp"> { "std::string", /*default=*/"std::string{}", "name of the input source file">, + Option<"dwarfVersion", "dwarf-version", + "int32_t", + /*default=*/"0", + "dwarf version">, ]; } diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index 335f0a45531c8..038f388f2ec0b 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -108,6 +108,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { InstrumentFunctionEntry = "__cyg_profile_func_enter"; InstrumentFunctionExit = "__cyg_profile_func_exit"; } + DwarfVersion = opts.DwarfVersion; } llvm::OptimizationLevel OptLevel; ///< optimisation level @@ -143,6 +144,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks { Fortran::frontend::CodeGenOptions::ComplexRangeKind ComplexRange = Fortran::frontend::CodeGenOptions::ComplexRangeKind:: CX_Full; ///< Method for calculating complex number division + int32_t DwarfVersion = 0; ///< Version of DWARF debug info to generate }; struct OffloadModuleOpts { diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index a00e568bb4a54..4729f8a7611a2 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -157,10 +157,9 @@ static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts, clang::DiagnosticsEngine::Warning, "Unsupported debug option: %0"); diags.Report(debugWarning) << arg->getValue(); } - // The default value of 2 here is to match clang. opts.DwarfVersion = getLastArgIntValue(args, clang::driver::options::OPT_dwarf_version_EQ, - /*Default=*/2, diags); + /*Default=*/0, diags); } return true; } diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 7c2777baebef1..58f60d43b1d49 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -95,11 +95,12 @@ getEmissionKind(llvm::codegenoptions::DebugInfoKind kind) { void addDebugInfoPass(mlir::PassManager &pm, llvm::codegenoptions::DebugInfoKind debugLevel, llvm::OptimizationLevel optLevel, - llvm::StringRef inputFilename) { + llvm::StringRef inputFilename, int32_t dwarfVersion) { fir::AddDebugInfoOptions options; options.debugLevel = getEmissionKind(debugLevel); options.isOptimized = optLevel != llvm::OptimizationLevel::O0; options.inputFilename = inputFilename; + options.dwarfVersion = dwarfVersion; addPassConditionally(pm, disableDebugInfo, [&]() { return fir::createAddDebugInfoPass(options); }); } @@ -333,9 +334,9 @@ void createOpenMPFIRPassPipeline(mlir::PassManager &pm, void createDebugPasses(mlir::PassManager &pm, llvm::codegenoptions::DebugInfoKind debugLevel, llvm::OptimizationLevel OptLevel, - llvm::StringRef inputFilename) { + llvm::StringRef inputFilename, int32_t dwarfVersion) { if (debugLevel != llvm::codegenoptions::NoDebugInfo) - addDebugInfoPass(pm, debugLevel, OptLevel, inputFilename); + addDebugInfoPass(pm, debugLevel, OptLevel, inputFilename, dwarfVersion); } void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, @@ -352,7 +353,8 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, fir::addCodeGenRewritePass( pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo)); fir::addExternalNameConversionPass(pm, config.Underscoring); - fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename); + fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename, + config.DwarfVersion); fir::addTargetRewritePass(pm); fir::addCompilerGeneratedNamesConversionPass(pm); diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp index 6eb914e67fd54..af96c0be6fae9 100644 --- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp +++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp @@ -649,6 +649,19 @@ void AddDebugInfoPass::runOnOperation() { signalPassFailure(); return; } + mlir::OpBuilder builder(context); + if (dwarfVersion > 0) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToEnd(module.getBody()); + llvm::SmallVector moduleFlags; + mlir::IntegerType int32Ty = mlir::IntegerType::get(context, 32); + moduleFlags.push_back(builder.getAttr( + mlir::LLVM::ModFlagBehavior::Max, + mlir::StringAttr::get(context, "Dwarf Version"), + mlir::IntegerAttr::get(int32Ty, dwarfVersion))); + mlir::LLVM::ModuleFlagsOp::create(builder, module.getLoc(), + builder.getArrayAttr(moduleFlags)); + } fir::DebugTypeGenerator typeGen(module, &symbolTable, *dl); // We need 2 type of file paths here. // 1. Name of the file as was presented to compiler. This can be absolute @@ -686,7 +699,6 @@ void AddDebugInfoPass::runOnOperation() { module.walk([&](mlir::func::FuncOp funcOp) { handleFuncOp(funcOp, fileAttr, cuAttr, typeGen, &symbolTable); }); - mlir::OpBuilder builder(context); // We have processed all function. Attach common block variables to the // global that represent the storage. for (auto [global, exprs] : globalToGlobalExprsMap) { diff --git a/flang/test/Integration/debug-dwarf-flags.f90 b/flang/test/Integration/debug-dwarf-flags.f90 new file mode 100644 index 0000000000000..8dae74ecb07cd --- /dev/null +++ b/flang/test/Integration/debug-dwarf-flags.f90 @@ -0,0 +1,24 @@ +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=5 %s \ +! RUN: -o - | FileCheck --check-prefix=CHECK-DWARF5 %s +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=line-tables-only -dwarf-version=5 \ +! RUN: %s -o - | FileCheck --check-prefix=CHECK-DWARF5 %s +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=4 %s \ +! RUN: -o - | FileCheck --check-prefix=CHECK-DWARF4 %s +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=3 %s \ +! RUN: -o - | FileCheck --check-prefix=CHECK-DWARF3 %s +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=2 %s \ +! RUN: -o - | FileCheck --check-prefix=CHECK-DWARF2 %s +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o -\ +! RUN: | FileCheck --check-prefix=CHECK-WITHOUT-VERSION %s +! RUN: %flang_fc1 -emit-llvm -dwarf-version=5 %s -o - \ +! RUN: | FileCheck --check-prefix=CHECK-WITHOUT-DEBUG-KIND %s + +program test +end program test + +! CHECK-DWARF5: !{i32 7, !"Dwarf Version", i32 5} +! CHECK-DWARF4: !{i32 7, !"Dwarf Version", i32 4} +! CHECK-DWARF3: !{i32 7, !"Dwarf Version", i32 3} +! CHECK-DWARF2: !{i32 7, !"Dwarf Version", i32 2} +! CHECK-WITHOUT-VERSION-NOT: "Dwarf Version" +! CHECK-WITHOUT-DEBUG-KIND-NOT: "Dwarf Version" diff --git a/flang/test/Transforms/debug-dwarf-version.fir b/flang/test/Transforms/debug-dwarf-version.fir new file mode 100644 index 0000000000000..d536b8dddbbd6 --- /dev/null +++ b/flang/test/Transforms/debug-dwarf-version.fir @@ -0,0 +1,22 @@ + +// RUN: fir-opt --add-debug-info="dwarf-version=5" --mlir-print-debuginfo %s \ +// RUN: | FileCheck --check-prefix=CHECK-DWARF5 %s +// RUN: fir-opt --add-debug-info="dwarf-version=4" --mlir-print-debuginfo %s \ +// RUN: | FileCheck --check-prefix=CHECK-DWARF4 %s +// RUN: fir-opt --add-debug-info="dwarf-version=3" --mlir-print-debuginfo %s \ +// RUN: | FileCheck --check-prefix=CHECK-DWARF3 %s +// RUN: fir-opt --add-debug-info="dwarf-version=2" --mlir-print-debuginfo %s \ +// RUN: | FileCheck --check-prefix=CHECK-DWARF2 %s +// RUN: fir-opt --add-debug-info= --mlir-print-debuginfo %s \ +// RUN: | FileCheck --check-prefix=CHECK-WITHOUT-VERSION %s +// REQUIRES: system-linux + +module { +} loc(#loc) +#loc = loc("simple.f90":0:0) + +// CHECK-DWARF5: llvm.module_flags [#llvm.mlir.module_flag] +// CHECK-DWARF4: llvm.module_flags [#llvm.mlir.module_flag] +// CHECK-DWARF3: llvm.module_flags [#llvm.mlir.module_flag] +// CHECK-DWARF2: llvm.module_flags [#llvm.mlir.module_flag] +// CHECK-WITHOUT-VERSION-NOT: llvm.module_flags From 65bfa4b3ed95e4209ce6c1382e272029e7159f9c Mon Sep 17 00:00:00 2001 From: Abid Qadeer Date: Wed, 17 Sep 2025 10:17:17 +0100 Subject: [PATCH 2/2] Handle review comments. --- flang/test/Integration/debug-dwarf-flags.f90 | 3 +-- flang/test/Transforms/debug-dwarf-version.fir | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/flang/test/Integration/debug-dwarf-flags.f90 b/flang/test/Integration/debug-dwarf-flags.f90 index 8dae74ecb07cd..ac5b1c0d8d4b2 100644 --- a/flang/test/Integration/debug-dwarf-flags.f90 +++ b/flang/test/Integration/debug-dwarf-flags.f90 @@ -11,7 +11,7 @@ ! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o -\ ! RUN: | FileCheck --check-prefix=CHECK-WITHOUT-VERSION %s ! RUN: %flang_fc1 -emit-llvm -dwarf-version=5 %s -o - \ -! RUN: | FileCheck --check-prefix=CHECK-WITHOUT-DEBUG-KIND %s +! RUN: | FileCheck --check-prefix=CHECK-WITHOUT-VERSION %s program test end program test @@ -21,4 +21,3 @@ end program test ! CHECK-DWARF3: !{i32 7, !"Dwarf Version", i32 3} ! CHECK-DWARF2: !{i32 7, !"Dwarf Version", i32 2} ! CHECK-WITHOUT-VERSION-NOT: "Dwarf Version" -! CHECK-WITHOUT-DEBUG-KIND-NOT: "Dwarf Version" diff --git a/flang/test/Transforms/debug-dwarf-version.fir b/flang/test/Transforms/debug-dwarf-version.fir index d536b8dddbbd6..fe2700274ab87 100644 --- a/flang/test/Transforms/debug-dwarf-version.fir +++ b/flang/test/Transforms/debug-dwarf-version.fir @@ -1,4 +1,3 @@ - // RUN: fir-opt --add-debug-info="dwarf-version=5" --mlir-print-debuginfo %s \ // RUN: | FileCheck --check-prefix=CHECK-DWARF5 %s // RUN: fir-opt --add-debug-info="dwarf-version=4" --mlir-print-debuginfo %s \