Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -649,7 +649,9 @@ def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">, HelpText<"Assume all functions with C linkage do not unwind">; def enable_split_dwarf : Flag<["-"], "enable-split-dwarf">, - HelpText<"Use split dwarf/Fission">; + HelpText<"Use DWARF fission in 'split' mode">; +def enable_split_dwarf_EQ : Joined<["-"], "enable-split-dwarf=">, + HelpText<"Set DWARF fission mode to either 'split' or 'single'">, Values<"split,single">; def fno_wchar : Flag<["-"], "fno-wchar">, HelpText<"Disable C++ builtin type wchar_t">; def fconstant_string_class : Separate<["-"], "fconstant-string-class">, Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1842,6 +1842,9 @@ def gcolumn_info : Flag<["-"], "gcolumn-info">, Group, Flags<[CoreOption]>; def gno_column_info : Flag<["-"], "gno-column-info">, Group, Flags<[CoreOption]>; def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group; +def gsplit_dwarf_EQ : Joined<["-"], "gsplit-dwarf=">, Group, + HelpText<"Set DWARF fission mode to either 'split' or 'single'">, + Values<"split,single">; def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group, Flags<[CC1Option]>; def gno_gnu_pubnames : Flag<["-"], "gno-gnu-pubnames">, Group, Flags<[CC1Option]>; def gpubnames : Flag<["-"], "gpubnames">, Group, Flags<[CC1Option]>; Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -71,6 +71,8 @@ LocalExecTLSModel }; + enum DwarfFissionKind { NoFission, SplitFileFission, SingleFileFission }; + /// Clang versions with different platform ABI conformance. enum class ClangABI { /// Attempt to be ABI-compatible with code generated by Clang 3.8.x Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -252,7 +252,9 @@ CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should ///< contain explicit imports for ///< anonymous namespaces -CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF + +ENUM_CODEGENOPT(SplitDwarfMode, DwarfFissionKind, 2, NoFission) ///< DWARF fission mode to use. + CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the ///< skeleton CU to allow for symbolication ///< of inline stack frames without .dwo files. Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -468,7 +468,7 @@ Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection; Options.EmitAddrsig = CodeGenOpts.Addrsig; - if (CodeGenOpts.EnableSplitDwarf) + if (CodeGenOpts.getSplitDwarfMode() != CodeGenOptions::NoFission) Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile; Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll; Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels; @@ -834,7 +834,8 @@ break; default: - if (!CodeGenOpts.SplitDwarfFile.empty()) { + if (!CodeGenOpts.SplitDwarfFile.empty() && + (CodeGenOpts.getSplitDwarfMode() == CodeGenOptions::SplitFileFission)) { DwoOS = openOutputFile(CodeGenOpts.SplitDwarfFile); if (!DwoOS) return; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -581,8 +581,11 @@ CGOpts.EmitVersionIdentMetadata ? Producer : "", LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO, CGOpts.DwarfDebugFlags, RuntimeVers, - CGOpts.EnableSplitDwarf ? "" : CGOpts.SplitDwarfFile, EmissionKind, - 0 /* DWOid */, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, + (CGOpts.getSplitDwarfMode() != CodeGenOptions::NoFission) + ? "" + : CGOpts.SplitDwarfFile, + EmissionKind, 0 /* DWOid */, CGOpts.SplitDwarfInlining, + CGOpts.DebugInfoForProfiling, CGM.getTarget().getTriple().isNVPTX() ? llvm::DICompileUnit::DebugNameTableKind::None : static_cast( Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -3009,12 +3009,35 @@ CmdArgs.push_back("-fno-spell-checking"); } +enum class DwarfFissionKind { None, Split, Single }; + +static DwarfFissionKind getDebugFissionKind(const Driver &D, + const ArgList &Args, Arg *&Arg) { + Arg = + Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ); + if (!Arg) + 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->getOption().getName() << Arg->getValue(); + return DwarfFissionKind::None; +} + static void RenderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, const ArgList &Args, bool EmitCodeView, bool IsWindowsMSVC, ArgStringList &CmdArgs, codegenoptions::DebugInfoKind &DebugInfoKind, - const Arg *&SplitDWARFArg) { + DwarfFissionKind &DwarfFission) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, options::OPT_fno_debug_info_for_profiling, false) && checkDebugInfoOption( @@ -3039,10 +3062,12 @@ Args.ClaimAllArgs(options::OPT_g_Group); - SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf); + Arg* SplitDWARFArg; + DwarfFission = getDebugFissionKind(D, Args, SplitDWARFArg); - if (SplitDWARFArg && !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) { - SplitDWARFArg = nullptr; + if (DwarfFission != DwarfFissionKind::None && + !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) { + DwarfFission = DwarfFissionKind::None; SplitDWARFInlining = false; } @@ -3059,13 +3084,13 @@ // composing split-dwarf and line-tables-only, so let those compose // naturally in that case. And if you just turned off debug info, // (-gsplit-dwarf -g0) - do that. - if (SplitDWARFArg) { + if (DwarfFission != DwarfFissionKind::None) { if (A->getIndex() > SplitDWARFArg->getIndex()) { if (DebugInfoKind == codegenoptions::NoDebugInfo || DebugInfoKind == codegenoptions::DebugDirectivesOnly || (DebugInfoKind == codegenoptions::DebugLineTablesOnly && SplitDWARFInlining)) - SplitDWARFArg = nullptr; + DwarfFission = DwarfFissionKind::None; } else if (SplitDWARFInlining) DebugInfoKind = codegenoptions::NoDebugInfo; } @@ -3153,10 +3178,14 @@ if (!SplitDWARFInlining) CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (SplitDWARFArg) { + if (DwarfFission != DwarfFissionKind::None) { if (DebugInfoKind == codegenoptions::NoDebugInfo) DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-enable-split-dwarf"); + + if (DwarfFission == DwarfFissionKind::Single) + CmdArgs.push_back("-enable-split-dwarf=single"); + else + CmdArgs.push_back("-enable-split-dwarf"); } } @@ -3201,7 +3230,8 @@ const auto *PubnamesArg = Args.getLastArg(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames, options::OPT_gpubnames, options::OPT_gno_pubnames); - if (SplitDWARFArg || DebuggerTuning == llvm::DebuggerKind::LLDB || + if (DwarfFission != DwarfFissionKind::None || + DebuggerTuning == llvm::DebuggerKind::LLDB || (PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC))) if (!PubnamesArg || (!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) && @@ -3905,20 +3935,20 @@ else EmitCodeView = Args.hasArg(options::OPT_gcodeview); - const Arg *SplitDWARFArg = nullptr; + DwarfFissionKind DwarfFission; RenderDebugOptions(TC, D, RawTriple, Args, EmitCodeView, IsWindowsMSVC, - CmdArgs, DebugInfoKind, SplitDWARFArg); + CmdArgs, DebugInfoKind, DwarfFission); // Add the split debug info name to the command lines here so we // can propagate it to the backend. - bool SplitDWARF = SplitDWARFArg && + bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) && (RawTriple.isOSLinux() || RawTriple.isOSFuchsia()) && (isa(JA) || isa(JA) || isa(JA)); const char *SplitDWARFOut; if (SplitDWARF) { CmdArgs.push_back("-split-dwarf-file"); - SplitDWARFOut = SplitDebugName(Args, Input); + SplitDWARFOut = SplitDebugName(Args, Input, Output); CmdArgs.push_back(SplitDWARFOut); } @@ -5876,10 +5906,11 @@ CmdArgs.push_back(Output.getFilename()); const llvm::Triple &T = getToolChain().getTriple(); - if (Args.hasArg(options::OPT_gsplit_dwarf) && + Arg *A; + if ((getDebugFissionKind(D, Args, A) == DwarfFissionKind::Split) && (T.isOSLinux() || T.isOSFuchsia())) { CmdArgs.push_back("-split-dwarf-file"); - CmdArgs.push_back(SplitDebugName(Args, Input)); + CmdArgs.push_back(SplitDebugName(Args, Input, Output)); } assert(Input.isFilename() && "Invalid input."); Index: lib/Driver/ToolChains/CommonArgs.h =================================================================== --- lib/Driver/ToolChains/CommonArgs.h +++ lib/Driver/ToolChains/CommonArgs.h @@ -63,7 +63,7 @@ const Tool &T); const char *SplitDebugName(const llvm::opt::ArgList &Args, - const InputInfo &Input); + const InputInfo &Input, const InputInfo &Output); void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const llvm::opt::ArgList &Args, Index: lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- lib/Driver/ToolChains/CommonArgs.cpp +++ lib/Driver/ToolChains/CommonArgs.cpp @@ -808,7 +808,12 @@ return false; } -const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input) { +const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input, + const InputInfo &Output) { + if (Arg *A = Args.getLastArg(options::OPT_gsplit_dwarf_EQ)) + if (StringRef(A->getValue()) == "single") + return Args.MakeArgString(Output.getFilename()); + Arg *FinalOutput = Args.getLastArg(options::OPT_o); if (FinalOutput && Args.hasArg(options::OPT_c)) { SmallString<128> T(FinalOutput->getValue()); Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -817,7 +817,7 @@ if (Args.hasArg(options::OPT_gsplit_dwarf) && getToolChain().getTriple().isOSLinux()) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Inputs[0])); + SplitDebugName(Args, Inputs[0], Output)); } namespace { Index: lib/Driver/ToolChains/MinGW.cpp =================================================================== --- lib/Driver/ToolChains/MinGW.cpp +++ lib/Driver/ToolChains/MinGW.cpp @@ -54,7 +54,7 @@ if (Args.hasArg(options::OPT_gsplit_dwarf)) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Inputs[0])); + SplitDebugName(Args, Inputs[0], Output)); } void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -596,9 +596,25 @@ Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro); Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables); Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std); - Opts.EnableSplitDwarf = Args.hasArg(OPT_enable_split_dwarf); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining); + + if (Arg *A = + Args.getLastArg(OPT_enable_split_dwarf, OPT_enable_split_dwarf_EQ)) { + if (A->getOption().matches(options::OPT_enable_split_dwarf)) { + Opts.setSplitDwarfMode(CodeGenOptions::SplitFileFission); + } else { + StringRef Name = A->getValue(); + if (Name == "single") + Opts.setSplitDwarfMode(CodeGenOptions::SingleFileFission); + else if (Name == "split") + Opts.setSplitDwarfMode(CodeGenOptions::SplitFileFission); + else + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << Name; + } + } + Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); Opts.DebugExplicitImport = Args.hasArg(OPT_dwarf_explicit_import); Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params); Index: test/CodeGen/split-debug-single-file.c =================================================================== --- test/CodeGen/split-debug-single-file.c +++ test/CodeGen/split-debug-single-file.c @@ -0,0 +1,17 @@ +// REQUIRES: x86-registered-target + +// Testing to ensure -enable-split-dwarf=single allows to place .dwo sections into regular output object. +// RUN: %clang_cc1 -debug-info-kind=limited -triple x86_64-unknown-linux \ +// RUN: -enable-split-dwarf=single -split-dwarf-file %t.o -emit-obj -o %t.o %s +// RUN: llvm-objdump -section-headers %t.o | FileCheck --check-prefix=MODE-SINGLE %s +// MODE-SINGLE: .dwo + +// Testing to ensure -enable-split-dwarf=single allows to place .dwo sections into regular output object. +// RUN: %clang_cc1 -debug-info-kind=limited -triple x86_64-unknown-linux \ +// RUN: -enable-split-dwarf=split -split-dwarf-file %t.o -emit-obj -o %t.o %s +// RUN: llvm-objdump -section-headers %t.o | FileCheck --check-prefix=MODE-SPLIT %s +// MODE-SPLIT-NOT: .dwo + +int main (void) { + return 0; +} Index: test/Driver/split-debug.c =================================================================== --- test/Driver/split-debug.c +++ test/Driver/split-debug.c @@ -5,6 +5,21 @@ // // CHECK-ACTIONS: "-split-dwarf-file" "split-debug.dwo" +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=split -c -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s + +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=single -c -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-ACTIONS-SINGLE-SPLIT < %t %s +// +// CHECK-ACTIONS-SINGLE-SPLIT: "-enable-split-dwarf=single" +// CHECK-ACTIONS-SINGLE-SPLIT: "-split-dwarf-file" "split-debug.o" + +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=single -c -### -o %tfoo.o %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-SINGLE-SPLIT-FILENAME < %t %s +// +// CHECK-SINGLE-SPLIT-FILENAME: "-split-dwarf-file" "{{.*}}foo.o" // RUN: %clang -target x86_64-macosx -gsplit-dwarf -c -### %s 2> %t // RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s Index: test/Driver/split-debug.s =================================================================== --- test/Driver/split-debug.s +++ test/Driver/split-debug.s @@ -5,6 +5,13 @@ // // CHECK-ACTIONS: "-split-dwarf-file" "split-debug.dwo" +// Check we pass -split-dwarf-file to `as` if -gsplit-dwarf=split. +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=split -c -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s + +// Check we do not pass any -split-dwarf* commands to `as` if -gsplit-dwarf=single. +// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=single -c -### %s 2> %t +// RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s // RUN: %clang -target x86_64-macosx -gsplit-dwarf -c -### %s 2> %t // RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s