1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
use crate::;
// Among all backends, the memory order guarantee of WebGPU is the weakest
// So Cubecl's memory order cannot be stronger than that of WebGPU
/// # Coordinates the following among all invocations in the current cube:
///
/// * Memory writes to variables in cube address space(shared memory) complete,
/// e.g. writes that were initiated actually land in the cube address space memory.
///
/// * Then all the invocations in the cube wait for each other to arrive at the barrier, i.e. this step.
///
/// * Then all the invocations int the cube begin executing after the barrier, and all writes to cube address space made before the barrier are now visible to any invocation in this cube.
/// Synchronizes units within their plane (e.g., warp or SIMD group).
///
/// Warning: not all targets support plane-level synchronization.
/// [`sync_plane()`] over storage memory (input args) as well as shared memory.
///
/// The units of the plane meet, and every write one of them made to storage before it is visible
/// to the others after it. Only the units of the plane must reach it, unlike [`sync_storage()`],
/// so a window a plane holds can hand its own units what they wrote to global memory. It orders
/// nothing for other planes or other cubes.
///
/// Warning: as with [`sync_plane()`], a target without plane-level synchronization (WebGPU) lowers
/// it to a cube barrier, which every unit of the cube must reach.
/// [`sync_cube`] over storage memory (input args) rather than shared memory, and the one
/// synchronization that reaches past the cube.
///
/// Every unit of the cube must reach it, and it is a [`sync_cube`] as well as what follows, so a
/// value one unit leaves in shared memory before it is readable by the rest after it. On top of
/// that cube barrier it is a release and an acquire at device scope: every write this cube made to storage before it is
/// visible to any other cube that calls it afterwards, and every write another cube published
/// before its own call is visible here after it. That is what lets cubes hand each other partial
/// results — publish, `sync_storage`, then announce through an atomic — with no second dispatch.
///
/// **Only where the runtime says so.** WebGPU's memory model promises nothing across workgroups,
/// so on a backend whose
/// [`device_memory_scope`] is `false` this is a cube
/// barrier and no more, and a cube reading another's writes may read them stale. Ask before
/// launching a kernel that depends on the promise.
///
/// [`sync_cube`]: fn@sync_cube
/// [`device_memory_scope`]: cubecl_ir::features::Features::device_memory_scope
/// [`sync_storage`] at system scope: the release and acquire also reach the host and kernels on
/// other devices that bind this memory.
///
/// Every unit of the cube must reach it. What this cube wrote before it, to its own device's
/// storage or to a peer's, is visible to a kernel on another device that synchronizes at system
/// scope after reading the signal this cube then publishes, and what such a kernel published
/// before its signal is visible here once this cube read the signal and called it. Signal through
/// an atomic at [`SyncScope::System`], such as [`Atomic::store_at`] and [`Atomic::load_at`]: a
/// device-scope atomic does not reach the other device.
///
/// On a runtime that shares no memory between devices this is [`sync_storage`].
/// `sync_async_proxy_shared` is a synchronization fence for the experimental SM 9.0+ copy
/// functions, applying bidirectionally between the async proxy (i.e. TMA) and shared memory.
/// Should be used after initializing the barriers, and before the copy operation.
/// PTX: `fence.proxy.async.shared::cta`
/// Experimental and subject to change.
/// Barrier, then load `reference` with the result marked workgroup-uniform —
/// mirrors WGSL's `workgroupUniformLoad`. Lets a workgroup-shared value gate
/// control flow that contains barriers. Non-WGSL backends lower it to
/// [`sync_cube`] plus a plain load.
///
/// Use [`workgroup_uniform_load_atomic`] for `Atomic<E>`.
///
/// [`sync_cube`]: fn@sync_cube
/// [`workgroup_uniform_load_atomic`]: fn@workgroup_uniform_load_atomic
/// Module containing the expand function for [`workgroup_uniform_load()`].
/// Atomic counterpart of [`workgroup_uniform_load`]: barrier + atomic load,
/// returning the underlying numeric (WGSL's atomic `workgroupUniformLoad`
/// overload).
///
/// [`workgroup_uniform_load`]: fn@workgroup_uniform_load
/// Module containing the expand function for [`workgroup_uniform_load_atomic()`].