diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -509,10 +509,8 @@ return UnifiedFeatures; } -template > -std::unique_ptr createLTO( - const ArgList &Args, const std::vector &Features, - ModuleHook Hook = [](size_t, const Module &) { return true; }) { +std::unique_ptr createLTO(const ArgList &Args, + const std::vector &Features) { const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); StringRef Arch = Args.getLastArgValue(OPT_arch_EQ); lto::Config Conf; @@ -566,7 +564,9 @@ return true; }; } - Conf.PostOptModuleHook = Hook; + Conf.OutputPreCodegenBitcode = Args.hasArg(OPT_embed_bitcode) || + Args.hasArg(OPT_builtin_bitcode_EQ) || + Args.hasArg(OPT_clang_backend); Conf.CGFileType = (Triple.isNVPTX() || SaveTemps) ? CGFT_AssemblyFile : CGFT_ObjectFile; @@ -639,31 +639,9 @@ // Remove all the bitcode files that we moved from the original input. llvm::erase_if(InputFiles, [](OffloadFile &F) { return !F.getBinary(); }); - // LTO Module hook to output bitcode without running the backend. - SmallVector BitcodeOutput; - auto OutputBitcode = [&](size_t, const Module &M) { - auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) + - "-jit-" + Triple.getTriple(), - "bc"); - if (!TempFileOrErr) - reportError(TempFileOrErr.takeError()); - - std::error_code EC; - raw_fd_ostream LinkedBitcode(*TempFileOrErr, EC, sys::fs::OF_None); - if (EC) - reportError(errorCodeToError(EC)); - WriteBitcodeToFile(M, LinkedBitcode); - BitcodeOutput.push_back(*TempFileOrErr); - return false; - }; - // We assume visibility of the whole program if every input file was bitcode. auto Features = getTargetFeatures(BitcodeInputFiles); - auto LTOBackend = Args.hasArg(OPT_embed_bitcode) || - Args.hasArg(OPT_builtin_bitcode_EQ) || - Args.hasArg(OPT_clang_backend) - ? createLTO(Args, Features, OutputBitcode) - : createLTO(Args, Features); + auto LTOBackend = createLTO(Args, Features); // We need to resolve the symbols so the LTO backend knows which symbols need // to be kept or can be internalized. This is a simplified symbol resolution @@ -736,9 +714,18 @@ auto AddStream = [&](size_t Task, const Twine &ModuleName) -> std::unique_ptr { + bool OutputBitcode = Args.hasArg(OPT_embed_bitcode) || + Args.hasArg(OPT_builtin_bitcode_EQ) || + Args.hasArg(OPT_clang_backend); int FD = -1; auto &TempFile = Files[Task]; - StringRef Extension = (Triple.isNVPTX() || SaveTemps) ? "s" : "o"; + StringRef Extension; + if (OutputBitcode) + Extension = "bc"; + else if (Triple.isNVPTX() || SaveTemps) + Extension = "s"; + else + Extension = "o"; std::string TaskStr = Task ? "." + std::to_string(Task) : ""; auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) + "." + @@ -747,6 +734,7 @@ if (!TempFileOrErr) reportError(TempFileOrErr.takeError()); TempFile = *TempFileOrErr; + llvm::errs() << "!!! " << TempFile << "\n"; if (std::error_code EC = sys::fs::openFileForWrite(TempFile, FD)) reportError(errorCodeToError(EC)); return std::make_unique( @@ -760,22 +748,13 @@ return createStringError(inconvertibleErrorCode(), "Errors encountered inside the LTO pipeline."); - // If we are embedding bitcode we only need the intermediate output. - bool SingleOutput = Files.size() == 1; - if (Args.hasArg(OPT_embed_bitcode)) { - if (BitcodeOutput.size() != 1 || !SingleOutput) + if (Args.hasArg(OPT_embed_bitcode)) + if (Files.size() != 1) return createStringError(inconvertibleErrorCode(), "Cannot embed bitcode with multiple files."); - OutputFiles.push_back(Args.MakeArgString(BitcodeOutput.front())); - return Error::success(); - } - // Append the new inputs to the device linker input. If the user requested an - // internalizing link we need to pass the bitcode to clang. - for (StringRef File : - Args.hasArg(OPT_clang_backend) || Args.hasArg(OPT_builtin_bitcode_EQ) - ? BitcodeOutput - : Files) + // Append the new inputs to the device linker input. + for (StringRef File : Files) OutputFiles.push_back(File); return Error::success(); diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -84,6 +84,10 @@ /// want to know a priori all possible output files. bool AlwaysEmitRegularLTOObj = false; + /// Write the pre-codegen module to the output without performing codegen. + /// Useful for post-processing on the fully linked LTO module. + bool OutputPreCodegenBitcode = false; + /// Allows non-imported definitions to get the potentially more constraining /// visibility from the prevailing definition. FromPrevailing is the default /// because it works for many binary formats. ELF can use the more optimized diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -366,6 +366,17 @@ if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; + if (Conf.OutputPreCodegenBitcode) { + Expected> StreamOrErr = + AddStream(Task, Mod.getModuleIdentifier()); + if (Error Err = StreamOrErr.takeError()) + report_fatal_error(std::move(Err)); + std::unique_ptr &Stream = *StreamOrErr; + + WriteBitcodeToFile(Mod, *Stream->OS); + return; + } + if (EmbedBitcode == LTOBitcodeEmbedding::EmbedOptimized) llvm::embedBitcodeInModule(Mod, llvm::MemoryBufferRef(), /*EmbedBitcode*/ true,