Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions clang/include/clang/Driver/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 8 additions & 7 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4754,13 +4754,13 @@ defm column_info : BoolOption<"g", "column-info",
PosFlag<SetTrue>, BothFlags<[], [ClangOption, CLOption, DXCOption]>>,
Group<g_flags_Group>;
def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>,
Visibility<[ClangOption, CLOption, DXCOption]>;
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>;
def gsplit_dwarf_EQ : Joined<["-"], "gsplit-dwarf=">, Group<g_flags_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<g_flags_Group>,
Visibility<[ClangOption, CLOption, DXCOption]>;
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>;
def gtemplate_alias : Flag<["-"], "gtemplate-alias">, Group<g_flags_Group>, Visibility<[ClangOption, CC1Option]>;
def gno_template_alias : Flag<["-"], "gno-template-alias">, Group<g_flags_Group>, Visibility<[ClangOption]>;
def gsimple_template_names : Flag<["-"], "gsimple-template-names">, Group<g_flags_Group>;
Expand Down Expand Up @@ -8405,7 +8405,7 @@ def main_file_name : Separate<["-"], "main-file-name">,
MarshallingInfoString<CodeGenOpts<"MainFileName">>;
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<CodeGenOpts<"SplitDwarfOutput">>;

let Visibility = [CC1Option, FC1Option] in {
Expand Down Expand Up @@ -8437,6 +8437,10 @@ def dependent_lib : Joined<["--"], "dependent-lib=">,
HelpText<"Add dependent library">,
MarshallingInfoStringVector<CodeGenOpts<"DependentLibraries">>;

def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
HelpText<"Name of the split dwarf debug info file to encode in the object file">,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this the first time around. I know that is already existed, but the wording is a bit unclear to me. Is the split dwarf debug info file actually encoded e.g. converted to base64 or something, into the object file? Is it "embedded" in the object file? Or is it something else?

It could be that I have misunderstood it. We don't have to do anything about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some background on how this works. Split dwarf means that part of the dwarf which don't need relocations are put in separate sections (generally they have .dwo in the name). These sections could be put in the same object file (-gsplit-dwarf=single) with rest of the sections or in separate file (-gslit-dwarf=split).

This help string could certainly be improved. I will try to do that in a separate PR as it will need broader agreement on the wording.

MarshallingInfoString<CodeGenOpts<"SplitDwarfFile">>;

} // let Visibility = [CC1Option, FC1Option]

let Visibility = [CC1Option] in {
Expand All @@ -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<LangOpts<"ExternCNoUnwind">>;
def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
HelpText<"Name of the split dwarf debug info file to encode in the object file">,
MarshallingInfoString<CodeGenOpts<"SplitDwarfFile">>;
def fno_wchar : Flag<["-"], "fno-wchar">,
HelpText<"Disable C++ builtin type wchar_t">,
MarshallingInfoNegativeFlag<LangOpts<"WChar">, cplusplus.KeyPath>,
Expand Down
31 changes: 0 additions & 31 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Driver/ToolChains/Clang.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
54 changes: 49 additions & 5 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to compare to nullptr here?

Suggested change
bool hasDwarfNArg = getDwarfNArg(Args) != nullptr;
bool hasDwarfNArg = getDwarfNArg(Args);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly necessary no because nullptr will be 0==false, but I think this is easier to understand at a glance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I added those for readability but have no strong opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. I don't have any strong opinion either way. We can leave it as it is.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should warn in cases where split dwarf cannot be done instead of silently ignoring?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was sort of following what clang was doing here. But happy to add a warning if you think that is better course of action.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following clang is good and I don't feel too strongly about it but the warnings won't be hard to add and our code structure already deviates from clang a bit anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a warning and updated the test accordingly.

}

if (!isa<AssembleJobAction>(JA) && !isa<CompileJobAction>(JA) &&
isa<BackendJobAction>(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,
Expand Down Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/ToolChains/Flang.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions flang/include/flang/Frontend/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
18 changes: 17 additions & 1 deletion flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<llvm::ToolOutputFile> dwoOS;
if (!codeGenOpts.SplitDwarfOutput.empty()) {
std::error_code ec;
dwoOS = std::make_unique<llvm::ToolOutputFile>(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");
Expand All @@ -909,6 +921,9 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
// Run the passes
codeGenPasses.run(llvmModule);

if (dwoOS)
dwoOS->keep();

// Cleanup
delete tlii;
}
Expand Down Expand Up @@ -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();

Expand Down
44 changes: 44 additions & 0 deletions flang/test/Driver/split-debug.f90
Original file line number Diff line number Diff line change
@@ -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'
21 changes: 21 additions & 0 deletions flang/test/Integration/debug-split-dwarf.f90
Original file line number Diff line number Diff line change
@@ -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