Author: Konstantinos Parasyris
Date: 2026-09-18T15:59:25-07:00
New Revision: 3e93e9368f9167e5129f369194db08edcdf167d6

URL: 
https://github.com/llvm/llvm-project/commit/3e93e9368f9167e5129f369194db08edcdf167d6
DIFF: 
https://github.com/llvm/llvm-project/commit/3e93e9368f9167e5129f369194db08edcdf167d6.diff

LOG: [CIR][SYCL] Embed and register offloaded device binary on host path 
(#224692)

Added: 
    clang/test/CIR/CodeGenSYCL/offload-include-binary.cpp

Modified: 
    clang/lib/CIR/FrontendAction/CIRGenAction.cpp
    clang/lib/CIR/FrontendAction/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp 
b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 11b78b717ba68..240601f9834e5 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -12,6 +12,7 @@
 #include "mlir/IR/OwningOpRef.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/DiagnosticCodeGen.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/CIR/CIRGenerator.h"
 #include "clang/CIR/CIRToCIRPasses.h"
 #include "clang/CIR/LowerToLLVM.h"
@@ -21,12 +22,14 @@
 #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"
@@ -208,6 +211,10 @@ class CIRGenConsumer : public clang::ASTConsumer {
       if (linkInModules(*LLVMModule))
         return;
 
+      // Embed the offloaded SYCL device binary into the host module.
+      if (C.getLangOpts().SYCLIsHost && !CGO.OffloadBinaryToEmbedFile.empty())
+        embedSYCLDeviceBinary(*LLVMModule);
+
       BackendAction BEAction = getBackendActionFromOutputType(Action);
       emitBackendOutput(CI, CI.getCodeGenOpts(), LLVMModule.get(), BEAction, 
FS,
                         std::move(OutputStream));
@@ -251,6 +258,28 @@ class CIRGenConsumer : public clang::ASTConsumer {
     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;
+    }
+  }
+
   void HandleTagDeclDefinition(TagDecl *D) override {
     PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                    Context->getSourceManager(),

diff  --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt 
b/clang/lib/CIR/FrontendAction/CMakeLists.txt
index d221771fd4086..b6b1e8b2bbbe2 100644
--- a/clang/lib/CIR/FrontendAction/CMakeLists.txt
+++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(LLVM_LINK_COMPONENTS
   Core
+  FrontendOffloading
   ipo
   Linker
   Support

diff  --git a/clang/test/CIR/CodeGenSYCL/offload-include-binary.cpp 
b/clang/test/CIR/CodeGenSYCL/offload-include-binary.cpp
new file mode 100644
index 0000000000000..dca4b38f3f4c3
--- /dev/null
+++ b/clang/test/CIR/CodeGenSYCL/offload-include-binary.cpp
@@ -0,0 +1,57 @@
+// REQUIRES: x86-registered-target
+
+// Verify that on the ClangIR path -foffload-include-binary embeds the 
finalized
+// SYCL device binary into the host module and emits the constructor that
+// registers it with the SYCL runtime, matching classic CodeGen. Unregistration
+// is done from 'atexit', so no global destructor is emitted for it.
+// 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 -fclangir \
+// RUN:   -foffload-include-binary %t.bin -emit-llvm %s -o - \
+// RUN:   | FileCheck %s --implicit-check-not='.llvm.offloading' \
+// RUN:     --implicit-check-not='llvm.global_dtors'
+
+// Object emission must succeed for a translation unit that has its own static
+// initializers, so the registration ctor merges into the existing ctor list.
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host -fclangir \
+// RUN:   -foffload-include-binary %t.bin -emit-obj %s -o %t.o
+
+// Without the flag no SYCL registration IR should be emitted.
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsycl-is-host -fclangir \
+// 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 
-fclangir \
+// 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 101, ptr @sycl.descriptor_reg
+// 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:   {{.*}}call i32 @atexit(ptr @sycl.descriptor_unreg)
+// 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'


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to