Index: include/llvm/LTO/Config.h =================================================================== --- include/llvm/LTO/Config.h +++ include/llvm/LTO/Config.h @@ -73,6 +73,12 @@ /// Sample PGO profile path. std::string SampleProfile; + /// The directory to store .dwo files when using ThinLTO. + std::string DWO_Dir; + + /// The objcopy binary used to extract dwo files. + std::string Objcopy; + /// Optimization remarks file path. std::string RemarksFilename = ""; Index: include/llvm/LTO/LTO.h =================================================================== --- include/llvm/LTO/LTO.h +++ include/llvm/LTO/LTO.h @@ -162,8 +162,11 @@ /// destructor. class NativeObjectStream { public: - NativeObjectStream(std::unique_ptr<raw_pwrite_stream> OS) : OS(std::move(OS)) {} + NativeObjectStream(std::unique_ptr<raw_pwrite_stream> OS, + std::string FileName=std::string()) + : OS(std::move(OS)), FileName(FileName) {} std::unique_ptr<raw_pwrite_stream> OS; + std::string FileName; virtual ~NativeObjectStream() = default; }; Index: lib/LTO/LTOBackend.cpp =================================================================== --- lib/LTO/LTOBackend.cpp +++ lib/LTO/LTOBackend.cpp @@ -30,6 +30,8 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Target/TargetMachine.h" @@ -279,16 +281,17 @@ return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } -void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, +std::string codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, unsigned Task, Module &Mod) { if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) - return; + return std::string(); auto Stream = AddStream(Task); legacy::PassManager CodeGenPasses; if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType)) report_fatal_error("Failed to setup codegen"); CodeGenPasses.run(Mod); + return Stream->FileName; } void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, @@ -431,6 +434,11 @@ std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod); + if (!Conf.DWO_Dir.empty()) { + SmallString<1024> DwarfFile(Conf.DWO_Dir); + llvm::sys::path::append(DwarfFile, Mod.getModuleIdentifier() + ".dwo"); + TM->Options.MCOptions.SplitDwarfFile = DwarfFile.str().str(); + } if (Conf.CodeGenOnly) { codegen(Conf, TM.get(), AddStream, Task, Mod); return Error::success(); @@ -476,6 +484,28 @@ /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) return Error::success(); - codegen(Conf, TM.get(), AddStream, Task, Mod); + std::string output_file = codegen(Conf, TM.get(), AddStream, Task, Mod); + if (!Conf.DWO_Dir.empty()) { + SmallString<1024> DwarfFile(Conf.DWO_Dir); + sys::path::append(DwarfFile, Mod.getModuleIdentifier() + ".dwo"); + sys::path::remove_filename(DwarfFile); + std::error_code EC = llvm::sys::fs::create_directories(DwarfFile.str()); + if (EC) { + errs() << "Failed to create directory " << DwarfFile.c_str() << "\n"; + return errorCodeToError(EC); + } + SmallVector<const char*, 8> ExtractArgs, StripArgs; + ExtractArgs.push_back(Conf.Objcopy.c_str()); + ExtractArgs.push_back("--extract-dwo"); + ExtractArgs.push_back(output_file.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(output_file.c_str()); + StripArgs.push_back(nullptr); + sys::ExecuteAndWait(Conf.Objcopy, ExtractArgs.data()); + sys::ExecuteAndWait(Conf.Objcopy, StripArgs.data()); + } return Error::success(); } Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ tools/gold/gold-plugin.cpp @@ -185,6 +185,10 @@ 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 @@ } 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 @@ if (!options::sample_profile.empty()) Conf.SampleProfile = options::sample_profile; + if (!options::dwo_dir.empty()) + Conf.DWO_Dir = 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; @@ -927,7 +941,8 @@ int FD = getOutputFileName(Filename, /* TempOutFile */ !SaveTemps, Files[Task].first, Task); return llvm::make_unique<lto::NativeObjectStream>( - llvm::make_unique<llvm::raw_fd_ostream>(FD, true)); + llvm::make_unique<llvm::raw_fd_ostream>(FD, true), + Files[Task].first.str().str()); }; auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {