Skip to content

Commit 006e471

Browse files
maksimsabgithub-actions[bot]
authored andcommitted
Automerge: [SYCL] Add offload wrapping for SYCL kind (#147508)
This patch adds an Offload Wrapper for the SYCL kind. This is an essential step for SYCL offloading and the compilation flow. The usage of offload wrapping is added to the clang-linker-wrapper tool. Modifications: Implemented `bundleSYCL()` function to handle SYCL image bundling. Implemented `wrapSYCLBinaries()` function that is invoked from clang-linker-wrapper. SYCL Offload Wrapping uses specific data structures such as `__sycl.tgt_device_image` and `__sycl.tgt_bin_desc`. Each SYCL image maintains its own symbol table (unlike shared global tables in other targets). Therefore, symbols are encoded explicitly during the offload wrapping. Also, images refer to their own Offloading Entries arrays unlike other targets. The proposed `__sycl.tgt_device_image` uses Version 3 to differentiate from images generated by Intel DPC++. The structure proposed in this patch doesn't have fields deprecated in DPC++.
2 parents 9e1e0ea + 65d730b commit 006e471

File tree

9 files changed

+517
-11
lines changed

9 files changed

+517
-11
lines changed

clang/test/Driver/linker-wrapper-image.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// REQUIRES: x86-registered-target
22
// REQUIRES: nvptx-registered-target
33
// REQUIRES: amdgpu-registered-target
4+
// REQUIRES: spirv-registered-target
45

56
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.elf.o
67

@@ -263,3 +264,36 @@
263264
// HIP: while.end:
264265
// HIP-NEXT: ret void
265266
// HIP-NEXT: }
267+
268+
// RUN: clang-offload-packager -o %t.out --image=file=%t.elf.o,kind=sycl,triple=spirv64-unknown-unknown,arch=generic
269+
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o \
270+
// RUN: -fembed-offload-object=%t.out
271+
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
272+
// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=SYCL
273+
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu -r \
274+
// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=SYCL
275+
276+
// SYCL: %__sycl.tgt_device_image = type { i16, i8, i8, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
277+
// SYCL-NEXT: %__sycl.tgt_bin_desc = type { i16, i16, ptr, ptr, ptr }
278+
279+
// SYCL: @.sycl_offloading.target.0 = internal unnamed_addr constant [1 x i8] zeroinitializer
280+
// SYCL-NEXT: @.sycl_offloading.opts.compile.0 = internal unnamed_addr constant [1 x i8] zeroinitializer
281+
// SYCL-NEXT: @.sycl_offloading.opts.link.0 = internal unnamed_addr constant [1 x i8] zeroinitializer
282+
// SYCL-NEXT: @.sycl_offloading.0.data = internal unnamed_addr constant [0 x i8] zeroinitializer, section ".llvm.offloading"
283+
// SYCL-NEXT: @.offloading.entry_name = internal unnamed_addr constant [5 x i8] c"stub\00", section ".llvm.rodata.offloading", align 1
284+
// SYCL-NEXT: @.offloading.entry.stub = weak constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 8, i32 0, ptr null, ptr @.offloading.entry_name, i64 0, i64 0, ptr null }, section "llvm_offload_entries", align 8
285+
// SYCL-NEXT: @.sycl_offloading.entries_arr = internal constant [1 x %struct.__tgt_offload_entry] [%struct.__tgt_offload_entry { i64 0, i16 1, i16 8, i32 0, ptr null, ptr @.offloading.entry_name, i64 0, i64 0, ptr null }]
286+
// SYCL-NEXT: @.sycl_offloading.device_images = internal unnamed_addr constant [1 x %__sycl.tgt_device_image] [%__sycl.tgt_device_image { i16 3, i8 8, i8 0, ptr @.sycl_offloading.target.0, ptr @.sycl_offloading.opts.compile.0, ptr @.sycl_offloading.opts.link.0, ptr @.sycl_offloading.0.data, ptr @.sycl_offloading.0.data, ptr @.sycl_offloading.entries_arr, ptr getelementptr ([1 x %struct.__tgt_offload_entry], ptr @.sycl_offloading.entries_arr, i64 0, i64 1), ptr null, ptr null }]
287+
// SYCL-NEXT: @.sycl_offloading.descriptor = internal constant %__sycl.tgt_bin_desc { i16 1, i16 1, ptr @.sycl_offloading.device_images, ptr null, ptr null }
288+
289+
// SYCL: define internal void @sycl.descriptor_reg() section ".text.startup" {
290+
// SYCL-NEXT: entry:
291+
// SYCL-NEXT: call void @__sycl_register_lib(ptr @.sycl_offloading.descriptor)
292+
// SYCL-NEXT: ret void
293+
// SYCL-NEXT: }
294+
295+
// SYCL: define internal void @sycl.descriptor_unreg() section ".text.startup" {
296+
// SYCL-NEXT: entry:
297+
// SYCL-NEXT: call void @__sycl_unregister_lib(ptr @.sycl_offloading.descriptor)
298+
// SYCL-NEXT: ret void
299+
// SYCL-NEXT: }

clang/test/Driver/linker-wrapper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ __attribute__((visibility("protected"), used)) int x;
5454
// RUN: clang-offload-packager -o %t.out \
5555
// RUN: --image=file=%t.spirv.bc,kind=sycl,triple=spirv64-unknown-unknown,arch=generic
5656
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
57-
// RUN: not clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
57+
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
5858
// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=SPIRV-LINK
5959

6060
// SPIRV-LINK: clang{{.*}} -o {{.*}}.img -dumpdir a.out.spirv64..img. --target=spirv64-unknown-unknown {{.*}}.o --sycl-link -Xlinker -triple=spirv64-unknown-unknown -Xlinker -arch=

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,14 @@ wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
717717
M, BuffersToWrap.front(), offloading::getOffloadEntryArray(M)))
718718
return std::move(Err);
719719
break;
720+
case OFK_SYCL: {
721+
// TODO: fill these options once the Driver supports them.
722+
offloading::SYCLJITOptions Options;
723+
if (Error Err =
724+
offloading::wrapSYCLBinaries(M, BuffersToWrap.front(), Options))
725+
return std::move(Err);
726+
break;
727+
}
720728
default:
721729
return createStringError(getOffloadKindName(Kind) +
722730
" wrapping is not supported");
@@ -754,6 +762,32 @@ bundleOpenMP(ArrayRef<OffloadingImage> Images) {
754762
return std::move(Buffers);
755763
}
756764

765+
Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
766+
bundleSYCL(ArrayRef<OffloadingImage> Images) {
767+
SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
768+
if (DryRun) {
769+
// In dry-run mode there is an empty input which is insufficient for the
770+
// testing. Therefore, we return here a stub image.
771+
OffloadingImage Image;
772+
Image.TheImageKind = IMG_None;
773+
Image.TheOffloadKind = OffloadKind::OFK_SYCL;
774+
Image.StringData["symbols"] = "stub";
775+
Image.Image = MemoryBuffer::getMemBufferCopy("");
776+
SmallString<0> SerializedImage = OffloadBinary::write(Image);
777+
Buffers.emplace_back(MemoryBuffer::getMemBufferCopy(SerializedImage));
778+
return std::move(Buffers);
779+
}
780+
781+
for (const OffloadingImage &Image : Images) {
782+
// clang-sycl-linker packs outputs into one binary blob. Therefore, it is
783+
// passed to Offload Wrapper as is.
784+
StringRef S(Image.Image->getBufferStart(), Image.Image->getBufferSize());
785+
Buffers.emplace_back(MemoryBuffer::getMemBufferCopy(S));
786+
}
787+
788+
return std::move(Buffers);
789+
}
790+
757791
Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
758792
bundleCuda(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
759793
SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
@@ -806,8 +840,9 @@ bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const ArgList &Args,
806840
llvm::TimeTraceScope TimeScope("Bundle linked output");
807841
switch (Kind) {
808842
case OFK_OpenMP:
809-
case OFK_SYCL:
810843
return bundleOpenMP(Images);
844+
case OFK_SYCL:
845+
return bundleSYCL(Images);
811846
case OFK_Cuda:
812847
return bundleCuda(Images, Args);
813848
case OFK_HIP:

llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "llvm/IR/Module.h"
1414
#include "llvm/Support/Compiler.h"
1515

16+
#include <string>
17+
1618
namespace llvm {
1719
namespace offloading {
1820
using EntryArrayTy = std::pair<GlobalVariable *, GlobalVariable *>;
@@ -52,6 +54,24 @@ LLVM_ABI llvm::Error wrapHIPBinary(llvm::Module &M, llvm::ArrayRef<char> Images,
5254
EntryArrayTy EntryArray,
5355
llvm::StringRef Suffix = "",
5456
bool EmitSurfacesAndTextures = true);
57+
58+
struct SYCLJITOptions {
59+
// Target/compiler specific options that are suggested to use to "compile"
60+
// program at runtime.
61+
std::string CompileOptions;
62+
// Target/compiler specific options that are suggested to use to "link"
63+
// program at runtime.
64+
std::string LinkOptions;
65+
};
66+
67+
/// Wraps OffloadBinaries in the given \p Buffers into the module \p M
68+
/// as global symbols and registers the images with the SYCL Runtime.
69+
/// \param Options Compiler and linker options to be encoded for the later
70+
/// use by a runtime for JIT compilation.
71+
LLVM_ABI llvm::Error
72+
wrapSYCLBinaries(llvm::Module &M, llvm::ArrayRef<char> Buffer,
73+
SYCLJITOptions Options = SYCLJITOptions());
74+
5575
} // namespace offloading
5676
} // namespace llvm
5777

llvm/include/llvm/Frontend/Offloading/Utility.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ LLVM_ABI StructType *getEntryTy(Module &M);
8282
/// \param Data Extra data storage associated with the entry.
8383
/// \param SectionName The section this entry will be placed at.
8484
/// \param AuxAddr An extra pointer if needed.
85-
LLVM_ABI void
85+
/// \return The emitted global variable containing the offloading entry.
86+
LLVM_ABI GlobalVariable *
8687
emitOffloadingEntry(Module &M, object::OffloadKind Kind, Constant *Addr,
8788
StringRef Name, uint64_t Size, uint32_t Flags,
8889
uint64_t Data, Constant *AuxAddr = nullptr,

llvm/include/llvm/Object/OffloadBinary.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum ImageKind : uint16_t {
4848
IMG_Cubin,
4949
IMG_Fatbinary,
5050
IMG_PTX,
51+
IMG_SPIRV,
5152
IMG_LAST,
5253
};
5354

@@ -70,9 +71,9 @@ class OffloadBinary : public Binary {
7071

7172
/// The offloading metadata that will be serialized to a memory buffer.
7273
struct OffloadingImage {
73-
ImageKind TheImageKind;
74-
OffloadKind TheOffloadKind;
75-
uint32_t Flags;
74+
ImageKind TheImageKind = ImageKind::IMG_None;
75+
OffloadKind TheOffloadKind = OffloadKind::OFK_None;
76+
uint32_t Flags = 0;
7677
MapVector<StringRef, StringRef> StringData;
7778
std::unique_ptr<MemoryBuffer> Image;
7879
};

0 commit comments

Comments
 (0)