Skip to main content

cubecl_ir/
features.rs

1use crate::{AddressType, ElemType, OpaqueType, SemanticType, Type};
2use alloc::collections::{BTreeMap, BTreeSet};
3
4use crate::EnumSetType;
5
6pub use crate::EnumSet;
7
8/// Features supported by a runtime
9#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
10pub struct Features {
11    /// Plane features supported by this runtime.
12    pub plane: EnumSet<Plane>,
13    /// Clustered launches and intra-cluster operations like cluster shared memory
14    pub cube_cluster: bool,
15    /// Enables changing the type of containers during kernel execution.
16    pub memory_reinterpret: bool,
17    /// Enables explicit alignment. If false, alignment still compiles, but isn't actually applied.
18    pub alignment: bool,
19
20    /// Type support
21    pub types: Types,
22    /// Matrix multiplication features
23    pub matmul: MatmulFeatures,
24
25    /// Whether `copy_async` is supported
26    pub copy_async: bool,
27    /// Whether a [`SyncScope::Device`](crate::dialect::synchronization::SyncScope::Device)
28    /// synchronization is a release and an acquire at device scope, so that one cube's writes to
29    /// storage are visible to another that synchronizes after it. Without it the same
30    /// synchronization is a cube barrier and nothing more, which is all WebGPU's memory model
31    /// promises, so a kernel whose cubes hand each other data must ask before it runs.
32    pub device_memory_scope: bool,
33    /// Tensor Memory Accelerator supported features
34    pub tma: EnumSet<Tma>,
35    /// Whether vectors can be read from / stored to addresses not aligned
36    /// with the `vector_size`
37    pub unaligned_io: bool,
38}
39
40/// Type support for a device
41#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
42pub struct Types {
43    /// Valid address types
44    pub address: BTreeSet<AddressType>,
45    /// Types supported by this runtime, and which usages they support.
46    pub elem: BTreeMap<ElemType, EnumSet<TypeUsage>>,
47    /// Complex-specific capability families supported by this runtime.
48    pub complex: BTreeMap<ElemType, EnumSet<ComplexUsage>>,
49    /// Semantic constructs supported by this runtime.
50    pub semantic: BTreeSet<SemanticType>,
51    /// Opaque types supported by this runtime.
52    pub opaque: BTreeSet<OpaqueType>,
53    /// Supported vector types for atomic ops, only specific vectorizations for specific types are
54    /// supported here. Not all vector types are supported as scalars, i.e. Vulkan on Nvidia only
55    /// supports vectorized `f16`, not scalar. Only use the exact vectorizations registered here.
56    /// These may not be supported everywhere - in practice, f32 vectors are only supported in global
57    /// memory.
58    pub atomic: BTreeMap<Type, EnumSet<AtomicUsage>>,
59}
60
61/// Matrix multiplication-related features
62#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
63pub struct MatmulFeatures {
64    /// The cmma feature enables cooperative matrix-multiply and accumulate operations.
65    pub cmma: BTreeSet<MmaConfig>,
66    /// Cube MMA is like cmma but at the cube level, rather than the plane level.
67    /// Loading may be staged in shared memory by the driver on Vulkan - check
68    /// [`cube_mma_reserved_shared_memory`](crate::HardwareProperties::cube_mma_reserved_shared_memory)
69    /// to take this into account when generating a matmul config.
70    pub cube_mma: BTreeSet<CubeMmaConfig>,
71    /// The manual MMA feature enables cooperative matrix-multiply with manually managed data
72    /// movement
73    pub mma: BTreeSet<MmaConfig>,
74    /// Scaled MMA allows combining matrix multiplication with unscaling quantized values into a single
75    /// instruction. Scales must fit a specific layout and block size.
76    pub scaled_mma: BTreeSet<ScaledMmaConfig>,
77    /// Types supported for ldmatrix, if any
78    pub ldmatrix: BTreeSet<ElemType>,
79    /// Types supported by stmatrix, if any
80    pub stmatrix: BTreeSet<ElemType>,
81    /// Whether tensor addressing is supported for CMMA load/store
82    pub cmma_tensor_addressing: bool,
83}
84
85/// Operations allowed for this type. CMMA is defined separately.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, EnumSetType)]
87pub enum TypeUsage {
88    /// Conversion to/from the type. All types should support this.
89    Conversion,
90    /// All math/logic instructions except dot product
91    Arithmetic,
92    /// Dot product, mainly for BF16 on Intel
93    DotProduct,
94    /// Whether this type can be stored in a buffer
95    Buffer,
96}
97
98/// Complex capability families allowed for a complex element type.
99#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, EnumSetType)]
100pub enum ComplexUsage {
101    /// Arithmetic, negation, conjugation, and real/imaginary extraction.
102    Core,
103    /// Equality and inequality comparisons.
104    Compare,
105    /// Higher-level complex math functions.
106    Math,
107}
108
109impl TypeUsage {
110    pub fn all() -> EnumSet<Self> {
111        EnumSet::all()
112    }
113
114    pub fn no_store() -> EnumSet<Self> {
115        TypeUsage::Conversion | TypeUsage::Arithmetic
116    }
117
118    pub fn maybe_store(storable: bool) -> EnumSet<Self> {
119        if storable {
120            EnumSet::all()
121        } else {
122            Self::no_store()
123        }
124    }
125}
126
127/// Atomic operations allowed for this type.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, EnumSetType)]
129pub enum AtomicUsage {
130    /// Atomic loads and stores
131    LoadStore,
132    /// Atomic exchange
133    Exchange,
134    /// Atomic add/sub
135    Add,
136    /// Atomic min/max
137    MinMax,
138    /// Atomic bitwise and/or/xor
139    Bitwise,
140    /// Atomic compare-and-exchange
141    CompareExchange,
142}
143
144impl AtomicUsage {
145    pub fn all() -> EnumSet<Self> {
146        EnumSet::all()
147    }
148}
149
150/// Supported plane features
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, EnumSetType)]
152pub enum Plane {
153    /// Basic plane-wide operations
154    Ops,
155    /// Plane-wide sync
156    Sync,
157    /// Allows using plane operations with divergent control flow.
158    NonUniformControlFlow,
159}
160
161/// Shape and element types of a valid MMA configuration
162#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164pub struct MmaConfig {
165    /// Element of the A matrix
166    pub a_type: ElemType,
167    /// Element of the B matrix
168    pub b_type: ElemType,
169    /// Element of the C/D matrices
170    pub cd_type: ElemType,
171    /// The size of the matrix on the `m` dimension
172    pub m: u32,
173    /// The size of the matrix on the `n` dimension
174    pub n: u32,
175    /// The size of the matrix on the `k` dimension
176    pub k: u32,
177}
178
179/// Shape and element types of a valid flexible MMA configuration
180/// Only Vulkan for now, but this should also be usable for wgmma/xmma on datacenter CUDA.
181/// Actual matrix size must be multiple of `granularity` and `<= max`.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
183#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
184pub struct CubeMmaConfig {
185    /// Element of the A matrix
186    pub a_type: ElemType,
187    /// Element of the B matrix
188    pub b_type: ElemType,
189    /// Element of the C/D matrices
190    pub cd_type: ElemType,
191    /// The granularity of the matrix on the `m` dimension
192    pub m_granularity: u32,
193    /// The maximum value for `m`
194    pub m_max: u32,
195    /// The size of the matrix on the `n` dimension
196    pub n_granularity: u32,
197    /// The maximum value for `n`
198    pub n_max: u32,
199    /// The size of the matrix on the `k` dimension
200    pub k_granularity: u32,
201    /// The maximum value for `k`
202    pub k_max: u32,
203    /// The number of units that must be in the cube for this configuration to be valid.
204    /// `None` means it's always valid (but might still have an optimal value).
205    pub units_per_block: Option<u32>,
206}
207
208/// Shape and element types of a valid block-scaled MMA configuration
209#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
211pub struct ScaledMmaConfig {
212    /// Element of the A matrix
213    pub a_type: ElemType,
214    /// Element of the B matrix
215    pub b_type: ElemType,
216    /// Element of the C/D matrices
217    pub cd_type: ElemType,
218    /// Element of the blocks scales
219    pub scales_type: ElemType,
220    /// The size of the matrix on the `m` dimension
221    pub m: u32,
222    /// The size of the matrix on the `n` dimension
223    pub n: u32,
224    /// The size of the matrix on the `k` dimension
225    pub k: u32,
226    /// Number of scales per tile row/col.
227    /// A scale factor of 2 means `m x 2` scales for A and `2 x n` for B (in CUDA)
228    /// Scales blocks must be organized along the natural `vector_layout` of the operation
229    pub scales_factor: u32,
230}
231
232/// Atomic features that may be supported by a ``Runtime``.
233#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, EnumSetType)]
234pub enum Tma {
235    /// Base feature set for tensor memory accelerator features. Includes tiling and im2col
236    Base,
237    /// im2colWide encoding for tensor map.
238    Im2colWide,
239    /// Different atomicities for 128-byte swizzle, i.e. 128-byte with 32-byte atomicity.
240    SwizzleAtomicity,
241}
242
243impl Features {
244    /// Get the usages for a type
245    pub fn type_usage(&self, ty: ElemType) -> EnumSet<TypeUsage> {
246        self.types
247            .elem
248            .get(&ty)
249            .cloned()
250            .unwrap_or_else(EnumSet::empty)
251    }
252
253    /// Get the complex capability families for a type.
254    pub fn complex_usage(&self, ty: ElemType) -> EnumSet<ComplexUsage> {
255        self.types
256            .complex
257            .get(&ty)
258            .cloned()
259            .unwrap_or_else(EnumSet::empty)
260    }
261
262    /// Whether a complex type supports the requested capability family.
263    pub fn supports_complex_usage(&self, ty: ElemType, usage: ComplexUsage) -> bool {
264        self.complex_usage(ty).contains(usage)
265    }
266
267    /// Get the usages for an atomic type
268    pub fn atomic_type_usage(&self, ty: Type) -> EnumSet<AtomicUsage> {
269        self.types
270            .atomic
271            .get(&ty)
272            .cloned()
273            .unwrap_or_else(EnumSet::empty)
274    }
275
276    /// Whether the type is supported in any way
277    pub fn supports_type(&self, ty: impl Into<Type>) -> bool {
278        match ty.into() {
279            Type::Semantic(semantic_type) => self.types.semantic.contains(&semantic_type),
280            Type::Opaque(opaque_type) => self.types.opaque.contains(&opaque_type),
281            ty => self.types.elem.contains_key(&ty.elem_type()),
282        }
283    }
284
285    /// Whether the address type is supported in any way
286    pub fn supports_address(&self, ty: impl Into<AddressType>) -> bool {
287        self.types.address.contains(&ty.into())
288    }
289}