https://github.com/koparasy updated https://github.com/llvm/llvm-project/pull/229441
>From 61cd8ccff15407b06ed24c2f44901f5766318579 Mon Sep 17 00:00:00 2001 From: Konstantinos Parasyris <[email protected]> Date: Tue, 6 Oct 2026 07:42:16 -0700 Subject: [PATCH 1/2] [CIR] Make the post-CIRGen emission path independent of ASTContext NFC. The SYCL-host and CUDA/OpenMP-offload embed decisions now read CI.getLangOpts() instead of ASTContext::getLangOpts(); both refer to the same object, and CI's is populated for .cir input too. This is preliminary work towards reusing code when reading `cir` and emitting its output. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --- clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 322 ++++++++++-------- 1 file changed, 179 insertions(+), 143 deletions(-) diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 71a7a17146af3..12dbbf05bd3e6 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -25,6 +25,7 @@ #include "clang/CodeGen/ModuleLinker.h" #include "clang/CodeGenUtils/BackendDiagnosticHandler.h" #include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" @@ -84,6 +85,176 @@ static void printCIRModule(mlir::ModuleOp MLIRModule, raw_ostream &OS) { MLIRModule->print(OS, Flags); } +// TODO: share with BackendConsumer::LinkInModules once the rest of the +// linking logic (not just diagnostics) is unified. +static bool linkInModules(CompilerInstance &CI, llvm::Module &M, + SmallVectorImpl<::clang::LinkModule> &LinkModules, + BackendDiagnosticConsumer &DiagConsumer) { + for (auto &LM : LinkModules) { + assert(LM.Module && "LinkModule does not actually have a module"); + + if (LM.PropagateAttrs) + for (llvm::Function &F : *LM.Module) { + if (F.isIntrinsic()) + continue; + clang::CodeGen::mergeDefaultFunctionDefinitionAttributes( + F, CI.getCodeGenOpts(), CI.getLangOpts(), CI.getTargetOpts(), + LM.Internalize); + } + + DiagConsumer.setCurLinkModule(LM.Module.get()); + bool Err; + if (LM.Internalize) { + Err = llvm::Linker::linkModules( + M, std::move(LM.Module), LM.LinkFlags, + [](llvm::Module &M, const llvm::StringSet<> &GVS) { + llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { + return !GV.hasName() || (GVS.count(GV.getName()) == 0); + }); + }); + } else { + Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags); + } + + if (Err) + return true; + } + + LinkModules.clear(); + return false; +} + +// Reads the device binary named by -foffload-include-binary and embeds it +// into the host module. wrapSYCLBinaries also appends the registration ctor +// at priority 101 when no registration-function out-param is supplied. +static void embedSYCLDeviceBinary(CompilerInstance &CI, llvm::Module &M) { + StringRef fileName = CI.getCodeGenOpts().OffloadBinaryToEmbedFile; + auto bufferOrErr = CI.getVirtualFileSystem().getBufferForFile(fileName); + if (std::error_code ec = bufferOrErr.getError()) { + CI.getDiagnostics().Report(diag::err_cannot_open_file) + << fileName << ec.message(); + return; + } + std::unique_ptr<llvm::MemoryBuffer> buffer = std::move(bufferOrErr.get()); + if (llvm::Error err = llvm::offloading::wrapSYCLBinaries( + M, ArrayRef<char>(buffer->getBufferStart(), buffer->getBufferSize()), + llvm::offloading::SYCLJITOptions(), /*IsFinalizedImage=*/true)) { + CI.getDiagnostics().Report(diag::err_fe_error_backend) + << llvm::toString(std::move(err)); + return; + } +} + +// Emits the output requested by \p Action for \p MlirModule, a CIR module that +// has been through the CIR-to-CIR pipeline. Language facts are read from the +// module's #cir.lowering_lang_options and target facts from \p CI, so this +// does not need an ASTContext and can also run on CIR loaded from a file. +// \p AddFunctionSourceLocations, if set, runs on the lowered LLVM module +// before linking. +static void emitCIRModuleOutput( + CIRGenAction::OutputType Action, CompilerInstance &CI, + mlir::ModuleOp MlirModule, llvm::LLVMContext &LLVMCtx, + SmallVectorImpl<::clang::LinkModule> &LinkModules, + BackendDiagnosticConsumer &DiagConsumer, + std::unique_ptr<raw_pwrite_stream> OutputStream, + llvm::function_ref<void(llvm::Module &)> AddFunctionSourceLocations = {}) { + CodeGenOptions &CGO = CI.getCodeGenOpts(); + switch (Action) { + case CIRGenAction::OutputType::EmitCIR: + if (OutputStream && MlirModule) + printCIRModule(MlirModule, *OutputStream); + break; + case CIRGenAction::OutputType::EmitCIRBC: + if (OutputStream && MlirModule && + failed(mlir::writeBytecodeToFile(MlirModule, *OutputStream)) && + !CI.getDiagnostics().hasErrorOccurred()) + CI.getDiagnostics().Report(diag::err_cir_bc_write_failed); + break; + case CIRGenAction::OutputType::EmitLLVM: + case CIRGenAction::OutputType::EmitBC: + case CIRGenAction::OutputType::EmitObj: + case CIRGenAction::OutputType::EmitAssembly: { + StringRef saveTempsPrefix = CGO.SaveTempsFilePrefix; + std::string cirSaveTempsOutFile, mlirSaveTempsOutFile; + if (!saveTempsPrefix.empty()) { + SmallString<128> stem(saveTempsPrefix); + llvm::sys::path::replace_extension(stem, "cir"); + cirSaveTempsOutFile = std::string(stem); + llvm::sys::path::replace_extension(stem, "mlir"); + mlirSaveTempsOutFile = std::string(stem); + } + + if (!cirSaveTempsOutFile.empty()) { + std::error_code ec; + llvm::raw_fd_ostream out(cirSaveTempsOutFile, ec); + if (!ec) + MlirModule->print(out); + } + + // If errors occurred during codegen, stop before running the backend. + if (CI.getDiagnostics().hasErrorOccurred()) + return; + + // Read the lowering facts before lowering rewrites the module. Without the + // attribute (e.g. hand-written CIR) every fact defaults to off. + auto LangOptsAttr = MlirModule->getAttrOfType<cir::LoweringLangOptionsAttr>( + cir::CIRDialect::getLoweringLangOptionsAttrName()); + const bool EnableOpenMP = LangOptsAttr && LangOptsAttr.getOpenmp(); + + // Route LLVM backend diagnostics (optimization remarks, unsupported + // features, inline-asm errors, etc.) through clang diagnostics for + // the remainder of the LLVM-emitting pipeline. + std::unique_ptr<llvm::DiagnosticHandler> OldDiagnosticHandler = + LLVMCtx.getDiagnosticHandler(); + llvm::scope_exit RestoreDiagnosticHandler([&]() { + LLVMCtx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); + }); + LLVMCtx.setDiagnosticHandler(DiagConsumer.createDiagnosticHandler()); + + std::unique_ptr<llvm::Module> LLVMModule = + lowerFromCIRToLLVMIR(MlirModule, LLVMCtx, EnableOpenMP, + mlirSaveTempsOutFile, &CI.getVirtualFileSystem()); + + LLVMModule->setDataLayout(CI.getTarget().getDataLayoutString()); + + if (AddFunctionSourceLocations) + AddFunctionSourceLocations(*LLVMModule); + + if (linkInModules(CI, *LLVMModule, LinkModules, DiagConsumer)) + return; + + const LangOptions &LangOpts = CI.getLangOpts(); + + // Embed the offloaded SYCL device binary into the host module. + if (LangOpts.SYCLIsHost && !CGO.OffloadBinaryToEmbedFile.empty()) + embedSYCLDeviceBinary(CI, *LLVMModule); + + // CUDA, HIP and OpenMP offloading rely on host-side offload entries that + // are not emitted on the ClangIR path yet, so embedding their device + // objects would produce a host object that cannot be registered. + // LangOptions::CUDA is also set for HIP. + if (!CGO.OffloadObjects.empty() && + (LangOpts.CUDA || !LangOpts.OMPTargetTriples.empty())) { + DiagnosticsEngine &Diags = CI.getDiagnostics(); + Diags.Report(Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "ClangIR code gen Not Yet Implemented: embedding offload objects " + "for CUDA, HIP or OpenMP offloading")); + return; + } + + // If there is device offloading code embed it in the host now. + EmbedObject(LLVMModule.get(), CGO, CI.getVirtualFileSystem(), + CI.getDiagnostics()); + + BackendAction BEAction = getBackendActionFromOutputType(Action); + emitBackendOutput(CI, CGO, LLVMModule.get(), BEAction, + CI.getVirtualFileSystemPtr(), std::move(OutputStream)); + break; + } + } +} + class CIRGenConsumer : public clang::ASTConsumer { virtual void anchor(); @@ -191,152 +362,17 @@ class CIRGenConsumer : public clang::ASTConsumer { } } - switch (Action) { - case CIRGenAction::OutputType::EmitCIR: - if (OutputStream && MlirModule) - printCIRModule(MlirModule, *OutputStream); - break; - case CIRGenAction::OutputType::EmitCIRBC: - if (OutputStream && MlirModule && - failed(mlir::writeBytecodeToFile(MlirModule, *OutputStream)) && - !CI.getDiagnostics().hasErrorOccurred()) - CI.getDiagnostics().Report(diag::err_cir_bc_write_failed); - break; - case CIRGenAction::OutputType::EmitLLVM: - case CIRGenAction::OutputType::EmitBC: - case CIRGenAction::OutputType::EmitObj: - case CIRGenAction::OutputType::EmitAssembly: { - StringRef saveTempsPrefix = CGO.SaveTempsFilePrefix; - std::string cirSaveTempsOutFile, mlirSaveTempsOutFile; - if (!saveTempsPrefix.empty()) { - SmallString<128> stem(saveTempsPrefix); - llvm::sys::path::replace_extension(stem, "cir"); - cirSaveTempsOutFile = std::string(stem); - llvm::sys::path::replace_extension(stem, "mlir"); - mlirSaveTempsOutFile = std::string(stem); - } - - if (!cirSaveTempsOutFile.empty()) { - std::error_code ec; - llvm::raw_fd_ostream out(cirSaveTempsOutFile, ec); - if (!ec) - MlirModule->print(out); - } - - // If errors occurred during codegen, stop before running the backend. - if (CI.getDiagnostics().hasErrorOccurred()) - return; - - // Route LLVM backend diagnostics (optimization remarks, unsupported - // features, inline-asm errors, etc.) through clang diagnostics for - // the remainder of the LLVM-emitting pipeline. - std::unique_ptr<llvm::DiagnosticHandler> OldDiagnosticHandler = - LLVMCtx.getDiagnosticHandler(); - llvm::scope_exit RestoreDiagnosticHandler([&]() { - LLVMCtx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); - }); - LLVMCtx.setDiagnosticHandler(DiagConsumer.createDiagnosticHandler()); - - std::unique_ptr<llvm::Module> LLVMModule = lowerFromCIRToLLVMIR( - MlirModule, LLVMCtx, C.getLangOpts().OpenMP, mlirSaveTempsOutFile, - &CI.getVirtualFileSystem()); - - LLVMModule->setDataLayout(C.getTargetInfo().getDataLayoutString()); - - for (llvm::Function &F : LLVMModule->functions()) + // CIRGen-only step: map the emitted LLVM functions back to their source + // declarations so backend diagnostics point at the original source. + auto AddFunctionSourceLocations = [&](llvm::Module &LLVMModule) { + for (llvm::Function &F : LLVMModule.functions()) if (const Decl *FD = Gen->getDeclForMangledName(F.getName())) DiagConsumer.addFunctionSourceLocation( F.getName(), FD->getASTContext().getFullLoc(FD->getLocation())); - - if (linkInModules(*LLVMModule)) - return; - - // Embed the offloaded SYCL device binary into the host module. - if (C.getLangOpts().SYCLIsHost && !CGO.OffloadBinaryToEmbedFile.empty()) - embedSYCLDeviceBinary(*LLVMModule); - - // CUDA, HIP and OpenMP offloading rely on host-side offload entries that - // are not emitted on the ClangIR path yet, so embedding their device - // objects would produce a host object that cannot be registered. - const LangOptions &LangOpts = C.getLangOpts(); - if (!CGO.OffloadObjects.empty() && - (LangOpts.CUDA || !LangOpts.OMPTargetTriples.empty())) { - DiagnosticsEngine &Diags = CI.getDiagnostics(); - Diags.Report(Diags.getCustomDiagID( - DiagnosticsEngine::Error, - "ClangIR code gen Not Yet Implemented: embedding offload objects " - "for CUDA, HIP or OpenMP offloading")); - return; - } - - // If there is device offloading code embed it in the host now. - EmbedObject(LLVMModule.get(), CGO, CI.getVirtualFileSystem(), - CI.getDiagnostics()); - - BackendAction BEAction = getBackendActionFromOutputType(Action); - emitBackendOutput(CI, CI.getCodeGenOpts(), LLVMModule.get(), BEAction, FS, - std::move(OutputStream)); - break; - } - } - } - - // TODO: share with BackendConsumer::LinkInModules once the rest of the - // linking logic (not just diagnostics) is unified. - bool linkInModules(llvm::Module &M) { - for (auto &LM : LinkModules) { - assert(LM.Module && "LinkModule does not actually have a module"); - - if (LM.PropagateAttrs) - for (llvm::Function &F : *LM.Module) { - if (F.isIntrinsic()) - continue; - clang::CodeGen::mergeDefaultFunctionDefinitionAttributes( - F, CGO, CI.getLangOpts(), CI.getTargetOpts(), LM.Internalize); - } - - DiagConsumer.setCurLinkModule(LM.Module.get()); - bool Err; - if (LM.Internalize) { - Err = llvm::Linker::linkModules( - M, std::move(LM.Module), LM.LinkFlags, - [](llvm::Module &M, const llvm::StringSet<> &GVS) { - llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { - return !GV.hasName() || (GVS.count(GV.getName()) == 0); - }); - }); - } else { - Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags); - } - - if (Err) - return true; - } - - LinkModules.clear(); - return false; - } - - // Reads the device binary named by -foffload-include-binary and embeds it - // into the host module. wrapSYCLBinaries also appends the registration ctor - // at priority 101 when no registration-function out-param is supplied. - void embedSYCLDeviceBinary(llvm::Module &M) { - StringRef fileName = CGO.OffloadBinaryToEmbedFile; - auto bufferOrErr = CI.getVirtualFileSystem().getBufferForFile(fileName); - if (std::error_code ec = bufferOrErr.getError()) { - CI.getDiagnostics().Report(diag::err_cannot_open_file) - << fileName << ec.message(); - return; - } - std::unique_ptr<llvm::MemoryBuffer> buffer = std::move(bufferOrErr.get()); - if (llvm::Error err = llvm::offloading::wrapSYCLBinaries( - M, - ArrayRef<char>(buffer->getBufferStart(), buffer->getBufferSize()), - llvm::offloading::SYCLJITOptions(), /*IsFinalizedImage=*/true)) { - CI.getDiagnostics().Report(diag::err_fe_error_backend) - << llvm::toString(std::move(err)); - return; - } + }; + emitCIRModuleOutput(Action, CI, MlirModule, LLVMCtx, LinkModules, + DiagConsumer, std::move(OutputStream), + AddFunctionSourceLocations); } void HandleTagDeclDefinition(TagDecl *D) override { >From 1353f7f61c0879cc626e66341aeb6c60effb3b17 Mon Sep 17 00:00:00 2001 From: Konstantinos Parasyris <[email protected]> Date: Tue, 13 Oct 2026 17:35:48 -0700 Subject: [PATCH 2/2] [clang][CIR] Share linkInModules between BackendConsumer and CIRGenAction BackendConsumer::LinkInModules and the ClangIR copy in CIRGenAction.cpp were near-identical. Move the logic to a free clang::linkInModules in ModuleLinker.h/.cpp, next to LinkModule and loadLinkModules, and have both paths call it. BackendConsumer::LinkInModules now forwards to it. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --- clang/include/clang/CodeGen/ModuleLinker.h | 11 +++++ clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 45 +------------------ clang/lib/CodeGen/CodeGenAction.cpp | 37 +-------------- clang/lib/CodeGen/ModuleLinker.cpp | 45 +++++++++++++++++++ 4 files changed, 60 insertions(+), 78 deletions(-) diff --git a/clang/include/clang/CodeGen/ModuleLinker.h b/clang/include/clang/CodeGen/ModuleLinker.h index 4f94e6057f1e8..f24b40f7cba23 100644 --- a/clang/include/clang/CodeGen/ModuleLinker.h +++ b/clang/include/clang/CodeGen/ModuleLinker.h @@ -19,6 +19,7 @@ class Module; } // namespace llvm namespace clang { +class BackendDiagnosticConsumer; class CodeGenOptions; class CompilerInstance; class LangOptions; @@ -39,6 +40,16 @@ struct LinkModule { bool loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, llvm::SmallVectorImpl<LinkModule> &LinkModules); +/// Link every module in \p LinkModules into \p M, propagating default +/// function attributes and internalizing as each entry requests. Linker +/// diagnostics are attributed to the module being linked through +/// \p DiagConsumer. Returns true on error. Clears \p LinkModules on success. +bool linkInModules(llvm::Module &M, + llvm::SmallVectorImpl<LinkModule> &LinkModules, + const CodeGenOptions &CodeGenOpts, + const LangOptions &LangOpts, const TargetOptions &TargetOpts, + BackendDiagnosticConsumer &DiagConsumer); + namespace CodeGen { /// Adds attributes to \p F according to our \p CodeGenOpts and \p LangOpts, as /// though we had emitted it ourselves. We remove any attributes on F that diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 12dbbf05bd3e6..8ae7b7824abf9 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -28,18 +28,15 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSet.h" #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/IR/DiagnosticHandler.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/Linker/Linker.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO/Internalize.h" using namespace cir; using namespace clang; @@ -85,45 +82,6 @@ static void printCIRModule(mlir::ModuleOp MLIRModule, raw_ostream &OS) { MLIRModule->print(OS, Flags); } -// TODO: share with BackendConsumer::LinkInModules once the rest of the -// linking logic (not just diagnostics) is unified. -static bool linkInModules(CompilerInstance &CI, llvm::Module &M, - SmallVectorImpl<::clang::LinkModule> &LinkModules, - BackendDiagnosticConsumer &DiagConsumer) { - for (auto &LM : LinkModules) { - assert(LM.Module && "LinkModule does not actually have a module"); - - if (LM.PropagateAttrs) - for (llvm::Function &F : *LM.Module) { - if (F.isIntrinsic()) - continue; - clang::CodeGen::mergeDefaultFunctionDefinitionAttributes( - F, CI.getCodeGenOpts(), CI.getLangOpts(), CI.getTargetOpts(), - LM.Internalize); - } - - DiagConsumer.setCurLinkModule(LM.Module.get()); - bool Err; - if (LM.Internalize) { - Err = llvm::Linker::linkModules( - M, std::move(LM.Module), LM.LinkFlags, - [](llvm::Module &M, const llvm::StringSet<> &GVS) { - llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { - return !GV.hasName() || (GVS.count(GV.getName()) == 0); - }); - }); - } else { - Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags); - } - - if (Err) - return true; - } - - LinkModules.clear(); - return false; -} - // Reads the device binary named by -foffload-include-binary and embeds it // into the host module. wrapSYCLBinaries also appends the registration ctor // at priority 101 when no registration-function out-param is supplied. @@ -220,7 +178,8 @@ static void emitCIRModuleOutput( if (AddFunctionSourceLocations) AddFunctionSourceLocations(*LLVMModule); - if (linkInModules(CI, *LLVMModule, LinkModules, DiagConsumer)) + if (linkInModules(*LLVMModule, LinkModules, CGO, CI.getLangOpts(), + CI.getTargetOpts(), DiagConsumer)) return; const LangOptions &LangOpts = CI.getLangOpts(); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 1abd8b0455a19..f9687eb904aaf 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -40,7 +40,6 @@ #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTOBackend.h" -#include "llvm/Linker/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -49,7 +48,6 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/Utils/Cloning.h" #include <optional> @@ -173,39 +171,8 @@ void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) { // Links each entry in LinkModules into our module. Returns true on error. bool BackendConsumer::LinkInModules(llvm::Module *M) { - for (auto &LM : LinkModules) { - assert(LM.Module && "LinkModule does not actually have a module"); - - if (LM.PropagateAttrs) - for (Function &F : *LM.Module) { - // Skip intrinsics. Keep consistent with how intrinsics are created - // in LLVM IR. - if (F.isIntrinsic()) - continue; - CodeGen::mergeDefaultFunctionDefinitionAttributes( - F, CodeGenOpts, LangOpts, TargetOpts, LM.Internalize); - } - - DiagConsumer.setCurLinkModule(LM.Module.get()); - bool Err; - - 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(LM.Module), LM.LinkFlags); - - if (Err) - return true; - } - - LinkModules.clear(); - return false; // success + return linkInModules(*M, LinkModules, CodeGenOpts, LangOpts, TargetOpts, + DiagConsumer); } void BackendConsumer::HandleTranslationUnit(ASTContext &C) { diff --git a/clang/lib/CodeGen/ModuleLinker.cpp b/clang/lib/CodeGen/ModuleLinker.cpp index 6c876276e344b..b50b412622f43 100644 --- a/clang/lib/CodeGen/ModuleLinker.cpp +++ b/clang/lib/CodeGen/ModuleLinker.cpp @@ -9,9 +9,13 @@ #include "clang/CodeGen/ModuleLinker.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/CodeGenUtils/BackendDiagnosticHandler.h" #include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/Module.h" +#include "llvm/Linker/Linker.h" +#include "llvm/Transforms/IPO/Internalize.h" using namespace clang; @@ -47,3 +51,44 @@ bool clang::loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, } return false; } + +bool clang::linkInModules(llvm::Module &M, + llvm::SmallVectorImpl<LinkModule> &LinkModules, + const CodeGenOptions &CodeGenOpts, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + BackendDiagnosticConsumer &DiagConsumer) { + for (LinkModule &LM : LinkModules) { + assert(LM.Module && "LinkModule does not actually have a module"); + + if (LM.PropagateAttrs) + for (llvm::Function &F : *LM.Module) { + // Skip intrinsics. Keep consistent with how intrinsics are created + // in LLVM IR. + if (F.isIntrinsic()) + continue; + CodeGen::mergeDefaultFunctionDefinitionAttributes( + F, CodeGenOpts, LangOpts, TargetOpts, LM.Internalize); + } + + DiagConsumer.setCurLinkModule(LM.Module.get()); + bool Err; + + if (LM.Internalize) { + Err = llvm::Linker::linkModules( + M, std::move(LM.Module), LM.LinkFlags, + [](llvm::Module &M, const llvm::StringSet<> &GVS) { + llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { + return !GV.hasName() || (GVS.count(GV.getName()) == 0); + }); + }); + } else + Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags); + + if (Err) + return true; + } + + LinkModules.clear(); + return false; // success +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
