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
