diff options
author | Jacob Lambert <jacob.lambert@amd.com> | 2024-02-14 10:39:21 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-14 10:39:21 -0800 |
commit | 6d4ffbdfa8ff90e4ee6081ad8dbb8ec24e982a02 (patch) | |
tree | debbfdb627a498626e0e69a32a8c290c3ee6d1a5 /clang/lib/CodeGen/CodeGenAction.cpp | |
parent | 16e7d6842ef6a5c904422c6dba034e0888ea8b7b (diff) | |
download | llvm-6d4ffbdfa8ff90e4ee6081ad8dbb8ec24e982a02.zip llvm-6d4ffbdfa8ff90e4ee6081ad8dbb8ec24e982a02.tar.gz llvm-6d4ffbdfa8ff90e4ee6081ad8dbb8ec24e982a02.tar.bz2 |
[clang][CodeGen] Shift relink option implementation away from module cloning (#81693)
We recently implemented a new option allowing relinking of bitcode
modules via the "-mllvm -relink-builtin-bitcode-postop"
option.
This implementation relied on llvm::CloneModule() in order to pass
copies to modules and preserve the original modules for later relinking.
However, cloning modules has been found to be prohibitively expensive,
significantly increasing compilation time for large bitcode libraries.
In this patch, we shift the relink option implementation to instead link
the original modules initially, and reload modules from the file system
if relinking is requested. This approach results in significantly
reduced overhead.
We accomplish this by creating a new ReloadModules() routine that can be
called from a BackendConsumer class, to mimic the behavior of
ASTConsumer's loadLinkModules(), but without access to the
CompilerInstance.
Because loading the bitcodes from the filesystem requires access to the
FileManager class, we also forward a reference to the CompilerInstance
class to the BackendConsumer. This mirrors what is already done for
several CompilerInstance members, such as TargetOptions and
CodeGenOptions.
Finally, we needed to add a const specifier to the
FileManager::getBufferForFile() routine to allow it to be called using
the const reference returned from CompilerInstance::getFileManager()
Diffstat (limited to 'clang/lib/CodeGen/CodeGenAction.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 161 |
1 files changed, 84 insertions, 77 deletions
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index f8038497..ab08a87 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -109,56 +109,52 @@ static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, }); } -BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - const LangOptions &LangOpts, - const std::string &InFile, - SmallVector<LinkModule, 4> LinkModules, - std::unique_ptr<raw_pwrite_stream> OS, - LLVMContext &C, - CoverageSourceInfo *CoverageInfo) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, - PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)) { - TimerIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; +BackendConsumer::BackendConsumer( + BackendAction Action, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, const LangOptions &LangOpts, + const FileManager &FileMgr, const std::string &InFile, + SmallVector<LinkModule, 4> LinkModules, + std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C, + CoverageSourceInfo *CoverageInfo) + : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), + CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), + FileMgr(FileMgr), AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), + LLVMIRGenerationRefCount(0), + Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, + PPOpts, CodeGenOpts, C, CoverageInfo)), + LinkModules(std::move(LinkModules)) { + TimerIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; } // This constructor is used in installing an empty BackendConsumer // to use the clang diagnostic handler for IR input files. It avoids // initializing the OS field. -BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - const LangOptions &LangOpts, - llvm::Module *Module, - SmallVector<LinkModule, 4> LinkModules, - LLVMContext &C, - CoverageSourceInfo *CoverageInfo) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, - PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)), CurLinkModule(Module) { - TimerIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; +BackendConsumer::BackendConsumer( + BackendAction Action, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, const LangOptions &LangOpts, + const FileManager &FileMgr, llvm::Module *Module, + SmallVector<LinkModule, 4> LinkModules, LLVMContext &C, + CoverageSourceInfo *CoverageInfo) + : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), + CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), + FileMgr(FileMgr), Context(nullptr), FS(VFS), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), + LLVMIRGenerationRefCount(0), + Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, PPOpts, + CodeGenOpts, C, CoverageInfo)), + LinkModules(std::move(LinkModules)), CurLinkModule(Module) { + TimerIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; } llvm::Module* BackendConsumer::getModule() const { @@ -233,9 +229,37 @@ void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) { HandleTopLevelDecl(D); } +bool BackendConsumer::ReloadModules(llvm::Module *M) { + for (const CodeGenOptions::BitcodeFileToLink &F : + CodeGenOpts.LinkBitcodeFiles) { + auto BCBuf = FileMgr.getBufferForFile(F.Filename); + if (!BCBuf) { + Diags.Report(diag::err_cannot_open_file) + << F.Filename << BCBuf.getError().message(); + LinkModules.clear(); + return true; + } + + LLVMContext &Ctx = getModule()->getContext(); + Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = + getOwningLazyBitcodeModule(std::move(*BCBuf), Ctx); + + if (!ModuleOrErr) { + handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) { + Diags.Report(diag::err_cannot_open_file) << F.Filename << EIB.message(); + }); + LinkModules.clear(); + return true; + } + LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs, + F.Internalize, F.LinkFlags}); + } + + return false; // success +} + // Links each entry in LinkModules into our module. Returns true on error. bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) { - for (auto &LM : LinkModules) { assert(LM.Module && "LinkModule does not actually have a module"); @@ -257,37 +281,19 @@ bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) { CurLinkModule = LM.Module.get(); bool Err; - auto DoLink = [&](auto &Mod) { - if (LM.Internalize) { - Err = Linker::linkModules( - *M, std::move(Mod), LM.LinkFlags, - [](llvm::Module &M, const llvm::StringSet<> &GVS) { - internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { - return !GV.hasName() || (GVS.count(GV.getName()) == 0); - }); + if (LM.Internalize) { + Err = Linker::linkModules( + *M, std::move(LM.Module), LM.LinkFlags, + [](llvm::Module &M, const llvm::StringSet<> &GVS) { + internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { + return !GV.hasName() || (GVS.count(GV.getName()) == 0); }); - } else - Err = Linker::linkModules(*M, std::move(Mod), LM.LinkFlags); - }; - - // Create a Clone to move to the linker, which preserves the original - // linking modules, allowing them to be linked again in the future - if (ClRelinkBuiltinBitcodePostop) { - // TODO: If CloneModule() is updated to support cloning of unmaterialized - // modules, we can remove this - if (Error E = CurLinkModule->materializeAll()) - return false; - - std::unique_ptr<llvm::Module> Clone = llvm::CloneModule(*LM.Module); - - DoLink(Clone); - } - // Otherwise we can link (and clean up) the original modules - else { - DoLink(LM.Module); - } + }); + } else + Err = Linker::linkModules(*M, std::move(LM.Module), LM.LinkFlags); } + LinkModules.clear(); return false; // success } @@ -1037,8 +1043,9 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::unique_ptr<BackendConsumer> Result(new BackendConsumer( BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), - CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile), - std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo)); + CI.getTargetOpts(), CI.getLangOpts(), CI.getFileManager(), + std::string(InFile), std::move(LinkModules), std::move(OS), *VMContext, + CoverageInfo)); BEConsumer = Result.get(); // Enable generating macro debug info only when debug info is not disabled and @@ -1199,7 +1206,7 @@ void CodeGenAction::ExecuteAction() { BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(), CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), - CI.getLangOpts(), TheModule.get(), + CI.getLangOpts(), CI.getFileManager(), TheModule.get(), std::move(LinkModules), *VMContext, nullptr); // Link in each pending link module. |