diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 1464ce4e1b31b..40ae40665b040 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -105,6 +105,16 @@ unsigned DwarfVersionNum(StringRef ArgValue); const llvm::opt::Arg *getDwarfNArg(const llvm::opt::ArgList &Args); unsigned getDwarfVersion(const ToolChain &TC, const llvm::opt::ArgList &Args); +enum class DwarfFissionKind { None, Split, Single }; + +DwarfFissionKind getDebugFissionKind(const Driver &D, + const llvm::opt::ArgList &Args, + llvm::opt::Arg *&Arg); + +bool checkDebugInfoOption(const llvm::opt::Arg *A, + const llvm::opt::ArgList &Args, const Driver &D, + const ToolChain &TC); + void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 16e1c396fedbe..61fd0fa3794ee 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4754,13 +4754,13 @@ defm column_info : BoolOption<"g", "column-info", PosFlag, BothFlags<[], [ClangOption, CLOption, DXCOption]>>, Group; def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group, - Visibility<[ClangOption, CLOption, DXCOption]>; + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; def gsplit_dwarf_EQ : Joined<["-"], "gsplit-dwarf=">, Group, - Visibility<[ClangOption, CLOption, DXCOption]>, + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, HelpText<"Set DWARF fission mode">, Values<"split,single">; def gno_split_dwarf : Flag<["-"], "gno-split-dwarf">, Group, - Visibility<[ClangOption, CLOption, DXCOption]>; + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; def gtemplate_alias : Flag<["-"], "gtemplate-alias">, Group, Visibility<[ClangOption, CC1Option]>; def gno_template_alias : Flag<["-"], "gno-template-alias">, Group, Visibility<[ClangOption]>; def gsimple_template_names : Flag<["-"], "gsimple-template-names">, Group; @@ -8405,7 +8405,7 @@ def main_file_name : Separate<["-"], "main-file-name">, MarshallingInfoString>; def split_dwarf_output : Separate<["-"], "split-dwarf-output">, HelpText<"File name to use for split dwarf debug info output">, - Visibility<[CC1Option, CC1AsOption]>, + Visibility<[CC1Option, CC1AsOption, FC1Option]>, MarshallingInfoString>; let Visibility = [CC1Option, FC1Option] in { @@ -8437,6 +8437,10 @@ def dependent_lib : Joined<["--"], "dependent-lib=">, HelpText<"Add dependent library">, MarshallingInfoStringVector>; +def split_dwarf_file : Separate<["-"], "split-dwarf-file">, + HelpText<"Name of the split dwarf debug info file to encode in the object file">, + MarshallingInfoString>; + } // let Visibility = [CC1Option, FC1Option] let Visibility = [CC1Option] in { @@ -8447,9 +8451,6 @@ def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">, def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">, HelpText<"Assume all functions with C linkage do not unwind">, MarshallingInfoFlag>; -def split_dwarf_file : Separate<["-"], "split-dwarf-file">, - HelpText<"Name of the split dwarf debug info file to encode in the object file">, - MarshallingInfoString>; def fno_wchar : Flag<["-"], "fno-wchar">, HelpText<"Disable C++ builtin type wchar_t">, MarshallingInfoNegativeFlag, cplusplus.KeyPath>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index e7aabee273a34..43cf8f54e272e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -695,16 +695,6 @@ RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, } } -static bool checkDebugInfoOption(const Arg *A, const ArgList &Args, - const Driver &D, const ToolChain &TC) { - assert(A && "Expected non-nullptr argument."); - if (TC.supportsDebugInfoOption(A)) - return true; - D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) - << A->getAsString(Args) << TC.getTripleString(); - return false; -} - static void RenderDebugInfoCompressionArgs(const ArgList &Args, ArgStringList &CmdArgs, const Driver &D, @@ -4327,27 +4317,6 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, Args.addLastArg(CmdArgs, options::OPT_warning_suppression_mappings_EQ); } -DwarfFissionKind tools::getDebugFissionKind(const Driver &D, - const ArgList &Args, Arg *&Arg) { - Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ, - options::OPT_gno_split_dwarf); - if (!Arg || Arg->getOption().matches(options::OPT_gno_split_dwarf)) - return DwarfFissionKind::None; - - if (Arg->getOption().matches(options::OPT_gsplit_dwarf)) - return DwarfFissionKind::Split; - - StringRef Value = Arg->getValue(); - if (Value == "split") - return DwarfFissionKind::Split; - if (Value == "single") - return DwarfFissionKind::Single; - - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getSpelling() << Arg->getValue(); - return DwarfFissionKind::None; -} - static void renderDwarfFormat(const Driver &D, const llvm::Triple &T, const ArgList &Args, ArgStringList &CmdArgs, unsigned DwarfVersion) { diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 18f6c5ed06a59..c22789591e00a 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -187,12 +187,6 @@ class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool { const char *LinkingOutput) const override; }; -enum class DwarfFissionKind { None, Split, Single }; - -DwarfFissionKind getDebugFissionKind(const Driver &D, - const llvm::opt::ArgList &Args, - llvm::opt::Arg *&Arg); - // Calculate the output path of the module file when compiling a module unit // with the `-fmodule-output` option or `-fmodule-output=` option specified. // The behavior is: diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 08cd98fd04df0..4902c2f3c0cbe 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -2270,6 +2270,37 @@ unsigned tools::getDwarfVersion(const ToolChain &TC, return DwarfVersion; } +DwarfFissionKind tools::getDebugFissionKind(const Driver &D, + const ArgList &Args, Arg *&Arg) { + Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ, + options::OPT_gno_split_dwarf); + if (!Arg || Arg->getOption().matches(options::OPT_gno_split_dwarf)) + return DwarfFissionKind::None; + + if (Arg->getOption().matches(options::OPT_gsplit_dwarf)) + return DwarfFissionKind::Split; + + StringRef Value = Arg->getValue(); + if (Value == "split") + return DwarfFissionKind::Split; + if (Value == "single") + return DwarfFissionKind::Single; + + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getSpelling() << Arg->getValue(); + return DwarfFissionKind::None; +} + +bool tools::checkDebugInfoOption(const Arg *A, const ArgList &Args, + const Driver &D, const ToolChain &TC) { + assert(A && "Expected non-nullptr argument."); + if (TC.supportsDebugInfoOption(A)) + return true; + D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + return false; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 6fc372eb75eb7..a5394813eeb97 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -120,7 +120,11 @@ static bool shouldLoopVersion(const ArgList &Args) { return false; } -void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { +void Flang::addDebugOptions(const llvm::opt::ArgList &Args, const JobAction &JA, + const InputInfo &Output, const InputInfo &Input, + llvm::opt::ArgStringList &CmdArgs) const { + const auto &TC = getToolChain(); + const Driver &D = TC.getDriver(); Args.addAllArgs(CmdArgs, {options::OPT_module_dir, options::OPT_fdebug_module_writer, options::OPT_fintrinsic_modules_path, options::OPT_pedantic, @@ -131,20 +135,60 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { options::OPT_finstrument_functions}); llvm::codegenoptions::DebugInfoKind DebugInfoKind; + bool hasDwarfNArg = getDwarfNArg(Args) != nullptr; 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_Group)) { + } else if (Args.hasArg(options::OPT_g_Flag) || hasDwarfNArg) { DebugInfoKind = llvm::codegenoptions::FullDebugInfo; } else { DebugInfoKind = llvm::codegenoptions::NoDebugInfo; } addDebugInfoKind(CmdArgs, DebugInfoKind); - if (getDwarfNArg(Args)) { + if (hasDwarfNArg) { const unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args); CmdArgs.push_back( Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); } + if (Args.hasArg(options::OPT_gsplit_dwarf) || + Args.hasArg(options::OPT_gsplit_dwarf_EQ)) { + // FIXME: -gsplit-dwarf on AIX is currently unimplemented. + if (TC.getTriple().isOSAIX()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_gsplit_dwarf)->getSpelling() + << TC.getTriple().str(); + return; + } + if (DebugInfoKind == llvm::codegenoptions::NoDebugInfo) + return; + + Arg *SplitDWARFArg; + DwarfFissionKind DwarfFission = getDebugFissionKind(D, Args, SplitDWARFArg); + + if (DwarfFission == DwarfFissionKind::None || + !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) + return; + + if (!TC.getTriple().isOSBinFormatELF() && + !TC.getTriple().isOSBinFormatWasm() && + !TC.getTriple().isOSBinFormatCOFF()) { + D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) + << SplitDWARFArg->getSpelling() << TC.getTriple().str(); + return; + } + + if (!isa(JA) && !isa(JA) && + isa(JA)) + return; + + const char *SplitDWARFOut = SplitDebugName(JA, Args, Input, Output); + CmdArgs.push_back("-split-dwarf-file"); + CmdArgs.push_back(SplitDWARFOut); + if (DwarfFission == DwarfFissionKind::Split) { + CmdArgs.push_back("-split-dwarf-output"); + CmdArgs.push_back(SplitDWARFOut); + } + } } void Flang::addCodegenOptions(const ArgList &Args, @@ -936,8 +980,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, if (willEmitRemarks(Args)) renderRemarksOptions(Args, CmdArgs, Input); - // Add other compile options - addOtherOptions(Args, CmdArgs); + // Add debug compile options + addDebugOptions(Args, JA, Output, Input, CmdArgs); // Disable all warnings // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h index 98167e1b75e15..c0837b80c032e 100644 --- a/clang/lib/Driver/ToolChains/Flang.h +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -125,12 +125,16 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool { void addCodegenOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - /// Extract other compilation options from the driver arguments and add them + /// Extract debug compilation options from the driver arguments and add them /// to the command arguments. /// /// \param [in] Args The list of input driver arguments + /// \param [in] JA The job action + /// \param [in] Output The output information on the current file output + /// \param [in] Input The input information on the current file input /// \param [out] CmdArgs The list of output command arguments - void addOtherOptions(const llvm::opt::ArgList &Args, + void addDebugOptions(const llvm::opt::ArgList &Args, const JobAction &JA, + const InputInfo &Output, const InputInfo &Input, llvm::opt::ArgStringList &CmdArgs) const; public: diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h index df6063cc90340..3dca169d43b39 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -168,6 +168,13 @@ class CodeGenOptions : public CodeGenOptionsBase { /// by -fprofile-sample-use or -fprofile-instr-use. std::string ProfileRemappingFile; + /// The name for the split debug info file used for the DW_AT_[GNU_]dwo_name + /// attribute in the skeleton CU. + std::string SplitDwarfFile; + + /// Output filename for the split debug info, not used in the skeleton CU. + std::string SplitDwarfOutput; + /// Check if Clang profile instrumenation is on. bool hasProfileClangInstr() const { return getProfileInstr() == llvm::driver::ProfileClangInstr; diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 09b51730d6216..81610edee36fb 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -160,6 +160,12 @@ static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts, opts.DwarfVersion = getLastArgIntValue(args, clang::driver::options::OPT_dwarf_version_EQ, /*Default=*/0, diags); + if (const llvm::opt::Arg *a = + args.getLastArg(clang::driver::options::OPT_split_dwarf_file)) + opts.SplitDwarfFile = a->getValue(); + if (const llvm::opt::Arg *a = + args.getLastArg(clang::driver::options::OPT_split_dwarf_output)) + opts.SplitDwarfOutput = a->getValue(); } return true; } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index c3c53d51015a2..9e0bef035a643 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -898,7 +898,19 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags, llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly) ? llvm::CodeGenFileType::AssemblyFile : llvm::CodeGenFileType::ObjectFile; - if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) { + std::unique_ptr dwoOS; + if (!codeGenOpts.SplitDwarfOutput.empty()) { + std::error_code ec; + dwoOS = std::make_unique(codeGenOpts.SplitDwarfOutput, + ec, llvm::sys::fs::OF_None); + if (ec) { + diags.Report(clang::diag::err_fe_unable_to_open_output) + << codeGenOpts.SplitDwarfOutput << ec.message(); + return; + } + } + if (tm.addPassesToEmitFile(codeGenPasses, os, dwoOS ? &dwoOS->os() : nullptr, + cgft)) { unsigned diagID = diags.getCustomDiagID(clang::DiagnosticsEngine::Error, "emission of this file type is not supported"); @@ -909,6 +921,9 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags, // Run the passes codeGenPasses.run(llvmModule); + if (dwoOS) + dwoOS->keep(); + // Cleanup delete tlii; } @@ -1324,6 +1339,7 @@ void CodeGenAction::executeAction() { llvm::TargetMachine &targetMachine = ci.getTargetMachine(); targetMachine.Options.MCOptions.AsmVerbose = targetOpts.asmVerbose; + targetMachine.Options.MCOptions.SplitDwarfFile = codeGenOpts.SplitDwarfFile; const llvm::Triple &theTriple = targetMachine.getTargetTriple(); diff --git a/flang/test/Driver/split-debug.f90 b/flang/test/Driver/split-debug.f90 new file mode 100644 index 0000000000000..1cb9f84d7a5d2 --- /dev/null +++ b/flang/test/Driver/split-debug.f90 @@ -0,0 +1,44 @@ +! Test -gsplit-dwarf and -gsplit-dwarf={split,single}. + +! RUN: %flang -### -c -target x86_64 -g -gsplit-dwarf %s 2>&1 | FileCheck %s --check-prefixes=SPLIT +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefixes=SPLIT +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf=split -g %s 2>&1 | FileCheck %s --check-prefixes=SPLIT + +! SPLIT: "-split-dwarf-file" "split-debug.dwo" "-split-dwarf-output" "split-debug.dwo" + +! Check warning on non-supported platforms. +! RUN: %flang -### -c -target x86_64-apple-darwin -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=WARN +! WARN: warning: debug information option '-gsplit-dwarf' is not supported for target 'x86_64-apple-darwin' + +! -gno-split-dwarf disables debug fission. +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf -g -gno-split-dwarf %s 2>&1 | FileCheck %s --check-prefix=NOSPLIT +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf=single -g -gno-split-dwarf %s 2>&1 | FileCheck %s --check-prefix=NOSPLIT +! RUN: %flang -### -c -target x86_64 -gno-split-dwarf -g -gsplit-dwarf %s 2>&1 | FileCheck %s --check-prefixes=SPLIT + +! NOSPLIT-NOT: "-split-dwarf + +! Test -gsplit-dwarf=single. +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf=single -g %s 2>&1 | FileCheck %s --check-prefix=SINGLE + +! SINGLE: "-split-dwarf-file" "split-debug.o" +! SINGLE-NOT: "-split-dwarf-output" + +! RUN: %flang -### -c -target x86_64 -gsplit-dwarf=single -g -o %tfoo.o %s 2>&1 | FileCheck %s --check-prefix=SINGLE_WITH_FILENAME +! SINGLE_WITH_FILENAME: "-split-dwarf-file" "{{.*}}foo.o" +! SINGLE_WITH_FILENAME-NOT: "-split-dwarf-output" + + +! Invoke objcopy if not using the integrated assembler. +! RUN: %flang -### -c -target x86_64-unknown-linux-gnu -fno-integrated-as -gsplit-dwarf -g %s 2>&1 | FileCheck %s --check-prefix=OBJCOPY +! OBJCOPY: objcopy{{(.exe)?}} +! OBJCOPY-SAME: --extract-dwo +! OBJCOPY-NEXT: objcopy{{(.exe)?}} +! OBJCOPY-SAME: --strip-dwo + +! RUN: not %flang -target powerpc-ibm-aix -gdwarf-4 -gsplit-dwarf %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=UNSUP_OPT_AIX +! RUN: not %flang -target powerpc64-ibm-aix -gdwarf-4 -gsplit-dwarf %s 2>&1 \ +! RUN: | FileCheck %s --check-prefix=UNSUP_OPT_AIX64 + +! UNSUP_OPT_AIX: error: unsupported option '-gsplit-dwarf' for target 'powerpc-ibm-aix' +! UNSUP_OPT_AIX64: error: unsupported option '-gsplit-dwarf' for target 'powerpc64-ibm-aix' diff --git a/flang/test/Integration/debug-split-dwarf.f90 b/flang/test/Integration/debug-split-dwarf.f90 new file mode 100644 index 0000000000000..60373efddc358 --- /dev/null +++ b/flang/test/Integration/debug-split-dwarf.f90 @@ -0,0 +1,21 @@ +! REQUIRES: x86-registered-target + +! Testing to ensure that setting only -split-dwarf-file allows to place +! .dwo sections into regular output object. +! RUN: %flang_fc1 -debug-info-kind=standalone -triple x86_64-unknown-linux \ +! RUN: -split-dwarf-file %t.o -emit-obj -o %t.o %s +! RUN: llvm-readobj -S %t.o | FileCheck --check-prefix=DWO %s + +! Testing to ensure that setting both -split-dwarf-file and -split-dwarf-output +! does not place .dwo sections into regular output object but in a separate +! file. +! RUN: %flang_fc1 -debug-info-kind=standalone -triple x86_64-unknown-linux \ +! RUN: -split-dwarf-file %t.dwo -split-dwarf-output %t.dwo -emit-obj -o %t.o %s +! RUN: llvm-readobj -S %t.dwo | FileCheck --check-prefix=DWO %s +! RUN: llvm-readobj -S %t.o | FileCheck --check-prefix=SPLIT %s + +! DWO: .dwo +! SPLIT-NOT: .dwo + +program test +end program test