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" <[email protected]> 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 <[email protected]> --- 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" <[email protected]> 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" <[email protected]> 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(); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
