While a pass exists to generate basic debug information, currently there is not a corresponding flag to enable it.
This patch adds support for activating this pass at any debug level >= -g1, as well as emiting a warning for higher levels that the functionality is not yet fully implemented.
This patch also adds -g and -gline-tables-only to appear when `flang-new` --help is run
Depends on D142347.
Reviewed By: awarzynski
Differential Revision: https://reviews.llvm.org/D146814
NormalizedValuesScope<"llvm::EmitDwarfUnwindType">,
MarshallingInfoEnum<CodeGenOpts<"EmitDwarfUnwind">, "Default">;
def g_Flag : Flag<["-"], "g">, Group<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<gN_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<gN_Group>,
Flags<[CoreOption]>, HelpText<"Emit debug line info directives only">;
def gmlt : Flag<["-"], "gmlt">, Alias<gline_tables_only>;
NormalizedValuesScope<"llvm::Reloc">,
NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>,
MarshallingInfoEnum<CodeGenOpts<"RelocationModel">, "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<CodeGenOpts<"MacroDebugInfo">>;
Default);
}
-// Convert an arg of the form "-gN" or "-ggdbN" 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 bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()){
default:
llvm::codegenoptions::DebugInfoKind DebugInfoKind,
unsigned DwarfVersion,
llvm::DebuggerKind DebuggerTuning) {
- 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;
- }
+ addDebugInfoKind(CmdArgs, DebugInfoKind);
if (DwarfVersion > 0)
CmdArgs.push_back(
Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
// If the last option explicitly specified a debug-info level, use it.
if (checkDebugInfoOption(A, Args, D, TC) &&
A->getOption().matches(options::OPT_gN_Group)) {
- DebugInfoKind = DebugLevelToInfoKind(*A);
+ DebugInfoKind = debugLevelToInfoKind(*A);
// For -g0 or -gline-tables-only, drop -gsplit-dwarf. This gets a bit more
// complicated if you've disabled inline info in the skeleton CUs
// (SplitDWARFInlining) - then there's value in composing split-dwarf and
return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value;
}
+void tools::addDebugInfoKind(
+ 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;
+ }
+}
+
+// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
+// to the corresponding DebugInfoKind.
+llvm::codegenoptions::DebugInfoKind tools::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 unsigned ParseDebugDefaultVersion(const ToolChain &TC,
const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version);
unsigned ParseFunctionAlignment(const ToolChain &TC,
const llvm::opt::ArgList &Args);
+void addDebugInfoKind(llvm::opt::ArgStringList &CmdArgs,
+ llvm::codegenoptions::DebugInfoKind DebugInfoKind);
+
+llvm::codegenoptions::DebugInfoKind
+debugLevelToInfoKind(const llvm::opt::Arg &A);
+
// Extract the integer N from a string spelled "-dwarf-N", returning 0
// on mismatch. The StringRef input (rather than an Arg) allows
// for use by the "-Xassembler" option parser.
#include "CommonArgs.h"
#include "clang/Driver/Options.h"
+#include "llvm/Frontend/Debug/Options.h"
#include <cassert>
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;
+ }
+ addDebugInfoKind(CmdArgs, DebugInfoKind);
}
void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
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
#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"
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "flang/Optimizer/HLFIR/Passes.h"
#include "flang/Optimizer/Transforms/Passes.h"
+#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
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");
}
#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<mlir::func::FuncOp>(
fir::createAbstractResultOnFuncOptPass());
fir::addCodeGenRewritePass(pm);
fir::addTargetRewritePass(pm);
fir::addExternalNameConversionPass(pm, underscoring);
+ fir::createDebugPasses(pm, debugInfo);
fir::addFIRToLLVMPass(pm, optLevel);
}
/// 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
#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"
return true;
}
+static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts,
+ llvm::opt::ArgList &args,
+ clang::DiagnosticsEngine &diags) {
+ using DebugInfoKind = llvm::codegenoptions::DebugInfoKind;
+ if (llvm::opt::Arg *arg =
+ args.getLastArg(clang::driver::options::OPT_debug_info_kind_EQ)) {
+ std::optional<DebugInfoKind> val =
+ llvm::StringSwitch<std::optional<DebugInfoKind>>(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(std::nullopt);
+ if (!val.has_value()) {
+ diags.Report(clang::diag::err_drv_invalid_value)
+ << arg->getAsString(args) << arg->getValue();
+ return false;
+ }
+ opts.setDebugInfo(val.value());
+ if (val != llvm::codegenoptions::DebugLineTablesOnly &&
+ val != llvm::codegenoptions::NoDebugInfo) {
+ const auto debugWarning = diags.getCustomDiagID(
+ clang::DiagnosticsEngine::Warning, "Unsupported debug option: %0");
+ diags.Report(debugWarning) << arg->getValue();
+ }
+ }
+ return true;
+}
+
static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
parseTargetArgs(res.getTargetOpts(), args);
parsePreprocessorArgs(res.getPreprocessorOpts(), args);
parseCodeGenArgs(res.getCodeGenOpts(), args, diags);
+ success &= parseDebugArgs(res.getCodeGenOpts(), args, diags);
success &= parseSemaArgs(res, args, diags);
success &= parseDialectArgs(res, args, diags);
success &= parseDiagArgs(res, args, diags);
// Create the pass pipeline
fir::createMLIRToLLVMPassPipeline(pm, level, opts.StackArrays,
- opts.Underscoring);
+ opts.Underscoring, opts.getDebugInfo());
mlir::applyPassManagerCLOptions(pm);
// run the pass manager
! 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 <dir> Add directory to the end of the list of include search paths
! CHECK-NEXT: -mllvm=<arg> Alias for -mllvm
! 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 <dir> Add directory to the end of the list of include search paths
! HELP-NEXT: -mllvm=<arg> Alias for -mllvm
--- /dev/null
+! 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
+
+! RUN: not %flang_fc1 -debug-info-kind=invalid -S -mmlir --mlir-pass-statistics -mmlir --mlir-pass-statistics-display=pipeline %s -o /dev/null 2>&1 | FileCheck --check-prefixes=DEBUG-ERR %s
+
+! REQUIRES: asserts
+
+end program
+
+! DEBUG-CONSTRUCT: warning: Unsupported debug option: constructor
+! DEBUG-DIRECTIVES: warning: Unsupported debug option: line-directives-only
+!
+! DEBUG-ERR: error: invalid value 'invalid' in '-debug-info-kind=invalid'
+! DEBUG-ERR-NOT: Pass statistics report
+
+! 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