Index: lib/Driver/ToolChains/Ananas.cpp =================================================================== --- lib/Driver/ToolChains/Ananas.cpp +++ lib/Driver/ToolChains/Ananas.cpp @@ -103,8 +103,11 @@ {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4589,31 +4589,10 @@ } // Setup statistics file output. - if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { - StringRef SaveStats = A->getValue(); - - SmallString<128> StatsFile; - bool DoSaveStats = false; - if (SaveStats == "obj") { - if (Output.isFilename()) { - StatsFile.assign(Output.getFilename()); - llvm::sys::path::remove_filename(StatsFile); - } - DoSaveStats = true; - } else if (SaveStats == "cwd") { - DoSaveStats = true; - } else { - D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; - } - - if (DoSaveStats) { - StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); - llvm::sys::path::append(StatsFile, BaseName); - llvm::sys::path::replace_extension(StatsFile, "stats"); - CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + - StatsFile)); - } - } + SmallString<128> StatsFile = + std::move(getStatsFileName(Args, Output, Input, D)); + if (!StatsFile.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Index: lib/Driver/ToolChains/CloudABI.cpp =================================================================== --- lib/Driver/ToolChains/CloudABI.cpp +++ lib/Driver/ToolChains/CloudABI.cpp @@ -75,8 +75,11 @@ {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); Index: lib/Driver/ToolChains/CommonArgs.h =================================================================== --- lib/Driver/ToolChains/CommonArgs.h +++ lib/Driver/ToolChains/CommonArgs.h @@ -60,8 +60,8 @@ const InputInfo &Output, const char *OutFile); void AddGoldPlugin(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, bool IsThinLTO, - const Driver &D); + llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, + const InputInfo &Input, bool IsThinLTO); std::tuple ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); @@ -107,6 +107,11 @@ std::vector &Features, llvm::opt::OptSpecifier Group); +/// Handles the -save-stats option and returns the filename to save statistics +/// to. +SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, + const InputInfo &Output, + const InputInfo &Input, const Driver &D); } // end namespace tools } // end namespace driver } // end namespace clang Index: lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- lib/Driver/ToolChains/CommonArgs.cpp +++ lib/Driver/ToolChains/CommonArgs.cpp @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// #include "CommonArgs.h" -#include "InputInfo.h" -#include "Hexagon.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" +#include "Hexagon.h" +#include "InputInfo.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" @@ -42,6 +42,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -370,8 +371,8 @@ } void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs, bool IsThinLTO, - const Driver &D) { + ArgStringList &CmdArgs, const InputInfo &Output, + const InputInfo &Input, bool IsThinLTO) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. @@ -416,7 +417,7 @@ if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); - if (unsigned Parallelism = getLTOParallelism(Args, D)) + if (unsigned Parallelism = getLTOParallelism(Args, ToolChain.getDriver())) CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); @@ -447,7 +448,7 @@ if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) - D.Diag(diag::err_drv_no_such_file) << FName; + ToolChain.getDriver().Diag(diag::err_drv_no_such_file) << FName; else CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); @@ -460,6 +461,12 @@ CmdArgs.push_back("-plugin-opt=new-pass-manager"); } + // Setup statistics file output. + SmallString<128> StatsFile = + std::move(getStatsFileName(Args, Output, Input, ToolChain.getDriver())); + if (!StatsFile.empty()) + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, @@ -1267,3 +1274,27 @@ Lksf << LksBuffer; } + +SmallString<128> tools::getStatsFileName(const llvm::opt::ArgList &Args, + const InputInfo &Output, + const InputInfo &Input, + const Driver &D) { + const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ); + if (!A) + return {}; + + StringRef SaveStats = A->getValue(); + SmallString<128> StatsFile; + if (SaveStats == "obj" && Output.isFilename()) { + StatsFile.assign(Output.getFilename()); + llvm::sys::path::remove_filename(StatsFile); + } else if (SaveStats != "cwd") { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; + return {}; + } + + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + return std::move(StatsFile); +} Index: lib/Driver/ToolChains/FreeBSD.cpp =================================================================== --- lib/Driver/ToolChains/FreeBSD.cpp +++ lib/Driver/ToolChains/FreeBSD.cpp @@ -231,8 +231,11 @@ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -435,8 +435,11 @@ ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); Index: test/Driver/save-stats.c =================================================================== --- test/Driver/save-stats.c +++ test/Driver/save-stats.c @@ -18,3 +18,11 @@ // RUN: %clang -target x86_64-apple-darwin -save-stats=bla -c %s -### 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID // CHECK-INVALID: invalid value 'bla' in '-save-stats=bla' + +// RUN: %clang -target x86_64-linux-unknown -save-stats -flto -o obj/dir/save-stats.exe %s -### 2>&1 | FileCheck %s -check-prefix=CHECK-LTO +// CHECK-LTO: "-stats-file=save-stats.stats" +// CHECK-LTO: "-o" "obj/dir{{/|\\\\}}save-stats.exe" +// CHECK-LTO: "-plugin-opt=stats-file=save-stats.stats" + +// RUN: %clang -target x86_64-linux-unknown -save-stats=obj -flto -o obj/dir/save-stats.exe %s -### 2>&1 | FileCheck %s -check-prefix=CHECK-LTO-OBJ +// CHECK-LTO-OBJ: "-plugin-opt=stats-file=obj/dir/save-stats.stats"