1use crate::{ir, valid::MAX_TYPE_SIZE};
9
10use super::TypeResolution;
11
12impl crate::ScalarKind {
13 pub const fn is_numeric(self) -> bool {
14 match self {
15 crate::ScalarKind::Sint
16 | crate::ScalarKind::Uint
17 | crate::ScalarKind::Float
18 | crate::ScalarKind::AbstractInt
19 | crate::ScalarKind::AbstractFloat => true,
20 crate::ScalarKind::Bool => false,
21 }
22 }
23}
24
25impl crate::Scalar {
26 pub const I16: Self = Self {
27 kind: crate::ScalarKind::Sint,
28 width: 2,
29 };
30 pub const U16: Self = Self {
31 kind: crate::ScalarKind::Uint,
32 width: 2,
33 };
34 pub const I32: Self = Self {
35 kind: crate::ScalarKind::Sint,
36 width: 4,
37 };
38 pub const U32: Self = Self {
39 kind: crate::ScalarKind::Uint,
40 width: 4,
41 };
42 pub const F16: Self = Self {
43 kind: crate::ScalarKind::Float,
44 width: 2,
45 };
46 pub const F32: Self = Self {
47 kind: crate::ScalarKind::Float,
48 width: 4,
49 };
50 pub const F64: Self = Self {
51 kind: crate::ScalarKind::Float,
52 width: 8,
53 };
54 pub const I64: Self = Self {
55 kind: crate::ScalarKind::Sint,
56 width: 8,
57 };
58 pub const U64: Self = Self {
59 kind: crate::ScalarKind::Uint,
60 width: 8,
61 };
62 pub const BOOL: Self = Self {
63 kind: crate::ScalarKind::Bool,
64 width: crate::BOOL_WIDTH,
65 };
66 pub const ABSTRACT_INT: Self = Self {
67 kind: crate::ScalarKind::AbstractInt,
68 width: crate::ABSTRACT_WIDTH,
69 };
70 pub const ABSTRACT_FLOAT: Self = Self {
71 kind: crate::ScalarKind::AbstractFloat,
72 width: crate::ABSTRACT_WIDTH,
73 };
74
75 pub const fn is_abstract(self) -> bool {
76 match self.kind {
77 crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => true,
78 crate::ScalarKind::Sint
79 | crate::ScalarKind::Uint
80 | crate::ScalarKind::Float
81 | crate::ScalarKind::Bool => false,
82 }
83 }
84
85 pub const fn float(width: crate::Bytes) -> Self {
90 Self {
91 kind: crate::ScalarKind::Float,
92 width,
93 }
94 }
95
96 pub const fn to_inner_scalar(self) -> crate::TypeInner {
97 crate::TypeInner::Scalar(self)
98 }
99
100 pub const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner {
101 crate::TypeInner::Vector { size, scalar: self }
102 }
103
104 pub const fn to_inner_atomic(self) -> crate::TypeInner {
105 crate::TypeInner::Atomic(self)
106 }
107}
108
109pub fn concrete_int_scalars() -> impl Iterator<Item = ir::Scalar> {
114 [
115 ir::Scalar::I32,
116 ir::Scalar::U32,
117 ir::Scalar::I16,
118 ir::Scalar::U16,
119 ir::Scalar::I64,
120 ir::Scalar::U64,
121 ]
122 .into_iter()
123}
124
125pub fn vector_sizes() -> impl Iterator<Item = ir::VectorSize> + Clone {
127 static SIZES: [ir::VectorSize; 3] = [
128 ir::VectorSize::Bi,
129 ir::VectorSize::Tri,
130 ir::VectorSize::Quad,
131 ];
132
133 SIZES.iter().cloned()
134}
135
136const POINTER_SPAN: u32 = 4;
137
138impl crate::TypeInner {
139 pub const fn scalar(&self) -> Option<crate::Scalar> {
150 use crate::TypeInner as Ti;
151 match *self {
152 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => Some(scalar),
153 Ti::Matrix { scalar, .. } => Some(scalar),
154 Ti::CooperativeMatrix { scalar, .. } => Some(scalar),
155 _ => None,
156 }
157 }
158
159 pub fn scalar_kind(&self) -> Option<crate::ScalarKind> {
160 self.scalar().map(|scalar| scalar.kind)
161 }
162
163 pub fn scalar_width(&self) -> Option<u8> {
165 self.scalar().map(|scalar| scalar.width)
166 }
167
168 pub fn scalar_for_conversions(
180 &self,
181 types: &crate::UniqueArena<crate::Type>,
182 ) -> Option<crate::Scalar> {
183 use crate::TypeInner as Ti;
184 match *self {
185 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } | Ti::Matrix { scalar, .. } => {
186 Some(scalar)
187 }
188 Ti::Array { base, .. } => types[base].inner.scalar_for_conversions(types),
189 _ => None,
190 }
191 }
192
193 pub const fn pointer_space(&self) -> Option<crate::AddressSpace> {
194 match *self {
195 Self::Pointer { space, .. } => Some(space),
196 Self::ValuePointer { space, .. } => Some(space),
197 _ => None,
198 }
199 }
200
201 pub const fn pointer_base_type(&self) -> Option<TypeResolution> {
203 match *self {
204 crate::TypeInner::Pointer { base, .. } => Some(TypeResolution::Handle(base)),
205 crate::TypeInner::ValuePointer {
206 size: None, scalar, ..
207 } => Some(TypeResolution::Value(crate::TypeInner::Scalar(scalar))),
208 crate::TypeInner::ValuePointer {
209 size: Some(size),
210 scalar,
211 ..
212 } => Some(TypeResolution::Value(crate::TypeInner::Vector {
213 size,
214 scalar,
215 })),
216 _ => None,
217 }
218 }
219
220 pub fn is_atomic_pointer(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
221 match *self {
222 Self::Pointer { base, .. } => match types[base].inner {
223 Self::Atomic { .. } => true,
224 _ => false,
225 },
226 _ => false,
227 }
228 }
229
230 pub fn try_size(&self, gctx: super::GlobalCtx) -> Option<u32> {
233 match *self {
234 Self::Scalar(scalar) | Self::Atomic(scalar) => Some(scalar.width as u32),
235 Self::Vector { size, scalar } => Some(size as u32 * scalar.width as u32),
236 Self::Matrix {
238 columns,
239 rows,
240 scalar,
241 } => Some(super::Alignment::from(rows) * scalar.width as u32 * columns as u32),
242 Self::CooperativeMatrix {
243 columns,
244 rows,
245 scalar,
246 role: _,
247 } => Some(columns as u32 * rows as u32 * scalar.width as u32),
248 Self::Pointer { .. } | Self::ValuePointer { .. } => Some(POINTER_SPAN),
249 Self::Array {
250 base: _,
251 size,
252 stride,
253 } => {
254 let count = match size.resolve(gctx) {
255 Ok(crate::proc::IndexableLength::Known(count)) => count,
256 Err(_) => 0,
259 Ok(crate::proc::IndexableLength::Dynamic) => 1,
261 };
262 if count > MAX_TYPE_SIZE {
263 None
266 } else {
267 count
268 .checked_mul(stride)
269 .filter(|size| *size <= MAX_TYPE_SIZE)
270 }
271 }
272 Self::Struct { span, .. } => Some(span),
273 Self::Image { .. }
274 | Self::Sampler { .. }
275 | Self::AccelerationStructure { .. }
276 | Self::RayQuery { .. }
277 | Self::BindingArray { .. } => Some(0),
278 }
279 }
280
281 pub fn size(&self, gctx: super::GlobalCtx) -> u32 {
288 self.try_size(gctx).expect("type is too large")
289 }
290
291 pub fn canonical_form(
300 &self,
301 types: &crate::UniqueArena<crate::Type>,
302 ) -> Option<crate::TypeInner> {
303 use crate::TypeInner as Ti;
304 match *self {
305 Ti::Pointer { base, space } => match types[base].inner {
306 Ti::Scalar(scalar) => Some(Ti::ValuePointer {
307 size: None,
308 scalar,
309 space,
310 }),
311 Ti::Vector { size, scalar } => Some(Ti::ValuePointer {
312 size: Some(size),
313 scalar,
314 space,
315 }),
316 _ => None,
317 },
318 _ => None,
319 }
320 }
321
322 pub fn non_struct_equivalent(
342 &self,
343 rhs: &ir::TypeInner,
344 types: &crate::UniqueArena<crate::Type>,
345 ) -> bool {
346 let left = self.canonical_form(types);
347 let right = rhs.canonical_form(types);
348
349 let left_struct = matches!(*self, ir::TypeInner::Struct { .. });
350 let right_struct = matches!(*rhs, ir::TypeInner::Struct { .. });
351
352 assert!(!left_struct || !right_struct);
353
354 left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs)
355 }
356
357 pub fn is_dynamically_sized(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
359 use crate::TypeInner as Ti;
360 match *self {
361 Ti::Array {
362 size: crate::ArraySize::Constant(_),
363 ..
364 } => false,
365 Ti::Array {
366 size: crate::ArraySize::Pending(_) | crate::ArraySize::Dynamic,
367 ..
368 } => true,
369 Ti::Struct { ref members, .. } => members
370 .last()
371 .map(|last| types[last.ty].inner.is_dynamically_sized(types))
372 .unwrap_or(false),
373 _ => false,
374 }
375 }
376
377 pub fn is_constructible(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
379 use crate::TypeInner as Ti;
380 match *self {
381 Ti::Array { base, size, .. } => {
382 let fixed_size = match size {
383 ir::ArraySize::Constant(_) => true,
384 ir::ArraySize::Pending(_) | ir::ArraySize::Dynamic => false,
385 };
386 fixed_size && types[base].inner.is_constructible(types)
387 }
388 Ti::Struct { ref members, .. } => members
389 .iter()
390 .all(|member| types[member.ty].inner.is_constructible(types)),
391 Ti::Atomic(_)
392 | Ti::Pointer { .. }
393 | Ti::ValuePointer { .. }
394 | Ti::Image { .. }
395 | Ti::Sampler { .. }
396 | Ti::AccelerationStructure { .. }
397 | Ti::BindingArray { .. } => false,
398 Ti::Scalar(_)
399 | Ti::Vector { .. }
400 | Ti::Matrix { .. }
401 | Ti::RayQuery { .. }
402 | Ti::CooperativeMatrix { .. } => true,
403 }
404 }
405
406 pub const fn components(&self) -> Option<u32> {
407 Some(match *self {
408 Self::Vector { size, .. } => size as u32,
409 Self::Matrix { columns, .. } => columns as u32,
410 Self::Array {
411 size: crate::ArraySize::Constant(len),
412 ..
413 } => len.get(),
414 Self::Struct { ref members, .. } => members.len() as u32,
415 _ => return None,
416 })
417 }
418
419 pub fn component_type(&self, index: usize) -> Option<TypeResolution> {
420 Some(match *self {
421 Self::Vector { scalar, .. } => TypeResolution::Value(crate::TypeInner::Scalar(scalar)),
422 Self::Matrix { rows, scalar, .. } => {
423 TypeResolution::Value(crate::TypeInner::Vector { size: rows, scalar })
424 }
425 Self::Array {
426 base,
427 size: crate::ArraySize::Constant(_),
428 ..
429 } => TypeResolution::Handle(base),
430 Self::Struct { ref members, .. } => TypeResolution::Handle(members[index].ty),
431 _ => return None,
432 })
433 }
434
435 pub const fn vector_size_and_scalar(
438 &self,
439 ) -> Option<(Option<crate::VectorSize>, crate::Scalar)> {
440 match *self {
441 crate::TypeInner::Scalar(scalar) => Some((None, scalar)),
442 crate::TypeInner::Vector { size, scalar } => Some((Some(size), scalar)),
443 crate::TypeInner::Matrix { .. }
444 | crate::TypeInner::CooperativeMatrix { .. }
445 | crate::TypeInner::Atomic(_)
446 | crate::TypeInner::Pointer { .. }
447 | crate::TypeInner::ValuePointer { .. }
448 | crate::TypeInner::Array { .. }
449 | crate::TypeInner::Struct { .. }
450 | crate::TypeInner::Image { .. }
451 | crate::TypeInner::Sampler { .. }
452 | crate::TypeInner::AccelerationStructure { .. }
453 | crate::TypeInner::RayQuery { .. }
454 | crate::TypeInner::BindingArray { .. } => None,
455 }
456 }
457
458 pub fn is_abstract(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
463 match *self {
464 crate::TypeInner::Scalar(scalar)
465 | crate::TypeInner::Vector { scalar, .. }
466 | crate::TypeInner::Matrix { scalar, .. }
467 | crate::TypeInner::Atomic(scalar) => scalar.is_abstract(),
468 crate::TypeInner::Array { base, .. } => types[base].inner.is_abstract(types),
469 crate::TypeInner::CooperativeMatrix { .. }
470 | crate::TypeInner::ValuePointer { .. }
471 | crate::TypeInner::Pointer { .. }
472 | crate::TypeInner::Struct { .. }
473 | crate::TypeInner::Image { .. }
474 | crate::TypeInner::Sampler { .. }
475 | crate::TypeInner::AccelerationStructure { .. }
476 | crate::TypeInner::RayQuery { .. }
477 | crate::TypeInner::BindingArray { .. } => false,
478 }
479 }
480
481 pub fn automatically_converts_to(
510 &self,
511 goal: &Self,
512 types: &crate::UniqueArena<crate::Type>,
513 ) -> Option<(crate::Scalar, crate::Scalar)> {
514 use crate::ScalarKind as Sk;
515 use crate::TypeInner as Ti;
516
517 let expr_scalar;
523 let goal_scalar;
524 match (self, goal) {
525 (&Ti::Scalar(expr), &Ti::Scalar(goal)) => {
526 expr_scalar = expr;
527 goal_scalar = goal;
528 }
529 (
530 &Ti::Vector {
531 size: expr_size,
532 scalar: expr,
533 },
534 &Ti::Vector {
535 size: goal_size,
536 scalar: goal,
537 },
538 ) if expr_size == goal_size => {
539 expr_scalar = expr;
540 goal_scalar = goal;
541 }
542 (
543 &Ti::Matrix {
544 rows: expr_rows,
545 columns: expr_columns,
546 scalar: expr,
547 },
548 &Ti::Matrix {
549 rows: goal_rows,
550 columns: goal_columns,
551 scalar: goal,
552 },
553 ) if expr_rows == goal_rows && expr_columns == goal_columns => {
554 expr_scalar = expr;
555 goal_scalar = goal;
556 }
557 (
558 &Ti::Array {
559 base: expr_base,
560 size: expr_size,
561 stride: _,
562 },
563 &Ti::Array {
564 base: goal_base,
565 size: goal_size,
566 stride: _,
567 },
568 ) if expr_size == goal_size => {
569 return types[expr_base]
570 .inner
571 .automatically_converts_to(&types[goal_base].inner, types);
572 }
573 _ => return None,
574 }
575
576 match (expr_scalar.kind, goal_scalar.kind) {
577 (Sk::AbstractFloat, Sk::Float) => {}
578 (Sk::AbstractInt, Sk::Sint | Sk::Uint | Sk::AbstractFloat | Sk::Float) => {}
579 _ => return None,
580 }
581
582 log::trace!(" okay: expr {expr_scalar:?}, goal {goal_scalar:?}");
583 Some((expr_scalar, goal_scalar))
584 }
585}
586
587pub trait IntFloatLimits<F>
590where
591 F: num_traits::Float,
592{
593 fn min_float() -> F;
596 fn max_float() -> F;
599}
600
601macro_rules! define_int_float_limits {
602 ($int:ty, $float:ty, $min:expr, $max:expr) => {
603 impl IntFloatLimits<$float> for $int {
604 fn min_float() -> $float {
605 $min
606 }
607 fn max_float() -> $float {
608 $max
609 }
610 }
611 };
612}
613
614define_int_float_limits!(i16, half::f16, half::f16::MIN, half::f16::MAX);
618define_int_float_limits!(u16, half::f16, half::f16::ZERO, half::f16::MAX);
619define_int_float_limits!(i16, f32, -32768.0f32, 32767.0f32);
620define_int_float_limits!(u16, f32, 0.0f32, 65535.0f32);
621define_int_float_limits!(i16, f64, -32768.0f64, 32767.0f64);
622define_int_float_limits!(u16, f64, 0.0f64, 65535.0f64);
623define_int_float_limits!(i32, half::f16, half::f16::MIN, half::f16::MAX);
624define_int_float_limits!(u32, half::f16, half::f16::ZERO, half::f16::MAX);
625define_int_float_limits!(i64, half::f16, half::f16::MIN, half::f16::MAX);
626define_int_float_limits!(u64, half::f16, half::f16::ZERO, half::f16::MAX);
627define_int_float_limits!(i32, f32, -2147483648.0f32, 2147483520.0f32);
628define_int_float_limits!(u32, f32, 0.0f32, 4294967040.0f32);
629define_int_float_limits!(
630 i64,
631 f32,
632 -9223372036854775808.0f32,
633 9223371487098961920.0f32
634);
635define_int_float_limits!(u64, f32, 0.0f32, 18446742974197923840.0f32);
636define_int_float_limits!(i32, f64, -2147483648.0f64, 2147483647.0f64);
637define_int_float_limits!(u32, f64, 0.0f64, 4294967295.0f64);
638define_int_float_limits!(
639 i64,
640 f64,
641 -9223372036854775808.0f64,
642 9223372036854774784.0f64
643);
644define_int_float_limits!(u64, f64, 0.0f64, 18446744073709549568.0f64);
645
646pub fn min_max_float_representable_by(
651 float: crate::Scalar,
652 int: crate::Scalar,
653) -> (crate::Literal, crate::Literal) {
654 match (float, int) {
655 (crate::Scalar::F16, crate::Scalar::I16) => (
656 crate::Literal::F16(i16::min_float()),
657 crate::Literal::F16(i16::max_float()),
658 ),
659 (crate::Scalar::F16, crate::Scalar::U16) => (
660 crate::Literal::F16(u16::min_float()),
661 crate::Literal::F16(u16::max_float()),
662 ),
663 (crate::Scalar::F16, crate::Scalar::I32) => (
664 crate::Literal::F16(i32::min_float()),
665 crate::Literal::F16(i32::max_float()),
666 ),
667 (crate::Scalar::F16, crate::Scalar::U32) => (
668 crate::Literal::F16(u32::min_float()),
669 crate::Literal::F16(u32::max_float()),
670 ),
671 (crate::Scalar::F16, crate::Scalar::I64) => (
672 crate::Literal::F16(i64::min_float()),
673 crate::Literal::F16(i64::max_float()),
674 ),
675 (crate::Scalar::F16, crate::Scalar::U64) => (
676 crate::Literal::F16(u64::min_float()),
677 crate::Literal::F16(u64::max_float()),
678 ),
679 (crate::Scalar::F32, crate::Scalar::I16) => (
680 crate::Literal::F32(i16::min_float()),
681 crate::Literal::F32(i16::max_float()),
682 ),
683 (crate::Scalar::F32, crate::Scalar::U16) => (
684 crate::Literal::F32(u16::min_float()),
685 crate::Literal::F32(u16::max_float()),
686 ),
687 (crate::Scalar::F32, crate::Scalar::I32) => (
688 crate::Literal::F32(i32::min_float()),
689 crate::Literal::F32(i32::max_float()),
690 ),
691 (crate::Scalar::F32, crate::Scalar::U32) => (
692 crate::Literal::F32(u32::min_float()),
693 crate::Literal::F32(u32::max_float()),
694 ),
695 (crate::Scalar::F32, crate::Scalar::I64) => (
696 crate::Literal::F32(i64::min_float()),
697 crate::Literal::F32(i64::max_float()),
698 ),
699 (crate::Scalar::F32, crate::Scalar::U64) => (
700 crate::Literal::F32(u64::min_float()),
701 crate::Literal::F32(u64::max_float()),
702 ),
703 (crate::Scalar::F64, crate::Scalar::I16) => (
704 crate::Literal::F64(i16::min_float()),
705 crate::Literal::F64(i16::max_float()),
706 ),
707 (crate::Scalar::F64, crate::Scalar::U16) => (
708 crate::Literal::F64(u16::min_float()),
709 crate::Literal::F64(u16::max_float()),
710 ),
711 (crate::Scalar::F64, crate::Scalar::I32) => (
712 crate::Literal::F64(i32::min_float()),
713 crate::Literal::F64(i32::max_float()),
714 ),
715 (crate::Scalar::F64, crate::Scalar::U32) => (
716 crate::Literal::F64(u32::min_float()),
717 crate::Literal::F64(u32::max_float()),
718 ),
719 (crate::Scalar::F64, crate::Scalar::I64) => (
720 crate::Literal::F64(i64::min_float()),
721 crate::Literal::F64(i64::max_float()),
722 ),
723 (crate::Scalar::F64, crate::Scalar::U64) => (
724 crate::Literal::F64(u64::min_float()),
725 crate::Literal::F64(u64::max_float()),
726 ),
727 _ => unreachable!(),
728 }
729}
730
731pub const fn vector_size_str(size: crate::VectorSize) -> &'static str {
733 match size {
734 crate::VectorSize::Bi => "2",
735 crate::VectorSize::Tri => "3",
736 crate::VectorSize::Quad => "4",
737 }
738}