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

Reply via email to