[clang] [clang-sycl-linker] Add support for linking static archives (PR #201253)

2026-06-03 Thread Nick Sarnie via cfe-commits

https://github.com/sarnex edited 
https://github.com/llvm/llvm-project/pull/201253
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-sycl-linker] Add support for linking static archives (PR #201253)

2026-06-03 Thread Nick Sarnie via cfe-commits


@@ -341,6 +342,38 @@ static Expected 
linkInputs(ArrayRef InputFiles,
 
   // Link in library files.
   for (auto &File : *BCLibFiles) {
+// Static archives are unpacked and each bitcode member is linked
+// individually with LinkOnlyNeeded.
+StringRef Ext = sys::path::extension(File);
+if (Ext == ".a" || Ext == ".lib") {

sarnex wrote:

instead of checking the ext should we use `llvm::identify_magic`?

https://github.com/llvm/llvm-project/pull/201253
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-sycl-linker] Add support for linking static archives (PR #201253)

2026-06-03 Thread Nick Sarnie via cfe-commits


@@ -341,6 +342,38 @@ static Expected 
linkInputs(ArrayRef InputFiles,
 
   // Link in library files.
   for (auto &File : *BCLibFiles) {
+// Static archives are unpacked and each bitcode member is linked
+// individually with LinkOnlyNeeded.
+StringRef Ext = sys::path::extension(File);
+if (Ext == ".a" || Ext == ".lib") {
+  auto BufOrErr = MemoryBuffer::getFile(File);
+  if (std::error_code EC = BufOrErr.getError())
+return createFileError(File, EC);
+  Expected> ArOrErr =
+  object::Archive::create((*BufOrErr)->getMemBufferRef());
+  if (!ArOrErr)
+return ArOrErr.takeError();
+  Error ArErr = Error::success();
+  for (const auto &Child : (*ArOrErr)->children(ArErr)) {
+Expected MemOrErr = Child.getMemoryBufferRef();
+if (!MemOrErr)
+  return MemOrErr.takeError();
+SMDiagnostic D;
+std::unique_ptr Mod = getLazyIRModule(
+MemoryBuffer::getMemBuffer(*MemOrErr, /*RequiresNullTerm=*/false),
+D, C);
+if (!Mod) {
+  // Skip non-IR archive members (e.g. symbol index, ELF objects).

sarnex wrote:

if no other path of `clang-sycl-linker` will handle those members IMO we should 
warn

https://github.com/llvm/llvm-project/pull/201253
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-sycl-linker] Add support for linking static archives (PR #201253)

2026-06-02 Thread via cfe-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-clang

Author: Alexey Bader (bader)


Changes

Add support for consuming static archives (.a, .lib) containing bitcode
device libraries. When an archive is passed via --bc-library, each
bitcode member is extracted and linked individually with LinkOnlyNeeded
semantics, ensuring only referenced symbols are included in the output.

Non-IR archive members (such as symbol tables or ELF objects) are
silently skipped. Archives with mismatched target triples are filtered
at the module level.

This enables sanitizer runtimes and other device libraries to be
packaged as static archives rather than individual bitcode files.

---
Full diff: https://github.com/llvm/llvm-project/pull/201253.diff


2 Files Affected:

- (modified) clang/test/OffloadTools/clang-sycl-linker/link.ll (+11) 
- (modified) clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp (+33) 


``diff
diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll 
b/clang/test/OffloadTools/clang-sycl-linker/link.ll
index 4114f0a3f3fb1..305f493e62dc5 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/link.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll
@@ -34,6 +34,17 @@
 ; Test that an absolute path to --bc-library is taken as-is, with no -L 
required.
 ; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc 
--dry-run -o a.spv --print-linked-module 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=CHECK-DEVICE-LIB
+;
+; Test linking with a static archive of bitcode libraries.
+; RUN: rm -f %t/libfoo.a
+; RUN: llvm-ar rcs %t/libfoo.a %t/libfoo.bc
+; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.a 
--dry-run -o a.spv --print-linked-module 2>&1 \
+; RUN:   | FileCheck %s --check-prefix=CHECK-ARCHIVE
+; CHECK-ARCHIVE: define {{.*}}foo_func1{{.*}}
+; CHECK-ARCHIVE: define {{.*}}foo_func2{{.*}}
+; CHECK-ARCHIVE: define {{.*}}bar_func1{{.*}}
+; CHECK-ARCHIVE: define {{.*}}addFive{{.*}}
+; CHECK-ARCHIVE-NOT: define {{.*}}unusedFunc{{.*}}
 
 ;--- foo.ll
 target datalayout = 
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp 
b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index e5e092c4737ec..da2af2e4315dc 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -30,6 +30,7 @@
 #include "llvm/LTO/LTO.h"
 #include "llvm/Linker/Linker.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Archive.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/OffloadBinary.h"
@@ -341,6 +342,38 @@ static Expected 
linkInputs(ArrayRef InputFiles,
 
   // Link in library files.
   for (auto &File : *BCLibFiles) {
+// Static archives are unpacked and each bitcode member is linked
+// individually with LinkOnlyNeeded.
+StringRef Ext = sys::path::extension(File);
+if (Ext == ".a" || Ext == ".lib") {
+  auto BufOrErr = MemoryBuffer::getFile(File);
+  if (std::error_code EC = BufOrErr.getError())
+return createFileError(File, EC);
+  Expected> ArOrErr =
+  object::Archive::create((*BufOrErr)->getMemBufferRef());
+  if (!ArOrErr)
+return ArOrErr.takeError();
+  Error ArErr = Error::success();
+  for (const auto &Child : (*ArOrErr)->children(ArErr)) {
+Expected MemOrErr = Child.getMemoryBufferRef();
+if (!MemOrErr)
+  return MemOrErr.takeError();
+SMDiagnostic D;
+std::unique_ptr Mod = getLazyIRModule(
+MemoryBuffer::getMemBuffer(*MemOrErr, /*RequiresNullTerm=*/false),
+D, C);
+if (!Mod) {
+  // Skip non-IR archive members (e.g. symbol index, ELF objects).
+  continue;
+}
+if (Mod->getTargetTriple() == TargetTriple)
+  if (L.linkInModule(std::move(Mod), Linker::Flags::LinkOnlyNeeded))
+return createStringError("Could not link IR from " + File);
+  }
+  if (ArErr)
+return std::move(ArErr);
+  continue;
+}
 auto LibMod = getBitcodeModule(File, C);
 if (!LibMod)
   return LibMod.takeError();

``




https://github.com/llvm/llvm-project/pull/201253
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-sycl-linker] Add support for linking static archives (PR #201253)

2026-06-02 Thread Alexey Bader via cfe-commits

https://github.com/bader created 
https://github.com/llvm/llvm-project/pull/201253

Add support for consuming static archives (.a, .lib) containing bitcode
device libraries. When an archive is passed via --bc-library, each
bitcode member is extracted and linked individually with LinkOnlyNeeded
semantics, ensuring only referenced symbols are included in the output.

Non-IR archive members (such as symbol tables or ELF objects) are
silently skipped. Archives with mismatched target triples are filtered
at the module level.

This enables sanitizer runtimes and other device libraries to be
packaged as static archives rather than individual bitcode files.

>From 25ddbb1535a604a5520da76e7e93bb7b0701bb4b Mon Sep 17 00:00:00 2001
From: Alexey Bader 
Date: Tue, 2 Jun 2026 19:57:29 -0700
Subject: [PATCH] [clang-sycl-linker] Add support for linking static archives

Add support for consuming static archives (.a, .lib) containing bitcode
device libraries. When an archive is passed via --bc-library, each
bitcode member is extracted and linked individually with LinkOnlyNeeded
semantics, ensuring only referenced symbols are included in the output.

Non-IR archive members (such as symbol tables or ELF objects) are
silently skipped. Archives with mismatched target triples are filtered
at the module level.

This enables sanitizer runtimes and other device libraries to be
packaged as static archives rather than individual bitcode files.
---
 .../OffloadTools/clang-sycl-linker/link.ll| 11 +++
 .../clang-sycl-linker/ClangSYCLLinker.cpp | 33 +++
 2 files changed, 44 insertions(+)

diff --git a/clang/test/OffloadTools/clang-sycl-linker/link.ll 
b/clang/test/OffloadTools/clang-sycl-linker/link.ll
index 4114f0a3f3fb1..305f493e62dc5 100644
--- a/clang/test/OffloadTools/clang-sycl-linker/link.ll
+++ b/clang/test/OffloadTools/clang-sycl-linker/link.ll
@@ -34,6 +34,17 @@
 ; Test that an absolute path to --bc-library is taken as-is, with no -L 
required.
 ; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.bc 
--dry-run -o a.spv --print-linked-module 2>&1 \
 ; RUN:   | FileCheck %s --check-prefix=CHECK-DEVICE-LIB
+;
+; Test linking with a static archive of bitcode libraries.
+; RUN: rm -f %t/libfoo.a
+; RUN: llvm-ar rcs %t/libfoo.a %t/libfoo.bc
+; RUN: clang-sycl-linker %t/foo.bc %t/bar.bc --bc-library %t/libfoo.a 
--dry-run -o a.spv --print-linked-module 2>&1 \
+; RUN:   | FileCheck %s --check-prefix=CHECK-ARCHIVE
+; CHECK-ARCHIVE: define {{.*}}foo_func1{{.*}}
+; CHECK-ARCHIVE: define {{.*}}foo_func2{{.*}}
+; CHECK-ARCHIVE: define {{.*}}bar_func1{{.*}}
+; CHECK-ARCHIVE: define {{.*}}addFive{{.*}}
+; CHECK-ARCHIVE-NOT: define {{.*}}unusedFunc{{.*}}
 
 ;--- foo.ll
 target datalayout = 
"e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp 
b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index e5e092c4737ec..da2af2e4315dc 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -30,6 +30,7 @@
 #include "llvm/LTO/LTO.h"
 #include "llvm/Linker/Linker.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Archive.h"
 #include "llvm/Object/Binary.h"
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/OffloadBinary.h"
@@ -341,6 +342,38 @@ static Expected 
linkInputs(ArrayRef InputFiles,
 
   // Link in library files.
   for (auto &File : *BCLibFiles) {
+// Static archives are unpacked and each bitcode member is linked
+// individually with LinkOnlyNeeded.
+StringRef Ext = sys::path::extension(File);
+if (Ext == ".a" || Ext == ".lib") {
+  auto BufOrErr = MemoryBuffer::getFile(File);
+  if (std::error_code EC = BufOrErr.getError())
+return createFileError(File, EC);
+  Expected> ArOrErr =
+  object::Archive::create((*BufOrErr)->getMemBufferRef());
+  if (!ArOrErr)
+return ArOrErr.takeError();
+  Error ArErr = Error::success();
+  for (const auto &Child : (*ArOrErr)->children(ArErr)) {
+Expected MemOrErr = Child.getMemoryBufferRef();
+if (!MemOrErr)
+  return MemOrErr.takeError();
+SMDiagnostic D;
+std::unique_ptr Mod = getLazyIRModule(
+MemoryBuffer::getMemBuffer(*MemOrErr, /*RequiresNullTerm=*/false),
+D, C);
+if (!Mod) {
+  // Skip non-IR archive members (e.g. symbol index, ELF objects).
+  continue;
+}
+if (Mod->getTargetTriple() == TargetTriple)
+  if (L.linkInModule(std::move(Mod), Linker::Flags::LinkOnlyNeeded))
+return createStringError("Could not link IR from " + File);
+  }
+  if (ArErr)
+return std::move(ArErr);
+  continue;
+}
 auto LibMod = getBitcodeModule(File, C);
 if (!LibMod)
   return LibMod.takeError();

___
cfe-commits mailing