1use cubecl_core::ir::{self as core, AddressSpace, ClampMode, FloatKind, IntKind, UIntKind};
2use rspirv::spirv::{
3 Capability, CooperativeMatrixLayout, CooperativeMatrixUse, FPEncoding, Scope, StorageClass,
4 TensorClampMode, Word,
5};
6use serde::{Deserialize, Serialize};
7
8use crate::{compiler::SpirvCompiler, target::SpirvTarget, value::ConstVal};
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub enum Item {
12 Scalar(Elem),
13 Vector(Elem, u32),
15 Pointer(StorageClass, Box<Item>),
16 Array(Box<Item>, u32),
17 DynamicArray(Box<Item>),
18 CoopMatrix {
19 ty: Elem,
20 rows: u32,
21 columns: u32,
22 ident: CooperativeMatrixUse,
23 layout: Option<CooperativeMatrixLayout>,
24 scope: Scope,
25 },
26 TensorLayout {
27 dims: usize,
28 clamp_mode: TensorClampMode,
29 },
30 TensorView {
31 dims: usize,
32 has_dims: bool,
33 permutation: Vec<u32>,
34 },
35}
36
37impl Item {
38 pub fn id<T: SpirvTarget>(&self, b: &mut SpirvCompiler<T>) -> Word {
39 let id = match self {
40 Item::Scalar(elem) => elem.id(b),
41 Item::Vector(elem, vec) => {
42 let elem = elem.id(b);
43 if b.compilation_options.vulkan.supports_long_vectors {
44 let len = b.const_u32(*vec);
45 b.type_vector_id_ext(elem, len)
46 } else {
47 b.type_vector(elem, *vec)
48 }
49 }
50 Item::Pointer(storage_class, item) => {
51 let item = item.id(b);
52 b.type_pointer(None, *storage_class, item)
53 }
54 Item::Array(item, size) => {
55 let item = item.id(b);
56 let id = b.id();
57 let size = b.const_u32(*size);
58 b.type_array_id(Some(id), item, size)
59 }
60 Item::DynamicArray(item) => {
61 let item = item.id(b);
62 let id = b.id();
63 b.type_runtime_array_id(Some(id), item)
64 }
65 Item::CoopMatrix {
66 ty,
67 rows,
68 columns,
69 ident,
70 scope,
71 ..
72 } => {
73 let ty = ty.id(b);
74 let scope = b.const_u32(*scope as u32);
75 let usage = b.const_u32(*ident as u32);
76 b.type_cooperative_matrix_khr(ty, scope, *rows, *columns, usage)
77 }
78 Item::TensorLayout { dims, clamp_mode } => {
79 let dim = b.const_u32(*dims as u32);
80 let clamp_mode = b.const_u32(*clamp_mode as u32);
81 b.type_tensor_layout_nv(dim, clamp_mode)
82 }
83 Item::TensorView {
84 dims,
85 has_dims,
86 permutation,
87 } => {
88 let bool = b.type_bool();
89 let dim = b.const_u32(*dims as u32);
90 let has_dims = if *has_dims {
91 b.constant_true(bool)
92 } else {
93 b.constant_false(bool)
94 };
95 let permutation = permutation
96 .iter()
97 .map(|it| b.const_u32(*it))
98 .collect::<Vec<_>>();
99 b.type_tensor_view_nv(dim, has_dims, permutation)
100 }
101 };
102 if b.debug_symbols && !b.state.debug_types.contains(&id) {
103 b.debug_name(id, format!("{self}"));
104 b.state.debug_types.insert(id);
105 }
106 id
107 }
108
109 pub fn builtin_u32() -> Self {
110 Item::Scalar(Elem::Int(32, false))
111 }
112
113 pub fn value_type(&self) -> Item {
114 match self {
115 Item::Pointer(_, item) => item.value_type(),
116 Item::Array(item, _) => item.value_type(),
117 Item::DynamicArray(item) => item.value_type(),
118 other => other.clone(),
119 }
120 }
121
122 pub fn unwrap_ptr(&self) -> Item {
123 match self {
124 Item::Pointer(_, item) => item.as_ref().clone(),
125 other => other.clone(),
126 }
127 }
128
129 pub fn size(&self) -> u32 {
130 match self {
131 Item::Scalar(elem) => elem.size(),
132 Item::Vector(elem, factor) => elem.size() * *factor,
133 Item::Pointer(_, item) => item.size(),
134 Item::Array(item, size) => item.size() * *size,
135 Item::DynamicArray(item) => item.size(),
136 Item::CoopMatrix { ty, .. } => ty.size(),
137 Item::TensorLayout { .. } => 1,
138 Item::TensorView { .. } => 1,
139 }
140 }
141
142 pub fn elem(&self) -> Elem {
143 match self {
144 Item::Scalar(elem) => *elem,
145 Item::Vector(elem, _) => *elem,
146 Item::Pointer(_, item) => item.elem(),
147 Item::Array(item, _) => item.elem(),
148 Item::DynamicArray(item) => item.elem(),
149 Item::CoopMatrix { ty, .. } => *ty,
150 Item::TensorLayout { .. } => Elem::Void,
151 Item::TensorView { .. } => Elem::Void,
152 }
153 }
154
155 pub fn same_vectorization(&self, elem: Elem) -> Item {
156 match self {
157 Item::Scalar(_) => Item::Scalar(elem),
158 Item::Vector(_, factor) => Item::Vector(elem, *factor),
159 _ => unreachable!(),
160 }
161 }
162
163 pub fn vectorization(&self) -> u32 {
164 match self {
165 Item::Vector(_, factor) => *factor,
166 _ => 1,
167 }
168 }
169
170 pub fn constant<T: SpirvTarget>(&self, b: &mut SpirvCompiler<T>, value: ConstVal) -> Word {
171 let scalar = self.elem().constant(b, value);
172 let ty = self.id(b);
173 match self {
174 Item::Scalar(_) => scalar,
175 Item::Vector(_, vec) => b.constant_composite(ty, (0..*vec).map(|_| scalar)),
176 Item::Pointer(_, _) => unimplemented!("Can't create constant pointer"),
177 Item::Array(_, _) => unimplemented!("Can't create constant pointer"),
178 Item::DynamicArray(..) => unimplemented!("Can't create constant pointer"),
179 Item::CoopMatrix { .. } => unimplemented!("Can't create constant cmma matrix"),
180 Item::TensorLayout { .. } => unimplemented!("Can't create constant cmma matrix"),
181 Item::TensorView { .. } => unimplemented!("Can't create constant cmma matrix"),
182 }
183 }
184
185 pub fn const_u32<T: SpirvTarget>(&self, b: &mut SpirvCompiler<T>, value: u32) -> Word {
186 b.static_cast(ConstVal::Bit32(value), &Elem::Int(32, false), self)
187 .0
188 }
189
190 pub fn broadcast<T: SpirvTarget>(
192 &self,
193 b: &mut SpirvCompiler<T>,
194 obj: Word,
195 out_id: Option<Word>,
196 other: &Item,
197 ) -> Word {
198 match (self, other) {
199 (Item::Scalar(elem), Item::Vector(_, factor)) => {
200 let item = Item::Vector(*elem, *factor);
201 let ty = item.id(b);
202 b.composite_construct(ty, out_id, (0..*factor).map(|_| obj).collect::<Vec<_>>())
203 .unwrap()
204 }
205 _ => obj,
206 }
207 }
208
209 pub fn cast_to<T: SpirvTarget>(
210 &self,
211 b: &mut SpirvCompiler<T>,
212 out_id: Option<Word>,
213 obj: Word,
214 other: &Item,
215 ) -> Word {
216 let ty = other.id(b);
217
218 let matching_vec = match (self, other) {
219 (Item::Scalar(_), Item::Scalar(_)) => true,
220 (Item::Scalar(_), Item::Vector(..)) => false,
221 (Item::Vector(_, factor_from), Item::Vector(_, factor_to)) => factor_from == factor_to,
222 _ => true,
223 };
224 let matching_elem = self.elem() == other.elem();
225
226 let convert_i_width =
227 |b: &mut SpirvCompiler<T>, obj: Word, out_id: Option<Word>, signed: bool| {
228 if signed {
229 b.s_convert(ty, out_id, obj).unwrap()
230 } else {
231 b.u_convert(ty, out_id, obj).unwrap()
232 }
233 };
234
235 let convert_int = |b: &mut SpirvCompiler<T>,
236 obj: Word,
237 out_id: Option<Word>,
238 (width_self, signed_self),
239 (width_other, signed_other)| {
240 let width_differs = width_self != width_other;
241 let sign_extend = signed_self && signed_other;
242 match width_differs {
243 true => convert_i_width(b, obj, out_id, sign_extend),
244 false => b.copy_object(ty, out_id, obj).unwrap(),
245 }
246 };
247
248 let cast_elem = |b: &mut SpirvCompiler<T>, obj: Word, out_id: Option<Word>| -> Word {
249 match (self.elem(), other.elem()) {
250 (Elem::Bool, Elem::Int(_, _)) => {
251 let one = other.const_u32(b, 1);
252 let zero = other.const_u32(b, 0);
253 b.select(ty, out_id, obj, one, zero).unwrap()
254 }
255 (Elem::Bool, Elem::Float(_, _)) | (Elem::Bool, Elem::Relaxed) => {
256 let one = other.const_u32(b, 1);
257 let zero = other.const_u32(b, 0);
258 b.select(ty, out_id, obj, one, zero).unwrap()
259 }
260 (Elem::Int(_, _), Elem::Bool) => {
261 let zero = self.const_u32(b, 0);
262 b.i_not_equal(ty, out_id, obj, zero).unwrap()
263 }
264 (Elem::Int(width_self, signed_self), Elem::Int(width_other, signed_other)) => {
265 convert_int(
266 b,
267 obj,
268 out_id,
269 (width_self, signed_self),
270 (width_other, signed_other),
271 )
272 }
273 (Elem::Int(_, false), Elem::Float(_, _)) | (Elem::Int(_, false), Elem::Relaxed) => {
274 b.convert_u_to_f(ty, out_id, obj).unwrap()
275 }
276 (Elem::Int(_, true), Elem::Float(_, _)) | (Elem::Int(_, true), Elem::Relaxed) => {
277 b.convert_s_to_f(ty, out_id, obj).unwrap()
278 }
279 (Elem::Float(_, _), Elem::Bool) | (Elem::Relaxed, Elem::Bool) => {
280 let zero = self.const_u32(b, 0);
281 b.f_unord_not_equal(ty, out_id, obj, zero).unwrap()
282 }
283 (Elem::Float(_, _), Elem::Int(_, false)) | (Elem::Relaxed, Elem::Int(_, false)) => {
284 b.convert_f_to_u(ty, out_id, obj).unwrap()
285 }
286 (Elem::Float(_, _), Elem::Int(_, true)) | (Elem::Relaxed, Elem::Int(_, true)) => {
287 b.convert_f_to_s(ty, out_id, obj).unwrap()
288 }
289 (Elem::Float(32, _), Elem::Relaxed) | (Elem::Relaxed, Elem::Float(32, _)) => {
290 if out_id.is_some() {
291 b.copy_object(ty, out_id, obj).unwrap()
292 } else {
293 obj
294 }
295 }
296 (Elem::Float(_, _), Elem::Float(_, _))
297 | (Elem::Float(_, _), Elem::Relaxed)
298 | (Elem::Relaxed, Elem::Float(_, _)) => b.f_convert(ty, out_id, obj).unwrap(),
299 (Elem::Bool, Elem::Bool) => b.copy_object(ty, out_id, obj).unwrap(),
300 (Elem::Relaxed, Elem::Relaxed) => b.copy_object(ty, out_id, obj).unwrap(),
301 (from, to) => panic!("Invalid cast from {from:?} to {to:?}"),
302 }
303 };
304
305 match (matching_vec, matching_elem) {
306 (true, true) if out_id.is_some() => b.copy_object(ty, out_id, obj).unwrap(),
307 (true, true) => obj,
308 (true, false) => cast_elem(b, obj, out_id),
309 (false, true) => self.broadcast(b, obj, out_id, other),
310 (false, false) => {
311 let broadcast = self.broadcast(b, obj, None, other);
312 cast_elem(b, broadcast, out_id)
313 }
314 }
315 }
316
317 pub fn is_ptr(&self) -> bool {
318 matches!(self, Item::Pointer(..))
319 }
320
321 pub fn is_array(&self) -> bool {
322 matches!(self, Item::Array(..) | Item::DynamicArray(..))
323 }
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
327pub enum Elem {
328 Void,
329 Bool,
330 Int(u32, bool),
331 Float(u32, Option<FPEncoding>),
332 Relaxed,
333}
334
335impl Elem {
336 pub fn id<T: SpirvTarget>(&self, b: &mut SpirvCompiler<T>) -> Word {
337 let id = match self {
338 Elem::Void => b.type_void(),
339 Elem::Bool => b.type_bool(),
340 Elem::Int(width, _) => b.type_int(*width, 0),
341 Elem::Float(width, encoding) => b.type_float(*width, *encoding),
342 Elem::Relaxed => b.type_float(32, None),
343 };
344 if b.debug_symbols && !b.state.debug_types.contains(&id) {
345 b.debug_name(id, format!("{self}"));
346 b.state.debug_types.insert(id);
347 }
348 id
349 }
350
351 pub fn size(&self) -> u32 {
352 match self {
353 Elem::Void => 0,
354 Elem::Bool => 1,
355 Elem::Int(size, _) => *size / 8,
356 Elem::Float(size, _) => *size / 8,
357 Elem::Relaxed => 4,
358 }
359 }
360
361 pub fn constant<T: SpirvTarget>(&self, b: &mut SpirvCompiler<T>, value: ConstVal) -> Word {
362 let ty = self.id(b);
363 match self {
364 Elem::Void => unreachable!(),
365 Elem::Bool if value.as_u64() != 0 => b.constant_true(ty),
366 Elem::Bool => b.constant_false(ty),
367 _ => match value {
368 ConstVal::Bit32(val) => b.dedup_constant_bit32(ty, val),
369 ConstVal::Bit64(val) => b.dedup_constant_bit64(ty, val),
370 },
371 }
372 }
373
374 pub fn float_encoding(&self) -> Option<FPEncoding> {
375 match self {
376 Elem::Float(_, encoding) => *encoding,
377 _ => None,
378 }
379 }
380
381 pub fn width(&self) -> u32 {
382 self.size() * 8
383 }
384}
385
386impl<T: SpirvTarget> SpirvCompiler<T> {
387 pub fn compile_type(&mut self, item: core::Type) -> Item {
388 match item {
389 core::Type::Scalar(storage) => Item::Scalar(self.compile_storage_type(storage)),
390 core::Type::Vector(inner, size) => {
391 Item::Vector(self.compile_storage_type(inner.storage_type()), size as u32)
392 }
393 core::Type::Atomic(inner) => {
394 if let core::Type::Vector(ty, _) = inner.value_type()
395 && ty.is_float()
396 && ty.size() == 2
397 {
398 self.capabilities.insert(Capability::AtomicFloat16VectorNV);
399 }
400 self.compile_type(*inner)
401 }
402 core::Type::Pointer(inner, class) => {
403 let storage_class = compile_pointer_class(class);
404 let item = self.compile_type(*inner);
405 Item::Pointer(storage_class, Box::new(item))
406 }
407 core::Type::Semantic(semantic) => match semantic {
408 core::SemanticType::TensorLayout(dims, clamp_mode) => Item::TensorLayout {
409 dims,
410 clamp_mode: compile_clamp_mode(clamp_mode),
411 },
412 core::SemanticType::TensorView(dims, has_dims, permutation) => Item::TensorView {
413 dims,
414 has_dims,
415 permutation: permutation[..dims].to_vec(),
416 },
417 },
418 core::Type::Array(inner, size) => {
419 let item = self.compile_type(*inner);
420 Item::Array(Box::new(item), size as u32)
421 }
422 core::Type::DynamicArray(inner) => {
423 let item = self.compile_type(*inner);
424 Item::DynamicArray(Box::new(item))
425 }
426 core::Type::Matrix(ty) => {
427 let mat = self.compile_matrix(&ty);
428 Item::CoopMatrix {
429 ty: mat.elem,
430 rows: self.matrix_rows(&mat),
431 columns: self.matrix_columns(&mat),
432 ident: mat.ident,
433 layout: mat.layout,
434 scope: mat.scope,
435 }
436 }
437 core::Type::Opaque(opaque_type) => match opaque_type {
438 core::OpaqueType::Barrier(..) | core::OpaqueType::BarrierToken(..) => {
439 panic!("Barrier not supported in SPIR-V")
440 }
441 core::OpaqueType::TensorMap => panic!("Tensor map not supported in SPIR-V"),
442 },
443 core::Type::Aggregate(_) => {
444 unreachable!("Should be disaggregated at this point")
445 }
446 }
447 }
448
449 pub fn compile_storage_type(&mut self, ty: core::StorageType) -> Elem {
450 match ty {
451 core::StorageType::Scalar(ty) => self.compile_elem(ty),
452 core::StorageType::Packed(_, _) => {
453 unimplemented!("Packed types not yet supported in SPIR-V")
454 }
455 }
456 }
457
458 pub fn compile_elem(&mut self, elem: core::ElemType) -> Elem {
459 match elem {
460 core::ElemType::Float(
461 core::FloatKind::E2M1
462 | core::FloatKind::E2M3
463 | core::FloatKind::E3M2
464 | core::FloatKind::UE8M0,
465 ) => panic!("Minifloat not supported in SPIR-V"),
466 core::ElemType::Float(core::FloatKind::E4M3) => {
467 self.capabilities.insert(Capability::Float8EXT);
468 Elem::Float(8, Some(FPEncoding::Float8E4M3EXT))
469 }
470 core::ElemType::Float(core::FloatKind::E5M2) => {
471 self.capabilities.insert(Capability::Float8EXT);
472 Elem::Float(8, Some(FPEncoding::Float8E5M2EXT))
473 }
474 core::ElemType::Float(core::FloatKind::BF16) => {
475 self.capabilities.insert(Capability::BFloat16TypeKHR);
476 Elem::Float(16, Some(FPEncoding::BFloat16KHR))
477 }
478 core::ElemType::Float(FloatKind::F16) => {
479 self.capabilities.insert(Capability::Float16);
480 Elem::Float(16, None)
481 }
482 core::ElemType::Float(FloatKind::TF32) => panic!("TF32 not supported in SPIR-V"),
483 core::ElemType::Float(FloatKind::Flex32) => Elem::Relaxed,
484 core::ElemType::Float(FloatKind::F32) => Elem::Float(32, None),
485 core::ElemType::Float(FloatKind::F64) => {
486 self.capabilities.insert(Capability::Float64);
487 Elem::Float(64, None)
488 }
489 core::ElemType::Int(IntKind::I8) => {
490 self.capabilities.insert(Capability::Int8);
491 Elem::Int(8, true)
492 }
493 core::ElemType::Int(IntKind::I16) => {
494 self.capabilities.insert(Capability::Int16);
495 Elem::Int(16, true)
496 }
497 core::ElemType::Int(IntKind::I32) => Elem::Int(32, true),
498 core::ElemType::Int(IntKind::I64) => {
499 self.capabilities.insert(Capability::Int64);
500 Elem::Int(64, true)
501 }
502 core::ElemType::UInt(UIntKind::U64) => {
503 self.capabilities.insert(Capability::Int64);
504 Elem::Int(64, false)
505 }
506 core::ElemType::UInt(UIntKind::U32) => Elem::Int(32, false),
507 core::ElemType::UInt(UIntKind::U16) => {
508 self.capabilities.insert(Capability::Int16);
509 Elem::Int(16, false)
510 }
511 core::ElemType::UInt(UIntKind::U8) => {
512 self.capabilities.insert(Capability::Int8);
513 Elem::Int(8, false)
514 }
515 core::ElemType::Bool => Elem::Bool,
516 }
517 }
518
519 pub fn compile_function_param_type(&mut self, val: core::Value) -> Word {
520 match val.kind {
521 core::ValueKind::Value { .. } | core::ValueKind::Constant(..) => {
522 self.compile_type(val.ty).id(self)
523 }
524 }
525 }
526
527 pub fn static_cast(&mut self, val: ConstVal, from: &Elem, item: &Item) -> (Word, ConstVal) {
528 let elem_cast = match (*from, item.elem()) {
529 (Elem::Bool, Elem::Int(width, _)) => ConstVal::from_uint(val.as_u32() as u64, width),
530 (Elem::Bool, Elem::Float(width, encoding)) => {
531 ConstVal::from_float(val.as_u32() as f64, width, encoding)
532 }
533 (Elem::Bool, Elem::Relaxed) => ConstVal::from_float(val.as_u32() as f64, 32, None),
534 (Elem::Int(_, _), Elem::Bool) => ConstVal::from_bool(val.as_u64() != 0),
535 (Elem::Int(_, false), Elem::Int(width, _)) => ConstVal::from_uint(val.as_u64(), width),
536 (Elem::Int(w_in, true), Elem::Int(width, _)) => {
537 ConstVal::from_uint(val.as_int(w_in) as u64, width)
538 }
539 (Elem::Int(_, false), Elem::Float(width, encoding)) => {
540 ConstVal::from_float(val.as_u64() as f64, width, encoding)
541 }
542 (Elem::Int(_, false), Elem::Relaxed) => {
543 ConstVal::from_float(val.as_u64() as f64, 32, None)
544 }
545 (Elem::Int(in_w, true), Elem::Float(width, encoding)) => {
546 ConstVal::from_float(val.as_int(in_w) as f64, width, encoding)
547 }
548 (Elem::Int(in_w, true), Elem::Relaxed) => {
549 ConstVal::from_float(val.as_int(in_w) as f64, 32, None)
550 }
551 (Elem::Float(in_w, encoding), Elem::Bool) => {
552 ConstVal::from_bool(val.as_float(in_w, encoding) != 0.0)
553 }
554 (Elem::Relaxed, Elem::Bool) => ConstVal::from_bool(val.as_float(32, None) != 0.0),
555 (Elem::Float(in_w, encoding), Elem::Int(out_w, false)) => {
556 ConstVal::from_uint(val.as_float(in_w, encoding) as u64, out_w)
557 }
558 (Elem::Relaxed, Elem::Int(out_w, false)) => {
559 ConstVal::from_uint(val.as_float(32, None) as u64, out_w)
560 }
561 (Elem::Float(in_w, encoding), Elem::Int(out_w, true)) => {
562 ConstVal::from_int(val.as_float(in_w, encoding) as i64, out_w)
563 }
564 (Elem::Relaxed, Elem::Int(out_w, true)) => {
565 ConstVal::from_int(val.as_float(32, None) as i64, out_w)
566 }
567 (Elem::Float(in_w, encoding), Elem::Float(out_w, encoding_out)) => {
568 ConstVal::from_float(val.as_float(in_w, encoding), out_w, encoding_out)
569 }
570 (Elem::Relaxed, Elem::Float(out_w, encoding)) => {
571 ConstVal::from_float(val.as_float(32, None), out_w, encoding)
572 }
573 (Elem::Float(in_w, encoding), Elem::Relaxed) => {
574 ConstVal::from_float(val.as_float(in_w, encoding), 32, None)
575 }
576 (Elem::Bool, Elem::Bool) => val,
577 (Elem::Relaxed, Elem::Relaxed) => val,
578 (_, Elem::Void) | (Elem::Void, _) => unreachable!(),
579 };
580 let id = item.constant(self, elem_cast);
581 (id, elem_cast)
582 }
583}
584
585pub fn compile_pointer_class(class: AddressSpace) -> StorageClass {
586 match class {
587 AddressSpace::Global(_) => StorageClass::PhysicalStorageBuffer,
588 AddressSpace::Shared => StorageClass::Workgroup,
589 AddressSpace::Local => StorageClass::Function,
590 }
591}
592
593impl std::fmt::Display for Item {
594 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
595 match self {
596 Item::Scalar(elem) => write!(f, "{elem}"),
597 Item::Vector(elem, factor) => write!(f, "vec{factor}<{elem}>"),
598 Item::Pointer(class, item) => write!(f, "ptr<{class:?}, {item}>"),
599 Item::Array(item, size) => write!(f, "array<{item}, {size}>"),
600 Item::DynamicArray(item) => write!(f, "array<{item}>"),
601 Item::CoopMatrix { ty, ident, .. } => write!(f, "matrix<{ty}, {ident:?}>"),
602 Item::TensorLayout { dims, clamp_mode } => {
603 write!(f, "tensor_layout<{dims}, {clamp_mode:?}>")
604 }
605 Item::TensorView {
606 dims,
607 has_dims,
608 permutation,
609 } => {
610 write!(
611 f,
612 "tensor_view<{:?}, has_dims: {has_dims}>",
613 &permutation[..*dims]
614 )
615 }
616 }
617 }
618}
619
620impl std::fmt::Display for Elem {
621 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
622 match self {
623 Elem::Void => write!(f, "void"),
624 Elem::Bool => write!(f, "bool"),
625 Elem::Int(width, false) => write!(f, "u{width}"),
626 Elem::Int(width, true) => write!(f, "i{width}"),
627 Elem::Float(width, None) => write!(f, "f{width}"),
628 Elem::Float(_, Some(FPEncoding::BFloat16KHR)) => write!(f, "bf16"),
629 Elem::Float(_, Some(FPEncoding::Float8E4M3EXT)) => write!(f, "e4m3"),
630 Elem::Float(_, Some(FPEncoding::Float8E5M2EXT)) => write!(f, "e5m2"),
631 Elem::Relaxed => write!(f, "flex32"),
632 }
633 }
634}
635
636fn compile_clamp_mode(clamp_mode: ClampMode) -> TensorClampMode {
637 match clamp_mode {
638 ClampMode::Undefined => TensorClampMode::Undefined,
639 ClampMode::Constant(_) => TensorClampMode::Constant,
640 ClampMode::ClampToEdge => TensorClampMode::ClampToEdge,
641 ClampMode::Repeat => TensorClampMode::Repeat,
642 ClampMode::RepeatMirrored => TensorClampMode::RepeatMirrored,
643 }
644}