[clang] [llvm] [clang][SYCL] Embed finalized device images for -foffload-include-binary (PR #216419)
Yury Plyakhin via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 18 11:18:45 PDT 2026
https://github.com/YuriPlyakhin updated https://github.com/llvm/llvm-project/pull/216419
>From e8866b747672072ffc5e139cf5795637202194a5 Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Mon, 10 Aug 2026 17:15:05 +0200
Subject: [PATCH 1/3] [clang][SYCL] Embed finalized device images for
-foffload-include-binary
During SYCL host compilation, honor -foffload-include-binary by reading
the finalized SYCL device image it names and embedding it into the host
module, along with the registration constructors and destructors the SYCL
runtime expects. This reuses the shared offloading wrapper
(llvm::offloading::wrapSYCLBinaries) rather than reimplementing any
registration IR.
wrapSYCLBinaries gains an IsFinalizedImage parameter. clang-linker-wrapper
scans sections whose name starts with ".llvm.offloading" for device code
that still needs a device link, so an already finalized image is placed in
".sycl_fatbin" instead, mirroring how CUDA/HIP use ".nv_fatbin"/
".hip_fatbin".
The embedding runs late in CodeGenModule::Release(), after the EmitCtorList
calls. wrapSYCLBinaries registers its constructor and destructor using
llvm::appendToGlobalCtors/appendToGlobalDtors, which merge into
llvm.global_ctors and llvm.global_dtors only when those globals already
exist. Registering any earlier leaves EmitCtorList to create a second,
auto-renamed llvm.global_ctors.1, which the backend rejects with "unknown
special variable with appending linkage" for any translation unit that has
static initializers of its own.
This is the compile-time counterpart of the -fembed-offload-object path
used in relocatable device code mode, and is what non-relocatable device
code mode (-fno-sycl-rdc) will use.
Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
---
clang/lib/CodeGen/CodeGenModule.cpp | 4 ++
clang/lib/CodeGen/CodeGenModule.h | 5 ++
clang/lib/CodeGen/CodeGenSYCL.cpp | 20 ++++++++
.../CodeGenSYCL/offload-include-binary.cpp | 47 +++++++++++++++++++
.../llvm/Frontend/Offloading/OffloadWrapper.h | 9 ++--
.../Frontend/Offloading/OffloadWrapper.cpp | 16 +++++--
6 files changed, 93 insertions(+), 8 deletions(-)
create mode 100644 clang/test/CodeGenSYCL/offload-include-binary.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index e17bd72c2f052..db8387f16a73f 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1182,6 +1182,10 @@ void CodeGenModule::Release() {
});
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
+ // The SYCL image registration functions are added to the constructor and
+ // destructor lists which merge into llvm.global_ctors and llvm.global_dtors.
+ if (LangOpts.SYCLIsHost && !CodeGenOpts.OffloadBinaryToEmbedFile.empty())
+ embedSYCLTargetBinary();
EmitGlobalAnnotations();
EmitStaticExternCAliases();
checkAliases();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 49892b6202192..5573ed69f4268 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -2179,6 +2179,11 @@ class CodeGenModule : public CodeGenTypeCache {
/// by clang-sycl-linker during device-code splitting.
void addSYCLModuleIdAttr(llvm::Function *Fn);
+ /// Embed the finalized SYCL device image named by -foffload-include-binary
+ /// into the host module and emit the registration constructors the SYCL
+ /// runtime expects.
+ void embedSYCLTargetBinary();
+
/// Determine whether the definition must be emitted; if this returns \c
/// false, the definition can be emitted lazily if it's used.
bool MustBeEmitted(const ValueDecl *D);
diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index 7ca749a25fe6c..de0d3750ae8fd 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -13,6 +13,10 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "llvm/Frontend/Offloading/OffloadWrapper.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
#include <cassert>
using namespace clang;
@@ -84,3 +88,19 @@ void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
SetLLVMFunctionAttributesForDefinition(cast<Decl>(OutlinedFnDecl), Fn);
CGF.FinishFunction();
}
+
+void CodeGenModule::embedSYCLTargetBinary() {
+ StringRef FileName = getCodeGenOpts().OffloadBinaryToEmbedFile;
+ auto BufferOrErr = getFileSystem()->getBufferForFile(FileName);
+ if (std::error_code EC = BufferOrErr.getError()) {
+ getDiags().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(
+ getModule(),
+ ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()),
+ llvm::offloading::SYCLJITOptions(), /*IsFinalizedImage=*/true))
+ getDiags().Report(diag::err_fe_error_backend)
+ << llvm::toString(std::move(Err));
+}
diff --git a/clang/test/CodeGenSYCL/offload-include-binary.cpp b/clang/test/CodeGenSYCL/offload-include-binary.cpp
new file mode 100644
index 0000000000000..759f7aa47e73b
--- /dev/null
+++ b/clang/test/CodeGenSYCL/offload-include-binary.cpp
@@ -0,0 +1,47 @@
+// Verify that -foffload-include-binary embeds the finalized SYCL device
+// image into the host module and emits the registration/unregistration
+// constructors and destructors expected by the SYCL runtime.
+// The image is already finalized, so it must not land in ".llvm.offloading".
+// RUN: echo -n 'FAKE_SYCL_DEVICE_IMAGE' > %t.bin
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
+// RUN: -foffload-include-binary %t.bin -emit-llvm %s -o - \
+// RUN: | FileCheck %s --implicit-check-not='.llvm.offloading' \
+// RUN: --implicit-check-not='llvm.global_ctors.'
+
+// The registration functions have to merge into the constructor and destructor
+// lists the rest of the translation unit contributes to, so object emission
+// must succeed for a translation unit that has its own static initializers.
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
+// RUN: -foffload-include-binary %t.bin -emit-obj %s -o %t.o
+
+// Without the flag no registration IR should be emitted.
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=NONE
+
+// A missing binary file must be diagnosed.
+// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
+// RUN: -foffload-include-binary %t.does-not-exist -emit-llvm %s -o - 2>&1 \
+// RUN: | FileCheck %s --check-prefix=ERROR
+
+struct S {
+ S();
+ ~S();
+};
+S s;
+
+void f() {}
+
+// CHECK: @.sycl_offloading.binary = internal unnamed_addr constant [22 x i8] c"FAKE_SYCL_DEVICE_IMAGE", section ".sycl_fatbin"
+// CHECK: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }]
+// CHECK-SAME: i32 65535, ptr @_GLOBAL__sub_I_
+// CHECK-SAME: i32 1, ptr @sycl.descriptor_reg
+// CHECK: @llvm.global_dtors = {{.*}}@sycl.descriptor_unreg
+// CHECK: define internal void @sycl.descriptor_reg()
+// CHECK: call void @__sycl_register_lib(ptr @.sycl_offloading.binary, i64 22)
+// CHECK: define internal void @sycl.descriptor_unreg()
+// CHECK: call void @__sycl_unregister_lib(ptr @.sycl_offloading.binary, i64 22)
+
+// NONE-NOT: .sycl_offloading.binary
+// NONE-NOT: __sycl_register_lib
+
+// ERROR: cannot open file '{{.*}}.does-not-exist'
diff --git a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
index cb2e793eb2c67..8767aa942bc80 100644
--- a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
+++ b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
@@ -68,9 +68,12 @@ struct SYCLJITOptions {
/// as global symbols and registers the images with the SYCL Runtime.
/// \param Options Compiler and linker options to be encoded for the later
/// use by a runtime for JIT compilation. Not used for AOT.
-LLVM_ABI llvm::Error
-wrapSYCLBinaries(llvm::Module &M, llvm::ArrayRef<char> Buffer,
- SYCLJITOptions Options = SYCLJITOptions());
+/// \param IsFinalizedImage True when \p Buffer holds an already finalized
+/// device image, which must not be device-linked again.
+LLVM_ABI llvm::Error wrapSYCLBinaries(llvm::Module &M,
+ llvm::ArrayRef<char> Buffer,
+ SYCLJITOptions Options = SYCLJITOptions(),
+ bool IsFinalizedImage = false);
} // namespace offloading
} // namespace llvm
diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
index ded603a1e00e3..320a0caf388fd 100644
--- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
+++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
@@ -635,8 +635,9 @@ void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc,
/// SYCLWrapper helper class that creates all LLVM IRs wrapping given images.
class SYCLWrapper {
public:
- SYCLWrapper(Module &M, const SYCLJITOptions &Options)
- : M(M), C(M.getContext()), Options(Options) {}
+ SYCLWrapper(Module &M, const SYCLJITOptions &Options, bool IsFinalizedImage)
+ : M(M), C(M.getContext()), Options(Options),
+ IsFinalizedImage(IsFinalizedImage) {}
/// Embeds \p Buffer (a raw OffloadBinary) as a global constant and returns
/// a pair of (Start, Size), where Start points to the beginning of the
@@ -647,7 +648,10 @@ class SYCLWrapper {
M, Arr->getType(), /*isConstant=*/true, GlobalValue::InternalLinkage,
Arr, ".sycl_offloading.binary");
BinaryGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
- BinaryGV->setSection(".llvm.offloading");
+ // The linker wrapper scans ".llvm.offloading" for device code to link, so
+ // an already finalized image must go elsewhere to avoid being linked again.
+ BinaryGV->setSection(IsFinalizedImage ? ".sycl_fatbin"
+ : ".llvm.offloading");
IntegerType *Int64Ty = Type::getInt64Ty(C);
Constant *Zero = ConstantInt::get(Int64Ty, 0);
@@ -705,6 +709,7 @@ class SYCLWrapper {
Module &M;
LLVMContext &C;
SYCLJITOptions Options;
+ bool IsFinalizedImage;
}; // end of SYCLWrapper
} // namespace
@@ -749,8 +754,9 @@ Error offloading::wrapHIPBinary(Module &M, ArrayRef<char> Image,
}
Error llvm::offloading::wrapSYCLBinaries(llvm::Module &M, ArrayRef<char> Buffer,
- SYCLJITOptions Options) {
- SYCLWrapper W(M, Options);
+ SYCLJITOptions Options,
+ bool IsFinalizedImage) {
+ SYCLWrapper W(M, Options, IsFinalizedImage);
auto [Start, Size] = W.embedBinary(Buffer);
W.createRegisterFatbinFunction(Start, Size);
W.createUnregisterFunction(Start, Size);
>From 6323d466a087ec26b4a165f138b8620ddf0ade14 Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Mon, 17 Aug 2026 15:04:52 -0700
Subject: [PATCH 2/3] addressed feedback
---
.../CodeGenSYCL/offload-include-binary.cpp | 28 +++++++++++++------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/clang/test/CodeGenSYCL/offload-include-binary.cpp b/clang/test/CodeGenSYCL/offload-include-binary.cpp
index 759f7aa47e73b..72e84da7c9cab 100644
--- a/clang/test/CodeGenSYCL/offload-include-binary.cpp
+++ b/clang/test/CodeGenSYCL/offload-include-binary.cpp
@@ -1,3 +1,5 @@
+// REQUIRES: x86-registered-target
+
// Verify that -foffload-include-binary embeds the finalized SYCL device
// image into the host module and emits the registration/unregistration
// constructors and destructors expected by the SYCL runtime.
@@ -14,9 +16,12 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
// RUN: -foffload-include-binary %t.bin -emit-obj %s -o %t.o
-// Without the flag no registration IR should be emitted.
+// Without the flag no SYCL registration IR should be emitted.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
-// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=NONE
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=NONE \
+// RUN: --implicit-check-not='.sycl_offloading.binary' \
+// RUN: --implicit-check-not='__sycl_register_lib' \
+// RUN: --implicit-check-not='llvm.global_dtors'
// A missing binary file must be diagnosed.
// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
@@ -36,12 +41,17 @@ void f() {}
// CHECK-SAME: i32 65535, ptr @_GLOBAL__sub_I_
// CHECK-SAME: i32 1, ptr @sycl.descriptor_reg
// CHECK: @llvm.global_dtors = {{.*}}@sycl.descriptor_unreg
-// CHECK: define internal void @sycl.descriptor_reg()
-// CHECK: call void @__sycl_register_lib(ptr @.sycl_offloading.binary, i64 22)
-// CHECK: define internal void @sycl.descriptor_unreg()
-// CHECK: call void @__sycl_unregister_lib(ptr @.sycl_offloading.binary, i64 22)
-
-// NONE-NOT: .sycl_offloading.binary
-// NONE-NOT: __sycl_register_lib
+// CHECK: define internal void @sycl.descriptor_reg()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__sycl_register_lib(ptr @.sycl_offloading.binary, i64 22)
+// CHECK-NEXT: ret void
+// CHECK: define internal void @sycl.descriptor_unreg()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__sycl_unregister_lib(ptr @.sycl_offloading.binary, i64 22)
+// CHECK-NEXT: ret void
+
+// NONE: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }]
+// NONE-SAME: i32 65535, ptr @_GLOBAL__sub_I_
+// NONE: define dso_local void @_Z1fv()
// ERROR: cannot open file '{{.*}}.does-not-exist'
>From 0e88bd2e84c1477dec1fb967076cfd0e2b18a63a Mon Sep 17 00:00:00 2001
From: "Plyakhin, Yury" <yury.plyakhin at intel.com>
Date: Tue, 18 Aug 2026 11:18:30 -0700
Subject: [PATCH 3/3] addressed feedback
---
clang/lib/CodeGen/CodeGenModule.cpp | 13 +++++++---
clang/lib/CodeGen/CodeGenModule.h | 9 ++++---
clang/lib/CodeGen/CodeGenSYCL.cpp | 12 ++++++---
.../CodeGenSYCL/offload-include-binary.cpp | 4 +--
.../llvm/Frontend/Offloading/OffloadWrapper.h | 12 ++++++---
.../Frontend/Offloading/OffloadWrapper.cpp | 26 ++++++++++++-------
6 files changed, 50 insertions(+), 26 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index db8387f16a73f..3b563e8eae2e9 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1157,6 +1157,15 @@ void CodeGenModule::Release() {
else
EmitCXXGlobalInitFunc();
EmitCXXGlobalCleanUpFunc();
+ if (LangOpts.SYCLIsHost && !CodeGenOpts.OffloadBinaryToEmbedFile.empty()) {
+ auto [SYCLCtorFunction, SYCLDtorFunction] = embedSYCLDeviceBinary();
+ if (SYCLCtorFunction) {
+ // A static initializer may launch a kernel, so the device binaries have
+ // to be registered before any of them run, hence a priority.
+ AddGlobalCtor(SYCLCtorFunction, /*Priority=*/1);
+ AddGlobalDtor(SYCLDtorFunction, /*Priority=*/1);
+ }
+ }
registerGlobalDtorsWithAtExit();
EmitCXXThreadLocalInitFunc();
if (ObjCRuntime)
@@ -1182,10 +1191,6 @@ void CodeGenModule::Release() {
});
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
- // The SYCL image registration functions are added to the constructor and
- // destructor lists which merge into llvm.global_ctors and llvm.global_dtors.
- if (LangOpts.SYCLIsHost && !CodeGenOpts.OffloadBinaryToEmbedFile.empty())
- embedSYCLTargetBinary();
EmitGlobalAnnotations();
EmitStaticExternCAliases();
checkAliases();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 5573ed69f4268..f3e0541636638 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -2179,10 +2179,11 @@ class CodeGenModule : public CodeGenTypeCache {
/// by clang-sycl-linker during device-code splitting.
void addSYCLModuleIdAttr(llvm::Function *Fn);
- /// Embed the finalized SYCL device image named by -foffload-include-binary
- /// into the host module and emit the registration constructors the SYCL
- /// runtime expects.
- void embedSYCLTargetBinary();
+ /// Embed the finalized SYCL device binary named by -foffload-include-binary
+ /// into the host module.
+ /// \return the functions that register and unregister the binary with the
+ /// runtime, both null if the binary could not be read.
+ std::pair<llvm::Function *, llvm::Function *> embedSYCLDeviceBinary();
/// Determine whether the definition must be emitted; if this returns \c
/// false, the definition can be emitted lazily if it's used.
diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp
index de0d3750ae8fd..ba7b246df9869 100644
--- a/clang/lib/CodeGen/CodeGenSYCL.cpp
+++ b/clang/lib/CodeGen/CodeGenSYCL.cpp
@@ -89,18 +89,24 @@ void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
CGF.FinishFunction();
}
-void CodeGenModule::embedSYCLTargetBinary() {
+std::pair<llvm::Function *, llvm::Function *>
+CodeGenModule::embedSYCLDeviceBinary() {
StringRef FileName = getCodeGenOpts().OffloadBinaryToEmbedFile;
auto BufferOrErr = getFileSystem()->getBufferForFile(FileName);
if (std::error_code EC = BufferOrErr.getError()) {
getDiags().Report(diag::err_cannot_open_file) << FileName << EC.message();
- return;
+ return {nullptr, nullptr};
}
std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
+ std::pair<llvm::Function *, llvm::Function *> RegistrationFuncs;
if (llvm::Error Err = llvm::offloading::wrapSYCLBinaries(
getModule(),
ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()),
- llvm::offloading::SYCLJITOptions(), /*IsFinalizedImage=*/true))
+ llvm::offloading::SYCLJITOptions(), /*IsFinalizedImage=*/true,
+ &RegistrationFuncs)) {
getDiags().Report(diag::err_fe_error_backend)
<< llvm::toString(std::move(Err));
+ return {nullptr, nullptr};
+ }
+ return RegistrationFuncs;
}
diff --git a/clang/test/CodeGenSYCL/offload-include-binary.cpp b/clang/test/CodeGenSYCL/offload-include-binary.cpp
index 72e84da7c9cab..02c92328d97ae 100644
--- a/clang/test/CodeGenSYCL/offload-include-binary.cpp
+++ b/clang/test/CodeGenSYCL/offload-include-binary.cpp
@@ -1,9 +1,9 @@
// REQUIRES: x86-registered-target
// Verify that -foffload-include-binary embeds the finalized SYCL device
-// image into the host module and emits the registration/unregistration
+// binary into the host module and emits the registration/unregistration
// constructors and destructors expected by the SYCL runtime.
-// The image is already finalized, so it must not land in ".llvm.offloading".
+// The binary is already finalized, so it must not land in ".llvm.offloading".
// RUN: echo -n 'FAKE_SYCL_DEVICE_IMAGE' > %t.bin
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host \
// RUN: -foffload-include-binary %t.bin -emit-llvm %s -o - \
diff --git a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
index 8767aa942bc80..bf78372168298 100644
--- a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
+++ b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h
@@ -70,10 +70,14 @@ struct SYCLJITOptions {
/// use by a runtime for JIT compilation. Not used for AOT.
/// \param IsFinalizedImage True when \p Buffer holds an already finalized
/// device image, which must not be device-linked again.
-LLVM_ABI llvm::Error wrapSYCLBinaries(llvm::Module &M,
- llvm::ArrayRef<char> Buffer,
- SYCLJITOptions Options = SYCLJITOptions(),
- bool IsFinalizedImage = false);
+/// \param RegistrationFuncs When given, receives the functions that register
+/// and unregister the binary with the runtime instead of them being appended
+/// to llvm.global_ctors and llvm.global_dtors. A caller has to add them
+/// to those lists itself.
+LLVM_ABI llvm::Error wrapSYCLBinaries(
+ llvm::Module &M, llvm::ArrayRef<char> Buffer,
+ SYCLJITOptions Options = SYCLJITOptions(), bool IsFinalizedImage = false,
+ std::pair<llvm::Function *, llvm::Function *> *RegistrationFuncs = nullptr);
} // namespace offloading
} // namespace llvm
diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
index 320a0caf388fd..594f0b70b31b2 100644
--- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
+++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp
@@ -661,7 +661,7 @@ class SYCLWrapper {
return {Start, Size};
}
- void createRegisterFatbinFunction(Constant *Start, Constant *Size) {
+ Function *createRegisterFatbinFunction(Constant *Start, Constant *Size) {
FunctionType *FuncTy =
FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
@@ -680,10 +680,10 @@ class SYCLWrapper {
Builder.CreateCall(RegFuncC, {Start, Size});
Builder.CreateRetVoid();
- appendToGlobalCtors(M, Func, /*Priority*/ 1);
+ return Func;
}
- void createUnregisterFunction(Constant *Start, Constant *Size) {
+ Function *createUnregisterFunction(Constant *Start, Constant *Size) {
FunctionType *FuncTy =
FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
@@ -702,7 +702,7 @@ class SYCLWrapper {
Builder.CreateCall(UnRegFuncC, {Start, Size});
Builder.CreateRetVoid();
- appendToGlobalDtors(M, Func, /*Priority*/ 1);
+ return Func;
}
private:
@@ -753,12 +753,20 @@ Error offloading::wrapHIPBinary(Module &M, ArrayRef<char> Image,
return Error::success();
}
-Error llvm::offloading::wrapSYCLBinaries(llvm::Module &M, ArrayRef<char> Buffer,
- SYCLJITOptions Options,
- bool IsFinalizedImage) {
+Error llvm::offloading::wrapSYCLBinaries(
+ llvm::Module &M, ArrayRef<char> Buffer, SYCLJITOptions Options,
+ bool IsFinalizedImage,
+ std::pair<Function *, Function *> *RegistrationFuncs) {
SYCLWrapper W(M, Options, IsFinalizedImage);
auto [Start, Size] = W.embedBinary(Buffer);
- W.createRegisterFatbinFunction(Start, Size);
- W.createUnregisterFunction(Start, Size);
+ Function *RegisterFunc = W.createRegisterFatbinFunction(Start, Size);
+ Function *UnregisterFunc = W.createUnregisterFunction(Start, Size);
+ if (RegistrationFuncs) {
+ *RegistrationFuncs = {RegisterFunc, UnregisterFunc};
+ return Error::success();
+ }
+
+ appendToGlobalCtors(M, RegisterFunc, /*Priority*/ 1);
+ appendToGlobalDtors(M, UnregisterFunc, /*Priority*/ 1);
return Error::success();
}
More information about the llvm-commits
mailing list