https://github.com/koparasy created https://github.com/llvm/llvm-project/pull/197751
None >From 09f730c2ed5ae3c5e08232f8d6f4050f2c341b08 Mon Sep 17 00:00:00 2001 From: y <[email protected]> Date: Thu, 14 May 2026 08:29:04 -0700 Subject: [PATCH 1/2] [CIR][CodeGen] Extract shared LinkModule struct and loadLinkModules helper The bitcode-link plumbing is ABI-neutral and identical between the classic CodeGen path and the ClangIR path. Prior to this change, each side carried its own copy of the `LinkModule` struct and `loadLinkModules` routine; CIRGenAction.cpp explicitly flagged the copy with a TODO. Move the struct and loader into clang/CodeGen/ModuleLinker.{h,cpp} so both frontends share one definition. `LinkInModules` remains per-consumer because the classic path threads `CurLinkModule` into its diagnostic handler while CIR does not. This is a straight refactor -- no behavior change. --- clang/include/clang/CodeGen/CodeGenAction.h | 24 +------- clang/include/clang/CodeGen/ModuleLinker.h | 40 +++++++++++++ clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 58 +++---------------- clang/lib/CIR/FrontendAction/CMakeLists.txt | 2 + clang/lib/CodeGen/BackendConsumer.h | 3 +- clang/lib/CodeGen/CMakeLists.txt | 1 + clang/lib/CodeGen/CodeGenAction.cpp | 34 +---------- clang/lib/CodeGen/ModuleLinker.cpp | 50 ++++++++++++++++ 8 files changed, 104 insertions(+), 108 deletions(-) create mode 100644 clang/include/clang/CodeGen/ModuleLinker.h create mode 100644 clang/lib/CodeGen/ModuleLinker.cpp diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index 186dbb43f01ef..84fa4549d5033 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_CODEGEN_CODEGENACTION_H #define LLVM_CLANG_CODEGEN_CODEGENACTION_H +#include "clang/CodeGen/ModuleLinker.h" #include "clang/Frontend/FrontendAction.h" #include <memory> @@ -23,26 +24,6 @@ class CodeGenerator; class CodeGenAction : public ASTFrontendAction { private: - // Let BackendConsumer access LinkModule. - friend class BackendConsumer; - - /// Info about module to link into a module we're generating. - struct LinkModule { - /// The module to link in. - std::unique_ptr<llvm::Module> Module; - - /// If true, we set attributes on Module's functions according to our - /// CodeGenOptions and LangOptions, as though we were generating the - /// function ourselves. - bool PropagateAttrs; - - /// If true, we use LLVM module internalizer. - bool Internalize; - - /// Bitwise combination of llvm::LinkerFlags used when we link the module. - unsigned LinkFlags; - }; - unsigned Act; std::unique_ptr<llvm::Module> TheModule; @@ -53,9 +34,6 @@ class CodeGenAction : public ASTFrontendAction { std::unique_ptr<llvm::Module> loadModule(llvm::MemoryBufferRef MBRef); - /// Load bitcode modules to link into our module from the options. - bool loadLinkModules(CompilerInstance &CI); - protected: bool BeginSourceFileAction(CompilerInstance &CI) override; diff --git a/clang/include/clang/CodeGen/ModuleLinker.h b/clang/include/clang/CodeGen/ModuleLinker.h new file mode 100644 index 0000000000000..8a326df763f47 --- /dev/null +++ b/clang/include/clang/CodeGen/ModuleLinker.h @@ -0,0 +1,40 @@ +//===--- ModuleLinker.h - Shared bitcode link helpers ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_MODULELINKER_H +#define LLVM_CLANG_CODEGEN_MODULELINKER_H + +#include "llvm/ADT/SmallVector.h" +#include <memory> + +namespace llvm { +class LLVMContext; +class Module; +} // namespace llvm + +namespace clang { +class CompilerInstance; + +/// Info about a module to link into the module currently being generated. +/// Shared between the classic clang CodeGen path and the ClangIR path. +struct LinkModule { + std::unique_ptr<llvm::Module> Module; + bool PropagateAttrs; + bool Internalize; + unsigned LinkFlags; +}; + +/// Load every bitcode file listed in CodeGenOpts.LinkBitcodeFiles into +/// \p LinkModules. Returns true on error (diagnostic already reported). +/// Appends to \p LinkModules; does not clear it. +bool loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, + llvm::SmallVectorImpl<LinkModule> &LinkModules); + +} // namespace clang + +#endif diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index ad358f802e86a..1e39ae79eec39 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -14,16 +14,15 @@ #include "clang/CIR/CIRToCIRPasses.h" #include "clang/CIR/LowerToLLVM.h" #include "clang/CodeGen/BackendUtil.h" +#include "clang/CodeGen/ModuleLinker.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/DiagnosticHandler.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" #include "llvm/Linker/Linker.h" -#include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO/Internalize.h" @@ -78,16 +77,7 @@ class CIRGenConsumer : public clang::ASTConsumer { const FrontendOptions &FEOptions; CodeGenOptions &CGO; - // TODO(cir): This is a 1:1 copy from OG Codegen, we might need to find a way - // to share this - struct LinkModule { - std::unique_ptr<llvm::Module> module; - bool propagateAttrs; - bool internalize; - unsigned linkFlags; - }; - - SmallVector<LinkModule, 4> linkModules; + SmallVector<::clang::LinkModule, 4> linkModules; public: CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI, @@ -179,7 +169,7 @@ class CIRGenConsumer : public clang::ASTConsumer { } llvm::LLVMContext LLVMCtx; - if (loadLinkModules(LLVMCtx)) + if (clang::loadLinkModules(CI, LLVMCtx, linkModules)) return; std::unique_ptr<llvm::Module> LLVMModule = @@ -198,55 +188,21 @@ class CIRGenConsumer : public clang::ASTConsumer { } } - bool loadLinkModules(llvm::LLVMContext &llvmCtx) { - if (!linkModules.empty()) - return false; - - for (const CodeGenOptions::BitcodeFileToLink &F : - CI.getCodeGenOpts().LinkBitcodeFiles) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BCBuf = - CI.getFileManager().getBufferForFile(F.Filename); - if (!BCBuf) { - CI.getDiagnostics().Report(diag::err_cannot_open_file) - << F.Filename << BCBuf.getError().message(); - linkModules.clear(); - return true; - } - - llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = - llvm::getOwningLazyBitcodeModule(std::move(*BCBuf), llvmCtx); - if (!ModuleOrErr) { - llvm::handleAllErrors( - ModuleOrErr.takeError(), [&](llvm::ErrorInfoBase &EIB) { - CI.getDiagnostics().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; - } - bool linkInModules(llvm::Module &M) { for (auto &LM : linkModules) { - assert(LM.module && "LinkModule does not actually have a module"); + assert(LM.Module && "LinkModule does not actually have a module"); bool Err; - if (LM.internalize) { + if (LM.Internalize) { Err = llvm::Linker::linkModules( - M, std::move(LM.module), LM.linkFlags, + 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); + Err = llvm::Linker::linkModules(M, std::move(LM.Module), LM.LinkFlags); } if (Err) diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt index 50d6ea7108ce1..b2d2fc1621693 100644 --- a/clang/lib/CIR/FrontendAction/CMakeLists.txt +++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt @@ -1,5 +1,7 @@ set(LLVM_LINK_COMPONENTS Core + ipo + Linker Support ) diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h index b7bbb81074836..eeac13bd42379 100644 --- a/clang/lib/CodeGen/BackendConsumer.h +++ b/clang/lib/CodeGen/BackendConsumer.h @@ -11,6 +11,7 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleLinker.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/Support/Timer.h" @@ -25,8 +26,6 @@ class CodeGenAction; class CoverageSourceInfo; class BackendConsumer : public ASTConsumer { - using LinkModule = CodeGenAction::LinkModule; - virtual void anchor(); CompilerInstance &CI; DiagnosticsEngine &Diags; diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 434781b3c4f02..f1d32fbab1a0f 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -114,6 +114,7 @@ add_clang_library(clangCodeGen MacroPPCallbacks.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp + ModuleLinker.cpp ObjectFilePCHContainerWriter.cpp PatternInit.cpp QualTypeMapper.cpp diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 73bf49b1a8046..fb1a410ce1761 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -911,36 +911,6 @@ CodeGenAction::~CodeGenAction() { delete VMContext; } -bool CodeGenAction::loadLinkModules(CompilerInstance &CI) { - if (!LinkModules.empty()) - return false; - - for (const CodeGenOptions::BitcodeFileToLink &F : - CI.getCodeGenOpts().LinkBitcodeFiles) { - auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename); - if (!BCBuf) { - CI.getDiagnostics().Report(diag::err_cannot_open_file) - << F.Filename << BCBuf.getError().message(); - LinkModules.clear(); - return true; - } - - Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = - getOwningLazyBitcodeModule(std::move(*BCBuf), *VMContext); - if (!ModuleOrErr) { - handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) { - CI.getDiagnostics().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; -} - bool CodeGenAction::hasIRSupport() const { return true; } void CodeGenAction::EndSourceFileAction() { @@ -1004,7 +974,7 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { return nullptr; // Load bitcode modules to link with, if we need to. - if (loadLinkModules(CI)) + if (clang::loadLinkModules(CI, *VMContext, LinkModules)) return nullptr; CoverageSourceInfo *CoverageInfo = nullptr; @@ -1082,7 +1052,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) { } // Load bitcode modules to link with, if we need to. - if (loadLinkModules(CI)) + if (clang::loadLinkModules(CI, *VMContext, LinkModules)) return nullptr; // Handle textual IR and bitcode file with one single module. diff --git a/clang/lib/CodeGen/ModuleLinker.cpp b/clang/lib/CodeGen/ModuleLinker.cpp new file mode 100644 index 0000000000000..fcf13f5bd59b3 --- /dev/null +++ b/clang/lib/CodeGen/ModuleLinker.cpp @@ -0,0 +1,50 @@ +//===--- ModuleLinker.cpp - Shared bitcode link helpers -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/CodeGen/ModuleLinker.h" + +#include "clang/Basic/CodeGenOptions.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/IR/Module.h" + +using namespace clang; + +bool clang::loadLinkModules(CompilerInstance &CI, llvm::LLVMContext &Ctx, + llvm::SmallVectorImpl<LinkModule> &LinkModules) { + if (!LinkModules.empty()) + return false; + + for (const CodeGenOptions::BitcodeFileToLink &F : + CI.getCodeGenOpts().LinkBitcodeFiles) { + auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename); + if (!BCBuf) { + CI.getDiagnostics().Report(diag::err_cannot_open_file) + << F.Filename << BCBuf.getError().message(); + LinkModules.clear(); + return true; + } + + llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr = + llvm::getOwningLazyBitcodeModule(std::move(*BCBuf), Ctx); + if (!ModuleOrErr) { + llvm::handleAllErrors(ModuleOrErr.takeError(), + [&](llvm::ErrorInfoBase &EIB) { + CI.getDiagnostics().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; +} >From 91f4a07c91a898423b085507289cf92ab92b5a33 Mon Sep 17 00:00:00 2001 From: y <[email protected]> Date: Thu, 14 May 2026 08:33:40 -0700 Subject: [PATCH 2/2] [CIR] Move bitcode-link state from CIRGenConsumer to CIRGenAction Match the classic CodeGenAction architecture: the action owns the LLVMContext and the vector of LinkModules. CIRGenConsumer receives them by reference. Bitcode files are loaded in BeginSourceFileAction (matching OG timing) so missing-file errors fire before the translation unit is parsed. Prepares CIRGen for driver-side offload work (CUDA/HIP split-compilation) that needs to inspect the llvm::Module after lowering. The previous shape kept the LLVMContext on the stack inside HandleTranslationUnit, making it impossible to hand the module back to the driver. No behavior change for existing callers. --- .../clang/CIR/FrontendAction/CIRGenAction.h | 11 +++++++ clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 30 ++++++++++++------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h index 99495f4718c5f..7f8c90f285521 100644 --- a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h +++ b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h @@ -9,11 +9,17 @@ #ifndef LLVM_CLANG_CIR_CIRGENACTION_H #define LLVM_CLANG_CIR_CIRGENACTION_H +#include "clang/CodeGen/ModuleLinker.h" #include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/SmallVector.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/OwningOpRef.h" +namespace llvm { +class LLVMContext; +} // namespace llvm + namespace mlir { class MLIRContext; class ModuleOp; @@ -39,9 +45,14 @@ class CIRGenAction : public clang::ASTFrontendAction { mlir::MLIRContext *MLIRCtx; + std::unique_ptr<llvm::LLVMContext> VMContext; + llvm::SmallVector<::clang::LinkModule, 4> LinkModules; + protected: CIRGenAction(OutputType Action, mlir::MLIRContext *MLIRCtx = nullptr); + bool BeginSourceFileAction(clang::CompilerInstance &CI) override; + std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef InFile) override; diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 1e39ae79eec39..9a74ba93e3152 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/IR/DiagnosticHandler.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Linker/Linker.h" #include "llvm/Support/Path.h" @@ -77,16 +78,20 @@ class CIRGenConsumer : public clang::ASTConsumer { const FrontendOptions &FEOptions; CodeGenOptions &CGO; - SmallVector<::clang::LinkModule, 4> linkModules; + llvm::LLVMContext &LLVMCtx; + SmallVectorImpl<::clang::LinkModule> &LinkModules; public: CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI, - CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS) + CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS, + llvm::LLVMContext &LLVMCtx, + SmallVectorImpl<::clang::LinkModule> &LinkModules) : Action(Action), CI(CI), OutputStream(std::move(OS)), FS(&CI.getVirtualFileSystem()), Gen(std::make_unique<CIRGenerator>(CI.getDiagnostics(), std::move(FS), CI.getCodeGenOpts())), - FEOptions(CI.getFrontendOpts()), CGO(CGO) {} + FEOptions(CI.getFrontendOpts()), CGO(CGO), LLVMCtx(LLVMCtx), + LinkModules(LinkModules) {} void Initialize(ASTContext &Ctx) override { assert(!Context && "initialized multiple times"); @@ -168,10 +173,6 @@ class CIRGenConsumer : public clang::ASTConsumer { MlirModule->print(out); } - llvm::LLVMContext LLVMCtx; - if (clang::loadLinkModules(CI, LLVMCtx, linkModules)) - return; - std::unique_ptr<llvm::Module> LLVMModule = lowerFromCIRToLLVMIR(MlirModule, LLVMCtx, mlirSaveTempsOutFile, &CI.getVirtualFileSystem()); @@ -189,7 +190,7 @@ class CIRGenConsumer : public clang::ASTConsumer { } bool linkInModules(llvm::Module &M) { - for (auto &LM : linkModules) { + for (auto &LM : LinkModules) { assert(LM.Module && "LinkModule does not actually have a module"); bool Err; @@ -209,7 +210,7 @@ class CIRGenConsumer : public clang::ASTConsumer { return true; } - linkModules.clear(); + LinkModules.clear(); return false; } @@ -235,10 +236,17 @@ class CIRGenConsumer : public clang::ASTConsumer { void CIRGenConsumer::anchor() {} CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx) - : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {} + : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), + VMContext(std::make_unique<llvm::LLVMContext>()), Action(Act) {} CIRGenAction::~CIRGenAction() { MLIRMod.release(); } +bool CIRGenAction::BeginSourceFileAction(CompilerInstance &CI) { + if (clang::loadLinkModules(CI, *VMContext, LinkModules)) + return false; + return ASTFrontendAction::BeginSourceFileAction(CI); +} + static std::unique_ptr<raw_pwrite_stream> getOutputStream(CompilerInstance &CI, StringRef InFile, CIRGenAction::OutputType Action) { @@ -265,7 +273,7 @@ CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { Out = getOutputStream(CI, InFile, Action); auto Result = std::make_unique<cir::CIRGenConsumer>( - Action, CI, CI.getCodeGenOpts(), std::move(Out)); + Action, CI, CI.getCodeGenOpts(), std::move(Out), *VMContext, LinkModules); return Result; } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
