[clang] [CIR] Add Support for linking modules on cc1 (PR #196245)
David Rivera via cfe-commits
cfe-commits at lists.llvm.org
Wed May 6 23:22:34 PDT 2026
https://github.com/RiverDave created https://github.com/llvm/llvm-project/pull/196245
I found certain unresolved external symbols when compiling polybench (for CUDA) specifically for libdevice - Therefore, this patch upstreams https://github.com/llvm/clangir/pull/2010/changes.
>From e47a97d0cfdf88b925c7f012b063640a3ff135aa Mon Sep 17 00:00:00 2001
From: David Rivera <davidriverg at gmail.com>
Date: Thu, 7 May 2026 06:18:01 +0000
Subject: [PATCH] [CIR] Add Support for linking modules on cc1
---
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 79 +++++++++++++++++++
clang/test/CIR/CodeGen/link-bitcode-file.c | 44 +++++++++++
2 files changed, 123 insertions(+)
create mode 100644 clang/test/CIR/CodeGen/link-bitcode-file.c
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index af38872c5ca98..424fbd4f1186a 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -16,9 +16,15 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Frontend/CompilerInstance.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Bitcode/BitcodeReader.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"
using namespace cir;
using namespace clang;
@@ -70,6 +76,15 @@ class CIRGenConsumer : public clang::ASTConsumer {
const FrontendOptions &FEOptions;
CodeGenOptions &CGO;
+ struct LinkModule {
+ std::unique_ptr<llvm::Module> Module;
+ bool PropagateAttrs;
+ bool Internalize;
+ unsigned LinkFlags;
+ };
+
+ SmallVector<LinkModule, 4> LinkModules;
+
public:
CIRGenConsumer(CIRGenAction::OutputType Action, CompilerInstance &CI,
CodeGenOptions &CGO, std::unique_ptr<raw_pwrite_stream> OS)
@@ -160,10 +175,16 @@ class CIRGenConsumer : public clang::ASTConsumer {
}
llvm::LLVMContext LLVMCtx;
+ if (loadLinkModules(LLVMCtx))
+ return;
+
std::unique_ptr<llvm::Module> LLVMModule =
lowerFromCIRToLLVMIR(MlirModule, LLVMCtx, mlirSaveTempsOutFile,
&CI.getVirtualFileSystem());
+ if (linkInModules(*LLVMModule))
+ return;
+
BackendAction BEAction = getBackendActionFromOutputType(Action);
emitBackendOutput(
CI, CI.getCodeGenOpts(), C.getTargetInfo().getDataLayoutString(),
@@ -173,6 +194,64 @@ class CIRGenConsumer : public clang::ASTConsumer {
}
}
+ bool loadLinkModules(llvm::LLVMContext &LLVMCtx) {
+ 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), 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");
+
+ 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;
+ }
+
void HandleTagDeclDefinition(TagDecl *D) override {
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(),
diff --git a/clang/test/CIR/CodeGen/link-bitcode-file.c b/clang/test/CIR/CodeGen/link-bitcode-file.c
new file mode 100644
index 0000000000000..ca6c070699f81
--- /dev/null
+++ b/clang/test/CIR/CodeGen/link-bitcode-file.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir -DBITCODE -emit-llvm-bc -o %t.bc %s
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir -DBITCODE2 -emit-llvm-bc -o %t-2.bc %s
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir -mlink-bitcode-file %t.bc \
+// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-BC %s
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir -mlink-builtin-bitcode %t.bc \
+// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-BUILTIN-BC %s
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o - \
+// RUN: -mlink-bitcode-file %t.bc -mlink-bitcode-file %t-2.bc %s \
+// RUN: | FileCheck -check-prefix=CHECK-BC -check-prefix=CHECK-BC2 %s
+// RUN: not %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN: -mlink-bitcode-file no-such-file.bc -emit-llvm -o - %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-NO-FILE %s
+
+int f(void);
+
+#ifdef BITCODE
+
+extern int f2(void);
+
+int f(void) {
+ f2();
+ return 42;
+}
+
+#elif defined(BITCODE2)
+
+int f2(void) { return 43; }
+
+#else
+
+// CHECK-BC-LABEL: define{{.*}} i32 @g
+// CHECK-BC: ret i32 42
+// CHECK-BUILTIN-BC-LABEL: define{{.*}} i32 @g
+// CHECK-BUILTIN-BC: ret i32 42
+int g(void) {
+ return f();
+}
+
+// CHECK-BC-LABEL: define{{.*}} i32 @f
+// CHECK-BC2-LABEL: define{{.*}} i32 @f2
+
+#endif
+
+// CHECK-NO-FILE: fatal error: cannot open file 'no-such-file.bc'
More information about the cfe-commits
mailing list