1use super::TypeResolution;
8
9impl crate::ScalarKind {
10 pub const fn is_numeric(self) -> bool {
11 match self {
12 crate::ScalarKind::Sint
13 | crate::ScalarKind::Uint
14 | crate::ScalarKind::Float
15 | crate::ScalarKind::AbstractInt
16 | crate::ScalarKind::AbstractFloat => true,
17 crate::ScalarKind::Bool => false,
18 }
19 }
20}
21
22impl crate::Scalar {
23 pub const I32: Self = Self {
24 kind: crate::ScalarKind::Sint,
25 width: 4,
26 };
27 pub const U32: Self = Self {
28 kind: crate::ScalarKind::Uint,
29 width: 4,
30 };
31 pub const F16: Self = Self {
32 kind: crate::ScalarKind::Float,
33 width: 2,
34 };
35 pub const F32: Self = Self {
36 kind: crate::ScalarKind::Float,
37 width: 4,
38 };
39 pub const F64: Self = Self {
40 kind: crate::ScalarKind::Float,
41 width: 8,
42 };
43 pub const I64: Self = Self {
44 kind: crate::ScalarKind::Sint,
45 width: 8,
46 };
47 pub const U64: Self = Self {
48 kind: crate::ScalarKind::Uint,
49 width: 8,
50 };
51 pub const BOOL: Self = Self {
52 kind: crate::ScalarKind::Bool,
53 width: crate::BOOL_WIDTH,
54 };
55 pub const ABSTRACT_INT: Self = Self {
56 kind: crate::ScalarKind::AbstractInt,
57 width: crate::ABSTRACT_WIDTH,
58 };
59 pub const ABSTRACT_FLOAT: Self = Self {
60 kind: crate::ScalarKind::AbstractFloat,
61 width: crate::ABSTRACT_WIDTH,
62 };
63
64 pub const fn is_abstract(self) -> bool {
65 match self.kind {
66 crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => true,
67 crate::ScalarKind::Sint
68 | crate::ScalarKind::Uint
69 | crate::ScalarKind::Float
70 | crate::ScalarKind::Bool => false,
71 }
72 }
73
74 pub const fn float(width: crate::Bytes) -> Self {
79 Self {
80 kind: crate::ScalarKind::Float,
81 width,
82 }
83 }
84
85 pub const fn to_inner_scalar(self) -> crate::TypeInner {
86 crate::TypeInner::Scalar(self)
87 }
88
89 pub const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner {
90 crate::TypeInner::Vector { size, scalar: self }
91 }
92
93 pub const fn to_inner_atomic(self) -> crate::TypeInner {
94 crate::TypeInner::Atomic(self)
95 }
96}
97
98const POINTER_SPAN: u32 = 4;
99
100impl crate::TypeInner {
101 pub const fn scalar(&self) -> Option<crate::Scalar> {
112 use crate::TypeInner as Ti;
113 match *self {
114 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => Some(scalar),
115 Ti::Matrix { scalar, .. } => Some(scalar),
116 _ => None,
117 }
118 }
119
120 pub fn scalar_kind(&self) -> Option<crate::ScalarKind> {
121 self.scalar().map(|scalar| scalar.kind)
122 }
123
124 pub fn scalar_width(&self) -> Option<u8> {
126 self.scalar().map(|scalar| scalar.width)
127 }
128
129 pub fn scalar_for_conversions(
141 &self,
142 types: &crate::UniqueArena<crate::Type>,
143 ) -> Option<crate::Scalar> {
144 use crate::TypeInner as Ti;
145 match *self {
146 Ti::Scalar(scalar) | Ti::Vector { scalar, .. } | Ti::Matrix { scalar, .. } => {
147 Some(scalar)
148 }
149 Ti::Array { base, .. } => types[base].inner.scalar_for_conversions(types),
150 _ => None,
151 }
152 }
153
154 pub const fn pointer_space(&self) -> Option<crate::AddressSpace> {
155 match *self {
156 Self::Pointer { space, .. } => Some(space),
157 Self::ValuePointer { space, .. } => Some(space),
158 _ => None,
159 }
160 }
161
162 pub const fn pointer_base_type(&self) -> Option<TypeResolution> {
164 match *self {
165 crate::TypeInner::Pointer { base, .. } => Some(TypeResolution::Handle(base)),
166 crate::TypeInner::ValuePointer {
167 size: None, scalar, ..
168 } => Some(TypeResolution::Value(crate::TypeInner::Scalar(scalar))),
169 crate::TypeInner::ValuePointer {
170 size: Some(size),
171 scalar,
172 ..
173 } => Some(TypeResolution::Value(crate::TypeInner::Vector {
174 size,
175 scalar,
176 })),
177 _ => None,
178 }
179 }
180
181 pub fn is_atomic_pointer(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
182 match *self {
183 crate::TypeInner::Pointer { base, .. } => match types[base].inner {
184 crate::TypeInner::Atomic { .. } => true,
185 _ => false,
186 },
187 _ => false,
188 }
189 }
190
191 pub fn size(&self, gctx: super::GlobalCtx) -> u32 {
193 match *self {
194 Self::Scalar(scalar) | Self::Atomic(scalar) => scalar.width as u32,
195 Self::Vector { size, scalar } => size as u32 * scalar.width as u32,
196 Self::Matrix {
198 columns,
199 rows,
200 scalar,
201 } => super::Alignment::from(rows) * scalar.width as u32 * columns as u32,
202 Self::Pointer { .. } | Self::ValuePointer { .. } => POINTER_SPAN,
203 Self::Array {
204 base: _,
205 size,
206 stride,
207 } => {
208 let count = match size.resolve(gctx) {
209 Ok(crate::proc::IndexableLength::Known(count)) => count,
210 Err(_) => 0,
213 Ok(crate::proc::IndexableLength::Dynamic) => 1,
215 };
216 count * stride
217 }
218 Self::Struct { span, .. } => span,
219 Self::Image { .. }
220 | Self::Sampler { .. }
221 | Self::AccelerationStructure { .. }
222 | Self::RayQuery { .. }
223 | Self::BindingArray { .. } => 0,
224 }
225 }
226
227 pub fn canonical_form(
236 &self,
237 types: &crate::UniqueArena<crate::Type>,
238 ) -> Option<crate::TypeInner> {
239 use crate::TypeInner as Ti;
240 match *self {
241 Ti::Pointer { base, space } => match types[base].inner {
242 Ti::Scalar(scalar) => Some(Ti::ValuePointer {
243 size: None,
244 scalar,
245 space,
246 }),
247 Ti::Vector { size, scalar } => Some(Ti::ValuePointer {
248 size: Some(size),
249 scalar,
250 space,
251 }),
252 _ => None,
253 },
254 _ => None,
255 }
256 }
257
258 pub fn equivalent(
267 &self,
268 rhs: &crate::TypeInner,
269 types: &crate::UniqueArena<crate::Type>,
270 ) -> bool {
271 let left = self.canonical_form(types);
272 let right = rhs.canonical_form(types);
273 left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs)
274 }
275
276 pub fn is_dynamically_sized(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
277 use crate::TypeInner as Ti;
278 match *self {
279 Ti::Array { size, .. } => size == crate::ArraySize::Dynamic,
280 Ti::Struct { ref members, .. } => members
281 .last()
282 .map(|last| types[last.ty].inner.is_dynamically_sized(types))
283 .unwrap_or(false),
284 _ => false,
285 }
286 }
287
288 pub fn components(&self) -> Option<u32> {
289 Some(match *self {
290 Self::Vector { size, .. } => size as u32,
291 Self::Matrix { columns, .. } => columns as u32,
292 Self::Array {
293 size: crate::ArraySize::Constant(len),
294 ..
295 } => len.get(),
296 Self::Struct { ref members, .. } => members.len() as u32,
297 _ => return None,
298 })
299 }
300
301 pub fn component_type(&self, index: usize) -> Option<TypeResolution> {
302 Some(match *self {
303 Self::Vector { scalar, .. } => TypeResolution::Value(crate::TypeInner::Scalar(scalar)),
304 Self::Matrix { rows, scalar, .. } => {
305 TypeResolution::Value(crate::TypeInner::Vector { size: rows, scalar })
306 }
307 Self::Array {
308 base,
309 size: crate::ArraySize::Constant(_),
310 ..
311 } => TypeResolution::Handle(base),
312 Self::Struct { ref members, .. } => TypeResolution::Handle(members[index].ty),
313 _ => return None,
314 })
315 }
316
317 pub const fn vector_size_and_scalar(
320 &self,
321 ) -> Option<(Option<crate::VectorSize>, crate::Scalar)> {
322 match *self {
323 crate::TypeInner::Scalar(scalar) => Some((None, scalar)),
324 crate::TypeInner::Vector { size, scalar } => Some((Some(size), scalar)),
325 crate::TypeInner::Matrix { .. }
326 | crate::TypeInner::Atomic(_)
327 | crate::TypeInner::Pointer { .. }
328 | crate::TypeInner::ValuePointer { .. }
329 | crate::TypeInner::Array { .. }
330 | crate::TypeInner::Struct { .. }
331 | crate::TypeInner::Image { .. }
332 | crate::TypeInner::Sampler { .. }
333 | crate::TypeInner::AccelerationStructure { .. }
334 | crate::TypeInner::RayQuery { .. }
335 | crate::TypeInner::BindingArray { .. } => None,
336 }
337 }
338
339 pub fn is_abstract(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
344 match *self {
345 crate::TypeInner::Scalar(scalar)
346 | crate::TypeInner::Vector { scalar, .. }
347 | crate::TypeInner::Matrix { scalar, .. }
348 | crate::TypeInner::Atomic(scalar) => scalar.is_abstract(),
349 crate::TypeInner::Array { base, .. } => types[base].inner.is_abstract(types),
350 crate::TypeInner::ValuePointer { .. }
351 | crate::TypeInner::Pointer { .. }
352 | crate::TypeInner::Struct { .. }
353 | crate::TypeInner::Image { .. }
354 | crate::TypeInner::Sampler { .. }
355 | crate::TypeInner::AccelerationStructure { .. }
356 | crate::TypeInner::RayQuery { .. }
357 | crate::TypeInner::BindingArray { .. } => false,
358 }
359 }
360
361 pub fn automatically_converts_to(
390 &self,
391 goal: &Self,
392 types: &crate::UniqueArena<crate::Type>,
393 ) -> Option<(crate::Scalar, crate::Scalar)> {
394 use crate::ScalarKind as Sk;
395 use crate::TypeInner as Ti;
396
397 let expr_scalar;
403 let goal_scalar;
404 match (self, goal) {
405 (&Ti::Scalar(expr), &Ti::Scalar(goal)) => {
406 expr_scalar = expr;
407 goal_scalar = goal;
408 }
409 (
410 &Ti::Vector {
411 size: expr_size,
412 scalar: expr,
413 },
414 &Ti::Vector {
415 size: goal_size,
416 scalar: goal,
417 },
418 ) if expr_size == goal_size => {
419 expr_scalar = expr;
420 goal_scalar = goal;
421 }
422 (
423 &Ti::Matrix {
424 rows: expr_rows,
425 columns: expr_columns,
426 scalar: expr,
427 },
428 &Ti::Matrix {
429 rows: goal_rows,
430 columns: goal_columns,
431 scalar: goal,
432 },
433 ) if expr_rows == goal_rows && expr_columns == goal_columns => {
434 expr_scalar = expr;
435 goal_scalar = goal;
436 }
437 (
438 &Ti::Array {
439 base: expr_base,
440 size: expr_size,
441 stride: _,
442 },
443 &Ti::Array {
444 base: goal_base,
445 size: goal_size,
446 stride: _,
447 },
448 ) if expr_size == goal_size => {
449 return types[expr_base]
450 .inner
451 .automatically_converts_to(&types[goal_base].inner, types);
452 }
453 _ => return None,
454 }
455
456 match (expr_scalar.kind, goal_scalar.kind) {
457 (Sk::AbstractFloat, Sk::Float) => {}
458 (Sk::AbstractInt, Sk::Sint | Sk::Uint | Sk::AbstractFloat | Sk::Float) => {}
459 _ => return None,
460 }
461
462 log::trace!(" okay: expr {expr_scalar:?}, goal {goal_scalar:?}");
463 Some((expr_scalar, goal_scalar))
464 }
465}
466
467pub trait IntFloatLimits<F>
470where
471 F: num_traits::Float,
472{
473 fn min_float() -> F;
476 fn max_float() -> F;
479}
480
481macro_rules! define_int_float_limits {
482 ($int:ty, $float:ty, $min:expr, $max:expr) => {
483 impl IntFloatLimits<$float> for $int {
484 fn min_float() -> $float {
485 $min
486 }
487 fn max_float() -> $float {
488 $max
489 }
490 }
491 };
492}
493
494define_int_float_limits!(i32, half::f16, half::f16::MIN, half::f16::MAX);
495define_int_float_limits!(u32, half::f16, half::f16::ZERO, half::f16::MAX);
496define_int_float_limits!(i64, half::f16, half::f16::MIN, half::f16::MAX);
497define_int_float_limits!(u64, half::f16, half::f16::ZERO, half::f16::MAX);
498define_int_float_limits!(i32, f32, -2147483648.0f32, 2147483520.0f32);
499define_int_float_limits!(u32, f32, 0.0f32, 4294967040.0f32);
500define_int_float_limits!(
501 i64,
502 f32,
503 -9223372036854775808.0f32,
504 9223371487098961920.0f32
505);
506define_int_float_limits!(u64, f32, 0.0f32, 18446742974197923840.0f32);
507define_int_float_limits!(i32, f64, -2147483648.0f64, 2147483647.0f64);
508define_int_float_limits!(u32, f64, 0.0f64, 4294967295.0f64);
509define_int_float_limits!(
510 i64,
511 f64,
512 -9223372036854775808.0f64,
513 9223372036854774784.0f64
514);
515define_int_float_limits!(u64, f64, 0.0f64, 18446744073709549568.0f64);
516
517pub fn min_max_float_representable_by(
522 float: crate::Scalar,
523 int: crate::Scalar,
524) -> (crate::Literal, crate::Literal) {
525 match (float, int) {
526 (crate::Scalar::F16, crate::Scalar::I32) => (
527 crate::Literal::F16(i32::min_float()),
528 crate::Literal::F16(i32::max_float()),
529 ),
530 (crate::Scalar::F16, crate::Scalar::U32) => (
531 crate::Literal::F16(u32::min_float()),
532 crate::Literal::F16(u32::max_float()),
533 ),
534 (crate::Scalar::F16, crate::Scalar::I64) => (
535 crate::Literal::F16(i64::min_float()),
536 crate::Literal::F16(i64::max_float()),
537 ),
538 (crate::Scalar::F16, crate::Scalar::U64) => (
539 crate::Literal::F16(u64::min_float()),
540 crate::Literal::F16(u64::max_float()),
541 ),
542 (crate::Scalar::F32, crate::Scalar::I32) => (
543 crate::Literal::F32(i32::min_float()),
544 crate::Literal::F32(i32::max_float()),
545 ),
546 (crate::Scalar::F32, crate::Scalar::U32) => (
547 crate::Literal::F32(u32::min_float()),
548 crate::Literal::F32(u32::max_float()),
549 ),
550 (crate::Scalar::F32, crate::Scalar::I64) => (
551 crate::Literal::F32(i64::min_float()),
552 crate::Literal::F32(i64::max_float()),
553 ),
554 (crate::Scalar::F32, crate::Scalar::U64) => (
555 crate::Literal::F32(u64::min_float()),
556 crate::Literal::F32(u64::max_float()),
557 ),
558 (crate::Scalar::F64, crate::Scalar::I32) => (
559 crate::Literal::F64(i32::min_float()),
560 crate::Literal::F64(i32::max_float()),
561 ),
562 (crate::Scalar::F64, crate::Scalar::U32) => (
563 crate::Literal::F64(u32::min_float()),
564 crate::Literal::F64(u32::max_float()),
565 ),
566 (crate::Scalar::F64, crate::Scalar::I64) => (
567 crate::Literal::F64(i64::min_float()),
568 crate::Literal::F64(i64::max_float()),
569 ),
570 (crate::Scalar::F64, crate::Scalar::U64) => (
571 crate::Literal::F64(u64::min_float()),
572 crate::Literal::F64(u64::max_float()),
573 ),
574 _ => unreachable!(),
575 }
576}