1use super::{ConstantValue, ExpandValue};
2use crate::{
3 AddressType, ContextExt, Scope, typed_vec_attr,
4 types::{scalar::*, spirv::ClampMode},
5};
6use alloc::vec::Vec;
7use core::fmt::Display;
8use cubecl_common::{
9 e2m1, e2m1x2, e2m3, e3m2, e4m3, e5m2, flex32,
10 quant::scheme::{QuantValue, ScaleDtype},
11 tf32, ue8m0,
12};
13use cubecl_macros_internal::TypeHash;
14use derive_more::{Display, From};
15use half::{bf16, f16};
16
17pub use internment::Intern;
18use pliron::{
19 builtin::types::{IntegerType, Signedness},
20 context::Context,
21 derive::format,
22 r#type::TypeHandle,
23};
24
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
27#[allow(missing_docs)]
28pub enum FloatKind {
29 E2M1,
31 E2M1x2,
33 E2M3,
36 E3M2,
39 E4M3,
41 E5M2,
43 UE8M0,
45 F16,
46 BF16,
47 Flex32,
48 F32,
49 TF32,
50 F64,
51}
52
53impl FloatKind {
54 pub fn to_type(&self, ctx: &Context) -> TypeHandle {
55 match self {
56 FloatKind::E2M1 => Float4E2M1Type::get(ctx).into(),
57 FloatKind::E2M1x2 => Float4E2M1x2Type::get(ctx).into(),
58 FloatKind::E2M3 => Float6E2M3Type::get(ctx).into(),
59 FloatKind::E3M2 => Float6E3M2Type::get(ctx).into(),
60 FloatKind::E4M3 => Float8E4M3Type::get(ctx).into(),
61 FloatKind::E5M2 => Float8E5M2Type::get(ctx).into(),
62 FloatKind::UE8M0 => Float8E8M0Type::get(ctx).into(),
63 FloatKind::F16 => Float16Type::get(ctx).into(),
64 FloatKind::BF16 => BFloat16Type::get(ctx).into(),
65 FloatKind::Flex32 => FloatFlex32Type::get(ctx).into(),
66 FloatKind::F32 => Float32Type::get(ctx).into(),
67 FloatKind::TF32 => TFloat32Type::get(ctx).into(),
68 FloatKind::F64 => Float64Type::get(ctx).into(),
69 }
70 }
71}
72
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
75#[allow(missing_docs)]
76pub enum IntKind {
77 I8,
78 I16,
79 I32,
80 I64,
81}
82
83impl IntKind {
84 pub fn to_type(&self, ctx: &Context) -> TypeHandle {
85 IntegerType::get(ctx, self.size_bits() as u32, Signedness::Signed).into()
86 }
87
88 pub fn size_bits(&self) -> usize {
89 match self {
90 IntKind::I8 => 8,
91 IntKind::I16 => 16,
92 IntKind::I32 => 32,
93 IntKind::I64 => 64,
94 }
95 }
96}
97
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
100#[allow(missing_docs)]
101pub enum UIntKind {
102 U8,
103 U16,
104 U32,
105 U64,
106}
107
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
110#[allow(missing_docs)]
111pub enum ComplexKind {
112 C32,
113 C64,
114}
115
116impl UIntKind {
117 pub fn to_type(&self, ctx: &Context) -> TypeHandle {
118 IntegerType::get(ctx, self.size_bits() as u32, Signedness::Unsigned).into()
119 }
120
121 pub fn size_bits(&self) -> usize {
122 match self {
123 UIntKind::U8 => 8,
124 UIntKind::U16 => 16,
125 UIntKind::U32 => 32,
126 UIntKind::U64 => 64,
127 }
128 }
129}
130
131#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
133#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord, From)]
134#[allow(missing_docs)]
135pub enum ElemType {
136 Index,
137 Float(FloatKind),
138 Int(IntKind),
139 UInt(UIntKind),
140 Complex(ComplexKind),
141 Bool,
142}
143
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
146pub enum OpaqueType {
147 Barrier,
148 TensorMap,
149}
150
151#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
152#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
153pub enum SemanticType {
154 TensorLayout(usize, ClampMode),
155 TensorView(usize, bool, [u32; 5]),
156}
157
158impl ElemType {
159 pub fn from_scale_dtype(dtype: ScaleDtype) -> Self {
161 match dtype {
162 ScaleDtype::F32 => Self::Float(FloatKind::F32),
163 ScaleDtype::F16 => Self::Float(FloatKind::F16),
164 ScaleDtype::BF16 => Self::Float(FloatKind::BF16),
165 ScaleDtype::UE8M0 => Self::Float(FloatKind::UE8M0),
166 ScaleDtype::UE4M3 => Self::Float(FloatKind::E4M3),
167 }
168 }
169
170 pub fn from_quant_value(quant_value: QuantValue) -> Self {
172 match quant_value {
173 QuantValue::E5M2 => Self::Float(FloatKind::E5M2),
174 QuantValue::E4M3 => Self::Float(FloatKind::E4M3),
175 QuantValue::E2M1 => Self::Float(FloatKind::E2M1),
176 QuantValue::Q8F | QuantValue::Q8S => Self::Int(IntKind::I8),
177 other => panic!("Unsupported quant value {other:?}"),
178 }
179 }
180
181 pub fn to_type(&self, ctx: &Context) -> TypeHandle {
182 match self {
183 ElemType::Index => IndexType::get(ctx).into(),
184 ElemType::Float(float_kind) => float_kind.to_type(ctx),
185 ElemType::Int(int_kind) => int_kind.to_type(ctx),
186 ElemType::UInt(uint_kind) => uint_kind.to_type(ctx),
187 ElemType::Complex(ComplexKind::C32) => Complex32Type::get(ctx).into(),
188 ElemType::Complex(ComplexKind::C64) => Complex64Type::get(ctx).into(),
189 ElemType::Bool => BoolType::get(ctx).into(),
190 }
191 }
192
193 pub fn constant(&self, val: ConstantValue) -> ExpandValue {
197 ExpandValue::constant(val, *self)
198 }
199
200 pub fn with_vector_size(self, vector_size: VectorSize) -> Type {
201 let ty = Type::Scalar(self);
202 if vector_size > 1 {
203 Type::Vector(ty.intern(), vector_size)
204 } else {
205 ty
206 }
207 }
208
209 pub fn expand_size(&self, address_type: AddressType) -> usize {
210 match self {
211 ElemType::Index => address_type.size(),
212 other => other.size(),
213 }
214 }
215
216 pub fn size(&self) -> usize {
218 match self {
219 ElemType::Index => panic!("Can't get index size outside kernel"),
220 ElemType::Float(kind) => match kind {
221 FloatKind::E2M1
222 | FloatKind::E2M1x2
223 | FloatKind::E2M3
224 | FloatKind::E3M2
225 | FloatKind::E4M3
226 | FloatKind::E5M2
227 | FloatKind::UE8M0 => core::mem::size_of::<u8>(),
228 FloatKind::F16 => core::mem::size_of::<half::f16>(),
229 FloatKind::BF16 => core::mem::size_of::<half::bf16>(),
230 FloatKind::F32 => core::mem::size_of::<f32>(),
231 FloatKind::F64 => core::mem::size_of::<f64>(),
232 FloatKind::Flex32 => core::mem::size_of::<f32>(),
233 FloatKind::TF32 => core::mem::size_of::<f32>(),
234 },
235 ElemType::Int(kind) => match kind {
236 IntKind::I8 => core::mem::size_of::<i8>(),
237 IntKind::I16 => core::mem::size_of::<i16>(),
238 IntKind::I32 => core::mem::size_of::<i32>(),
239 IntKind::I64 => core::mem::size_of::<i64>(),
240 },
241 ElemType::UInt(kind) => match kind {
242 UIntKind::U8 => core::mem::size_of::<u8>(),
243 UIntKind::U16 => core::mem::size_of::<u16>(),
244 UIntKind::U32 => core::mem::size_of::<u32>(),
245 UIntKind::U64 => core::mem::size_of::<u64>(),
246 },
247 ElemType::Complex(ComplexKind::C32) => {
248 core::mem::size_of::<num_complex::Complex<f32>>()
249 }
250 ElemType::Complex(ComplexKind::C64) => {
251 core::mem::size_of::<num_complex::Complex<f64>>()
252 }
253 ElemType::Bool => core::mem::size_of::<bool>(),
254 }
255 }
256
257 pub fn size_bits(&self) -> usize {
259 match self {
260 ElemType::Index => panic!("Can't get index size outside kernel"),
261 ElemType::Float(kind) => match kind {
262 FloatKind::E2M1x2
263 | FloatKind::E2M3
264 | FloatKind::E3M2
265 | FloatKind::E4M3
266 | FloatKind::E5M2
267 | FloatKind::UE8M0
268 | FloatKind::F16
269 | FloatKind::BF16
270 | FloatKind::F32
271 | FloatKind::F64
272 | FloatKind::Flex32
273 | FloatKind::TF32 => self.size() * 8,
274 FloatKind::E2M1 => 4,
275 },
276 ElemType::Int(_) | ElemType::UInt(_) | ElemType::Complex(_) | ElemType::Bool => {
277 self.size() * 8
278 }
279 }
280 }
281
282 pub const fn min_vector_size(&self) -> u8 {
283 match self {
284 ElemType::Float(FloatKind::E2M1) => 2,
285 _ => 1,
286 }
287 }
288
289 pub fn is_int(&self) -> bool {
290 matches!(self, ElemType::Int(_) | ElemType::UInt(_) | ElemType::Bool)
291 }
292
293 pub fn is_signed_int(&self) -> bool {
294 matches!(self, ElemType::Int(_))
295 }
296
297 pub fn is_unsigned_int(&self) -> bool {
298 matches!(self, ElemType::UInt(_) | ElemType::Bool)
299 }
300
301 pub fn is_float(&self) -> bool {
302 matches!(self, ElemType::Float(_))
303 }
304
305 pub fn is_bool(&self) -> bool {
306 matches!(self, ElemType::Bool)
307 }
308
309 pub fn is_complex(&self) -> bool {
310 matches!(self, ElemType::Complex(_))
311 }
312
313 pub fn as_complex(&self) -> Option<ComplexKind> {
314 match self {
315 ElemType::Complex(kind) => Some(*kind),
316 _ => None,
317 }
318 }
319
320 pub fn as_float(&self) -> Option<FloatKind> {
321 match self {
322 ElemType::Float(kind) => Some(*kind),
323 _ => None,
324 }
325 }
326
327 pub fn max_variable(&self, scope: &Scope) -> ExpandValue {
328 let value = match self {
329 ElemType::Index => {
330 let addr = scope.ctx().address_type().unsigned_type();
331 return addr.max_variable(scope);
332 }
333 ElemType::Float(kind) => match kind {
334 FloatKind::E2M1 => e2m1::MAX.to_f64(),
335 FloatKind::E2M1x2 => e2m1::MAX.to_f64(),
336 FloatKind::E2M3 => e2m3::MAX,
337 FloatKind::E3M2 => e3m2::MAX,
338 FloatKind::E4M3 => e4m3::MAX.to_f64(),
339 FloatKind::E5M2 => e5m2::MAX.to_f64(),
340 FloatKind::UE8M0 => ue8m0::MAX.to_f64(),
341 FloatKind::F16 => half::f16::MAX.to_f64(),
342 FloatKind::BF16 => half::bf16::MAX.to_f64(),
343 FloatKind::Flex32 | FloatKind::TF32 | FloatKind::F32 => f32::MAX as f64,
344 FloatKind::F64 => f64::MAX,
345 }
346 .into(),
347 ElemType::Int(kind) => match kind {
348 IntKind::I8 => i8::MAX as i64,
349 IntKind::I16 => i16::MAX as i64,
350 IntKind::I32 => i32::MAX as i64,
351 IntKind::I64 => i64::MAX,
352 }
353 .into(),
354 ElemType::UInt(kind) => match kind {
355 UIntKind::U8 => u8::MAX as u64,
356 UIntKind::U16 => u16::MAX as u64,
357 UIntKind::U32 => u32::MAX as u64,
358 UIntKind::U64 => u64::MAX,
359 }
360 .into(),
361 ElemType::Complex(_) => panic!("Complex numbers have no maximum"),
362 ElemType::Bool => true.into(),
363 };
364
365 ExpandValue::Constant { value, ty: *self }
366 }
367
368 pub fn min_variable(&self) -> ExpandValue {
369 let value = match self {
370 ElemType::Index => 0u64.into(),
371 ElemType::Float(kind) => match kind {
372 FloatKind::E2M1 => e2m1::MIN.to_f64(),
373 FloatKind::E2M1x2 => e2m1::MIN.to_f64(),
374 FloatKind::E2M3 => e2m3::MIN,
375 FloatKind::E3M2 => e3m2::MIN,
376 FloatKind::E4M3 => e4m3::MIN.to_f64(),
377 FloatKind::E5M2 => e5m2::MIN.to_f64(),
378 FloatKind::UE8M0 => ue8m0::MIN.to_f64(),
379 FloatKind::F16 => half::f16::MIN.to_f64(),
380 FloatKind::BF16 => half::bf16::MIN.to_f64(),
381 FloatKind::Flex32 | FloatKind::TF32 | FloatKind::F32 => f32::MIN as f64,
382 FloatKind::F64 => f64::MIN,
383 }
384 .into(),
385 ElemType::Int(kind) => match kind {
386 IntKind::I8 => i8::MIN as i64,
387 IntKind::I16 => i16::MIN as i64,
388 IntKind::I32 => i32::MIN as i64,
389 IntKind::I64 => i64::MIN,
390 }
391 .into(),
392 ElemType::UInt(kind) => match kind {
393 UIntKind::U8 => u8::MIN as u64,
394 UIntKind::U16 => u16::MIN as u64,
395 UIntKind::U32 => u32::MIN as u64,
396 UIntKind::U64 => u64::MIN,
397 }
398 .into(),
399 ElemType::Complex(_) => panic!("Complex numbers have no minimum"),
400 ElemType::Bool => false.into(),
401 };
402
403 ExpandValue::Constant { value, ty: *self }
404 }
405
406 pub fn epsilon(&self) -> f64 {
407 match self {
408 ElemType::Float(kind) => match kind {
409 FloatKind::E2M1 => 0.5 * (e2m1::MAX.to_f64() - e2m1::MIN.to_f64()),
410 FloatKind::E2M1x2 => 0.5 * (e2m1::MAX.to_f64() - e2m1::MIN.to_f64()),
411 FloatKind::E2M3 => 0.5 * (e2m3::MAX - e2m3::MIN),
412 FloatKind::E3M2 => 0.5 * (e3m2::MAX - e3m2::MIN),
413 FloatKind::E4M3 => 0.5 * (e4m3::MAX.to_f64() - e4m3::MIN.to_f64()),
414 FloatKind::E5M2 => 0.5 * (e5m2::MAX.to_f64() - e5m2::MIN.to_f64()),
415 FloatKind::UE8M0 => 0.5 * (ue8m0::MAX.to_f64() - ue8m0::MIN.to_f64()),
416 FloatKind::F16 => half::f16::EPSILON.to_f64(),
417 FloatKind::BF16 => 0.0078125, FloatKind::Flex32 | FloatKind::F32 | FloatKind::TF32 => f32::EPSILON.into(),
419 FloatKind::F64 => f64::EPSILON,
420 },
421 ElemType::Index | ElemType::Int(_) | ElemType::UInt(_) => 1.0, ElemType::Complex(ComplexKind::C32) => f32::EPSILON.into(),
423 ElemType::Complex(ComplexKind::C64) => f64::EPSILON,
424 ElemType::Bool => 1.0,
425 }
426 }
427}
428
429impl From<OpaqueType> for Type {
430 fn from(val: OpaqueType) -> Self {
431 Type::Opaque(val)
432 }
433}
434
435impl<T: Into<ElemType>> From<T> for Type {
436 fn from(val: T) -> Self {
437 Type::new(val.into())
438 }
439}
440
441impl From<SemanticType> for Type {
442 fn from(val: SemanticType) -> Self {
443 Type::semantic(val)
444 }
445}
446
447#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
453#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, Hash, PartialOrd, Ord)]
454#[format]
455pub enum AddressSpace {
456 #[format("`<` $0 `>`")]
457 Global(usize),
458 Shared,
459 Local,
460}
461
462typed_vec_attr!(AddressSpace, "cube.address_spaces", AddressSpaceVecAttr);
463
464#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
465#[derive(Debug, Clone, Copy, TypeHash, PartialEq, Eq, PartialOrd, Ord)]
466pub enum Type {
467 Scalar(ElemType),
469 Opaque(OpaqueType),
472 Vector(Intern<Type>, VectorSize),
474 Semantic(SemanticType),
476 Atomic(Intern<Type>),
478}
479
480impl core::hash::Hash for Type {
483 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
484 core::mem::discriminant(self).hash(state);
485 match self {
486 Type::Scalar(storage_type) => storage_type.hash(state),
487 Type::Opaque(opaque) => opaque.hash(state),
488 Type::Vector(intern, size) => {
489 intern.as_ref().hash(state);
490 size.hash(state);
491 }
492 Type::Semantic(semantic_type) => semantic_type.hash(state),
493 Type::Atomic(intern) => intern.as_ref().hash(state),
494 }
495 }
496}
497
498pub type VectorSize = usize;
499
500impl Type {
501 pub fn intern(self) -> Intern<Type> {
502 Intern::new(self)
503 }
504
505 pub fn new(elem: impl Into<ElemType>) -> Self {
507 Type::Scalar(elem.into())
508 }
509
510 pub fn semantic(ty: SemanticType) -> Self {
511 Self::Semantic(ty)
512 }
513
514 pub fn atomic(ty: impl Into<Type>) -> Self {
515 Self::Atomic(ty.into().intern())
516 }
517
518 pub fn with_vector_size(self, vector_size: VectorSize) -> Self {
519 match self {
520 Type::Scalar(inner) if vector_size > 1 => {
521 Type::Vector(Type::new(inner).intern(), vector_size)
522 }
523 Type::Opaque(opaque) => Type::Opaque(opaque),
524 Type::Vector(inner, _) if vector_size <= 1 => *inner,
525 Type::Vector(inner, _) => Type::Vector(inner, vector_size),
526 Type::Atomic(inner) => Type::Atomic(inner.with_vector_size(vector_size).intern()),
527 this @ (Type::Scalar(_) | Type::Semantic(_)) => this,
528 }
529 }
530
531 pub fn vector_size(&self) -> VectorSize {
532 match self {
533 Type::Scalar(_) => 1,
534 Type::Opaque(_) => 1,
535 Type::Vector(inner, vector_size) => inner.vector_size() * *vector_size,
536 Type::Atomic(inner) => inner.vector_size(),
537 Type::Semantic(_) => 0,
538 }
539 }
540
541 pub fn size(&self) -> usize {
542 match self {
543 Type::Scalar(ty) => ty.size(),
544 Type::Opaque(_) => panic!("Can't get size of opaque type"),
545 Type::Vector(ty, vector_size) => ty.size() * *vector_size,
546 Type::Atomic(inner) => inner.size(),
547 Type::Semantic(_) => 0,
548 }
549 }
550
551 pub fn elem_type(&self) -> ElemType {
552 match self {
553 Type::Scalar(ty) => *ty,
554 Type::Semantic(_) | Type::Opaque(_) => {
555 unimplemented!("Can't get storage for semantic type")
556 }
557 Type::Atomic(inner) | Type::Vector(inner, _) => inner.elem_type(),
558 }
559 }
560}
561
562impl Display for Type {
563 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
564 match self {
565 Type::Semantic(ty) => write!(f, "{ty}"),
566 Type::Opaque(ty) => write!(f, "{ty}"),
567 Type::Scalar(ty) => write!(f, "{ty}"),
568 Type::Vector(ty, vector_size) => write!(f, "vector<{ty}, {vector_size}>"),
569 Type::Atomic(ty) => write!(f, "atomic<{ty}>"),
570 }
571 }
572}
573
574impl Display for ElemType {
575 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
576 match self {
577 Self::Index => f.write_str("usize"),
578 Self::Float(kind) => match kind {
579 FloatKind::E2M1 => f.write_str("e2m1"),
580 FloatKind::E2M1x2 => f.write_str("e2m1x2"),
581 FloatKind::E2M3 => f.write_str("e2m3"),
582 FloatKind::E3M2 => f.write_str("e3m2"),
583 FloatKind::E4M3 => f.write_str("e4m3"),
584 FloatKind::E5M2 => f.write_str("e5m2"),
585 FloatKind::UE8M0 => f.write_str("ue8m0"),
586 FloatKind::F16 => f.write_str("f16"),
587 FloatKind::BF16 => f.write_str("bf16"),
588 FloatKind::Flex32 => f.write_str("flex32"),
589 FloatKind::TF32 => f.write_str("tf32"),
590 FloatKind::F32 => f.write_str("f32"),
591 FloatKind::F64 => f.write_str("f64"),
592 },
593 Self::Int(kind) => match kind {
594 IntKind::I8 => f.write_str("i8"),
595 IntKind::I16 => f.write_str("i16"),
596 IntKind::I32 => f.write_str("i32"),
597 IntKind::I64 => f.write_str("i64"),
598 },
599 Self::UInt(kind) => match kind {
600 UIntKind::U8 => f.write_str("u8"),
601 UIntKind::U16 => f.write_str("u16"),
602 UIntKind::U32 => f.write_str("u32"),
603 UIntKind::U64 => f.write_str("u64"),
604 },
605 Self::Complex(ComplexKind::C32) => f.write_str("c32"),
606 Self::Complex(ComplexKind::C64) => f.write_str("c64"),
607 Self::Bool => f.write_str("bool"),
608 }
609 }
610}
611
612impl Display for SemanticType {
613 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
614 match self {
615 SemanticType::TensorLayout(dims, _) => write!(f, "tensor_layout<{dims}>"),
616 SemanticType::TensorView(dims, has_dims, permutation) => {
617 write!(
618 f,
619 "tensor_layout<{:?}, has_dims: {has_dims}>",
620 &permutation[..*dims]
621 )
622 }
623 }
624 }
625}
626
627impl Display for OpaqueType {
628 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
629 match self {
630 OpaqueType::Barrier => write!(f, "barrier"),
631 OpaqueType::TensorMap => f.write_str("tensor_map"),
632 }
633 }
634}
635
636impl Display for AddressSpace {
637 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
638 match self {
639 AddressSpace::Global(id) => write!(f, "global<{id}>"),
640 AddressSpace::Shared => write!(f, "shared"),
641 AddressSpace::Local => f.write_str("local"),
642 }
643 }
644}
645
646#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
647#[derive(Debug, Clone, Copy, PartialEq, Eq, TypeHash, PartialOrd, Ord, Display)]
648pub enum AggregateKind {
649 #[display("ptr<{meta}, {inner_ty}>")]
650 Ptr {
651 inner_ty: Intern<Type>,
652 meta: MetadataKind,
653 },
654}
655
656impl core::hash::Hash for AggregateKind {
659 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
660 core::mem::discriminant(self).hash(state);
661 match self {
662 AggregateKind::Ptr { inner_ty, meta } => {
663 inner_ty.as_ref().hash(state);
664 meta.hash(state);
665 }
666 }
667 }
668}
669
670impl AggregateKind {
671 pub fn ptr(inner_ty: Type, meta: MetadataKind) -> Self {
672 AggregateKind::Ptr {
673 inner_ty: inner_ty.intern(),
674 meta,
675 }
676 }
677}
678
679#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
680#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TypeHash, PartialOrd, Ord, Display)]
681pub enum MetadataKind {
682 #[display("slice")]
684 Slice,
685 #[display("bounds_checked")]
687 BoundsCheck,
688}
689
690pub struct BoundsCheckMetadata;
691impl BoundsCheckMetadata {
692 pub const POINTER: usize = 0;
693 pub const IS_IN_BOUNDS: usize = 1;
694}
695
696pub struct SliceMetadata;
697impl SliceMetadata {
698 pub const LIST: usize = 0;
699 pub const OFFSET: usize = 1;
700 pub const LENGTH: usize = 2;
701}
702
703impl From<e2m1x2> for ExpandValue {
704 fn from(_value: e2m1x2) -> Self {
705 unimplemented!("Can't currently construct e2m1x2")
706 }
707}
708
709impl From<e2m3> for ExpandValue {
710 fn from(_value: e2m3) -> Self {
711 unimplemented!("Can't currently construct fp6")
712 }
713}
714
715impl From<e3m2> for ExpandValue {
716 fn from(_value: e3m2) -> Self {
717 unimplemented!("Can't currently construct fp6")
718 }
719}
720
721impl From<i8> for ConstantValue {
722 fn from(value: i8) -> Self {
723 ConstantValue::Int(value as i64)
724 }
725}
726
727impl From<i16> for ConstantValue {
728 fn from(value: i16) -> Self {
729 ConstantValue::Int(value as i64)
730 }
731}
732
733impl From<i32> for ConstantValue {
734 fn from(value: i32) -> Self {
735 ConstantValue::Int(value as i64)
736 }
737}
738
739impl From<isize> for ConstantValue {
740 fn from(value: isize) -> Self {
741 ConstantValue::Int(value as i64)
742 }
743}
744
745impl From<u8> for ConstantValue {
746 fn from(value: u8) -> Self {
747 ConstantValue::UInt(value as u64)
748 }
749}
750
751impl From<u16> for ConstantValue {
752 fn from(value: u16) -> Self {
753 ConstantValue::UInt(value as u64)
754 }
755}
756
757impl From<u32> for ConstantValue {
758 fn from(value: u32) -> Self {
759 ConstantValue::UInt(value as u64)
760 }
761}
762
763impl From<usize> for ConstantValue {
764 fn from(value: usize) -> Self {
765 ConstantValue::UInt(value as u64)
766 }
767}
768
769impl From<e2m1> for ConstantValue {
770 fn from(value: e2m1) -> Self {
771 ConstantValue::Float(value.to_f64())
772 }
773}
774
775impl From<e4m3> for ConstantValue {
776 fn from(value: e4m3) -> Self {
777 ConstantValue::Float(value.to_f64())
778 }
779}
780
781impl From<e5m2> for ConstantValue {
782 fn from(value: e5m2) -> Self {
783 ConstantValue::Float(value.to_f64())
784 }
785}
786
787impl From<ue8m0> for ConstantValue {
788 fn from(value: ue8m0) -> Self {
789 ConstantValue::Float(value.to_f64())
790 }
791}
792
793impl From<half::f16> for ConstantValue {
794 fn from(value: half::f16) -> Self {
795 ConstantValue::Float(value.to_f64())
796 }
797}
798
799impl From<half::bf16> for ConstantValue {
800 fn from(value: half::bf16) -> Self {
801 ConstantValue::Float(value.to_f64())
802 }
803}
804
805impl From<flex32> for ConstantValue {
806 fn from(value: flex32) -> Self {
807 ConstantValue::Float(value.to_f64())
808 }
809}
810
811impl From<tf32> for ConstantValue {
812 fn from(value: tf32) -> Self {
813 ConstantValue::Float(value.to_f64())
814 }
815}
816
817impl From<f32> for ConstantValue {
818 fn from(value: f32) -> Self {
819 ConstantValue::Float(value as f64)
820 }
821}
822
823macro_rules! impl_into_value {
824 ($($ty: ty => $kind: path,)*) => {
825 $(
826 impl From<$ty> for ExpandValue {
827 fn from(value: $ty) -> Self {
828 ExpandValue::Constant { value: value.into(), ty: $kind.into() }
829 }
830 }
831 )*
832 };
833}
834
835impl From<num_complex::Complex<f32>> for ExpandValue {
836 fn from(value: num_complex::Complex<f32>) -> Self {
837 ExpandValue::Constant {
838 value: ConstantValue::Complex(value.re as f64, value.im as f64),
839 ty: ElemType::Complex(ComplexKind::C32),
840 }
841 }
842}
843
844impl From<num_complex::Complex<f64>> for ExpandValue {
845 fn from(value: num_complex::Complex<f64>) -> Self {
846 ExpandValue::Constant {
847 value: ConstantValue::Complex(value.re, value.im),
848 ty: ElemType::Complex(ComplexKind::C64),
849 }
850 }
851}
852
853impl_into_value!(
854 bool => ElemType::Bool,
855
856 i8 => IntKind::I8,
857 i16 => IntKind::I16,
858 i32 => IntKind::I32,
859 i64 => IntKind::I64,
860
861 u8 => UIntKind::U8,
862 u16 => UIntKind::U16,
863 u32 => UIntKind::U32,
864 u64 => UIntKind::U64,
865
866 e2m1 => FloatKind::E2M1,
867 e4m3 => FloatKind::E4M3,
868 e5m2 => FloatKind::E5M2,
869 ue8m0 => FloatKind::UE8M0,
870 f16 => FloatKind::F16,
871 bf16 => FloatKind::BF16,
872 f32 => FloatKind::F32,
873 flex32 => FloatKind::Flex32,
874 tf32 => FloatKind::TF32,
875 f64 => FloatKind::F64,
876
877 usize => ElemType::Index,
878 isize => IntKind::I32,
879);
880
881#[cfg(test)]
882mod tests {
883 use super::*;
884 use core::hash::Hash;
885 use cubecl_common::hash::{StableHash, StableHasher};
886
887 fn hash(ty: Type) -> StableHash {
888 let mut hasher = StableHasher::new();
889 ty.hash(&mut hasher);
890 hasher.finalize()
891 }
892
893 #[test]
894 fn vector_size_is_part_of_the_hash() {
895 let f32_ty = Type::Scalar(ElemType::Float(FloatKind::F32));
896
897 assert_ne!(
898 hash(Type::Vector(f32_ty.intern(), 2)),
899 hash(Type::Vector(f32_ty.intern(), 4))
900 );
901 }
902}