blob: f9f44a45177c013537ab85237c310edaa0956a72 [file] [log] [blame]
diff --git a/include/llvm/LTO/Config.h b/include/llvm/LTO/Config.h
index 4bd981c090b..21ad781ad95 100644
--- a/include/llvm/LTO/Config.h
+++ b/include/llvm/LTO/Config.h
@@ -73,6 +73,12 @@ struct Config {
/// Sample PGO profile path.
std::string SampleProfile;
+ /// The directory to store .dwo files.
+ std::string DwoDir;
+
+ /// The objcopy binary used to extract dwo files.
+ std::string Objcopy;
+
/// Optimization remarks file path.
std::string RemarksFilename = "";
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
index e9ac314e7c8..ec46af2a759 100644
--- a/lib/LTO/LTO.cpp
+++ b/lib/LTO/LTO.cpp
@@ -136,6 +136,8 @@ static void computeCacheKey(
AddString(Conf.AAPipeline);
AddString(Conf.OverrideTriple);
AddString(Conf.DefaultTriple);
+ if (!Conf.DwoDir.empty())
+ AddString(Conf.DwoDir);
// Include the hash for the current module
auto ModHash = Index.getModuleHash(ModuleID);
diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp
index 074a3986015..991e2f380a8 100644
--- a/lib/LTO/LTOBackend.cpp
+++ b/lib/LTO/LTOBackend.cpp
@@ -30,6 +30,10 @@
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Target/TargetMachine.h"
@@ -279,11 +283,74 @@ bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
}
+void codegenWithSplitDwarf(Config &Conf, TargetMachine *TM,
+ AddStreamFn AddStream, unsigned Task, Module &Mod) {
+ SmallString<128> TempFile;
+ int FD = -1;
+ if (auto EC =
+ sys::fs::createTemporaryFile("lto-llvm-fission", "o", FD, TempFile))
+ report_fatal_error("Could not create temporary file " +
+ TempFile.str() + ": " + EC.message());
+ llvm::raw_fd_ostream OS(FD, true);
+ SmallString<1024> DwarfFile(Conf.DwoDir);
+ std::string DwoName = sys::path::filename(Mod.getModuleIdentifier()).str() +
+ "-" + std::to_string(Task) + "-";
+ size_t index = TempFile.str().rfind("lto-llvm-fission");
+ StringRef TempID = TempFile.str().substr(index + 17, 6);
+ DwoName += TempID.str() + ".dwo";
+ sys::path::append(DwarfFile, DwoName);
+ TM->Options.MCOptions.SplitDwarfFile = DwarfFile.str().str();
+
+ legacy::PassManager CodeGenPasses;
+ if (TM->addPassesToEmitFile(CodeGenPasses, OS, Conf.CGFileType))
+ report_fatal_error("Failed to setup codegen");
+ CodeGenPasses.run(Mod);
+
+ if (auto EC = llvm::sys::fs::create_directories(Conf.DwoDir))
+ report_fatal_error("Failed to create directory " +
+ Conf.DwoDir + ": " + EC.message());
+
+ SmallVector<const char*, 5> ExtractArgs, StripArgs;
+ ExtractArgs.push_back(Conf.Objcopy.c_str());
+ ExtractArgs.push_back("--extract-dwo");
+ ExtractArgs.push_back(TempFile.c_str());
+ ExtractArgs.push_back(TM->Options.MCOptions.SplitDwarfFile.c_str());
+ ExtractArgs.push_back(nullptr);
+ StripArgs.push_back(Conf.Objcopy.c_str());
+ StripArgs.push_back("--strip-dwo");
+ StripArgs.push_back(TempFile.c_str());
+ StripArgs.push_back(nullptr);
+
+ if (auto Ret = sys::ExecuteAndWait(Conf.Objcopy, ExtractArgs.data())) {
+ report_fatal_error("Failed to extract dwo from " + TempFile.str() +
+ ". Exit code " + std::to_string(Ret));
+ }
+ if (auto Ret = sys::ExecuteAndWait(Conf.Objcopy, StripArgs.data())) {
+ report_fatal_error("Failed to strip dwo from " + TempFile.str() +
+ ". Exit code " + std::to_string(Ret));
+ }
+
+ auto Stream = AddStream(Task);
+ auto Buffer = MemoryBuffer::getFile(TempFile);
+ if (auto EC = Buffer.getError())
+ report_fatal_error("Failed to load file " +
+ TempFile.str() + ": " + EC.message());
+ *Stream->OS << Buffer.get()->getBuffer();
+ if (auto EC = sys::fs::remove(TempFile))
+ report_fatal_error("Failed to delete file " +
+ TempFile.str() + ": " + EC.message());
+}
+
void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream,
unsigned Task, Module &Mod) {
if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
return;
+ if (!Conf.DwoDir.empty()) {
+ codegenWithSplitDwarf(Conf, TM, AddStream, Task, Mod);
+ return;
+ }
+
auto Stream = AddStream(Task);
legacy::PassManager CodeGenPasses;
if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType))
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index 19804a1ff12..08a872e9176 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -185,6 +185,10 @@ namespace options {
static std::string sample_profile;
// New pass manager
static bool new_pass_manager = false;
+ // Objcopy to debug fission.
+ static std::string objcopy;
+ // Directory to store the .dwo files.
+ static std::string dwo_dir;
static void process_plugin_option(const char *opt_)
{
@@ -243,10 +247,14 @@ namespace options {
} else if (opt == "disable-verify") {
DisableVerify = true;
} else if (opt.startswith("sample-profile=")) {
- sample_profile= opt.substr(strlen("sample-profile="));
+ sample_profile = opt.substr(strlen("sample-profile="));
} else if (opt == "new-pass-manager") {
new_pass_manager = true;
- } else {
+ } else if (opt.startswith("objcopy=")) {
+ objcopy = opt.substr(strlen("objcopy="));
+ } else if (opt.startswith("dwo_dir=")) {
+ dwo_dir = opt.substr(strlen("dwo_dir="));
+ }else {
// Save this option to pass to the code generator.
// ParseCommandLineOptions() expects argv[0] to be program name. Lazily
// add that.
@@ -803,6 +811,12 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
if (!options::sample_profile.empty())
Conf.SampleProfile = options::sample_profile;
+ if (!options::dwo_dir.empty())
+ Conf.DwoDir = options::dwo_dir;
+
+ if (!options::objcopy.empty())
+ Conf.Objcopy = options::objcopy;
+
// Use new pass manager if set in driver
Conf.UseNewPM = options::new_pass_manager;
--- a/tools/clang/docs/ClangCommandLineReference.rst
+++ b/tools/clang/docs/ClangCommandLineReference.rst
@@ -2587,6 +2587,8 @@ Debug information flags
.. option:: -gstrict-dwarf, -gno-strict-dwarf
+.. option:: -glto-dwo-dir=<arg>
+
.. option:: -gz
DWARF debug sections compression type
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 6925157d2e..83a4f5bc86 100644
--- a/tools/clang/include/clang/Driver/Options.td
+++ b/tools/clang/include/clang/Driver/Options.td
@@ -1700,6 +1700,7 @@ def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>;
def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[CoreOption]>;
def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>, Flags<[CoreOption]>;
def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>;
+def glto_dwo_dir_EQ : Joined<["-"], "glto-dwo-dir=">, Group<g_flags_Group>;
def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>;
def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>;
def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>,
diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
index 17ab82e97c..67992a655e 100644
--- a/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -415,6 +415,16 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
if (IsThinLTO)
CmdArgs.push_back("-plugin-opt=thinlto");
+ if (Arg *A = Args.getLastArg(options::OPT_glto_dwo_dir_EQ)) {
+ const char *Objcopy =
+ Args.MakeArgString(ToolChain.GetProgramPath(CLANG_DEFAULT_OBJCOPY));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=objcopy=") + Objcopy));
+ StringRef DWO_Dir = A->getValue();
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") + DWO_Dir));
+ }
+
if (unsigned Parallelism = getLTOParallelism(Args, D))
CmdArgs.push_back(
Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism)));