1use core::fmt::{self, Display, Formatter};
4
5use cubecl::zspace::Tiling;
6
7use crate::{Axis, LineMisfit};
8
9#[derive(Clone, PartialEq, Eq, Debug)]
11pub enum Refusal {
12 StrideOrderOfAStatedLayout,
14 GatherOfATiledBinding(Tiling),
16 GatherWithLabels,
18 GatherRankMismatch { mapped: usize, rank: usize },
20 GatherOfAnUnknownAxis(Axis),
22 RankBelowLabels { rank: usize, block: usize },
24 UnlabelledBatchDims { dims: usize, axes: usize },
26 NoCoordinate,
28 WidthNotServed { width: usize, why: LineMisfit },
30 UncheckableVectorEdge,
32 GatherInnermostNotInLines,
35 GatherAxisAddressedTwice(Axis),
38 GridNotReadOffLevels { units: u32, plane: u32 },
41 CubePastDevice { units: u32, most: u32 },
43 PlanesUnavailable,
45 ImprecisePlaneDim { min: u32, max: u32 },
47 Declined { why: &'static str },
49 CubeShapePastDevice {
52 shape: (u32, u32, u32),
53 most: (u32, u32, u32),
54 },
55 NoUnits,
57 NoCubes,
60 GridPastDevice {
63 count: (u32, u32, u32),
64 most: (u32, u32, u32),
65 },
66 SharedMemoryPastDevice { bytes: usize, most: usize },
68 FillersWithoutBarriers { fillers: u32 },
71 BoxPastDescriptor {
73 axis: Axis,
74 edge: usize,
75 most: usize,
76 },
77 BoxSplitsStageBlocks {
81 axis: Axis,
82 rows: usize,
83 period: usize,
84 },
85 RowsNoDescriptorLands { why: &'static str },
88 PagingOfAStatedLayout,
92 PagingOfAnUnlabelledAxis(Axis),
95 PagingOfOneDim(Axis),
98 PagesAlongALine(Axis),
101 PagingOfAnEmptyPool,
104 PagingMovedByRuns,
107 ScalesOfAPoolUnpaged,
111 IndexTableNotU32,
114 IndexTableRank { keys: usize, rank: usize },
117 IndexOfAStatedLayout,
120 IndexOfAnAxisNotSpanned(Axis),
122 IndexAlongALine(Axis),
126 IndexKeyedByItsAxis(Axis),
128 RunKeyedByMany(usize),
131 IndexKeysCutApart(Vec<Axis>),
134 IndexedAxisCut(Axis),
137 CodebookOfValuesNotIndices,
140 CodebookTableNotPlain,
143 CodebookTableShort { entries: usize, bits: usize },
146}
147
148impl Display for Refusal {
149 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
150 match self {
151 Refusal::StrideOrderOfAStatedLayout => write!(
152 f,
153 "Arg::in_stride_order: the order a buffer steps is read off strides, which a \
154 gathered mapping states for itself and a storage-tiled binding stores in tiles"
155 ),
156 Refusal::GatherOfATiledBinding(tiling) => write!(
157 f,
158 "Arg::gathered: the mapping addresses the buffer's own dims, so a storage-tiled \
159 binding ({tiling:?}) has no reading here"
160 ),
161 Refusal::GatherWithLabels => write!(
162 f,
163 "Arg::gathered: the mapping is stated outright, so `axes` and `batches` have \
164 nothing left to describe"
165 ),
166 Refusal::GatherRankMismatch { mapped, rank } => write!(
167 f,
168 "Arg::gathered: the mapping addresses {mapped} dims but the operand has {rank}"
169 ),
170 Refusal::GatherOfAnUnknownAxis(axis) => write!(
171 f,
172 "Arg::gathered: the mapping spans {axis:?}, which the launched space does not have"
173 ),
174 Refusal::RankBelowLabels { rank, block } => write!(
175 f,
176 "Arg: operand rank {rank} is smaller than its labelled block of {block} dims"
177 ),
178 Refusal::UnlabelledBatchDims { dims, axes } => {
179 write!(f, "Arg: {dims} batch dims but only {axes} batch axes given")
180 }
181 Refusal::NoCoordinate => {
182 write!(f, "Arg: an operand must address at least one coordinate")
183 }
184 Refusal::WidthNotServed { width, why } => {
185 write!(
186 f,
187 "Arg::vectorize: this operand cannot be served {width} wide: {why}"
188 )
189 }
190 Refusal::UncheckableVectorEdge => write!(
191 f,
192 "Arg: the innermost axis is served in vector lines but is not provably in bounds \
193 (it overhangs its tiling, or its map is affine and reaches past any extent stated \
194 here); serve it scalar, or state BoundaryPolicy::Unchecked if the launch proves \
195 its vector lines are in bounds"
196 ),
197 Refusal::GatherInnermostNotInLines => write!(
198 f,
199 "Arg::gathered: the innermost physical axis must step by the operand's last \
200 logical axis at coefficient 1 (it is addressed in vector lines)"
201 ),
202 Refusal::GatherAxisAddressedTwice(axis) => write!(
203 f,
204 "Arg::gathered: logical axis {axis:?} addresses several physical axes, so it is \
205 either storage-tiled (a gathered operand must be untiled gmem) or read off two \
206 places at once"
207 ),
208 Refusal::GridNotReadOffLevels { units, plane } => write!(
209 f,
210 "Launcher: a grid read off the levels needs a units level of one unit or the \
211 whole plane ({plane}), got {units}"
212 ),
213 Refusal::CubePastDevice { units, most } => write!(
214 f,
215 "Launcher: a cube of {units} units, but the device holds at most {most}"
216 ),
217 Refusal::PlanesUnavailable => {
218 write!(
219 f,
220 "the kernel works in planes, and the device runs no plane operations"
221 )
222 }
223 Refusal::ImprecisePlaneDim { min, max } => write!(
224 f,
225 "the kernel needs one plane width, and the device's varies from {min} to {max}"
226 ),
227 Refusal::Declined { why } => f.write_str(why),
228 Refusal::CubeShapePastDevice { shape, most } => write!(
229 f,
230 "Launcher: a cube shaped {shape:?}, but the device spawns at most {most:?}"
231 ),
232 Refusal::NoUnits => write!(f, "Launcher: the cube has a zero axis and spawns no units"),
233 Refusal::NoCubes => write!(f, "Launcher: the grid has a zero axis and spawns no cubes"),
234 Refusal::GridPastDevice { count, most } => write!(
235 f,
236 "Launcher: a grid of {count:?} cubes, but the device launches at most {most:?}"
237 ),
238 Refusal::SharedMemoryPastDevice { bytes, most } => write!(
239 f,
240 "Launcher: a cube holding {bytes} bytes of shared memory, but the device gives \
241 one at most {most}"
242 ),
243 Refusal::FillersWithoutBarriers { fillers } => write!(
244 f,
245 "Launcher: {fillers} plane(s) are set aside to fill a walk's stages, and this \
246 device carries no barrier type for the two roles to meet on"
247 ),
248 Refusal::BoxPastDescriptor { axis, edge, most } => write!(
249 f,
250 "TMA: {edge} along {axis:?} exceeds the {most}-per-axis box limit"
251 ),
252 Refusal::BoxSplitsStageBlocks { axis, rows, period } => write!(
253 f,
254 "TMA: a box lands its rows whole and in order, and the stage's blocks split \
255 {axis:?} or stack {rows} rows apiece where the swizzle repeats every {period}"
256 ),
257 Refusal::RowsNoDescriptorLands { why } => write!(
258 f,
259 "TMA: a box lands its rows dense, at most swizzled within a span, and the stage \
260 holds {why}"
261 ),
262 Refusal::PagingOfAStatedLayout => write!(
263 f,
264 "TileArgLaunch::indexed: a page is resolved coordinate by coordinate over a plain \
265 buffer's labelled dims, so a gathered mapping or a storage-tiled binding has no \
266 reading here"
267 ),
268 Refusal::PagingOfAnUnlabelledAxis(axis) => write!(
269 f,
270 "TileArgLaunch::indexed: {axis:?} labels no dim of this operand, so no dim holds \
271 its pages"
272 ),
273 Refusal::PagingOfOneDim(axis) => write!(
274 f,
275 "TileArgLaunch::indexed: {axis:?} names the pages and their positions both, on one \
276 dim"
277 ),
278 Refusal::PagesAlongALine(axis) => write!(
279 f,
280 "TileArgLaunch::indexed: the pages along {axis:?} lie on the innermost dim, which \
281 a line runs along, so a line would span pages"
282 ),
283 Refusal::PagingOfAnEmptyPool => write!(
284 f,
285 "TileArgLaunch::indexed: the pool holds no page, or its pages no position, for a \
286 table entry to read"
287 ),
288 Refusal::ScalesOfAPoolUnpaged => write!(
289 f,
290 "TileArgLaunch::indexed: the scales of a pool of pages span its pages or \
291 positions, so they are a pool of their own, placed by the same table before they \
292 are stated"
293 ),
294 Refusal::PagingMovedByRuns => write!(
295 f,
296 "TileArgLaunch::indexed: a page table is resolved a line at a time, so a delivery \
297 that moves runs has no reading through it"
298 ),
299 Refusal::CodebookOfValuesNotIndices => write!(
300 f,
301 "TileArgLaunch::codebook: a codebook is read through values stored as indices \
302 (`Field::Index`)"
303 ),
304 Refusal::CodebookTableNotPlain => write!(
305 f,
306 "TileArgLaunch::codebook: the table is a plain one-dim buffer, one value a line"
307 ),
308 Refusal::CodebookTableShort { entries, bits } => write!(
309 f,
310 "TileArgLaunch::codebook: {bits}-bit indices name {} entries; the table holds \
311 {entries}",
312 1usize << bits
313 ),
314 Refusal::IndexTableNotU32 => write!(
315 f,
316 "TileArgLaunch::indexed: a table holds plain u32 entries, one a line, each a \
317 coordinate"
318 ),
319 Refusal::IndexTableRank { keys, rank } => write!(
320 f,
321 "TileArgLaunch::indexed: the table has {rank} dims and {keys} keys; it holds one dim \
322 per key"
323 ),
324 Refusal::IndexOfAStatedLayout => write!(
325 f,
326 "TileArgLaunch::indexed: an entry moves the window of a plain buffer over its \
327 labelled dims, which a tensor map, a gathered, storage-tiled or paged operand is not"
328 ),
329 Refusal::IndexOfAnAxisNotSpanned(axis) => write!(
330 f,
331 "TileArgLaunch::indexed: the entry places {axis:?}, which the operand does not span"
332 ),
333 Refusal::IndexAlongALine(axis) => write!(
334 f,
335 "TileArgLaunch::indexed: the entry places {axis:?}, the innermost axis, which the \
336 operand reads more than one value a line along; bind it one value a line"
337 ),
338 Refusal::IndexKeyedByItsAxis(axis) => write!(
339 f,
340 "TileArgLaunch::indexed: the table is keyed by no axis, or by {axis:?}, the axis its \
341 entry places"
342 ),
343 Refusal::RunKeyedByMany(keys) => write!(
344 f,
345 "Indexing::Run: a run ends at the next entry along its one key, and this table has \
346 {keys} keys"
347 ),
348 Refusal::IndexKeysCutApart(keys) => write!(
349 f,
350 "Indexing: the first level cutting one of {keys:?} does not cut them all; the \
351 table is read at one step"
352 ),
353 Refusal::IndexedAxisCut(axis) => write!(
354 f,
355 "Indexing: a level cuts {axis:?}, the axis the entry places; a coordinate is the \
356 table's to state, and a run is placed whole before any level cuts it"
357 ),
358 }
359 }
360}
361
362impl std::error::Error for Refusal {}