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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
//! [`Refusal`]: why a launch cannot run as described, or an operand cannot be bound to it.
use core::fmt::{self, Display, Formatter};
use cubecl::zspace::Tiling;
use crate::{Axis, LineMisfit};
/// Why a launch cannot run as described, or an operand cannot be bound to it.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Refusal {
/// [`in_stride_order`](super::Arg::in_stride_order) on a gathered or storage-tiled operand.
StrideOrderOfAStatedLayout,
/// A gathered mapping over a storage-tiled binding.
GatherOfATiledBinding(Tiling),
/// [`gathered`](super::Arg::gathered) combined with `axes` or `batches`.
GatherWithLabels,
/// The mapping addresses `mapped` dims but the operand has `rank`.
GatherRankMismatch { mapped: usize, rank: usize },
/// The mapping spans an axis the launched space does not have.
GatherOfAnUnknownAxis(Axis),
/// The operand's rank is smaller than its labelled block of dims.
RankBelowLabels { rank: usize, block: usize },
/// More leading dims than batch axes to label them.
UnlabelledBatchDims { dims: usize, axes: usize },
/// An operand must address at least one coordinate.
NoCoordinate,
/// The buffer cannot be served `width` wide.
WidthNotServed { width: usize, why: LineMisfit },
/// The innermost axis is served in vector lines but is not provably in bounds.
UncheckableVectorEdge,
/// A gathered mapping read in vector lines whose innermost physical axis does not step by the
/// operand's last logical axis at coefficient 1.
GatherInnermostNotInLines,
/// A gathered mapping that reads `axis` off several physical axes: the operand is
/// storage-tiled, or reads one axis from two places.
GatherAxisAddressedTwice(Axis),
/// A grid read off the levels ([`Grid::FromLevels`](crate::launch::Grid::FromLevels)) needs a
/// units level of one unit or the whole `plane`; this one holds `units`.
GridNotReadOffLevels { units: u32, plane: u32 },
/// A cube of `units` units, past the `most` the device holds.
CubePastDevice { units: u32, most: u32 },
/// The kernel works in planes, and the device runs no plane operations.
PlanesUnavailable,
/// The kernel needs one plane width, and the device's varies between `min` and `max`.
ImprecisePlaneDim { min: u32, max: u32 },
/// A routine declines a problem it does not serve, for the reason `why`.
Declined { why: &'static str },
/// A cube shaped `shape` along x, y and z, past the `most` the device spawns along one of them:
/// a cube legal in units can still be too long on an axis.
CubeShapePastDevice {
shape: (u32, u32, u32),
most: (u32, u32, u32),
},
/// A cube with a zero axis, which spawns no units.
NoUnits,
/// A grid with a zero axis, which spawns no cubes: the runtime returns without dispatching
/// anything, and the outputs keep whatever they held.
NoCubes,
/// A grid of `count` cubes along x, y and z, past the `most` the device launches along one of
/// them.
GridPastDevice {
count: (u32, u32, u32),
most: (u32, u32, u32),
},
/// A cube holding `bytes` of shared memory, past the `most` the device gives one.
SharedMemoryPastDevice { bytes: usize, most: usize },
/// `fillers` planes are set aside to fill a walk's stages, and the device has no barrier type
/// for the two roles to meet on.
FillersWithoutBarriers { fillers: u32 },
/// A TMA box edge past the descriptor's per-axis limit `most`.
BoxPastDescriptor {
axis: Axis,
edge: usize,
most: usize,
},
/// A TMA box lands its rows whole, one after the other, and the stage's blocks split the rows
/// along `axis`, the innermost, or stack `rows` of them where the swizzle repeats every
/// `period`.
BoxSplitsStageBlocks {
axis: Axis,
rows: usize,
period: usize,
},
/// A TMA box lands its rows dense, at most swizzled within one span, and the stage keeps them
/// as `why` says.
RowsNoDescriptorLands { why: &'static str },
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages on a gathered or
/// storage-tiled operand: a page is resolved coordinate by coordinate over a plain buffer's
/// labelled dims.
PagingOfAStatedLayout,
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages naming an axis no dim of the
/// operand is labelled with.
PagingOfAnUnlabelledAxis(Axis),
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages naming one dim for both the
/// pages and their positions.
PagingOfOneDim(Axis),
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages with the pages along the
/// innermost dim, this axis's: a line runs along it, so one line would span pages.
PagesAlongALine(Axis),
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages on a pool of no pages, or of
/// pages of no positions: there is no page for a table entry to read.
PagingOfAnEmptyPool,
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages on an operand moved by runs
/// (a bulk copy, a tensor map): the table resolves one line at a time.
PagingMovedByRuns,
/// [`indexed`](crate::TileArgLaunch::indexed) over a pool of pages whose scales span its pages
/// or positions unplaced: they are a pool of their own, placed by the same table before they
/// are stated.
ScalesOfAPoolUnpaged,
/// [`indexed`](crate::TileArgLaunch::indexed) with a table that is not plain `u32` entries,
/// one a line: an entry is a coordinate.
IndexTableNotU32,
/// [`indexed`](crate::TileArgLaunch::indexed) with a table of `rank` dims keyed by `keys`
/// axes: a table holds one dim per key.
IndexTableRank { keys: usize, rank: usize },
/// [`indexed`](crate::TileArgLaunch::indexed) on a tensor map, or on a gathered, storage-tiled
/// or paged operand: an entry moves a window of a plain buffer's labelled dims.
IndexOfAStatedLayout,
/// [`indexed`](crate::TileArgLaunch::indexed) placing an axis the operand does not span.
IndexOfAnAxisNotSpanned(Axis),
/// [`indexed`](crate::TileArgLaunch::indexed) placing the innermost axis, this one, which the
/// operand reads more than one value a line along: an entry is an element, and a line would
/// straddle two of them.
IndexAlongALine(Axis),
/// [`indexed`](crate::TileArgLaunch::indexed) with no key, or keyed by the axis it places.
IndexKeyedByItsAxis(Axis),
/// [`Indexing::Run`](crate::Indexing::Run) keyed by this many axes: a run's end is the next
/// entry along its one key.
RunKeyedByMany(usize),
/// An indexed operand under a nest whose first level cutting one of these keys does not cut
/// them all: the table is read at one step.
IndexKeysCutApart(Vec<Axis>),
/// An indexed operand under a nest that cuts the axis its entry places: a coordinate is the
/// table's to state, and a run is placed whole before any level cuts it.
IndexedAxisCut(Axis),
/// [`codebook`](crate::TileArgLaunch::codebook) on values not stored as indices
/// ([`Field::Index`](crate::Field::Index)).
CodebookOfValuesNotIndices,
/// [`codebook`](crate::TileArgLaunch::codebook) with a table that is not a plain one-dim
/// buffer read one value a line.
CodebookTableNotPlain,
/// [`codebook`](crate::TileArgLaunch::codebook) with a table of `entries`, fewer than the
/// `2^bits` the indices name.
CodebookTableShort { entries: usize, bits: usize },
}
impl Display for Refusal {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Refusal::StrideOrderOfAStatedLayout => write!(
f,
"Arg::in_stride_order: the order a buffer steps is read off strides, which a \
gathered mapping states for itself and a storage-tiled binding stores in tiles"
),
Refusal::GatherOfATiledBinding(tiling) => write!(
f,
"Arg::gathered: the mapping addresses the buffer's own dims, so a storage-tiled \
binding ({tiling:?}) has no reading here"
),
Refusal::GatherWithLabels => write!(
f,
"Arg::gathered: the mapping is stated outright, so `axes` and `batches` have \
nothing left to describe"
),
Refusal::GatherRankMismatch { mapped, rank } => write!(
f,
"Arg::gathered: the mapping addresses {mapped} dims but the operand has {rank}"
),
Refusal::GatherOfAnUnknownAxis(axis) => write!(
f,
"Arg::gathered: the mapping spans {axis:?}, which the launched space does not have"
),
Refusal::RankBelowLabels { rank, block } => write!(
f,
"Arg: operand rank {rank} is smaller than its labelled block of {block} dims"
),
Refusal::UnlabelledBatchDims { dims, axes } => {
write!(f, "Arg: {dims} batch dims but only {axes} batch axes given")
}
Refusal::NoCoordinate => {
write!(f, "Arg: an operand must address at least one coordinate")
}
Refusal::WidthNotServed { width, why } => {
write!(
f,
"Arg::vectorize: this operand cannot be served {width} wide: {why}"
)
}
Refusal::UncheckableVectorEdge => write!(
f,
"Arg: the innermost axis is served in vector lines but is not provably in bounds \
(it overhangs its tiling, or its map is affine and reaches past any extent stated \
here); serve it scalar, or state BoundaryPolicy::Unchecked if the launch proves \
its vector lines are in bounds"
),
Refusal::GatherInnermostNotInLines => write!(
f,
"Arg::gathered: the innermost physical axis must step by the operand's last \
logical axis at coefficient 1 (it is addressed in vector lines)"
),
Refusal::GatherAxisAddressedTwice(axis) => write!(
f,
"Arg::gathered: logical axis {axis:?} addresses several physical axes, so it is \
either storage-tiled (a gathered operand must be untiled gmem) or read off two \
places at once"
),
Refusal::GridNotReadOffLevels { units, plane } => write!(
f,
"Launcher: a grid read off the levels needs a units level of one unit or the \
whole plane ({plane}), got {units}"
),
Refusal::CubePastDevice { units, most } => write!(
f,
"Launcher: a cube of {units} units, but the device holds at most {most}"
),
Refusal::PlanesUnavailable => {
write!(
f,
"the kernel works in planes, and the device runs no plane operations"
)
}
Refusal::ImprecisePlaneDim { min, max } => write!(
f,
"the kernel needs one plane width, and the device's varies from {min} to {max}"
),
Refusal::Declined { why } => f.write_str(why),
Refusal::CubeShapePastDevice { shape, most } => write!(
f,
"Launcher: a cube shaped {shape:?}, but the device spawns at most {most:?}"
),
Refusal::NoUnits => write!(f, "Launcher: the cube has a zero axis and spawns no units"),
Refusal::NoCubes => write!(f, "Launcher: the grid has a zero axis and spawns no cubes"),
Refusal::GridPastDevice { count, most } => write!(
f,
"Launcher: a grid of {count:?} cubes, but the device launches at most {most:?}"
),
Refusal::SharedMemoryPastDevice { bytes, most } => write!(
f,
"Launcher: a cube holding {bytes} bytes of shared memory, but the device gives \
one at most {most}"
),
Refusal::FillersWithoutBarriers { fillers } => write!(
f,
"Launcher: {fillers} plane(s) are set aside to fill a walk's stages, and this \
device carries no barrier type for the two roles to meet on"
),
Refusal::BoxPastDescriptor { axis, edge, most } => write!(
f,
"TMA: {edge} along {axis:?} exceeds the {most}-per-axis box limit"
),
Refusal::BoxSplitsStageBlocks { axis, rows, period } => write!(
f,
"TMA: a box lands its rows whole and in order, and the stage's blocks split \
{axis:?} or stack {rows} rows apiece where the swizzle repeats every {period}"
),
Refusal::RowsNoDescriptorLands { why } => write!(
f,
"TMA: a box lands its rows dense, at most swizzled within a span, and the stage \
holds {why}"
),
Refusal::PagingOfAStatedLayout => write!(
f,
"TileArgLaunch::indexed: a page is resolved coordinate by coordinate over a plain \
buffer's labelled dims, so a gathered mapping or a storage-tiled binding has no \
reading here"
),
Refusal::PagingOfAnUnlabelledAxis(axis) => write!(
f,
"TileArgLaunch::indexed: {axis:?} labels no dim of this operand, so no dim holds \
its pages"
),
Refusal::PagingOfOneDim(axis) => write!(
f,
"TileArgLaunch::indexed: {axis:?} names the pages and their positions both, on one \
dim"
),
Refusal::PagesAlongALine(axis) => write!(
f,
"TileArgLaunch::indexed: the pages along {axis:?} lie on the innermost dim, which \
a line runs along, so a line would span pages"
),
Refusal::PagingOfAnEmptyPool => write!(
f,
"TileArgLaunch::indexed: the pool holds no page, or its pages no position, for a \
table entry to read"
),
Refusal::ScalesOfAPoolUnpaged => write!(
f,
"TileArgLaunch::indexed: the scales of a pool of pages span its pages or \
positions, so they are a pool of their own, placed by the same table before they \
are stated"
),
Refusal::PagingMovedByRuns => write!(
f,
"TileArgLaunch::indexed: a page table is resolved a line at a time, so a delivery \
that moves runs has no reading through it"
),
Refusal::CodebookOfValuesNotIndices => write!(
f,
"TileArgLaunch::codebook: a codebook is read through values stored as indices \
(`Field::Index`)"
),
Refusal::CodebookTableNotPlain => write!(
f,
"TileArgLaunch::codebook: the table is a plain one-dim buffer, one value a line"
),
Refusal::CodebookTableShort { entries, bits } => write!(
f,
"TileArgLaunch::codebook: {bits}-bit indices name {} entries; the table holds \
{entries}",
1usize << bits
),
Refusal::IndexTableNotU32 => write!(
f,
"TileArgLaunch::indexed: a table holds plain u32 entries, one a line, each a \
coordinate"
),
Refusal::IndexTableRank { keys, rank } => write!(
f,
"TileArgLaunch::indexed: the table has {rank} dims and {keys} keys; it holds one dim \
per key"
),
Refusal::IndexOfAStatedLayout => write!(
f,
"TileArgLaunch::indexed: an entry moves the window of a plain buffer over its \
labelled dims, which a tensor map, a gathered, storage-tiled or paged operand is not"
),
Refusal::IndexOfAnAxisNotSpanned(axis) => write!(
f,
"TileArgLaunch::indexed: the entry places {axis:?}, which the operand does not span"
),
Refusal::IndexAlongALine(axis) => write!(
f,
"TileArgLaunch::indexed: the entry places {axis:?}, the innermost axis, which the \
operand reads more than one value a line along; bind it one value a line"
),
Refusal::IndexKeyedByItsAxis(axis) => write!(
f,
"TileArgLaunch::indexed: the table is keyed by no axis, or by {axis:?}, the axis its \
entry places"
),
Refusal::RunKeyedByMany(keys) => write!(
f,
"Indexing::Run: a run ends at the next entry along its one key, and this table has \
{keys} keys"
),
Refusal::IndexKeysCutApart(keys) => write!(
f,
"Indexing: the first level cutting one of {keys:?} does not cut them all; the \
table is read at one step"
),
Refusal::IndexedAxisCut(axis) => write!(
f,
"Indexing: a level cuts {axis:?}, the axis the entry places; a coordinate is the \
table's to state, and a run is placed whole before any level cuts it"
),
}
}
}
impl std::error::Error for Refusal {}