1use cubecl_core::{
2 cmma::{MatrixIdent, MatrixType},
3 ir::{
4 ElemType, FloatKind, IntKind, UIntKind,
5 dialect::matrix::{ColIndexOp, RowIndexOp},
6 features::{MmaConfig, ScaledMmaConfig},
7 interfaces::TypedExt,
8 prelude::*,
9 },
10 prelude::*,
11};
12use itertools::Itertools;
13use pliron::r#type::TypedHandle;
14
15use cubecl_core::prelude::polyfills::mma::{col_index, row_index};
16
17use crate::{
18 cuda::arch::CudaArchitecture,
19 shared::{
20 Architecture, SupportedMmaCombinations, SupportedScaledMmaCombinations, lowering::LowerOp,
21 },
22 target::Cuda,
23};
24
25#[op_interface_impl]
26impl LowerOp<Cuda> for RowIndexOp {
27 fn lower(&self, scope: &Scope) -> Vec<Value> {
28 let matrix = *self.matrix_ty(scope.ctx()).deref(scope.ctx());
29 let elems_per_reg = 32 / matrix.unpacked_elem_size_bits(scope.ctx());
30 let lane_id = self.lane_id(scope.ctx());
31 let i = self.i(scope.ctx());
32 let out = row_index::expand(scope, lane_id.into(), i.into(), elems_per_reg, matrix.ident);
33 vec![out.value(scope)]
34 }
35}
36
37#[op_interface_impl]
38impl LowerOp<Cuda> for ColIndexOp {
39 fn lower(&self, scope: &Scope) -> Vec<Value> {
40 let matrix = *self.matrix_ty(scope.ctx()).deref(scope.ctx());
41 let elems_per_reg = 32 / matrix.unpacked_elem_size_bits(scope.ctx());
42 let lane_id = self.lane_id(scope.ctx());
43 let i = self.i(scope.ctx());
44 let out = col_index::expand(scope, lane_id.into(), i.into(), elems_per_reg, matrix.ident);
45 vec![out.value(scope)]
46 }
47}
48
49pub fn supported_mma_combinations(arch: &CudaArchitecture) -> SupportedMmaCombinations {
50 if !arch.tensor_cores {
51 return vec![];
52 }
53 let mut result: SupportedMmaCombinations = vec![];
54 if arch.get_version() >= 80 {
58 result.extend([
59 MmaConfig {
60 a_type: ElemType::Float(FloatKind::F16), b_type: ElemType::Float(FloatKind::F16), cd_type: ElemType::Float(FloatKind::F32), m: 16,
64 n: 8,
65 k: 16,
66 },
67 MmaConfig {
68 a_type: ElemType::Float(FloatKind::BF16),
69 b_type: ElemType::Float(FloatKind::BF16),
70 cd_type: ElemType::Float(FloatKind::F32),
71 m: 16,
72 n: 8,
73 k: 16,
74 },
75 MmaConfig {
76 a_type: ElemType::Float(FloatKind::TF32),
77 b_type: ElemType::Float(FloatKind::TF32),
78 cd_type: ElemType::Float(FloatKind::F32),
79 m: 16,
80 n: 8,
81 k: 8,
82 },
83 MmaConfig {
84 a_type: ElemType::Int(IntKind::I8),
85 b_type: ElemType::Int(IntKind::I8),
86 cd_type: ElemType::Int(IntKind::I32),
87 m: 16,
88 n: 8,
89 k: 32,
90 },
91 MmaConfig {
92 a_type: ElemType::UInt(UIntKind::U8),
93 b_type: ElemType::UInt(UIntKind::U8),
94 cd_type: ElemType::Int(IntKind::I32),
95 m: 16,
96 n: 8,
97 k: 32,
98 },
99 MmaConfig {
100 a_type: ElemType::Int(IntKind::I8),
101 b_type: ElemType::UInt(UIntKind::U8),
102 cd_type: ElemType::Int(IntKind::I32),
103 m: 16,
104 n: 8,
105 k: 32,
106 },
107 MmaConfig {
108 a_type: ElemType::UInt(UIntKind::U8),
109 b_type: ElemType::Int(IntKind::I8),
110 cd_type: ElemType::Int(IntKind::I32),
111 m: 16,
112 n: 8,
113 k: 32,
114 },
115 ]);
117 }
118 if arch.get_version() >= 89 {
119 let f8f6f4_types = [
120 FloatKind::E4M3,
121 FloatKind::E5M2,
122 FloatKind::E3M2,
123 FloatKind::E2M3,
124 FloatKind::E2M1,
125 ];
126 let combinations = f8f6f4_types.iter().cartesian_product(f8f6f4_types.iter());
127 result.extend(combinations.map(|(t1, t2)| MmaConfig {
128 a_type: ElemType::Float(*t1),
129 b_type: ElemType::Float(*t2),
130 cd_type: ElemType::Float(FloatKind::F32),
131 m: 16,
132 n: 8,
133 k: 32,
134 }));
135 }
136 if arch.get_version() >= 70 && arch.get_version() < 80 {
138 result.push(MmaConfig {
139 a_type: ElemType::Float(FloatKind::F16),
140 b_type: ElemType::Float(FloatKind::F16),
141 cd_type: ElemType::Float(FloatKind::F32),
142 m: 16,
143 n: 8,
144 k: 8,
145 });
146 }
147 result
148}
149
150pub fn supported_scaled_mma_combinations(
151 arch: &CudaArchitecture,
152) -> SupportedScaledMmaCombinations {
153 if !arch.tensor_cores {
154 return vec![];
155 }
156 let mut result: SupportedScaledMmaCombinations = vec![];
157 if arch.get_version() >= 120 && arch.get_version() < 130 {
159 let f8f6f4_types = [
160 FloatKind::E4M3,
161 FloatKind::E5M2,
162 FloatKind::E3M2,
163 FloatKind::E2M3,
164 FloatKind::E2M1,
165 ];
166 let combinations = f8f6f4_types
167 .iter()
168 .flat_map(|t1| f8f6f4_types.iter().map(move |t2| (t1, t2)));
169
170 result.extend(combinations.map(|(t1, t2)| ScaledMmaConfig {
171 a_type: ElemType::Float(*t1),
172 b_type: ElemType::Float(*t2),
173 cd_type: ElemType::Float(FloatKind::F32),
174 scales_type: ElemType::Float(FloatKind::UE8M0),
175 m: 16,
176 n: 8,
177 k: 32,
178 scales_factor: 1,
179 }));
180
181 result.extend([
182 ScaledMmaConfig {
183 a_type: ElemType::Float(FloatKind::E2M1x2),
184 b_type: ElemType::Float(FloatKind::E2M1x2),
185 cd_type: ElemType::Float(FloatKind::F32),
186 scales_type: ElemType::Float(FloatKind::UE8M0),
187 m: 16,
188 n: 8,
189 k: 64,
190 scales_factor: 2,
191 },
192 ScaledMmaConfig {
194 a_type: ElemType::Float(FloatKind::E2M1x2),
195 b_type: ElemType::Float(FloatKind::E2M1x2),
196 cd_type: ElemType::Float(FloatKind::F32),
197 scales_type: ElemType::Float(FloatKind::E4M3),
198 m: 16,
199 n: 8,
200 k: 64,
201 scales_factor: 4,
202 },
203 ]);
204 }
205 result
206}
207
208pub fn contiguous_elements_cuda(
209 ctx: &Context,
210 ident: MatrixIdent,
211 matrix: TypedHandle<MatrixType>,
212) -> usize {
213 let elem = matrix.deref(ctx).elem_ty;
214 match ident {
215 MatrixIdent::A | MatrixIdent::B => 32 / elem.size_bits(ctx),
216 MatrixIdent::Accumulator => 2,
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::supported_mma_combinations;
223 use crate::cuda::arch::CudaArchitecture;
224
225 #[test]
228 fn a_turing_die_without_tensor_cores_offers_no_mma() {
229 let turing = |name: &str| CudaArchitecture {
230 version: 75,
231 tensor_cores: CudaArchitecture::has_tensor_cores(75, name),
232 };
233
234 assert!(supported_mma_combinations(&turing("NVIDIA GeForce GTX 1660 SUPER")).is_empty());
235 assert!(!supported_mma_combinations(&turing("NVIDIA GeForce RTX 2060")).is_empty());
236 }
237}