1use alloc::{
7 format,
8 string::{String, ToString},
9 vec,
10 vec::Vec,
11};
12use core::iter;
13
14use arrayvec::ArrayVec;
15use half::f16;
16use num_traits::{real::Real, FromPrimitive, One, ToPrimitive, Zero};
17
18use crate::{
19 arena::{Arena, Handle, HandleVec, UniqueArena},
20 ArraySize, BinaryOperator, Constant, Expression, Literal, Override, RelationalFunction,
21 ScalarKind, Span, Type, TypeInner, UnaryOperator,
22};
23
24#[cfg(feature = "wgsl-in")]
25use crate::common::wgsl::TryToWgsl;
26
27macro_rules! with_dollar_sign {
33 ($($body:tt)*) => {
34 macro_rules! __with_dollar_sign { $($body)* }
35 __with_dollar_sign!($);
36 }
37}
38
39macro_rules! gen_component_wise_extractor {
40 (
41 $ident:ident -> $target:ident,
42 literals: [$( $literal:ident => $mapping:ident: $ty:ident ),+ $(,)?],
43 scalar_kinds: [$( $scalar_kind:ident ),* $(,)?],
44 ) => {
45 #[derive(Debug)]
47 #[cfg_attr(test, derive(PartialEq))]
48 enum $target<const N: usize> {
49 $(
50 #[doc = concat!(
51 "Maps to [`Literal::",
52 stringify!($literal),
53 "`]",
54 )]
55 $mapping([$ty; N]),
56 )+
57 }
58
59 impl From<$target<1>> for Expression {
60 fn from(value: $target<1>) -> Self {
61 match value {
62 $(
63 $target::$mapping([value]) => {
64 Expression::Literal(Literal::$literal(value))
65 }
66 )+
67 }
68 }
69 }
70
71 #[doc = concat!(
72 "Attempts to evaluate multiple `exprs` as a combined [`",
73 stringify!($target),
74 "`] to pass to `handler`. ",
75 )]
76 fn $ident<const N: usize, const M: usize>(
83 eval: &mut ConstantEvaluator<'_>,
84 span: Span,
85 exprs: [Handle<Expression>; N],
86 handler: fn($target<N>) -> Result<$target<M>, ConstantEvaluatorError>,
87 ) -> Result<Handle<Expression>, ConstantEvaluatorError>
88 where
89 $target<M>: Into<Expression>,
90 {
91 assert!(N > 0);
92 let err = ConstantEvaluatorError::InvalidMathArg;
93 let mut exprs = exprs.into_iter();
94
95 macro_rules! sanitize {
96 ($expr:expr) => {
97 eval.eval_zero_value_and_splat($expr, span)
98 .map(|expr| &eval.expressions[expr])
99 };
100 }
101
102 let new_expr: Result<Expression, ConstantEvaluatorError> = match sanitize!(exprs.next().unwrap())? {
103 $(
104 &Expression::Literal(Literal::$literal(x)) => {
105 let mut arr = ArrayVec::<_, N>::new();
106 arr.push(x);
107 for expr in exprs {
108 match sanitize!(expr)? {
109 &Expression::Literal(Literal::$literal(val)) => arr.push(val),
110 _ => return Err(err),
111 }
112 }
113 let comps = $target::$mapping(arr.into_inner().unwrap());
114 Ok(handler(comps)?.into())
115 },
116 )+
117 &Expression::Compose { ty, ref components } => match &eval.types[ty].inner {
118 &TypeInner::Vector { size, scalar } => match scalar.kind {
119 $(ScalarKind::$scalar_kind)|* => {
120 let first_ty = ty;
121 let mut component_groups =
122 ArrayVec::<ArrayVec<_, { crate::VectorSize::MAX }>, N>::new();
123 {
124 let mut inner = ArrayVec::new();
125 for item in crate::proc::flatten_compose(
126 first_ty,
127 components,
128 eval.expressions,
129 eval.types,
130 ) {
131 inner.push(item);
132 }
133 component_groups.push(inner);
134 }
135 for expr in exprs {
136 match sanitize!(expr)? {
137 &Expression::Compose { ty, ref components }
138 if &eval.types[ty].inner
139 == &eval.types[first_ty].inner =>
140 {
141 let mut inner = ArrayVec::new();
142 for item in crate::proc::flatten_compose(
143 ty,
144 components,
145 eval.expressions,
146 eval.types,
147 ) {
148 inner.push(item);
149 }
150 component_groups.push(inner);
151 }
152 _ => return Err(err),
153 }
154 }
155 let component_groups = component_groups.into_inner().unwrap();
156 let mut new_components =
157 ArrayVec::<_, { crate::VectorSize::MAX }>::new();
158 for idx in 0..(size as u8).into() {
159 let mut group_arr = ArrayVec::<_, N>::new();
160 for cs in component_groups.iter() {
161 group_arr.push(
162 cs.get(idx).cloned().ok_or_else(|| err.clone())?,
163 );
164 }
165 let group = group_arr.into_inner().unwrap();
166 new_components.push($ident(
167 eval,
168 span,
169 group,
170 handler,
171 )?);
172 }
173 Ok(Expression::Compose {
174 ty: first_ty,
175 components: new_components.into_iter().collect(),
176 })
177 }
178 _ => return Err(err),
179 },
180 _ => return Err(err),
181 },
182 _ => return Err(err),
183 };
184 eval.register_evaluated_expr(new_expr?, span)
185 }
186
187 with_dollar_sign! {
188 ($d:tt) => {
189 #[allow(unused)]
190 #[doc = concat!(
191 "A convenience macro for using the same RHS for each [`",
192 stringify!($target),
193 "`] variant in a call to [`",
194 stringify!($ident),
195 "`].",
196 )]
197 macro_rules! $ident {
198 (
199 $eval:expr,
200 $span:expr,
201 [$d ($d expr:expr),+ $d (,)?],
202 |$d ($d arg:ident),+| $d tt:tt
203 ) => {
204 $ident($eval, $span, [$d ($d expr),+], |args| match args {
205 $(
206 $target::$mapping([$d ($d arg),+]) => {
207 let res = $d tt;
208 Result::map(res, $target::$mapping)
209 },
210 )+
211 })
212 };
213 }
214 };
215 }
216 };
217}
218
219gen_component_wise_extractor! {
220 component_wise_scalar -> Scalar,
221 literals: [
222 AbstractFloat => AbstractFloat: f64,
223 F32 => F32: f32,
224 F16 => F16: f16,
225 AbstractInt => AbstractInt: i64,
226 U32 => U32: u32,
227 I32 => I32: i32,
228 U64 => U64: u64,
229 I64 => I64: i64,
230 ],
231 scalar_kinds: [
232 Float,
233 AbstractFloat,
234 Sint,
235 Uint,
236 AbstractInt,
237 ],
238}
239
240gen_component_wise_extractor! {
241 component_wise_float -> Float,
242 literals: [
243 AbstractFloat => Abstract: f64,
244 F32 => F32: f32,
245 F16 => F16: f16,
246 ],
247 scalar_kinds: [
248 Float,
249 AbstractFloat,
250 ],
251}
252
253gen_component_wise_extractor! {
254 component_wise_concrete_int -> ConcreteInt,
255 literals: [
256 U32 => U32: u32,
257 I32 => I32: i32,
258 ],
259 scalar_kinds: [
260 Sint,
261 Uint,
262 ],
263}
264
265gen_component_wise_extractor! {
266 component_wise_signed -> Signed,
267 literals: [
268 AbstractFloat => AbstractFloat: f64,
269 AbstractInt => AbstractInt: i64,
270 F32 => F32: f32,
271 F16 => F16: f16,
272 I32 => I32: i32,
273 ],
274 scalar_kinds: [
275 Sint,
276 AbstractInt,
277 Float,
278 AbstractFloat,
279 ],
280}
281
282#[derive(Debug)]
284enum LiteralVector {
285 F64(ArrayVec<f64, { crate::VectorSize::MAX }>),
286 F32(ArrayVec<f32, { crate::VectorSize::MAX }>),
287 F16(ArrayVec<f16, { crate::VectorSize::MAX }>),
288 U16(ArrayVec<u16, { crate::VectorSize::MAX }>),
289 I16(ArrayVec<i16, { crate::VectorSize::MAX }>),
290 U32(ArrayVec<u32, { crate::VectorSize::MAX }>),
291 I32(ArrayVec<i32, { crate::VectorSize::MAX }>),
292 U64(ArrayVec<u64, { crate::VectorSize::MAX }>),
293 I64(ArrayVec<i64, { crate::VectorSize::MAX }>),
294 Bool(ArrayVec<bool, { crate::VectorSize::MAX }>),
295 AbstractInt(ArrayVec<i64, { crate::VectorSize::MAX }>),
296 AbstractFloat(ArrayVec<f64, { crate::VectorSize::MAX }>),
297}
298
299impl LiteralVector {
300 #[allow(clippy::missing_const_for_fn, reason = "MSRV")]
301 fn len(&self) -> usize {
302 match *self {
303 LiteralVector::F64(ref v) => v.len(),
304 LiteralVector::F32(ref v) => v.len(),
305 LiteralVector::F16(ref v) => v.len(),
306 LiteralVector::U16(ref v) => v.len(),
307 LiteralVector::I16(ref v) => v.len(),
308 LiteralVector::U32(ref v) => v.len(),
309 LiteralVector::I32(ref v) => v.len(),
310 LiteralVector::U64(ref v) => v.len(),
311 LiteralVector::I64(ref v) => v.len(),
312 LiteralVector::Bool(ref v) => v.len(),
313 LiteralVector::AbstractInt(ref v) => v.len(),
314 LiteralVector::AbstractFloat(ref v) => v.len(),
315 }
316 }
317
318 fn from_literal(literal: Literal) -> Self {
320 fn arrayvec_of<T, const N: usize>(val: T) -> ArrayVec<T, N> {
321 let mut v = ArrayVec::new();
322 v.push(val);
323 v
324 }
325 match literal {
326 Literal::F64(e) => Self::F64(arrayvec_of(e)),
327 Literal::F32(e) => Self::F32(arrayvec_of(e)),
328 Literal::U16(e) => Self::U16(arrayvec_of(e)),
329 Literal::I16(e) => Self::I16(arrayvec_of(e)),
330 Literal::U32(e) => Self::U32(arrayvec_of(e)),
331 Literal::I32(e) => Self::I32(arrayvec_of(e)),
332 Literal::U64(e) => Self::U64(arrayvec_of(e)),
333 Literal::I64(e) => Self::I64(arrayvec_of(e)),
334 Literal::Bool(e) => Self::Bool(arrayvec_of(e)),
335 Literal::AbstractInt(e) => Self::AbstractInt(arrayvec_of(e)),
336 Literal::AbstractFloat(e) => Self::AbstractFloat(arrayvec_of(e)),
337 Literal::F16(e) => Self::F16(arrayvec_of(e)),
338 }
339 }
340
341 fn from_literal_vec(
346 components: ArrayVec<Literal, { crate::VectorSize::MAX }>,
347 ) -> Result<Self, ConstantEvaluatorError> {
348 assert!(!components.is_empty());
349 macro_rules! compose_literals {
351 ($components:expr, $variant:ident, $self_variant:ident) => {{
352 let mut out = ArrayVec::new();
353 for l in &$components {
354 match l {
355 &Literal::$variant(v) => out.push(v),
356 _ => return Err(ConstantEvaluatorError::InvalidMathArg),
357 }
358 }
359 Self::$self_variant(out)
360 }};
361 }
362 Ok(match components[0] {
363 Literal::I16(_) => compose_literals!(components, I16, I16),
364 Literal::U16(_) => compose_literals!(components, U16, U16),
365 Literal::I32(_) => compose_literals!(components, I32, I32),
366 Literal::U32(_) => compose_literals!(components, U32, U32),
367 Literal::I64(_) => compose_literals!(components, I64, I64),
368 Literal::U64(_) => compose_literals!(components, U64, U64),
369 Literal::F32(_) => compose_literals!(components, F32, F32),
370 Literal::F64(_) => compose_literals!(components, F64, F64),
371 Literal::Bool(_) => compose_literals!(components, Bool, Bool),
372 Literal::AbstractInt(_) => compose_literals!(components, AbstractInt, AbstractInt),
373 Literal::AbstractFloat(_) => {
374 compose_literals!(components, AbstractFloat, AbstractFloat)
375 }
376 Literal::F16(_) => compose_literals!(components, F16, F16),
377 })
378 }
379
380 #[allow(dead_code)]
381 fn to_literal_vec(&self) -> ArrayVec<Literal, { crate::VectorSize::MAX }> {
383 macro_rules! decompose_literals {
384 ($v:expr, $variant:ident) => {{
385 let mut out = ArrayVec::new();
386 for e in $v {
387 out.push(Literal::$variant(*e));
388 }
389 out
390 }};
391 }
392 match *self {
393 LiteralVector::F64(ref v) => decompose_literals!(v, F64),
394 LiteralVector::F32(ref v) => decompose_literals!(v, F32),
395 LiteralVector::F16(ref v) => decompose_literals!(v, F16),
396 LiteralVector::U16(ref v) => decompose_literals!(v, U16),
397 LiteralVector::I16(ref v) => decompose_literals!(v, I16),
398 LiteralVector::U32(ref v) => decompose_literals!(v, U32),
399 LiteralVector::I32(ref v) => decompose_literals!(v, I32),
400 LiteralVector::U64(ref v) => decompose_literals!(v, U64),
401 LiteralVector::I64(ref v) => decompose_literals!(v, I64),
402 LiteralVector::Bool(ref v) => decompose_literals!(v, Bool),
403 LiteralVector::AbstractInt(ref v) => decompose_literals!(v, AbstractInt),
404 LiteralVector::AbstractFloat(ref v) => decompose_literals!(v, AbstractFloat),
405 }
406 }
407
408 #[allow(dead_code)]
409 fn register_as_evaluated_expr(
411 &self,
412 eval: &mut ConstantEvaluator<'_>,
413 span: Span,
414 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
415 let lit_vec = self.to_literal_vec();
416 assert!(!lit_vec.is_empty());
417 let expr = if lit_vec.len() == 1 {
418 Expression::Literal(lit_vec[0])
419 } else {
420 Expression::Compose {
421 ty: eval.types.insert(
422 Type {
423 name: None,
424 inner: TypeInner::Vector {
425 size: match lit_vec.len() {
426 2 => crate::VectorSize::Bi,
427 3 => crate::VectorSize::Tri,
428 4 => crate::VectorSize::Quad,
429 _ => unreachable!(),
430 },
431 scalar: lit_vec[0].scalar(),
432 },
433 },
434 Span::UNDEFINED,
435 ),
436 components: lit_vec
437 .iter()
438 .map(|&l| eval.register_evaluated_expr(Expression::Literal(l), span))
439 .collect::<Result<_, _>>()?,
440 }
441 };
442 eval.register_evaluated_expr(expr, span)
443 }
444}
445
446macro_rules! match_literal_vector {
471 (match $lit_vec:expr => $out:ident {
472 $(
473 $ty:ident => |$($var:ident),+| $(-> $ret:ident)? { $body:expr }
474 ),+
475 $(,)?
476 }) => {
477 match_literal_vector!(@inner_start $lit_vec; $out; [$($ty),+]; [$({ $($var),+ ; $($ret)? ; $body }),+])
478 };
479
480 (@inner_start
481 $lit_vec:expr;
482 $out:ident;
483 [$($ty:ident),+];
484 [$({ $($var:ident),+ ; $($ret:ident)? ; $body:expr }),+]
485 ) => {
486 match_literal_vector!(@inner
487 $lit_vec;
488 $out;
489 [$($ty),+];
490 [] <> [$({ $($var),+ ; $($ret)? ; $body }),+]
491 )
492 };
493
494 (@inner
495 $lit_vec:expr;
496 $out:ident;
497 [$ty:ident $(, $ty1:ident)*];
498 [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
499 [$({ $($var:ident),+ ; $($ret:ident)? ; $body:expr }),+]
500 ) => {
501 match_literal_vector!(@inner
502 $ty;
503 $lit_vec;
504 $out;
505 [$($ty1),*];
506 [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
507 [$({ $($var),+ ; $($ret)? ; $body }),+]
508 )
509 };
510 (@inner
511 Integer;
512 $lit_vec:expr;
513 $out:ident;
514 [$($ty:ident),*];
515 [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
516 [
517 { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
518 $(,{ $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
519 ]
520 ) => {
521 match_literal_vector!(@inner
522 $lit_vec;
523 $out;
524 [U32, I32, U64, I64, AbstractInt $(, $ty)*];
525 [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
526 [
527 { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body } $(,{ $($var1),+ ; $($ret1)? ; $body1 })*
533 ]
534 )
535 };
536 (@inner
537 Float;
538 $lit_vec:expr;
539 $out:ident;
540 [$($ty:ident),*];
541 [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
542 [
543 { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
544 $(,{ $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
545 ]
546 ) => {
547 match_literal_vector!(@inner
548 $lit_vec;
549 $out;
550 [F16, F32, F64, AbstractFloat $(, $ty)*];
551 [$({$_ty ; $($_var),+ ; $($_ret)? ; $_body}),*] <>
552 [
553 { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body }, { $($var),+ ; $($ret)? ; $body } $(,{ $($var1),+ ; $($ret1)? ; $body1 })*
558 ]
559 )
560 };
561 (@inner
562 $ty:ident;
563 $lit_vec:expr;
564 $out:ident;
565 [$ty1:ident $(,$ty2:ident)*];
566 [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <> [
567 { $($var:ident),+ ; $($ret:ident)? ; $body:expr }
568 $(, { $($var1:ident),+ ; $($ret1:ident)? ; $body1:expr })*
569 ]
570 ) => {
571 match_literal_vector!(@inner
572 $ty1;
573 $lit_vec;
574 $out;
575 [$($ty2),*];
576 [
577 $({$_ty ; $($_var),+ ; $($_ret)? ; $_body},)*
578 { $ty; $($var),+ ; $($ret)? ; $body }
579 ] <>
580 [$({ $($var1),+ ; $($ret1)? ; $body1 }),*]
581
582 )
583 };
584 (@inner
585 $ty:ident;
586 $lit_vec:expr;
587 $out:ident;
588 [];
589 [$({$_ty:ident ; $($_var:ident),+ ; $($_ret:ident)? ; $_body:expr}),*] <>
590 [{ $($var:ident),+ ; $($ret:ident)? ; $body:expr }]
591 ) => {
592 match_literal_vector!(@inner_finish
593 $lit_vec;
594 $out;
595 [
596 $({ $_ty ; $($_var),+ ; $($_ret)? ; $_body },)*
597 { $ty; $($var),+ ; $($ret)? ; $body }
598 ]
599 )
600 };
601 (@inner_finish
602 $lit_vec:expr;
603 $out:ident;
604 [$({$ty:ident ; $($var:ident),+ ; $($ret:ident)? ; $body:expr}),+]
605 ) => {
606 match $lit_vec {
607 $(
608 #[allow(unused_parens)]
609 ($(LiteralVector::$ty(ref $var)),+) => { Ok(match_literal_vector!(@expand_ret $out; $ty $(; $ret)? ; $body)) }
610 )+
611 _ => Err(ConstantEvaluatorError::InvalidMathArg),
612 }
613 };
614 (@expand_ret $out:ident; $ty:ident; $body:expr) => {
615 $out::$ty($body)
616 };
617 (@expand_ret $out:ident; $_ty:ident; $ret:ident; $body:expr) => {
618 $out::$ret($body)
619 };
620}
621
622fn float_length<F>(e: &[F]) -> Option<F>
623where
624 F: core::ops::Mul<F> + num_traits::Float + iter::Sum,
625{
626 if e.len() == 1 {
627 Some(e[0].abs())
629 } else {
630 let result = e.iter().map(|&ei| ei * ei).sum::<F>().sqrt();
631 result.is_finite().then_some(result)
632 }
633}
634
635fn float_dot<F>(a: &[F], b: &[F]) -> Option<F>
637where
638 F: num_traits::Float,
639{
640 let result = a
641 .iter()
642 .zip(b.iter())
643 .map(|(&aa, &bb)| aa * bb)
644 .fold(F::zero(), |acc, x| acc + x);
645 result.is_finite().then_some(result)
646}
647
648#[derive(Debug)]
649enum Behavior<'a> {
650 Wgsl(WgslRestrictions<'a>),
651 Glsl(GlslRestrictions<'a>),
652}
653
654impl Behavior<'_> {
655 const fn has_runtime_restrictions(&self) -> bool {
657 matches!(
658 self,
659 &Behavior::Wgsl(WgslRestrictions::Runtime(_))
660 | &Behavior::Glsl(GlslRestrictions::Runtime(_))
661 )
662 }
663}
664
665#[derive(Debug)]
683pub struct ConstantEvaluator<'a> {
684 behavior: Behavior<'a>,
686
687 types: &'a mut UniqueArena<Type>,
694
695 constants: &'a Arena<Constant>,
697
698 overrides: &'a Arena<Override>,
700
701 expressions: &'a mut Arena<Expression>,
703
704 expression_kind_tracker: &'a mut ExpressionKindTracker,
706
707 layouter: &'a mut crate::proc::Layouter,
708}
709
710#[derive(Debug)]
711enum WgslRestrictions<'a> {
712 Const(Option<FunctionLocalData<'a>>),
714 Override,
717 Runtime(FunctionLocalData<'a>),
721}
722
723#[derive(Debug)]
724enum GlslRestrictions<'a> {
725 Const,
727 Runtime(FunctionLocalData<'a>),
731}
732
733#[derive(Debug)]
734struct FunctionLocalData<'a> {
735 global_expressions: &'a Arena<Expression>,
737 emitter: &'a mut super::Emitter,
738 block: &'a mut crate::Block,
739}
740
741#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
742pub enum ExpressionKind {
743 Const,
744 Override,
745 Runtime,
746}
747
748#[derive(Debug)]
749pub struct ExpressionKindTracker {
750 inner: HandleVec<Expression, ExpressionKind>,
751}
752
753impl ExpressionKindTracker {
754 pub const fn new() -> Self {
755 Self {
756 inner: HandleVec::new(),
757 }
758 }
759
760 pub fn force_non_const(&mut self, value: Handle<Expression>) {
762 self.inner[value] = ExpressionKind::Runtime;
763 }
764
765 pub fn insert(&mut self, value: Handle<Expression>, expr_type: ExpressionKind) {
766 self.inner.insert(value, expr_type);
767 }
768
769 pub fn is_const(&self, h: Handle<Expression>) -> bool {
770 matches!(self.type_of(h), ExpressionKind::Const)
771 }
772
773 pub fn is_const_or_override(&self, h: Handle<Expression>) -> bool {
774 matches!(
775 self.type_of(h),
776 ExpressionKind::Const | ExpressionKind::Override
777 )
778 }
779
780 fn type_of(&self, value: Handle<Expression>) -> ExpressionKind {
781 self.inner[value]
782 }
783
784 pub fn from_arena(arena: &Arena<Expression>) -> Self {
785 let mut tracker = Self {
786 inner: HandleVec::with_capacity(arena.len()),
787 };
788 for (handle, expr) in arena.iter() {
789 tracker
790 .inner
791 .insert(handle, tracker.type_of_with_expr(expr));
792 }
793 tracker
794 }
795
796 fn type_of_with_expr(&self, expr: &Expression) -> ExpressionKind {
797 match *expr {
798 Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => {
799 ExpressionKind::Const
800 }
801 Expression::Override(_) => ExpressionKind::Override,
802 Expression::Compose { ref components, .. } => {
803 let mut expr_type = ExpressionKind::Const;
804 for component in components {
805 expr_type = expr_type.max(self.type_of(*component))
806 }
807 expr_type
808 }
809 Expression::Splat { value, .. } => self.type_of(value),
810 Expression::AccessIndex { base, .. } => self.type_of(base),
811 Expression::Access { base, index } => self.type_of(base).max(self.type_of(index)),
812 Expression::Swizzle { vector, .. } => self.type_of(vector),
813 Expression::Unary { expr, .. } => self.type_of(expr),
814 Expression::Binary { left, right, .. } => self.type_of(left).max(self.type_of(right)),
815 Expression::Math {
816 arg,
817 arg1,
818 arg2,
819 arg3,
820 ..
821 } => self
822 .type_of(arg)
823 .max(
824 arg1.map(|arg| self.type_of(arg))
825 .unwrap_or(ExpressionKind::Const),
826 )
827 .max(
828 arg2.map(|arg| self.type_of(arg))
829 .unwrap_or(ExpressionKind::Const),
830 )
831 .max(
832 arg3.map(|arg| self.type_of(arg))
833 .unwrap_or(ExpressionKind::Const),
834 ),
835 Expression::As { expr, .. } => self.type_of(expr),
836 Expression::Select {
837 condition,
838 accept,
839 reject,
840 } => self
841 .type_of(condition)
842 .max(self.type_of(accept))
843 .max(self.type_of(reject)),
844 Expression::Relational { argument, .. } => self.type_of(argument),
845 Expression::ArrayLength(expr) => self.type_of(expr),
846 _ => ExpressionKind::Runtime,
847 }
848 }
849}
850
851#[derive(Clone, Debug, thiserror::Error)]
852#[cfg_attr(test, derive(PartialEq))]
853pub enum ConstantEvaluatorError {
854 #[error("Constants cannot access function arguments")]
855 FunctionArg,
856 #[error("Constants cannot access global variables")]
857 GlobalVariable,
858 #[error("Constants cannot access local variables")]
859 LocalVariable,
860 #[error("Cannot get the array length of a non array type")]
861 InvalidArrayLengthArg,
862 #[error("Constants cannot get the array length of a dynamically sized array")]
863 ArrayLengthDynamic,
864 #[error("Cannot call arrayLength on array sized by override-expression")]
865 ArrayLengthOverridden,
866 #[error("Constants cannot call functions")]
867 Call,
868 #[error("Constants don't support workGroupUniformLoad")]
869 WorkGroupUniformLoadResult,
870 #[error("Constants don't support atomic functions")]
871 Atomic,
872 #[error("Constants don't support derivative functions")]
873 Derivative,
874 #[error("Constants don't support load expressions")]
875 Load,
876 #[error("Constants don't support image expressions")]
877 ImageExpression,
878 #[error("Constants don't support ray query expressions")]
879 RayQueryExpression,
880 #[error("Constants don't support subgroup expressions")]
881 SubgroupExpression,
882 #[error("Cannot access the type")]
883 InvalidAccessBase,
884 #[error("Cannot access at the index")]
885 InvalidAccessIndex,
886 #[error("Cannot access with index of type")]
887 InvalidAccessIndexTy,
888 #[error("Constants don't support array length expressions")]
889 ArrayLength,
890 #[error("Cannot cast scalar components of expression `{from}` to type `{to}`")]
891 InvalidCastArg { from: String, to: String },
892 #[error("Cannot apply the unary op to the argument")]
893 InvalidUnaryOpArg,
894 #[error("Cannot apply the binary op to the arguments")]
895 InvalidBinaryOpArgs,
896 #[error("Cannot apply math function to type")]
897 InvalidMathArg,
898 #[error("{0:?} built-in function expects {1:?} arguments but {2:?} were supplied")]
899 InvalidMathArgCount(crate::MathFunction, usize, usize),
900 #[error("{0} built-in function argument is out of valid range")]
901 InvalidMathArgValue(String),
902 #[error(
903 "`offset` + `count` must be at most {width}, the bit width of the operand of the \
904 {builtin} built-in function, but {offset} + {count} is greater"
905 )]
906 BitfieldRangeTooLarge {
907 builtin: &'static str,
908 offset: u32,
909 count: u32,
910 width: u32,
911 },
912 #[error("Cannot apply relational function to type")]
913 InvalidRelationalArg(RelationalFunction),
914 #[error("value of `low` is greater than `high` for clamp built-in function")]
915 InvalidClamp,
916 #[error("Constructor expects {expected} components, found {actual}")]
917 InvalidVectorComposeLength { expected: usize, actual: usize },
918 #[error("Constructor must only contain vector or scalar arguments")]
919 InvalidVectorComposeComponent,
920 #[error("Splat is defined only on scalar values")]
921 SplatScalarOnly,
922 #[error("Can only swizzle vector constants")]
923 SwizzleVectorOnly,
924 #[error("swizzle component not present in source expression")]
925 SwizzleOutOfBounds,
926 #[error("Type is not constructible")]
927 TypeNotConstructible,
928 #[error("Subexpression(s) are not constant")]
929 SubexpressionsAreNotConstant,
930 #[error("Not implemented as constant expression: {0}")]
931 NotImplemented(String),
932 #[error("{0} operation overflowed")]
933 Overflow(String),
934 #[error(
935 "the concrete type `{to_type}` cannot represent the abstract value `{value}` accurately"
936 )]
937 AutomaticConversionLossy {
938 value: String,
939 to_type: &'static str,
940 },
941 #[error("Division by zero")]
942 DivisionByZero,
943 #[error("Remainder by zero")]
944 RemainderByZero,
945 #[error("RHS of shift operation is greater than or equal to 32")]
946 ShiftedMoreThan32Bits,
947 #[error(transparent)]
948 Literal(#[from] crate::valid::LiteralError),
949 #[error("Can't use pipeline-overridable constants in const-expressions")]
950 Override,
951 #[error("Unexpected runtime-expression")]
952 RuntimeExpr,
953 #[error("Unexpected override-expression")]
954 OverrideExpr,
955 #[error("Expected boolean expression for condition argument of `select`, got something else")]
956 SelectScalarConditionNotABool,
957 #[error(
958 "Expected vectors of the same size for reject and accept args., got {:?} and {:?}",
959 reject,
960 accept
961 )]
962 SelectVecRejectAcceptSizeMismatch {
963 reject: crate::VectorSize,
964 accept: crate::VectorSize,
965 },
966 #[error("Expected boolean vector for condition arg., got something else")]
967 SelectConditionNotAVecBool,
968 #[error(
969 "Expected same number of vector components between condition, accept, and reject args., got something else",
970 )]
971 SelectConditionVecSizeMismatch,
972 #[error(
973 "Expected reject and accept args. to be scalars of vectors of the same type, got something else",
974 )]
975 SelectAcceptRejectTypeMismatch,
976 #[error("Cooperative operations can't be constant")]
977 CooperativeOperation,
978 #[error("Type is too large")]
979 TypeTooLarge(Handle<Type>),
980}
981
982impl<'a> ConstantEvaluator<'a> {
983 pub const fn for_wgsl_module(
988 module: &'a mut crate::Module,
989 global_expression_kind_tracker: &'a mut ExpressionKindTracker,
990 layouter: &'a mut crate::proc::Layouter,
991 in_override_ctx: bool,
992 ) -> Self {
993 Self::for_module(
994 Behavior::Wgsl(if in_override_ctx {
995 WgslRestrictions::Override
996 } else {
997 WgslRestrictions::Const(None)
998 }),
999 module,
1000 global_expression_kind_tracker,
1001 layouter,
1002 )
1003 }
1004
1005 pub const fn for_glsl_module(
1010 module: &'a mut crate::Module,
1011 global_expression_kind_tracker: &'a mut ExpressionKindTracker,
1012 layouter: &'a mut crate::proc::Layouter,
1013 ) -> Self {
1014 Self::for_module(
1015 Behavior::Glsl(GlslRestrictions::Const),
1016 module,
1017 global_expression_kind_tracker,
1018 layouter,
1019 )
1020 }
1021
1022 const fn for_module(
1023 behavior: Behavior<'a>,
1024 module: &'a mut crate::Module,
1025 global_expression_kind_tracker: &'a mut ExpressionKindTracker,
1026 layouter: &'a mut crate::proc::Layouter,
1027 ) -> Self {
1028 Self {
1029 behavior,
1030 types: &mut module.types,
1031 constants: &module.constants,
1032 overrides: &module.overrides,
1033 expressions: &mut module.global_expressions,
1034 expression_kind_tracker: global_expression_kind_tracker,
1035 layouter,
1036 }
1037 }
1038
1039 pub const fn for_wgsl_function(
1044 module: &'a mut crate::Module,
1045 expressions: &'a mut Arena<Expression>,
1046 local_expression_kind_tracker: &'a mut ExpressionKindTracker,
1047 layouter: &'a mut crate::proc::Layouter,
1048 emitter: &'a mut super::Emitter,
1049 block: &'a mut crate::Block,
1050 is_const: bool,
1051 ) -> Self {
1052 let local_data = FunctionLocalData {
1053 global_expressions: &module.global_expressions,
1054 emitter,
1055 block,
1056 };
1057 Self {
1058 behavior: Behavior::Wgsl(if is_const {
1059 WgslRestrictions::Const(Some(local_data))
1060 } else {
1061 WgslRestrictions::Runtime(local_data)
1062 }),
1063 types: &mut module.types,
1064 constants: &module.constants,
1065 overrides: &module.overrides,
1066 expressions,
1067 expression_kind_tracker: local_expression_kind_tracker,
1068 layouter,
1069 }
1070 }
1071
1072 pub const fn for_glsl_function(
1077 module: &'a mut crate::Module,
1078 expressions: &'a mut Arena<Expression>,
1079 local_expression_kind_tracker: &'a mut ExpressionKindTracker,
1080 layouter: &'a mut crate::proc::Layouter,
1081 emitter: &'a mut super::Emitter,
1082 block: &'a mut crate::Block,
1083 ) -> Self {
1084 Self {
1085 behavior: Behavior::Glsl(GlslRestrictions::Runtime(FunctionLocalData {
1086 global_expressions: &module.global_expressions,
1087 emitter,
1088 block,
1089 })),
1090 types: &mut module.types,
1091 constants: &module.constants,
1092 overrides: &module.overrides,
1093 expressions,
1094 expression_kind_tracker: local_expression_kind_tracker,
1095 layouter,
1096 }
1097 }
1098
1099 pub const fn to_ctx(&self) -> crate::proc::GlobalCtx<'_> {
1100 crate::proc::GlobalCtx {
1101 types: self.types,
1102 constants: self.constants,
1103 overrides: self.overrides,
1104 global_expressions: match self.function_local_data() {
1105 Some(data) => data.global_expressions,
1106 None => self.expressions,
1107 },
1108 }
1109 }
1110
1111 fn check(&self, expr: Handle<Expression>) -> Result<(), ConstantEvaluatorError> {
1112 if !self.expression_kind_tracker.is_const(expr) {
1113 log::debug!("check: SubexpressionsAreNotConstant");
1114 return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
1115 }
1116 Ok(())
1117 }
1118
1119 fn check_and_get(
1120 &mut self,
1121 expr: Handle<Expression>,
1122 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1123 match self.expressions[expr] {
1124 Expression::Constant(c) => {
1125 if let Some(function_local_data) = self.function_local_data() {
1128 self.copy_from(
1130 self.constants[c].init,
1131 function_local_data.global_expressions,
1132 )
1133 } else {
1134 Ok(self.constants[c].init)
1136 }
1137 }
1138 _ => {
1139 self.check(expr)?;
1140 Ok(expr)
1141 }
1142 }
1143 }
1144
1145 pub fn try_eval_and_append(
1169 &mut self,
1170 expr: Expression,
1171 span: Span,
1172 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1173 match self.expression_kind_tracker.type_of_with_expr(&expr) {
1174 ExpressionKind::Const => {
1175 let eval_result = self.try_eval_and_append_impl(&expr, span);
1176 if self.behavior.has_runtime_restrictions()
1181 && matches!(
1182 eval_result,
1183 Err(ConstantEvaluatorError::NotImplemented(_)
1184 | ConstantEvaluatorError::InvalidBinaryOpArgs,)
1185 )
1186 {
1187 Ok(self.append_expr(expr, span, ExpressionKind::Runtime))
1188 } else {
1189 eval_result
1190 }
1191 }
1192 ExpressionKind::Override => match self.behavior {
1193 Behavior::Wgsl(WgslRestrictions::Override | WgslRestrictions::Runtime(_)) => {
1194 Ok(self.append_expr(expr, span, ExpressionKind::Override))
1195 }
1196 Behavior::Wgsl(WgslRestrictions::Const(_)) => {
1197 Err(ConstantEvaluatorError::OverrideExpr)
1198 }
1199
1200 Behavior::Glsl(GlslRestrictions::Runtime(_)) => {
1202 Ok(self.append_expr(expr, span, ExpressionKind::Override))
1203 }
1204 Behavior::Glsl(GlslRestrictions::Const) => {
1205 Err(ConstantEvaluatorError::OverrideExpr)
1206 }
1207 },
1208 ExpressionKind::Runtime => {
1209 if self.behavior.has_runtime_restrictions() {
1210 Ok(self.append_expr(expr, span, ExpressionKind::Runtime))
1211 } else {
1212 Err(ConstantEvaluatorError::RuntimeExpr)
1213 }
1214 }
1215 }
1216 }
1217
1218 const fn is_global_arena(&self) -> bool {
1220 matches!(
1221 self.behavior,
1222 Behavior::Wgsl(WgslRestrictions::Const(None) | WgslRestrictions::Override)
1223 | Behavior::Glsl(GlslRestrictions::Const)
1224 )
1225 }
1226
1227 const fn function_local_data(&self) -> Option<&FunctionLocalData<'a>> {
1228 match self.behavior {
1229 Behavior::Wgsl(
1230 WgslRestrictions::Runtime(ref function_local_data)
1231 | WgslRestrictions::Const(Some(ref function_local_data)),
1232 )
1233 | Behavior::Glsl(GlslRestrictions::Runtime(ref function_local_data)) => {
1234 Some(function_local_data)
1235 }
1236 _ => None,
1237 }
1238 }
1239
1240 fn try_eval_and_append_impl(
1241 &mut self,
1242 expr: &Expression,
1243 span: Span,
1244 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1245 log::trace!("try_eval_and_append: {expr:?}");
1246 match *expr {
1247 Expression::Constant(c) if self.is_global_arena() => {
1248 Ok(self.constants[c].init)
1251 }
1252 Expression::Override(_) => Err(ConstantEvaluatorError::Override),
1253 Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => {
1254 self.register_evaluated_expr(expr.clone(), span)
1255 }
1256 Expression::Compose { ty, ref components } => {
1257 let components = components
1258 .iter()
1259 .map(|component| self.check_and_get(*component))
1260 .collect::<Result<Vec<_>, _>>()?;
1261 self.register_evaluated_expr(Expression::Compose { ty, components }, span)
1262 }
1263 Expression::Splat { size, value } => {
1264 let value = self.check_and_get(value)?;
1265 self.register_evaluated_expr(Expression::Splat { size, value }, span)
1266 }
1267 Expression::AccessIndex { base, index } => {
1268 let base = self.check_and_get(base)?;
1269
1270 self.access(base, index as usize, span)
1271 }
1272 Expression::Access { base, index } => {
1273 let base = self.check_and_get(base)?;
1274 let index = self.check_and_get(index)?;
1275
1276 let index_val: u32 = self
1277 .to_ctx()
1278 .get_const_val_from(index, self.expressions)
1279 .map_err(|_| ConstantEvaluatorError::InvalidAccessIndexTy)?;
1280 self.access(base, index_val as usize, span)
1281 }
1282 Expression::Swizzle {
1283 size,
1284 vector,
1285 pattern,
1286 } => {
1287 let vector = self.check_and_get(vector)?;
1288
1289 self.swizzle(size, span, vector, pattern)
1290 }
1291 Expression::Unary { expr, op } => {
1292 let expr = self.check_and_get(expr)?;
1293
1294 self.unary_op(op, expr, span)
1295 }
1296 Expression::Binary { left, right, op } => {
1297 let left = self.check_and_get(left)?;
1298 let right = self.check_and_get(right)?;
1299
1300 self.binary_op(op, left, right, span)
1301 }
1302 Expression::Math {
1303 fun,
1304 arg,
1305 arg1,
1306 arg2,
1307 arg3,
1308 } => {
1309 let arg = self.check_and_get(arg)?;
1310 let arg1 = arg1.map(|arg| self.check_and_get(arg)).transpose()?;
1311 let arg2 = arg2.map(|arg| self.check_and_get(arg)).transpose()?;
1312 let arg3 = arg3.map(|arg| self.check_and_get(arg)).transpose()?;
1313
1314 self.math(arg, arg1, arg2, arg3, fun, span)
1315 }
1316 Expression::As {
1317 convert,
1318 expr,
1319 kind,
1320 } => {
1321 let expr = self.check_and_get(expr)?;
1322
1323 match convert {
1324 Some(width) => self.cast(expr, crate::Scalar { kind, width }, span),
1325 None => Err(ConstantEvaluatorError::NotImplemented(
1326 "bitcast built-in function".into(),
1327 )),
1328 }
1329 }
1330 Expression::Select {
1331 reject,
1332 accept,
1333 condition,
1334 } => {
1335 let mut arg = |expr| self.check_and_get(expr);
1336
1337 let reject = arg(reject)?;
1338 let accept = arg(accept)?;
1339 let condition = arg(condition)?;
1340
1341 self.select(reject, accept, condition, span)
1342 }
1343 Expression::Relational { fun, argument } => {
1344 let argument = self.check_and_get(argument)?;
1345 self.relational(fun, argument, span)
1346 }
1347 Expression::ArrayLength(expr) => match self.behavior {
1348 Behavior::Wgsl(_) => Err(ConstantEvaluatorError::ArrayLength),
1349 Behavior::Glsl(_) => {
1350 let expr = self.check_and_get(expr)?;
1351 self.array_length(expr, span)
1352 }
1353 },
1354 Expression::Load { .. } => Err(ConstantEvaluatorError::Load),
1355 Expression::LocalVariable(_) => Err(ConstantEvaluatorError::LocalVariable),
1356 Expression::Derivative { .. } => Err(ConstantEvaluatorError::Derivative),
1357 Expression::CallResult { .. } => Err(ConstantEvaluatorError::Call),
1358 Expression::WorkGroupUniformLoadResult { .. } => {
1359 Err(ConstantEvaluatorError::WorkGroupUniformLoadResult)
1360 }
1361 Expression::AtomicResult { .. } => Err(ConstantEvaluatorError::Atomic),
1362 Expression::FunctionArgument(_) => Err(ConstantEvaluatorError::FunctionArg),
1363 Expression::GlobalVariable(_) => Err(ConstantEvaluatorError::GlobalVariable),
1364 Expression::ImageSample { .. }
1365 | Expression::ImageLoad { .. }
1366 | Expression::ImageQuery { .. } => Err(ConstantEvaluatorError::ImageExpression),
1367 Expression::RayQueryProceedResult
1368 | Expression::RayQueryGetIntersection { .. }
1369 | Expression::RayQueryVertexPositions { .. } => {
1370 Err(ConstantEvaluatorError::RayQueryExpression)
1371 }
1372 Expression::SubgroupBallotResult => Err(ConstantEvaluatorError::SubgroupExpression),
1373 Expression::SubgroupOperationResult { .. } => {
1374 Err(ConstantEvaluatorError::SubgroupExpression)
1375 }
1376 Expression::CooperativeLoad { .. } | Expression::CooperativeMultiplyAdd { .. } => {
1377 Err(ConstantEvaluatorError::CooperativeOperation)
1378 }
1379 }
1380 }
1381
1382 fn splat(
1395 &mut self,
1396 value: Handle<Expression>,
1397 size: crate::VectorSize,
1398 span: Span,
1399 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1400 match self.expressions[value] {
1401 Expression::Literal(literal) => {
1402 let scalar = literal.scalar();
1403 let ty = self.types.insert(
1404 Type {
1405 name: None,
1406 inner: TypeInner::Vector { size, scalar },
1407 },
1408 span,
1409 );
1410 let expr = Expression::Compose {
1411 ty,
1412 components: vec![value; size as usize],
1413 };
1414 self.register_evaluated_expr(expr, span)
1415 }
1416 Expression::ZeroValue(ty) => {
1417 let inner = match self.types[ty].inner {
1418 TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar },
1419 _ => return Err(ConstantEvaluatorError::SplatScalarOnly),
1420 };
1421 let res_ty = self.types.insert(Type { name: None, inner }, span);
1422 let expr = Expression::ZeroValue(res_ty);
1423 self.register_evaluated_expr(expr, span)
1424 }
1425 _ => Err(ConstantEvaluatorError::SplatScalarOnly),
1426 }
1427 }
1428
1429 fn swizzle(
1430 &mut self,
1431 size: crate::VectorSize,
1432 span: Span,
1433 src_constant: Handle<Expression>,
1434 pattern: [crate::SwizzleComponent; 4],
1435 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1436 let mut get_dst_ty = |ty| match self.types[ty].inner {
1437 TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
1438 Type {
1439 name: None,
1440 inner: TypeInner::Vector { size, scalar },
1441 },
1442 span,
1443 )),
1444 _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1445 };
1446
1447 match self.expressions[src_constant] {
1448 Expression::ZeroValue(ty) => {
1449 let dst_ty = get_dst_ty(ty)?;
1450 let expr = Expression::ZeroValue(dst_ty);
1451 self.register_evaluated_expr(expr, span)
1452 }
1453 Expression::Splat { value, .. } => {
1454 let expr = Expression::Splat { size, value };
1455 self.register_evaluated_expr(expr, span)
1456 }
1457 Expression::Compose { ty, ref components } => {
1458 let dst_ty = get_dst_ty(ty)?;
1459
1460 let mut flattened = [src_constant; 4]; let len =
1462 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
1463 .zip(flattened.iter_mut())
1464 .map(|(component, elt)| *elt = component)
1465 .count();
1466 let flattened = &flattened[..len];
1467
1468 let swizzled_components = pattern[..size as usize]
1469 .iter()
1470 .map(|&sc| {
1471 let sc = sc as usize;
1472 if let Some(elt) = flattened.get(sc) {
1473 Ok(*elt)
1474 } else {
1475 Err(ConstantEvaluatorError::SwizzleOutOfBounds)
1476 }
1477 })
1478 .collect::<Result<Vec<Handle<Expression>>, _>>()?;
1479 let expr = Expression::Compose {
1480 ty: dst_ty,
1481 components: swizzled_components,
1482 };
1483 self.register_evaluated_expr(expr, span)
1484 }
1485 _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1486 }
1487 }
1488
1489 fn math(
1490 &mut self,
1491 arg: Handle<Expression>,
1492 arg1: Option<Handle<Expression>>,
1493 arg2: Option<Handle<Expression>>,
1494 arg3: Option<Handle<Expression>>,
1495 fun: crate::MathFunction,
1496 span: Span,
1497 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1498 let expected = fun.argument_count();
1499 let given = Some(arg)
1500 .into_iter()
1501 .chain(arg1)
1502 .chain(arg2)
1503 .chain(arg3)
1504 .count();
1505 if expected != given {
1506 return Err(ConstantEvaluatorError::InvalidMathArgCount(
1507 fun, expected, given,
1508 ));
1509 }
1510
1511 match fun {
1513 crate::MathFunction::Abs => {
1515 component_wise_scalar(self, span, [arg], |args| match args {
1516 Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
1517 Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])),
1518 Scalar::F16([e]) => Ok(Scalar::F16([e.abs()])),
1519 Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.wrapping_abs()])),
1520 Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])),
1521 Scalar::U32([e]) => Ok(Scalar::U32([e])), Scalar::I64([e]) => Ok(Scalar::I64([e.wrapping_abs()])),
1523 Scalar::U64([e]) => Ok(Scalar::U64([e])),
1524 })
1525 }
1526 crate::MathFunction::Min => {
1527 component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1528 Ok([e1.min(e2)])
1529 })
1530 }
1531 crate::MathFunction::Max => {
1532 component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1533 Ok([e1.max(e2)])
1534 })
1535 }
1536 crate::MathFunction::Clamp => {
1537 component_wise_scalar!(
1538 self,
1539 span,
1540 [arg, arg1.unwrap(), arg2.unwrap()],
1541 |e, low, high| {
1542 if low > high {
1543 Err(ConstantEvaluatorError::InvalidClamp)
1544 } else {
1545 Ok([e.clamp(low, high)])
1546 }
1547 }
1548 )
1549 }
1550 crate::MathFunction::Saturate => component_wise_float(self, span, [arg], |e| match e {
1551 Float::F16([e]) => Ok(Float::F16(
1552 [e.clamp(f16::from_f32(0.0), f16::from_f32(1.0))],
1553 )),
1554 Float::F32([e]) => Ok(Float::F32([e.clamp(0., 1.)])),
1555 Float::Abstract([e]) => Ok(Float::Abstract([e.clamp(0., 1.)])),
1556 }),
1557
1558 crate::MathFunction::Cos => {
1560 component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) })
1561 }
1562 crate::MathFunction::Cosh => {
1563 component_wise_float!(self, span, [arg], |e| {
1564 let result = e.cosh();
1565 if result.is_finite() {
1566 Ok([result])
1567 } else {
1568 Err(ConstantEvaluatorError::Overflow("cosh".into()))
1569 }
1570 })
1571 }
1572 crate::MathFunction::Sin => {
1573 component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
1574 }
1575 crate::MathFunction::Sinh => {
1576 component_wise_float!(self, span, [arg], |e| {
1577 let result = e.sinh();
1578 if result.is_finite() {
1579 Ok([result])
1580 } else {
1581 Err(ConstantEvaluatorError::Overflow("sinh".into()))
1582 }
1583 })
1584 }
1585 crate::MathFunction::Tan => {
1586 component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
1587 }
1588 crate::MathFunction::Tanh => {
1589 component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
1590 }
1591 crate::MathFunction::Acos => {
1592 component_wise_float!(self, span, [arg], |e| {
1593 if e.abs() <= One::one() {
1594 Ok([e.acos()])
1595 } else {
1596 Err(ConstantEvaluatorError::InvalidMathArgValue("acos".into()))
1597 }
1598 })
1599 }
1600 crate::MathFunction::Asin => {
1601 component_wise_float!(self, span, [arg], |e| {
1602 if e.abs() <= One::one() {
1603 Ok([e.asin()])
1604 } else {
1605 Err(ConstantEvaluatorError::InvalidMathArgValue("asin".into()))
1606 }
1607 })
1608 }
1609 crate::MathFunction::Atan => {
1610 component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
1611 }
1612 crate::MathFunction::Atan2 => {
1613 component_wise_float!(self, span, [arg, arg1.unwrap()], |y, x| {
1614 Ok([y.atan2(x)])
1615 })
1616 }
1617 crate::MathFunction::Asinh => component_wise_float(self, span, [arg], |e| match e {
1618 Float::Abstract([e]) => Ok(Float::Abstract([libm::asinh(e)])),
1619 Float::F32([e]) => Ok(Float::F32([(e as f64).asinh() as f32])),
1620 Float::F16([e]) => Ok(Float::F16([e.asinh()])),
1621 }),
1622 crate::MathFunction::Acosh => component_wise_float(self, span, [arg], |e| match e {
1623 Float::Abstract([e]) if e >= One::one() => Ok(Float::Abstract([libm::acosh(e)])),
1624 Float::F32([e]) if e >= One::one() => Ok(Float::F32([(e as f64).acosh() as f32])),
1625 Float::F16([e]) if e >= One::one() => Ok(Float::F16([e.acosh()])),
1626 _ => Err(ConstantEvaluatorError::InvalidMathArgValue("acosh".into())),
1627 }),
1628 crate::MathFunction::Atanh => {
1629 component_wise_float!(self, span, [arg], |e| {
1630 if e.abs() < One::one() {
1631 Ok([e.atanh()])
1632 } else {
1633 Err(ConstantEvaluatorError::InvalidMathArgValue("atanh".into()))
1634 }
1635 })
1636 }
1637 crate::MathFunction::Radians => {
1638 component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) })
1639 }
1640 crate::MathFunction::Degrees => {
1641 component_wise_float!(self, span, [arg], |e| {
1642 let result = e.to_degrees();
1643 if result.is_finite() {
1644 Ok([result])
1645 } else {
1646 Err(ConstantEvaluatorError::Overflow("degrees".into()))
1647 }
1648 })
1649 }
1650
1651 crate::MathFunction::Ceil => {
1653 component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) })
1654 }
1655 crate::MathFunction::Floor => {
1656 component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
1657 }
1658 crate::MathFunction::Round => {
1659 component_wise_float(self, span, [arg], |e| match e {
1660 Float::Abstract([e]) => Ok(Float::Abstract([libm::rint(e)])),
1661 Float::F32([e]) => Ok(Float::F32([libm::rintf(e)])),
1662 Float::F16([e]) => {
1663 fn round_ties_even(x: f64) -> f64 {
1671 let i = x as i64;
1672 let f = (x - i as f64).abs();
1673 if f == 0.5 {
1674 if i & 1 == 1 {
1675 (x.abs() + 0.5).copysign(x)
1677 } else {
1678 (x.abs() - 0.5).copysign(x)
1679 }
1680 } else {
1681 x.round()
1682 }
1683 }
1684
1685 Ok(Float::F16([(f16::from_f64(round_ties_even(f64::from(e))))]))
1686 }
1687 })
1688 }
1689 crate::MathFunction::Fract => {
1690 component_wise_float!(self, span, [arg], |e| {
1691 Ok([e - e.floor()])
1694 })
1695 }
1696 crate::MathFunction::Trunc => {
1697 component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) })
1698 }
1699
1700 crate::MathFunction::Exp => {
1702 component_wise_float!(self, span, [arg], |e| {
1703 let result = e.exp();
1704 if result.is_finite() {
1705 Ok([result])
1706 } else {
1707 Err(ConstantEvaluatorError::Overflow("exp".into()))
1708 }
1709 })
1710 }
1711 crate::MathFunction::Exp2 => {
1712 component_wise_float!(self, span, [arg], |e| {
1713 let result = e.exp2();
1714 if result.is_finite() {
1715 Ok([result])
1716 } else {
1717 Err(ConstantEvaluatorError::Overflow("exp2".into()))
1718 }
1719 })
1720 }
1721 crate::MathFunction::Log => {
1722 component_wise_float!(self, span, [arg], |e| {
1723 if e > Zero::zero() {
1724 Ok([e.ln()])
1725 } else {
1726 Err(ConstantEvaluatorError::InvalidMathArgValue("log".into()))
1727 }
1728 })
1729 }
1730 crate::MathFunction::Log2 => {
1731 component_wise_float!(self, span, [arg], |e| {
1732 if e > Zero::zero() {
1733 Ok([e.log2()])
1734 } else {
1735 Err(ConstantEvaluatorError::InvalidMathArgValue("log2".into()))
1736 }
1737 })
1738 }
1739 crate::MathFunction::Pow => {
1740 component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1741 if e1 < Zero::zero()
1744 || e1.is_one() && e2.is_infinite()
1745 || e1.is_infinite() && e2.is_zero()
1746 || e1.is_zero() && e2.is_zero()
1747 {
1748 Err(ConstantEvaluatorError::InvalidMathArgValue("pow".into()))
1749 } else {
1750 let result = e1.powf(e2);
1751 if result.is_finite() {
1752 Ok([result])
1753 } else {
1754 Err(ConstantEvaluatorError::Overflow("pow".into()))
1755 }
1756 }
1757 })
1758 }
1759
1760 crate::MathFunction::Sign => {
1762 component_wise_signed!(self, span, [arg], |e| {
1763 Ok([if e.is_zero() {
1764 Zero::zero()
1765 } else {
1766 e.signum()
1767 }])
1768 })
1769 }
1770 crate::MathFunction::Fma => {
1771 component_wise_float!(
1772 self,
1773 span,
1774 [arg, arg1.unwrap(), arg2.unwrap()],
1775 |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) }
1776 )
1777 }
1778 crate::MathFunction::Step => {
1779 component_wise_float(self, span, [arg, arg1.unwrap()], |x| match x {
1780 Float::Abstract([edge, x]) => {
1781 Ok(Float::Abstract([if edge <= x { 1.0 } else { 0.0 }]))
1782 }
1783 Float::F32([edge, x]) => Ok(Float::F32([if edge <= x { 1.0 } else { 0.0 }])),
1784 Float::F16([edge, x]) => Ok(Float::F16([if edge <= x {
1785 f16::one()
1786 } else {
1787 f16::zero()
1788 }])),
1789 })
1790 }
1791 crate::MathFunction::Sqrt => {
1792 component_wise_float!(self, span, [arg], |e| {
1793 if e >= Zero::zero() {
1794 Ok([e.sqrt()])
1795 } else {
1796 Err(ConstantEvaluatorError::InvalidMathArgValue("sqrt".into()))
1797 }
1798 })
1799 }
1800 crate::MathFunction::InverseSqrt => {
1801 component_wise_float(self, span, [arg], |e| match e {
1802 Float::Abstract([e]) => Ok(Float::Abstract([1. / e.sqrt()])),
1803 Float::F32([e]) => Ok(Float::F32([1. / e.sqrt()])),
1804 Float::F16([e]) => Ok(Float::F16([f16::from_f32(1. / f32::from(e).sqrt())])),
1805 })
1806 }
1807
1808 crate::MathFunction::CountTrailingZeros => {
1810 component_wise_concrete_int!(self, span, [arg], |e| {
1811 #[allow(clippy::useless_conversion)]
1812 Ok([e
1813 .trailing_zeros()
1814 .try_into()
1815 .expect("bit count overflowed 32 bits, somehow!?")])
1816 })
1817 }
1818 crate::MathFunction::CountLeadingZeros => {
1819 component_wise_concrete_int!(self, span, [arg], |e| {
1820 #[allow(clippy::useless_conversion)]
1821 Ok([e
1822 .leading_zeros()
1823 .try_into()
1824 .expect("bit count overflowed 32 bits, somehow!?")])
1825 })
1826 }
1827 crate::MathFunction::CountOneBits => {
1828 component_wise_concrete_int!(self, span, [arg], |e| {
1829 #[allow(clippy::useless_conversion)]
1830 Ok([e
1831 .count_ones()
1832 .try_into()
1833 .expect("bit count overflowed 32 bits, somehow!?")])
1834 })
1835 }
1836 crate::MathFunction::ReverseBits => {
1837 component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
1838 }
1839 crate::MathFunction::ExtractBits => {
1840 let (offset, count) = self.bitfield_range(arg1.unwrap(), arg2.unwrap(), span)?;
1842 let e = self.extract_vec(arg, true)?;
1843
1844 let result = match_literal_vector!(match e => LiteralVector {
1845 I16 => |e| { extract_bits(e, offset, count)? },
1846 U16 => |e| { extract_bits(e, offset, count)? },
1847 I32 => |e| { extract_bits(e, offset, count)? },
1848 U32 => |e| { extract_bits(e, offset, count)? },
1849 I64 => |e| { extract_bits(e, offset, count)? },
1850 U64 => |e| { extract_bits(e, offset, count)? },
1851 })?;
1852 result.register_as_evaluated_expr(self, span)
1853 }
1854 crate::MathFunction::InsertBits => {
1855 let (offset, count) = self.bitfield_range(arg2.unwrap(), arg3.unwrap(), span)?;
1857 let e = self.extract_vec(arg, true)?;
1858 let newbits = self.extract_vec(arg1.unwrap(), true)?;
1859 if e.len() != newbits.len() {
1860 return Err(ConstantEvaluatorError::InvalidMathArg);
1861 }
1862
1863 let result = match_literal_vector!(match (e, newbits) => LiteralVector {
1864 I16 => |e, n| { insert_bits(e, n, offset, count)? },
1865 U16 => |e, n| { insert_bits(e, n, offset, count)? },
1866 I32 => |e, n| { insert_bits(e, n, offset, count)? },
1867 U32 => |e, n| { insert_bits(e, n, offset, count)? },
1868 I64 => |e, n| { insert_bits(e, n, offset, count)? },
1869 U64 => |e, n| { insert_bits(e, n, offset, count)? },
1870 })?;
1871 result.register_as_evaluated_expr(self, span)
1872 }
1873 crate::MathFunction::FirstTrailingBit => {
1874 component_wise_concrete_int(self, span, [arg], |ci| Ok(first_trailing_bit(ci)))
1875 }
1876 crate::MathFunction::FirstLeadingBit => {
1877 component_wise_concrete_int(self, span, [arg], |ci| Ok(first_leading_bit(ci)))
1878 }
1879
1880 crate::MathFunction::Dot4I8Packed => {
1882 self.packed_dot_product(arg, arg1.unwrap(), span, true)
1883 }
1884 crate::MathFunction::Dot4U8Packed => {
1885 self.packed_dot_product(arg, arg1.unwrap(), span, false)
1886 }
1887 crate::MathFunction::Cross => self.cross_product(arg, arg1.unwrap(), span),
1888 crate::MathFunction::Dot => {
1889 let e1 = self.extract_vec(arg, false)?;
1891 let e2 = self.extract_vec(arg1.unwrap(), false)?;
1892 if e1.len() != e2.len() {
1893 return Err(ConstantEvaluatorError::InvalidMathArg);
1894 }
1895
1896 fn int_dot_checked<P>(a: &[P], b: &[P]) -> Result<P, ConstantEvaluatorError>
1897 where
1898 P: num_traits::PrimInt + num_traits::CheckedAdd + num_traits::CheckedMul,
1899 {
1900 a.iter()
1901 .zip(b.iter())
1902 .map(|(&aa, bb)| aa.checked_mul(bb))
1903 .try_fold(P::zero(), |acc, x| {
1904 if let Some(x) = x {
1905 acc.checked_add(&x)
1906 } else {
1907 None
1908 }
1909 })
1910 .ok_or(ConstantEvaluatorError::Overflow(
1911 "in dot built-in".to_string(),
1912 ))
1913 }
1914
1915 fn int_dot_wrapping<P>(a: &[P], b: &[P]) -> P
1916 where
1917 P: num_traits::PrimInt + num_traits::WrappingAdd + num_traits::WrappingMul,
1918 {
1919 a.iter()
1920 .zip(b.iter())
1921 .map(|(&aa, bb)| aa.wrapping_mul(bb))
1922 .fold(P::zero(), |acc, x| acc.wrapping_add(&x))
1923 }
1924
1925 let result = match_literal_vector!(match (e1, e2) => Literal {
1926 Float => |e1, e2| {
1927 float_dot(e1, e2).ok_or_else(|| {
1928 ConstantEvaluatorError::Overflow("in mathfunction::dot".into())
1929 })?
1930 },
1931 AbstractInt => |e1, e2 | { int_dot_checked(e1, e2)? },
1932 I32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1933 U32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1934 })?;
1935 self.register_evaluated_expr(Expression::Literal(result), span)
1936 }
1937 crate::MathFunction::Length => {
1938 let e1 = self.extract_vec(arg, true)?;
1940
1941 let result = match_literal_vector!(match e1 => Literal {
1942 Float => |e1| {
1943 float_length(e1).ok_or_else(|| ConstantEvaluatorError::Overflow("length".into()))?
1944 },
1945 })?;
1946 self.register_evaluated_expr(Expression::Literal(result), span)
1947 }
1948 crate::MathFunction::Distance => {
1949 let e1 = self.extract_vec(arg, true)?;
1951 let e2 = self.extract_vec(arg1.unwrap(), true)?;
1952 if e1.len() != e2.len() {
1953 return Err(ConstantEvaluatorError::InvalidMathArg);
1954 }
1955
1956 fn float_distance<F>(a: &[F], b: &[F]) -> F
1957 where
1958 F: core::ops::Mul<F>,
1959 F: num_traits::Float + iter::Sum + core::ops::Sub,
1960 {
1961 if a.len() == 1 {
1962 (a[0] - b[0]).abs()
1964 } else {
1965 a.iter()
1966 .zip(b.iter())
1967 .map(|(&aa, &bb)| aa - bb)
1968 .map(|ei| ei * ei)
1969 .sum::<F>()
1970 .sqrt()
1971 }
1972 }
1973 let result = match_literal_vector!(match (e1, e2) => Literal {
1974 Float => |e1, e2| { float_distance(e1, e2) },
1975 })?;
1976 self.register_evaluated_expr(Expression::Literal(result), span)
1977 }
1978 crate::MathFunction::Normalize => {
1979 let e1 = self.extract_vec(arg, true)?;
1981
1982 fn float_normalize<F>(
1983 e: &[F],
1984 ) -> Result<ArrayVec<F, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
1985 where
1986 F: core::ops::Mul<F>,
1987 F: num_traits::Float + iter::Sum,
1988 {
1989 let len = match float_length(e) {
1990 Some(len) if !len.is_zero() => Ok(len),
1991 Some(_) => Err(ConstantEvaluatorError::InvalidMathArgValue(
1992 "normalize".into(),
1993 )),
1994 None => Err(ConstantEvaluatorError::Overflow("normalize".into())),
1995 }?;
1996
1997 let mut out = ArrayVec::new();
1998 for &ei in e {
1999 out.push(ei / len);
2000 }
2001 Ok(out)
2002 }
2003
2004 let result = match_literal_vector!(match e1 => LiteralVector {
2005 Float => |e1| { float_normalize(e1)? },
2006 })?;
2007 result.register_as_evaluated_expr(self, span)
2008 }
2009 crate::MathFunction::FaceForward => {
2010 let e1 = self.extract_vec(arg, false)?;
2012 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2013 let e3 = self.extract_vec(arg2.unwrap(), false)?;
2014 if e1.len() != e2.len() || e1.len() != e3.len() {
2015 return Err(ConstantEvaluatorError::InvalidMathArg);
2016 }
2017
2018 let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2019 Float => |e1, e2, e3| {
2020 float_face_forward(e1, e2, e3).ok_or_else(|| {
2021 ConstantEvaluatorError::Overflow("in mathfunction::faceforward".into())
2022 })?
2023 },
2024 })?;
2025 result.register_as_evaluated_expr(self, span)
2026 }
2027 crate::MathFunction::Reflect => {
2028 let e1 = self.extract_vec(arg, false)?;
2030 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2031 if e1.len() != e2.len() {
2032 return Err(ConstantEvaluatorError::InvalidMathArg);
2033 }
2034
2035 let result = match_literal_vector!(match (e1, e2) => LiteralVector {
2036 Float => |e1, e2| {
2037 float_reflect(e1, e2)
2038 .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::reflect".into()))?
2039 },
2040 })?;
2041 result.register_as_evaluated_expr(self, span)
2042 }
2043 crate::MathFunction::Refract => {
2044 let e1 = self.extract_vec(arg, false)?;
2046 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2047 let e3 = self.extract_vec(arg2.unwrap(), true)?;
2050 if e1.len() != e2.len() || e3.len() != 1 {
2051 return Err(ConstantEvaluatorError::InvalidMathArg);
2052 }
2053
2054 let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2055 Float => |e1, e2, e3| {
2056 float_refract(e1, e2, e3[0])
2057 .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::refract".into()))?
2058 },
2059 })?;
2060 result.register_as_evaluated_expr(self, span)
2061 }
2062
2063 crate::MathFunction::Modf
2065 | crate::MathFunction::Frexp
2066 | crate::MathFunction::Ldexp
2067 | crate::MathFunction::Outer
2068 | crate::MathFunction::Mix
2069 | crate::MathFunction::SmoothStep
2070 | crate::MathFunction::Inverse
2071 | crate::MathFunction::Transpose
2072 | crate::MathFunction::Determinant
2073 | crate::MathFunction::QuantizeToF16
2074 | crate::MathFunction::Pack4x8snorm
2075 | crate::MathFunction::Pack4x8unorm
2076 | crate::MathFunction::Pack2x16snorm
2077 | crate::MathFunction::Pack2x16unorm
2078 | crate::MathFunction::Pack2x16float
2079 | crate::MathFunction::Pack4xI8
2080 | crate::MathFunction::Pack4xU8
2081 | crate::MathFunction::Pack4xI8Clamp
2082 | crate::MathFunction::Pack4xU8Clamp
2083 | crate::MathFunction::Unpack4x8snorm
2084 | crate::MathFunction::Unpack4x8unorm
2085 | crate::MathFunction::Unpack2x16snorm
2086 | crate::MathFunction::Unpack2x16unorm
2087 | crate::MathFunction::Unpack2x16float
2088 | crate::MathFunction::Unpack4xI8
2089 | crate::MathFunction::Unpack4xU8 => Err(ConstantEvaluatorError::NotImplemented(
2090 format!("{fun:?} built-in function"),
2091 )),
2092 }
2093 }
2094
2095 fn packed_dot_product(
2097 &mut self,
2098 a: Handle<Expression>,
2099 b: Handle<Expression>,
2100 span: Span,
2101 signed: bool,
2102 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2103 let Expression::Literal(Literal::U32(a)) = self.expressions[a] else {
2104 return Err(ConstantEvaluatorError::InvalidMathArg);
2105 };
2106 let Expression::Literal(Literal::U32(b)) = self.expressions[b] else {
2107 return Err(ConstantEvaluatorError::InvalidMathArg);
2108 };
2109
2110 let result = if signed {
2111 Literal::I32(
2112 (a & 0xFF) as i8 as i32 * (b & 0xFF) as i8 as i32
2113 + ((a >> 8) & 0xFF) as i8 as i32 * ((b >> 8) & 0xFF) as i8 as i32
2114 + ((a >> 16) & 0xFF) as i8 as i32 * ((b >> 16) & 0xFF) as i8 as i32
2115 + ((a >> 24) & 0xFF) as i8 as i32 * ((b >> 24) & 0xFF) as i8 as i32,
2116 )
2117 } else {
2118 Literal::U32(
2119 (a & 0xFF) * (b & 0xFF)
2120 + ((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)
2121 + ((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)
2122 + ((a >> 24) & 0xFF) * ((b >> 24) & 0xFF),
2123 )
2124 };
2125
2126 self.register_evaluated_expr(Expression::Literal(result), span)
2127 }
2128
2129 fn cross_product(
2131 &mut self,
2132 a: Handle<Expression>,
2133 b: Handle<Expression>,
2134 span: Span,
2135 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2136 use Literal as Li;
2137
2138 let (a, ty) = self.extract_vec_with_size::<3>(a)?;
2139 let (b, _) = self.extract_vec_with_size::<3>(b)?;
2140
2141 let product = match (a, b) {
2142 (
2143 [Li::AbstractInt(a0), Li::AbstractInt(a1), Li::AbstractInt(a2)],
2144 [Li::AbstractInt(b0), Li::AbstractInt(b1), Li::AbstractInt(b2)],
2145 ) => {
2146 let p = cross_product(
2151 [a0 as f64, a1 as f64, a2 as f64],
2152 [b0 as f64, b1 as f64, b2 as f64],
2153 );
2154 [
2155 Li::AbstractFloat(p[0]),
2156 Li::AbstractFloat(p[1]),
2157 Li::AbstractFloat(p[2]),
2158 ]
2159 }
2160 (
2161 [Li::AbstractFloat(a0), Li::AbstractFloat(a1), Li::AbstractFloat(a2)],
2162 [Li::AbstractFloat(b0), Li::AbstractFloat(b1), Li::AbstractFloat(b2)],
2163 ) => {
2164 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2165 [
2166 Li::AbstractFloat(p[0]),
2167 Li::AbstractFloat(p[1]),
2168 Li::AbstractFloat(p[2]),
2169 ]
2170 }
2171 ([Li::F16(a0), Li::F16(a1), Li::F16(a2)], [Li::F16(b0), Li::F16(b1), Li::F16(b2)]) => {
2172 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2173 [Li::F16(p[0]), Li::F16(p[1]), Li::F16(p[2])]
2174 }
2175 ([Li::F32(a0), Li::F32(a1), Li::F32(a2)], [Li::F32(b0), Li::F32(b1), Li::F32(b2)]) => {
2176 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2177 [Li::F32(p[0]), Li::F32(p[1]), Li::F32(p[2])]
2178 }
2179 ([Li::F64(a0), Li::F64(a1), Li::F64(a2)], [Li::F64(b0), Li::F64(b1), Li::F64(b2)]) => {
2180 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2181 [Li::F64(p[0]), Li::F64(p[1]), Li::F64(p[2])]
2182 }
2183 _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2184 };
2185
2186 let p0 = self.register_evaluated_expr(Expression::Literal(product[0]), span)?;
2187 let p1 = self.register_evaluated_expr(Expression::Literal(product[1]), span)?;
2188 let p2 = self.register_evaluated_expr(Expression::Literal(product[2]), span)?;
2189
2190 self.register_evaluated_expr(
2191 Expression::Compose {
2192 ty,
2193 components: vec![p0, p1, p2],
2194 },
2195 span,
2196 )
2197 }
2198
2199 fn extract_vec_with_size<const N: usize>(
2207 &mut self,
2208 expr: Handle<Expression>,
2209 ) -> Result<([Literal; N], Handle<Type>), ConstantEvaluatorError> {
2210 let span = self.expressions.get_span(expr);
2211 let expr = self.eval_zero_value_and_splat(expr, span)?;
2212 let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2213 return Err(ConstantEvaluatorError::InvalidMathArg);
2214 };
2215
2216 let mut value = [Literal::Bool(false); N];
2217 for (component, elt) in
2218 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2219 .zip(value.iter_mut())
2220 {
2221 let Expression::Literal(literal) = self.expressions[component] else {
2222 return Err(ConstantEvaluatorError::InvalidMathArg);
2223 };
2224 *elt = literal;
2225 }
2226
2227 Ok((value, ty))
2228 }
2229
2230 fn extract_vec(
2238 &mut self,
2239 expr: Handle<Expression>,
2240 allow_single: bool,
2241 ) -> Result<LiteralVector, ConstantEvaluatorError> {
2242 let span = self.expressions.get_span(expr);
2243 let expr = self.eval_zero_value_and_splat(expr, span)?;
2244
2245 match self.expressions[expr] {
2246 Expression::Literal(literal) if allow_single => {
2247 Ok(LiteralVector::from_literal(literal))
2248 }
2249 Expression::Compose { ty, ref components } => {
2250 let mut components_out = ArrayVec::<Literal, { crate::VectorSize::MAX }>::new();
2251 for expr in
2252 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2253 {
2254 match self.expressions[expr] {
2255 Expression::Literal(l) => components_out.push(l),
2256 _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2257 }
2258 }
2259 LiteralVector::from_literal_vec(components_out)
2260 }
2261 _ => Err(ConstantEvaluatorError::InvalidMathArg),
2262 }
2263 }
2264
2265 fn bitfield_range(
2268 &mut self,
2269 offset: Handle<Expression>,
2270 count: Handle<Expression>,
2271 span: Span,
2272 ) -> Result<(u32, u32), ConstantEvaluatorError> {
2273 let offset = self.eval_zero_value_and_splat(offset, span)?;
2274 let count = self.eval_zero_value_and_splat(count, span)?;
2275
2276 match (&self.expressions[offset], &self.expressions[count]) {
2277 (
2278 &Expression::Literal(Literal::U32(offset)),
2279 &Expression::Literal(Literal::U32(count)),
2280 ) => Ok((offset, count)),
2281 _ => Err(ConstantEvaluatorError::InvalidMathArg),
2282 }
2283 }
2284
2285 fn array_length(
2286 &mut self,
2287 array: Handle<Expression>,
2288 span: Span,
2289 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2290 match self.expressions[array] {
2291 Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => {
2292 match self.types[ty].inner {
2293 TypeInner::Array { size, .. } => match size {
2294 ArraySize::Constant(len) => {
2295 let expr = Expression::Literal(Literal::U32(len.get()));
2296 self.register_evaluated_expr(expr, span)
2297 }
2298 ArraySize::Pending(_) => Err(ConstantEvaluatorError::ArrayLengthOverridden),
2299 ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic),
2300 },
2301 _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2302 }
2303 }
2304 _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2305 }
2306 }
2307
2308 fn access(
2309 &mut self,
2310 base: Handle<Expression>,
2311 index: usize,
2312 span: Span,
2313 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2314 match self.expressions[base] {
2315 Expression::ZeroValue(ty) => {
2316 let ty_inner = &self.types[ty].inner;
2317 let components = ty_inner
2318 .components()
2319 .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2320
2321 if index >= components as usize {
2322 Err(ConstantEvaluatorError::InvalidAccessBase)
2323 } else {
2324 let ty_res = ty_inner
2325 .component_type(index)
2326 .ok_or(ConstantEvaluatorError::InvalidAccessIndex)?;
2327 let ty = match ty_res {
2328 crate::proc::TypeResolution::Handle(ty) => ty,
2329 crate::proc::TypeResolution::Value(inner) => {
2330 self.types.insert(Type { name: None, inner }, span)
2331 }
2332 };
2333 self.register_evaluated_expr(Expression::ZeroValue(ty), span)
2334 }
2335 }
2336 Expression::Splat { size, value } => {
2337 if index >= size as usize {
2338 Err(ConstantEvaluatorError::InvalidAccessBase)
2339 } else {
2340 Ok(value)
2341 }
2342 }
2343 Expression::Compose { ty, ref components } => {
2344 let _ = self.types[ty]
2345 .inner
2346 .components()
2347 .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2348
2349 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2350 .nth(index)
2351 .ok_or(ConstantEvaluatorError::InvalidAccessIndex)
2352 }
2353 _ => Err(ConstantEvaluatorError::InvalidAccessBase),
2354 }
2355 }
2356
2357 fn eval_zero_value_and_splat(
2364 &mut self,
2365 mut expr: Handle<Expression>,
2366 span: Span,
2367 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2368 if let Expression::Compose { ty, ref components } = self.expressions[expr] {
2371 let components = components
2372 .clone()
2373 .iter()
2374 .map(|component| self.eval_zero_value_and_splat(*component, span))
2375 .collect::<Result<_, _>>()?;
2376 expr = self.register_evaluated_expr(Expression::Compose { ty, components }, span)?;
2377 }
2378
2379 if let Expression::Splat { size, value } = self.expressions[expr] {
2383 expr = self.splat(value, size, span)?;
2384 }
2385 if let Expression::ZeroValue(ty) = self.expressions[expr] {
2386 expr = self.eval_zero_value_impl(ty, span)?;
2387 }
2388 Ok(expr)
2389 }
2390
2391 fn eval_zero_value(
2397 &mut self,
2398 expr: Handle<Expression>,
2399 span: Span,
2400 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2401 match self.expressions[expr] {
2402 Expression::ZeroValue(ty) => self.eval_zero_value_impl(ty, span),
2403 _ => Ok(expr),
2404 }
2405 }
2406
2407 fn eval_zero_value_impl(
2413 &mut self,
2414 ty: Handle<Type>,
2415 span: Span,
2416 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2417 match self.types[ty].inner {
2418 TypeInner::Scalar(scalar) => {
2419 let expr = Expression::Literal(
2420 Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
2421 );
2422 self.register_evaluated_expr(expr, span)
2423 }
2424 TypeInner::Vector { size, scalar } => {
2425 let scalar_ty = self.types.insert(
2426 Type {
2427 name: None,
2428 inner: TypeInner::Scalar(scalar),
2429 },
2430 span,
2431 );
2432 let el = self.eval_zero_value_impl(scalar_ty, span)?;
2433 let expr = Expression::Compose {
2434 ty,
2435 components: vec![el; size as usize],
2436 };
2437 self.register_evaluated_expr(expr, span)
2438 }
2439 TypeInner::Matrix {
2440 columns,
2441 rows,
2442 scalar,
2443 } => {
2444 let vec_ty = self.types.insert(
2445 Type {
2446 name: None,
2447 inner: TypeInner::Vector { size: rows, scalar },
2448 },
2449 span,
2450 );
2451 let el = self.eval_zero_value_impl(vec_ty, span)?;
2452 let expr = Expression::Compose {
2453 ty,
2454 components: vec![el; columns as usize],
2455 };
2456 self.register_evaluated_expr(expr, span)
2457 }
2458 TypeInner::Array {
2459 base,
2460 size: ArraySize::Constant(size),
2461 ..
2462 } => {
2463 let el = self.eval_zero_value_impl(base, span)?;
2464 let expr = Expression::Compose {
2465 ty,
2466 components: vec![el; size.get() as usize],
2467 };
2468 self.register_evaluated_expr(expr, span)
2469 }
2470 TypeInner::Struct { ref members, .. } => {
2471 let types: Vec<_> = members.iter().map(|m| m.ty).collect();
2472 let mut components = Vec::with_capacity(members.len());
2473 for ty in types {
2474 components.push(self.eval_zero_value_impl(ty, span)?);
2475 }
2476 let expr = Expression::Compose { ty, components };
2477 self.register_evaluated_expr(expr, span)
2478 }
2479 _ => Err(ConstantEvaluatorError::TypeNotConstructible),
2480 }
2481 }
2482
2483 pub fn cast(
2487 &mut self,
2488 expr: Handle<Expression>,
2489 target: crate::Scalar,
2490 span: Span,
2491 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2492 use crate::Scalar as Sc;
2493
2494 let expr = self.eval_zero_value(expr, span)?;
2495
2496 let make_error = || -> Result<_, ConstantEvaluatorError> {
2497 let from = format!("{:?} {:?}", expr, self.expressions[expr]);
2498
2499 #[cfg(feature = "wgsl-in")]
2500 let to = target.to_wgsl_for_diagnostics();
2501
2502 #[cfg(not(feature = "wgsl-in"))]
2503 let to = format!("{target:?}");
2504
2505 Err(ConstantEvaluatorError::InvalidCastArg { from, to })
2506 };
2507
2508 use crate::proc::type_methods::IntFloatLimits;
2509
2510 let expr = match self.expressions[expr] {
2511 Expression::Literal(literal) => {
2512 let literal = match target {
2513 Sc::I16 => Literal::I16(match literal {
2514 Literal::I16(v) => v,
2515 Literal::U16(v) => v as i16,
2516 Literal::I32(v) => v as i16,
2517 Literal::U32(v) => v as i16,
2518 Literal::F32(v) => v.clamp(i16::MIN as f32, i16::MAX as f32) as i16,
2519 Literal::F16(v) => {
2520 f16::to_f32(v).clamp(i16::MIN as f32, i16::MAX as f32) as i16
2521 }
2522 Literal::Bool(v) => v as i16,
2523 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2524 return make_error();
2525 }
2526 Literal::AbstractInt(v) => v as i16,
2527 Literal::AbstractFloat(v) => v as i16,
2528 }),
2529 Sc::U16 => Literal::U16(match literal {
2530 Literal::I16(v) => v as u16,
2531 Literal::U16(v) => v,
2532 Literal::I32(v) => v as u16,
2533 Literal::U32(v) => v as u16,
2534 Literal::F32(v) => v.clamp(u16::MIN as f32, u16::MAX as f32) as u16,
2535 Literal::F16(v) => f16::to_u16(&v.max(f16::ZERO)).unwrap(),
2536 Literal::Bool(v) => v as u16,
2537 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2538 return make_error();
2539 }
2540 Literal::AbstractInt(v) => v as u16,
2541 Literal::AbstractFloat(v) => v as u16,
2542 }),
2543 Sc::I32 => Literal::I32(match literal {
2544 Literal::I16(v) => v as i32,
2545 Literal::U16(v) => v as i32,
2546 Literal::I32(v) => v,
2547 Literal::U32(v) => v as i32,
2548 Literal::F32(v) => v.clamp(i32::min_float(), i32::max_float()) as i32,
2549 Literal::F16(v) => f16::to_i32(&v).unwrap(), Literal::Bool(v) => v as i32,
2551 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2552 return make_error();
2553 }
2554 Literal::AbstractInt(v) => i32::try_from_abstract(v)?,
2555 Literal::AbstractFloat(v) => i32::try_from_abstract(v)?,
2556 }),
2557 Sc::U32 => Literal::U32(match literal {
2558 Literal::I16(v) => v as u32,
2559 Literal::U16(v) => v as u32,
2560 Literal::I32(v) => v as u32,
2561 Literal::U32(v) => v,
2562 Literal::F32(v) => v.clamp(u32::min_float(), u32::max_float()) as u32,
2563 Literal::F16(v) => f16::to_u32(&v.max(f16::ZERO)).unwrap(),
2565 Literal::Bool(v) => v as u32,
2566 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2567 return make_error();
2568 }
2569 Literal::AbstractInt(v) => u32::try_from_abstract(v)?,
2570 Literal::AbstractFloat(v) => u32::try_from_abstract(v)?,
2571 }),
2572 Sc::I64 => Literal::I64(match literal {
2573 Literal::I16(v) => v as i64,
2574 Literal::U16(v) => v as i64,
2575 Literal::I32(v) => v as i64,
2576 Literal::U32(v) => v as i64,
2577 Literal::F32(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2578 Literal::Bool(v) => v as i64,
2579 Literal::F64(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2580 Literal::I64(v) => v,
2581 Literal::U64(v) => v as i64,
2582 Literal::F16(v) => f16::to_i64(&v).unwrap(), Literal::AbstractInt(v) => i64::try_from_abstract(v)?,
2584 Literal::AbstractFloat(v) => i64::try_from_abstract(v)?,
2585 }),
2586 Sc::U64 => Literal::U64(match literal {
2587 Literal::I16(v) => v as u64,
2588 Literal::U16(v) => v as u64,
2589 Literal::I32(v) => v as u64,
2590 Literal::U32(v) => v as u64,
2591 Literal::F32(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2592 Literal::Bool(v) => v as u64,
2593 Literal::F64(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2594 Literal::I64(v) => v as u64,
2595 Literal::U64(v) => v,
2596 Literal::F16(v) => f16::to_u64(&v.max(f16::ZERO)).unwrap(),
2598 Literal::AbstractInt(v) => u64::try_from_abstract(v)?,
2599 Literal::AbstractFloat(v) => u64::try_from_abstract(v)?,
2600 }),
2601 Sc::F16 => Literal::F16(match literal {
2602 Literal::F16(v) => v,
2603 Literal::F32(v) => f16::from_f32(v),
2604 Literal::F64(v) => f16::from_f64(v),
2605 Literal::Bool(v) => f16::from_u32(v as u32).unwrap(),
2606 Literal::I16(v) => f16::from_f32(v as f32),
2607 Literal::U16(v) => f16::from_f32(v as f32),
2608 Literal::I64(v) => f16::from_i64(v).unwrap(),
2609 Literal::U64(v) => f16::from_u64(v).unwrap(),
2610 Literal::I32(v) => f16::from_i32(v).unwrap(),
2611 Literal::U32(v) => f16::from_u32(v).unwrap(),
2612 Literal::AbstractFloat(v) => f16::try_from_abstract(v)?,
2613 Literal::AbstractInt(v) => f16::try_from_abstract(v)?,
2614 }),
2615 Sc::F32 => Literal::F32(match literal {
2616 Literal::I16(v) => v as f32,
2617 Literal::U16(v) => v as f32,
2618 Literal::I32(v) => v as f32,
2619 Literal::U32(v) => v as f32,
2620 Literal::F32(v) => v,
2621 Literal::Bool(v) => v as u32 as f32,
2622 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2623 return make_error();
2624 }
2625 Literal::F16(v) => f16::to_f32(v),
2626 Literal::AbstractInt(v) => f32::try_from_abstract(v)?,
2627 Literal::AbstractFloat(v) => f32::try_from_abstract(v)?,
2628 }),
2629 Sc::F64 => Literal::F64(match literal {
2630 Literal::I16(v) => v as f64,
2631 Literal::U16(v) => v as f64,
2632 Literal::I32(v) => v as f64,
2633 Literal::U32(v) => v as f64,
2634 Literal::F16(v) => f16::to_f64(v),
2635 Literal::F32(v) => v as f64,
2636 Literal::F64(v) => v,
2637 Literal::Bool(v) => v as u32 as f64,
2638 Literal::I64(_) | Literal::U64(_) => return make_error(),
2639 Literal::AbstractInt(v) => f64::try_from_abstract(v)?,
2640 Literal::AbstractFloat(v) => f64::try_from_abstract(v)?,
2641 }),
2642 Sc::BOOL => Literal::Bool(match literal {
2643 Literal::I16(v) => v != 0,
2644 Literal::U16(v) => v != 0,
2645 Literal::I32(v) => v != 0,
2646 Literal::U32(v) => v != 0,
2647 Literal::F32(v) => v != 0.0,
2648 Literal::F16(v) => v != f16::zero(),
2649 Literal::Bool(v) => v,
2650 Literal::AbstractInt(v) => v != 0,
2651 Literal::AbstractFloat(v) => v != 0.0,
2652 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2653 return make_error();
2654 }
2655 }),
2656 Sc::ABSTRACT_FLOAT => Literal::AbstractFloat(match literal {
2657 Literal::AbstractInt(v) => {
2658 v as f64
2663 }
2664 Literal::AbstractFloat(v) => v,
2665 _ => return make_error(),
2666 }),
2667 Sc::ABSTRACT_INT => Literal::AbstractInt(match literal {
2668 Literal::AbstractInt(v) => v,
2669 _ => return make_error(),
2670 }),
2671 _ => {
2672 log::debug!("Constant evaluator refused to convert value to {target:?}");
2673 return make_error();
2674 }
2675 };
2676 Expression::Literal(literal)
2677 }
2678 Expression::Compose {
2679 ty,
2680 components: ref src_components,
2681 } => {
2682 let ty_inner = match self.types[ty].inner {
2683 TypeInner::Vector { size, .. } => TypeInner::Vector {
2684 size,
2685 scalar: target,
2686 },
2687 TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix {
2688 columns,
2689 rows,
2690 scalar: target,
2691 },
2692 _ => return make_error(),
2693 };
2694
2695 let mut components = src_components.clone();
2696 for component in &mut components {
2697 *component = self.cast(*component, target, span)?;
2698 }
2699
2700 let ty = self.types.insert(
2701 Type {
2702 name: None,
2703 inner: ty_inner,
2704 },
2705 span,
2706 );
2707
2708 Expression::Compose { ty, components }
2709 }
2710 Expression::Splat { size, value } => {
2711 let value_span = self.expressions.get_span(value);
2712 let cast_value = self.cast(value, target, value_span)?;
2713 Expression::Splat {
2714 size,
2715 value: cast_value,
2716 }
2717 }
2718 _ => return make_error(),
2719 };
2720
2721 self.register_evaluated_expr(expr, span)
2722 }
2723
2724 pub fn cast_array(
2737 &mut self,
2738 expr: Handle<Expression>,
2739 target: crate::Scalar,
2740 span: Span,
2741 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2742 let expr = self.check_and_get(expr)?;
2743
2744 let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2745 return self.cast(expr, target, span);
2746 };
2747
2748 let TypeInner::Array {
2749 base: _,
2750 size,
2751 stride: _,
2752 } = self.types[ty].inner
2753 else {
2754 return self.cast(expr, target, span);
2755 };
2756
2757 let mut components = components.clone();
2758 for component in &mut components {
2759 *component = self.cast_array(*component, target, span)?;
2760 }
2761
2762 let first = components.first().unwrap();
2763 let new_base = match self.resolve_type(*first)? {
2764 crate::proc::TypeResolution::Handle(ty) => ty,
2765 crate::proc::TypeResolution::Value(inner) => {
2766 self.types.insert(Type { name: None, inner }, span)
2767 }
2768 };
2769 let mut layouter = core::mem::take(self.layouter);
2770 layouter.update(self.to_ctx()).map_err(|err| {
2771 let crate::proc::LayoutErrorInner::TooLarge = err.inner else {
2774 unreachable!("unexpected layout error: {err:?}");
2775 };
2776 ConstantEvaluatorError::TypeTooLarge(err.ty)
2777 })?;
2778 *self.layouter = layouter;
2779
2780 let new_base_stride = self.layouter[new_base].to_stride();
2781 let new_array_ty = self.types.insert(
2782 Type {
2783 name: None,
2784 inner: TypeInner::Array {
2785 base: new_base,
2786 size,
2787 stride: new_base_stride,
2788 },
2789 },
2790 span,
2791 );
2792
2793 let compose = Expression::Compose {
2794 ty: new_array_ty,
2795 components,
2796 };
2797 self.register_evaluated_expr(compose, span)
2798 }
2799
2800 fn unary_op(
2801 &mut self,
2802 op: UnaryOperator,
2803 expr: Handle<Expression>,
2804 span: Span,
2805 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2806 let expr = self.eval_zero_value_and_splat(expr, span)?;
2807
2808 let expr = match self.expressions[expr] {
2809 Expression::Literal(value) => Expression::Literal(match op {
2810 UnaryOperator::Negate => match value {
2811 Literal::I16(v) => Literal::I16(v.wrapping_neg()),
2812 Literal::I32(v) => Literal::I32(v.wrapping_neg()),
2813 Literal::I64(v) => Literal::I64(v.wrapping_neg()),
2814 Literal::F32(v) => Literal::F32(-v),
2815 Literal::F16(v) => Literal::F16(-v),
2816 Literal::F64(v) => Literal::F64(-v),
2817 Literal::AbstractInt(v) => Literal::AbstractInt(v.wrapping_neg()),
2818 Literal::AbstractFloat(v) => Literal::AbstractFloat(-v),
2819 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2820 },
2821 UnaryOperator::LogicalNot => match value {
2822 Literal::Bool(v) => Literal::Bool(!v),
2823 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2824 },
2825 UnaryOperator::BitwiseNot => match value {
2826 Literal::I16(v) => Literal::I16(!v),
2827 Literal::I32(v) => Literal::I32(!v),
2828 Literal::I64(v) => Literal::I64(!v),
2829 Literal::U16(v) => Literal::U16(!v),
2830 Literal::U32(v) => Literal::U32(!v),
2831 Literal::U64(v) => Literal::U64(!v),
2832 Literal::AbstractInt(v) => Literal::AbstractInt(!v),
2833 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2834 },
2835 }),
2836 Expression::Compose {
2837 ty,
2838 components: ref src_components,
2839 } => {
2840 match self.types[ty].inner {
2841 TypeInner::Vector { .. } => (),
2842 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2843 }
2844
2845 let mut components = src_components.clone();
2846 for component in &mut components {
2847 *component = self.unary_op(op, *component, span)?;
2848 }
2849
2850 Expression::Compose { ty, components }
2851 }
2852 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2853 };
2854
2855 self.register_evaluated_expr(expr, span)
2856 }
2857
2858 fn binary_op(
2859 &mut self,
2860 op: BinaryOperator,
2861 left: Handle<Expression>,
2862 right: Handle<Expression>,
2863 span: Span,
2864 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2865 let left = self.eval_zero_value_and_splat(left, span)?;
2866 let right = self.eval_zero_value_and_splat(right, span)?;
2867
2868 let expr = match (&self.expressions[left], &self.expressions[right]) {
2873 (&Expression::Literal(left_value), &Expression::Literal(right_value)) => {
2874 if !matches!(op, BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight)
2875 && core::mem::discriminant(&left_value) != core::mem::discriminant(&right_value)
2876 {
2877 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2878 }
2879
2880 if matches!(
2881 (left_value, op),
2882 (
2883 Literal::Bool(_),
2884 BinaryOperator::Less
2885 | BinaryOperator::LessEqual
2886 | BinaryOperator::Greater
2887 | BinaryOperator::GreaterEqual
2888 )
2889 ) {
2890 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2891 }
2892
2893 let literal = match op {
2894 BinaryOperator::Equal => Literal::Bool(left_value == right_value),
2895 BinaryOperator::NotEqual => Literal::Bool(left_value != right_value),
2896 BinaryOperator::Less => Literal::Bool(left_value < right_value),
2897 BinaryOperator::LessEqual => Literal::Bool(left_value <= right_value),
2898 BinaryOperator::Greater => Literal::Bool(left_value > right_value),
2899 BinaryOperator::GreaterEqual => Literal::Bool(left_value >= right_value),
2900
2901 _ => match (left_value, right_value) {
2902 (Literal::I16(a), Literal::I16(b)) => Literal::I16(match op {
2903 BinaryOperator::Add => a.wrapping_add(b),
2904 BinaryOperator::Subtract => a.wrapping_sub(b),
2905 BinaryOperator::Multiply => a.wrapping_mul(b),
2906 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2907 if b == 0 {
2908 ConstantEvaluatorError::DivisionByZero
2909 } else {
2910 ConstantEvaluatorError::Overflow("division".into())
2911 }
2912 })?,
2913 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2914 if b == 0 {
2915 ConstantEvaluatorError::RemainderByZero
2916 } else {
2917 ConstantEvaluatorError::Overflow("remainder".into())
2918 }
2919 })?,
2920 BinaryOperator::And => a & b,
2921 BinaryOperator::ExclusiveOr => a ^ b,
2922 BinaryOperator::InclusiveOr => a | b,
2923 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2924 }),
2925 (Literal::I16(a), Literal::U32(b)) => Literal::I16(match op {
2926 BinaryOperator::ShiftLeft => {
2927 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2928 return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2929 }
2930 a.checked_shl(b)
2931 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2932 }
2933 BinaryOperator::ShiftRight => a
2934 .checked_shr(b)
2935 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2936 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2937 }),
2938 (Literal::U16(a), Literal::U16(b)) => Literal::U16(match op {
2939 BinaryOperator::Add => a.wrapping_add(b),
2940 BinaryOperator::Subtract => a.wrapping_sub(b),
2941 BinaryOperator::Multiply => a.wrapping_mul(b),
2942 BinaryOperator::Divide => a
2943 .checked_div(b)
2944 .ok_or(ConstantEvaluatorError::DivisionByZero)?,
2945 BinaryOperator::Modulo => a
2946 .checked_rem(b)
2947 .ok_or(ConstantEvaluatorError::RemainderByZero)?,
2948 BinaryOperator::And => a & b,
2949 BinaryOperator::ExclusiveOr => a ^ b,
2950 BinaryOperator::InclusiveOr => a | b,
2951 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2952 }),
2953 (Literal::U16(a), Literal::U32(b)) => Literal::U16(match op {
2954 BinaryOperator::ShiftLeft => a
2955 .checked_mul(
2956 1u16.checked_shl(b)
2957 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2958 )
2959 .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
2960 BinaryOperator::ShiftRight => a
2961 .checked_shr(b)
2962 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2963 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2964 }),
2965 (Literal::I32(a), Literal::I32(b)) => Literal::I32(match op {
2966 BinaryOperator::Add => a.wrapping_add(b),
2967 BinaryOperator::Subtract => a.wrapping_sub(b),
2968 BinaryOperator::Multiply => a.wrapping_mul(b),
2969 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2970 if b == 0 {
2971 ConstantEvaluatorError::DivisionByZero
2972 } else {
2973 ConstantEvaluatorError::Overflow("division".into())
2974 }
2975 })?,
2976 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2977 if b == 0 {
2978 ConstantEvaluatorError::RemainderByZero
2979 } else {
2980 ConstantEvaluatorError::Overflow("remainder".into())
2981 }
2982 })?,
2983 BinaryOperator::And => a & b,
2984 BinaryOperator::ExclusiveOr => a ^ b,
2985 BinaryOperator::InclusiveOr => a | b,
2986 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2987 }),
2988 (Literal::I32(a), Literal::U32(b)) => Literal::I32(match op {
2989 BinaryOperator::ShiftLeft => {
2990 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2991 return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2992 }
2993 a.checked_shl(b)
2994 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2995 }
2996 BinaryOperator::ShiftRight => a
2997 .checked_shr(b)
2998 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2999 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3000 }),
3001 (Literal::U32(a), Literal::U32(b)) => Literal::U32(match op {
3002 BinaryOperator::Add => a.wrapping_add(b),
3003 BinaryOperator::Subtract => a.wrapping_sub(b),
3004 BinaryOperator::Multiply => a.wrapping_mul(b),
3005 BinaryOperator::Divide => a
3006 .checked_div(b)
3007 .ok_or(ConstantEvaluatorError::DivisionByZero)?,
3008 BinaryOperator::Modulo => a
3009 .checked_rem(b)
3010 .ok_or(ConstantEvaluatorError::RemainderByZero)?,
3011 BinaryOperator::And => a & b,
3012 BinaryOperator::ExclusiveOr => a ^ b,
3013 BinaryOperator::InclusiveOr => a | b,
3014 BinaryOperator::ShiftLeft => a
3015 .checked_mul(
3016 1u32.checked_shl(b)
3017 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3018 )
3019 .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
3020 BinaryOperator::ShiftRight => a
3021 .checked_shr(b)
3022 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3023 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3024 }),
3025 (Literal::F32(a), Literal::F32(b)) => Literal::F32(match op {
3026 BinaryOperator::Add => a + b,
3027 BinaryOperator::Subtract => a - b,
3028 BinaryOperator::Multiply => a * b,
3029 BinaryOperator::Divide => a / b,
3030 BinaryOperator::Modulo => a % b,
3031 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3032 }),
3033 (Literal::AbstractInt(a), Literal::U32(b)) => {
3034 Literal::AbstractInt(match op {
3035 BinaryOperator::ShiftLeft => {
3036 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
3037 return Err(ConstantEvaluatorError::Overflow(
3038 "<<".to_string(),
3039 ));
3040 }
3041 a.checked_shl(b).unwrap_or(0)
3042 }
3043 BinaryOperator::ShiftRight => a.checked_shr(b).unwrap_or(0),
3044 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3045 })
3046 }
3047 (Literal::F16(a), Literal::F16(b)) => {
3048 let result = match op {
3049 BinaryOperator::Add => a + b,
3050 BinaryOperator::Subtract => a - b,
3051 BinaryOperator::Multiply => a * b,
3052 BinaryOperator::Divide => a / b,
3053 BinaryOperator::Modulo => a % b,
3054 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3055 };
3056 if !result.is_finite() {
3057 return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3058 }
3059 Literal::F16(result)
3060 }
3061 (Literal::AbstractInt(a), Literal::AbstractInt(b)) => {
3062 Literal::AbstractInt(match op {
3063 BinaryOperator::Add => a.checked_add(b).ok_or_else(|| {
3064 ConstantEvaluatorError::Overflow("addition".into())
3065 })?,
3066 BinaryOperator::Subtract => a.checked_sub(b).ok_or_else(|| {
3067 ConstantEvaluatorError::Overflow("subtraction".into())
3068 })?,
3069 BinaryOperator::Multiply => a.checked_mul(b).ok_or_else(|| {
3070 ConstantEvaluatorError::Overflow("multiplication".into())
3071 })?,
3072 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
3073 if b == 0 {
3074 ConstantEvaluatorError::DivisionByZero
3075 } else {
3076 ConstantEvaluatorError::Overflow("division".into())
3077 }
3078 })?,
3079 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
3080 if b == 0 {
3081 ConstantEvaluatorError::RemainderByZero
3082 } else {
3083 ConstantEvaluatorError::Overflow("remainder".into())
3084 }
3085 })?,
3086 BinaryOperator::And => a & b,
3087 BinaryOperator::ExclusiveOr => a ^ b,
3088 BinaryOperator::InclusiveOr => a | b,
3089 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3090 })
3091 }
3092 (Literal::AbstractFloat(a), Literal::AbstractFloat(b)) => {
3093 let result = match op {
3094 BinaryOperator::Add => a + b,
3095 BinaryOperator::Subtract => a - b,
3096 BinaryOperator::Multiply => a * b,
3097 BinaryOperator::Divide => a / b,
3098 BinaryOperator::Modulo => a % b,
3099 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3100 };
3101 if !result.is_finite() {
3102 return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3103 }
3104 Literal::AbstractFloat(result)
3105 }
3106 (Literal::Bool(a), Literal::Bool(b)) => Literal::Bool(match op {
3107 BinaryOperator::LogicalAnd => a && b,
3108 BinaryOperator::LogicalOr => a || b,
3109 BinaryOperator::And => a & b,
3110 BinaryOperator::InclusiveOr => a | b,
3111 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3112 }),
3113 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3114 },
3115 };
3116 Expression::Literal(literal)
3117 }
3118 (
3119 &Expression::Compose {
3120 components: ref src_components,
3121 ty,
3122 },
3123 &Expression::Literal(_),
3124 ) => {
3125 if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3126 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3127 }
3128 let mut components = src_components.clone();
3129 for component in &mut components {
3130 *component = self.binary_op(op, *component, right, span)?;
3131 }
3132 Expression::Compose { ty, components }
3133 }
3134 (
3135 &Expression::Literal(_),
3136 &Expression::Compose {
3137 components: ref src_components,
3138 ty,
3139 },
3140 ) => {
3141 if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3142 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3143 }
3144 let mut components = src_components.clone();
3145 for component in &mut components {
3146 *component = self.binary_op(op, left, *component, span)?;
3147 }
3148 Expression::Compose { ty, components }
3149 }
3150 (
3151 &Expression::Compose {
3152 components: ref left_components,
3153 ty: left_ty,
3154 },
3155 &Expression::Compose {
3156 components: ref right_components,
3157 ty: right_ty,
3158 },
3159 ) => {
3160 let left_flattened = crate::proc::flatten_compose(
3164 left_ty,
3165 left_components,
3166 self.expressions,
3167 self.types,
3168 )
3169 .collect::<Vec<_>>();
3170 let right_flattened = crate::proc::flatten_compose(
3171 right_ty,
3172 right_components,
3173 self.expressions,
3174 self.types,
3175 )
3176 .collect::<Vec<_>>();
3177
3178 self.binary_op_compose(
3179 op,
3180 &left_flattened,
3181 &right_flattened,
3182 left_ty,
3183 right_ty,
3184 span,
3185 )?
3186 }
3187 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3188 };
3189
3190 return self.register_evaluated_expr(expr, span);
3191
3192 fn is_allowed_compose_literal_op(compose_ty: &TypeInner, op: BinaryOperator) -> bool {
3193 let is_numeric_vec = matches!(
3194 compose_ty, TypeInner::Vector { scalar, .. }
3195 if scalar.kind != ScalarKind::Bool
3196 );
3197 let is_allowed_vec_scalar_op = matches!(
3198 op,
3199 BinaryOperator::Add
3200 | BinaryOperator::Subtract
3201 | BinaryOperator::Multiply
3202 | BinaryOperator::Divide
3203 | BinaryOperator::Modulo
3204 );
3205 let is_mat = matches!(compose_ty, TypeInner::Matrix { .. });
3206 let is_allowed_mat_scalar_op = matches!(op, BinaryOperator::Multiply);
3207 is_numeric_vec && is_allowed_vec_scalar_op || is_mat && is_allowed_mat_scalar_op
3208 }
3209 }
3210
3211 fn binary_op_compose(
3212 &mut self,
3213 op: BinaryOperator,
3214 left_components: &[Handle<Expression>],
3215 right_components: &[Handle<Expression>],
3216 left_ty: Handle<Type>,
3217 right_ty: Handle<Type>,
3218 span: Span,
3219 ) -> Result<Expression, ConstantEvaluatorError> {
3220 match (&self.types[left_ty].inner, &self.types[right_ty].inner) {
3221 (
3223 &TypeInner::Vector {
3224 size: left_size, ..
3225 },
3226 &TypeInner::Vector {
3227 size: right_size, ..
3228 },
3229 ) if left_size == right_size => self.binary_op_vector(
3230 op,
3231 left_size,
3232 left_components,
3233 right_components,
3234 left_ty,
3235 span,
3236 ),
3237 (
3239 &TypeInner::Vector { size, .. },
3240 &TypeInner::Matrix {
3241 columns,
3242 rows,
3243 scalar,
3244 },
3245 ) if op == BinaryOperator::Multiply && size == rows => self.multiply_vector_matrix(
3246 left_components,
3247 right_components,
3248 columns,
3249 scalar,
3250 span,
3251 ),
3252 (
3254 &TypeInner::Matrix {
3255 columns,
3256 rows,
3257 scalar,
3258 },
3259 &TypeInner::Vector { size, .. },
3260 ) if op == BinaryOperator::Multiply && size == columns => {
3261 self.multiply_matrix_vector(left_components, right_components, rows, scalar, span)
3262 }
3263 (
3265 &TypeInner::Matrix {
3266 columns: left_columns,
3267 rows: left_rows,
3268 scalar,
3269 },
3270 &TypeInner::Matrix {
3271 columns: right_columns,
3272 rows: right_rows,
3273 ..
3274 },
3275 ) => match op {
3276 BinaryOperator::Add | BinaryOperator::Subtract
3277 if left_columns == right_columns && left_rows == right_rows =>
3278 {
3279 let components = left_components
3280 .iter()
3281 .zip(right_components)
3282 .map(|(&left, &right)| self.binary_op(op, left, right, span))
3283 .collect::<Result<Vec<_>, _>>()?;
3284 Ok(Expression::Compose {
3285 ty: left_ty,
3286 components,
3287 })
3288 }
3289 BinaryOperator::Multiply if left_columns == right_rows => self
3290 .multiply_matrix_matrix(
3291 left_components,
3292 right_components,
3293 left_rows,
3294 right_columns,
3295 scalar,
3296 span,
3297 ),
3298 _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3299 },
3300 _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3301 }
3302 }
3303
3304 fn binary_op_vector(
3305 &mut self,
3306 op: BinaryOperator,
3307 size: crate::VectorSize,
3308 left_components: &[Handle<Expression>],
3309 right_components: &[Handle<Expression>],
3310 left_ty: Handle<Type>,
3311 span: Span,
3312 ) -> Result<Expression, ConstantEvaluatorError> {
3313 let ty = match op {
3314 BinaryOperator::Equal
3316 | BinaryOperator::NotEqual
3317 | BinaryOperator::Less
3318 | BinaryOperator::LessEqual
3319 | BinaryOperator::Greater
3320 | BinaryOperator::GreaterEqual => self.types.insert(
3321 Type {
3322 name: None,
3323 inner: TypeInner::Vector {
3324 size,
3325 scalar: crate::Scalar::BOOL,
3326 },
3327 },
3328 span,
3329 ),
3330
3331 BinaryOperator::Add
3334 | BinaryOperator::Subtract
3335 | BinaryOperator::Multiply
3336 | BinaryOperator::Divide
3337 | BinaryOperator::Modulo
3338 | BinaryOperator::And
3339 | BinaryOperator::ExclusiveOr
3340 | BinaryOperator::InclusiveOr
3341 | BinaryOperator::ShiftLeft
3342 | BinaryOperator::ShiftRight => left_ty,
3343
3344 BinaryOperator::LogicalAnd | BinaryOperator::LogicalOr => {
3345 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3347 }
3348 };
3349
3350 let components = left_components
3351 .iter()
3352 .zip(right_components)
3353 .map(|(&left, &right)| self.binary_op(op, left, right, span))
3354 .collect::<Result<Vec<_>, _>>()?;
3355
3356 Ok(Expression::Compose { ty, components })
3357 }
3358
3359 fn multiply_vector_matrix(
3360 &mut self,
3361 vec_components: &[Handle<Expression>],
3362 mat_components: &[Handle<Expression>],
3363 mat_columns: crate::VectorSize,
3364 scalar: crate::Scalar,
3365 span: Span,
3366 ) -> Result<Expression, ConstantEvaluatorError> {
3367 let ty = self.types.insert(
3368 Type {
3369 name: None,
3370 inner: TypeInner::Vector {
3371 size: mat_columns,
3372 scalar,
3373 },
3374 },
3375 span,
3376 );
3377 let components = mat_components
3378 .iter()
3379 .map(|&column| {
3380 let Expression::Compose { ref components, .. } = self.expressions[column] else {
3381 unreachable!()
3382 };
3383 self.dot_exprs(
3384 vec_components.iter().cloned(),
3385 components.clone().into_iter(),
3386 span,
3387 )
3388 })
3389 .collect::<Result<Vec<_>, _>>()?;
3390 Ok(Expression::Compose { ty, components })
3391 }
3392
3393 fn multiply_matrix_vector(
3394 &mut self,
3395 mat_components: &[Handle<Expression>],
3396 vec_components: &[Handle<Expression>],
3397 mat_rows: crate::VectorSize,
3398 scalar: crate::Scalar,
3399 span: Span,
3400 ) -> Result<Expression, ConstantEvaluatorError> {
3401 let ty = self.types.insert(
3402 Type {
3403 name: None,
3404 inner: TypeInner::Vector {
3405 size: mat_rows,
3406 scalar,
3407 },
3408 },
3409 span,
3410 );
3411
3412 let flatten = self.flatten_matrix(mat_components);
3413 let nr = mat_rows as usize;
3414 let components = (0..nr)
3415 .map(|r| {
3416 let row = flatten.iter().skip(r).step_by(nr).cloned();
3417 self.dot_exprs(row, vec_components.iter().cloned(), span)
3418 })
3419 .collect::<Result<Vec<_>, _>>()?;
3420 Ok(Expression::Compose { ty, components })
3421 }
3422
3423 fn multiply_matrix_matrix(
3424 &mut self,
3425 left_components: &[Handle<Expression>],
3426 right_components: &[Handle<Expression>],
3427 left_rows: crate::VectorSize,
3428 right_columns: crate::VectorSize,
3429 scalar: crate::Scalar,
3430 span: Span,
3431 ) -> Result<Expression, ConstantEvaluatorError> {
3432 let left_nc = left_components.len();
3433 let left_nr = left_rows as usize;
3434 let right_nc = right_columns as usize;
3435 let right_nr = left_nc;
3436
3437 let mut result = Vec::with_capacity(right_nc);
3438 let result_ty = self.types.insert(
3439 Type {
3440 name: None,
3441 inner: TypeInner::Matrix {
3442 columns: right_columns,
3443 rows: left_rows,
3444 scalar,
3445 },
3446 },
3447 span,
3448 );
3449 let result_column_ty = self.types.insert(
3450 Type {
3451 name: None,
3452 inner: TypeInner::Vector {
3453 size: left_rows,
3454 scalar,
3455 },
3456 },
3457 span,
3458 );
3459
3460 let left_flattened = self.flatten_matrix(left_components);
3461 let right_flattened = self.flatten_matrix(right_components);
3462 for c in 0..right_nc {
3463 let result_column = (0..left_nr)
3464 .map(|r| {
3465 let row = left_flattened.iter().skip(r).step_by(left_nr);
3466 let column = right_flattened.iter().skip(c * right_nr).take(right_nr);
3467 self.dot_exprs(row.cloned(), column.cloned(), span)
3468 })
3469 .collect::<Result<Vec<_>, _>>()?;
3470 let expr = Expression::Compose {
3471 ty: result_column_ty,
3472 components: result_column,
3473 };
3474 let handle = self.register_evaluated_expr(expr, span)?;
3475 result.push(handle);
3476 }
3477 Ok(Expression::Compose {
3478 ty: result_ty,
3479 components: result,
3480 })
3481 }
3482
3483 fn flatten_matrix(&self, columns: &[Handle<Expression>]) -> ArrayVec<Handle<Expression>, 16> {
3484 let mut flattened = ArrayVec::<_, 16>::new();
3485 for &column in columns {
3486 let Expression::Compose { ref components, .. } = self.expressions[column] else {
3487 unreachable!()
3488 };
3489 flattened.extend(components.iter().cloned());
3490 }
3491 flattened
3492 }
3493
3494 fn dot_exprs(
3495 &mut self,
3496 left: impl Iterator<Item = Handle<Expression>>,
3497 right: impl Iterator<Item = Handle<Expression>>,
3498 span: Span,
3499 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3500 let mut acc = None;
3501 for (l, r) in left.zip(right) {
3502 let result = self.binary_op(BinaryOperator::Multiply, l, r, span)?;
3503 match acc.as_mut() {
3504 Some(acc) => *acc = self.binary_op(BinaryOperator::Add, *acc, result, span)?,
3505 None => acc = Some(result),
3506 }
3507 }
3508 Ok(acc.unwrap())
3509 }
3510
3511 fn relational(
3512 &mut self,
3513 fun: RelationalFunction,
3514 arg: Handle<Expression>,
3515 span: Span,
3516 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3517 let arg = self.eval_zero_value_and_splat(arg, span)?;
3518 match fun {
3519 RelationalFunction::All | RelationalFunction::Any => match self.expressions[arg] {
3520 Expression::Literal(Literal::Bool(_)) => Ok(arg),
3521 Expression::Compose { ty, ref components }
3522 if matches!(self.types[ty].inner, TypeInner::Vector { .. }) =>
3523 {
3524 let mut bool_components = ArrayVec::<bool, { crate::VectorSize::MAX }>::new();
3525 for component in
3526 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
3527 {
3528 match self.expressions[component] {
3529 Expression::Literal(Literal::Bool(val)) => {
3530 bool_components.push(val);
3531 }
3532 _ => {
3533 return Err(ConstantEvaluatorError::InvalidRelationalArg(fun));
3534 }
3535 }
3536 }
3537 let components = bool_components;
3538 let result = match fun {
3539 RelationalFunction::All => components.iter().all(|c| *c),
3540 RelationalFunction::Any => components.iter().any(|c| *c),
3541 _ => unreachable!(),
3542 };
3543 self.register_evaluated_expr(Expression::Literal(Literal::Bool(result)), span)
3544 }
3545 _ => Err(ConstantEvaluatorError::InvalidRelationalArg(fun)),
3546 },
3547 _ => Err(ConstantEvaluatorError::NotImplemented(format!(
3548 "{fun:?} built-in function"
3549 ))),
3550 }
3551 }
3552
3553 fn copy_from(
3561 &mut self,
3562 expr: Handle<Expression>,
3563 expressions: &Arena<Expression>,
3564 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3565 let span = expressions.get_span(expr);
3566 match expressions[expr] {
3567 ref expr @ (Expression::Literal(_)
3568 | Expression::Constant(_)
3569 | Expression::ZeroValue(_)) => self.register_evaluated_expr(expr.clone(), span),
3570 Expression::Compose { ty, ref components } => {
3571 let mut components = components.clone();
3572 for component in &mut components {
3573 *component = self.copy_from(*component, expressions)?;
3574 }
3575 self.register_evaluated_expr(Expression::Compose { ty, components }, span)
3576 }
3577 Expression::Splat { size, value } => {
3578 let value = self.copy_from(value, expressions)?;
3579 self.register_evaluated_expr(Expression::Splat { size, value }, span)
3580 }
3581 _ => {
3582 log::debug!("copy_from: SubexpressionsAreNotConstant");
3583 Err(ConstantEvaluatorError::SubexpressionsAreNotConstant)
3584 }
3585 }
3586 }
3587
3588 fn vector_compose_flattened_size(
3590 &self,
3591 components: &[Handle<Expression>],
3592 ) -> Result<usize, ConstantEvaluatorError> {
3593 components
3594 .iter()
3595 .try_fold(0, |acc, c| -> Result<_, ConstantEvaluatorError> {
3596 let size = match *self.resolve_type(*c)?.inner_with(self.types) {
3597 TypeInner::Scalar(_) => 1,
3598 TypeInner::Vector { size, .. } => size as usize,
3602 _ => return Err(ConstantEvaluatorError::InvalidVectorComposeComponent),
3603 };
3604 Ok(acc + size)
3605 })
3606 }
3607
3608 fn register_evaluated_expr(
3609 &mut self,
3610 expr: Expression,
3611 span: Span,
3612 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3613 if let Expression::Literal(literal) = expr {
3618 crate::valid::check_literal_value(literal)?;
3619 }
3620
3621 if let Expression::Compose { ty, ref components } = expr {
3625 if let TypeInner::Vector { size, scalar: _ } = self.types[ty].inner {
3626 let expected = size as usize;
3627 let actual = self.vector_compose_flattened_size(components)?;
3628 if expected != actual {
3629 return Err(ConstantEvaluatorError::InvalidVectorComposeLength {
3630 expected,
3631 actual,
3632 });
3633 }
3634 }
3635 }
3636
3637 Ok(self.append_expr(expr, span, ExpressionKind::Const))
3638 }
3639
3640 fn append_expr(
3641 &mut self,
3642 expr: Expression,
3643 span: Span,
3644 expr_type: ExpressionKind,
3645 ) -> Handle<Expression> {
3646 let h = match self.behavior {
3647 Behavior::Wgsl(
3648 WgslRestrictions::Runtime(ref mut function_local_data)
3649 | WgslRestrictions::Const(Some(ref mut function_local_data)),
3650 )
3651 | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => {
3652 let is_running = function_local_data.emitter.is_running();
3653 let needs_pre_emit = expr.needs_pre_emit();
3654 if is_running && needs_pre_emit {
3655 function_local_data
3656 .block
3657 .extend(function_local_data.emitter.finish(self.expressions));
3658 let h = self.expressions.append(expr, span);
3659 function_local_data.emitter.start(self.expressions);
3660 h
3661 } else {
3662 self.expressions.append(expr, span)
3663 }
3664 }
3665 _ => self.expressions.append(expr, span),
3666 };
3667 self.expression_kind_tracker.insert(h, expr_type);
3668 h
3669 }
3670
3671 fn resolve_type(
3676 &self,
3677 expr: Handle<Expression>,
3678 ) -> Result<crate::proc::TypeResolution, ConstantEvaluatorError> {
3679 use crate::proc::TypeResolution as Tr;
3680 use crate::Expression as Ex;
3681 let resolution = match self.expressions[expr] {
3682 Ex::Literal(ref literal) => Tr::Value(literal.ty_inner()),
3683 Ex::Constant(c) => Tr::Handle(self.constants[c].ty),
3684 Ex::ZeroValue(ty) | Ex::Compose { ty, .. } => Tr::Handle(ty),
3685 Ex::Splat { size, value } => {
3686 let Tr::Value(TypeInner::Scalar(scalar)) = self.resolve_type(value)? else {
3687 return Err(ConstantEvaluatorError::SplatScalarOnly);
3688 };
3689 Tr::Value(TypeInner::Vector { scalar, size })
3690 }
3691 _ => {
3692 log::debug!("resolve_type: SubexpressionsAreNotConstant");
3693 return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
3694 }
3695 };
3696
3697 Ok(resolution)
3698 }
3699
3700 fn select(
3701 &mut self,
3702 reject: Handle<Expression>,
3703 accept: Handle<Expression>,
3704 condition: Handle<Expression>,
3705 span: Span,
3706 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3707 let mut arg = |arg| self.eval_zero_value_and_splat(arg, span);
3708
3709 let reject = arg(reject)?;
3710 let accept = arg(accept)?;
3711 let condition = arg(condition)?;
3712
3713 let select_single_component =
3714 |this: &mut Self, reject_scalar, reject, accept, condition| {
3715 let accept = this.cast(accept, reject_scalar, span)?;
3716 if condition {
3717 Ok(accept)
3718 } else {
3719 Ok(reject)
3720 }
3721 };
3722
3723 match (&self.expressions[reject], &self.expressions[accept]) {
3724 (&Expression::Literal(reject_lit), &Expression::Literal(_accept_lit)) => {
3725 let reject_scalar = reject_lit.scalar();
3726 let &Expression::Literal(Literal::Bool(condition)) = &self.expressions[condition]
3727 else {
3728 return Err(ConstantEvaluatorError::SelectScalarConditionNotABool);
3729 };
3730 select_single_component(self, reject_scalar, reject, accept, condition)
3731 }
3732 (
3733 &Expression::Compose {
3734 ty: reject_ty,
3735 components: ref reject_components,
3736 },
3737 &Expression::Compose {
3738 ty: accept_ty,
3739 components: ref accept_components,
3740 },
3741 ) => {
3742 let ty_deets = |ty| {
3743 self.types[ty]
3744 .inner
3745 .vector_size_and_scalar()
3746 .map(|(size, scalar)| {
3747 (size.expect("expected vector type, not scalar type"), scalar)
3748 })
3749 };
3750
3751 let expected_vec_size = {
3752 let [(reject_vec_size, _), (accept_vec_size, _)] =
3753 [reject_ty, accept_ty].map(|ty| ty_deets(ty).unwrap());
3754
3755 if reject_vec_size != accept_vec_size {
3756 return Err(ConstantEvaluatorError::SelectVecRejectAcceptSizeMismatch {
3757 reject: reject_vec_size,
3758 accept: accept_vec_size,
3759 });
3760 }
3761 reject_vec_size
3762 };
3763
3764 let condition_components = match self.expressions[condition] {
3765 Expression::Literal(Literal::Bool(condition)) => {
3766 vec![condition; (expected_vec_size as u8).into()]
3767 }
3768 Expression::Compose {
3769 ty: condition_ty,
3770 components: ref condition_components,
3771 } => {
3772 let Some((condition_vec_size, condition_scalar)) = ty_deets(condition_ty)
3773 else {
3774 return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3775 };
3776 if condition_scalar.kind != ScalarKind::Bool {
3777 return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3778 }
3779 if condition_vec_size != expected_vec_size {
3780 return Err(ConstantEvaluatorError::SelectConditionVecSizeMismatch);
3781 }
3782 condition_components
3783 .iter()
3784 .copied()
3785 .map(|component| match &self.expressions[component] {
3786 &Expression::Literal(Literal::Bool(condition)) => condition,
3787 _ => unreachable!(),
3788 })
3789 .collect()
3790 }
3791
3792 _ => return Err(ConstantEvaluatorError::SelectConditionNotAVecBool),
3793 };
3794
3795 let evaluated = Expression::Compose {
3796 ty: reject_ty,
3797 components: reject_components
3798 .clone()
3799 .into_iter()
3800 .zip(accept_components.clone())
3801 .zip(condition_components)
3802 .map(|((reject, accept), condition)| {
3803 let reject_scalar = match &self.expressions[reject] {
3804 &Expression::Literal(lit) => lit.scalar(),
3805 _ => unreachable!(),
3806 };
3807 select_single_component(self, reject_scalar, reject, accept, condition)
3808 })
3809 .collect::<Result<_, _>>()?,
3810 };
3811 self.register_evaluated_expr(evaluated, span)
3812 }
3813 _ => Err(ConstantEvaluatorError::SelectAcceptRejectTypeMismatch),
3814 }
3815 }
3816}
3817
3818fn float_face_forward<F>(
3820 e1: &[F],
3821 e2: &[F],
3822 e3: &[F],
3823) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3824where
3825 F: num_traits::Float,
3826{
3827 let d = float_dot(e2, e3)?;
3828
3829 let mut out = ArrayVec::new();
3830 for &e in e1 {
3831 out.push(if d < F::zero() { e } else { -e });
3832 }
3833 Some(out)
3834}
3835
3836fn float_reflect<F>(e1: &[F], e2: &[F]) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3839where
3840 F: num_traits::Float,
3841{
3842 let d = float_dot(e2, e1)?;
3843 let two = F::one() + F::one();
3844
3845 let mut out = ArrayVec::new();
3846 for (&a, &b) in e1.iter().zip(e2) {
3847 let r = a - two * d * b;
3848 if !r.is_finite() {
3849 return None;
3850 }
3851 out.push(r);
3852 }
3853 Some(out)
3854}
3855
3856fn float_refract<F>(e1: &[F], e2: &[F], e3: F) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3859where
3860 F: num_traits::Float,
3861{
3862 let d = float_dot(e2, e1)?;
3863 let one = F::one();
3864
3865 let k = one - e3 * e3 * (one - d * d);
3866 if !k.is_finite() {
3867 return None;
3868 }
3869
3870 let mut out = ArrayVec::new();
3871
3872 if k < F::zero() {
3874 for _ in e1 {
3875 out.push(F::zero());
3876 }
3877 return Some(out);
3878 }
3879
3880 let scale = e3 * d + k.sqrt();
3881 for (&a, &b) in e1.iter().zip(e2) {
3882 let r = e3 * a - scale * b;
3883 if !r.is_finite() {
3884 return None;
3885 }
3886 out.push(r);
3887 }
3888 Some(out)
3889}
3890
3891#[test]
3892fn face_forward_smoke() {
3893 #[track_caller]
3894 fn ff(e1: &[f32], e2: &[f32], e3: &[f32]) -> Vec<f32> {
3895 float_face_forward(e1, e2, e3).unwrap().to_vec()
3896 }
3897
3898 assert_eq!(ff(&[1.0, 2.0], &[-1.0, 0.0], &[1.0, 0.0]), [1.0, 2.0]);
3900 assert_eq!(ff(&[1.0, 2.0], &[1.0, 0.0], &[1.0, 0.0]), [-1.0, -2.0]);
3901
3902 assert_eq!(ff(&[1.0, 2.0], &[0.0, 1.0], &[1.0, 0.0]), [-1.0, -2.0]);
3904
3905 assert_eq!(
3906 ff(&[1.0, 2.0, 3.0], &[-1.0, 0.0, 0.0], &[1.0, 0.0, 0.0]),
3907 [1.0, 2.0, 3.0]
3908 );
3909
3910 assert!(float_face_forward(&[1.0f32, 0.0], &[f32::MAX, 0.0], &[f32::MAX, 0.0]).is_none());
3912}
3913
3914#[test]
3915fn reflect_smoke() {
3916 #[track_caller]
3917 fn rf(e1: &[f32], e2: &[f32]) -> Vec<f32> {
3918 float_reflect(e1, e2).unwrap().to_vec()
3919 }
3920
3921 assert_eq!(rf(&[1.0, -1.0], &[0.0, 1.0]), [1.0, 1.0]);
3923 assert_eq!(rf(&[1.0, -1.0, 0.0], &[0.0, 1.0, 0.0]), [1.0, 1.0, 0.0]);
3924
3925 assert_eq!(rf(&[1.0, 0.0], &[1.0, 0.0]), [-1.0, 0.0]);
3927
3928 assert_eq!(rf(&[1.0, 0.0], &[0.0, 1.0]), [1.0, 0.0]);
3930
3931 assert!(float_reflect(&[1.0f32, 0.0], &[f32::MAX, 0.0]).is_none());
3932}
3933
3934#[test]
3935fn refract_smoke() {
3936 #[track_caller]
3937 fn rr(e1: &[f32], e2: &[f32], e3: f32) -> Vec<f32> {
3938 float_refract(e1, e2, e3).unwrap().to_vec()
3939 }
3940
3941 assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 1.0), [0.0, -1.0]);
3943 assert_eq!(rr(&[0.5, -0.5], &[0.0, 1.0], 1.0), [0.5, -0.5]);
3944
3945 assert_eq!(rr(&[0.5, -0.5], &[0.0, -1.0], 1.0), [0.5, 0.5]);
3947
3948 assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 0.5), [0.0, -1.0]);
3950
3951 assert_eq!(rr(&[0.8, -0.6], &[0.0, 1.0], 2.0), [0.0, 0.0]);
3953 assert_eq!(
3954 rr(&[0.8, -0.6, 0.0], &[0.0, 1.0, 0.0], 2.0),
3955 [0.0, 0.0, 0.0]
3956 );
3957
3958 assert!(float_refract(&[1.0f32, 0.0], &[f32::MAX, 0.0], 1.0).is_none());
3959 assert!(float_refract(&[1.0f32, 0.0], &[0.0, 1.0], f32::MAX).is_none());
3960}
3961
3962const fn bit_width<T>() -> u32 {
3965 size_of::<T>() as u32 * 8
3966}
3967
3968pub fn check_bitfield_range(
3975 builtin: &'static str,
3976 offset: u32,
3977 count: u32,
3978 width: u32,
3979) -> Result<(), ConstantEvaluatorError> {
3980 if u64::from(offset) + u64::from(count) > u64::from(width) {
3981 return Err(ConstantEvaluatorError::BitfieldRangeTooLarge {
3982 builtin,
3983 offset,
3984 count,
3985 width,
3986 });
3987 }
3988 Ok(())
3989}
3990
3991fn extract_bits<T>(
3992 e: &[T],
3993 offset: u32,
3994 count: u32,
3995) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
3996where
3997 T: num_traits::PrimInt,
3998{
3999 check_bitfield_range("extractBits", offset, count, bit_width::<T>())?;
4000 let w = bit_width::<T>();
4001
4002 let mut out = ArrayVec::new();
4003 for &e in e {
4004 out.push(if count == 0 {
4005 T::zero()
4006 } else {
4007 (e << (w - offset - count) as usize) >> (w - count) as usize
4012 });
4013 }
4014 Ok(out)
4015}
4016
4017fn insert_bits<T>(
4018 e: &[T],
4019 newbits: &[T],
4020 offset: u32,
4021 count: u32,
4022) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
4023where
4024 T: num_traits::PrimInt,
4025{
4026 check_bitfield_range("insertBits", offset, count, bit_width::<T>())?;
4027 let w = bit_width::<T>();
4028
4029 let mut out = ArrayVec::new();
4030 for (&e, &newbits) in e.iter().zip(newbits) {
4031 out.push(if count == 0 {
4032 e
4033 } else {
4034 let mask = (!T::zero()).unsigned_shr(w - count) << offset as usize;
4035 (e & !mask) | ((newbits << offset as usize) & mask)
4036 });
4037 }
4038 Ok(out)
4039}
4040
4041#[cfg(test)]
4042fn extract_bits_scalar<T: num_traits::PrimInt>(e: T, offset: u32, count: u32) -> T {
4043 extract_bits(&[e], offset, count).unwrap()[0]
4044}
4045
4046#[cfg(test)]
4047fn insert_bits_scalar<T: num_traits::PrimInt>(e: T, newbits: T, offset: u32, count: u32) -> T {
4048 insert_bits(&[e], &[newbits], offset, count).unwrap()[0]
4049}
4050
4051#[test]
4052fn extract_bits_smoke() {
4053 assert_eq!(extract_bits_scalar(0xffffffff_u32, 0, 0), 0);
4055 assert_eq!(extract_bits_scalar(-1_i32, 32, 0), 0);
4056
4057 assert_eq!(extract_bits_scalar(0x12345678_u32, 0, 32), 0x12345678);
4059 assert_eq!(extract_bits_scalar(i32::MIN, 0, 32), i32::MIN);
4060
4061 assert_eq!(extract_bits_scalar(0x12345678_u32, 8, 8), 0x56);
4063 assert_eq!(extract_bits_scalar(0xf0000000_u32, 28, 4), 0xf);
4064 assert_eq!(extract_bits_scalar(0x12345678_u32, 31, 1), 0);
4065
4066 assert_eq!(extract_bits_scalar(0x12345678_i32, 8, 8), 0x56);
4068 assert_eq!(extract_bits_scalar(0x8_i32, 3, 1), -1);
4069 assert_eq!(extract_bits_scalar(0xf0000000_u32 as i32, 28, 4), -1);
4070 assert_eq!(extract_bits_scalar(0x70000000_i32, 28, 4), 7);
4071
4072 assert_eq!(extract_bits_scalar(0x1234_u16, 4, 8), 0x23);
4074 assert_eq!(extract_bits_scalar(-1_i16, 0, 16), -1);
4075 assert_eq!(
4076 extract_bits_scalar(0x123456789abcdef0_u64, 32, 32),
4077 0x12345678
4078 );
4079 assert_eq!(extract_bits_scalar(-1_i64, 63, 1), -1);
4080
4081 assert!(extract_bits(&[0_u32], 30, 8).is_err());
4083 assert!(extract_bits(&[0_u32], 33, 0).is_err());
4084 assert!(extract_bits(&[0_u16], 8, 16).is_err());
4085 assert!(extract_bits(&[0_u32], u32::MAX, u32::MAX).is_err());
4086 assert!(extract_bits(&[0_u32], 32, 0).is_ok());
4087}
4088
4089#[test]
4090fn insert_bits_smoke() {
4091 assert_eq!(
4093 insert_bits_scalar(0x12345678_u32, 0xffffffff, 0, 0),
4094 0x12345678
4095 );
4096 assert_eq!(insert_bits_scalar(-1_i32, 0, 32, 0), -1);
4097
4098 assert_eq!(
4100 insert_bits_scalar(0x12345678_u32, 0xdeadbeef, 0, 32),
4101 0xdeadbeef
4102 );
4103 assert_eq!(insert_bits_scalar(0_i32, i32::MIN, 0, 32), i32::MIN);
4104
4105 assert_eq!(insert_bits_scalar(0x12345678_u32, 0xff, 8, 8), 0x1234ff78);
4108 assert_eq!(insert_bits_scalar(0x12345678_u32, 0xabcd, 8, 8), 0x1234cd78);
4109 assert_eq!(insert_bits_scalar(0_u32, 0xf, 28, 4), 0xf0000000);
4110 assert_eq!(insert_bits_scalar(0_u32, 1, 31, 1), 0x80000000);
4111
4112 assert_eq!(insert_bits_scalar(0_i32, -1, 31, 1), i32::MIN);
4114 assert_eq!(insert_bits_scalar(-1_i32, 0, 0, 31), i32::MIN);
4115
4116 assert_eq!(insert_bits_scalar(0x1234_u16, 0xf, 4, 4), 0x12f4);
4118 assert_eq!(insert_bits_scalar(0_i16, -1, 15, 1), i16::MIN);
4119 assert_eq!(
4120 insert_bits_scalar(0_u64, 0xffffffff, 32, 32),
4121 0xffffffff00000000
4122 );
4123
4124 assert!(insert_bits(&[0_u32], &[0], 30, 8).is_err());
4126 assert!(insert_bits(&[0_u32], &[0], 33, 0).is_err());
4127 assert!(insert_bits(&[0_u16], &[0], 8, 16).is_err());
4128 assert!(insert_bits(&[0_u32], &[0], u32::MAX, u32::MAX).is_err());
4129 assert!(insert_bits(&[0_u32], &[0], 32, 0).is_ok());
4130}
4131
4132fn first_trailing_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4133 let trailing_zeros_to_bit_idx = |e: u32| -> u32 {
4137 match e {
4138 idx @ 0..=31 => idx,
4139 32 => u32::MAX,
4140 _ => unreachable!(),
4141 }
4142 };
4143 match concrete_int {
4144 ConcreteInt::U32([e]) => ConcreteInt::U32([trailing_zeros_to_bit_idx(e.trailing_zeros())]),
4145 ConcreteInt::I32([e]) => {
4146 ConcreteInt::I32([trailing_zeros_to_bit_idx(e.trailing_zeros()) as i32])
4147 }
4148 }
4149}
4150
4151#[test]
4152fn first_trailing_bit_smoke() {
4153 assert_eq!(
4154 first_trailing_bit(ConcreteInt::I32([0])),
4155 ConcreteInt::I32([-1])
4156 );
4157 assert_eq!(
4158 first_trailing_bit(ConcreteInt::I32([1])),
4159 ConcreteInt::I32([0])
4160 );
4161 assert_eq!(
4162 first_trailing_bit(ConcreteInt::I32([2])),
4163 ConcreteInt::I32([1])
4164 );
4165 assert_eq!(
4166 first_trailing_bit(ConcreteInt::I32([-1])),
4167 ConcreteInt::I32([0]),
4168 );
4169 assert_eq!(
4170 first_trailing_bit(ConcreteInt::I32([i32::MIN])),
4171 ConcreteInt::I32([31]),
4172 );
4173 assert_eq!(
4174 first_trailing_bit(ConcreteInt::I32([i32::MAX])),
4175 ConcreteInt::I32([0]),
4176 );
4177 for idx in 0..32 {
4178 assert_eq!(
4179 first_trailing_bit(ConcreteInt::I32([1 << idx])),
4180 ConcreteInt::I32([idx])
4181 )
4182 }
4183
4184 assert_eq!(
4185 first_trailing_bit(ConcreteInt::U32([0])),
4186 ConcreteInt::U32([u32::MAX])
4187 );
4188 assert_eq!(
4189 first_trailing_bit(ConcreteInt::U32([1])),
4190 ConcreteInt::U32([0])
4191 );
4192 assert_eq!(
4193 first_trailing_bit(ConcreteInt::U32([2])),
4194 ConcreteInt::U32([1])
4195 );
4196 assert_eq!(
4197 first_trailing_bit(ConcreteInt::U32([1 << 31])),
4198 ConcreteInt::U32([31]),
4199 );
4200 assert_eq!(
4201 first_trailing_bit(ConcreteInt::U32([u32::MAX])),
4202 ConcreteInt::U32([0]),
4203 );
4204 for idx in 0..32 {
4205 assert_eq!(
4206 first_trailing_bit(ConcreteInt::U32([1 << idx])),
4207 ConcreteInt::U32([idx])
4208 )
4209 }
4210}
4211
4212fn first_leading_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4213 let rtl_to_ltr_bit_idx = |e: u32| -> u32 {
4217 match e {
4218 idx @ 0..=31 => 31 - idx,
4219 32 => u32::MAX,
4220 _ => unreachable!(),
4221 }
4222 };
4223 match concrete_int {
4224 ConcreteInt::I32([e]) => ConcreteInt::I32([{
4225 let rtl_bit_index = if e.is_negative() {
4226 e.leading_ones()
4227 } else {
4228 e.leading_zeros()
4229 };
4230 rtl_to_ltr_bit_idx(rtl_bit_index) as i32
4231 }]),
4232 ConcreteInt::U32([e]) => ConcreteInt::U32([rtl_to_ltr_bit_idx(e.leading_zeros())]),
4233 }
4234}
4235
4236#[test]
4237fn first_leading_bit_smoke() {
4238 assert_eq!(
4239 first_leading_bit(ConcreteInt::I32([-1])),
4240 ConcreteInt::I32([-1])
4241 );
4242 assert_eq!(
4243 first_leading_bit(ConcreteInt::I32([0])),
4244 ConcreteInt::I32([-1])
4245 );
4246 assert_eq!(
4247 first_leading_bit(ConcreteInt::I32([1])),
4248 ConcreteInt::I32([0])
4249 );
4250 assert_eq!(
4251 first_leading_bit(ConcreteInt::I32([-2])),
4252 ConcreteInt::I32([0])
4253 );
4254 assert_eq!(
4255 first_leading_bit(ConcreteInt::I32([1234 + 4567])),
4256 ConcreteInt::I32([12])
4257 );
4258 assert_eq!(
4259 first_leading_bit(ConcreteInt::I32([i32::MAX])),
4260 ConcreteInt::I32([30])
4261 );
4262 assert_eq!(
4263 first_leading_bit(ConcreteInt::I32([i32::MIN])),
4264 ConcreteInt::I32([30])
4265 );
4266 for idx in 0..(32 - 1) {
4268 assert_eq!(
4269 first_leading_bit(ConcreteInt::I32([1 << idx])),
4270 ConcreteInt::I32([idx])
4271 );
4272 }
4273 for idx in 1..(32 - 1) {
4274 assert_eq!(
4275 first_leading_bit(ConcreteInt::I32([-(1 << idx)])),
4276 ConcreteInt::I32([idx - 1])
4277 );
4278 }
4279
4280 assert_eq!(
4281 first_leading_bit(ConcreteInt::U32([0])),
4282 ConcreteInt::U32([u32::MAX])
4283 );
4284 assert_eq!(
4285 first_leading_bit(ConcreteInt::U32([1])),
4286 ConcreteInt::U32([0])
4287 );
4288 assert_eq!(
4289 first_leading_bit(ConcreteInt::U32([u32::MAX])),
4290 ConcreteInt::U32([31])
4291 );
4292 for idx in 0..32 {
4293 assert_eq!(
4294 first_leading_bit(ConcreteInt::U32([1 << idx])),
4295 ConcreteInt::U32([idx])
4296 )
4297 }
4298}
4299
4300trait TryFromAbstract<T>: Sized {
4302 fn try_from_abstract(value: T) -> Result<Self, ConstantEvaluatorError>;
4324}
4325
4326impl TryFromAbstract<i64> for i32 {
4327 fn try_from_abstract(value: i64) -> Result<i32, ConstantEvaluatorError> {
4328 i32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4329 value: format!("{value:?}"),
4330 to_type: "i32",
4331 })
4332 }
4333}
4334
4335impl TryFromAbstract<i64> for u32 {
4336 fn try_from_abstract(value: i64) -> Result<u32, ConstantEvaluatorError> {
4337 u32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4338 value: format!("{value:?}"),
4339 to_type: "u32",
4340 })
4341 }
4342}
4343
4344impl TryFromAbstract<i64> for u64 {
4345 fn try_from_abstract(value: i64) -> Result<u64, ConstantEvaluatorError> {
4346 u64::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4347 value: format!("{value:?}"),
4348 to_type: "u64",
4349 })
4350 }
4351}
4352
4353impl TryFromAbstract<i64> for i64 {
4354 fn try_from_abstract(value: i64) -> Result<i64, ConstantEvaluatorError> {
4355 Ok(value)
4356 }
4357}
4358
4359impl TryFromAbstract<i64> for f32 {
4360 fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4361 let f = value as f32;
4362 Ok(f)
4366 }
4367}
4368
4369impl TryFromAbstract<f64> for f32 {
4370 fn try_from_abstract(value: f64) -> Result<f32, ConstantEvaluatorError> {
4371 let f = value as f32;
4372 if f.is_infinite() {
4373 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4374 value: format!("{value:?}"),
4375 to_type: "f32",
4376 });
4377 }
4378 Ok(f)
4379 }
4380}
4381
4382impl TryFromAbstract<i64> for f64 {
4383 fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4384 let f = value as f64;
4385 Ok(f)
4389 }
4390}
4391
4392impl TryFromAbstract<f64> for f64 {
4393 fn try_from_abstract(value: f64) -> Result<f64, ConstantEvaluatorError> {
4394 Ok(value)
4395 }
4396}
4397
4398impl TryFromAbstract<f64> for i32 {
4399 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4400 Ok(value as i32)
4413 }
4414}
4415
4416impl TryFromAbstract<f64> for u32 {
4417 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4418 Ok(value as u32)
4421 }
4422}
4423
4424impl TryFromAbstract<f64> for i64 {
4425 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4426 use crate::proc::type_methods::IntFloatLimits;
4429 Ok(value.clamp(i64::min_float(), i64::max_float()) as i64)
4430 }
4431}
4432
4433impl TryFromAbstract<f64> for u64 {
4434 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4435 use crate::proc::type_methods::IntFloatLimits;
4438 Ok(value.clamp(u64::min_float(), u64::max_float()) as u64)
4439 }
4440}
4441
4442impl TryFromAbstract<f64> for f16 {
4443 fn try_from_abstract(value: f64) -> Result<f16, ConstantEvaluatorError> {
4444 let f = f16::from_f64(value);
4445 if f.is_infinite() {
4446 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4447 value: format!("{value:?}"),
4448 to_type: "f16",
4449 });
4450 }
4451 Ok(f)
4452 }
4453}
4454
4455impl TryFromAbstract<i64> for f16 {
4456 fn try_from_abstract(value: i64) -> Result<f16, ConstantEvaluatorError> {
4457 let f = f16::from_i64(value);
4458 if f.is_none() {
4459 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4460 value: format!("{value:?}"),
4461 to_type: "f16",
4462 });
4463 }
4464 Ok(f.unwrap())
4465 }
4466}
4467
4468fn cross_product<T>(a: [T; 3], b: [T; 3]) -> [T; 3]
4469where
4470 T: Copy,
4471 T: core::ops::Mul<T, Output = T>,
4472 T: core::ops::Sub<T, Output = T>,
4473{
4474 [
4475 a[1] * b[2] - a[2] * b[1],
4476 a[2] * b[0] - a[0] * b[2],
4477 a[0] * b[1] - a[1] * b[0],
4478 ]
4479}
4480
4481#[cfg(test)]
4482mod tests {
4483 use alloc::{vec, vec::Vec};
4484
4485 use crate::{
4486 Arena, BinaryOperator, Constant, Expression, FastHashMap, Handle, Literal, ScalarKind,
4487 Type, TypeInner, UnaryOperator, UniqueArena, VectorSize,
4488 };
4489
4490 use super::{Behavior, ConstantEvaluator, ExpressionKindTracker, WgslRestrictions};
4491
4492 #[test]
4493 fn unary_op() {
4494 let mut types = UniqueArena::new();
4495 let mut constants = Arena::new();
4496 let overrides = Arena::new();
4497 let mut global_expressions = Arena::new();
4498
4499 let scalar_ty = types.insert(
4500 Type {
4501 name: None,
4502 inner: TypeInner::Scalar(crate::Scalar::I32),
4503 },
4504 Default::default(),
4505 );
4506
4507 let vec_ty = types.insert(
4508 Type {
4509 name: None,
4510 inner: TypeInner::Vector {
4511 size: VectorSize::Bi,
4512 scalar: crate::Scalar::I32,
4513 },
4514 },
4515 Default::default(),
4516 );
4517
4518 let h = constants.append(
4519 Constant {
4520 name: None,
4521 ty: scalar_ty,
4522 init: global_expressions
4523 .append(Expression::Literal(Literal::I32(4)), Default::default()),
4524 },
4525 Default::default(),
4526 );
4527
4528 let h1 = constants.append(
4529 Constant {
4530 name: None,
4531 ty: scalar_ty,
4532 init: global_expressions
4533 .append(Expression::Literal(Literal::I32(8)), Default::default()),
4534 },
4535 Default::default(),
4536 );
4537
4538 let vec_h = constants.append(
4539 Constant {
4540 name: None,
4541 ty: vec_ty,
4542 init: global_expressions.append(
4543 Expression::Compose {
4544 ty: vec_ty,
4545 components: vec![constants[h].init, constants[h1].init],
4546 },
4547 Default::default(),
4548 ),
4549 },
4550 Default::default(),
4551 );
4552
4553 let expr = global_expressions.append(Expression::Constant(h), Default::default());
4554 let expr1 = global_expressions.append(Expression::Constant(vec_h), Default::default());
4555
4556 let expr2 = Expression::Unary {
4557 op: UnaryOperator::Negate,
4558 expr,
4559 };
4560
4561 let expr3 = Expression::Unary {
4562 op: UnaryOperator::BitwiseNot,
4563 expr,
4564 };
4565
4566 let expr4 = Expression::Unary {
4567 op: UnaryOperator::BitwiseNot,
4568 expr: expr1,
4569 };
4570
4571 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4572 let mut solver = ConstantEvaluator {
4573 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4574 types: &mut types,
4575 constants: &constants,
4576 overrides: &overrides,
4577 expressions: &mut global_expressions,
4578 expression_kind_tracker,
4579 layouter: &mut crate::proc::Layouter::default(),
4580 };
4581
4582 let res1 = solver
4583 .try_eval_and_append(expr2, Default::default())
4584 .unwrap();
4585 let res2 = solver
4586 .try_eval_and_append(expr3, Default::default())
4587 .unwrap();
4588 let res3 = solver
4589 .try_eval_and_append(expr4, Default::default())
4590 .unwrap();
4591
4592 assert_eq!(
4593 global_expressions[res1],
4594 Expression::Literal(Literal::I32(-4))
4595 );
4596
4597 assert_eq!(
4598 global_expressions[res2],
4599 Expression::Literal(Literal::I32(!4))
4600 );
4601
4602 let res3_inner = &global_expressions[res3];
4603
4604 match *res3_inner {
4605 Expression::Compose {
4606 ref ty,
4607 ref components,
4608 } => {
4609 assert_eq!(*ty, vec_ty);
4610 let mut components_iter = components.iter().copied();
4611 assert_eq!(
4612 global_expressions[components_iter.next().unwrap()],
4613 Expression::Literal(Literal::I32(!4))
4614 );
4615 assert_eq!(
4616 global_expressions[components_iter.next().unwrap()],
4617 Expression::Literal(Literal::I32(!8))
4618 );
4619 assert!(components_iter.next().is_none());
4620 }
4621 _ => panic!("Expected vector"),
4622 }
4623 }
4624
4625 #[test]
4626 fn matrix_op() {
4627 let mut helper = MatrixTestHelper::new();
4628
4629 for nc in 2..=4 {
4630 for nr in 2..=4 {
4631 let evaluated = helper.eval_vector_multiply_matrix(nc, nr);
4634 let expected = (0..nc)
4635 .map(|c| (0..nr).map(|r| (r * (c * nr + r)) as f32).sum())
4636 .collect::<Vec<f32>>();
4637 assert_eq!(evaluated, expected);
4638
4639 let evaluated = helper.eval_matrix_multiply_vector(nc, nr);
4642 let expected = (0..nr)
4643 .map(|r| (0..nc).map(|c| (c * (c * nr + r)) as f32).sum())
4644 .collect::<Vec<f32>>();
4645 assert_eq!(evaluated, expected);
4646
4647 for k in 2..=4 {
4648 let evaluated = helper.eval_matrix_multiply_matrix(nr, nc, k);
4651 let expected = (0..nc)
4652 .flat_map(|c| {
4653 (0..nr).map(move |r| {
4654 (0..k).map(|v| ((v * nr + r) * (c * k + v)) as f32).sum()
4655 })
4656 })
4657 .collect::<Vec<f32>>();
4658 assert_eq!(evaluated, expected);
4659 }
4660 }
4661 }
4662 }
4663
4664 struct MatrixTestHelper {
4668 types: UniqueArena<Type>,
4669 expressions: Arena<Expression>,
4670 vec_exprs: FastHashMap<usize, Handle<Expression>>,
4672 mat_exprs: FastHashMap<(usize, usize), Handle<Expression>>,
4674 }
4675
4676 impl MatrixTestHelper {
4677 fn new() -> Self {
4678 let mut types = UniqueArena::new();
4679 let mut expressions = Arena::new();
4680 let span = crate::Span::default();
4681
4682 let (mut vec_tys, mut mat_tys) = (FastHashMap::default(), FastHashMap::default());
4683 for c in 2..=4 {
4684 let vec_ty = types.insert(
4685 Type {
4686 name: None,
4687 inner: TypeInner::Vector {
4688 size: Self::int_to_vector_size(c),
4689 scalar: crate::Scalar::F32,
4690 },
4691 },
4692 span,
4693 );
4694 vec_tys.insert(c, vec_ty);
4695 for r in 2..=4 {
4696 let mat_ty = types.insert(
4697 Type {
4698 name: None,
4699 inner: TypeInner::Matrix {
4700 columns: Self::int_to_vector_size(c),
4701 rows: Self::int_to_vector_size(r),
4702 scalar: crate::Scalar::F32,
4703 },
4704 },
4705 span,
4706 );
4707 mat_tys.insert((c, r), mat_ty);
4708 }
4709 }
4710
4711 let mut lit_exprs = FastHashMap::default();
4712 for i in 0..16 {
4713 let expr = expressions.append(Expression::Literal(Literal::F32(i as f32)), span);
4714 lit_exprs.insert(i, expr);
4715 }
4716
4717 let mut vec_exprs = FastHashMap::default();
4718 for c in 2..=4 {
4719 let expr = expressions.append(
4720 Expression::Compose {
4721 ty: *vec_tys.get(&c).unwrap(),
4722 components: (0..c)
4723 .map(|i| *lit_exprs.get(&i).unwrap())
4724 .collect::<Vec<_>>(),
4725 },
4726 span,
4727 );
4728 vec_exprs.insert(c, expr);
4729 }
4730
4731 let mut mat_exprs = FastHashMap::default();
4732 for c in 2..=4 {
4733 for r in 2..=4 {
4734 let mut columns = Vec::with_capacity(c);
4735 for cc in 0..c {
4736 let start = cc * r;
4737 let expr = expressions.append(
4738 Expression::Compose {
4739 ty: *vec_tys.get(&r).unwrap(),
4740 components: (start..start + r)
4741 .map(|i| *lit_exprs.get(&i).unwrap())
4742 .collect::<Vec<_>>(),
4743 },
4744 span,
4745 );
4746 columns.push(expr);
4747 }
4748
4749 let expr = expressions.append(
4750 Expression::Compose {
4751 ty: *mat_tys.get(&(c, r)).unwrap(),
4752 components: columns,
4753 },
4754 span,
4755 );
4756 mat_exprs.insert((c, r), expr);
4757 }
4758 }
4759
4760 Self {
4761 types,
4762 expressions,
4763 vec_exprs,
4764 mat_exprs,
4765 }
4766 }
4767
4768 fn eval_vector_multiply_matrix(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4770 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4771 let mut solver = ConstantEvaluator {
4772 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4773 types: &mut self.types,
4774 constants: &Arena::new(),
4775 overrides: &Arena::new(),
4776 expressions: &mut self.expressions,
4777 expression_kind_tracker,
4778 layouter: &mut crate::proc::Layouter::default(),
4779 };
4780
4781 let result = solver
4782 .try_eval_and_append(
4783 Expression::Binary {
4784 op: BinaryOperator::Multiply,
4785 left: *self.vec_exprs.get(&nr).unwrap(),
4786 right: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4787 },
4788 Default::default(),
4789 )
4790 .unwrap();
4791 self.flatten(result)
4792 }
4793
4794 fn eval_matrix_multiply_vector(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4796 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4797 let mut solver = ConstantEvaluator {
4798 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4799 types: &mut self.types,
4800 constants: &Arena::new(),
4801 overrides: &Arena::new(),
4802 expressions: &mut self.expressions,
4803 expression_kind_tracker,
4804 layouter: &mut crate::proc::Layouter::default(),
4805 };
4806
4807 let result = solver
4808 .try_eval_and_append(
4809 Expression::Binary {
4810 op: BinaryOperator::Multiply,
4811 left: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4812 right: *self.vec_exprs.get(&nc).unwrap(),
4813 },
4814 Default::default(),
4815 )
4816 .unwrap();
4817 self.flatten(result)
4818 }
4819
4820 fn eval_matrix_multiply_matrix(&mut self, l_nr: usize, r_nc: usize, k: usize) -> Vec<f32> {
4823 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4824 let mut solver = ConstantEvaluator {
4825 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4826 types: &mut self.types,
4827 constants: &Arena::new(),
4828 overrides: &Arena::new(),
4829 expressions: &mut self.expressions,
4830 expression_kind_tracker,
4831 layouter: &mut crate::proc::Layouter::default(),
4832 };
4833
4834 let result = solver
4835 .try_eval_and_append(
4836 Expression::Binary {
4837 op: BinaryOperator::Multiply,
4838 left: *self.mat_exprs.get(&(k, l_nr)).unwrap(),
4839 right: *self.mat_exprs.get(&(r_nc, k)).unwrap(),
4840 },
4841 Default::default(),
4842 )
4843 .unwrap();
4844 self.flatten(result)
4845 }
4846
4847 fn flatten(&self, expr: Handle<Expression>) -> Vec<f32> {
4848 let Expression::Compose {
4849 ref components,
4850 ref ty,
4851 } = self.expressions[expr]
4852 else {
4853 unreachable!()
4854 };
4855
4856 match self.types[*ty].inner {
4857 TypeInner::Vector { .. } => components
4858 .iter()
4859 .map(|&comp| {
4860 let Expression::Literal(Literal::F32(v)) = self.expressions[comp] else {
4861 unreachable!()
4862 };
4863 v
4864 })
4865 .collect(),
4866 TypeInner::Matrix { .. } => components
4867 .iter()
4868 .flat_map(|&comp| self.flatten(comp))
4869 .collect(),
4870 _ => unreachable!(),
4871 }
4872 }
4873
4874 fn int_to_vector_size(int: usize) -> VectorSize {
4875 match int {
4876 2 => VectorSize::Bi,
4877 3 => VectorSize::Tri,
4878 4 => VectorSize::Quad,
4879 _ => unreachable!(),
4880 }
4881 }
4882 }
4883
4884 #[test]
4885 fn cast() {
4886 let mut types = UniqueArena::new();
4887 let mut constants = Arena::new();
4888 let overrides = Arena::new();
4889 let mut global_expressions = Arena::new();
4890
4891 let scalar_ty = types.insert(
4892 Type {
4893 name: None,
4894 inner: TypeInner::Scalar(crate::Scalar::I32),
4895 },
4896 Default::default(),
4897 );
4898
4899 let h = constants.append(
4900 Constant {
4901 name: None,
4902 ty: scalar_ty,
4903 init: global_expressions
4904 .append(Expression::Literal(Literal::I32(4)), Default::default()),
4905 },
4906 Default::default(),
4907 );
4908
4909 let expr = global_expressions.append(Expression::Constant(h), Default::default());
4910
4911 let root = Expression::As {
4912 expr,
4913 kind: ScalarKind::Bool,
4914 convert: Some(crate::BOOL_WIDTH),
4915 };
4916
4917 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4918 let mut solver = ConstantEvaluator {
4919 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4920 types: &mut types,
4921 constants: &constants,
4922 overrides: &overrides,
4923 expressions: &mut global_expressions,
4924 expression_kind_tracker,
4925 layouter: &mut crate::proc::Layouter::default(),
4926 };
4927
4928 let res = solver
4929 .try_eval_and_append(root, Default::default())
4930 .unwrap();
4931
4932 assert_eq!(
4933 global_expressions[res],
4934 Expression::Literal(Literal::Bool(true))
4935 );
4936 }
4937
4938 #[test]
4939 fn access() {
4940 let mut types = UniqueArena::new();
4941 let mut constants = Arena::new();
4942 let overrides = Arena::new();
4943 let mut global_expressions = Arena::new();
4944
4945 let matrix_ty = types.insert(
4946 Type {
4947 name: None,
4948 inner: TypeInner::Matrix {
4949 columns: VectorSize::Bi,
4950 rows: VectorSize::Tri,
4951 scalar: crate::Scalar::F32,
4952 },
4953 },
4954 Default::default(),
4955 );
4956
4957 let vec_ty = types.insert(
4958 Type {
4959 name: None,
4960 inner: TypeInner::Vector {
4961 size: VectorSize::Tri,
4962 scalar: crate::Scalar::F32,
4963 },
4964 },
4965 Default::default(),
4966 );
4967
4968 let mut vec1_components = Vec::with_capacity(3);
4969 let mut vec2_components = Vec::with_capacity(3);
4970
4971 for i in 0..3 {
4972 let h = global_expressions.append(
4973 Expression::Literal(Literal::F32(i as f32)),
4974 Default::default(),
4975 );
4976
4977 vec1_components.push(h)
4978 }
4979
4980 for i in 3..6 {
4981 let h = global_expressions.append(
4982 Expression::Literal(Literal::F32(i as f32)),
4983 Default::default(),
4984 );
4985
4986 vec2_components.push(h)
4987 }
4988
4989 let vec1 = constants.append(
4990 Constant {
4991 name: None,
4992 ty: vec_ty,
4993 init: global_expressions.append(
4994 Expression::Compose {
4995 ty: vec_ty,
4996 components: vec1_components,
4997 },
4998 Default::default(),
4999 ),
5000 },
5001 Default::default(),
5002 );
5003
5004 let vec2 = constants.append(
5005 Constant {
5006 name: None,
5007 ty: vec_ty,
5008 init: global_expressions.append(
5009 Expression::Compose {
5010 ty: vec_ty,
5011 components: vec2_components,
5012 },
5013 Default::default(),
5014 ),
5015 },
5016 Default::default(),
5017 );
5018
5019 let h = constants.append(
5020 Constant {
5021 name: None,
5022 ty: matrix_ty,
5023 init: global_expressions.append(
5024 Expression::Compose {
5025 ty: matrix_ty,
5026 components: vec![constants[vec1].init, constants[vec2].init],
5027 },
5028 Default::default(),
5029 ),
5030 },
5031 Default::default(),
5032 );
5033
5034 let base = global_expressions.append(Expression::Constant(h), Default::default());
5035
5036 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5037 let mut solver = ConstantEvaluator {
5038 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5039 types: &mut types,
5040 constants: &constants,
5041 overrides: &overrides,
5042 expressions: &mut global_expressions,
5043 expression_kind_tracker,
5044 layouter: &mut crate::proc::Layouter::default(),
5045 };
5046
5047 let root1 = Expression::AccessIndex { base, index: 1 };
5048
5049 let res1 = solver
5050 .try_eval_and_append(root1, Default::default())
5051 .unwrap();
5052
5053 let root2 = Expression::AccessIndex {
5054 base: res1,
5055 index: 2,
5056 };
5057
5058 let res2 = solver
5059 .try_eval_and_append(root2, Default::default())
5060 .unwrap();
5061
5062 match global_expressions[res1] {
5063 Expression::Compose {
5064 ref ty,
5065 ref components,
5066 } => {
5067 assert_eq!(*ty, vec_ty);
5068 let mut components_iter = components.iter().copied();
5069 assert_eq!(
5070 global_expressions[components_iter.next().unwrap()],
5071 Expression::Literal(Literal::F32(3.))
5072 );
5073 assert_eq!(
5074 global_expressions[components_iter.next().unwrap()],
5075 Expression::Literal(Literal::F32(4.))
5076 );
5077 assert_eq!(
5078 global_expressions[components_iter.next().unwrap()],
5079 Expression::Literal(Literal::F32(5.))
5080 );
5081 assert!(components_iter.next().is_none());
5082 }
5083 _ => panic!("Expected vector"),
5084 }
5085
5086 assert_eq!(
5087 global_expressions[res2],
5088 Expression::Literal(Literal::F32(5.))
5089 );
5090 }
5091
5092 #[test]
5093 fn compose_of_constants() {
5094 let mut types = UniqueArena::new();
5095 let mut constants = Arena::new();
5096 let overrides = Arena::new();
5097 let mut global_expressions = Arena::new();
5098
5099 let i32_ty = types.insert(
5100 Type {
5101 name: None,
5102 inner: TypeInner::Scalar(crate::Scalar::I32),
5103 },
5104 Default::default(),
5105 );
5106
5107 let vec2_i32_ty = types.insert(
5108 Type {
5109 name: None,
5110 inner: TypeInner::Vector {
5111 size: VectorSize::Bi,
5112 scalar: crate::Scalar::I32,
5113 },
5114 },
5115 Default::default(),
5116 );
5117
5118 let h = constants.append(
5119 Constant {
5120 name: None,
5121 ty: i32_ty,
5122 init: global_expressions
5123 .append(Expression::Literal(Literal::I32(4)), Default::default()),
5124 },
5125 Default::default(),
5126 );
5127
5128 let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5129
5130 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5131 let mut solver = ConstantEvaluator {
5132 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5133 types: &mut types,
5134 constants: &constants,
5135 overrides: &overrides,
5136 expressions: &mut global_expressions,
5137 expression_kind_tracker,
5138 layouter: &mut crate::proc::Layouter::default(),
5139 };
5140
5141 let solved_compose = solver
5142 .try_eval_and_append(
5143 Expression::Compose {
5144 ty: vec2_i32_ty,
5145 components: vec![h_expr, h_expr],
5146 },
5147 Default::default(),
5148 )
5149 .unwrap();
5150 let solved_negate = solver
5151 .try_eval_and_append(
5152 Expression::Unary {
5153 op: UnaryOperator::Negate,
5154 expr: solved_compose,
5155 },
5156 Default::default(),
5157 )
5158 .unwrap();
5159
5160 let pass = match global_expressions[solved_negate] {
5161 Expression::Compose { ty, ref components } => {
5162 ty == vec2_i32_ty
5163 && components.iter().all(|&component| {
5164 let component = &global_expressions[component];
5165 matches!(*component, Expression::Literal(Literal::I32(-4)))
5166 })
5167 }
5168 _ => false,
5169 };
5170 if !pass {
5171 panic!("unexpected evaluation result")
5172 }
5173 }
5174
5175 #[test]
5176 fn splat_of_constant() {
5177 let mut types = UniqueArena::new();
5178 let mut constants = Arena::new();
5179 let overrides = Arena::new();
5180 let mut global_expressions = Arena::new();
5181
5182 let i32_ty = types.insert(
5183 Type {
5184 name: None,
5185 inner: TypeInner::Scalar(crate::Scalar::I32),
5186 },
5187 Default::default(),
5188 );
5189
5190 let vec2_i32_ty = types.insert(
5191 Type {
5192 name: None,
5193 inner: TypeInner::Vector {
5194 size: VectorSize::Bi,
5195 scalar: crate::Scalar::I32,
5196 },
5197 },
5198 Default::default(),
5199 );
5200
5201 let h = constants.append(
5202 Constant {
5203 name: None,
5204 ty: i32_ty,
5205 init: global_expressions
5206 .append(Expression::Literal(Literal::I32(4)), Default::default()),
5207 },
5208 Default::default(),
5209 );
5210
5211 let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5212
5213 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5214 let mut solver = ConstantEvaluator {
5215 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5216 types: &mut types,
5217 constants: &constants,
5218 overrides: &overrides,
5219 expressions: &mut global_expressions,
5220 expression_kind_tracker,
5221 layouter: &mut crate::proc::Layouter::default(),
5222 };
5223
5224 let solved_compose = solver
5225 .try_eval_and_append(
5226 Expression::Splat {
5227 size: VectorSize::Bi,
5228 value: h_expr,
5229 },
5230 Default::default(),
5231 )
5232 .unwrap();
5233 let solved_negate = solver
5234 .try_eval_and_append(
5235 Expression::Unary {
5236 op: UnaryOperator::Negate,
5237 expr: solved_compose,
5238 },
5239 Default::default(),
5240 )
5241 .unwrap();
5242
5243 let pass = match global_expressions[solved_negate] {
5244 Expression::Compose { ty, ref components } => {
5245 ty == vec2_i32_ty
5246 && components.iter().all(|&component| {
5247 let component = &global_expressions[component];
5248 matches!(*component, Expression::Literal(Literal::I32(-4)))
5249 })
5250 }
5251 _ => false,
5252 };
5253 if !pass {
5254 panic!("unexpected evaluation result")
5255 }
5256 }
5257
5258 #[test]
5259 fn splat_of_zero_value() {
5260 let mut types = UniqueArena::new();
5261 let constants = Arena::new();
5262 let overrides = Arena::new();
5263 let mut global_expressions = Arena::new();
5264
5265 let f32_ty = types.insert(
5266 Type {
5267 name: None,
5268 inner: TypeInner::Scalar(crate::Scalar::F32),
5269 },
5270 Default::default(),
5271 );
5272
5273 let vec2_f32_ty = types.insert(
5274 Type {
5275 name: None,
5276 inner: TypeInner::Vector {
5277 size: VectorSize::Bi,
5278 scalar: crate::Scalar::F32,
5279 },
5280 },
5281 Default::default(),
5282 );
5283
5284 let five =
5285 global_expressions.append(Expression::Literal(Literal::F32(5.0)), Default::default());
5286 let five_splat = global_expressions.append(
5287 Expression::Splat {
5288 size: VectorSize::Bi,
5289 value: five,
5290 },
5291 Default::default(),
5292 );
5293 let zero = global_expressions.append(Expression::ZeroValue(f32_ty), Default::default());
5294 let zero_splat = global_expressions.append(
5295 Expression::Splat {
5296 size: VectorSize::Bi,
5297 value: zero,
5298 },
5299 Default::default(),
5300 );
5301
5302 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5303 let mut solver = ConstantEvaluator {
5304 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5305 types: &mut types,
5306 constants: &constants,
5307 overrides: &overrides,
5308 expressions: &mut global_expressions,
5309 expression_kind_tracker,
5310 layouter: &mut crate::proc::Layouter::default(),
5311 };
5312
5313 let solved_add = solver
5314 .try_eval_and_append(
5315 Expression::Binary {
5316 op: BinaryOperator::Add,
5317 left: zero_splat,
5318 right: five_splat,
5319 },
5320 Default::default(),
5321 )
5322 .unwrap();
5323
5324 let pass = match global_expressions[solved_add] {
5325 Expression::Compose { ty, ref components } => {
5326 ty == vec2_f32_ty
5327 && components.iter().all(|&component| {
5328 let component = &global_expressions[component];
5329 matches!(*component, Expression::Literal(Literal::F32(5.0)))
5330 })
5331 }
5332 _ => false,
5333 };
5334 if !pass {
5335 panic!("unexpected evaluation result")
5336 }
5337 }
5338}