Skip to content

Commit d85f338

Browse files
authored
[SYCL][Doc] Add spec for "spirv" to kernel compiler (#11954)
Add an extension that defines support for online compiled kernels that are written in binary SPIR-V.
1 parent 7085686 commit d85f338

File tree

3 files changed

+311
-2
lines changed

3 files changed

+311
-2
lines changed

sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler.asciidoc

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,26 @@ kernel_bundle<bundle_state::ext_oneapi_source> create_kernel_bundle_from_source(
177177
source_language lang,
178178
const std::string& source)
179179
180+
kernel_bundle<bundle_state::ext_oneapi_source> create_kernel_bundle_from_source(
181+
const context& ctxt,
182+
source_language lang,
183+
const std::vector<std::byte>& bytes)
184+
180185
} // namespace sycl::ext::oneapi::experimental
181186
----
182187
!====
183188

184-
_Effects:_ Creates a new kernel bundle that represents a kernel that is defined
185-
by the source code string `source` using the language `lang`.
189+
_Preconditions:_ There are two overloads of this function: one that reads the
190+
source code of the kernel from an `std::string`, and one that reads the source
191+
code of the kernel from an `std::vector` of `std::byte`.
192+
Each source language `lang` specifies whether the language is text format or
193+
binary format, and the application must use the overload that corresponds to
194+
that format.
195+
196+
_Effects:_ Creates a new kernel bundle that represents a kernel written in the
197+
source language `lang`, where the source code is contained either by `source`
198+
(if the source language is a text format) or by `bytes` (if the source language
199+
is binary format).
186200
The bundle is associated with the context `ctxt`, and kernels from this bundle
187201
may only be submitted to a queue that shares the same context.
188202
The bundle's set of associated devices is the set of devices contained in

sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler_opencl.asciidoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ enum class source_language : /*unspecified*/ {
107107
} // namespace sycl::ext::oneapi::experimental
108108
```
109109

110+
=== Source code is text format
111+
112+
Kernels written in the `opencl` language are text format.
113+
As a result, the application must use the overload of
114+
`create_kernel_bundle_from_source` taking `std::string` when creating a kernel
115+
bundle from this language.
116+
110117
=== Build options
111118

112119
The `build_options` property accepts any of the compiler or linker options
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
= sycl_ext_oneapi_kernel_compiler_spirv
2+
3+
:source-highlighter: coderay
4+
:coderay-linenums-mode: table
5+
6+
// This section needs to be after the document title.
7+
:doctype: book
8+
:toc2:
9+
:toc: left
10+
:encoding: utf-8
11+
:lang: en
12+
:dpcpp: pass:[DPC++]
13+
:endnote: &#8212;{nbsp}end{nbsp}note
14+
15+
// Set the default source code type in this document to C++,
16+
// for syntax highlighting purposes. This is needed because
17+
// docbook uses c++ and html5 uses cpp.
18+
:language: {basebackend@docbook:c++:cpp}
19+
20+
21+
== Notice
22+
23+
[%hardbreaks]
24+
Copyright (C) 2023-2023 Intel Corporation. All rights reserved.
25+
26+
Khronos(R) is a registered trademark and SYCL(TM) and SPIR(TM) are trademarks
27+
of The Khronos Group Inc.
28+
OpenCL(TM) is a trademark of Apple Inc. used by permission by Khronos.
29+
30+
31+
== Contact
32+
33+
To report problems with this extension, please open a new issue at:
34+
35+
https://github.com/intel/llvm/issues
36+
37+
38+
== Dependencies
39+
40+
This extension is written against the SYCL 2020 revision 8 specification.
41+
All references below to the "core SYCL specification" or to section numbers in
42+
the SYCL specification refer to that revision.
43+
This extension also depends on the SPIR-V version 1.6, revision 2
44+
specification.
45+
All references below to the "SPIR-V specification" refer to that revision.
46+
47+
This extension also depends on the following other SYCL extensions:
48+
49+
* link:../experimental/sycl_ext_oneapi_kernel_compiler.asciidoc[
50+
sycl_ext_oneapi_kernel_compiler]
51+
52+
53+
== Status
54+
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.*
63+
64+
65+
== Overview
66+
67+
This is an extension to
68+
link:../experimental/sycl_ext_oneapi_kernel_compiler.asciidoc[
69+
sycl_ext_oneapi_kernel_compiler], which allows an application to define a
70+
kernel as a SPIR-V binary module when dynamically compiling a kernel from
71+
source.
72+
One possible use case is an application that stores pre-compiled kernels as
73+
individual SPIR-V files.
74+
The application can load one of these files at runtime and then use this
75+
extension to enqueue the kernel and set its arguments.
76+
77+
78+
== Specification
79+
80+
=== Feature test macro
81+
82+
This extension provides a feature-test macro as described in the core SYCL
83+
specification.
84+
An implementation supporting this extension must predefine the macro
85+
`SYCL_EXT_ONEAPI_KERNEL_COMPILER_SPIRV`
86+
to one of the values defined in the table below.
87+
Applications can test for the existence of this macro to determine if the
88+
implementation supports this feature, or applications can test the macro's
89+
value to determine which of the extension's features the implementation
90+
supports.
91+
92+
[%header,cols="1,5"]
93+
|===
94+
|Value
95+
|Description
96+
97+
|1
98+
|The APIs of this experimental extension are not versioned, so the
99+
feature-test macro always has this value.
100+
|===
101+
102+
=== New source language enumerator
103+
104+
This extension adds the `spirv` enumerator to the `source_language`
105+
enumeration, which indicates that a kernel bundle defines kernels as a SPIR-V
106+
binary module.
107+
108+
```
109+
namespace sycl::ext::oneapi::experimental {
110+
111+
enum class source_language : /*unspecified*/ {
112+
// ...
113+
spirv
114+
};
115+
116+
} // namespace sycl::ext::oneapi::experimental
117+
```
118+
119+
=== Source code is binary format
120+
121+
Kernels written in the `spirv` language are SPIR-V binary modules.
122+
As a result, the application must use the overload of
123+
`create_kernel_bundle_from_source` taking `std::vector<std::byte>` when
124+
creating a kernel bundle from this language.
125+
126+
=== Build options
127+
128+
This extension does not specify any options that may be passed via the
129+
`build_options` property, however an implementation may allow
130+
implementation-defined options to be passed this way.
131+
132+
=== SPIR-V execution environment
133+
134+
The precise rules for interpreting a SPIR-V module are defined both by the
135+
SPIR-V specification and by the SPIR-V execution environment.
136+
For the purposes of this SYCL extension, the SPIR-V execution environment is
137+
defined by the SYCL backend.
138+
Each SYCL backend that supports this extension must provide a SPIR-V client API
139+
specification that formally defines the SPIR-V execution environment.
140+
141+
[_Note:_ {dpcpp} provides two backends that can support this SYCL extension,
142+
and each has its own SPIR-V client API.
143+
For the Level Zero backend, see the
144+
https://spec.oneapi.io/level-zero/latest/core/SPIRV.html[SPIR-V Programming
145+
Guide].
146+
For the OpenCL backend, see the
147+
https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_Env.html[
148+
OpenCL SPIR-V Environment Specification].
149+
_{endnote}_]
150+
151+
=== Obtaining a kernel
152+
153+
In SPIR-V, a kernel is represented as an *OpEntryPoint*, which has a literal
154+
_Name_ parameter.
155+
The `ext_oneapi_has_kernel` and `ext_oneapi_get_kernel` member functions
156+
identify a kernel using the name, exactly as it appears in the *OpEntryPoint*
157+
instruction.
158+
For example, if the kernel is defined this way in SPIR-V:
159+
160+
```
161+
OpEntryPoint Kernel %20 "foo"
162+
```
163+
164+
Then the application's host code can query for the kernel like so:
165+
166+
```
167+
sycl::kernel_bundle<sycl::bundle_state::executable> kb = /*...*/;
168+
sycl::kernel k = kb.ext_oneapi_get_kernel("foo");
169+
```
170+
171+
=== Passing kernel arguments
172+
173+
The SPIR-V *OpEntryPoint* that defines a kernel has an associated *OpFunction*.
174+
This *OpFunction* is followed by a list of *OpFunctionParameter* instructions,
175+
one for each kernel argument.
176+
The following table defines the set of argument types that are supported by
177+
this extension, and explains how to pass each type of argument from SYCL.
178+
However, the set of supported argument types may be further limited by the
179+
backend's SPIR-V client API specification.
180+
181+
[%header,cols="1,1"]
182+
|===
183+
|SPIR-V type
184+
|Corresponding SYCL type
185+
186+
|*OpTypeInt*
187+
|A C++ type that is device copyable, which has the same width and data
188+
representation.
189+
190+
[_Note:_ Applications typically use a fixed-width integer type where the width
191+
matches the width of the *OpTypeInt*.
192+
_{endnote}_]
193+
194+
|*OpTypeFloat*
195+
|A C++ type that is device copyable, which has the same width and data
196+
representation.
197+
198+
[_Note:_ Applications typically use `float` when the *OpTypeFloat* has a width
199+
of 32, `double` when the *OpTypeFloat* has a width of 64, and `sycl::half` when
200+
the *OpTypeFloat* has a width of 16.
201+
_{endnote}_]
202+
203+
|*OpTypePointer* with storage class *CrossWorkgroup*
204+
|Either a pointer to USM memory or an `accessor` whose target is
205+
`target::device`.
206+
207+
|*OpTypePointer* with storage class *Workgroup*
208+
|A `local_accessor`.
209+
210+
|*OpTypeStruct* whose member types are limited to *OpTypeInt*, *OpTypeFloat*,
211+
and *OpTypePointer* (with storage class *CrossWorkgroup*).
212+
The *OpTypeStruct* may contain members which are also *OpTypeStruct* so long
213+
as its members are limited to the same types.
214+
|A C++ struct or class that is device copyable.
215+
Each member variable must have the corresponding type as defined above,
216+
except that an *OpTypePointer* member must correspond to a USM pointer.
217+
It is not valid to pass an `accessor` for these members.
218+
|===
219+
220+
When data allocated on the host is accessed by the kernel via a pointer, the
221+
application must ensure that the data has the same size and representation on
222+
the host and inside the SPIR-V module.
223+
224+
[_Note:_ Applications should consider using the fixed-width integer types when
225+
allocating integer data that will be accessed by the kernel through a pointer
226+
because this helps ensure that the size of the integers on the host matches the
227+
size in the kernel.
228+
_{endnote}_]
229+
230+
231+
== Example
232+
233+
The following example shows a simple SYCL program that loads a SPIR-V module
234+
from a file and then launches a kernel from that module.
235+
236+
```
237+
#include <cstddef>
238+
#include <cstdint>
239+
#include <fstream>
240+
#include <vector>
241+
#include <sycl/sycl.hpp>
242+
243+
namespace syclex = sycl::ext::oneapi::experimental;
244+
245+
int main() {
246+
sycl::queue q;
247+
248+
// Read the SPIR-V module from disk.
249+
std::ifstream spv_stream("my-kernel.spv", std::ios::binary);
250+
spv_stream.seekg(0, std::ios::end);
251+
size_t sz = spv_stream.tellg();
252+
spv_stream.seekg(0);
253+
std::vector<std::byte> spv(sz);
254+
spv_stream.read((char*)spv.data(), sz);
255+
256+
// Create a kernel bundle from the binary SPIR-V.
257+
sycl::kernel_bundle<sycl::bundle_state::ext_oneapi_source> kb_src =
258+
syclex::create_kernel_bundle_from_source(
259+
q.get_context(),
260+
syclex::source_language::spirv,
261+
spv);
262+
263+
// Build the SPIR-V module for our device.
264+
sycl::kernel_bundle<sycl::bundle_state::executable> kb_exe =
265+
syclex::build(kb_src);
266+
267+
// Get a "kernel" object representing the kernel from the SPIR-V module.
268+
sycl::kernel k = kb_exe.ext_oneapi_get_kernel("my_kernel");
269+
270+
constexpr int N = 4;
271+
int32_t input[N] = {0, 1, 2, 3};
272+
int32_t output[N] = {};
273+
274+
sycl::buffer inputbuf(input, sycl::range{N});
275+
sycl::buffer outputbuf(output, sycl::range{N});
276+
277+
q.submit([&](sycl::handler &cgh) {
278+
sycl::accessor in{inputbuf, cgh, sycl::read_only};
279+
sycl::accessor out{outputbuf, cgh, sycl::read_write};
280+
281+
// Set the values for the kernel arguments.
282+
cgh.set_args(in, out);
283+
284+
// Invoke the kernel over a range.
285+
cgh.parallel_for(sycl::range{N}, k);
286+
});
287+
}
288+
```

0 commit comments

Comments
 (0)