Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -105,6 +105,8 @@ std::map DLLOrder; SymbolBody *DelayLoadHelper = nullptr; + bool SaveTemps = false; + // Used for SafeSEH. Symbol *SEHTable = nullptr; Symbol *SEHCount = nullptr; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -622,6 +622,9 @@ } } + if (Args.hasArg(OPT_lldsavetemps)) + Config->SaveTemps = true; + // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); Index: COFF/LTO.cpp =================================================================== --- COFF/LTO.cpp +++ COFF/LTO.cpp @@ -54,6 +54,14 @@ }); } +static void saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error("cannot create " + Path + ": " + EC.message()); + OS << Buffer; +} + static std::unique_ptr createLTO() { lto::Config Conf; Conf.Options = InitTargetOptionsFromCodeGenFlags(); @@ -61,6 +69,9 @@ Conf.DisableVerify = true; Conf.DiagHandler = diagnosticHandler; Conf.OptLevel = Config->LTOOptLevel; + if (Config->SaveTemps) + checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", + /*UseInputModulePath*/ true)); lto::ThinBackend Backend; if (Config->LTOJobs != -1u) Backend = lto::createInProcessThinBackend(Config->LTOJobs); @@ -116,8 +127,16 @@ })); std::vector Ret; - for (unsigned I = 0; I != MaxTasks; ++I) - if (!Buff[I].empty()) - Ret.emplace_back(Buff[I].data(), Buff[I].size()); + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buff[I].empty()) + continue; + if (Config->SaveTemps) { + if (I == 0) + saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); + else + saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); + } + Ret.emplace_back(Buff[I].data(), Buff[I].size()); + } return Ret; } Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -28,6 +28,8 @@ def implib : P<"implib", "Import library name">; def libpath : P<"libpath", "Additional library search path">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; +def lldsavetemps : F<"lldsavetemps">, + HelpText<"Save temporary files instead of deleting them">; def machine : P<"machine", "Specify target platform">; def merge : P<"merge", "Combine sections">; def mllvm : P<"mllvm", "Options to pass to LLVM">; Index: test/COFF/savetemps.ll =================================================================== --- /dev/null +++ test/COFF/savetemps.ll @@ -0,0 +1,24 @@ +; RUN: rm -f %T/savetemps.* +; RUN: llvm-as -o %T/savetemps.obj %s +; RUN: lld-link /out:%T/savetemps.exe /entry:main /subsystem:console %T/savetemps.obj +; RUN: not llvm-dis -o - %T/savetemps.exe.0.0.preopt.bc +; RUN: not llvm-dis -o - %T/savetemps.exe.0.2.internalize.bc +; RUN: not llvm-dis -o - %T/savetemps.exe.0.4.opt.bc +; RUN: not llvm-dis -o - %T/savetemps.exe.0.5.precodegen.bc +; RUN: not llvm-objdump -s %T/savetemps.exe.lto.obj +; RUN: lld-link /lldsavetemps /out:%T/savetemps.exe /entry:main /subsystem:console %T/savetemps.obj +; RUN: llvm-dis -o - %T/savetemps.exe.0.0.preopt.bc | FileCheck %s +; RUN: llvm-dis -o - %T/savetemps.exe.0.2.internalize.bc | FileCheck %s +; RUN: llvm-dis -o - %T/savetemps.exe.0.4.opt.bc | FileCheck %s +; RUN: llvm-dis -o - %T/savetemps.exe.0.5.precodegen.bc | FileCheck %s +; RUN: llvm-objdump -s %T/savetemps.exe.lto.obj | FileCheck --check-prefix=CHECK-OBJDUMP %s + +; CHECK: define i32 @main() +; CHECK-OBJDUMP: file format COFF + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define i32 @main() { + ret i32 0 +}