Skip to main content

cubek_std/
plane_flow.rs

1//! Plane-flow vocabulary used by stage / global readers / partition tiles.
2//! All types live here:
3//!   - comptime data: [`PlaneFlowCounts`], [`PlaneFlowPartitionRule`],
4//!     [`PlaneFlowConfig`], [`InputLoadFlow`]
5//!   - runtime cube types: [`PartitionThreshold`], [`PlaneFlowPartition`]
6//!   - composition helper: [`partition_coordinates`]
7//!
8//! cubek-matmul (and other consumers) re-export these to keep their own paths
9//! stable; the canonical home is here so tile-level primitives can compose
10//! plane-flow logic without reaching into cubek-matmul.
11
12use cubecl::{prelude::*, std::tensor::layout::Coords2d};
13
14use crate::tile::Partitioner;
15
16// ============================================================================
17// Comptime data: plane counts, partition rule, full config, input-load flow.
18// ============================================================================
19
20#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
21/// Represents how many planes are used for main computation and for loading-only tasks.
22pub struct PlaneFlowCounts {
23    /// Number of planes participating in main flow and (possibly) loading.
24    pub main_flow: u32,
25    /// Number of planes dedicated solely to loading.
26    pub load_only: u32,
27}
28
29impl PlaneFlowCounts {
30    /// Return the total number of planes
31    pub fn total_count(&self) -> u32 {
32        self.main_flow + self.load_only
33    }
34}
35
36#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
37/// How planes are partitioned by id between the main flow and load-only roles.
38pub enum PlaneFlowPartitionRule {
39    MainFlowOnly,
40    LoadOnlyFirst { load_only: u32 },
41    LoadOnlyLast { main_flow: u32 },
42}
43
44#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
45/// Plane-flow configuration carried by `CubeDimResource::Specialized`. Holds the
46/// counts for main-flow vs load-only planes and the partition rule used at
47/// runtime.
48pub struct PlaneFlowConfig {
49    pub counts: PlaneFlowCounts,
50    pub partition_rule: PlaneFlowPartitionRule,
51}
52
53impl PlaneFlowConfig {
54    /// All planes participate in the main flow; no load-only planes.
55    pub fn new_unspecialized(num_planes: u32) -> Self {
56        Self {
57            counts: PlaneFlowCounts {
58                main_flow: num_planes,
59                load_only: 0,
60            },
61            partition_rule: PlaneFlowPartitionRule::MainFlowOnly,
62        }
63    }
64
65    /// Number of planes participating in main flow.
66    pub fn main_flow_count(&self) -> u32 {
67        self.counts.main_flow
68    }
69
70    /// Whether the configuration uses dedicated load-only planes.
71    pub fn has_specialization(&self) -> bool {
72        self.counts.load_only > 0
73    }
74}
75
76#[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq)]
77/// Determines which types of planes are responsible for loading a tensor.
78pub enum InputLoadFlow {
79    /// Loaded exclusively by planes that participate in the main computation flow.
80    #[default]
81    MainOnly,
82    /// Loaded exclusively by planes dedicated to loading (load-only planes).
83    LoadOnly,
84}
85
86impl InputLoadFlow {
87    /// Whether there is specialization for the tensor.
88    pub fn has_specialization(&self) -> bool {
89        matches!(self, InputLoadFlow::LoadOnly)
90    }
91}
92
93// ============================================================================
94// Runtime cube types: PartitionThreshold, PlaneFlowPartition.
95// ============================================================================
96
97#[derive(CubeType, Copy, Clone, Debug, Hash, PartialEq, Eq)]
98/// Threshold of plane id at which the roles change.
99///
100/// Only exists because Cube enums cannot hold a comptime value directly.
101pub struct PartitionThreshold {
102    #[cube(comptime)]
103    threshold: u32,
104}
105
106#[derive(CubeType, Copy, Clone, Debug, Hash, PartialEq, Eq)]
107/// Runtime view of [`PlaneFlowPartitionRule`]: distinguishes a plane's role
108/// based on its plane id.
109pub enum PlaneFlowPartition {
110    /// All planes are in the main flow (no specialization).
111    MainFlowOnly,
112    /// Load-only planes: `[0, Threshold)`; main-flow planes: `[Threshold, total)`.
113    LoadOnlyFirst(PartitionThreshold),
114    /// Main-flow planes: `[0, Threshold)`; load-only planes: `[Threshold, total)`.
115    LoadOnlyLast(PartitionThreshold),
116}
117
118#[cube]
119impl PlaneFlowPartition {
120    /// Construct from comptime rule.
121    pub fn new(#[comptime] comptime_rule: PlaneFlowPartitionRule) -> PlaneFlowPartition {
122        match comptime_rule {
123            PlaneFlowPartitionRule::MainFlowOnly => PlaneFlowPartition::new_MainFlowOnly(),
124            PlaneFlowPartitionRule::LoadOnlyFirst { load_only } => {
125                PlaneFlowPartition::new_LoadOnlyFirst(PartitionThreshold {
126                    threshold: load_only,
127                })
128            }
129            PlaneFlowPartitionRule::LoadOnlyLast { main_flow } => {
130                PlaneFlowPartition::new_LoadOnlyLast(PartitionThreshold {
131                    threshold: main_flow,
132                })
133            }
134        }
135    }
136
137    /// The index of the current plane among planes that perform compute,
138    /// ignoring load-only planes.
139    pub fn compute_index(self) -> u32 {
140        match self {
141            PlaneFlowPartition::MainFlowOnly => UNIT_POS_Y,
142            PlaneFlowPartition::LoadOnlyFirst(load_only) => UNIT_POS_Y - load_only.threshold,
143            PlaneFlowPartition::LoadOnlyLast(_) => UNIT_POS_Y,
144        }
145    }
146
147    /// The index of the current plane among planes that perform loading,
148    /// ignoring any plane that does not participate for this `ident`.
149    pub fn load_index(self, #[comptime] specialization_tensor_config: InputLoadFlow) -> u32 {
150        match self {
151            PlaneFlowPartition::MainFlowOnly => UNIT_POS_Y,
152            PlaneFlowPartition::LoadOnlyFirst(load_only) => match specialization_tensor_config {
153                InputLoadFlow::MainOnly => UNIT_POS_Y - load_only.threshold,
154                InputLoadFlow::LoadOnly => UNIT_POS_Y,
155            },
156            PlaneFlowPartition::LoadOnlyLast(main_flow) => match specialization_tensor_config {
157                InputLoadFlow::LoadOnly => UNIT_POS_Y - main_flow.threshold,
158                InputLoadFlow::MainOnly => UNIT_POS_Y,
159            },
160        }
161    }
162
163    /// Whether this unit is the leader of the loading units. Always the lowest
164    /// unit in the correct group. Used by TMA; `plane_broadcast` / `plane_elect`
165    /// keep the value warp-uniform.
166    pub fn elect_load_leader(&self) -> bool {
167        let plane_id = plane_broadcast(UNIT_POS_Y, 0u32);
168
169        let is_elected_plane = match self {
170            PlaneFlowPartition::MainFlowOnly | PlaneFlowPartition::LoadOnlyFirst(_) => {
171                plane_id == 0
172            }
173            PlaneFlowPartition::LoadOnlyLast(main_flow) => plane_id == main_flow.threshold,
174        };
175
176        is_elected_plane && plane_elect()
177    }
178
179    /// Whether the current plane is a load-only plane.
180    pub fn is_load_plane(self) -> bool {
181        match self {
182            PlaneFlowPartition::MainFlowOnly => false,
183            PlaneFlowPartition::LoadOnlyFirst(load_only) => UNIT_POS_Y < load_only.threshold,
184            PlaneFlowPartition::LoadOnlyLast(main_flow) => UNIT_POS_Y >= main_flow.threshold,
185        }
186    }
187
188    /// Whether this plane is part of the compute planes. Used in specialized
189    /// kernels; `plane_broadcast` keeps the value warp-uniform.
190    pub fn is_compute_plane(self) -> bool {
191        let plane_id = plane_broadcast(UNIT_POS_Y, 0u32);
192
193        match self {
194            PlaneFlowPartition::MainFlowOnly => true,
195            PlaneFlowPartition::LoadOnlyFirst(load_only) => plane_id >= load_only.threshold,
196            PlaneFlowPartition::LoadOnlyLast(main_flow) => plane_id < main_flow.threshold,
197        }
198    }
199}
200
201// ============================================================================
202// Composition helper: combines PlaneFlowPartition::compute_index with a
203// Partitioner's `coordinates` to return the current primitive's (row, col)
204// in the partition grid.
205// ============================================================================
206
207#[cube]
208/// Returns the `(row, col)` of the current compute primitive within the stage,
209/// deriving `compute_index` from `role_rule_config` via [`PlaneFlowPartition`]
210/// and delegating the per-scope math to
211/// [`Partitioner::coordinates`](crate::tile::Partitioner::coordinates).
212pub fn partition_coordinates<P: Partitioner>(
213    #[comptime] role_rule_config: PlaneFlowPartitionRule,
214    #[comptime] plane_dim: u32,
215    #[comptime] num_partitions_col: u32,
216) -> Coords2d {
217    let compute_index = PlaneFlowPartition::new(role_rule_config).compute_index();
218    P::coordinates(compute_index, plane_dim, num_partitions_col)
219}