diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -51,7 +51,8 @@ llvm::LLVMContext *VMContext; bool OwnsVMContext; - std::unique_ptr loadModule(llvm::MemoryBufferRef MBRef); + std::vector> + loadModule(llvm::MemoryBufferRef MBRef); /// Load bitcode modules to link into our module from the options. bool loadLinkModules(CompilerInstance &CI); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -1107,26 +1107,59 @@ return std::move(Result); } -std::unique_ptr +std::vector> CodeGenAction::loadModule(MemoryBufferRef MBRef) { CompilerInstance &CI = getCompilerInstance(); SourceManager &SM = CI.getSourceManager(); + std::vector> Result; + + if (!llvm::isBitcode((const unsigned char *)MBRef.getBufferStart(), + (const unsigned char *)MBRef.getBufferEnd())) { + llvm::SMDiagnostic Err; + std::unique_ptr M = parseIR(MBRef, Err, *VMContext); + if (!M) { + // Translate from the diagnostic info to the SourceManager location if + // available. + // TODO: Unify this with ConvertBackendLocation() + SourceLocation Loc; + if (Err.getLineNo() > 0) { + assert(Err.getColumnNo() >= 0); + Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()), + Err.getLineNo(), Err.getColumnNo() + 1); + } + + // Strip off a leading diagnostic code if there is one. + StringRef Msg = Err.getMessage(); + if (Msg.startswith("error: ")) + Msg = Msg.substr(7); + + unsigned DiagID = + CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); + + CI.getDiagnostics().Report(Loc, DiagID) << Msg; + return {}; + } + + Result.push_back(std::move(M)); + return Result; + } + + auto DiagErrors = [&](Error E) -> std::vector> { + unsigned DiagID = + CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); + handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { + CI.getDiagnostics().Report(DiagID) << EIB.message(); + }); + return {}; + }; + // For ThinLTO backend invocations, ensure that the context // merges types based on ODR identifiers. We also need to read // the correct module out of a multi-module bitcode file. if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) { VMContext->enableDebugTypeODRUniquing(); - auto DiagErrors = [&](Error E) -> std::unique_ptr { - unsigned DiagID = - CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); - handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { - CI.getDiagnostics().Report(DiagID) << EIB.message(); - }); - return {}; - }; - Expected> BMsOrErr = getBitcodeModuleList(MBRef); if (!BMsOrErr) return DiagErrors(BMsOrErr.takeError()); @@ -1138,43 +1171,33 @@ if (!Bm) { auto M = std::make_unique("empty", *VMContext); M->setTargetTriple(CI.getTargetOpts().Triple); - return M; + Result.push_back(std::move(M)); + return Result; } Expected> MOrErr = Bm->parseModule(*VMContext); if (!MOrErr) return DiagErrors(MOrErr.takeError()); - return std::move(*MOrErr); + Result.push_back(std::move(MOrErr.get())); + return Result; } // Load bitcode modules to link with, if we need to. if (loadLinkModules(CI)) - return nullptr; - - llvm::SMDiagnostic Err; - if (std::unique_ptr M = parseIR(MBRef, Err, *VMContext)) - return M; - - // Translate from the diagnostic info to the SourceManager location if - // available. - // TODO: Unify this with ConvertBackendLocation() - SourceLocation Loc; - if (Err.getLineNo() > 0) { - assert(Err.getColumnNo() >= 0); - Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()), - Err.getLineNo(), Err.getColumnNo() + 1); - } + return {}; - // Strip off a leading diagnostic code if there is one. - StringRef Msg = Err.getMessage(); - if (Msg.startswith("error: ")) - Msg = Msg.substr(7); + Expected> BMsOrErr = getBitcodeModuleList(MBRef); + if (!BMsOrErr) + return DiagErrors(BMsOrErr.takeError()); - unsigned DiagID = - CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0"); + for (auto BM : BMsOrErr.get()) { + auto M = BM.parseModule(*VMContext); + if (!M) + return DiagErrors(M.takeError()); + Result.push_back(std::move(M.get())); + } - CI.getDiagnostics().Report(Loc, DiagID) << Msg; - return {}; + return Result; } void CodeGenAction::ExecuteAction() { @@ -1188,10 +1211,7 @@ CompilerInstance &CI = getCompilerInstance(); auto &CodeGenOpts = CI.getCodeGenOpts(); auto &Diagnostics = CI.getDiagnostics(); - std::unique_ptr OS = - GetOutputStream(CI, getCurrentFileOrBufferName(), BA); - if (BA != Backend_EmitNothing && !OS) - return; + const TargetOptions &TargetOpts = CI.getTargetOpts(); SourceManager &SM = CI.getSourceManager(); FileID FID = SM.getMainFileID(); @@ -1199,67 +1219,87 @@ if (!MainFile) return; - TheModule = loadModule(*MainFile); - if (!TheModule) - return; + std::vector> Modules = loadModule(*MainFile); + + for (size_t I = 0; I < Modules.size(); ++I) { + llvm::Module *TheModule = Modules[I].get(); + llvm::StringRef OutputPath = getCurrentFileOrBufferName(); + std::unique_ptr OS = nullptr; + if (Modules.size() > 1) { + std::string FrontendPath = CI.getFrontendOpts().OutputFile; + if (!FrontendPath.empty()) + OutputPath = FrontendPath; + llvm::SmallString<16> Ext = llvm::sys::path::extension(OutputPath); + llvm::SmallString<128> TmpName = OutputPath.drop_back(Ext.size()); + TmpName += "."; + TmpName += std::to_string(I); + TmpName += ".ll"; + OS = CI.createOutputFile(TmpName, false, false, + CI.getFrontendOpts().UseTemporary); + } else { + OS = GetOutputStream(CI, OutputPath, BA); + } - const TargetOptions &TargetOpts = CI.getTargetOpts(); - if (TheModule->getTargetTriple() != TargetOpts.Triple) { - Diagnostics.Report(SourceLocation(), diag::warn_fe_override_module) - << TargetOpts.Triple; - TheModule->setTargetTriple(TargetOpts.Triple); - } + if (BA == Backend_EmitNothing || !OS) + return; - EmbedObject(TheModule.get(), CodeGenOpts, Diagnostics); - EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile); - - LLVMContext &Ctx = TheModule->getContext(); - - // Restore any diagnostic handler previously set before returning from this - // function. - struct RAII { - LLVMContext &Ctx; - std::unique_ptr PrevHandler = Ctx.getDiagnosticHandler(); - ~RAII() { Ctx.setDiagnosticHandler(std::move(PrevHandler)); } - } _{Ctx}; - - // Set clang diagnostic handler. To do this we need to create a fake - // BackendConsumer. - BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), - CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), - CI.getCodeGenOpts(), CI.getTargetOpts(), - CI.getLangOpts(), TheModule.get(), - std::move(LinkModules), *VMContext, nullptr); - - // Link in each pending link module. - if (Result.LinkInModules(&*TheModule)) - return; + if (TheModule->getTargetTriple() != TargetOpts.Triple) { + Diagnostics.Report(SourceLocation(), diag::warn_fe_override_module) + << TargetOpts.Triple; + TheModule->setTargetTriple(TargetOpts.Triple); + } - // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be - // true here because the valued names are needed for reading textual IR. - Ctx.setDiscardValueNames(false); - Ctx.setDiagnosticHandler( - std::make_unique(CodeGenOpts, &Result)); + EmbedObject(TheModule, CodeGenOpts, Diagnostics); + EmbedBitcode(TheModule, CodeGenOpts, *MainFile); - Expected> OptRecordFileOrErr = - setupLLVMOptimizationRemarks( - Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, - CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, - CodeGenOpts.DiagnosticsHotnessThreshold); + LLVMContext &Ctx = TheModule->getContext(); - if (Error E = OptRecordFileOrErr.takeError()) { - reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts); - return; + // Restore any diagnostic handler previously set before returning from this + // function. + struct RAII { + LLVMContext &Ctx; + std::unique_ptr PrevHandler = + Ctx.getDiagnosticHandler(); + ~RAII() { Ctx.setDiagnosticHandler(std::move(PrevHandler)); } + } _{Ctx}; + + // Set clang diagnostic handler. To do this we need to create a fake + // BackendConsumer. + BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), + CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), + CI.getCodeGenOpts(), TargetOpts, + CI.getLangOpts(), TheModule, std::move(LinkModules), + *VMContext, nullptr); + // Link in each pending link module. + if (Result.LinkInModules(&*TheModule)) + return; + + // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be + // true here because the valued names are needed for reading textual IR. + Ctx.setDiscardValueNames(false); + Ctx.setDiagnosticHandler( + std::make_unique(CodeGenOpts, &Result)); + + Expected> OptRecordFileOrErr = + setupLLVMOptimizationRemarks( + Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, + CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, + CodeGenOpts.DiagnosticsHotnessThreshold); + + if (Error E = OptRecordFileOrErr.takeError()) { + reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts); + return; + } + std::unique_ptr OptRecordFile = + std::move(*OptRecordFileOrErr); + + EmitBackendOutput( + Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, TargetOpts, + CI.getLangOpts(), CI.getTarget().getDataLayoutString(), TheModule, BA, + CI.getFileManager().getVirtualFileSystemPtr(), std::move(OS)); + if (OptRecordFile) + OptRecordFile->keep(); } - std::unique_ptr OptRecordFile = - std::move(*OptRecordFileOrErr); - - EmitBackendOutput( - Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, TargetOpts, - CI.getLangOpts(), CI.getTarget().getDataLayoutString(), TheModule.get(), - BA, CI.getFileManager().getVirtualFileSystemPtr(), std::move(OS)); - if (OptRecordFile) - OptRecordFile->keep(); } // diff --git a/clang/test/Frontend/split-lto-ir-support.cpp b/clang/test/Frontend/split-lto-ir-support.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/split-lto-ir-support.cpp @@ -0,0 +1,29 @@ +// RUN: %clang -O0 -Xclang -mconstructor-aliases -c -flto=thin -Xclang -fsplit-lto-unit -ffunction-sections %s -o %t0.bc +// RUN: rm -rf %t1.d && mkdir -p %t1.d +// RUN: %clang -S -emit-llvm %t0.bc -o %t1.d/split-lto-ir-support.ll +// RUN: %clang -S %t1.d/split-lto-ir-support.0.ll %t1.d/split-lto-ir-support.1.ll +// RUN: FileCheck c(0); +}