1use super::WMMA_MINIMUM_VERSION;
2use crate::{
3 Dialect,
4 cuda::{
5 CudaDialect,
6 arch::CudaArchitecture,
7 ptx::{comma_separated, ldmatrix_call, stmatrix_call},
8 },
9 shared::{
10 Architecture, Component, DialectWmmaCompiler, Elem, Flags, FmtLeft, FragmentIdent,
11 FragmentLayout, FragmentType, Item, ManualMma, SupportedMmaCombinations,
12 SupportedScaledMmaCombinations, Value, WmmaInstruction,
13 },
14};
15use cubecl_core::ir::{
16 self as gpu, ConstantValue, MatrixIdent, MatrixType,
17 features::{MmaConfig, ScaledMmaConfig},
18};
19use itertools::Itertools;
20use std::fmt::Display;
21
22#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
23pub struct PtxWmmaCompiler {}
24
25impl DialectWmmaCompiler<CudaDialect<Self>> for PtxWmmaCompiler {
26 fn compile_wmma_includes(
27 f: &mut std::fmt::Formatter<'_>,
28 flags: &Flags<CudaDialect<Self>>,
29 ) -> std::fmt::Result {
30 if flags.elem_tf32 {
32 f.write_str("#include <mma.h>\n")?;
33 }
34 Ok(())
35 }
36
37 fn compile_wmma_fragment_declaration(
38 f: &mut std::fmt::Formatter<'_>,
39 val: &Value<CudaDialect<Self>>,
40 ty: &Item<CudaDialect<Self>>,
41 ) -> std::fmt::Result {
42 let frag = match ty {
43 Item::Fragment(frag) => frag,
44 _ => panic!("load instruction expects a WmmaFragment"),
45 };
46 let reg_count = get_fragment_register_total_count(frag);
47 let ty = match frag.elem {
48 Elem::U8 | Elem::I8 | Elem::F16 | Elem::BF16 | Elem::TF32 => "unsigned int",
49 Elem::F32 => "float",
50 Elem::F64 => "double",
51 _ => panic!("unsupported type"),
52 };
53 writeln!(f, "{ty} {val}_store[{reg_count}];")
54 }
55
56 fn compile_wmma_instruction(
57 f: &mut std::fmt::Formatter<'_>,
58 instruction: &WmmaInstruction<CudaDialect<Self>>,
59 ) -> std::fmt::Result {
60 match instruction {
61 WmmaInstruction::Fill { frag, value } => {
62 let frag_ty = match frag.item() {
63 Item::Fragment(frag) => frag,
64 _ => panic!("load instruction expects a WmmaFragment"),
65 };
66 let reg_count = get_fragment_register_total_count(&frag_ty);
67 write!(
68 f,
69 "// fill
70for (uint i = 0; i < uint({reg_count}); ++i) {{
71 {frag}[i] = {value};
72}}
73 "
74 )
75 }
76 WmmaInstruction::Load {
77 frag,
78 ptr,
79 stride,
80 layout,
81 } => {
82 let frag_ty = match frag.item() {
83 Item::Fragment(frag) => frag,
84 _ => panic!("load instruction expects a WmmaFragment"),
85 };
86 let layout = if frag_ty.layout.is_some() {
91 get_fragment_layout_qualifier(frag)
92 } else if let Some(layout) = layout {
93 get_qualifier_from_layout(layout)
94 } else {
95 panic!("unknown matrix layout for wmma load instruction");
96 };
97 let ty = get_type_qualifier(ptr);
99 let matrix = match frag_ty.ident {
100 FragmentIdent::A => "a",
101 FragmentIdent::B => "b",
102 FragmentIdent::Accumulator => "c",
103 FragmentIdent::_Dialect(_) => unreachable!(),
104 };
105 let value_ptr_ty = ptr.item().value_ptr();
106 let opcode = match frag_ty.elem {
107 Elem::U8 | Elem::I8 | Elem::F16 | Elem::BF16 | Elem::F32 | Elem::TF32 => {
108 format!(
109 "wmma.load.{matrix}.sync.aligned.{layout}.m{}n{}k{}.{ty}",
110 frag_ty.m, frag_ty.n, frag_ty.k,
111 )
112 }
113 other => panic!("{other} fragment type not supported"),
114 };
115 let mut reg_count = 0;
117 let (regs_decl, out_constraints) =
118 get_value_regs_decl_constraints(frag, true, &mut reg_count);
119 let buffer_reg = format_reg_and_inc(&mut reg_count);
120 let (stride_reg, stride_constraint) =
121 get_value_regs_decl_constraints(stride, false, &mut reg_count);
122 let tmp_ptr = Value::tmp(value_ptr_ty);
123 let tmp_ptr_left = tmp_ptr.fmt_left();
124 write!(
125 f,
126 r#"// load
127{tmp_ptr_left} = ({value_ptr_ty}){ptr};
128asm volatile(
129 "{opcode} "
130 "{{{regs_decl}}}, [{buffer_reg}], {stride_reg};\n"
131 : {out_constraints}
132 : "l"({tmp_ptr}){stride_constraint}
133);
134"#
135 )
136 }
137 WmmaInstruction::LdMatrix {
138 output,
139 ptr,
140 factor,
141 transpose,
142 } => f.write_str(&ldmatrix_call(output, ptr, factor, transpose)),
143 WmmaInstruction::StMatrix {
144 registers,
145 ptr,
146 factor,
147 transpose,
148 } => f.write_str(&stmatrix_call(registers, ptr, factor, transpose)),
149 WmmaInstruction::Execute {
150 frag_a,
151 frag_b,
152 frag_c,
153 frag_d,
154 ..
155 } => {
156 let frag_a_ty = match frag_a.item() {
157 Item::Fragment(frag) => frag,
158 _ => panic!("value should be WmmaFragment"),
159 };
160 let layout_a = get_fragment_layout_qualifier(frag_a);
161 let layout_b = get_fragment_layout_qualifier(frag_b);
162 let type_c = get_type_qualifier(frag_c);
163 let type_d = get_type_qualifier(frag_d);
164 let opcode = match frag_a.elem() {
165 Elem::U8 | Elem::I8 | Elem::F16 | Elem::F32 => format!(
166 "wmma.mma.sync.aligned.m{}n{}k{}.{layout_a}.{layout_b}.{type_d}.{type_c}",
167 frag_a_ty.m, frag_a_ty.n, frag_a_ty.k,
168 ),
169 Elem::BF16 => format!(
170 "wmma.mma.sync.aligned.{layout_a}.{layout_b}.m{}n{}k{}.f32.bf16.bf16.f32",
171 frag_a_ty.m, frag_a_ty.n, frag_a_ty.k,
172 ),
173 Elem::TF32 => format!(
174 "wmma.mma.sync.aligned.{layout_a}.{layout_b}.m{}n{}k{}.f32.tf32.tf32.f32",
175 frag_a_ty.m, frag_a_ty.n, frag_a_ty.k,
176 ),
177 other => panic!("{other} fragment type not supported"),
178 };
179 let mut reg_count = 0;
180 let (regs_decl_d, out_constraints_d) =
182 get_value_regs_decl_constraints(frag_d, true, &mut reg_count);
183 let (regs_decl_a, in_constraints_a) =
184 get_value_regs_decl_constraints(frag_a, false, &mut reg_count);
185 let (regs_decl_b, in_constraints_b) =
186 get_value_regs_decl_constraints(frag_b, false, &mut reg_count);
187 let (regs_decl_c, in_constraints_c) =
188 get_value_regs_decl_constraints(frag_c, false, &mut reg_count);
189 write!(
190 f,
191 r#"// execute
192asm volatile(
193 "{opcode} "
194 "{{{regs_decl_d}}}, "
195 "{{{regs_decl_a}}}, "
196 "{{{regs_decl_b}}}, "
197 "{{{regs_decl_c}}};\n"
198 : {out_constraints_d}
199 : {in_constraints_a}, {in_constraints_b}, {in_constraints_c}
200);
201"#
202 )
203 }
204 WmmaInstruction::ExecuteManual {
205 shape,
206 frag_a,
207 frag_b,
208 frag_c,
209 frag_d,
210 } => {
211 Self::compile_manual_mma(f, ManualMma::new(*shape, frag_a, frag_b, frag_c, frag_d))
212 }
213 WmmaInstruction::ExecuteScaled {
214 shape,
215 frag_a,
216 frag_b,
217 frag_c,
218 frag_d,
219
220 scales_a,
221 scales_b,
222 scales_factor,
223 } => Self::compile_scaled_mma(
224 f,
225 ManualMma::new(*shape, frag_a, frag_b, frag_c, frag_d),
226 *scales_a,
227 *scales_b,
228 *scales_factor,
229 ),
230 WmmaInstruction::Store {
231 frag,
232 stride,
233 destination,
234 layout,
235 } => {
236 let frag_acc = match frag.item() {
237 Item::Fragment(frag) => frag,
238 _ => panic!("value should be WmmaFragment"),
239 };
240 let layout = match layout {
242 FragmentLayout::ColMajor => "col",
243 FragmentLayout::RowMajor => "row",
244 FragmentLayout::_Dialect(..) => unreachable!(),
245 };
246 let opcode = match frag.elem() {
247 Elem::F16 | Elem::BF16 => format!(
248 "wmma.store.d.sync.aligned.{layout}.m{}n{}k{}.f16",
252 frag_acc.m, frag_acc.n, frag_acc.k,
253 ),
254 Elem::TF32 | Elem::F32 => format!(
255 "wmma.store.d.sync.aligned.{layout}.m{}n{}k{}.f32",
257 frag_acc.m, frag_acc.n, frag_acc.k,
258 ),
259 Elem::I32 => format!(
260 "wmma.store.d.sync.aligned.{layout}.m{}n{}k{}.s32",
262 frag_acc.m, frag_acc.n, frag_acc.k,
263 ),
264 other => panic!("{other} fragment type not supported"),
265 };
266 let mut reg_count = 0;
268 let buffer_reg = format_reg_and_inc(&mut reg_count);
269 let (stride_reg, stride_constraint) =
272 get_value_regs_decl_constraints(stride, false, &mut reg_count);
273 let (regs_decl, in_constraints) =
275 get_value_regs_decl_constraints(frag, false, &mut reg_count);
276 write!(
277 f,
278 r#"// store
279asm volatile(
280 "{opcode} "
281 "[{buffer_reg}], {{{regs_decl}}}, {stride_reg};\n"
282 :
283 : "l"({destination}),
284 {in_constraints}{stride_constraint}
285);
286"#
287 )
288 }
289 WmmaInstruction::Cast { input, output } => {
290 let frag = match input.item() {
291 Item::Fragment(frag) => frag,
292 _ => panic!("value should be WmmaFragment"),
293 };
294 let reg_count = get_fragment_register_total_count(&frag);
295 match output.elem() {
296 Elem::F16 => {
297 write!(
298 f,
299 "// cast
300for (int i = 0; i < {reg_count}; ++i) {{
301 __half h_lo = __float2half_rn({input}[2*i + 0]);
302 __half h_hi = __float2half_rn({input}[2*i + 1]);
303 __half2 h2 = __halves2half2(h_lo, h_hi);
304 {output}[i] = *reinterpret_cast<unsigned int*>(&h2);
305}}
306"
307 )
308 }
309 Elem::BF16 => {
310 write!(
311 f,
312 "// cast
313for (int i = 0; i < {reg_count}; ++i) {{
314 __nv_bfloat16 b_lo = __float2bfloat16({input}[2*i + 0]);
315 __nv_bfloat16 b_hi = __float2bfloat16({input}[2*i + 1]);
316 __nv_bfloat162 bf2 = __halves2bfloat162(b_lo, b_hi);
317 {output}[i] = *reinterpret_cast<unsigned int*>(&bf2);
318}}
319"
320 )
321 }
322 other => panic!("casting fragment to {other} not supported"),
323 }
324 }
325 }
326 }
327
328 fn compile_manual_mma(
329 f: &mut std::fmt::Formatter<'_>,
330 mma: ManualMma<CudaDialect<Self>>,
331 ) -> std::fmt::Result {
332 compile_manual_mma(f, mma)
333 }
334
335 fn compile_scaled_mma(
336 f: &mut std::fmt::Formatter<'_>,
337 mma: ManualMma<CudaDialect<Self>>,
338 scales_a: Value<CudaDialect<Self>>,
339 scales_b: Value<CudaDialect<Self>>,
340 scales_factor: u32,
341 ) -> std::fmt::Result {
342 compile_scaled_mma(f, mma, scales_a, scales_b, scales_factor)
343 }
344
345 fn supported_wmma_combinations(arch: &CudaArchitecture) -> SupportedMmaCombinations {
346 let mut result: SupportedMmaCombinations = vec![];
347 if arch.get_version() >= WMMA_MINIMUM_VERSION {
348 let types = vec![
350 (
351 gpu::ElemType::Float(gpu::FloatKind::F16), gpu::ElemType::Float(gpu::FloatKind::F16), gpu::ElemType::Float(gpu::FloatKind::F16), ),
355 (
356 gpu::ElemType::Float(gpu::FloatKind::F16),
357 gpu::ElemType::Float(gpu::FloatKind::F16),
358 gpu::ElemType::Float(gpu::FloatKind::F32),
359 ),
360 (
361 gpu::ElemType::Float(gpu::FloatKind::BF16),
362 gpu::ElemType::Float(gpu::FloatKind::BF16),
363 gpu::ElemType::Float(gpu::FloatKind::F32),
364 ),
365 ];
366 let combinations: SupportedMmaCombinations = types
367 .into_iter()
368 .map(|(a, b, cd)| MmaConfig {
369 a_type: a.into(),
370 b_type: b.into(),
371 cd_type: cd.into(),
372 m: 16,
373 n: 16,
374 k: 16,
375 })
376 .collect();
377 result.extend(combinations);
378 if arch.get_version() >= 72 {
379 result.extend([
380 MmaConfig {
381 a_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
382 b_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
383 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
384 m: 16,
385 n: 16,
386 k: 16,
387 },
388 MmaConfig {
389 a_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
390 b_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
391 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
392 m: 16,
393 n: 16,
394 k: 16,
395 },
396 ]);
397 }
398 if arch.get_version() >= 80 {
399 result.push(MmaConfig {
400 a_type: gpu::ElemType::Float(gpu::FloatKind::TF32).into(),
401 b_type: gpu::ElemType::Float(gpu::FloatKind::TF32).into(),
402 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
403 m: 16,
404 n: 16,
405 k: 8,
406 });
407 }
408 }
409 result
410 }
411
412 fn supported_mma_combinations(arch: &CudaArchitecture) -> SupportedMmaCombinations {
413 supported_mma_combinations(arch)
414 }
415
416 fn supported_scaled_mma_combinations(
417 arch: &CudaArchitecture,
418 ) -> SupportedScaledMmaCombinations {
419 supported_scaled_mma_combinations(arch)
420 }
421}
422
423fn get_fragment_register_total_count(frag: &FragmentType<CudaDialect<PtxWmmaCompiler>>) -> u32 {
424 let FragmentType {
425 ident,
426 m,
427 n,
428 k,
429 elem,
430 ..
431 } = frag;
432 let elements = match ident {
433 FragmentIdent::A => m * k,
434 FragmentIdent::B => k * n,
435 FragmentIdent::Accumulator => m * n,
436 _ => unreachable!(),
437 };
438 let bits_per_elem = elem.size_bits() as u32;
439 let lanes_per_reg = 32 / bits_per_elem;
441 let threads_per_frag = match ident {
445 FragmentIdent::Accumulator => 32,
446 FragmentIdent::A | FragmentIdent::B => {
447 if frag.elem == Elem::TF32 {
448 32
449 } else {
450 16
451 }
452 }
453 _ => unreachable!(),
454 };
455
456 elements / (lanes_per_reg * threads_per_frag)
457}
458
459fn get_type_qualifier(val: &Value<CudaDialect<PtxWmmaCompiler>>) -> String {
460 match val.elem() {
461 Elem::U8 => "u8",
462 Elem::I8 => "s8",
463 Elem::F16 => "f16",
464 Elem::BF16 => "bf16",
465 Elem::F32 => "f32",
466 Elem::TF32 => "tf32",
467 Elem::I32 => "s32",
468 Elem::F64 => "f64",
469 _ => panic!("unsupported WMMA fragment type"),
470 }
471 .to_string()
472}
473
474fn get_fragment_layout_qualifier(val: &Value<CudaDialect<PtxWmmaCompiler>>) -> String {
475 let frag = match val.item() {
476 Item::Fragment(frag) => frag,
477 _ => panic!("value should be WmmaFragment"),
478 };
479 match frag.layout {
480 Some(layout) => get_qualifier_from_layout(&layout),
481 None => "".to_string(),
482 }
483}
484
485fn get_qualifier_from_layout(layout: &FragmentLayout<CudaDialect<PtxWmmaCompiler>>) -> String {
486 match layout {
487 FragmentLayout::ColMajor => "col",
488 FragmentLayout::RowMajor => "row",
489 FragmentLayout::_Dialect(..) => unreachable!(),
490 }
491 .to_string()
492}
493
494fn get_value_regs_decl_constraints(
495 val: &Value<CudaDialect<PtxWmmaCompiler>>,
496 output: bool,
497 reg_count: &mut u8,
498) -> (String, String) {
499 match val {
500 _ if let Item::Fragment(frag) = val.item() => {
501 let reg_total_count = get_fragment_register_total_count(&frag);
502 let reg_decl = (0..reg_total_count)
503 .map(|_| format_reg_and_inc(reg_count))
504 .collect::<Vec<_>>()
505 .join(",");
506 let frag_elem = frag.elem;
507 let modifier = format!(
508 "{}{}",
509 if output { "=" } else { "" },
510 match frag_elem {
511 Elem::F32 => "f",
512 Elem::F64 => "d",
513 _ => "r",
514 },
515 );
516 let constraints = (0..reg_total_count)
517 .map(|i| format!("\"{modifier}\"({val}[{i}])"))
518 .collect::<Vec<_>>()
519 .join(", ");
520 (reg_decl, constraints)
521 }
522 Value::Constant(number, ..) => match number {
523 ConstantValue::UInt(val, ..) => (val.to_string(), "".to_string()),
524 _ => panic!("value should be an unsigned integer"),
525 },
526 _ => (format_reg_and_inc(reg_count), format!(r#", "r"({val})"#)),
527 }
528}
529
530fn format_reg_and_inc(count: &mut u8) -> String {
531 let res = format!("%{count}");
532 *count += 1;
533 res
534}
535
536fn as_ty_idx<D: Dialect>(val: &Value<D>, idx: impl Display, ty: impl Display) -> String {
537 format!("reinterpret_cast<{ty}*>({})[{idx}]", val.fmt_ptr())
538}
539
540fn as_const_ty_idx<D: Dialect>(val: &Value<D>, idx: impl Display, ty: impl Display) -> String {
541 format!("reinterpret_cast<const {ty}*>({})[{idx}]", val.fmt_ptr())
542}
543
544pub(super) fn compile_manual_mma<D: Dialect>(
545 f: &mut core::fmt::Formatter<'_>,
546 mma: ManualMma<D>,
547) -> std::fmt::Result {
548 let ManualMma {
549 shape,
550 frag_a,
551 frag_b,
552 frag_c,
553 frag_d,
554 } = mma;
555
556 let a_elem = frag_a.elem().unpacked();
557 let b_elem = frag_b.elem().unpacked();
558 let cd_elem = frag_c.elem().unpacked();
559
560 let ab_ty = match a_elem {
561 Elem::F32 => &format!("{}", Elem::<D>::F32),
562 _ => &format!("{}", Elem::<D>::U32),
563 };
564 let cd_ty = match cd_elem {
565 Elem::F32 => &format!("{}", Elem::<D>::F32),
566 _ => &format!("{}", Elem::<D>::U32),
567 };
568
569 let a_elems = shape.num_elems(FragmentIdent::<D>::A) / 32;
570 let b_elems = shape.num_elems(FragmentIdent::<D>::B) / 32;
571 let cd_elems = shape.num_elems(FragmentIdent::<D>::Accumulator) / 32;
572
573 let a_regs = a_elems as usize / (32 / frag_a.elem().unpacked().size_bits());
574 let b_regs = b_elems as usize / (32 / frag_b.elem().unpacked().size_bits());
575 let cd_regs = cd_elems as usize / (32 / frag_c.elem().unpacked().size_bits());
576
577 let frag_a = (0..a_regs).map(|i| as_const_ty_idx(frag_a, i, ab_ty));
578 let frag_b = (0..b_regs).map(|i| as_const_ty_idx(frag_b, i, ab_ty));
579 let frag_c = (0..cd_regs).map(|i| as_const_ty_idx(frag_c, i, cd_ty));
580 let frag_d = (0..cd_regs).map(|i| as_ty_idx(frag_d, i, cd_ty));
581
582 let args = comma_separated(frag_a.chain(frag_b).chain(frag_c).chain(frag_d));
583 write!(
584 f,
585 "__mma_m16n8k{}_{}_{}_{}({args});",
586 shape.k, a_elem, b_elem, cd_elem
587 )
588}
589
590pub(super) fn compile_scaled_mma<D: Dialect>(
591 f: &mut core::fmt::Formatter<'_>,
592 mma: ManualMma<D>,
593 scales_a: Value<D>,
594 scales_b: Value<D>,
595 scales_factor: u32,
596) -> std::fmt::Result {
597 let ManualMma {
598 shape,
599 frag_a,
600 frag_b,
601 frag_c,
602 frag_d,
603 } = mma;
604
605 let a_elem = frag_a.elem().unpacked();
606 let b_elem = frag_b.elem().unpacked();
607 let cd_elem = frag_c.elem().unpacked();
608
609 let ab_ty = &format!("{}", Elem::<D>::U32);
610 let cd_ty = &format!("{}", Elem::<D>::F32);
611
612 let a_elems = shape.num_elems(FragmentIdent::<D>::A) / 32;
613 let b_elems = shape.num_elems(FragmentIdent::<D>::B) / 32;
614 let cd_elems = shape.num_elems(FragmentIdent::<D>::Accumulator) / 32;
615
616 let a_regs = a_elems as usize / (32 / frag_a.elem().unpacked().size_bits());
617 let b_regs = b_elems as usize / (32 / frag_b.elem().unpacked().size_bits());
618 let cd_regs = cd_elems as usize / (32 / frag_c.elem().unpacked().size_bits());
619
620 let frag_a = (0..a_regs).map(|i| as_const_ty_idx(frag_a, i, ab_ty));
621 let frag_b = (0..b_regs).map(|i| as_const_ty_idx(frag_b, i, ab_ty));
622 let frag_c = (0..cd_regs).map(|i| as_const_ty_idx(frag_c, i, cd_ty));
623 let frag_d = (0..cd_regs).map(|i| as_ty_idx(frag_d, i, cd_ty));
624
625 let scales_a = scales_a.ensure_lvalue(f)?;
626 let scales_b = scales_b.ensure_lvalue(f)?;
627
628 let fragments = comma_separated(frag_a.chain(frag_b).chain(frag_c).chain(frag_d));
629 write!(
630 f,
631 "__mma_scaled_{scales_factor}x_m16n8k{}_{}_{}_{}({fragments}, reinterpret_cast<const uint32&>({scales_a}), reinterpret_cast<const uint32&>({scales_b}));",
632 shape.k, a_elem, b_elem, cd_elem
633 )
634}
635
636pub(super) fn supported_mma_combinations(arch: &CudaArchitecture) -> SupportedMmaCombinations {
637 let mut result: SupportedMmaCombinations = vec![];
638 if arch.get_version() >= 80 {
642 result.extend([
643 MmaConfig {
644 a_type: gpu::ElemType::Float(gpu::FloatKind::F16).into(), b_type: gpu::ElemType::Float(gpu::FloatKind::F16).into(), cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(), m: 16,
648 n: 8,
649 k: 16,
650 },
651 MmaConfig {
652 a_type: gpu::ElemType::Float(gpu::FloatKind::BF16).into(),
653 b_type: gpu::ElemType::Float(gpu::FloatKind::BF16).into(),
654 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
655 m: 16,
656 n: 8,
657 k: 16,
658 },
659 MmaConfig {
660 a_type: gpu::ElemType::Float(gpu::FloatKind::TF32).into(),
661 b_type: gpu::ElemType::Float(gpu::FloatKind::TF32).into(),
662 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
663 m: 16,
664 n: 8,
665 k: 8,
666 },
667 MmaConfig {
668 a_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
669 b_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
670 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
671 m: 16,
672 n: 8,
673 k: 32,
674 },
675 MmaConfig {
676 a_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
677 b_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
678 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
679 m: 16,
680 n: 8,
681 k: 32,
682 },
683 MmaConfig {
684 a_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
685 b_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
686 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
687 m: 16,
688 n: 8,
689 k: 32,
690 },
691 MmaConfig {
692 a_type: gpu::ElemType::UInt(gpu::UIntKind::U8).into(),
693 b_type: gpu::ElemType::Int(gpu::IntKind::I8).into(),
694 cd_type: gpu::ElemType::Int(gpu::IntKind::I32).into(),
695 m: 16,
696 n: 8,
697 k: 32,
698 },
699 ]);
701 }
702 if arch.get_version() >= 89 {
703 let f8f6f4_types = [
704 gpu::FloatKind::E4M3,
705 gpu::FloatKind::E5M2,
706 gpu::FloatKind::E3M2,
707 gpu::FloatKind::E2M3,
708 gpu::FloatKind::E2M1,
709 ];
710 let combinations = f8f6f4_types.iter().cartesian_product(f8f6f4_types.iter());
711 result.extend(combinations.map(|(t1, t2)| MmaConfig {
712 a_type: gpu::ElemType::Float(*t1).into(),
713 b_type: gpu::ElemType::Float(*t2).into(),
714 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
715 m: 16,
716 n: 8,
717 k: 32,
718 }));
719 }
720 if arch.get_version() >= 70 && arch.get_version() < 80 {
722 result.push(MmaConfig {
723 a_type: gpu::ElemType::Float(gpu::FloatKind::F16).into(),
724 b_type: gpu::ElemType::Float(gpu::FloatKind::F16).into(),
725 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
726 m: 16,
727 n: 8,
728 k: 8,
729 });
730 }
731 result
732}
733
734pub(super) fn supported_scaled_mma_combinations(
735 arch: &CudaArchitecture,
736) -> SupportedScaledMmaCombinations {
737 let mut result: SupportedScaledMmaCombinations = vec![];
738 if arch.get_version() >= 120 && arch.get_version() < 130 {
740 let f8f6f4_types = [
741 gpu::FloatKind::E4M3,
742 gpu::FloatKind::E5M2,
743 gpu::FloatKind::E3M2,
744 gpu::FloatKind::E2M3,
745 gpu::FloatKind::E2M1,
746 ];
747 let combinations = f8f6f4_types
748 .iter()
749 .flat_map(|t1| f8f6f4_types.iter().map(move |t2| (t1, t2)));
750
751 result.extend(combinations.map(|(t1, t2)| ScaledMmaConfig {
752 a_type: gpu::ElemType::Float(*t1).into(),
753 b_type: gpu::ElemType::Float(*t2).into(),
754 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
755 scales_type: gpu::ElemType::Float(gpu::FloatKind::UE8M0).into(),
756 m: 16,
757 n: 8,
758 k: 32,
759 scales_factor: 1,
760 }));
761
762 result.extend([
763 ScaledMmaConfig {
764 a_type: gpu::StorageType::Packed(gpu::ElemType::Float(gpu::FloatKind::E2M1), 2),
765 b_type: gpu::StorageType::Packed(gpu::ElemType::Float(gpu::FloatKind::E2M1), 2),
766 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
767 scales_type: gpu::ElemType::Float(gpu::FloatKind::UE8M0).into(),
768 m: 16,
769 n: 8,
770 k: 64,
771 scales_factor: 2,
772 },
773 ScaledMmaConfig {
775 a_type: gpu::StorageType::Packed(gpu::ElemType::Float(gpu::FloatKind::E2M1), 2),
776 b_type: gpu::StorageType::Packed(gpu::ElemType::Float(gpu::FloatKind::E2M1), 2),
777 cd_type: gpu::ElemType::Float(gpu::FloatKind::F32).into(),
778 scales_type: gpu::ElemType::Float(gpu::FloatKind::E4M3).into(),
779 m: 16,
780 n: 8,
781 k: 64,
782 scales_factor: 4,
783 },
784 ]);
785 }
786 result
787}
788
789pub fn contiguous_elements_cuda(ident: MatrixIdent, matrix: MatrixType) -> usize {
790 match ident {
791 MatrixIdent::A | MatrixIdent::B => 32 / matrix.storage.size_bits(),
792 MatrixIdent::Accumulator => 2,
793 }
794}