cubecl_std/tensor/layout/
tiled_view.rs1use cubecl::prelude::*;
2use cubecl_core::{self as cubecl};
3
4use crate::tensor::{
5 View,
6 launch::{MemoryArg, ViewArg, ViewLayoutLaunchArg},
7 layout::{Coords1d, CoordsDyn, Layout, LayoutExpand},
8};
9
10#[derive(CubeType, Clone)]
17pub struct TiledLayout {
18 physical_shape: CoordsDyn,
19 #[cube(comptime)]
20 start_axis: usize,
21 #[cube(comptime)]
22 num_tiled: usize,
23 #[cube(comptime)]
24 levels: usize,
25}
26
27#[cube]
28impl TiledLayout {
29 pub fn new(
30 physical_shape: CoordsDyn,
31 #[comptime] start_axis: usize,
32 #[comptime] num_tiled: usize,
33 #[comptime] levels: usize,
34 ) -> TiledLayout {
35 TiledLayout {
36 physical_shape,
37 start_axis,
38 num_tiled,
39 levels,
40 }
41 }
42}
43
44#[cube]
45impl Layout for TiledLayout {
46 type Coordinates = CoordsDyn;
47 type SourceCoordinates = CoordsDyn;
48
49 fn to_source_pos(&self, pos: Self::Coordinates) -> Self::SourceCoordinates {
53 #[comptime]
54 let n = self.num_tiled;
55 #[comptime]
56 let levels = self.levels;
57 #[comptime]
58 let physical_rank = self.physical_shape.len();
59
60 let mut physical = CoordsDyn::new();
61 #[unroll]
62 for i in 0..self.start_axis {
63 physical.push(pos[i]);
64 }
65 #[unroll]
66 for k in 0..comptime!(levels + 1) {
67 #[unroll]
68 for i in 0..n {
69 let mut divisor = 1u32;
72 #[unroll]
73 for finer in 0..comptime!(levels + 1) {
74 if comptime!(finer > k) {
75 divisor *= self.physical_shape[comptime!(self.start_axis + finer * n + i)];
76 }
77 }
78 let digit = pos[comptime!(self.start_axis + i)] / divisor;
79 if comptime!(k == 0) {
80 physical.push(digit);
81 } else {
82 physical
83 .push(digit % self.physical_shape[comptime!(self.start_axis + k * n + i)]);
84 }
85 }
86 }
87 #[unroll]
88 for i in 0..comptime!(physical_rank - (self.start_axis + (levels + 1) * n)) {
89 physical.push(pos[comptime!(self.start_axis + n + i)]);
90 }
91 physical
92 }
93
94 fn to_source_pos_checked(&self, pos: Self::Coordinates) -> (Self::SourceCoordinates, bool) {
95 let in_bounds = self.is_in_bounds(pos.clone());
96 (self.to_source_pos(pos), in_bounds)
97 }
98
99 fn shape(&self) -> Self::Coordinates {
102 #[comptime]
103 let n = self.num_tiled;
104 #[comptime]
105 let levels = self.levels;
106 #[comptime]
107 let physical_rank = self.physical_shape.len();
108
109 let mut semantic = CoordsDyn::new();
110 #[unroll]
111 for i in 0..self.start_axis {
112 semantic.push(self.physical_shape[i]);
113 }
114 #[unroll]
115 for i in 0..n {
116 let mut extent = 1u32;
117 #[unroll]
118 for k in 0..comptime!(levels + 1) {
119 extent *= self.physical_shape[comptime!(self.start_axis + k * n + i)];
120 }
121 semantic.push(extent);
122 }
123 #[unroll]
124 for i in 0..comptime!(physical_rank - (self.start_axis + (levels + 1) * n)) {
125 semantic.push(self.physical_shape[comptime!(self.start_axis + (levels + 1) * n + i)]);
126 }
127 semantic
128 }
129
130 fn is_in_bounds(&self, pos: Self::Coordinates) -> bool {
131 let bounds = self.shape();
132 let mut is_valid = true;
133 #[unroll]
134 for i in 0..bounds.len() {
135 is_valid = is_valid && pos[i] < bounds[i];
136 }
137 is_valid
138 }
139}
140
141#[derive(CubeType, Clone)]
145pub struct TiledViewLayout {
146 physical_shape: CoordsDyn,
147 physical_strides: CoordsDyn,
148 #[cube(comptime)]
149 start_axis: usize,
150 #[cube(comptime)]
151 num_tiled: usize,
152 #[cube(comptime)]
153 levels: usize,
154}
155
156#[cube]
157impl Layout for TiledViewLayout {
158 type Coordinates = CoordsDyn;
159 type SourceCoordinates = Coords1d;
160
161 fn to_source_pos(&self, pos: Self::Coordinates) -> Self::SourceCoordinates {
163 let split = TiledLayout::new(
164 self.physical_shape.clone(),
165 self.start_axis,
166 self.num_tiled,
167 self.levels,
168 );
169 let physical = split.to_source_pos(pos);
170
171 let mut offset = 0u32;
172 #[unroll]
173 for i in 0..self.physical_strides.len() {
174 offset += physical[i] * self.physical_strides[i];
175 }
176 offset as usize
177 }
178
179 fn to_source_pos_checked(&self, pos: Self::Coordinates) -> (Self::SourceCoordinates, bool) {
180 let in_bounds = self.is_in_bounds(pos.clone());
181 (self.to_source_pos(pos), in_bounds)
182 }
183
184 fn shape(&self) -> Self::Coordinates {
185 let split = TiledLayout::new(
186 self.physical_shape.clone(),
187 self.start_axis,
188 self.num_tiled,
189 self.levels,
190 );
191 split.shape()
192 }
193
194 fn is_in_bounds(&self, pos: Self::Coordinates) -> bool {
195 let bounds = self.shape();
196 let mut is_valid = true;
197 #[unroll]
198 for i in 0..bounds.len() {
199 is_valid = is_valid && pos[i] < bounds[i];
200 }
201 is_valid
202 }
203}
204
205#[derive(Clone, Debug)]
209pub struct TileSpec {
210 pub start_axis: u8,
211 pub num_tiled: usize,
212 pub levels: usize,
213}
214
215#[derive(Debug, Hash, PartialEq, Eq, Clone)]
216pub struct TiledViewLayoutCompilationArg {
217 physical_shape: <CoordsDyn as LaunchArg>::CompilationArg,
218 physical_strides: <CoordsDyn as LaunchArg>::CompilationArg,
219 start_axis: u8,
220 num_tiled: usize,
221 levels: usize,
222}
223
224impl ViewLayoutLaunchArg for TiledViewLayout {
225 type RuntimeArg<R: Runtime> = TileSpec;
226 type CompilationArg = TiledViewLayoutCompilationArg;
227
228 fn register<R: Runtime, B: MemoryArg>(
229 spec: Self::RuntimeArg<R>,
230 buffer: &B,
231 _ty: Type,
232 launcher: &mut KernelLauncher<R>,
233 ) -> Self::CompilationArg {
234 let shape = buffer.shape();
235 let strides = buffer.strides();
236
237 let shape_arg: <CoordsDyn as LaunchArg>::RuntimeArg<R> =
238 shape.iter().map(|&s| s as u32).collect();
239 let strides_arg: <CoordsDyn as LaunchArg>::RuntimeArg<R> =
240 strides.iter().map(|&s| s as u32).collect();
241
242 TiledViewLayoutCompilationArg {
243 physical_shape: <CoordsDyn as LaunchArg>::register(shape_arg, launcher),
244 physical_strides: <CoordsDyn as LaunchArg>::register(strides_arg, launcher),
245 start_axis: spec.start_axis,
246 num_tiled: spec.num_tiled,
247 levels: spec.levels,
248 }
249 }
250
251 fn expand(
252 arg: &Self::CompilationArg,
253 _ty: Type,
254 builder: &mut KernelBuilder,
255 ) -> <Self as CubeType>::ExpandType {
256 TiledViewLayoutExpand {
257 physical_shape: <CoordsDyn as LaunchArg>::expand(&arg.physical_shape, builder),
258 physical_strides: <CoordsDyn as LaunchArg>::expand(&arg.physical_strides, builder),
259 start_axis: arg.start_axis as usize,
260 num_tiled: arg.num_tiled,
261 levels: arg.levels,
262 }
263 }
264}
265
266pub type TiledView<'a, E> = View<'a, E, CoordsDyn>;
268pub type TiledViewLaunch<R> = ViewArg<CoordsDyn, R>;