Skip to content

Commit 0482586

Browse files
committed
[SYCL] Implement sycl_ext_oneapi_kernel_compiler_spirv
Implements the extension described in #11954. This PR includes the following changes: - Adds a `create_kernel_bundle_from_source` overload for `std::vector<std::byte>` kernel sources. - Adds new `source_language::spirv`. - Defines `SYCL_EXT_ONEAPI_KERNEL_COMPILER_SPIRV`. - Adds support for SPIR-V kernels created from `std::vector<std::byte>` sources. - Moves `sycl_ext_oneapi_kernel_compiler_spirv.asciidoc` from `proposed` to `experimental`. Signed-off-by: Michael Aziz <[email protected]>
1 parent 53ab58a commit 0482586

File tree

8 files changed

+159
-23
lines changed

8 files changed

+159
-23
lines changed

sycl/doc/extensions/proposed/sycl_ext_oneapi_kernel_compiler_spirv.asciidoc renamed to sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler_spirv.asciidoc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,12 @@ This extension also depends on the following other SYCL extensions:
5252

5353
== Status
5454

55-
This is a proposed extension specification, intended to gather community
56-
feedback.
57-
Interfaces defined in this specification may not be implemented yet or may be
58-
in a preliminary state.
59-
The specification itself may also change in incompatible ways before it is
60-
finalized.
61-
*Shipping software products should not rely on APIs defined in this
62-
specification.*
55+
This is an experimental extension specification, intended to provide early
56+
access to features and gather community feedback. Interfaces defined in
57+
this specification are implemented in DPC++, but they are not finalized
58+
and may change incompatibly in future versions of DPC++ without prior notice.
59+
*Shipping software products should not rely on APIs defined in
60+
this specification.*
6361

6462

6563
== Overview

sycl/include/sycl/kernel_bundle.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#pragma once
1010

11+
#include <cstddef> // for std::byte
1112
#include <sycl/backend_types.hpp> // for backend, backend_return_t
1213
#include <sycl/context.hpp> // for context
1314
#include <sycl/detail/export.hpp> // for __SYCL_EXPORT
@@ -887,10 +888,14 @@ __SYCL_EXPORT bool is_source_kernel_bundle_supported(backend BE,
887888
// syclex::create_kernel_bundle_from_source
888889
/////////////////////////
889890
__SYCL_EXPORT kernel_bundle<bundle_state::ext_oneapi_source>
890-
create_kernel_bundle_from_source(
891-
const context &SyclContext,
892-
sycl::ext::oneapi::experimental::source_language Language,
893-
const std::string &Source);
891+
create_kernel_bundle_from_source(const context &SyclContext,
892+
source_language Language,
893+
const std::string &Source);
894+
895+
__SYCL_EXPORT kernel_bundle<bundle_state::ext_oneapi_source>
896+
create_kernel_bundle_from_source(const context &SyclContext,
897+
source_language Language,
898+
const std::vector<std::byte> &Bytes);
894899

895900
/////////////////////////
896901
// syclex::build(source_kb) => exe_kb

sycl/include/sycl/kernel_bundle_enums.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ enum class bundle_state : char {
2020

2121
namespace ext::oneapi::experimental {
2222

23-
enum class source_language : int { opencl = 0 /* sycl , spir-v, cuda */ };
23+
enum class source_language : int { opencl = 0, spirv = 1 /* sycl, cuda */ };
2424

2525
} // namespace ext::oneapi::experimental
2626

sycl/source/detail/kernel_bundle_impl.hpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <algorithm>
2424
#include <cassert>
25+
#include <cstdint>
2526
#include <cstring>
2627
#include <memory>
2728
#include <vector>
@@ -334,6 +335,14 @@ class kernel_bundle_impl {
334335
: MContext(Context), MDevices(Context.get_devices()),
335336
MState(bundle_state::ext_oneapi_source), Language(Lang), Source(Src) {}
336337

338+
// oneapi_ext_kernel_compiler
339+
// construct from source bytes
340+
kernel_bundle_impl(const context &Context, syclex::source_language Lang,
341+
const std::vector<std::byte> &Bytes)
342+
: MContext(Context), MDevices(Context.get_devices()),
343+
MState(bundle_state::ext_oneapi_source), Language(Lang), Source(Bytes) {
344+
}
345+
337346
// oneapi_ext_kernel_compiler
338347
// interop constructor
339348
kernel_bundle_impl(context Ctx, std::vector<device> Devs,
@@ -350,17 +359,30 @@ class kernel_bundle_impl {
350359
std::string *LogPtr) {
351360
assert(MState == bundle_state::ext_oneapi_source &&
352361
"bundle_state::ext_oneapi_source required");
353-
assert(Language == syclex::source_language::opencl &&
354-
"TODO: add other Languages. Must be OpenCL");
355-
if (Language != syclex::source_language::opencl)
356-
throw sycl::exception(
357-
make_error_code(errc::invalid),
358-
"OpenCL C is the only supported language at this time");
362+
assert((Language == syclex::source_language::opencl ||
363+
Language == syclex::source_language::spirv) &&
364+
"TODO: add other Languages. Must be OpenCL or SPIR-V");
359365

360366
// if successful, the log is empty. if failed, throws an error with the
361367
// compilation log.
362-
auto spirv =
363-
syclex::detail::OpenCLC_to_SPIRV(this->Source, BuildOptions, LogPtr);
368+
const auto spirv = [&]() -> std::vector<uint8_t> {
369+
if (Language == syclex::source_language::opencl) {
370+
const auto &SourceStr = std::get<std::string>(this->Source);
371+
return syclex::detail::OpenCLC_to_SPIRV(SourceStr, BuildOptions,
372+
LogPtr);
373+
}
374+
if (Language == syclex::source_language::spirv) {
375+
const auto &SourceBytes =
376+
std::get<std::vector<std::byte>>(this->Source);
377+
std::vector<uint8_t> Result(SourceBytes.size());
378+
std::transform(SourceBytes.cbegin(), SourceBytes.cend(), Result.begin(),
379+
[](std::byte B) { return static_cast<uint8_t>(B); });
380+
return Result;
381+
}
382+
throw sycl::exception(
383+
make_error_code(errc::invalid),
384+
"OpenCL C and SPIR-V are the only supported languages at this time");
385+
}();
364386

365387
// see also program_manager.cpp::createSpirvProgram()
366388
using ContextImplPtr = std::shared_ptr<sycl::detail::context_impl>;
@@ -682,7 +704,7 @@ class kernel_bundle_impl {
682704
bundle_state MState;
683705
// ext_oneapi_kernel_compiler : Source, Languauge, KernelNames
684706
const syclex::source_language Language = syclex::source_language::opencl;
685-
const std::string Source;
707+
const std::variant<std::string, std::vector<std::byte>> Source;
686708
// only kernel_bundles created from source have KernelNames member.
687709
std::vector<std::string> KernelNames;
688710
};

sycl/source/feature_test.hpp.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ inline namespace _V1 {
4545
#define SYCL_EXT_ONEAPI_GROUP_SORT 1
4646
#define SYCL_EXT_ONEAPI_KERNEL_COMPILER 1
4747
#define SYCL_EXT_ONEAPI_KERNEL_COMPILER_OPENCL 1
48+
#define SYCL_EXT_ONEAPI_KERNEL_COMPILER_SPIRV 1
4849
#define SYCL_EXT_ONEAPI_MAX_WORK_GROUP_QUERY 1
4950
#define SYCL_EXT_ONEAPI_ND_RANGE_REDUCTIONS 1
5051
#define SYCL_EXT_ONEAPI_DEFAULT_CONTEXT 1

sycl/source/kernel_bundle.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
#include <detail/kernel_id_impl.hpp>
1313
#include <detail/program_manager/program_manager.hpp>
1414

15+
#include <cstddef>
1516
#include <set>
17+
#include <vector>
1618

1719
namespace sycl {
1820
inline namespace _V1 {
@@ -372,7 +374,9 @@ bool is_source_kernel_bundle_supported(backend BE, source_language Language) {
372374
// and it's support is limited to the opencl and level_zero backends.
373375
bool BE_Acceptable = (BE == sycl::backend::ext_oneapi_level_zero) ||
374376
(BE == sycl::backend::opencl);
375-
if ((Language == source_language::opencl) && BE_Acceptable) {
377+
if ((Language == source_language::opencl ||
378+
Language == source_language::spirv) &&
379+
BE_Acceptable) {
376380
return detail::OpenCLC_Compilation_Available();
377381
}
378382

@@ -399,6 +403,20 @@ source_kb create_kernel_bundle_from_source(const context &SyclContext,
399403
return sycl::detail::createSyclObjFromImpl<source_kb>(KBImpl);
400404
}
401405

406+
source_kb
407+
create_kernel_bundle_from_source(const context &SyclContext,
408+
source_language Language,
409+
const std::vector<std::byte> &Bytes) {
410+
backend BE = SyclContext.get_backend();
411+
if (!is_source_kernel_bundle_supported(BE, Language))
412+
throw sycl::exception(make_error_code(errc::invalid),
413+
"kernel_bundle creation from source not supported");
414+
415+
std::shared_ptr<kernel_bundle_impl> KBImpl =
416+
std::make_shared<kernel_bundle_impl>(SyclContext, Language, Bytes);
417+
return sycl::detail::createSyclObjFromImpl<source_kb>(KBImpl);
418+
}
419+
402420
/////////////////////////
403421
// syclex::detail::build_from_source(source_kb) => exe_kb
404422
/////////////////////////
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__kernel void my_kernel(__global int *in, __global int *out) {
2+
size_t i = get_global_id(0);
3+
out[i] = in[i]*2 + 100;
4+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//==- kernel_compiler_spirv.cpp --------------------------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: ocloc
10+
11+
// RUN: ocloc -spv_only -file %S/Kernels/my_kernel.cl -o %t.spv
12+
// RUN: %{build} -o %t.out
13+
// RUN: %{run} %t.out %t.spv
14+
15+
// Test case for the sycl_ext_oneapi_kernel_compiler_spirv extension. This test
16+
// loads a pre-compiled kernel from a SPIR-V file and runs it.
17+
18+
#include <cassert>
19+
#include <fstream>
20+
#include <sycl/sycl.hpp>
21+
22+
using namespace sycl;
23+
24+
void testSyclKernel(sycl::queue &Q, sycl::kernel Kernel, int multiplier,
25+
int added) {
26+
constexpr int N = 4;
27+
cl_int InputArray[N] = {0, 1, 2, 3};
28+
cl_int OutputArray[N] = {};
29+
30+
sycl::buffer InputBuf(InputArray, sycl::range<1>(N));
31+
sycl::buffer OutputBuf(OutputArray, sycl::range<1>(N));
32+
33+
Q.submit([&](sycl::handler &CGH) {
34+
CGH.set_arg(0, InputBuf.get_access<sycl::access::mode::read>(CGH));
35+
CGH.set_arg(1, OutputBuf.get_access<sycl::access::mode::write>(CGH));
36+
CGH.parallel_for(sycl::range<1>{N}, Kernel);
37+
});
38+
39+
sycl::host_accessor Out{OutputBuf};
40+
for (int I = 0; I < N; I++) {
41+
assert(Out[I] == ((I * multiplier) + added));
42+
}
43+
}
44+
45+
void testKernelFromSpvFile(std::string file_name) {
46+
namespace syclex = sycl::ext::oneapi::experimental;
47+
48+
sycl::queue q;
49+
50+
// Read the SPIR-V module from disk.
51+
std::ifstream spv_stream(file_name, std::ios::binary);
52+
spv_stream.seekg(0, std::ios::end);
53+
size_t sz = spv_stream.tellg();
54+
spv_stream.seekg(0);
55+
std::vector<std::byte> spv(sz);
56+
spv_stream.read(reinterpret_cast<char *>(spv.data()), sz);
57+
58+
// Create a kernel bundle from the binary SPIR-V.
59+
sycl::kernel_bundle<sycl::bundle_state::ext_oneapi_source> kb_src =
60+
syclex::create_kernel_bundle_from_source(
61+
q.get_context(), syclex::source_language::spirv, spv);
62+
63+
// Build the SPIR-V module for our device.
64+
sycl::kernel_bundle<sycl::bundle_state::executable> kb_exe =
65+
syclex::build(kb_src);
66+
67+
// Get a "kernel" object representing the kernel from the SPIR-V module.
68+
sycl::kernel my_kernel = kb_exe.ext_oneapi_get_kernel("my_kernel");
69+
70+
// Test the kernel
71+
auto my_num_args = my_kernel.get_info<sycl::info::kernel::num_args>();
72+
assert(my_num_args == 2 && "my_kernel should take 2 args");
73+
testSyclKernel(q, my_kernel, 2, 100);
74+
}
75+
76+
int main(int argc, char **argv) {
77+
#ifndef SYCL_EXT_ONEAPI_KERNEL_COMPILER_SPIRV
78+
static_assert(false, "KernelCompiler SPIR-V feature test macro undefined");
79+
#endif
80+
81+
#ifdef SYCL_EXT_ONEAPI_KERNEL_COMPILER
82+
assert(argc == 2 && "Usage: ./%t.out <kernel-spv-file>");
83+
testKernelFromSpvFile(argv[1]);
84+
#else
85+
static_assert(false, "Kernel Compiler feature test macro undefined");
86+
#endif
87+
return 0;
88+
}

0 commit comments

Comments
 (0)