1use core::ptr::NonNull;
3
4#[unstable(feature = "gpu_offload", issue = "131513")]
5pub use crate::macros::builtin::offload_kernel;
6#[unstable(feature = "gpu_offload", issue = "131513")]
7pub use crate::offload;
8
9#[macro_export]
41#[unstable(feature = "gpu_offload", issue = "131513")]
42#[allow_internal_unstable(core_intrinsics, gpu_offload)]
43macro_rules! offload {
44 (@munch [kernel = $val:expr $(, $($rest:tt)*)?]; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
45 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = (SOME $val); workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = $device; args = $a)
46 };
47 (@munch [kernel = $val:expr $(, $($rest:tt)*)?]; kernel = (SOME $old:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
48 compile_error!("duplicate field `kernel`")
49 };
50 (@munch [workgroup_dim = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = ([1, 1, 1]); thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
51 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = (SOME $val); thread_dim = $t; dyn_cache = $d; device = $device; args = $a)
52 };
53 (@munch [workgroup_dim = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = (SOME $old:expr); thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
54 compile_error!("duplicate field `workgroup_dim`")
55 };
56 (@munch [thread_dim = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = ([1, 1, 1]); dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
57 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = $w; thread_dim = (SOME $val); dyn_cache = $d; device = $device; args = $a)
58 };
59 (@munch [thread_dim = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = (SOME $old:expr); dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
60 compile_error!("duplicate field `thread_dim`")
61 };
62 (@munch [dyn_cache = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (0); device = $device:tt; args = $a:tt) => {
63 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = (SOME $val); device = $device; args = $a)
64 };
65 (@munch [dyn_cache = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = (SOME $old:expr); device = $device:tt; args = $a:tt) => {
66 compile_error!("duplicate field `dyn_cache`")
67 };
68 (@munch [device = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = NONE; args = $a:tt) => {
69 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = (SOME $val); args = $a)
70 };
71 (@munch [device = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = (SOME $old:expr); args = $a:tt) => {
72 compile_error!("duplicate field `device`")
73 };
74 (@munch [args = ($($arg:expr),* $(,)?) $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = NONE) => {
75 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = $device; args = (SOME_TUPLE ($($arg),*)))
76 };
77 (@munch [args = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = NONE) => {
78 $crate::offload!(@munch [ $($($rest)*)? ]; kernel = $k; workgroup_dim = $w; thread_dim = $t; dyn_cache = $d; device = $device; args = (SOME $val))
79 };
80 (@munch [args = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME $old:expr)) => {
81 compile_error!("duplicate field `args`")
82 };
83 (@munch [args = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME_TUPLE $old:tt)) => {
84 compile_error!("duplicate field `args`")
85 };
86
87 (@munch [$invalid:ident = $val:expr $(, $($rest:tt)*)?]; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
88 compile_error!(concat!("unknown field `", stringify!($invalid), "`"))
89 };
90
91 (@munch []; kernel = NONE; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = $a:tt) => {
92 compile_error!("missing `kernel`")
93 };
94 (@munch []; kernel = $k:tt; workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = NONE) => {
95 compile_error!("missing `args`")
96 };
97 (@munch []; kernel = (SOME $kernel:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME_TUPLE ($($arg:expr),* $(,)?))) => {{
98 #[allow(unused_imports)]
99 use $crate::offload::{DefaultLaunchCheck as _, RegionLaunchCheck as _};
100
101 let __offload_grid = $crate::offload!(@value $w);
102 let __offload_block = $crate::offload!(@value $t);
103
104 $crate::intrinsics::offload::<_, _, ()>(
105 $kernel,
106 __offload_grid,
107 __offload_block,
108 $crate::offload!(@value $d),
109 $crate::offload!(@device $device),
110 ($({
111 let __offload_arg = $arg;
112 (&__offload_arg).__offload_check_launch(__offload_grid, __offload_block);
113 __offload_arg
114 },)*),
115 )
116 }};
117 (@munch []; kernel = (SOME $kernel:expr); workgroup_dim = $w:tt; thread_dim = $t:tt; dyn_cache = $d:tt; device = $device:tt; args = (SOME $args:expr)) => {
121 compile_error!(
122 "`args` must be a tuple literal"
123 )
124 };
125
126 (@value (SOME $val:expr)) => { $val };
127 (@value ($val:expr)) => { $val };
128
129 (@device NONE) => { -1 };
131 (@device (SOME $val:expr)) => { {
132 const { $crate::assert!($val >= 0, "offload device must be non-negative; omit `device` to use the default device") };
133 let device: i32 = $val;
134 $crate::assert!(
135 device < $crate::intrinsics::offload_get_num_devices(),
136 "offload device {} is not available",
137 device,
138 );
139 device
140 } };
141
142 ( $($tt:tt)* ) => {
143 $crate::offload!(@munch
144 [ $($tt)* ];
145 kernel = NONE;
146 workgroup_dim = ([1, 1, 1]);
147 thread_dim = ([1, 1, 1]);
148 dyn_cache = (0);
149 device = NONE;
150 args = NONE
151 )
152 };
153}
154
155#[derive(Debug)]
160#[unstable(feature = "gpu_offload", issue = "131513")]
161pub struct LaunchError {
162 message: &'static str,
163}
164
165impl LaunchError {
166 #[unstable(feature = "gpu_offload", issue = "131513")]
168 pub const fn new(message: &'static str) -> Self {
169 Self { message }
170 }
171}
172
173#[unstable(feature = "gpu_offload", issue = "131513")]
174impl core::fmt::Display for LaunchError {
175 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176 f.write_str(self.message)
177 }
178}
179
180#[unstable(feature = "gpu_offload", issue = "131513")]
190pub unsafe trait PartitioningStrategy {
191 type View<'a, T: 'a>;
193
194 type ViewMut<'a, T: 'a>;
196
197 fn index() -> usize;
199
200 unsafe fn get<'a, T>(ptr: NonNull<T>, len: usize) -> Option<Self::View<'a, T>>;
207
208 unsafe fn get_mut<'a, T>(ptr: NonNull<T>, len: usize) -> Option<Self::ViewMut<'a, T>>;
216
217 fn check_launch(len: usize, grid: [u32; 3], block: [u32; 3]) -> Result<(), LaunchError>;
229}
230
231#[derive(Debug)]
233#[unstable(feature = "gpu_offload", issue = "131513")]
234#[rustc_diagnostic_item = "offload_region"]
235pub struct Region<'a, T, S: PartitioningStrategy> {
236 ptr: NonNull<T>,
237 len: usize,
238 _marker: core::marker::PhantomData<(&'a mut [T], S)>,
239}
240
241#[derive(Debug)]
243#[unstable(feature = "gpu_offload", issue = "131513")]
244pub struct RawRegion<'a, T> {
245 ptr: NonNull<T>,
246 len: usize,
247 _marker: core::marker::PhantomData<&'a mut [T]>,
248}
249
250impl<'a, T> From<&'a mut [T]> for RawRegion<'a, T> {
251 fn from(data: &'a mut [T]) -> Self {
252 let ptr = unsafe { NonNull::new_unchecked(data.as_mut_ptr()) };
254 Self { ptr, len: data.len(), _marker: core::marker::PhantomData }
255 }
256}
257
258impl<'a, T, const N: usize> From<&'a mut [T; N]> for RawRegion<'a, T> {
259 fn from(data: &'a mut [T; N]) -> Self {
260 let ptr = unsafe { NonNull::new_unchecked(data.as_mut_ptr()) };
262 Self { ptr, len: N, _marker: core::marker::PhantomData }
263 }
264}
265
266#[unstable(feature = "gpu_offload", issue = "131513")]
267impl<'a, T, S: PartitioningStrategy> Region<'a, T, S> {
268 pub fn new<D>(data: D) -> Self
270 where
271 D: Into<RawRegion<'a, T>>,
272 {
273 let raw = data.into();
274 Self { ptr: raw.ptr, len: raw.len, _marker: core::marker::PhantomData }
275 }
276
277 pub fn get(&self) -> Option<S::View<'_, T>> {
279 unsafe { S::get(self.ptr, self.len) }
281 }
282
283 pub fn get_mut(&mut self) -> Option<S::ViewMut<'_, T>> {
285 unsafe { S::get_mut(self.ptr, self.len) }
288 }
289
290 pub fn check_launch(&self, grid: [u32; 3], block: [u32; 3]) -> Result<(), LaunchError> {
294 S::check_launch(self.len, grid, block)
295 }
296
297 pub fn reborrow(&mut self) -> Region<'_, T, S> {
300 Region { ptr: self.ptr, len: self.len, _marker: core::marker::PhantomData }
301 }
302}
303
304#[doc(hidden)]
309#[unstable(feature = "gpu_offload", issue = "131513")]
310pub trait RegionLaunchCheck {
311 fn __offload_check_launch(&self, grid: [u32; 3], block: [u32; 3]);
313}
314
315#[unstable(feature = "gpu_offload", issue = "131513")]
316impl<'a, T, S: PartitioningStrategy> RegionLaunchCheck for Region<'a, T, S> {
317 fn __offload_check_launch(&self, grid: [u32; 3], block: [u32; 3]) {
318 if let Err(err) = self.check_launch(grid, block) {
319 panic!(
320 "offload launch is not supported by the region's partitioning strategy: {}",
321 err,
322 );
323 }
324 }
325}
326
327#[doc(hidden)]
329#[unstable(feature = "gpu_offload", issue = "131513")]
330pub trait DefaultLaunchCheck {
331 fn __offload_check_launch(&self, grid: [u32; 3], block: [u32; 3]);
333}
334
335#[unstable(feature = "gpu_offload", issue = "131513")]
336impl<T: ?Sized> DefaultLaunchCheck for &T {
337 fn __offload_check_launch(&self, _grid: [u32; 3], _block: [u32; 3]) {}
338}