1use alloc::vec;
4use pliron::{r#type::TypeHandle, value::Value};
5
6use crate as cubecl;
7use cubecl_ir::{
8 ExpandValue,
9 dialect::tma::*,
10 types::barrier::{BarrierLevel, BarrierType},
11};
12use cubecl_macros::intrinsic;
13use paste::paste;
14
15use crate::{
16 ir::{Scope, dialect::barrier::*},
17 prelude::*,
18 unexpanded,
19};
20
21use super::{CubePrimitive, CubeType, NativeExpand, SliceExpand, TensorMap};
22
23#[derive(Clone, Copy, PartialEq, Eq)]
26pub struct Barrier;
27pub type BarrierExpand = NativeExpand<Barrier>;
28
29#[derive(Clone, Copy, PartialEq)]
30pub struct BarrierToken;
31
32impl CubeType for Barrier {
33 type ExpandType = NativeExpand<Barrier>;
34}
35
36impl CubeDebug for Barrier {}
37
38impl CubePrimitive for Barrier {
39 type Scalar = u32; type Size = Const<1>;
41 type WithScalar<S: Scalar> = S;
42 fn from_const_value(_value: cubecl_ir::ConstantValue) -> Self {
43 unreachable!("Can't create from const value")
44 }
45
46 fn __expand_as_type(scope: &Scope) -> TypeHandle {
47 BarrierType::get(scope.ctx(), BarrierLevel::Cube).into()
48 }
49}
50
51impl NativeAssign for Barrier {
52 fn elem_init_mut(_scope: &Scope, elem: ExpandValue) -> ExpandValue {
53 elem
54 }
55}
56
57impl CubeType for BarrierToken {
58 type ExpandType = NativeExpand<BarrierToken>;
59}
60
61impl ReadValue for NativeExpand<BarrierToken> {
62 fn read_value(&self, scope: &Scope) -> Value {
63 self.expand.read_value(scope)
64 }
65}
66
67impl NativeAssign for BarrierToken {
68 fn elem_init_mut(_scope: &Scope, elem: ExpandValue) -> ExpandValue {
69 elem
70 }
71}
72
73impl AsMutExpand for NativeExpand<BarrierToken> {
74 fn __expand_ref_mut_method(&mut self, _: &Scope) -> &mut Self {
75 self
76 }
77}
78
79macro_rules! tensor_map_load {
80 ($dim: literal, $($arg: expr),*) => {
81 paste! {
82 impl Barrier {
83 #[allow(unused, clippy::too_many_arguments)]
86 pub fn [<tma_load_ $dim d>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
87 &self,
88 source: &TensorMap<C1, Tiled>,
89 destination: &mut [C2],
90 $($arg: i32),*
91 ) {
92 unexpanded!()
93 }
94
95 #[allow(clippy::too_many_arguments)]
96 pub fn [<__expand_tma_load_ $dim d>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
97 scope: &Scope,
98 expand: &NativeExpand<Barrier>,
99 source: &NativeExpand<TensorMap<C1, Tiled>>,
100 destination: &mut SliceExpand<C2>,
101 $($arg: NativeExpand<i32>),*
102 ) {
103 expand.[<__expand_tma_load_ $dim d_method>](scope, source, destination, $($arg),*);
104 }
105 }
106
107 impl NativeExpand<Barrier> {
108 #[allow(clippy::too_many_arguments)]
109 pub fn [<__expand_tma_load_ $dim d_method>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
110 &self,
111 scope: &Scope,
112 source: &NativeExpand<TensorMap<C1, Tiled>>,
113 destination: &mut SliceExpand<C2>,
114 $($arg: NativeExpand<i32>),*
115 ) {
116 let barrier = self.value(scope);
117 let source = source.value(scope);
118 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
119 let indices = vec![$($arg.read_value(scope)),*];
120
121 let mem_copy = TmaLoadOp::new(scope.ctx_mut(), barrier, source, destination, indices);
122 scope.register(&mem_copy);
123 }
124 }
125 }
126 };
127}
128
129macro_rules! tensor_map_load_im2col {
130 ($dim: literal, $($arg: expr),*; $($offset: expr),*) => {
131 paste! {
132 impl Barrier {
133 #[allow(unused, clippy::too_many_arguments)]
136 pub fn [<tma_load_im2col_ $dim d>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
137 &self,
138 source: &TensorMap<C1, Im2col>,
139 destination: &mut [C2],
140 $($arg: i32,)*
141 $($offset: u16),*
142 ) {
143 unexpanded!()
144 }
145
146 #[allow(clippy::too_many_arguments)]
147 pub fn [<__expand_tma_load_im2col_ $dim d>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
148 scope: &Scope,
149 expand: &NativeExpand<Barrier>,
150 source: &NativeExpand<TensorMap<C1, Im2col>>,
151 destination: &mut SliceExpand<C2>,
152 $($arg: NativeExpand<i32>,)*
153 $($offset: NativeExpand<u16>),*
154 ) {
155 expand.[<__expand_tma_load_im2col_ $dim d_method>](scope, source, destination, $($arg),*, $($offset),*);
156 }
157 }
158
159 impl NativeExpand<Barrier> {
160 #[allow(clippy::too_many_arguments)]
161 pub fn [<__expand_tma_load_im2col_ $dim d_method>]<C1: CubePrimitive, C2: CubePrimitive<Scalar = C1::Scalar>>(
162 &self,
163 scope: &Scope,
164 source: &NativeExpand<TensorMap<C1, Im2col>>,
165 destination: &mut SliceExpand<C2>,
166 $($arg: NativeExpand<i32>,)*
167 $($offset: NativeExpand<u16>),*
168 ) {
169 let barrier = self.value(scope);
170 let source = source.value(scope);
171 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
172 let indices = vec![$($arg.read_value(scope)),*];
173 let offsets = vec![$($offset.read_value(scope)),*];
174
175 let mem_copy = TmaLoadIm2colOp::new(scope.ctx_mut(), barrier, source, destination, indices, offsets);
176 scope.register(&mem_copy);
177 }
178 }
179 }
180 };
181}
182
183tensor_map_load!(1, x);
184tensor_map_load!(2, y, x);
185tensor_map_load!(3, z, y, x);
186tensor_map_load!(4, w, z, y, x);
187tensor_map_load!(5, v, w, z, y, x);
188
189tensor_map_load_im2col!(3, n, w, c; w_offset);
190tensor_map_load_im2col!(4, n, h, w, c; h_offset, w_offset);
191tensor_map_load_im2col!(5, n, d, h, w, c; d_offset, h_offset, w_offset);
192
193#[cube]
194impl Barrier {
195 pub fn local() -> Self {
198 intrinsic!(|scope| {
199 let value =
200 scope.create_local_mut(BarrierType::get(scope.ctx(), BarrierLevel::Unit), None);
201 let arrival_count: ExpandValue = 1u32.into();
202 let arrival_count = arrival_count.read_value(scope);
203 let op = InitOp::new(scope.ctx_mut(), value, arrival_count);
204 scope.register(&op);
205 value.into()
206 })
207 }
208
209 pub fn shared(arrival_count: u32, is_elected: bool) -> Shared<Barrier> {
216 intrinsic!(|scope| {
217 let value =
218 scope.create_shared(BarrierType::get(scope.ctx(), BarrierLevel::Cube), None);
219 if_expand(scope, is_elected, |scope| {
220 let arrival_count = arrival_count.read_value(scope);
221 let op = InitOp::new(scope.ctx_mut(), value, arrival_count);
222 scope.register(&op);
223 });
224 sync_cube::expand(scope);
225 value.into()
226 })
227 }
228
229 pub fn shared_uninit() -> Shared<Barrier> {
232 intrinsic!(|scope| {
233 let value =
234 scope.create_shared(BarrierType::get(scope.ctx(), BarrierLevel::Cube), None);
235 value.into()
236 })
237 }
238
239 pub fn init_manual(&self, arrival_count: u32) {
252 intrinsic!(|scope| {
253 let barrier = self.value(scope);
254 let arrival_count = arrival_count.read_value(scope);
255 let op = InitOp::new(scope.ctx_mut(), barrier, arrival_count);
256 scope.register(&op);
257 })
258 }
259}
260
261#[cube]
264impl Barrier {
265 pub fn memcpy_async<C: CubePrimitive>(&self, source: &[C], destination: &mut [C]) {
272 intrinsic!(|scope| {
273 let barrier = self.value(scope);
274 let source_length = source.__extract_length(scope).value(scope);
275 let source = unsafe { *source.__expand_as_ptr_method(scope) }.value(scope);
276 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
277
278 let mem_copy = MemCopyAsyncOp::new(
279 scope.ctx_mut(),
280 barrier,
281 source,
282 destination,
283 source_length,
284 false,
285 );
286
287 scope.register(&mem_copy);
288 })
289 }
290
291 pub fn memcpy_async_cooperative<C: CubePrimitive>(&self, source: &[C], destination: &mut [C]) {
298 intrinsic!(|scope| {
299 let barrier = self.value(scope);
300 let source_length = source.__extract_length(scope).value(scope);
301 let source = unsafe { *source.__expand_as_ptr_method(scope) }.value(scope);
302 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
303
304 let mem_copy = MemCopyAsyncOp::new(
305 scope.ctx_mut(),
306 barrier,
307 source,
308 destination,
309 source_length,
310 true,
311 );
312
313 scope.register(&mem_copy);
314 })
315 }
316
317 pub fn memcpy_async_tx<C: CubePrimitive>(&self, source: &[C], destination: &mut [C]) {
325 intrinsic!(|scope| {
326 let barrier = self.value(scope);
327 let source_length = source.__extract_length(scope).value(scope);
328 let source = unsafe { *source.__expand_as_ptr_method(scope) }.value(scope);
329 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
330
331 let mem_copy =
332 MemCopyAsyncTxOp::new(scope.ctx_mut(), barrier, source, destination, source_length);
333
334 scope.register(&mem_copy);
335 })
336 }
337}
338
339#[cube]
342impl Barrier {
343 pub fn arrive(&self) -> BarrierToken {
345 intrinsic!(|scope| {
346 let barrier = self.value(scope);
347 let arrive = ArriveOp::new(scope.ctx_mut(), barrier);
348 scope.register_with_result(&arrive).into()
349 })
350 }
351
352 pub fn arrive_and_expect_tx(&self, arrival_count: u32, transaction_count: u32) -> BarrierToken {
354 intrinsic!(|scope| {
355 let barrier = self.value(scope);
356 let arrival_count = arrival_count.read_value(scope);
357 let transaction_count = transaction_count.read_value(scope);
358 let op = ArriveAndExpectTxOp::new(
359 scope.ctx_mut(),
360 barrier,
361 arrival_count,
362 transaction_count,
363 );
364 scope.register_with_result(&op).into()
365 })
366 }
367
368 pub fn expect_tx(&self, transaction_count_update: u32) {
370 intrinsic!(|scope| {
371 let barrier = self.value(scope);
372 let transaction_count_update = transaction_count_update.value(scope);
373 scope.register(&ExpectTxOp::new(
374 scope.ctx_mut(),
375 barrier,
376 transaction_count_update,
377 ));
378 })
379 }
380
381 pub fn arrive_and_wait(&self) {
383 intrinsic!(|scope| {
384 let barrier = self.value(scope);
385 scope.register(&ArriveAndWaitOp::new(scope.ctx_mut(), barrier));
386 })
387 }
388
389 pub fn wait(&self, token: BarrierToken) {
391 intrinsic!(|scope| {
392 let barrier = self.value(scope);
393 let token = token.value(scope);
394 scope.register(&WaitOp::new(scope.ctx_mut(), barrier, token));
395 })
396 }
397
398 pub fn wait_parity(&self, phase: u32) {
401 intrinsic!(|scope| {
402 let barrier = self.value(scope);
403 let phase = phase.read_value(scope);
404 scope.register(&WaitParityOp::new(scope.ctx_mut(), barrier, phase));
405 })
406 }
407}
408
409pub fn copy_async<C: CubePrimitive>(_source: &[C], _destination: &mut [C], _copy_size: u32) {
421 unexpanded!()
422}
423
424pub mod copy_async {
425 use super::*;
426
427 pub fn expand<C: CubePrimitive>(
428 scope: &Scope,
429 source: &SliceExpand<C>,
430 destination: &mut SliceExpand<C>,
431 copy_length: u32,
432 ) {
433 let source = unsafe { *source.__expand_as_ptr_method(scope) }.value(scope);
434 let destination = unsafe { *destination.__expand_as_ptr_method(scope) }.value(scope);
435 let scalar_size = C::Scalar::__expand_size(scope);
436 let copy_length_bytes = copy_length as usize * scalar_size;
437 let source_length = ExpandValue::from(copy_length_bytes).read_value(scope);
438
439 let mem_copy = CopyAsyncOp::new(
440 scope.ctx_mut(),
441 source,
442 destination,
443 source_length,
444 copy_length_bytes,
445 false,
446 );
447
448 scope.register(&mem_copy);
449 }
450}
451
452pub fn copy_async_checked<C: CubePrimitive>(
464 _source: &[C],
465 _destination: &mut [C],
466 _copy_size: u32,
467) {
468 unexpanded!();
469}
470
471pub mod copy_async_checked {
472 use super::*;
473
474 pub fn expand<C: CubePrimitive>(
475 scope: &Scope,
476 source: &SliceExpand<C>,
477 destination: &mut SliceExpand<C>,
478 copy_length: u32,
479 ) {
480 let source_length = source.__extract_length(scope);
481
482 let source = unsafe { *source.__expand_as_ptr_unchecked_method(scope) }.value(scope);
483 let destination =
484 unsafe { *destination.__expand_as_ptr_unchecked_method(scope) }.value(scope);
485 let scalar_size = C::Scalar::__expand_size(scope);
486 let vector_size = C::__expand_size(scope).__expand_runtime_method(scope);
487 let source_length_bytes = source_length.__expand_mul_method(scope, vector_size);
488
489 let mem_copy = CopyAsyncOp::new(
490 scope.ctx_mut(),
491 source,
492 destination,
493 source_length_bytes.read_value(scope),
494 copy_length as usize * scalar_size,
495 true,
496 );
497
498 scope.register(&mem_copy);
499 }
500}
501
502#[cube]
503impl Barrier {
504 pub fn commit_copy_async(&self) {
511 intrinsic!(|scope| {
512 let barrier = self.value(scope);
513 scope.register(&CommitCopyAsyncOp::new(scope.ctx_mut(), barrier));
514 })
515 }
516}
517
518impl From<SharedExpand<Barrier>> for BarrierExpand {
519 fn from(value: SharedExpand<Barrier>) -> Self {
520 value.expand.into()
521 }
522}