From 398549955258d92b4ba43b20ab485226aef3621f Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 14:18:16 +0000 Subject: [PATCH 1/8] Make the doc example compatible with testing --- sycl/sycl-rs/src/lib.rs | 81 +++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/sycl/sycl-rs/src/lib.rs b/sycl/sycl-rs/src/lib.rs index 4fcdb19..ba099b3 100644 --- a/sycl/sycl-rs/src/lib.rs +++ b/sycl/sycl-rs/src/lib.rs @@ -31,49 +31,58 @@ //! You must also source `setvars.sh` before running any SYCL program. //! //! ### Hello world -//! 1. Create a [`Queue`](crate::queue::Queue). It's the main entry point to the SYCL API. -//! ```rust,ignore -//! let mut queue = Queue::new(); -//! ``` //! -//! 2. Create an [USM buffer](crate::buffer::Buffer) for your data. -//! ```rust,ignore -//! let mut device_buffer = queue.alloc_device::(1024).wait(); //! ``` +//! # use sycl_rs::prelude::*; //! -//! 3. Build a SYCL kernel. -//! ```rust,ignore -//! let kernel = queue -//! .get_context() -//! .create_kernel_bundle_from_source(IOTA_SRC) -//! .build() -//! .get_kernel("iota"); -//! ``` +//! # static IOTA_SRC: &str = r#" +//! # #include +//! # namespace syclext = sycl::ext::oneapi; +//! # namespace syclexp = sycl::ext::oneapi::experimental; +//! # +//! # extern "C" +//! # SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>)) +//! # void iota(float start, float *ptr) { +//! # size_t id = syclext::this_work_item::get_nd_item<1>().get_global_linear_id(); +//! # ptr[id] = start + static_cast(id); +//! # } +//! # "#; +//! # +//! fn main() -> sycl_rs::Result<()> { +//! // 1. Create a Queue. It's the main entry point to the SYCL API. +//! let mut queue = Queue::new(); +//! let mut device_buffer = queue.alloc_device::(1024)?.wait()?; //! -//! 4. Launch your kernel. -//! ```rust,ignore -//! unsafe { -//! queue.launch( -//! NdRange::new([1024], [16]), -//! &kernel, -//! (3.14, &mut device_buffer), -//! ) -//! } -//! .wait(); -//! ``` +//! // 3. Build a SYCL kernel. +//! let kernel = queue +//! .get_context() +//! .create_kernel_bundle_from_source(IOTA_SRC)? +//! .build()? +//! .get_kernel("iota")?; //! -//! 5. Copy your data to the host. -//! ```rust,ignore -//! let mut host_buffer = queue.alloc_host::(1024).wait(); -//! queue.copy(&device_buffer, &mut host_buffer).wait(); -//! ``` +//! // 4. Launch your kernel. +//! unsafe { +//! queue.launch( +//! NdRange::new([1024], [16]), +//! &kernel, +//! (3.14_f32, &mut device_buffer), +//! ) +//! }? +//! .wait()?; +//! +//! let mut host_buffer = queue.alloc_host::(1024)?.wait()?; +//! +//! // 5. Copy your data to the host. +//! queue.copy(&device_buffer, &mut host_buffer)?.wait()?; +//! +//! // You can access your host data just like a normal Rust slice. +//! for e in host_buffer.iter() { +//! print!("{e} "); +//! } +//! println!(); //! -//! You can access your host data just like a normal Rust slice. -//! ```rust,ignore -//! for e in host_buffer.iter() { -//! print!("{e} "); +//! Ok(()) //! } -//! println!(); //! ``` //! //! # Safety model From c1794b1902f6757e85eae3faac96c6637d19e0d2 Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 14:27:18 +0000 Subject: [PATCH 2/8] Add thread safety documentation --- sycl/sycl-rs/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sycl/sycl-rs/src/lib.rs b/sycl/sycl-rs/src/lib.rs index ba099b3..39d9db2 100644 --- a/sycl/sycl-rs/src/lib.rs +++ b/sycl/sycl-rs/src/lib.rs @@ -99,6 +99,10 @@ //! You can also synchronously call [`Queue::wait()`](crate::queue::Queue::wait) to wait for a //! [`Queue`](crate::queue::Queue) directly. To do the same asynchronously you have to `.await` an //! event returned by [`Queue::barrier()`](crate::queue::Queue::barrier). +//! +//! All basic SYCL wrapper types (`Queue`, `Event`, `Context`, `Platform`, `Device`) are thread safe as +//! indicated by the provided [`Send`] and [`Sync`] trait implementations. However - Buffers are +//! not thread-safe. If you need a thread-safe Buffer you need to wrap it in an `Arc>`. pub mod buffer; pub mod context; From 170d830c3bef671e965caacf583c874fcf1532ba Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 14:46:14 +0000 Subject: [PATCH 3/8] Add safety comments for USM allocator traits --- sycl/sycl-rs/src/usm.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sycl/sycl-rs/src/usm.rs b/sycl/sycl-rs/src/usm.rs index 682c173..1ad3a84 100644 --- a/sycl/sycl-rs/src/usm.rs +++ b/sycl/sycl-rs/src/usm.rs @@ -22,6 +22,8 @@ pub struct UsmAllocator { } /// A marker trait for USM allocators. +/// +/// Safety: a type implementing this trait must be a valid USM allocator managed by a SYCL runtime. pub unsafe trait UsmAlloc: Allocator {} unsafe impl UsmAlloc for UsmAllocator {} @@ -31,6 +33,9 @@ pub trait UsmAllocatorKind { } /// A marker trait for host-accessible USM allocators. +/// +/// Safety: a type implementing this trait must be a valid USM allocator managed by a SYCL runtime, +/// that allocates memory accessible from the host. pub unsafe trait HostAccessible {} impl From<&Queue> for UsmAllocator { @@ -61,6 +66,7 @@ unsafe impl Allocator for UsmAllocator { } /// An allocator for Device-side buffers +/// /// Safety: memory allocated by this allocator cannot be accessed on the host side #[allow(dead_code)] pub struct DeviceAllocator; From 2c63497d89cf37571816055ee749147eac63988a Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 15:17:59 +0000 Subject: [PATCH 4/8] Add safety comments for kernel arguments --- sycl/sycl-rs/src/kernel.rs | 6 ++++++ sycl/sycl-rs/src/lib.rs | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sycl/sycl-rs/src/kernel.rs b/sycl/sycl-rs/src/kernel.rs index f34b51c..1eb9c19 100644 --- a/sycl/sycl-rs/src/kernel.rs +++ b/sycl/sycl-rs/src/kernel.rs @@ -50,6 +50,9 @@ impl From> for Kernel { } /// Types which can be passed as SYCL kernel arguments. +/// +/// Safety: a type implement this trait must mirror the representation and alignment of the +/// corresponding SYCL kernel argument structure. pub unsafe trait KernelArgument { unsafe fn as_raw_arg(&self) -> &[u8]; } @@ -61,6 +64,9 @@ unsafe impl KernelArgument for T { } /// Types which describe an argument list for a SYCL kernel. +/// +/// Safety: a type implement this trait must mirror the representation and alignment of each +/// corresponding SYCL kernel argument inside the returned array. pub unsafe trait KernelArgumentList { unsafe fn as_raw_arg_list(&self) -> [&[u8]; ARGC]; } diff --git a/sycl/sycl-rs/src/lib.rs b/sycl/sycl-rs/src/lib.rs index 39d9db2..12fc185 100644 --- a/sycl/sycl-rs/src/lib.rs +++ b/sycl/sycl-rs/src/lib.rs @@ -90,7 +90,8 @@ //! - Note: Unlike SYCL buffers, SYCL-rs buffers do not rely on accessors. //! - Buffers are zero-initialized by default. //! - Buffers can only store types that implement [`bytemuck::Pod`]. -//! - Kernel launch is inherently unsafe. +//! - Kernel launch is inherently unsafe. In particular, the caller must ensure that every argument +//! has the correct representation, layout, and alignment. //! //! # Asynchronous programming model //! Each queue operation returns an [`Event`](`crate::event::Event`). You can synchronously From 134f1bcc648a33aa5d88a3fc668aefebd5db2609 Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 15:18:14 +0000 Subject: [PATCH 5/8] Add driver compatibility documentation --- sycl/sycl-rs/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sycl/sycl-rs/src/lib.rs b/sycl/sycl-rs/src/lib.rs index 12fc185..9022cc2 100644 --- a/sycl/sycl-rs/src/lib.rs +++ b/sycl/sycl-rs/src/lib.rs @@ -20,6 +20,10 @@ //! source /setvars.sh //! ``` //! +//! This project was tested on oneAPI Toolkit 2026.1 and requires the Unified Runtime over Level Zero +//! driver version 1.14.37020 or newer. For more detailed information check out the +//! [required extensions](crate#required-extensions) section. +//! //! # Getting started //! ### Building the crate //! Before building this crate you need to source the `setvars.sh` file. You can then build it as @@ -104,6 +108,15 @@ //! All basic SYCL wrapper types (`Queue`, `Event`, `Context`, `Platform`, `Device`) are thread safe as //! indicated by the provided [`Send`] and [`Sync`] trait implementations. However - Buffers are //! not thread-safe. If you need a thread-safe Buffer you need to wrap it in an `Arc>`. +//! +//! # Required extensions +//! This project requires the following SYCL extensions to work: +//! - [sycl_ext_oneapi_kernel_compiler](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler.asciidoc) +//! - [sycl_ext_oneapi_raw_kernel_arg](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/experimental/sycl_ext_oneapi_raw_kernel_arg.asciidoc) +//! +//! The following extensions are also required for async support: +//! - [sycl_ext_intel_queue_immediate_command_list](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_intel_queue_immediate_command_list.asciidoc) +//! - [sycl_ext_oneapi_enqueue_barrier](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_oneapi_enqueue_barrier.asciidoc) pub mod buffer; pub mod context; From 2ba12b384760b1aedbe7b7ec21a44d1e4212c061 Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 15:34:03 +0000 Subject: [PATCH 6/8] Document wait synchronous errors --- sycl/sycl-rs/src/buffer.rs | 3 ++- sycl/sycl-rs/src/event.rs | 2 ++ sycl/sycl-rs/src/queue.rs | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sycl/sycl-rs/src/buffer.rs b/sycl/sycl-rs/src/buffer.rs index be86382..674c7db 100644 --- a/sycl/sycl-rs/src/buffer.rs +++ b/sycl/sycl-rs/src/buffer.rs @@ -121,7 +121,8 @@ impl EnqueuedBuffer { } impl EnqueuedBuffer { - /// Waits for [`Buffer`] initialization to finish. + /// Performs a blocking wait for the [`Buffer`] initialization to complete. Returns an error if + /// a synchronous SYCL exception occurs. pub fn wait(mut self) -> Result> { self.event.wait().map(|_| self.buffer) } diff --git a/sycl/sycl-rs/src/event.rs b/sycl/sycl-rs/src/event.rs index e89c452..2b22d70 100644 --- a/sycl/sycl-rs/src/event.rs +++ b/sycl/sycl-rs/src/event.rs @@ -21,6 +21,8 @@ use crate::{Result, info::InfoTarget, private::Sealed, queue::Queue}; pub struct Event(pub(crate) cxx::UniquePtr); impl Event { + /// Performs a blocking wait for the event to complete. Returns an error if a synchronous SYCL + /// exception occurs. pub fn wait(&mut self) -> Result<()> { ffi::wait(&mut self.0) } diff --git a/sycl/sycl-rs/src/queue.rs b/sycl/sycl-rs/src/queue.rs index 0f9b703..ec12ec1 100644 --- a/sycl/sycl-rs/src/queue.rs +++ b/sycl/sycl-rs/src/queue.rs @@ -137,7 +137,8 @@ impl Queue { ffi::barrier(&mut self.0, dep_events).map(Into::into) } - /// Performs a blocking wait for the completion of all enqueued tasks in the queue. + /// Performs a blocking wait for the completion of all enqueued tasks in the queue. Returns an + /// error if a synchronous SYCL exception occurs. pub fn wait(&mut self) -> Result<()> { ffi::wait(&mut self.0) } From 01c6769610b52010ddcae41d4899a84484ec0886 Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 15:54:39 +0000 Subject: [PATCH 7/8] Add synchronization on drop behavior documentation --- sycl/sycl-rs/src/buffer.rs | 2 ++ sycl/sycl-rs/src/event.rs | 2 ++ sycl/sycl-rs/src/queue.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/sycl/sycl-rs/src/buffer.rs b/sycl/sycl-rs/src/buffer.rs index 674c7db..361dcd0 100644 --- a/sycl/sycl-rs/src/buffer.rs +++ b/sycl/sycl-rs/src/buffer.rs @@ -123,6 +123,8 @@ impl EnqueuedBuffer { impl EnqueuedBuffer { /// Performs a blocking wait for the [`Buffer`] initialization to complete. Returns an error if /// a synchronous SYCL exception occurs. + /// + /// Dropping an enqueued buffer does not wait for its completion. pub fn wait(mut self) -> Result> { self.event.wait().map(|_| self.buffer) } diff --git a/sycl/sycl-rs/src/event.rs b/sycl/sycl-rs/src/event.rs index 2b22d70..e0f85fd 100644 --- a/sycl/sycl-rs/src/event.rs +++ b/sycl/sycl-rs/src/event.rs @@ -23,6 +23,8 @@ pub struct Event(pub(crate) cxx::UniquePtr); impl Event { /// Performs a blocking wait for the event to complete. Returns an error if a synchronous SYCL /// exception occurs. + /// + /// Dropping the event does not wait for its completion. pub fn wait(&mut self) -> Result<()> { ffi::wait(&mut self.0) } diff --git a/sycl/sycl-rs/src/queue.rs b/sycl/sycl-rs/src/queue.rs index ec12ec1..96ca5e0 100644 --- a/sycl/sycl-rs/src/queue.rs +++ b/sycl/sycl-rs/src/queue.rs @@ -139,6 +139,8 @@ impl Queue { /// Performs a blocking wait for the completion of all enqueued tasks in the queue. Returns an /// error if a synchronous SYCL exception occurs. + /// + /// Dropping the queue does not wait for its completion. pub fn wait(&mut self) -> Result<()> { ffi::wait(&mut self.0) } From 5f68b10af873545823dee4749010c48c5464b852 Mon Sep 17 00:00:00 2001 From: Szymon Zadworny Date: Mon, 10 Aug 2026 16:20:01 +0000 Subject: [PATCH 8/8] Document internal unsafe methods --- sycl/sycl-rs/src/kernel.rs | 8 ++++++++ sycl/sycl-rs/src/queue.rs | 3 +++ sycl/sycl-rs/src/usm.rs | 3 +++ 3 files changed, 14 insertions(+) diff --git a/sycl/sycl-rs/src/kernel.rs b/sycl/sycl-rs/src/kernel.rs index 1eb9c19..afe052a 100644 --- a/sycl/sycl-rs/src/kernel.rs +++ b/sycl/sycl-rs/src/kernel.rs @@ -54,6 +54,10 @@ impl From> for Kernel { /// Safety: a type implement this trait must mirror the representation and alignment of the /// corresponding SYCL kernel argument structure. pub unsafe trait KernelArgument { + /// Converts self to a raw byte representation. + /// + /// Safety: This function returns a reference to raw bytes. These bytes will be passed to FFI + /// functions. The caller must make sure these functions respect Rust's aliasing rules. unsafe fn as_raw_arg(&self) -> &[u8]; } @@ -68,6 +72,10 @@ unsafe impl KernelArgument for T { /// Safety: a type implement this trait must mirror the representation and alignment of each /// corresponding SYCL kernel argument inside the returned array. pub unsafe trait KernelArgumentList { + /// Converts each struct member to a raw byte representation. + /// + /// Safety: This function returns references to raw bytes. These bytes will be passed to FFI + /// functions. The caller must make sure these functions respect Rust's aliasing rules. unsafe fn as_raw_arg_list(&self) -> [&[u8]; ARGC]; } diff --git a/sycl/sycl-rs/src/queue.rs b/sycl/sycl-rs/src/queue.rs index 96ca5e0..2a99fc8 100644 --- a/sycl/sycl-rs/src/queue.rs +++ b/sycl/sycl-rs/src/queue.rs @@ -147,6 +147,9 @@ impl Queue { /// Enqueues a kernel object to the queue as an ND-range kernel, using the number of work-items /// specified by the [`NdRange`] nd_range. + /// + /// Safety: The caller must make sure each argument matches the launched SYCL kernel's + /// signature, including their respective size, layout and alignment. pub unsafe fn launch( &mut self, nd_range: NdRange, diff --git a/sycl/sycl-rs/src/usm.rs b/sycl/sycl-rs/src/usm.rs index 1ad3a84..1db0ee3 100644 --- a/sycl/sycl-rs/src/usm.rs +++ b/sycl/sycl-rs/src/usm.rs @@ -29,6 +29,9 @@ pub unsafe trait UsmAlloc: Allocator {} unsafe impl UsmAlloc for UsmAllocator {} pub trait UsmAllocatorKind { + /// Allocates uninitialized memory. + /// Safety: the caller must not read uninitialized memory. The caller must also free this + /// memory manually. unsafe fn alloc(alignment: usize, num_bytes: usize, queue: &Queue) -> CxxResult<*mut u8>; }