diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3232,9 +3232,9 @@ NormalizedValuesScope<"llvm::EmitDwarfUnwindType">, MarshallingInfoEnum, "Default">; def g_Flag : Flag<["-"], "g">, Group, - HelpText<"Generate source-level debug information">; + Flags<[CoreOption,FlangOption]>, HelpText<"Generate source-level debug information">; def gline_tables_only : Flag<["-"], "gline-tables-only">, Group, - Flags<[CoreOption]>, HelpText<"Emit debug line number tables only">; + Flags<[CoreOption,FlangOption]>, HelpText<"Emit debug line number tables only">; def gline_directives_only : Flag<["-"], "gline-directives-only">, Group, Flags<[CoreOption]>, HelpText<"Emit debug line info directives only">; def gmlt : Flag<["-"], "gmlt">, Alias; @@ -5468,12 +5468,12 @@ NormalizedValuesScope<"llvm::Reloc">, NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>, MarshallingInfoEnum, "PIC_">; +def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; } // let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { -def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; def debug_info_macro : Flag<["-"], "debug-info-macro">, HelpText<"Emit macro debug information">, MarshallingInfoFlag>; diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -20,7 +20,6 @@ #include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Option/Option.h" diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -13,7 +13,6 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" #include "clang/Driver/Types.h" -#include "llvm/ADT/Triple.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Option/Option.h" #include "llvm/Support/raw_ostream.h" diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -11,6 +11,7 @@ #include "CommonArgs.h" #include "clang/Driver/Options.h" +#include "llvm/Frontend/Debug/Options.h" #include @@ -27,6 +28,49 @@ CmdArgs.push_back(types::getTypeName(Input.getType())); } +// Convert an arg of the form "-gN" or one of their aliases +// to the corresponding DebugInfoKind. +static llvm::codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { + assert(A.getOption().matches(options::OPT_gN_Group) && + "Not a -g option that specifies a debug-info level"); + if (A.getOption().matches(options::OPT_g0) || + A.getOption().matches(options::OPT_ggdb0)) + return llvm::codegenoptions::NoDebugInfo; + if (A.getOption().matches(options::OPT_gline_tables_only) || + A.getOption().matches(options::OPT_ggdb1)) + return llvm::codegenoptions::DebugLineTablesOnly; + if (A.getOption().matches(options::OPT_gline_directives_only)) + return llvm::codegenoptions::DebugDirectivesOnly; + return llvm::codegenoptions::DebugInfoConstructor; +} + +static void +addFortranDebugOptions(ArgStringList &CmdArgs, + llvm::codegenoptions::DebugInfoKind DebugInfoKind) { + switch (DebugInfoKind) { + case llvm::codegenoptions::DebugDirectivesOnly: + CmdArgs.push_back("-debug-info-kind=line-directives-only"); + break; + case llvm::codegenoptions::DebugLineTablesOnly: + CmdArgs.push_back("-debug-info-kind=line-tables-only"); + break; + case llvm::codegenoptions::DebugInfoConstructor: + CmdArgs.push_back("-debug-info-kind=constructor"); + break; + case llvm::codegenoptions::LimitedDebugInfo: + CmdArgs.push_back("-debug-info-kind=limited"); + break; + case llvm::codegenoptions::FullDebugInfo: + CmdArgs.push_back("-debug-info-kind=standalone"); + break; + case llvm::codegenoptions::UnusedTypeInfo: + CmdArgs.push_back("-debug-info-kind=unused-types"); + break; + default: + break; + } +} + void Flang::addFortranDialectOptions(const ArgList &Args, ArgStringList &CmdArgs) const { Args.AddAllArgs( @@ -68,6 +112,17 @@ if (Args.hasArg(options::OPT_flang_experimental_hlfir)) CmdArgs.push_back("-flang-experimental-hlfir"); + + llvm::codegenoptions::DebugInfoKind DebugInfoKind; + if (Args.hasArg(options::OPT_gN_Group)) { + Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); + DebugInfoKind = DebugLevelToInfoKind(*gNArg); + } else if (Args.hasArg(options::OPT_g_Flag)) { + DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; + } else { + DebugInfoKind = llvm::codegenoptions::NoDebugInfo; + } + addFortranDebugOptions(CmdArgs, DebugInfoKind); } void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H #define LLVM_CLANG_BASIC_CODEGENOPTIONS_H +#include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetOptions.h" diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -34,6 +34,7 @@ CODEGENOPT(Underscoring, 1, 1) ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< Name of the relocation model to use. +ENUM_CODEGENOPT(DebugInfo, llvm::codegenoptions::DebugInfoKind, 4, llvm::codegenoptions::NoDebugInfo) ///< Level of debug info to generate #undef CODEGENOPT #undef ENUM_CODEGENOPT diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -18,6 +18,7 @@ #include "flang/Optimizer/Transforms/Passes.h" #include "llvm/Passes/OptimizationLevel.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Frontend/Debug/Options.h" #define DisableOption(DOName, DOOption, DODescription) \ static llvm::cl::opt disable##DOName("disable-" DOOption, \ @@ -56,6 +57,9 @@ const static llvm::OptimizationLevel &defaultOptLevel{ llvm::OptimizationLevel::O0}; +const static llvm::codegenoptions::DebugInfoKind &NoDebugInfo{ + llvm::codegenoptions::NoDebugInfo}; + /// Optimizer Passes DisableOption(CfgConversion, "cfg-conversion", "disable FIR to CFG pass"); DisableOption(FirAvc, "avc", "array value copy analysis and transformation"); @@ -228,9 +232,28 @@ } #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: + addDebugFoundationPass(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. + addDebugFoundationPass(pm); + return; + } +} + inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel, - bool underscoring = true) { + bool underscoring = true, + llvm::codegenoptions::DebugInfoKind debugInfo = NoDebugInfo) { fir::addBoxedProcedurePass(pm); pm.addNestedPass( fir::createAbstractResultOnFuncOptPass()); @@ -238,6 +261,7 @@ fir::addCodeGenRewritePass(pm); fir::addTargetRewritePass(pm); fir::addExternalNameConversionPass(pm, underscoring); + fir::createDebugPasses(pm, debugInfo); fir::addFIRToLLVMPass(pm, optLevel); } @@ -248,14 +272,15 @@ /// passes pipeline inline void createMLIRToLLVMPassPipeline(mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel, - bool stackArrays = false, bool underscoring = true) { + bool stackArrays = false, bool underscoring = true, + llvm::codegenoptions::DebugInfoKind debugInfo = NoDebugInfo) { fir::createHLFIRToFIRPassPipeline(pm, optLevel); // Add default optimizer pass pipeline. fir::createDefaultFIROptimizerPassPipeline(pm, optLevel, stackArrays); // Add codegen pass pipeline. - fir::createDefaultFIRCodeGenPassPipeline(pm, optLevel, underscoring); + fir::createDefaultFIRCodeGenPassPipeline(pm, optLevel, underscoring, debugInfo); } #undef FLANG_EXCLUDE_CODEGEN #endif diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -25,6 +25,7 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Frontend/Debug/Options.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -117,9 +118,42 @@ return true; } +static void parseDebugArgs(Fortran::frontend::CodeGenOptions &opts, + llvm::opt::ArgList &args, + clang::DiagnosticsEngine &diags) { + if (llvm::opt::Arg *arg = + args.getLastArg(clang::driver::options::OPT_debug_info_kind_EQ)) { + unsigned val = + llvm::StringSwitch(arg->getValue()) + .Case("line-tables-only", llvm::codegenoptions::DebugLineTablesOnly) + .Case("line-directives-only", + llvm::codegenoptions::DebugDirectivesOnly) + .Case("constructor", llvm::codegenoptions::DebugInfoConstructor) + .Case("limited", llvm::codegenoptions::LimitedDebugInfo) + .Case("standalone", llvm::codegenoptions::FullDebugInfo) + .Case("unused-types", llvm::codegenoptions::UnusedTypeInfo) + .Default(~0U); + if (val == ~0U) { + diags.Report(clang::diag::err_drv_invalid_value) + << arg->getAsString(args) << arg->getValue(); + } else { + opts.setDebugInfo(static_cast(val)); + } + if (val != llvm::codegenoptions::DebugLineTablesOnly && + val != llvm::codegenoptions::NoDebugInfo) { + // TODO: This is not a great warning message, could be improved + const auto debugErr = diags.getCustomDiagID( + clang::DiagnosticsEngine::Warning, + "Debug options greater than -g1 not yet implemented"); + diags.Report(debugErr) << arg->getAsString(args); + } + } +} + static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) { + parseDebugArgs(opts, args, diags); opts.OptimizationLevel = getOptimizationLevel(args, diags); if (args.hasFlag(clang::driver::options::OPT_fdebug_pass_manager, diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -606,7 +606,7 @@ // Create the pass pipeline fir::createMLIRToLLVMPassPipeline(pm, level, opts.StackArrays, - opts.Underscoring); + opts.Underscoring, opts.getDebugInfo()); mlir::applyPassManagerCLOptions(pm); // run the pass manager diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -60,6 +60,8 @@ ! CHECK-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages ! CHECK-NEXT: -funderscoring Appends one trailing underscore to external names ! CHECK-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV. +! CHECK-NEXT: -gline-tables-only Emit debug line number tables only +! CHECK-NEXT: -g Generate source-level debug information ! CHECK-NEXT: -help Display available options ! CHECK-NEXT: -I Add directory to the end of the list of include search paths ! CHECK-NEXT: -mllvm= Alias for -mllvm diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -56,6 +56,8 @@ ! HELP-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages ! HELP-NEXT: -funderscoring Appends one trailing underscore to external names ! HELP-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV. +! HELP-NEXT: -gline-tables-only Emit debug line number tables only +! HELP-NEXT: -g Generate source-level debug information ! HELP-NEXT: -help Display available options ! HELP-NEXT: -I Add directory to the end of the list of include search paths ! HELP-NEXT: -mllvm= Alias for -mllvm diff --git a/flang/test/Driver/mlir-debug-pass-pipeline.f90 b/flang/test/Driver/mlir-debug-pass-pipeline.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/mlir-debug-pass-pipeline.f90 @@ -0,0 +1,76 @@ +! Test the debug pass pipeline + +! RUN: %flang -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline -o /dev/null %s 2>&1 | FileCheck --check-prefixes=ALL,NO-DEBUG %s +! +! RUN: %flang -g0 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,NO-DEBUG %s +! RUN: %flang -g -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG %s +! RUN: %flang -g1 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG %s +! RUN: %flang -gline-tables-only -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG %s +! RUN: %flang -gline-directives-only -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG,DEBUG-DIRECTIVES %s +! RUN: %flang -g2 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG,DEBUG-CONSTRUCT %s +! RUN: %flang -g3 -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=ALL,DEBUG,DEBUG-CONSTRUCT %s + +! REQUIRES: asserts + +end program +! DEBUG-CONSTRUCT: warning: Debug options greater than -g1 not yet implemented +! DEBUG-DIRECTIVES: warning: Debug options greater than -g1 not yet implemented +! ALL: Pass statistics report + +! ALL: Fortran::lower::VerifierPass +! ALL-NEXT: LowerHLFIRIntrinsics +! ALL-NEXT: BufferizeHLFIR +! ALL-NEXT: ConvertHLFIRtoFIR +! ALL-NEXT: CSE +! Ideally, we need an output with only the pass names, but +! there is currently no way to get that, so in order to +! guarantee that the passes are in the expected order +! (i.e. use -NEXT) we have to check the statistics output as well. +! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd +! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd + +! ALL-NEXT: 'func.func' Pipeline +! ALL-NEXT: ArrayValueCopy +! ALL-NEXT: CharacterConversion + +! ALL-NEXT: Canonicalizer +! ALL-NEXT: SimplifyRegionLite +! ALL-NEXT: CSE +! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd +! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd + +! ALL-NEXT: 'func.func' Pipeline +! ALL-NEXT: MemoryAllocationOpt + +! ALL-NEXT: Inliner +! ALL-NEXT: SimplifyRegionLite +! ALL-NEXT: CSE +! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd +! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd + +! ALL-NEXT: 'func.func' Pipeline +! ALL-NEXT: PolymorphicOpConversion +! ALL-NEXT: CFGConversion + +! ALL-NEXT: SCFToControlFlow +! ALL-NEXT: Canonicalizer +! ALL-NEXT: SimplifyRegionLite +! ALL-NEXT: CSE +! ALL-NEXT: (S) 0 num-cse'd - Number of operations CSE'd +! ALL-NEXT: (S) 0 num-dce'd - Number of operations DCE'd +! ALL-NEXT: BoxedProcedurePass + +! ALL-NEXT: Pipeline Collection : ['fir.global', 'func.func'] +! ALL-NEXT: 'fir.global' Pipeline +! ALL-NEXT: AbstractResultOnGlobalOpt +! ALL-NEXT: 'func.func' Pipeline +! ALL-NEXT: AbstractResultOnFuncOpt + +! ALL-NEXT: CodeGenRewrite +! ALL-NEXT: (S) 0 num-dce'd - Number of operations eliminated +! ALL-NEXT: TargetRewrite +! ALL-NEXT: ExternalNameConversion +! DEBUG-NEXT: AddDebugFoundation +! NO-DEBUG-NOT: AddDebugFoundation +! ALL-NEXT: FIRToLLVMLowering +! ALL-NOT: LLVMIRLoweringPass