1use alloc::vec;
4use core::ops::{Deref, DerefMut};
5
6use ruda_core::ir::{Instruction, ManagedVariable, OpaqueType};
7use ruda_kernel_macros::intrinsic;
8use paste::paste;
9
10use crate::dsl::{
11 ir::{BarrierOps, Scope},
12 prelude::*,
13 unexpanded,
14};
15
16use super::{
17 RudaPrimitive, RudaType, NativeExpand, ReadOnly, ReadWrite, Slice, SliceExpand, SliceMut,
18 TensorMap,
19};
20
21#[derive(Clone, Copy, PartialEq, Eq)]
24pub struct Barrier;
25pub type BarrierExpand = NativeExpand<Barrier>;
26
27#[derive(Clone, Copy, PartialEq)]
28pub struct BarrierToken;
29
30impl RudaType for Barrier {
31 type ExpandType = NativeExpand<Barrier>;
32}
33
34impl RudaPrimitive for Barrier {
35 type Scalar = u32; type Size = Const<1>;
37 type WithScalar<S: Scalar> = S;
38 fn from_const_value(_value: ruda_core::ir::ConstantValue) -> Self {
39 unreachable!("Can't create from const value")
40 }
41}
42
43impl NativeAssign for Barrier {
44 fn elem_init_mut(_scope: &mut Scope, elem: ManagedVariable) -> ManagedVariable {
45 elem
46 }
47}
48
49impl RudaType for BarrierToken {
50 type ExpandType = NativeExpand<BarrierToken>;
51}
52
53impl NativeAssign for BarrierToken {
54 fn elem_init_mut(_scope: &mut crate::dsl::ir::Scope, elem: ManagedVariable) -> ManagedVariable {
55 elem
56 }
57}
58
59macro_rules! tensor_map_load {
60 ($dim: literal, $($arg: expr),*) => {
61 paste! {
62 impl Barrier {
63 #[allow(unused, clippy::too_many_arguments)]
66 pub fn [<tma_load_ $dim d>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
67 &self,
68 source: &TensorMap<C1, Tiled>,
69 destination: &mut SliceMut<C2>,
70 $($arg: i32),*
71 ) {
72 unexpanded!()
73 }
74
75 #[allow(clippy::too_many_arguments)]
76 pub fn [<__expand_tma_load_ $dim d>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
77 scope: &mut Scope,
78 expand: BarrierExpand,
79 source: NativeExpand<TensorMap<C1, Tiled>>,
80 destination: SliceExpand<C2, ReadWrite>,
81 $($arg: NativeExpand<i32>),*
82 ) {
83 expand.[<__expand_tma_load_ $dim d_method>](scope, source, destination, $($arg),*);
84 }
85 }
86
87 impl BarrierExpand {
88 #[allow(clippy::too_many_arguments)]
89 pub fn [<__expand_tma_load_ $dim d_method>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
90 &self,
91 scope: &mut Scope,
92 source: NativeExpand<TensorMap<C1, Tiled>>,
93 destination: SliceExpand<C2, ReadWrite>,
94 $($arg: NativeExpand<i32>),*
95 ) {
96 let barrier = *self.expand;
97 let source = *source.expand;
98 let (destination, destination_offset) = destination.__to_raw_parts();
99
100 let mem_copy = BarrierOps::TmaLoad {
101 barrier,
102 tensor_map: source,
103 indices: vec![$(*$arg.expand),*],
104 offset_out: destination_offset
105 };
106
107 scope.register(Instruction::new(mem_copy, destination));
108 }
109 }
110 }
111 };
112}
113
114macro_rules! tensor_map_load_im2col {
115 ($dim: literal, $($arg: expr),*; $($offset: expr),*) => {
116 paste! {
117 impl Barrier {
118 #[allow(unused, clippy::too_many_arguments)]
121 pub fn [<tma_load_im2col_ $dim d>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
122 &self,
123 source: &TensorMap<C1, Im2col>,
124 destination: &mut SliceMut<C2>,
125 $($arg: i32,)*
126 $($offset: u16),*
127 ) {
128 unexpanded!()
129 }
130
131 #[allow(clippy::too_many_arguments)]
132 pub fn [<__expand_tma_load_im2col_ $dim d>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
133 scope: &mut Scope,
134 expand: BarrierExpand,
135 source: NativeExpand<TensorMap<C1, Im2col>>,
136 destination: SliceExpand<C2, ReadWrite>,
137 $($arg: NativeExpand<i32>,)*
138 $($offset: NativeExpand<u16>),*
139 ) {
140 expand.[<__expand_tma_load_im2col_ $dim d_method>](scope, source, destination, $($arg),*, $($offset),*);
141 }
142 }
143
144 impl BarrierExpand {
145 #[allow(clippy::too_many_arguments)]
146 pub fn [<__expand_tma_load_im2col_ $dim d_method>]<C1: RudaPrimitive, C2: RudaPrimitive<Scalar = C1::Scalar>>(
147 &self,
148 scope: &mut Scope,
149 source: NativeExpand<TensorMap<C1, Im2col>>,
150 destination: SliceExpand<C2, ReadWrite>,
151 $($arg: NativeExpand<i32>,)*
152 $($offset: NativeExpand<u16>),*
153 ) {
154 let barrier = *self.expand;
155 let source = *source.expand;
156 let (destination, destination_offset) = destination.__to_raw_parts();
157
158 let mem_copy = BarrierOps::TmaLoadIm2col {
159 barrier,
160 tensor_map: source,
161 indices: vec![$(*$arg.expand),*],
162 offsets: vec![$(*$offset.expand),*],
163 offset_out: destination_offset,
164 };
165
166 scope.register(Instruction::new(mem_copy, destination));
167 }
168 }
169 }
170 };
171}
172
173tensor_map_load!(1, x);
174tensor_map_load!(2, y, x);
175tensor_map_load!(3, z, y, x);
176tensor_map_load!(4, w, z, y, x);
177tensor_map_load!(5, v, w, z, y, x);
178
179tensor_map_load_im2col!(3, n, w, c; w_offset);
180tensor_map_load_im2col!(4, n, h, w, c; h_offset, w_offset);
181tensor_map_load_im2col!(5, n, d, h, w, c; d_offset, h_offset, w_offset);
182
183#[ruda(self_type = "ref")]
184impl Barrier {
185 pub fn local() -> Self {
188 intrinsic!(|scope| {
189 let variable =
190 scope.create_local_mut(OpaqueType::Barrier(ruda_core::ir::BarrierLevel::Unit));
191 scope.register(BarrierOps::Init {
192 barrier: *variable,
193 is_elected: true.into(),
194 arrival_count: 1.into(),
195 });
196 variable.into()
197 })
198 }
199
200 #[allow(unused_variables)]
207 pub fn shared(arrival_count: u32, is_elected: bool) -> Shared<Barrier> {
208 intrinsic!(|scope| {
209 let variable = scope.create_shared(OpaqueType::Barrier(ruda_core::ir::BarrierLevel::Ruda));
210 scope.register(BarrierOps::Init {
211 barrier: *variable,
212 is_elected: *is_elected.expand,
213 arrival_count: *arrival_count.expand,
214 });
215 variable.into()
216 })
217 }
218
219 pub fn shared_uninit() -> Shared<Barrier> {
222 intrinsic!(|scope| {
223 let variable = scope.create_shared(OpaqueType::Barrier(ruda_core::ir::BarrierLevel::Ruda));
224 scope.register(BarrierOps::Declare { barrier: *variable });
225 variable.into()
226 })
227 }
228
229 #[allow(unused_variables)]
242 pub fn init_manual(&self, arrival_count: u32) {
243 intrinsic!(|scope| {
244 let barrier = *self.expand.clone();
245
246 scope.register(BarrierOps::InitManual {
247 barrier,
248 arrival_count: *arrival_count.expand,
249 });
250 })
251 }
252}
253
254#[ruda(self_type = "ref")]
257impl Barrier {
258 #[allow(unused_variables)]
265 pub fn memcpy_async<C: RudaPrimitive>(&self, source: &Slice<C>, destination: &mut SliceMut<C>) {
266 intrinsic!(|scope| {
267 let barrier = *self.expand;
268 let source_length = *source.length.expand;
269 let (source, source_offset) = source.__to_raw_parts();
270 let (destination, destination_offset) = destination.__to_raw_parts();
271
272 let mem_copy = BarrierOps::MemCopyAsync {
273 barrier,
274 source,
275 source_length,
276 offset_source: source_offset,
277 offset_out: destination_offset,
278 };
279
280 scope.register(Instruction::new(mem_copy, destination));
281 })
282 }
283
284 #[allow(unused_variables)]
291 pub fn memcpy_async_cooperative<C: RudaPrimitive>(
292 &self,
293 source: &Slice<C>,
294 destination: &mut SliceMut<C>,
295 ) {
296 intrinsic!(|scope| {
297 let barrier = *self.expand;
298 let source_length = *source.length.expand;
299 let (source, source_offset) = source.__to_raw_parts();
300 let (destination, destination_offset) = destination.__to_raw_parts();
301
302 let mem_copy = BarrierOps::MemCopyAsyncCooperative {
303 barrier,
304 source,
305 source_length,
306 offset_source: source_offset,
307 offset_out: destination_offset,
308 };
309
310 scope.register(Instruction::new(mem_copy, destination));
311 })
312 }
313
314 #[allow(unused_variables)]
322 pub fn memcpy_async_tx<C: RudaPrimitive>(
323 &self,
324 source: &Slice<C>,
325 destination: &mut SliceMut<C>,
326 ) {
327 intrinsic!(|scope| {
328 let barrier = *self.expand;
329 let source_length = *source.length.expand;
330 let (source, source_offset) = source.__to_raw_parts();
331 let (destination, destination_offset) = destination.__to_raw_parts();
332
333 let mem_copy = BarrierOps::MemCopyAsyncTx {
334 barrier,
335 source,
336 source_length,
337 offset_source: source_offset,
338 offset_out: destination_offset,
339 };
340
341 scope.register(Instruction::new(mem_copy, destination));
342 })
343 }
344}
345
346#[ruda(self_type = "ref")]
349impl Barrier {
350 pub fn arrive(&self) -> BarrierToken {
352 intrinsic!(|scope| {
353 let barrier = *self.expand;
354 let StorageType::Opaque(OpaqueType::Barrier(level)) = barrier.ty.storage_type() else {
355 unreachable!()
356 };
357 let token = scope.create_barrier_token(barrier.index().unwrap(), level);
358 scope.register(Instruction::new(BarrierOps::Arrive { barrier }, *token));
359 token.into()
360 })
361 }
362
363 #[allow(unused_variables)]
365 pub fn arrive_and_expect_tx(&self, arrival_count: u32, transaction_count: u32) -> BarrierToken {
366 intrinsic!(|scope| {
367 let barrier = *self.expand;
368 let StorageType::Opaque(OpaqueType::Barrier(level)) = barrier.ty.storage_type() else {
369 unreachable!()
370 };
371 let token = scope.create_barrier_token(barrier.index().unwrap(), level);
372 let arrival_count: ManagedVariable = arrival_count.into();
373 let transaction_count: ManagedVariable = transaction_count.into();
374 scope.register(Instruction::new(
375 BarrierOps::ArriveTx {
376 barrier,
377 arrive_count_update: arrival_count.consume(),
378 transaction_count_update: transaction_count.consume(),
379 },
380 *token,
381 ));
382 token.into()
383 })
384 }
385
386 #[allow(unused_variables)]
388 pub fn expect_tx(&self, expected_count: u32) {
389 intrinsic!(|scope| {
390 let barrier = *self.expand;
391 let transaction_count: ManagedVariable = expected_count.into();
392 scope.register(BarrierOps::ExpectTx {
393 barrier,
394 transaction_count_update: transaction_count.consume(),
395 });
396 })
397 }
398
399 pub fn arrive_and_wait(&self) {
401 intrinsic!(|scope| {
402 let barrier = *self.expand;
403 scope.register(BarrierOps::ArriveAndWait { barrier });
404 })
405 }
406
407 #[allow(unused_variables)]
409 pub fn wait(&self, token: BarrierToken) {
410 intrinsic!(|scope| {
411 let barrier = *self.expand;
412 let token = *token.expand;
413 scope.register(BarrierOps::Wait { barrier, token });
414 })
415 }
416
417 #[allow(unused_variables)]
420 pub fn wait_parity(&self, phase: u32) {
421 intrinsic!(|scope| {
422 let barrier = *self.expand;
423 let phase = *phase.expand;
424 scope.register(BarrierOps::WaitParity { barrier, phase });
425 })
426 }
427}
428
429pub fn copy_async<C: RudaPrimitive>(
441 _source: &Slice<C>,
442 _destination: &mut SliceMut<C>,
443 _copy_size: u32,
444) {
445 unexpanded!()
446}
447
448pub mod copy_async {
449 use super::*;
450
451 pub fn expand<C: RudaPrimitive>(
452 scope: &mut Scope,
453 source: SliceExpand<C, ReadOnly>,
454 destination: SliceExpand<C, ReadWrite>,
455 copy_length: u32,
456 ) {
457 let source_length = copy_length.into();
458 let (source, source_offset) = source.__to_raw_parts();
459 let (destination, destination_offset) = destination.__to_raw_parts();
460 let scalar_size = C::as_type(scope).storage_type().size();
461
462 let mem_copy = BarrierOps::CopyAsync {
463 source,
464 source_length,
465 offset_source: source_offset,
466 offset_out: destination_offset,
467 copy_length: copy_length * scalar_size as u32,
468 checked: false,
469 };
470
471 scope.register(Instruction::new(mem_copy, destination));
472 }
473}
474
475pub fn copy_async_checked<C: RudaPrimitive>(
487 _source: &Slice<C>,
488 _destination: &mut SliceMut<C>,
489 _copy_size: u32,
490) {
491 unexpanded!();
492}
493
494pub mod copy_async_checked {
495 use super::*;
496
497 pub fn expand<C: RudaPrimitive>(
498 scope: &mut Scope,
499 source: SliceExpand<C, ReadOnly>,
500 destination: SliceExpand<C, ReadWrite>,
501 copy_length: u32,
502 ) {
503 let source_length = *source.length.expand;
504 let (source, source_offset) = source.__to_raw_parts();
505 let (destination, destination_offset) = destination.__to_raw_parts();
506 let scalar_size = C::as_type(scope).storage_type().size();
507
508 let mem_copy = BarrierOps::CopyAsync {
509 source,
510 source_length,
511 offset_source: source_offset,
512 offset_out: destination_offset,
513 copy_length: copy_length * scalar_size as u32,
514 checked: true,
515 };
516
517 scope.register(Instruction::new(mem_copy, destination));
518 }
519}
520
521#[ruda(self_type = "ref")]
522impl Barrier {
523 pub fn commit_copy_async(&self) {
530 intrinsic!(|scope| {
531 let barrier = *self.expand;
532 let StorageType::Opaque(OpaqueType::Barrier(level)) = barrier.ty.storage_type() else {
533 unreachable!()
534 };
535 let token = scope.create_barrier_token(barrier.index().unwrap(), level);
536 scope.register(Instruction::new(
537 BarrierOps::CommitCopyAsync { barrier },
538 *token,
539 ));
540 })
541 }
542}
543
544impl Deref for Shared<Barrier> {
545 type Target = Barrier;
546
547 fn deref(&self) -> &Self::Target {
548 unexpanded!()
549 }
550}
551impl Deref for SharedExpand<Barrier> {
552 type Target = BarrierExpand;
553
554 fn deref(&self) -> &Self::Target {
555 unsafe { self.as_type_ref_unchecked::<Barrier>() }
556 }
557}
558
559impl DerefMut for Shared<Barrier> {
560 fn deref_mut(&mut self) -> &mut Self::Target {
561 todo!()
562 }
563}
564impl DerefMut for SharedExpand<Barrier> {
565 fn deref_mut(&mut self) -> &mut Self::Target {
566 unsafe { self.as_type_mut_unchecked::<Barrier>() }
567 }
568}
569
570impl From<SharedExpand<Barrier>> for BarrierExpand {
571 fn from(value: SharedExpand<Barrier>) -> Self {
572 value.expand.into()
573 }
574}