1use cubecl_core::{
2 cmma::{MatrixIdent, MatrixLayout, MatrixShape},
3 ir::{
4 DeviceProperties,
5 features::{MmaConfig, ScaledMmaConfig},
6 },
7};
8
9pub type SupportedMmaCombinations = Vec<MmaConfig>;
10pub type SupportedScaledMmaCombinations = Vec<ScaledMmaConfig>;
11
12pub trait Architecture {
13 fn warp_size(&self) -> u32;
14 fn is_wmma_capable(&self) -> bool;
15 fn is_mfma_capable(&self) -> bool;
16 fn get_version(&self) -> u32 {
17 0
18 }
19}
20
21pub fn register_wmma_features(
22 supported_combinations: SupportedMmaCombinations,
23 properties: &mut DeviceProperties,
24) {
25 for config in supported_combinations {
26 properties.features.matmul.cmma.insert(config);
27 }
28}
29
30pub fn register_mma_features(
31 supported_combinations: SupportedMmaCombinations,
32 properties: &mut DeviceProperties,
33) {
34 for config in supported_combinations {
35 properties.features.matmul.mma.insert(config);
36 }
37}
38
39pub fn register_scaled_mma_features(
40 supported_combinations: SupportedScaledMmaCombinations,
41 properties: &mut DeviceProperties,
42) {
43 for config in supported_combinations {
44 properties.features.matmul.scaled_mma.insert(config);
45 }
46}
47
48pub mod wmma_api_base {
49 use cubecl_core::{
50 cmma::{MatrixIdent, MatrixLayout, MatrixType},
51 ir::{
52 dialect::matrix::{CastOp, FillOp, LoadOp, MultiplyAccumulateOp, StoreOp},
53 interfaces::{TypeExt, TypedExt},
54 types::{PointerType, scalar::TFloat32Type},
55 },
56 };
57 use pliron::{
58 context::Context,
59 r#type::{TypeHandle, Typed},
60 value::Value,
61 };
62
63 use crate::shared::{CppValue, ty::TypeExtCPP};
64
65 use super::*;
66
67 pub fn compile_matrix_declaration(ctx: &Context, val: Value, value_ty: TypeHandle) -> String {
68 format!(
69 "{} {id}_store; {} {id} = &{id}_store;",
70 value_ty.to_cpp(ctx),
71 val.get_type(ctx).to_cpp(ctx),
72 id = val.name(ctx),
73 )
74 }
75
76 pub fn compile_matrix(ctx: &Context, ty: &MatrixType, ns: &str) -> String {
77 let elem = match ty.elem_ty.deref(ctx).is::<TFloat32Type>() {
78 true => format!("{ns}::precision::tf32"),
79 false => ty.elem_ty.to_cpp(ctx),
80 };
81 let ident = match ty.ident {
82 MatrixIdent::A => format!("{ns}::matrix_a"),
83 MatrixIdent::B => format!("{ns}::matrix_b"),
84 MatrixIdent::Accumulator => format!("{ns}::accumulator"),
85 };
86 let MatrixShape { m, n, k } = ty.shape;
87 let layout = match (ty.ident, ty.layout) {
89 (MatrixIdent::Accumulator, _) => {
90 return format!("{ns}::fragment<{ident}, {m}, {n}, {k}, {elem}>");
91 }
92 (_, MatrixLayout::ColMajor) => format!("{ns}::col_major"),
93 (_, MatrixLayout::RowMajor) => format!("{ns}::row_major"),
94 (_, MatrixLayout::Undefined) => {
95 panic!("An A or B fragment names the layout of the data it is loaded from.")
96 }
97 };
98 format!("{ns}::fragment<{ident}, {m}, {n}, {k}, {elem}, {layout}>")
99 }
100
101 pub fn fill(ctx: &Context, op: &FillOp, namespace: &str) -> String {
102 let mat = op.matrix(ctx).name(ctx);
103 let value = op.value(ctx).name(ctx);
104 format!("{namespace}::fill_fragment(*{mat}, {value});")
105 }
106
107 pub fn load(ctx: &Context, op: &LoadOp, namespace: &str) -> String {
108 let mat = op.matrix(ctx).name(ctx);
109 let stride = op.stride(ctx).name(ctx);
110 let ptr = as_scalar_ptr(ctx, op.source(ctx));
111 let mat_ty = matrix_ty(ctx, op.matrix(ctx));
112 let layout = match mat_ty.ident {
114 MatrixIdent::A | MatrixIdent::B => String::new(),
115 MatrixIdent::Accumulator => match op.layout(ctx).0 {
116 MatrixLayout::RowMajor => format!(", {namespace}::mem_row_major"),
117 MatrixLayout::ColMajor => format!(", {namespace}::mem_col_major"),
118 _ => String::new(),
119 },
120 };
121 format!("{namespace}::load_matrix_sync(*{mat}, {ptr}, {stride}{layout});")
122 }
123
124 pub fn store(ctx: &Context, op: &StoreOp, namespace: &str) -> String {
125 let mat = op.matrix(ctx).name(ctx);
126 let stride = op.stride(ctx).name(ctx);
127 let destination = as_scalar_ptr(ctx, op.destination(ctx));
128 let mat_ty = matrix_ty(ctx, op.matrix(ctx));
129 let layout = match mat_ty.ident {
131 MatrixIdent::A | MatrixIdent::B => String::new(),
132 MatrixIdent::Accumulator => match op.layout(ctx).0 {
133 MatrixLayout::RowMajor => format!(", {namespace}::mem_row_major"),
134 MatrixLayout::ColMajor => format!(", {namespace}::mem_col_major"),
135 _ => String::new(),
136 },
137 };
138
139 format!("{namespace}::store_matrix_sync({destination}, *{mat}, {stride}{layout});")
140 }
141
142 pub fn execute(ctx: &Context, op: &MultiplyAccumulateOp, namespace: &str) -> String {
143 let mat_a = op.mat_a(ctx).name(ctx);
144 let mat_b = op.mat_b(ctx).name(ctx);
145 let mat_c = op.mat_c(ctx).name(ctx);
146 let mat_d = op.mat_d(ctx).name(ctx);
147
148 format!("{namespace}::mma_sync(*{mat_d}, *{mat_a}, *{mat_b}, *{mat_c});")
149 }
150
151 pub fn cast(ctx: &Context, op: &CastOp) -> String {
152 let input = op.input(ctx).name(ctx);
153 let output = op.output(ctx).name(ctx);
154 let mat_ty = matrix_ty(ctx, op.output(ctx));
155 let out_elem = mat_ty.elem_ty.to_cpp(ctx);
156 format!(
157 "for(int t=0; t<{input}->num_elements; t++) {{ {output}->x[t] = {out_elem}({input}->x[t]); }}"
158 )
159 }
160
161 pub fn as_scalar_ptr(ctx: &Context, value: Value) -> String {
162 let PointerType {
163 inner,
164 address_space,
165 } = value.get_type(ctx).as_ptr(ctx);
166 let new_ty = PointerType::get(ctx, inner.scalar_ty(ctx), address_space).to_handle();
167 format!(
168 "reinterpret_cast<{}>({})",
169 new_ty.to_cpp(ctx),
170 value.name(ctx)
171 )
172 }
173
174 pub fn matrix_ty(ctx: &Context, value: impl Typed) -> MatrixType {
175 let ty = value.unwrap_ptr(ctx).deref(ctx);
176 *ty.downcast_ref::<MatrixType>().unwrap()
177 }
178}
179
180pub fn frag_ident_str(frag: &MatrixIdent) -> &str {
181 match frag {
182 MatrixIdent::A => "a",
183 MatrixIdent::B => "b",
184 MatrixIdent::Accumulator => "c",
185 }
186}
187
188pub fn frag_layout_str(frag: &MatrixLayout) -> &str {
189 match frag {
190 MatrixLayout::ColMajor => "col",
191 MatrixLayout::RowMajor => "row",
192 MatrixLayout::Undefined => "",
193 }
194}