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, .. } | Expression::Bitcast { 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 { expr, target } => {
1317 let expr = self.check_and_get(expr)?;
1318 self.cast(expr, target, span)
1319 }
1320 Expression::Bitcast { .. } => Err(ConstantEvaluatorError::NotImplemented(
1321 "bitcast built-in function".into(),
1322 )),
1323 Expression::Select {
1324 reject,
1325 accept,
1326 condition,
1327 } => {
1328 let mut arg = |expr| self.check_and_get(expr);
1329
1330 let reject = arg(reject)?;
1331 let accept = arg(accept)?;
1332 let condition = arg(condition)?;
1333
1334 self.select(reject, accept, condition, span)
1335 }
1336 Expression::Relational { fun, argument } => {
1337 let argument = self.check_and_get(argument)?;
1338 self.relational(fun, argument, span)
1339 }
1340 Expression::ArrayLength(expr) => match self.behavior {
1341 Behavior::Wgsl(_) => Err(ConstantEvaluatorError::ArrayLength),
1342 Behavior::Glsl(_) => {
1343 let expr = self.check_and_get(expr)?;
1344 self.array_length(expr, span)
1345 }
1346 },
1347 Expression::Load { .. } => Err(ConstantEvaluatorError::Load),
1348 Expression::LocalVariable(_) => Err(ConstantEvaluatorError::LocalVariable),
1349 Expression::Derivative { .. } => Err(ConstantEvaluatorError::Derivative),
1350 Expression::CallResult { .. } => Err(ConstantEvaluatorError::Call),
1351 Expression::WorkGroupUniformLoadResult { .. } => {
1352 Err(ConstantEvaluatorError::WorkGroupUniformLoadResult)
1353 }
1354 Expression::AtomicResult { .. } => Err(ConstantEvaluatorError::Atomic),
1355 Expression::FunctionArgument(_) => Err(ConstantEvaluatorError::FunctionArg),
1356 Expression::GlobalVariable(_) => Err(ConstantEvaluatorError::GlobalVariable),
1357 Expression::ImageSample { .. }
1358 | Expression::ImageLoad { .. }
1359 | Expression::ImageQuery { .. } => Err(ConstantEvaluatorError::ImageExpression),
1360 Expression::RayQueryProceedResult
1361 | Expression::RayQueryGetIntersection { .. }
1362 | Expression::RayQueryVertexPositions { .. } => {
1363 Err(ConstantEvaluatorError::RayQueryExpression)
1364 }
1365 Expression::SubgroupBallotResult => Err(ConstantEvaluatorError::SubgroupExpression),
1366 Expression::SubgroupOperationResult { .. } => {
1367 Err(ConstantEvaluatorError::SubgroupExpression)
1368 }
1369 Expression::CooperativeLoad { .. } | Expression::CooperativeMultiplyAdd { .. } => {
1370 Err(ConstantEvaluatorError::CooperativeOperation)
1371 }
1372 }
1373 }
1374
1375 fn splat(
1388 &mut self,
1389 value: Handle<Expression>,
1390 size: crate::VectorSize,
1391 span: Span,
1392 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1393 match self.expressions[value] {
1394 Expression::Literal(literal) => {
1395 let scalar = literal.scalar();
1396 let ty = self.types.insert(
1397 Type {
1398 name: None,
1399 inner: TypeInner::Vector { size, scalar },
1400 },
1401 span,
1402 );
1403 let expr = Expression::Compose {
1404 ty,
1405 components: vec![value; size as usize],
1406 };
1407 self.register_evaluated_expr(expr, span)
1408 }
1409 Expression::ZeroValue(ty) => {
1410 let inner = match self.types[ty].inner {
1411 TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar },
1412 _ => return Err(ConstantEvaluatorError::SplatScalarOnly),
1413 };
1414 let res_ty = self.types.insert(Type { name: None, inner }, span);
1415 let expr = Expression::ZeroValue(res_ty);
1416 self.register_evaluated_expr(expr, span)
1417 }
1418 _ => Err(ConstantEvaluatorError::SplatScalarOnly),
1419 }
1420 }
1421
1422 fn swizzle(
1423 &mut self,
1424 size: crate::VectorSize,
1425 span: Span,
1426 src_constant: Handle<Expression>,
1427 pattern: [crate::SwizzleComponent; 4],
1428 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1429 let mut get_dst_ty = |ty| match self.types[ty].inner {
1430 TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
1431 Type {
1432 name: None,
1433 inner: TypeInner::Vector { size, scalar },
1434 },
1435 span,
1436 )),
1437 _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1438 };
1439
1440 match self.expressions[src_constant] {
1441 Expression::ZeroValue(ty) => {
1442 let dst_ty = get_dst_ty(ty)?;
1443 let expr = Expression::ZeroValue(dst_ty);
1444 self.register_evaluated_expr(expr, span)
1445 }
1446 Expression::Splat { value, .. } => {
1447 let expr = Expression::Splat { size, value };
1448 self.register_evaluated_expr(expr, span)
1449 }
1450 Expression::Compose { ty, ref components } => {
1451 let dst_ty = get_dst_ty(ty)?;
1452
1453 let mut flattened = [src_constant; 4]; let len =
1455 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
1456 .zip(flattened.iter_mut())
1457 .map(|(component, elt)| *elt = component)
1458 .count();
1459 let flattened = &flattened[..len];
1460
1461 let swizzled_components = pattern[..size as usize]
1462 .iter()
1463 .map(|&sc| {
1464 let sc = sc as usize;
1465 if let Some(elt) = flattened.get(sc) {
1466 Ok(*elt)
1467 } else {
1468 Err(ConstantEvaluatorError::SwizzleOutOfBounds)
1469 }
1470 })
1471 .collect::<Result<Vec<Handle<Expression>>, _>>()?;
1472 let expr = Expression::Compose {
1473 ty: dst_ty,
1474 components: swizzled_components,
1475 };
1476 self.register_evaluated_expr(expr, span)
1477 }
1478 _ => Err(ConstantEvaluatorError::SwizzleVectorOnly),
1479 }
1480 }
1481
1482 fn math(
1483 &mut self,
1484 arg: Handle<Expression>,
1485 arg1: Option<Handle<Expression>>,
1486 arg2: Option<Handle<Expression>>,
1487 arg3: Option<Handle<Expression>>,
1488 fun: crate::MathFunction,
1489 span: Span,
1490 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
1491 let expected = fun.argument_count();
1492 let given = Some(arg)
1493 .into_iter()
1494 .chain(arg1)
1495 .chain(arg2)
1496 .chain(arg3)
1497 .count();
1498 if expected != given {
1499 return Err(ConstantEvaluatorError::InvalidMathArgCount(
1500 fun, expected, given,
1501 ));
1502 }
1503
1504 match fun {
1506 crate::MathFunction::Abs => {
1508 component_wise_scalar(self, span, [arg], |args| match args {
1509 Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
1510 Scalar::F32([e]) => Ok(Scalar::F32([e.abs()])),
1511 Scalar::F16([e]) => Ok(Scalar::F16([e.abs()])),
1512 Scalar::AbstractInt([e]) => Ok(Scalar::AbstractInt([e.wrapping_abs()])),
1513 Scalar::I32([e]) => Ok(Scalar::I32([e.wrapping_abs()])),
1514 Scalar::U32([e]) => Ok(Scalar::U32([e])), Scalar::I64([e]) => Ok(Scalar::I64([e.wrapping_abs()])),
1516 Scalar::U64([e]) => Ok(Scalar::U64([e])),
1517 })
1518 }
1519 crate::MathFunction::Min => {
1520 component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1521 Ok([e1.min(e2)])
1522 })
1523 }
1524 crate::MathFunction::Max => {
1525 component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1526 Ok([e1.max(e2)])
1527 })
1528 }
1529 crate::MathFunction::Clamp => {
1530 component_wise_scalar!(
1531 self,
1532 span,
1533 [arg, arg1.unwrap(), arg2.unwrap()],
1534 |e, low, high| {
1535 if low > high {
1536 Err(ConstantEvaluatorError::InvalidClamp)
1537 } else {
1538 Ok([e.clamp(low, high)])
1539 }
1540 }
1541 )
1542 }
1543 crate::MathFunction::Saturate => component_wise_float(self, span, [arg], |e| match e {
1544 Float::F16([e]) => Ok(Float::F16(
1545 [e.clamp(f16::from_f32(0.0), f16::from_f32(1.0))],
1546 )),
1547 Float::F32([e]) => Ok(Float::F32([e.clamp(0., 1.)])),
1548 Float::Abstract([e]) => Ok(Float::Abstract([e.clamp(0., 1.)])),
1549 }),
1550
1551 crate::MathFunction::Cos => {
1553 component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) })
1554 }
1555 crate::MathFunction::Cosh => {
1556 component_wise_float!(self, span, [arg], |e| {
1557 let result = e.cosh();
1558 if result.is_finite() {
1559 Ok([result])
1560 } else {
1561 Err(ConstantEvaluatorError::Overflow("cosh".into()))
1562 }
1563 })
1564 }
1565 crate::MathFunction::Sin => {
1566 component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
1567 }
1568 crate::MathFunction::Sinh => {
1569 component_wise_float!(self, span, [arg], |e| {
1570 let result = e.sinh();
1571 if result.is_finite() {
1572 Ok([result])
1573 } else {
1574 Err(ConstantEvaluatorError::Overflow("sinh".into()))
1575 }
1576 })
1577 }
1578 crate::MathFunction::Tan => {
1579 component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
1580 }
1581 crate::MathFunction::Tanh => {
1582 component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
1583 }
1584 crate::MathFunction::Acos => {
1585 component_wise_float!(self, span, [arg], |e| {
1586 if e.abs() <= One::one() {
1587 Ok([e.acos()])
1588 } else {
1589 Err(ConstantEvaluatorError::InvalidMathArgValue("acos".into()))
1590 }
1591 })
1592 }
1593 crate::MathFunction::Asin => {
1594 component_wise_float!(self, span, [arg], |e| {
1595 if e.abs() <= One::one() {
1596 Ok([e.asin()])
1597 } else {
1598 Err(ConstantEvaluatorError::InvalidMathArgValue("asin".into()))
1599 }
1600 })
1601 }
1602 crate::MathFunction::Atan => {
1603 component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
1604 }
1605 crate::MathFunction::Atan2 => {
1606 component_wise_float!(self, span, [arg, arg1.unwrap()], |y, x| {
1607 Ok([y.atan2(x)])
1608 })
1609 }
1610 crate::MathFunction::Asinh => component_wise_float(self, span, [arg], |e| match e {
1611 Float::Abstract([e]) => Ok(Float::Abstract([libm::asinh(e)])),
1612 Float::F32([e]) => Ok(Float::F32([(e as f64).asinh() as f32])),
1613 Float::F16([e]) => Ok(Float::F16([e.asinh()])),
1614 }),
1615 crate::MathFunction::Acosh => component_wise_float(self, span, [arg], |e| match e {
1616 Float::Abstract([e]) if e >= One::one() => Ok(Float::Abstract([libm::acosh(e)])),
1617 Float::F32([e]) if e >= One::one() => Ok(Float::F32([(e as f64).acosh() as f32])),
1618 Float::F16([e]) if e >= One::one() => Ok(Float::F16([e.acosh()])),
1619 _ => Err(ConstantEvaluatorError::InvalidMathArgValue("acosh".into())),
1620 }),
1621 crate::MathFunction::Atanh => {
1622 component_wise_float!(self, span, [arg], |e| {
1623 if e.abs() < One::one() {
1624 Ok([e.atanh()])
1625 } else {
1626 Err(ConstantEvaluatorError::InvalidMathArgValue("atanh".into()))
1627 }
1628 })
1629 }
1630 crate::MathFunction::Radians => {
1631 component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) })
1632 }
1633 crate::MathFunction::Degrees => {
1634 component_wise_float!(self, span, [arg], |e| {
1635 let result = e.to_degrees();
1636 if result.is_finite() {
1637 Ok([result])
1638 } else {
1639 Err(ConstantEvaluatorError::Overflow("degrees".into()))
1640 }
1641 })
1642 }
1643
1644 crate::MathFunction::Ceil => {
1646 component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) })
1647 }
1648 crate::MathFunction::Floor => {
1649 component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
1650 }
1651 crate::MathFunction::Round => {
1652 component_wise_float(self, span, [arg], |e| match e {
1653 Float::Abstract([e]) => Ok(Float::Abstract([libm::rint(e)])),
1654 Float::F32([e]) => Ok(Float::F32([libm::rintf(e)])),
1655 Float::F16([e]) => {
1656 fn round_ties_even(x: f64) -> f64 {
1664 let i = x as i64;
1665 let f = (x - i as f64).abs();
1666 if f == 0.5 {
1667 if i & 1 == 1 {
1668 (x.abs() + 0.5).copysign(x)
1670 } else {
1671 (x.abs() - 0.5).copysign(x)
1672 }
1673 } else {
1674 x.round()
1675 }
1676 }
1677
1678 Ok(Float::F16([(f16::from_f64(round_ties_even(f64::from(e))))]))
1679 }
1680 })
1681 }
1682 crate::MathFunction::Fract => {
1683 component_wise_float!(self, span, [arg], |e| {
1684 Ok([e - e.floor()])
1687 })
1688 }
1689 crate::MathFunction::Trunc => {
1690 component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) })
1691 }
1692
1693 crate::MathFunction::Exp => {
1695 component_wise_float!(self, span, [arg], |e| {
1696 let result = e.exp();
1697 if result.is_finite() {
1698 Ok([result])
1699 } else {
1700 Err(ConstantEvaluatorError::Overflow("exp".into()))
1701 }
1702 })
1703 }
1704 crate::MathFunction::Exp2 => {
1705 component_wise_float!(self, span, [arg], |e| {
1706 let result = e.exp2();
1707 if result.is_finite() {
1708 Ok([result])
1709 } else {
1710 Err(ConstantEvaluatorError::Overflow("exp2".into()))
1711 }
1712 })
1713 }
1714 crate::MathFunction::Log => {
1715 component_wise_float!(self, span, [arg], |e| {
1716 if e > Zero::zero() {
1717 Ok([e.ln()])
1718 } else {
1719 Err(ConstantEvaluatorError::InvalidMathArgValue("log".into()))
1720 }
1721 })
1722 }
1723 crate::MathFunction::Log2 => {
1724 component_wise_float!(self, span, [arg], |e| {
1725 if e > Zero::zero() {
1726 Ok([e.log2()])
1727 } else {
1728 Err(ConstantEvaluatorError::InvalidMathArgValue("log2".into()))
1729 }
1730 })
1731 }
1732 crate::MathFunction::Pow => {
1733 component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
1734 if e1 < Zero::zero()
1737 || e1.is_one() && e2.is_infinite()
1738 || e1.is_infinite() && e2.is_zero()
1739 || e1.is_zero() && e2.is_zero()
1740 {
1741 Err(ConstantEvaluatorError::InvalidMathArgValue("pow".into()))
1742 } else {
1743 let result = e1.powf(e2);
1744 if result.is_finite() {
1745 Ok([result])
1746 } else {
1747 Err(ConstantEvaluatorError::Overflow("pow".into()))
1748 }
1749 }
1750 })
1751 }
1752
1753 crate::MathFunction::Sign => {
1755 component_wise_signed!(self, span, [arg], |e| {
1756 Ok([if e.is_zero() {
1757 Zero::zero()
1758 } else {
1759 e.signum()
1760 }])
1761 })
1762 }
1763 crate::MathFunction::Fma => {
1764 component_wise_float!(
1765 self,
1766 span,
1767 [arg, arg1.unwrap(), arg2.unwrap()],
1768 |e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) }
1769 )
1770 }
1771 crate::MathFunction::Step => {
1772 component_wise_float(self, span, [arg, arg1.unwrap()], |x| match x {
1773 Float::Abstract([edge, x]) => {
1774 Ok(Float::Abstract([if edge <= x { 1.0 } else { 0.0 }]))
1775 }
1776 Float::F32([edge, x]) => Ok(Float::F32([if edge <= x { 1.0 } else { 0.0 }])),
1777 Float::F16([edge, x]) => Ok(Float::F16([if edge <= x {
1778 f16::one()
1779 } else {
1780 f16::zero()
1781 }])),
1782 })
1783 }
1784 crate::MathFunction::Sqrt => {
1785 component_wise_float!(self, span, [arg], |e| {
1786 if e >= Zero::zero() {
1787 Ok([e.sqrt()])
1788 } else {
1789 Err(ConstantEvaluatorError::InvalidMathArgValue("sqrt".into()))
1790 }
1791 })
1792 }
1793 crate::MathFunction::InverseSqrt => {
1794 component_wise_float(self, span, [arg], |e| match e {
1795 Float::Abstract([e]) => Ok(Float::Abstract([1. / e.sqrt()])),
1796 Float::F32([e]) => Ok(Float::F32([1. / e.sqrt()])),
1797 Float::F16([e]) => Ok(Float::F16([f16::from_f32(1. / f32::from(e).sqrt())])),
1798 })
1799 }
1800
1801 crate::MathFunction::CountTrailingZeros => {
1803 component_wise_concrete_int!(self, span, [arg], |e| {
1804 #[allow(clippy::useless_conversion)]
1805 Ok([e
1806 .trailing_zeros()
1807 .try_into()
1808 .expect("bit count overflowed 32 bits, somehow!?")])
1809 })
1810 }
1811 crate::MathFunction::CountLeadingZeros => {
1812 component_wise_concrete_int!(self, span, [arg], |e| {
1813 #[allow(clippy::useless_conversion)]
1814 Ok([e
1815 .leading_zeros()
1816 .try_into()
1817 .expect("bit count overflowed 32 bits, somehow!?")])
1818 })
1819 }
1820 crate::MathFunction::CountOneBits => {
1821 component_wise_concrete_int!(self, span, [arg], |e| {
1822 #[allow(clippy::useless_conversion)]
1823 Ok([e
1824 .count_ones()
1825 .try_into()
1826 .expect("bit count overflowed 32 bits, somehow!?")])
1827 })
1828 }
1829 crate::MathFunction::ReverseBits => {
1830 component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
1831 }
1832 crate::MathFunction::ExtractBits => {
1833 let (offset, count) = self.bitfield_range(arg1.unwrap(), arg2.unwrap(), span)?;
1835 let e = self.extract_vec(arg, true)?;
1836
1837 let result = match_literal_vector!(match e => LiteralVector {
1838 I16 => |e| { extract_bits(e, offset, count)? },
1839 U16 => |e| { extract_bits(e, offset, count)? },
1840 I32 => |e| { extract_bits(e, offset, count)? },
1841 U32 => |e| { extract_bits(e, offset, count)? },
1842 I64 => |e| { extract_bits(e, offset, count)? },
1843 U64 => |e| { extract_bits(e, offset, count)? },
1844 })?;
1845 result.register_as_evaluated_expr(self, span)
1846 }
1847 crate::MathFunction::InsertBits => {
1848 let (offset, count) = self.bitfield_range(arg2.unwrap(), arg3.unwrap(), span)?;
1850 let e = self.extract_vec(arg, true)?;
1851 let newbits = self.extract_vec(arg1.unwrap(), true)?;
1852 if e.len() != newbits.len() {
1853 return Err(ConstantEvaluatorError::InvalidMathArg);
1854 }
1855
1856 let result = match_literal_vector!(match (e, newbits) => LiteralVector {
1857 I16 => |e, n| { insert_bits(e, n, offset, count)? },
1858 U16 => |e, n| { insert_bits(e, n, offset, count)? },
1859 I32 => |e, n| { insert_bits(e, n, offset, count)? },
1860 U32 => |e, n| { insert_bits(e, n, offset, count)? },
1861 I64 => |e, n| { insert_bits(e, n, offset, count)? },
1862 U64 => |e, n| { insert_bits(e, n, offset, count)? },
1863 })?;
1864 result.register_as_evaluated_expr(self, span)
1865 }
1866 crate::MathFunction::FirstTrailingBit => {
1867 component_wise_concrete_int(self, span, [arg], |ci| Ok(first_trailing_bit(ci)))
1868 }
1869 crate::MathFunction::FirstLeadingBit => {
1870 component_wise_concrete_int(self, span, [arg], |ci| Ok(first_leading_bit(ci)))
1871 }
1872
1873 crate::MathFunction::Dot4I8Packed => {
1875 self.packed_dot_product(arg, arg1.unwrap(), span, true)
1876 }
1877 crate::MathFunction::Dot4U8Packed => {
1878 self.packed_dot_product(arg, arg1.unwrap(), span, false)
1879 }
1880 crate::MathFunction::Cross => self.cross_product(arg, arg1.unwrap(), span),
1881 crate::MathFunction::Dot => {
1882 let e1 = self.extract_vec(arg, false)?;
1884 let e2 = self.extract_vec(arg1.unwrap(), false)?;
1885 if e1.len() != e2.len() {
1886 return Err(ConstantEvaluatorError::InvalidMathArg);
1887 }
1888
1889 fn int_dot_checked<P>(a: &[P], b: &[P]) -> Result<P, ConstantEvaluatorError>
1890 where
1891 P: num_traits::PrimInt + num_traits::CheckedAdd + num_traits::CheckedMul,
1892 {
1893 a.iter()
1894 .zip(b.iter())
1895 .map(|(&aa, bb)| aa.checked_mul(bb))
1896 .try_fold(P::zero(), |acc, x| {
1897 if let Some(x) = x {
1898 acc.checked_add(&x)
1899 } else {
1900 None
1901 }
1902 })
1903 .ok_or(ConstantEvaluatorError::Overflow(
1904 "in dot built-in".to_string(),
1905 ))
1906 }
1907
1908 fn int_dot_wrapping<P>(a: &[P], b: &[P]) -> P
1909 where
1910 P: num_traits::PrimInt + num_traits::WrappingAdd + num_traits::WrappingMul,
1911 {
1912 a.iter()
1913 .zip(b.iter())
1914 .map(|(&aa, bb)| aa.wrapping_mul(bb))
1915 .fold(P::zero(), |acc, x| acc.wrapping_add(&x))
1916 }
1917
1918 let result = match_literal_vector!(match (e1, e2) => Literal {
1919 Float => |e1, e2| {
1920 float_dot(e1, e2).ok_or_else(|| {
1921 ConstantEvaluatorError::Overflow("in mathfunction::dot".into())
1922 })?
1923 },
1924 AbstractInt => |e1, e2 | { int_dot_checked(e1, e2)? },
1925 I32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1926 U32 => |e1, e2| { int_dot_wrapping(e1, e2) },
1927 })?;
1928 self.register_evaluated_expr(Expression::Literal(result), span)
1929 }
1930 crate::MathFunction::Length => {
1931 let e1 = self.extract_vec(arg, true)?;
1933
1934 let result = match_literal_vector!(match e1 => Literal {
1935 Float => |e1| {
1936 float_length(e1).ok_or_else(|| ConstantEvaluatorError::Overflow("length".into()))?
1937 },
1938 })?;
1939 self.register_evaluated_expr(Expression::Literal(result), span)
1940 }
1941 crate::MathFunction::Distance => {
1942 let e1 = self.extract_vec(arg, true)?;
1944 let e2 = self.extract_vec(arg1.unwrap(), true)?;
1945 if e1.len() != e2.len() {
1946 return Err(ConstantEvaluatorError::InvalidMathArg);
1947 }
1948
1949 fn float_distance<F>(a: &[F], b: &[F]) -> F
1950 where
1951 F: core::ops::Mul<F>,
1952 F: num_traits::Float + iter::Sum + core::ops::Sub,
1953 {
1954 if a.len() == 1 {
1955 (a[0] - b[0]).abs()
1957 } else {
1958 a.iter()
1959 .zip(b.iter())
1960 .map(|(&aa, &bb)| aa - bb)
1961 .map(|ei| ei * ei)
1962 .sum::<F>()
1963 .sqrt()
1964 }
1965 }
1966 let result = match_literal_vector!(match (e1, e2) => Literal {
1967 Float => |e1, e2| { float_distance(e1, e2) },
1968 })?;
1969 self.register_evaluated_expr(Expression::Literal(result), span)
1970 }
1971 crate::MathFunction::Normalize => {
1972 let e1 = self.extract_vec(arg, true)?;
1974
1975 fn float_normalize<F>(
1976 e: &[F],
1977 ) -> Result<ArrayVec<F, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
1978 where
1979 F: core::ops::Mul<F>,
1980 F: num_traits::Float + iter::Sum,
1981 {
1982 let len = match float_length(e) {
1983 Some(len) if !len.is_zero() => Ok(len),
1984 Some(_) => Err(ConstantEvaluatorError::InvalidMathArgValue(
1985 "normalize".into(),
1986 )),
1987 None => Err(ConstantEvaluatorError::Overflow("normalize".into())),
1988 }?;
1989
1990 let mut out = ArrayVec::new();
1991 for &ei in e {
1992 out.push(ei / len);
1993 }
1994 Ok(out)
1995 }
1996
1997 let result = match_literal_vector!(match e1 => LiteralVector {
1998 Float => |e1| { float_normalize(e1)? },
1999 })?;
2000 result.register_as_evaluated_expr(self, span)
2001 }
2002 crate::MathFunction::FaceForward => {
2003 let e1 = self.extract_vec(arg, false)?;
2005 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2006 let e3 = self.extract_vec(arg2.unwrap(), false)?;
2007 if e1.len() != e2.len() || e1.len() != e3.len() {
2008 return Err(ConstantEvaluatorError::InvalidMathArg);
2009 }
2010
2011 let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2012 Float => |e1, e2, e3| {
2013 float_face_forward(e1, e2, e3).ok_or_else(|| {
2014 ConstantEvaluatorError::Overflow("in mathfunction::faceforward".into())
2015 })?
2016 },
2017 })?;
2018 result.register_as_evaluated_expr(self, span)
2019 }
2020 crate::MathFunction::Reflect => {
2021 let e1 = self.extract_vec(arg, false)?;
2023 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2024 if e1.len() != e2.len() {
2025 return Err(ConstantEvaluatorError::InvalidMathArg);
2026 }
2027
2028 let result = match_literal_vector!(match (e1, e2) => LiteralVector {
2029 Float => |e1, e2| {
2030 float_reflect(e1, e2)
2031 .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::reflect".into()))?
2032 },
2033 })?;
2034 result.register_as_evaluated_expr(self, span)
2035 }
2036 crate::MathFunction::Refract => {
2037 let e1 = self.extract_vec(arg, false)?;
2039 let e2 = self.extract_vec(arg1.unwrap(), false)?;
2040 let e3 = self.extract_vec(arg2.unwrap(), true)?;
2043 if e1.len() != e2.len() || e3.len() != 1 {
2044 return Err(ConstantEvaluatorError::InvalidMathArg);
2045 }
2046
2047 let result = match_literal_vector!(match (e1, e2, e3) => LiteralVector {
2048 Float => |e1, e2, e3| {
2049 float_refract(e1, e2, e3[0])
2050 .ok_or_else(|| ConstantEvaluatorError::Overflow("in mathfunction::refract".into()))?
2051 },
2052 })?;
2053 result.register_as_evaluated_expr(self, span)
2054 }
2055
2056 crate::MathFunction::Modf
2058 | crate::MathFunction::Frexp
2059 | crate::MathFunction::Ldexp
2060 | crate::MathFunction::Outer
2061 | crate::MathFunction::Mix
2062 | crate::MathFunction::SmoothStep
2063 | crate::MathFunction::Inverse
2064 | crate::MathFunction::Transpose
2065 | crate::MathFunction::Determinant
2066 | crate::MathFunction::QuantizeToF16
2067 | crate::MathFunction::Pack4x8snorm
2068 | crate::MathFunction::Pack4x8unorm
2069 | crate::MathFunction::Pack2x16snorm
2070 | crate::MathFunction::Pack2x16unorm
2071 | crate::MathFunction::Pack2x16float
2072 | crate::MathFunction::Pack4xI8
2073 | crate::MathFunction::Pack4xU8
2074 | crate::MathFunction::Pack4xI8Clamp
2075 | crate::MathFunction::Pack4xU8Clamp
2076 | crate::MathFunction::Unpack4x8snorm
2077 | crate::MathFunction::Unpack4x8unorm
2078 | crate::MathFunction::Unpack2x16snorm
2079 | crate::MathFunction::Unpack2x16unorm
2080 | crate::MathFunction::Unpack2x16float
2081 | crate::MathFunction::Unpack4xI8
2082 | crate::MathFunction::Unpack4xU8 => Err(ConstantEvaluatorError::NotImplemented(
2083 format!("{fun:?} built-in function"),
2084 )),
2085 }
2086 }
2087
2088 fn packed_dot_product(
2090 &mut self,
2091 a: Handle<Expression>,
2092 b: Handle<Expression>,
2093 span: Span,
2094 signed: bool,
2095 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2096 let Expression::Literal(Literal::U32(a)) = self.expressions[a] else {
2097 return Err(ConstantEvaluatorError::InvalidMathArg);
2098 };
2099 let Expression::Literal(Literal::U32(b)) = self.expressions[b] else {
2100 return Err(ConstantEvaluatorError::InvalidMathArg);
2101 };
2102
2103 let result = if signed {
2104 Literal::I32(
2105 (a & 0xFF) as i8 as i32 * (b & 0xFF) as i8 as i32
2106 + ((a >> 8) & 0xFF) as i8 as i32 * ((b >> 8) & 0xFF) as i8 as i32
2107 + ((a >> 16) & 0xFF) as i8 as i32 * ((b >> 16) & 0xFF) as i8 as i32
2108 + ((a >> 24) & 0xFF) as i8 as i32 * ((b >> 24) & 0xFF) as i8 as i32,
2109 )
2110 } else {
2111 Literal::U32(
2112 (a & 0xFF) * (b & 0xFF)
2113 + ((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)
2114 + ((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)
2115 + ((a >> 24) & 0xFF) * ((b >> 24) & 0xFF),
2116 )
2117 };
2118
2119 self.register_evaluated_expr(Expression::Literal(result), span)
2120 }
2121
2122 fn cross_product(
2124 &mut self,
2125 a: Handle<Expression>,
2126 b: Handle<Expression>,
2127 span: Span,
2128 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2129 use Literal as Li;
2130
2131 let (a, ty) = self.extract_vec_with_size::<3>(a)?;
2132 let (b, _) = self.extract_vec_with_size::<3>(b)?;
2133
2134 let product = match (a, b) {
2135 (
2136 [Li::AbstractInt(a0), Li::AbstractInt(a1), Li::AbstractInt(a2)],
2137 [Li::AbstractInt(b0), Li::AbstractInt(b1), Li::AbstractInt(b2)],
2138 ) => {
2139 let p = cross_product(
2144 [a0 as f64, a1 as f64, a2 as f64],
2145 [b0 as f64, b1 as f64, b2 as f64],
2146 );
2147 [
2148 Li::AbstractFloat(p[0]),
2149 Li::AbstractFloat(p[1]),
2150 Li::AbstractFloat(p[2]),
2151 ]
2152 }
2153 (
2154 [Li::AbstractFloat(a0), Li::AbstractFloat(a1), Li::AbstractFloat(a2)],
2155 [Li::AbstractFloat(b0), Li::AbstractFloat(b1), Li::AbstractFloat(b2)],
2156 ) => {
2157 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2158 [
2159 Li::AbstractFloat(p[0]),
2160 Li::AbstractFloat(p[1]),
2161 Li::AbstractFloat(p[2]),
2162 ]
2163 }
2164 ([Li::F16(a0), Li::F16(a1), Li::F16(a2)], [Li::F16(b0), Li::F16(b1), Li::F16(b2)]) => {
2165 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2166 [Li::F16(p[0]), Li::F16(p[1]), Li::F16(p[2])]
2167 }
2168 ([Li::F32(a0), Li::F32(a1), Li::F32(a2)], [Li::F32(b0), Li::F32(b1), Li::F32(b2)]) => {
2169 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2170 [Li::F32(p[0]), Li::F32(p[1]), Li::F32(p[2])]
2171 }
2172 ([Li::F64(a0), Li::F64(a1), Li::F64(a2)], [Li::F64(b0), Li::F64(b1), Li::F64(b2)]) => {
2173 let p = cross_product([a0, a1, a2], [b0, b1, b2]);
2174 [Li::F64(p[0]), Li::F64(p[1]), Li::F64(p[2])]
2175 }
2176 _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2177 };
2178
2179 let p0 = self.register_evaluated_expr(Expression::Literal(product[0]), span)?;
2180 let p1 = self.register_evaluated_expr(Expression::Literal(product[1]), span)?;
2181 let p2 = self.register_evaluated_expr(Expression::Literal(product[2]), span)?;
2182
2183 self.register_evaluated_expr(
2184 Expression::Compose {
2185 ty,
2186 components: vec![p0, p1, p2],
2187 },
2188 span,
2189 )
2190 }
2191
2192 fn extract_vec_with_size<const N: usize>(
2200 &mut self,
2201 expr: Handle<Expression>,
2202 ) -> Result<([Literal; N], Handle<Type>), ConstantEvaluatorError> {
2203 let span = self.expressions.get_span(expr);
2204 let expr = self.eval_zero_value_and_splat(expr, span)?;
2205 let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2206 return Err(ConstantEvaluatorError::InvalidMathArg);
2207 };
2208
2209 let mut value = [Literal::Bool(false); N];
2210 for (component, elt) in
2211 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2212 .zip(value.iter_mut())
2213 {
2214 let Expression::Literal(literal) = self.expressions[component] else {
2215 return Err(ConstantEvaluatorError::InvalidMathArg);
2216 };
2217 *elt = literal;
2218 }
2219
2220 Ok((value, ty))
2221 }
2222
2223 fn extract_vec(
2231 &mut self,
2232 expr: Handle<Expression>,
2233 allow_single: bool,
2234 ) -> Result<LiteralVector, ConstantEvaluatorError> {
2235 let span = self.expressions.get_span(expr);
2236 let expr = self.eval_zero_value_and_splat(expr, span)?;
2237
2238 match self.expressions[expr] {
2239 Expression::Literal(literal) if allow_single => {
2240 Ok(LiteralVector::from_literal(literal))
2241 }
2242 Expression::Compose { ty, ref components } => {
2243 let mut components_out = ArrayVec::<Literal, { crate::VectorSize::MAX }>::new();
2244 for expr in
2245 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2246 {
2247 match self.expressions[expr] {
2248 Expression::Literal(l) => components_out.push(l),
2249 _ => return Err(ConstantEvaluatorError::InvalidMathArg),
2250 }
2251 }
2252 LiteralVector::from_literal_vec(components_out)
2253 }
2254 _ => Err(ConstantEvaluatorError::InvalidMathArg),
2255 }
2256 }
2257
2258 fn bitfield_range(
2261 &mut self,
2262 offset: Handle<Expression>,
2263 count: Handle<Expression>,
2264 span: Span,
2265 ) -> Result<(u32, u32), ConstantEvaluatorError> {
2266 let offset = self.eval_zero_value_and_splat(offset, span)?;
2267 let count = self.eval_zero_value_and_splat(count, span)?;
2268
2269 match (&self.expressions[offset], &self.expressions[count]) {
2270 (
2271 &Expression::Literal(Literal::U32(offset)),
2272 &Expression::Literal(Literal::U32(count)),
2273 ) => Ok((offset, count)),
2274 _ => Err(ConstantEvaluatorError::InvalidMathArg),
2275 }
2276 }
2277
2278 fn array_length(
2279 &mut self,
2280 array: Handle<Expression>,
2281 span: Span,
2282 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2283 match self.expressions[array] {
2284 Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => {
2285 match self.types[ty].inner {
2286 TypeInner::Array { size, .. } => match size {
2287 ArraySize::Constant(len) => {
2288 let expr = Expression::Literal(Literal::U32(len.get()));
2289 self.register_evaluated_expr(expr, span)
2290 }
2291 ArraySize::Pending(_) => Err(ConstantEvaluatorError::ArrayLengthOverridden),
2292 ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic),
2293 },
2294 _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2295 }
2296 }
2297 _ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
2298 }
2299 }
2300
2301 fn access(
2302 &mut self,
2303 base: Handle<Expression>,
2304 index: usize,
2305 span: Span,
2306 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2307 match self.expressions[base] {
2308 Expression::ZeroValue(ty) => {
2309 let ty_inner = &self.types[ty].inner;
2310 let components = ty_inner
2311 .components()
2312 .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2313
2314 if index >= components as usize {
2315 Err(ConstantEvaluatorError::InvalidAccessBase)
2316 } else {
2317 let ty_res = ty_inner
2318 .component_type(index)
2319 .ok_or(ConstantEvaluatorError::InvalidAccessIndex)?;
2320 let ty = match ty_res {
2321 crate::proc::TypeResolution::Handle(ty) => ty,
2322 crate::proc::TypeResolution::Value(inner) => {
2323 self.types.insert(Type { name: None, inner }, span)
2324 }
2325 };
2326 self.register_evaluated_expr(Expression::ZeroValue(ty), span)
2327 }
2328 }
2329 Expression::Splat { size, value } => {
2330 if index >= size as usize {
2331 Err(ConstantEvaluatorError::InvalidAccessBase)
2332 } else {
2333 Ok(value)
2334 }
2335 }
2336 Expression::Compose { ty, ref components } => {
2337 let _ = self.types[ty]
2338 .inner
2339 .components()
2340 .ok_or(ConstantEvaluatorError::InvalidAccessBase)?;
2341
2342 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
2343 .nth(index)
2344 .ok_or(ConstantEvaluatorError::InvalidAccessIndex)
2345 }
2346 _ => Err(ConstantEvaluatorError::InvalidAccessBase),
2347 }
2348 }
2349
2350 fn eval_zero_value_and_splat(
2357 &mut self,
2358 mut expr: Handle<Expression>,
2359 span: Span,
2360 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2361 if let Expression::Compose { ty, ref components } = self.expressions[expr] {
2364 let components = components
2365 .clone()
2366 .iter()
2367 .map(|component| self.eval_zero_value_and_splat(*component, span))
2368 .collect::<Result<_, _>>()?;
2369 expr = self.register_evaluated_expr(Expression::Compose { ty, components }, span)?;
2370 }
2371
2372 if let Expression::Splat { size, value } = self.expressions[expr] {
2376 expr = self.splat(value, size, span)?;
2377 }
2378 if let Expression::ZeroValue(ty) = self.expressions[expr] {
2379 expr = self.eval_zero_value_impl(ty, span)?;
2380 }
2381 Ok(expr)
2382 }
2383
2384 fn eval_zero_value(
2390 &mut self,
2391 expr: Handle<Expression>,
2392 span: Span,
2393 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2394 match self.expressions[expr] {
2395 Expression::ZeroValue(ty) => self.eval_zero_value_impl(ty, span),
2396 _ => Ok(expr),
2397 }
2398 }
2399
2400 fn eval_zero_value_impl(
2406 &mut self,
2407 ty: Handle<Type>,
2408 span: Span,
2409 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2410 match self.types[ty].inner {
2411 TypeInner::Scalar(scalar) => {
2412 let expr = Expression::Literal(
2413 Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
2414 );
2415 self.register_evaluated_expr(expr, span)
2416 }
2417 TypeInner::Vector { size, scalar } => {
2418 let scalar_ty = self.types.insert(
2419 Type {
2420 name: None,
2421 inner: TypeInner::Scalar(scalar),
2422 },
2423 span,
2424 );
2425 let el = self.eval_zero_value_impl(scalar_ty, span)?;
2426 let expr = Expression::Compose {
2427 ty,
2428 components: vec![el; size as usize],
2429 };
2430 self.register_evaluated_expr(expr, span)
2431 }
2432 TypeInner::Matrix {
2433 columns,
2434 rows,
2435 scalar,
2436 } => {
2437 let vec_ty = self.types.insert(
2438 Type {
2439 name: None,
2440 inner: TypeInner::Vector { size: rows, scalar },
2441 },
2442 span,
2443 );
2444 let el = self.eval_zero_value_impl(vec_ty, span)?;
2445 let expr = Expression::Compose {
2446 ty,
2447 components: vec![el; columns as usize],
2448 };
2449 self.register_evaluated_expr(expr, span)
2450 }
2451 TypeInner::Array {
2452 base,
2453 size: ArraySize::Constant(size),
2454 ..
2455 } => {
2456 let el = self.eval_zero_value_impl(base, span)?;
2457 let expr = Expression::Compose {
2458 ty,
2459 components: vec![el; size.get() as usize],
2460 };
2461 self.register_evaluated_expr(expr, span)
2462 }
2463 TypeInner::Struct { ref members, .. } => {
2464 let types: Vec<_> = members.iter().map(|m| m.ty).collect();
2465 let mut components = Vec::with_capacity(members.len());
2466 for ty in types {
2467 components.push(self.eval_zero_value_impl(ty, span)?);
2468 }
2469 let expr = Expression::Compose { ty, components };
2470 self.register_evaluated_expr(expr, span)
2471 }
2472 _ => Err(ConstantEvaluatorError::TypeNotConstructible),
2473 }
2474 }
2475
2476 pub fn cast(
2480 &mut self,
2481 expr: Handle<Expression>,
2482 target: crate::Scalar,
2483 span: Span,
2484 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2485 use crate::Scalar as Sc;
2486
2487 let expr = self.eval_zero_value(expr, span)?;
2488
2489 let make_error = || -> Result<_, ConstantEvaluatorError> {
2490 let from = format!("{:?} {:?}", expr, self.expressions[expr]);
2491
2492 #[cfg(feature = "wgsl-in")]
2493 let to = target.to_wgsl_for_diagnostics();
2494
2495 #[cfg(not(feature = "wgsl-in"))]
2496 let to = format!("{target:?}");
2497
2498 Err(ConstantEvaluatorError::InvalidCastArg { from, to })
2499 };
2500
2501 use crate::proc::type_methods::IntFloatLimits;
2502
2503 let expr = match self.expressions[expr] {
2504 Expression::Literal(literal) => {
2505 let literal = match target {
2506 Sc::I16 => Literal::I16(match literal {
2507 Literal::I16(v) => v,
2508 Literal::U16(v) => v as i16,
2509 Literal::I32(v) => v as i16,
2510 Literal::U32(v) => v as i16,
2511 Literal::F32(v) => v.clamp(i16::MIN as f32, i16::MAX as f32) as i16,
2512 Literal::F16(v) => {
2513 f16::to_f32(v).clamp(i16::MIN as f32, i16::MAX as f32) as i16
2514 }
2515 Literal::Bool(v) => v as i16,
2516 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2517 return make_error();
2518 }
2519 Literal::AbstractInt(v) => v as i16,
2520 Literal::AbstractFloat(v) => v as i16,
2521 }),
2522 Sc::U16 => Literal::U16(match literal {
2523 Literal::I16(v) => v as u16,
2524 Literal::U16(v) => v,
2525 Literal::I32(v) => v as u16,
2526 Literal::U32(v) => v as u16,
2527 Literal::F32(v) => v.clamp(u16::MIN as f32, u16::MAX as f32) as u16,
2528 Literal::F16(v) => f16::to_u16(&v.max(f16::ZERO)).unwrap(),
2529 Literal::Bool(v) => v as u16,
2530 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2531 return make_error();
2532 }
2533 Literal::AbstractInt(v) => v as u16,
2534 Literal::AbstractFloat(v) => v as u16,
2535 }),
2536 Sc::I32 => Literal::I32(match literal {
2537 Literal::I16(v) => v as i32,
2538 Literal::U16(v) => v as i32,
2539 Literal::I32(v) => v,
2540 Literal::U32(v) => v as i32,
2541 Literal::F32(v) => v.clamp(i32::min_float(), i32::max_float()) as i32,
2542 Literal::F16(v) => f16::to_i32(&v).unwrap(), Literal::Bool(v) => v as i32,
2544 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2545 return make_error();
2546 }
2547 Literal::AbstractInt(v) => i32::try_from_abstract(v)?,
2548 Literal::AbstractFloat(v) => i32::try_from_abstract(v)?,
2549 }),
2550 Sc::U32 => Literal::U32(match literal {
2551 Literal::I16(v) => v as u32,
2552 Literal::U16(v) => v as u32,
2553 Literal::I32(v) => v as u32,
2554 Literal::U32(v) => v,
2555 Literal::F32(v) => v.clamp(u32::min_float(), u32::max_float()) as u32,
2556 Literal::F16(v) => f16::to_u32(&v.max(f16::ZERO)).unwrap(),
2558 Literal::Bool(v) => v as u32,
2559 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2560 return make_error();
2561 }
2562 Literal::AbstractInt(v) => u32::try_from_abstract(v)?,
2563 Literal::AbstractFloat(v) => u32::try_from_abstract(v)?,
2564 }),
2565 Sc::I64 => Literal::I64(match literal {
2566 Literal::I16(v) => v as i64,
2567 Literal::U16(v) => v as i64,
2568 Literal::I32(v) => v as i64,
2569 Literal::U32(v) => v as i64,
2570 Literal::F32(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2571 Literal::Bool(v) => v as i64,
2572 Literal::F64(v) => v.clamp(i64::min_float(), i64::max_float()) as i64,
2573 Literal::I64(v) => v,
2574 Literal::U64(v) => v as i64,
2575 Literal::F16(v) => f16::to_i64(&v).unwrap(), Literal::AbstractInt(v) => i64::try_from_abstract(v)?,
2577 Literal::AbstractFloat(v) => i64::try_from_abstract(v)?,
2578 }),
2579 Sc::U64 => Literal::U64(match literal {
2580 Literal::I16(v) => v as u64,
2581 Literal::U16(v) => v as u64,
2582 Literal::I32(v) => v as u64,
2583 Literal::U32(v) => v as u64,
2584 Literal::F32(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2585 Literal::Bool(v) => v as u64,
2586 Literal::F64(v) => v.clamp(u64::min_float(), u64::max_float()) as u64,
2587 Literal::I64(v) => v as u64,
2588 Literal::U64(v) => v,
2589 Literal::F16(v) => f16::to_u64(&v.max(f16::ZERO)).unwrap(),
2591 Literal::AbstractInt(v) => u64::try_from_abstract(v)?,
2592 Literal::AbstractFloat(v) => u64::try_from_abstract(v)?,
2593 }),
2594 Sc::F16 => Literal::F16(match literal {
2595 Literal::F16(v) => v,
2596 Literal::F32(v) => f16::from_f32(v),
2597 Literal::F64(v) => f16::from_f64(v),
2598 Literal::Bool(v) => f16::from_u32(v as u32).unwrap(),
2599 Literal::I16(v) => f16::from_f32(v as f32),
2600 Literal::U16(v) => f16::from_f32(v as f32),
2601 Literal::I64(v) => f16::from_i64(v).unwrap(),
2602 Literal::U64(v) => f16::from_u64(v).unwrap(),
2603 Literal::I32(v) => f16::from_i32(v).unwrap(),
2604 Literal::U32(v) => f16::from_u32(v).unwrap(),
2605 Literal::AbstractFloat(v) => f16::try_from_abstract(v)?,
2606 Literal::AbstractInt(v) => f16::try_from_abstract(v)?,
2607 }),
2608 Sc::F32 => Literal::F32(match literal {
2609 Literal::I16(v) => v as f32,
2610 Literal::U16(v) => v as f32,
2611 Literal::I32(v) => v as f32,
2612 Literal::U32(v) => v as f32,
2613 Literal::F32(v) => v,
2614 Literal::Bool(v) => v as u32 as f32,
2615 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2616 return make_error();
2617 }
2618 Literal::F16(v) => f16::to_f32(v),
2619 Literal::AbstractInt(v) => f32::try_from_abstract(v)?,
2620 Literal::AbstractFloat(v) => f32::try_from_abstract(v)?,
2621 }),
2622 Sc::F64 => Literal::F64(match literal {
2623 Literal::I16(v) => v as f64,
2624 Literal::U16(v) => v as f64,
2625 Literal::I32(v) => v as f64,
2626 Literal::U32(v) => v as f64,
2627 Literal::F16(v) => f16::to_f64(v),
2628 Literal::F32(v) => v as f64,
2629 Literal::F64(v) => v,
2630 Literal::Bool(v) => v as u32 as f64,
2631 Literal::I64(_) | Literal::U64(_) => return make_error(),
2632 Literal::AbstractInt(v) => f64::try_from_abstract(v)?,
2633 Literal::AbstractFloat(v) => f64::try_from_abstract(v)?,
2634 }),
2635 Sc::BOOL => Literal::Bool(match literal {
2636 Literal::I16(v) => v != 0,
2637 Literal::U16(v) => v != 0,
2638 Literal::I32(v) => v != 0,
2639 Literal::U32(v) => v != 0,
2640 Literal::F32(v) => v != 0.0,
2641 Literal::F16(v) => v != f16::zero(),
2642 Literal::Bool(v) => v,
2643 Literal::AbstractInt(v) => v != 0,
2644 Literal::AbstractFloat(v) => v != 0.0,
2645 Literal::F64(_) | Literal::I64(_) | Literal::U64(_) => {
2646 return make_error();
2647 }
2648 }),
2649 Sc::ABSTRACT_FLOAT => Literal::AbstractFloat(match literal {
2650 Literal::AbstractInt(v) => {
2651 v as f64
2656 }
2657 Literal::AbstractFloat(v) => v,
2658 _ => return make_error(),
2659 }),
2660 Sc::ABSTRACT_INT => Literal::AbstractInt(match literal {
2661 Literal::AbstractInt(v) => v,
2662 _ => return make_error(),
2663 }),
2664 _ => {
2665 log::debug!("Constant evaluator refused to convert value to {target:?}");
2666 return make_error();
2667 }
2668 };
2669 Expression::Literal(literal)
2670 }
2671 Expression::Compose {
2672 ty,
2673 components: ref src_components,
2674 } => {
2675 let ty_inner = match self.types[ty].inner {
2676 TypeInner::Vector { size, .. } => TypeInner::Vector {
2677 size,
2678 scalar: target,
2679 },
2680 TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix {
2681 columns,
2682 rows,
2683 scalar: target,
2684 },
2685 _ => return make_error(),
2686 };
2687
2688 let mut components = src_components.clone();
2689 for component in &mut components {
2690 *component = self.cast(*component, target, span)?;
2691 }
2692
2693 let ty = self.types.insert(
2694 Type {
2695 name: None,
2696 inner: ty_inner,
2697 },
2698 span,
2699 );
2700
2701 Expression::Compose { ty, components }
2702 }
2703 Expression::Splat { size, value } => {
2704 let value_span = self.expressions.get_span(value);
2705 let cast_value = self.cast(value, target, value_span)?;
2706 Expression::Splat {
2707 size,
2708 value: cast_value,
2709 }
2710 }
2711 _ => return make_error(),
2712 };
2713
2714 self.register_evaluated_expr(expr, span)
2715 }
2716
2717 pub fn cast_array(
2730 &mut self,
2731 expr: Handle<Expression>,
2732 target: crate::Scalar,
2733 span: Span,
2734 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2735 let expr = self.check_and_get(expr)?;
2736
2737 let Expression::Compose { ty, ref components } = self.expressions[expr] else {
2738 return self.cast(expr, target, span);
2739 };
2740
2741 let TypeInner::Array {
2742 base: _,
2743 size,
2744 stride: _,
2745 } = self.types[ty].inner
2746 else {
2747 return self.cast(expr, target, span);
2748 };
2749
2750 let mut components = components.clone();
2751 for component in &mut components {
2752 *component = self.cast_array(*component, target, span)?;
2753 }
2754
2755 let first = components.first().unwrap();
2756 let new_base = match self.resolve_type(*first)? {
2757 crate::proc::TypeResolution::Handle(ty) => ty,
2758 crate::proc::TypeResolution::Value(inner) => {
2759 self.types.insert(Type { name: None, inner }, span)
2760 }
2761 };
2762 let mut layouter = core::mem::take(self.layouter);
2763 layouter.update(self.to_ctx()).map_err(|err| {
2764 let crate::proc::LayoutErrorInner::TooLarge = err.inner else {
2767 unreachable!("unexpected layout error: {err:?}");
2768 };
2769 ConstantEvaluatorError::TypeTooLarge(err.ty)
2770 })?;
2771 *self.layouter = layouter;
2772
2773 let new_base_stride = self.layouter[new_base].to_stride();
2774 let new_array_ty = self.types.insert(
2775 Type {
2776 name: None,
2777 inner: TypeInner::Array {
2778 base: new_base,
2779 size,
2780 stride: new_base_stride,
2781 },
2782 },
2783 span,
2784 );
2785
2786 let compose = Expression::Compose {
2787 ty: new_array_ty,
2788 components,
2789 };
2790 self.register_evaluated_expr(compose, span)
2791 }
2792
2793 fn unary_op(
2794 &mut self,
2795 op: UnaryOperator,
2796 expr: Handle<Expression>,
2797 span: Span,
2798 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2799 let expr = self.eval_zero_value_and_splat(expr, span)?;
2800
2801 let expr = match self.expressions[expr] {
2802 Expression::Literal(value) => Expression::Literal(match op {
2803 UnaryOperator::Negate => match value {
2804 Literal::I16(v) => Literal::I16(v.wrapping_neg()),
2805 Literal::I32(v) => Literal::I32(v.wrapping_neg()),
2806 Literal::I64(v) => Literal::I64(v.wrapping_neg()),
2807 Literal::F32(v) => Literal::F32(-v),
2808 Literal::F16(v) => Literal::F16(-v),
2809 Literal::F64(v) => Literal::F64(-v),
2810 Literal::AbstractInt(v) => Literal::AbstractInt(v.wrapping_neg()),
2811 Literal::AbstractFloat(v) => Literal::AbstractFloat(-v),
2812 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2813 },
2814 UnaryOperator::LogicalNot => match value {
2815 Literal::Bool(v) => Literal::Bool(!v),
2816 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2817 },
2818 UnaryOperator::BitwiseNot => match value {
2819 Literal::I16(v) => Literal::I16(!v),
2820 Literal::I32(v) => Literal::I32(!v),
2821 Literal::I64(v) => Literal::I64(!v),
2822 Literal::U16(v) => Literal::U16(!v),
2823 Literal::U32(v) => Literal::U32(!v),
2824 Literal::U64(v) => Literal::U64(!v),
2825 Literal::AbstractInt(v) => Literal::AbstractInt(!v),
2826 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2827 },
2828 }),
2829 Expression::Compose {
2830 ty,
2831 components: ref src_components,
2832 } => {
2833 match self.types[ty].inner {
2834 TypeInner::Vector { .. } => (),
2835 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2836 }
2837
2838 let mut components = src_components.clone();
2839 for component in &mut components {
2840 *component = self.unary_op(op, *component, span)?;
2841 }
2842
2843 Expression::Compose { ty, components }
2844 }
2845 _ => return Err(ConstantEvaluatorError::InvalidUnaryOpArg),
2846 };
2847
2848 self.register_evaluated_expr(expr, span)
2849 }
2850
2851 fn binary_op(
2852 &mut self,
2853 op: BinaryOperator,
2854 left: Handle<Expression>,
2855 right: Handle<Expression>,
2856 span: Span,
2857 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
2858 let left = self.eval_zero_value_and_splat(left, span)?;
2859 let right = self.eval_zero_value_and_splat(right, span)?;
2860
2861 let expr = match (&self.expressions[left], &self.expressions[right]) {
2866 (&Expression::Literal(left_value), &Expression::Literal(right_value)) => {
2867 if !matches!(op, BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight)
2868 && core::mem::discriminant(&left_value) != core::mem::discriminant(&right_value)
2869 {
2870 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2871 }
2872
2873 if matches!(
2874 (left_value, op),
2875 (
2876 Literal::Bool(_),
2877 BinaryOperator::Less
2878 | BinaryOperator::LessEqual
2879 | BinaryOperator::Greater
2880 | BinaryOperator::GreaterEqual
2881 )
2882 ) {
2883 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2884 }
2885
2886 let literal = match op {
2887 BinaryOperator::Equal => Literal::Bool(left_value == right_value),
2888 BinaryOperator::NotEqual => Literal::Bool(left_value != right_value),
2889 BinaryOperator::Less => Literal::Bool(left_value < right_value),
2890 BinaryOperator::LessEqual => Literal::Bool(left_value <= right_value),
2891 BinaryOperator::Greater => Literal::Bool(left_value > right_value),
2892 BinaryOperator::GreaterEqual => Literal::Bool(left_value >= right_value),
2893
2894 _ => match (left_value, right_value) {
2895 (Literal::I16(a), Literal::I16(b)) => Literal::I16(match op {
2896 BinaryOperator::Add => a.wrapping_add(b),
2897 BinaryOperator::Subtract => a.wrapping_sub(b),
2898 BinaryOperator::Multiply => a.wrapping_mul(b),
2899 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2900 if b == 0 {
2901 ConstantEvaluatorError::DivisionByZero
2902 } else {
2903 ConstantEvaluatorError::Overflow("division".into())
2904 }
2905 })?,
2906 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2907 if b == 0 {
2908 ConstantEvaluatorError::RemainderByZero
2909 } else {
2910 ConstantEvaluatorError::Overflow("remainder".into())
2911 }
2912 })?,
2913 BinaryOperator::And => a & b,
2914 BinaryOperator::ExclusiveOr => a ^ b,
2915 BinaryOperator::InclusiveOr => a | b,
2916 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2917 }),
2918 (Literal::I16(a), Literal::U32(b)) => Literal::I16(match op {
2919 BinaryOperator::ShiftLeft => {
2920 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2921 return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2922 }
2923 a.checked_shl(b)
2924 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2925 }
2926 BinaryOperator::ShiftRight => a
2927 .checked_shr(b)
2928 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2929 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2930 }),
2931 (Literal::U16(a), Literal::U16(b)) => Literal::U16(match op {
2932 BinaryOperator::Add => a.wrapping_add(b),
2933 BinaryOperator::Subtract => a.wrapping_sub(b),
2934 BinaryOperator::Multiply => a.wrapping_mul(b),
2935 BinaryOperator::Divide => a
2936 .checked_div(b)
2937 .ok_or(ConstantEvaluatorError::DivisionByZero)?,
2938 BinaryOperator::Modulo => a
2939 .checked_rem(b)
2940 .ok_or(ConstantEvaluatorError::RemainderByZero)?,
2941 BinaryOperator::And => a & b,
2942 BinaryOperator::ExclusiveOr => a ^ b,
2943 BinaryOperator::InclusiveOr => a | b,
2944 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2945 }),
2946 (Literal::U16(a), Literal::U32(b)) => Literal::U16(match op {
2947 BinaryOperator::ShiftLeft => a
2948 .checked_mul(
2949 1u16.checked_shl(b)
2950 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2951 )
2952 .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
2953 BinaryOperator::ShiftRight => a
2954 .checked_shr(b)
2955 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2956 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2957 }),
2958 (Literal::I32(a), Literal::I32(b)) => Literal::I32(match op {
2959 BinaryOperator::Add => a.wrapping_add(b),
2960 BinaryOperator::Subtract => a.wrapping_sub(b),
2961 BinaryOperator::Multiply => a.wrapping_mul(b),
2962 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
2963 if b == 0 {
2964 ConstantEvaluatorError::DivisionByZero
2965 } else {
2966 ConstantEvaluatorError::Overflow("division".into())
2967 }
2968 })?,
2969 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
2970 if b == 0 {
2971 ConstantEvaluatorError::RemainderByZero
2972 } else {
2973 ConstantEvaluatorError::Overflow("remainder".into())
2974 }
2975 })?,
2976 BinaryOperator::And => a & b,
2977 BinaryOperator::ExclusiveOr => a ^ b,
2978 BinaryOperator::InclusiveOr => a | b,
2979 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2980 }),
2981 (Literal::I32(a), Literal::U32(b)) => Literal::I32(match op {
2982 BinaryOperator::ShiftLeft => {
2983 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
2984 return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
2985 }
2986 a.checked_shl(b)
2987 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
2988 }
2989 BinaryOperator::ShiftRight => a
2990 .checked_shr(b)
2991 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
2992 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
2993 }),
2994 (Literal::U32(a), Literal::U32(b)) => Literal::U32(match op {
2995 BinaryOperator::Add => a.wrapping_add(b),
2996 BinaryOperator::Subtract => a.wrapping_sub(b),
2997 BinaryOperator::Multiply => a.wrapping_mul(b),
2998 BinaryOperator::Divide => a
2999 .checked_div(b)
3000 .ok_or(ConstantEvaluatorError::DivisionByZero)?,
3001 BinaryOperator::Modulo => a
3002 .checked_rem(b)
3003 .ok_or(ConstantEvaluatorError::RemainderByZero)?,
3004 BinaryOperator::And => a & b,
3005 BinaryOperator::ExclusiveOr => a ^ b,
3006 BinaryOperator::InclusiveOr => a | b,
3007 BinaryOperator::ShiftLeft => a
3008 .checked_mul(
3009 1u32.checked_shl(b)
3010 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3011 )
3012 .ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
3013 BinaryOperator::ShiftRight => a
3014 .checked_shr(b)
3015 .ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
3016 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3017 }),
3018 (Literal::F32(a), Literal::F32(b)) => Literal::F32(match op {
3019 BinaryOperator::Add => a + b,
3020 BinaryOperator::Subtract => a - b,
3021 BinaryOperator::Multiply => a * b,
3022 BinaryOperator::Divide => a / b,
3023 BinaryOperator::Modulo => a % b,
3024 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3025 }),
3026 (Literal::AbstractInt(a), Literal::U32(b)) => {
3027 Literal::AbstractInt(match op {
3028 BinaryOperator::ShiftLeft => {
3029 if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
3030 return Err(ConstantEvaluatorError::Overflow(
3031 "<<".to_string(),
3032 ));
3033 }
3034 a.checked_shl(b).unwrap_or(0)
3035 }
3036 BinaryOperator::ShiftRight => a.checked_shr(b).unwrap_or(0),
3037 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3038 })
3039 }
3040 (Literal::F16(a), Literal::F16(b)) => {
3041 let result = match op {
3042 BinaryOperator::Add => a + b,
3043 BinaryOperator::Subtract => a - b,
3044 BinaryOperator::Multiply => a * b,
3045 BinaryOperator::Divide => a / b,
3046 BinaryOperator::Modulo => a % b,
3047 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3048 };
3049 if !result.is_finite() {
3050 return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3051 }
3052 Literal::F16(result)
3053 }
3054 (Literal::AbstractInt(a), Literal::AbstractInt(b)) => {
3055 Literal::AbstractInt(match op {
3056 BinaryOperator::Add => a.checked_add(b).ok_or_else(|| {
3057 ConstantEvaluatorError::Overflow("addition".into())
3058 })?,
3059 BinaryOperator::Subtract => a.checked_sub(b).ok_or_else(|| {
3060 ConstantEvaluatorError::Overflow("subtraction".into())
3061 })?,
3062 BinaryOperator::Multiply => a.checked_mul(b).ok_or_else(|| {
3063 ConstantEvaluatorError::Overflow("multiplication".into())
3064 })?,
3065 BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
3066 if b == 0 {
3067 ConstantEvaluatorError::DivisionByZero
3068 } else {
3069 ConstantEvaluatorError::Overflow("division".into())
3070 }
3071 })?,
3072 BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
3073 if b == 0 {
3074 ConstantEvaluatorError::RemainderByZero
3075 } else {
3076 ConstantEvaluatorError::Overflow("remainder".into())
3077 }
3078 })?,
3079 BinaryOperator::And => a & b,
3080 BinaryOperator::ExclusiveOr => a ^ b,
3081 BinaryOperator::InclusiveOr => a | b,
3082 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3083 })
3084 }
3085 (Literal::AbstractFloat(a), Literal::AbstractFloat(b)) => {
3086 let result = match op {
3087 BinaryOperator::Add => a + b,
3088 BinaryOperator::Subtract => a - b,
3089 BinaryOperator::Multiply => a * b,
3090 BinaryOperator::Divide => a / b,
3091 BinaryOperator::Modulo => a % b,
3092 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3093 };
3094 if !result.is_finite() {
3095 return Err(ConstantEvaluatorError::Overflow(format!("{op:?}")));
3096 }
3097 Literal::AbstractFloat(result)
3098 }
3099 (Literal::Bool(a), Literal::Bool(b)) => Literal::Bool(match op {
3100 BinaryOperator::LogicalAnd => a && b,
3101 BinaryOperator::LogicalOr => a || b,
3102 BinaryOperator::And => a & b,
3103 BinaryOperator::InclusiveOr => a | b,
3104 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3105 }),
3106 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3107 },
3108 };
3109 Expression::Literal(literal)
3110 }
3111 (
3112 &Expression::Compose {
3113 components: ref src_components,
3114 ty,
3115 },
3116 &Expression::Literal(_),
3117 ) => {
3118 if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3119 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3120 }
3121 let mut components = src_components.clone();
3122 for component in &mut components {
3123 *component = self.binary_op(op, *component, right, span)?;
3124 }
3125 Expression::Compose { ty, components }
3126 }
3127 (
3128 &Expression::Literal(_),
3129 &Expression::Compose {
3130 components: ref src_components,
3131 ty,
3132 },
3133 ) => {
3134 if !is_allowed_compose_literal_op(&self.types[ty].inner, op) {
3135 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3136 }
3137 let mut components = src_components.clone();
3138 for component in &mut components {
3139 *component = self.binary_op(op, left, *component, span)?;
3140 }
3141 Expression::Compose { ty, components }
3142 }
3143 (
3144 &Expression::Compose {
3145 components: ref left_components,
3146 ty: left_ty,
3147 },
3148 &Expression::Compose {
3149 components: ref right_components,
3150 ty: right_ty,
3151 },
3152 ) => {
3153 let left_flattened = crate::proc::flatten_compose(
3157 left_ty,
3158 left_components,
3159 self.expressions,
3160 self.types,
3161 )
3162 .collect::<Vec<_>>();
3163 let right_flattened = crate::proc::flatten_compose(
3164 right_ty,
3165 right_components,
3166 self.expressions,
3167 self.types,
3168 )
3169 .collect::<Vec<_>>();
3170
3171 self.binary_op_compose(
3172 op,
3173 &left_flattened,
3174 &right_flattened,
3175 left_ty,
3176 right_ty,
3177 span,
3178 )?
3179 }
3180 _ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3181 };
3182
3183 return self.register_evaluated_expr(expr, span);
3184
3185 fn is_allowed_compose_literal_op(compose_ty: &TypeInner, op: BinaryOperator) -> bool {
3186 let is_numeric_vec = matches!(
3187 compose_ty, TypeInner::Vector { scalar, .. }
3188 if scalar.kind != ScalarKind::Bool
3189 );
3190 let is_allowed_vec_scalar_op = matches!(
3191 op,
3192 BinaryOperator::Add
3193 | BinaryOperator::Subtract
3194 | BinaryOperator::Multiply
3195 | BinaryOperator::Divide
3196 | BinaryOperator::Modulo
3197 );
3198 let is_mat = matches!(compose_ty, TypeInner::Matrix { .. });
3199 let is_allowed_mat_scalar_op = matches!(op, BinaryOperator::Multiply);
3200 is_numeric_vec && is_allowed_vec_scalar_op || is_mat && is_allowed_mat_scalar_op
3201 }
3202 }
3203
3204 fn binary_op_compose(
3205 &mut self,
3206 op: BinaryOperator,
3207 left_components: &[Handle<Expression>],
3208 right_components: &[Handle<Expression>],
3209 left_ty: Handle<Type>,
3210 right_ty: Handle<Type>,
3211 span: Span,
3212 ) -> Result<Expression, ConstantEvaluatorError> {
3213 match (&self.types[left_ty].inner, &self.types[right_ty].inner) {
3214 (
3216 &TypeInner::Vector {
3217 size: left_size, ..
3218 },
3219 &TypeInner::Vector {
3220 size: right_size, ..
3221 },
3222 ) if left_size == right_size => self.binary_op_vector(
3223 op,
3224 left_size,
3225 left_components,
3226 right_components,
3227 left_ty,
3228 span,
3229 ),
3230 (
3232 &TypeInner::Vector { size, .. },
3233 &TypeInner::Matrix {
3234 columns,
3235 rows,
3236 scalar,
3237 },
3238 ) if op == BinaryOperator::Multiply && size == rows => self.multiply_vector_matrix(
3239 left_components,
3240 right_components,
3241 columns,
3242 scalar,
3243 span,
3244 ),
3245 (
3247 &TypeInner::Matrix {
3248 columns,
3249 rows,
3250 scalar,
3251 },
3252 &TypeInner::Vector { size, .. },
3253 ) if op == BinaryOperator::Multiply && size == columns => {
3254 self.multiply_matrix_vector(left_components, right_components, rows, scalar, span)
3255 }
3256 (
3258 &TypeInner::Matrix {
3259 columns: left_columns,
3260 rows: left_rows,
3261 scalar,
3262 },
3263 &TypeInner::Matrix {
3264 columns: right_columns,
3265 rows: right_rows,
3266 ..
3267 },
3268 ) => match op {
3269 BinaryOperator::Add | BinaryOperator::Subtract
3270 if left_columns == right_columns && left_rows == right_rows =>
3271 {
3272 let components = left_components
3273 .iter()
3274 .zip(right_components)
3275 .map(|(&left, &right)| self.binary_op(op, left, right, span))
3276 .collect::<Result<Vec<_>, _>>()?;
3277 Ok(Expression::Compose {
3278 ty: left_ty,
3279 components,
3280 })
3281 }
3282 BinaryOperator::Multiply if left_columns == right_rows => self
3283 .multiply_matrix_matrix(
3284 left_components,
3285 right_components,
3286 left_rows,
3287 right_columns,
3288 scalar,
3289 span,
3290 ),
3291 _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3292 },
3293 _ => Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
3294 }
3295 }
3296
3297 fn binary_op_vector(
3298 &mut self,
3299 op: BinaryOperator,
3300 size: crate::VectorSize,
3301 left_components: &[Handle<Expression>],
3302 right_components: &[Handle<Expression>],
3303 left_ty: Handle<Type>,
3304 span: Span,
3305 ) -> Result<Expression, ConstantEvaluatorError> {
3306 let ty = match op {
3307 BinaryOperator::Equal
3309 | BinaryOperator::NotEqual
3310 | BinaryOperator::Less
3311 | BinaryOperator::LessEqual
3312 | BinaryOperator::Greater
3313 | BinaryOperator::GreaterEqual => self.types.insert(
3314 Type {
3315 name: None,
3316 inner: TypeInner::Vector {
3317 size,
3318 scalar: crate::Scalar::BOOL,
3319 },
3320 },
3321 span,
3322 ),
3323
3324 BinaryOperator::Add
3327 | BinaryOperator::Subtract
3328 | BinaryOperator::Multiply
3329 | BinaryOperator::Divide
3330 | BinaryOperator::Modulo
3331 | BinaryOperator::And
3332 | BinaryOperator::ExclusiveOr
3333 | BinaryOperator::InclusiveOr
3334 | BinaryOperator::ShiftLeft
3335 | BinaryOperator::ShiftRight => left_ty,
3336
3337 BinaryOperator::LogicalAnd | BinaryOperator::LogicalOr => {
3338 return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
3340 }
3341 };
3342
3343 let components = left_components
3344 .iter()
3345 .zip(right_components)
3346 .map(|(&left, &right)| self.binary_op(op, left, right, span))
3347 .collect::<Result<Vec<_>, _>>()?;
3348
3349 Ok(Expression::Compose { ty, components })
3350 }
3351
3352 fn multiply_vector_matrix(
3353 &mut self,
3354 vec_components: &[Handle<Expression>],
3355 mat_components: &[Handle<Expression>],
3356 mat_columns: crate::VectorSize,
3357 scalar: crate::Scalar,
3358 span: Span,
3359 ) -> Result<Expression, ConstantEvaluatorError> {
3360 let ty = self.types.insert(
3361 Type {
3362 name: None,
3363 inner: TypeInner::Vector {
3364 size: mat_columns,
3365 scalar,
3366 },
3367 },
3368 span,
3369 );
3370 let components = mat_components
3371 .iter()
3372 .map(|&column| {
3373 let Expression::Compose { ref components, .. } = self.expressions[column] else {
3374 unreachable!()
3375 };
3376 self.dot_exprs(
3377 vec_components.iter().cloned(),
3378 components.clone().into_iter(),
3379 span,
3380 )
3381 })
3382 .collect::<Result<Vec<_>, _>>()?;
3383 Ok(Expression::Compose { ty, components })
3384 }
3385
3386 fn multiply_matrix_vector(
3387 &mut self,
3388 mat_components: &[Handle<Expression>],
3389 vec_components: &[Handle<Expression>],
3390 mat_rows: crate::VectorSize,
3391 scalar: crate::Scalar,
3392 span: Span,
3393 ) -> Result<Expression, ConstantEvaluatorError> {
3394 let ty = self.types.insert(
3395 Type {
3396 name: None,
3397 inner: TypeInner::Vector {
3398 size: mat_rows,
3399 scalar,
3400 },
3401 },
3402 span,
3403 );
3404
3405 let flatten = self.flatten_matrix(mat_components);
3406 let nr = mat_rows as usize;
3407 let components = (0..nr)
3408 .map(|r| {
3409 let row = flatten.iter().skip(r).step_by(nr).cloned();
3410 self.dot_exprs(row, vec_components.iter().cloned(), span)
3411 })
3412 .collect::<Result<Vec<_>, _>>()?;
3413 Ok(Expression::Compose { ty, components })
3414 }
3415
3416 fn multiply_matrix_matrix(
3417 &mut self,
3418 left_components: &[Handle<Expression>],
3419 right_components: &[Handle<Expression>],
3420 left_rows: crate::VectorSize,
3421 right_columns: crate::VectorSize,
3422 scalar: crate::Scalar,
3423 span: Span,
3424 ) -> Result<Expression, ConstantEvaluatorError> {
3425 let left_nc = left_components.len();
3426 let left_nr = left_rows as usize;
3427 let right_nc = right_columns as usize;
3428 let right_nr = left_nc;
3429
3430 let mut result = Vec::with_capacity(right_nc);
3431 let result_ty = self.types.insert(
3432 Type {
3433 name: None,
3434 inner: TypeInner::Matrix {
3435 columns: right_columns,
3436 rows: left_rows,
3437 scalar,
3438 },
3439 },
3440 span,
3441 );
3442 let result_column_ty = self.types.insert(
3443 Type {
3444 name: None,
3445 inner: TypeInner::Vector {
3446 size: left_rows,
3447 scalar,
3448 },
3449 },
3450 span,
3451 );
3452
3453 let left_flattened = self.flatten_matrix(left_components);
3454 let right_flattened = self.flatten_matrix(right_components);
3455 for c in 0..right_nc {
3456 let result_column = (0..left_nr)
3457 .map(|r| {
3458 let row = left_flattened.iter().skip(r).step_by(left_nr);
3459 let column = right_flattened.iter().skip(c * right_nr).take(right_nr);
3460 self.dot_exprs(row.cloned(), column.cloned(), span)
3461 })
3462 .collect::<Result<Vec<_>, _>>()?;
3463 let expr = Expression::Compose {
3464 ty: result_column_ty,
3465 components: result_column,
3466 };
3467 let handle = self.register_evaluated_expr(expr, span)?;
3468 result.push(handle);
3469 }
3470 Ok(Expression::Compose {
3471 ty: result_ty,
3472 components: result,
3473 })
3474 }
3475
3476 fn flatten_matrix(&self, columns: &[Handle<Expression>]) -> ArrayVec<Handle<Expression>, 16> {
3477 let mut flattened = ArrayVec::<_, 16>::new();
3478 for &column in columns {
3479 let Expression::Compose { ref components, .. } = self.expressions[column] else {
3480 unreachable!()
3481 };
3482 flattened.extend(components.iter().cloned());
3483 }
3484 flattened
3485 }
3486
3487 fn dot_exprs(
3488 &mut self,
3489 left: impl Iterator<Item = Handle<Expression>>,
3490 right: impl Iterator<Item = Handle<Expression>>,
3491 span: Span,
3492 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3493 let mut acc = None;
3494 for (l, r) in left.zip(right) {
3495 let result = self.binary_op(BinaryOperator::Multiply, l, r, span)?;
3496 match acc.as_mut() {
3497 Some(acc) => *acc = self.binary_op(BinaryOperator::Add, *acc, result, span)?,
3498 None => acc = Some(result),
3499 }
3500 }
3501 Ok(acc.unwrap())
3502 }
3503
3504 fn relational(
3505 &mut self,
3506 fun: RelationalFunction,
3507 arg: Handle<Expression>,
3508 span: Span,
3509 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3510 let arg = self.eval_zero_value_and_splat(arg, span)?;
3511 match fun {
3512 RelationalFunction::All | RelationalFunction::Any => match self.expressions[arg] {
3513 Expression::Literal(Literal::Bool(_)) => Ok(arg),
3514 Expression::Compose { ty, ref components }
3515 if matches!(self.types[ty].inner, TypeInner::Vector { .. }) =>
3516 {
3517 let mut bool_components = ArrayVec::<bool, { crate::VectorSize::MAX }>::new();
3518 for component in
3519 crate::proc::flatten_compose(ty, components, self.expressions, self.types)
3520 {
3521 match self.expressions[component] {
3522 Expression::Literal(Literal::Bool(val)) => {
3523 bool_components.push(val);
3524 }
3525 _ => {
3526 return Err(ConstantEvaluatorError::InvalidRelationalArg(fun));
3527 }
3528 }
3529 }
3530 let components = bool_components;
3531 let result = match fun {
3532 RelationalFunction::All => components.iter().all(|c| *c),
3533 RelationalFunction::Any => components.iter().any(|c| *c),
3534 _ => unreachable!(),
3535 };
3536 self.register_evaluated_expr(Expression::Literal(Literal::Bool(result)), span)
3537 }
3538 _ => Err(ConstantEvaluatorError::InvalidRelationalArg(fun)),
3539 },
3540 _ => Err(ConstantEvaluatorError::NotImplemented(format!(
3541 "{fun:?} built-in function"
3542 ))),
3543 }
3544 }
3545
3546 fn copy_from(
3554 &mut self,
3555 expr: Handle<Expression>,
3556 expressions: &Arena<Expression>,
3557 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3558 let span = expressions.get_span(expr);
3559 match expressions[expr] {
3560 ref expr @ (Expression::Literal(_)
3561 | Expression::Constant(_)
3562 | Expression::ZeroValue(_)) => self.register_evaluated_expr(expr.clone(), span),
3563 Expression::Compose { ty, ref components } => {
3564 let mut components = components.clone();
3565 for component in &mut components {
3566 *component = self.copy_from(*component, expressions)?;
3567 }
3568 self.register_evaluated_expr(Expression::Compose { ty, components }, span)
3569 }
3570 Expression::Splat { size, value } => {
3571 let value = self.copy_from(value, expressions)?;
3572 self.register_evaluated_expr(Expression::Splat { size, value }, span)
3573 }
3574 _ => {
3575 log::debug!("copy_from: SubexpressionsAreNotConstant");
3576 Err(ConstantEvaluatorError::SubexpressionsAreNotConstant)
3577 }
3578 }
3579 }
3580
3581 fn vector_compose_flattened_size(
3583 &self,
3584 components: &[Handle<Expression>],
3585 ) -> Result<usize, ConstantEvaluatorError> {
3586 components
3587 .iter()
3588 .try_fold(0, |acc, c| -> Result<_, ConstantEvaluatorError> {
3589 let size = match *self.resolve_type(*c)?.inner_with(self.types) {
3590 TypeInner::Scalar(_) => 1,
3591 TypeInner::Vector { size, .. } => size as usize,
3595 _ => return Err(ConstantEvaluatorError::InvalidVectorComposeComponent),
3596 };
3597 Ok(acc + size)
3598 })
3599 }
3600
3601 fn register_evaluated_expr(
3602 &mut self,
3603 expr: Expression,
3604 span: Span,
3605 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3606 if let Expression::Literal(literal) = expr {
3611 crate::valid::check_literal_value(literal)?;
3612 }
3613
3614 if let Expression::Compose { ty, ref components } = expr {
3618 if let TypeInner::Vector { size, scalar: _ } = self.types[ty].inner {
3619 let expected = size as usize;
3620 let actual = self.vector_compose_flattened_size(components)?;
3621 if expected != actual {
3622 return Err(ConstantEvaluatorError::InvalidVectorComposeLength {
3623 expected,
3624 actual,
3625 });
3626 }
3627 }
3628 }
3629
3630 Ok(self.append_expr(expr, span, ExpressionKind::Const))
3631 }
3632
3633 fn append_expr(
3634 &mut self,
3635 expr: Expression,
3636 span: Span,
3637 expr_type: ExpressionKind,
3638 ) -> Handle<Expression> {
3639 let h = match self.behavior {
3640 Behavior::Wgsl(
3641 WgslRestrictions::Runtime(ref mut function_local_data)
3642 | WgslRestrictions::Const(Some(ref mut function_local_data)),
3643 )
3644 | Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => {
3645 let is_running = function_local_data.emitter.is_running();
3646 let needs_pre_emit = expr.needs_pre_emit();
3647 if is_running && needs_pre_emit {
3648 function_local_data
3649 .block
3650 .extend(function_local_data.emitter.finish(self.expressions));
3651 let h = self.expressions.append(expr, span);
3652 function_local_data.emitter.start(self.expressions);
3653 h
3654 } else {
3655 self.expressions.append(expr, span)
3656 }
3657 }
3658 _ => self.expressions.append(expr, span),
3659 };
3660 self.expression_kind_tracker.insert(h, expr_type);
3661 h
3662 }
3663
3664 fn resolve_type(
3669 &self,
3670 expr: Handle<Expression>,
3671 ) -> Result<crate::proc::TypeResolution, ConstantEvaluatorError> {
3672 use crate::proc::TypeResolution as Tr;
3673 use crate::Expression as Ex;
3674 let resolution = match self.expressions[expr] {
3675 Ex::Literal(ref literal) => Tr::Value(literal.ty_inner()),
3676 Ex::Constant(c) => Tr::Handle(self.constants[c].ty),
3677 Ex::ZeroValue(ty) | Ex::Compose { ty, .. } => Tr::Handle(ty),
3678 Ex::Splat { size, value } => {
3679 let Tr::Value(TypeInner::Scalar(scalar)) = self.resolve_type(value)? else {
3680 return Err(ConstantEvaluatorError::SplatScalarOnly);
3681 };
3682 Tr::Value(TypeInner::Vector { scalar, size })
3683 }
3684 _ => {
3685 log::debug!("resolve_type: SubexpressionsAreNotConstant");
3686 return Err(ConstantEvaluatorError::SubexpressionsAreNotConstant);
3687 }
3688 };
3689
3690 Ok(resolution)
3691 }
3692
3693 fn select(
3694 &mut self,
3695 reject: Handle<Expression>,
3696 accept: Handle<Expression>,
3697 condition: Handle<Expression>,
3698 span: Span,
3699 ) -> Result<Handle<Expression>, ConstantEvaluatorError> {
3700 let mut arg = |arg| self.eval_zero_value_and_splat(arg, span);
3701
3702 let reject = arg(reject)?;
3703 let accept = arg(accept)?;
3704 let condition = arg(condition)?;
3705
3706 let select_single_component =
3707 |this: &mut Self, reject_scalar, reject, accept, condition| {
3708 let accept = this.cast(accept, reject_scalar, span)?;
3709 if condition {
3710 Ok(accept)
3711 } else {
3712 Ok(reject)
3713 }
3714 };
3715
3716 match (&self.expressions[reject], &self.expressions[accept]) {
3717 (&Expression::Literal(reject_lit), &Expression::Literal(_accept_lit)) => {
3718 let reject_scalar = reject_lit.scalar();
3719 let &Expression::Literal(Literal::Bool(condition)) = &self.expressions[condition]
3720 else {
3721 return Err(ConstantEvaluatorError::SelectScalarConditionNotABool);
3722 };
3723 select_single_component(self, reject_scalar, reject, accept, condition)
3724 }
3725 (
3726 &Expression::Compose {
3727 ty: reject_ty,
3728 components: ref reject_components,
3729 },
3730 &Expression::Compose {
3731 ty: accept_ty,
3732 components: ref accept_components,
3733 },
3734 ) => {
3735 let ty_deets = |ty| {
3736 self.types[ty]
3737 .inner
3738 .vector_size_and_scalar()
3739 .map(|(size, scalar)| {
3740 (size.expect("expected vector type, not scalar type"), scalar)
3741 })
3742 };
3743
3744 let expected_vec_size = {
3745 let [(reject_vec_size, _), (accept_vec_size, _)] =
3746 [reject_ty, accept_ty].map(|ty| ty_deets(ty).unwrap());
3747
3748 if reject_vec_size != accept_vec_size {
3749 return Err(ConstantEvaluatorError::SelectVecRejectAcceptSizeMismatch {
3750 reject: reject_vec_size,
3751 accept: accept_vec_size,
3752 });
3753 }
3754 reject_vec_size
3755 };
3756
3757 let condition_components = match self.expressions[condition] {
3758 Expression::Literal(Literal::Bool(condition)) => {
3759 vec![condition; (expected_vec_size as u8).into()]
3760 }
3761 Expression::Compose {
3762 ty: condition_ty,
3763 components: ref condition_components,
3764 } => {
3765 let Some((condition_vec_size, condition_scalar)) = ty_deets(condition_ty)
3766 else {
3767 return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3768 };
3769 if condition_scalar.kind != ScalarKind::Bool {
3770 return Err(ConstantEvaluatorError::SelectConditionNotAVecBool);
3771 }
3772 if condition_vec_size != expected_vec_size {
3773 return Err(ConstantEvaluatorError::SelectConditionVecSizeMismatch);
3774 }
3775 condition_components
3776 .iter()
3777 .copied()
3778 .map(|component| match &self.expressions[component] {
3779 &Expression::Literal(Literal::Bool(condition)) => condition,
3780 _ => unreachable!(),
3781 })
3782 .collect()
3783 }
3784
3785 _ => return Err(ConstantEvaluatorError::SelectConditionNotAVecBool),
3786 };
3787
3788 let evaluated = Expression::Compose {
3789 ty: reject_ty,
3790 components: reject_components
3791 .clone()
3792 .into_iter()
3793 .zip(accept_components.clone())
3794 .zip(condition_components)
3795 .map(|((reject, accept), condition)| {
3796 let reject_scalar = match &self.expressions[reject] {
3797 &Expression::Literal(lit) => lit.scalar(),
3798 _ => unreachable!(),
3799 };
3800 select_single_component(self, reject_scalar, reject, accept, condition)
3801 })
3802 .collect::<Result<_, _>>()?,
3803 };
3804 self.register_evaluated_expr(evaluated, span)
3805 }
3806 _ => Err(ConstantEvaluatorError::SelectAcceptRejectTypeMismatch),
3807 }
3808 }
3809}
3810
3811fn float_face_forward<F>(
3813 e1: &[F],
3814 e2: &[F],
3815 e3: &[F],
3816) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3817where
3818 F: num_traits::Float,
3819{
3820 let d = float_dot(e2, e3)?;
3821
3822 let mut out = ArrayVec::new();
3823 for &e in e1 {
3824 out.push(if d < F::zero() { e } else { -e });
3825 }
3826 Some(out)
3827}
3828
3829fn float_reflect<F>(e1: &[F], e2: &[F]) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3832where
3833 F: num_traits::Float,
3834{
3835 let d = float_dot(e2, e1)?;
3836 let two = F::one() + F::one();
3837
3838 let mut out = ArrayVec::new();
3839 for (&a, &b) in e1.iter().zip(e2) {
3840 let r = a - two * d * b;
3841 if !r.is_finite() {
3842 return None;
3843 }
3844 out.push(r);
3845 }
3846 Some(out)
3847}
3848
3849fn float_refract<F>(e1: &[F], e2: &[F], e3: F) -> Option<ArrayVec<F, { crate::VectorSize::MAX }>>
3852where
3853 F: num_traits::Float,
3854{
3855 let d = float_dot(e2, e1)?;
3856 let one = F::one();
3857
3858 let k = one - e3 * e3 * (one - d * d);
3859 if !k.is_finite() {
3860 return None;
3861 }
3862
3863 let mut out = ArrayVec::new();
3864
3865 if k < F::zero() {
3867 for _ in e1 {
3868 out.push(F::zero());
3869 }
3870 return Some(out);
3871 }
3872
3873 let scale = e3 * d + k.sqrt();
3874 for (&a, &b) in e1.iter().zip(e2) {
3875 let r = e3 * a - scale * b;
3876 if !r.is_finite() {
3877 return None;
3878 }
3879 out.push(r);
3880 }
3881 Some(out)
3882}
3883
3884#[test]
3885fn face_forward_smoke() {
3886 #[track_caller]
3887 fn ff(e1: &[f32], e2: &[f32], e3: &[f32]) -> Vec<f32> {
3888 float_face_forward(e1, e2, e3).unwrap().to_vec()
3889 }
3890
3891 assert_eq!(ff(&[1.0, 2.0], &[-1.0, 0.0], &[1.0, 0.0]), [1.0, 2.0]);
3893 assert_eq!(ff(&[1.0, 2.0], &[1.0, 0.0], &[1.0, 0.0]), [-1.0, -2.0]);
3894
3895 assert_eq!(ff(&[1.0, 2.0], &[0.0, 1.0], &[1.0, 0.0]), [-1.0, -2.0]);
3897
3898 assert_eq!(
3899 ff(&[1.0, 2.0, 3.0], &[-1.0, 0.0, 0.0], &[1.0, 0.0, 0.0]),
3900 [1.0, 2.0, 3.0]
3901 );
3902
3903 assert!(float_face_forward(&[1.0f32, 0.0], &[f32::MAX, 0.0], &[f32::MAX, 0.0]).is_none());
3905}
3906
3907#[test]
3908fn reflect_smoke() {
3909 #[track_caller]
3910 fn rf(e1: &[f32], e2: &[f32]) -> Vec<f32> {
3911 float_reflect(e1, e2).unwrap().to_vec()
3912 }
3913
3914 assert_eq!(rf(&[1.0, -1.0], &[0.0, 1.0]), [1.0, 1.0]);
3916 assert_eq!(rf(&[1.0, -1.0, 0.0], &[0.0, 1.0, 0.0]), [1.0, 1.0, 0.0]);
3917
3918 assert_eq!(rf(&[1.0, 0.0], &[1.0, 0.0]), [-1.0, 0.0]);
3920
3921 assert_eq!(rf(&[1.0, 0.0], &[0.0, 1.0]), [1.0, 0.0]);
3923
3924 assert!(float_reflect(&[1.0f32, 0.0], &[f32::MAX, 0.0]).is_none());
3925}
3926
3927#[test]
3928fn refract_smoke() {
3929 #[track_caller]
3930 fn rr(e1: &[f32], e2: &[f32], e3: f32) -> Vec<f32> {
3931 float_refract(e1, e2, e3).unwrap().to_vec()
3932 }
3933
3934 assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 1.0), [0.0, -1.0]);
3936 assert_eq!(rr(&[0.5, -0.5], &[0.0, 1.0], 1.0), [0.5, -0.5]);
3937
3938 assert_eq!(rr(&[0.5, -0.5], &[0.0, -1.0], 1.0), [0.5, 0.5]);
3940
3941 assert_eq!(rr(&[0.0, -1.0], &[0.0, 1.0], 0.5), [0.0, -1.0]);
3943
3944 assert_eq!(rr(&[0.8, -0.6], &[0.0, 1.0], 2.0), [0.0, 0.0]);
3946 assert_eq!(
3947 rr(&[0.8, -0.6, 0.0], &[0.0, 1.0, 0.0], 2.0),
3948 [0.0, 0.0, 0.0]
3949 );
3950
3951 assert!(float_refract(&[1.0f32, 0.0], &[f32::MAX, 0.0], 1.0).is_none());
3952 assert!(float_refract(&[1.0f32, 0.0], &[0.0, 1.0], f32::MAX).is_none());
3953}
3954
3955const fn bit_width<T>() -> u32 {
3958 size_of::<T>() as u32 * 8
3959}
3960
3961pub fn check_bitfield_range(
3968 builtin: &'static str,
3969 offset: u32,
3970 count: u32,
3971 width: u32,
3972) -> Result<(), ConstantEvaluatorError> {
3973 if u64::from(offset) + u64::from(count) > u64::from(width) {
3974 return Err(ConstantEvaluatorError::BitfieldRangeTooLarge {
3975 builtin,
3976 offset,
3977 count,
3978 width,
3979 });
3980 }
3981 Ok(())
3982}
3983
3984fn extract_bits<T>(
3985 e: &[T],
3986 offset: u32,
3987 count: u32,
3988) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
3989where
3990 T: num_traits::PrimInt,
3991{
3992 check_bitfield_range("extractBits", offset, count, bit_width::<T>())?;
3993 let w = bit_width::<T>();
3994
3995 let mut out = ArrayVec::new();
3996 for &e in e {
3997 out.push(if count == 0 {
3998 T::zero()
3999 } else {
4000 (e << (w - offset - count) as usize) >> (w - count) as usize
4005 });
4006 }
4007 Ok(out)
4008}
4009
4010fn insert_bits<T>(
4011 e: &[T],
4012 newbits: &[T],
4013 offset: u32,
4014 count: u32,
4015) -> Result<ArrayVec<T, { crate::VectorSize::MAX }>, ConstantEvaluatorError>
4016where
4017 T: num_traits::PrimInt,
4018{
4019 check_bitfield_range("insertBits", offset, count, bit_width::<T>())?;
4020 let w = bit_width::<T>();
4021
4022 let mut out = ArrayVec::new();
4023 for (&e, &newbits) in e.iter().zip(newbits) {
4024 out.push(if count == 0 {
4025 e
4026 } else {
4027 let mask = (!T::zero()).unsigned_shr(w - count) << offset as usize;
4028 (e & !mask) | ((newbits << offset as usize) & mask)
4029 });
4030 }
4031 Ok(out)
4032}
4033
4034#[cfg(test)]
4035fn extract_bits_scalar<T: num_traits::PrimInt>(e: T, offset: u32, count: u32) -> T {
4036 extract_bits(&[e], offset, count).unwrap()[0]
4037}
4038
4039#[cfg(test)]
4040fn insert_bits_scalar<T: num_traits::PrimInt>(e: T, newbits: T, offset: u32, count: u32) -> T {
4041 insert_bits(&[e], &[newbits], offset, count).unwrap()[0]
4042}
4043
4044#[test]
4045fn extract_bits_smoke() {
4046 assert_eq!(extract_bits_scalar(0xffffffff_u32, 0, 0), 0);
4048 assert_eq!(extract_bits_scalar(-1_i32, 32, 0), 0);
4049
4050 assert_eq!(extract_bits_scalar(0x12345678_u32, 0, 32), 0x12345678);
4052 assert_eq!(extract_bits_scalar(i32::MIN, 0, 32), i32::MIN);
4053
4054 assert_eq!(extract_bits_scalar(0x12345678_u32, 8, 8), 0x56);
4056 assert_eq!(extract_bits_scalar(0xf0000000_u32, 28, 4), 0xf);
4057 assert_eq!(extract_bits_scalar(0x12345678_u32, 31, 1), 0);
4058
4059 assert_eq!(extract_bits_scalar(0x12345678_i32, 8, 8), 0x56);
4061 assert_eq!(extract_bits_scalar(0x8_i32, 3, 1), -1);
4062 assert_eq!(extract_bits_scalar(0xf0000000_u32 as i32, 28, 4), -1);
4063 assert_eq!(extract_bits_scalar(0x70000000_i32, 28, 4), 7);
4064
4065 assert_eq!(extract_bits_scalar(0x1234_u16, 4, 8), 0x23);
4067 assert_eq!(extract_bits_scalar(-1_i16, 0, 16), -1);
4068 assert_eq!(
4069 extract_bits_scalar(0x123456789abcdef0_u64, 32, 32),
4070 0x12345678
4071 );
4072 assert_eq!(extract_bits_scalar(-1_i64, 63, 1), -1);
4073
4074 assert!(extract_bits(&[0_u32], 30, 8).is_err());
4076 assert!(extract_bits(&[0_u32], 33, 0).is_err());
4077 assert!(extract_bits(&[0_u16], 8, 16).is_err());
4078 assert!(extract_bits(&[0_u32], u32::MAX, u32::MAX).is_err());
4079 assert!(extract_bits(&[0_u32], 32, 0).is_ok());
4080}
4081
4082#[test]
4083fn insert_bits_smoke() {
4084 assert_eq!(
4086 insert_bits_scalar(0x12345678_u32, 0xffffffff, 0, 0),
4087 0x12345678
4088 );
4089 assert_eq!(insert_bits_scalar(-1_i32, 0, 32, 0), -1);
4090
4091 assert_eq!(
4093 insert_bits_scalar(0x12345678_u32, 0xdeadbeef, 0, 32),
4094 0xdeadbeef
4095 );
4096 assert_eq!(insert_bits_scalar(0_i32, i32::MIN, 0, 32), i32::MIN);
4097
4098 assert_eq!(insert_bits_scalar(0x12345678_u32, 0xff, 8, 8), 0x1234ff78);
4101 assert_eq!(insert_bits_scalar(0x12345678_u32, 0xabcd, 8, 8), 0x1234cd78);
4102 assert_eq!(insert_bits_scalar(0_u32, 0xf, 28, 4), 0xf0000000);
4103 assert_eq!(insert_bits_scalar(0_u32, 1, 31, 1), 0x80000000);
4104
4105 assert_eq!(insert_bits_scalar(0_i32, -1, 31, 1), i32::MIN);
4107 assert_eq!(insert_bits_scalar(-1_i32, 0, 0, 31), i32::MIN);
4108
4109 assert_eq!(insert_bits_scalar(0x1234_u16, 0xf, 4, 4), 0x12f4);
4111 assert_eq!(insert_bits_scalar(0_i16, -1, 15, 1), i16::MIN);
4112 assert_eq!(
4113 insert_bits_scalar(0_u64, 0xffffffff, 32, 32),
4114 0xffffffff00000000
4115 );
4116
4117 assert!(insert_bits(&[0_u32], &[0], 30, 8).is_err());
4119 assert!(insert_bits(&[0_u32], &[0], 33, 0).is_err());
4120 assert!(insert_bits(&[0_u16], &[0], 8, 16).is_err());
4121 assert!(insert_bits(&[0_u32], &[0], u32::MAX, u32::MAX).is_err());
4122 assert!(insert_bits(&[0_u32], &[0], 32, 0).is_ok());
4123}
4124
4125fn first_trailing_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4126 let trailing_zeros_to_bit_idx = |e: u32| -> u32 {
4130 match e {
4131 idx @ 0..=31 => idx,
4132 32 => u32::MAX,
4133 _ => unreachable!(),
4134 }
4135 };
4136 match concrete_int {
4137 ConcreteInt::U32([e]) => ConcreteInt::U32([trailing_zeros_to_bit_idx(e.trailing_zeros())]),
4138 ConcreteInt::I32([e]) => {
4139 ConcreteInt::I32([trailing_zeros_to_bit_idx(e.trailing_zeros()) as i32])
4140 }
4141 }
4142}
4143
4144#[test]
4145fn first_trailing_bit_smoke() {
4146 assert_eq!(
4147 first_trailing_bit(ConcreteInt::I32([0])),
4148 ConcreteInt::I32([-1])
4149 );
4150 assert_eq!(
4151 first_trailing_bit(ConcreteInt::I32([1])),
4152 ConcreteInt::I32([0])
4153 );
4154 assert_eq!(
4155 first_trailing_bit(ConcreteInt::I32([2])),
4156 ConcreteInt::I32([1])
4157 );
4158 assert_eq!(
4159 first_trailing_bit(ConcreteInt::I32([-1])),
4160 ConcreteInt::I32([0]),
4161 );
4162 assert_eq!(
4163 first_trailing_bit(ConcreteInt::I32([i32::MIN])),
4164 ConcreteInt::I32([31]),
4165 );
4166 assert_eq!(
4167 first_trailing_bit(ConcreteInt::I32([i32::MAX])),
4168 ConcreteInt::I32([0]),
4169 );
4170 for idx in 0..32 {
4171 assert_eq!(
4172 first_trailing_bit(ConcreteInt::I32([1 << idx])),
4173 ConcreteInt::I32([idx])
4174 )
4175 }
4176
4177 assert_eq!(
4178 first_trailing_bit(ConcreteInt::U32([0])),
4179 ConcreteInt::U32([u32::MAX])
4180 );
4181 assert_eq!(
4182 first_trailing_bit(ConcreteInt::U32([1])),
4183 ConcreteInt::U32([0])
4184 );
4185 assert_eq!(
4186 first_trailing_bit(ConcreteInt::U32([2])),
4187 ConcreteInt::U32([1])
4188 );
4189 assert_eq!(
4190 first_trailing_bit(ConcreteInt::U32([1 << 31])),
4191 ConcreteInt::U32([31]),
4192 );
4193 assert_eq!(
4194 first_trailing_bit(ConcreteInt::U32([u32::MAX])),
4195 ConcreteInt::U32([0]),
4196 );
4197 for idx in 0..32 {
4198 assert_eq!(
4199 first_trailing_bit(ConcreteInt::U32([1 << idx])),
4200 ConcreteInt::U32([idx])
4201 )
4202 }
4203}
4204
4205fn first_leading_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
4206 let rtl_to_ltr_bit_idx = |e: u32| -> u32 {
4210 match e {
4211 idx @ 0..=31 => 31 - idx,
4212 32 => u32::MAX,
4213 _ => unreachable!(),
4214 }
4215 };
4216 match concrete_int {
4217 ConcreteInt::I32([e]) => ConcreteInt::I32([{
4218 let rtl_bit_index = if e.is_negative() {
4219 e.leading_ones()
4220 } else {
4221 e.leading_zeros()
4222 };
4223 rtl_to_ltr_bit_idx(rtl_bit_index) as i32
4224 }]),
4225 ConcreteInt::U32([e]) => ConcreteInt::U32([rtl_to_ltr_bit_idx(e.leading_zeros())]),
4226 }
4227}
4228
4229#[test]
4230fn first_leading_bit_smoke() {
4231 assert_eq!(
4232 first_leading_bit(ConcreteInt::I32([-1])),
4233 ConcreteInt::I32([-1])
4234 );
4235 assert_eq!(
4236 first_leading_bit(ConcreteInt::I32([0])),
4237 ConcreteInt::I32([-1])
4238 );
4239 assert_eq!(
4240 first_leading_bit(ConcreteInt::I32([1])),
4241 ConcreteInt::I32([0])
4242 );
4243 assert_eq!(
4244 first_leading_bit(ConcreteInt::I32([-2])),
4245 ConcreteInt::I32([0])
4246 );
4247 assert_eq!(
4248 first_leading_bit(ConcreteInt::I32([1234 + 4567])),
4249 ConcreteInt::I32([12])
4250 );
4251 assert_eq!(
4252 first_leading_bit(ConcreteInt::I32([i32::MAX])),
4253 ConcreteInt::I32([30])
4254 );
4255 assert_eq!(
4256 first_leading_bit(ConcreteInt::I32([i32::MIN])),
4257 ConcreteInt::I32([30])
4258 );
4259 for idx in 0..(32 - 1) {
4261 assert_eq!(
4262 first_leading_bit(ConcreteInt::I32([1 << idx])),
4263 ConcreteInt::I32([idx])
4264 );
4265 }
4266 for idx in 1..(32 - 1) {
4267 assert_eq!(
4268 first_leading_bit(ConcreteInt::I32([-(1 << idx)])),
4269 ConcreteInt::I32([idx - 1])
4270 );
4271 }
4272
4273 assert_eq!(
4274 first_leading_bit(ConcreteInt::U32([0])),
4275 ConcreteInt::U32([u32::MAX])
4276 );
4277 assert_eq!(
4278 first_leading_bit(ConcreteInt::U32([1])),
4279 ConcreteInt::U32([0])
4280 );
4281 assert_eq!(
4282 first_leading_bit(ConcreteInt::U32([u32::MAX])),
4283 ConcreteInt::U32([31])
4284 );
4285 for idx in 0..32 {
4286 assert_eq!(
4287 first_leading_bit(ConcreteInt::U32([1 << idx])),
4288 ConcreteInt::U32([idx])
4289 )
4290 }
4291}
4292
4293trait TryFromAbstract<T>: Sized {
4295 fn try_from_abstract(value: T) -> Result<Self, ConstantEvaluatorError>;
4317}
4318
4319impl TryFromAbstract<i64> for i32 {
4320 fn try_from_abstract(value: i64) -> Result<i32, ConstantEvaluatorError> {
4321 i32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4322 value: format!("{value:?}"),
4323 to_type: "i32",
4324 })
4325 }
4326}
4327
4328impl TryFromAbstract<i64> for u32 {
4329 fn try_from_abstract(value: i64) -> Result<u32, ConstantEvaluatorError> {
4330 u32::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4331 value: format!("{value:?}"),
4332 to_type: "u32",
4333 })
4334 }
4335}
4336
4337impl TryFromAbstract<i64> for u64 {
4338 fn try_from_abstract(value: i64) -> Result<u64, ConstantEvaluatorError> {
4339 u64::try_from(value).map_err(|_| ConstantEvaluatorError::AutomaticConversionLossy {
4340 value: format!("{value:?}"),
4341 to_type: "u64",
4342 })
4343 }
4344}
4345
4346impl TryFromAbstract<i64> for i64 {
4347 fn try_from_abstract(value: i64) -> Result<i64, ConstantEvaluatorError> {
4348 Ok(value)
4349 }
4350}
4351
4352impl TryFromAbstract<i64> for f32 {
4353 fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4354 let f = value as f32;
4355 Ok(f)
4359 }
4360}
4361
4362impl TryFromAbstract<f64> for f32 {
4363 fn try_from_abstract(value: f64) -> Result<f32, ConstantEvaluatorError> {
4364 let f = value as f32;
4365 if f.is_infinite() {
4366 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4367 value: format!("{value:?}"),
4368 to_type: "f32",
4369 });
4370 }
4371 Ok(f)
4372 }
4373}
4374
4375impl TryFromAbstract<i64> for f64 {
4376 fn try_from_abstract(value: i64) -> Result<Self, ConstantEvaluatorError> {
4377 let f = value as f64;
4378 Ok(f)
4382 }
4383}
4384
4385impl TryFromAbstract<f64> for f64 {
4386 fn try_from_abstract(value: f64) -> Result<f64, ConstantEvaluatorError> {
4387 Ok(value)
4388 }
4389}
4390
4391impl TryFromAbstract<f64> for i32 {
4392 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4393 Ok(value as i32)
4406 }
4407}
4408
4409impl TryFromAbstract<f64> for u32 {
4410 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4411 Ok(value as u32)
4414 }
4415}
4416
4417impl TryFromAbstract<f64> for i64 {
4418 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4419 use crate::proc::type_methods::IntFloatLimits;
4422 Ok(value.clamp(i64::min_float(), i64::max_float()) as i64)
4423 }
4424}
4425
4426impl TryFromAbstract<f64> for u64 {
4427 fn try_from_abstract(value: f64) -> Result<Self, ConstantEvaluatorError> {
4428 use crate::proc::type_methods::IntFloatLimits;
4431 Ok(value.clamp(u64::min_float(), u64::max_float()) as u64)
4432 }
4433}
4434
4435impl TryFromAbstract<f64> for f16 {
4436 fn try_from_abstract(value: f64) -> Result<f16, ConstantEvaluatorError> {
4437 let f = f16::from_f64(value);
4438 if f.is_infinite() {
4439 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4440 value: format!("{value:?}"),
4441 to_type: "f16",
4442 });
4443 }
4444 Ok(f)
4445 }
4446}
4447
4448impl TryFromAbstract<i64> for f16 {
4449 fn try_from_abstract(value: i64) -> Result<f16, ConstantEvaluatorError> {
4450 let f = f16::from_i64(value);
4451 if f.is_none() {
4452 return Err(ConstantEvaluatorError::AutomaticConversionLossy {
4453 value: format!("{value:?}"),
4454 to_type: "f16",
4455 });
4456 }
4457 Ok(f.unwrap())
4458 }
4459}
4460
4461fn cross_product<T>(a: [T; 3], b: [T; 3]) -> [T; 3]
4462where
4463 T: Copy,
4464 T: core::ops::Mul<T, Output = T>,
4465 T: core::ops::Sub<T, Output = T>,
4466{
4467 [
4468 a[1] * b[2] - a[2] * b[1],
4469 a[2] * b[0] - a[0] * b[2],
4470 a[0] * b[1] - a[1] * b[0],
4471 ]
4472}
4473
4474#[cfg(test)]
4475mod tests {
4476 use alloc::{vec, vec::Vec};
4477
4478 use crate::{
4479 Arena, BinaryOperator, Constant, Expression, FastHashMap, Handle, Literal, Type, TypeInner,
4480 UnaryOperator, UniqueArena, VectorSize,
4481 };
4482
4483 use super::{Behavior, ConstantEvaluator, ExpressionKindTracker, WgslRestrictions};
4484
4485 #[test]
4486 fn unary_op() {
4487 let mut types = UniqueArena::new();
4488 let mut constants = Arena::new();
4489 let overrides = Arena::new();
4490 let mut global_expressions = Arena::new();
4491
4492 let scalar_ty = types.insert(
4493 Type {
4494 name: None,
4495 inner: TypeInner::Scalar(crate::Scalar::I32),
4496 },
4497 Default::default(),
4498 );
4499
4500 let vec_ty = types.insert(
4501 Type {
4502 name: None,
4503 inner: TypeInner::Vector {
4504 size: VectorSize::Bi,
4505 scalar: crate::Scalar::I32,
4506 },
4507 },
4508 Default::default(),
4509 );
4510
4511 let h = constants.append(
4512 Constant {
4513 name: None,
4514 ty: scalar_ty,
4515 init: global_expressions
4516 .append(Expression::Literal(Literal::I32(4)), Default::default()),
4517 },
4518 Default::default(),
4519 );
4520
4521 let h1 = constants.append(
4522 Constant {
4523 name: None,
4524 ty: scalar_ty,
4525 init: global_expressions
4526 .append(Expression::Literal(Literal::I32(8)), Default::default()),
4527 },
4528 Default::default(),
4529 );
4530
4531 let vec_h = constants.append(
4532 Constant {
4533 name: None,
4534 ty: vec_ty,
4535 init: global_expressions.append(
4536 Expression::Compose {
4537 ty: vec_ty,
4538 components: vec![constants[h].init, constants[h1].init],
4539 },
4540 Default::default(),
4541 ),
4542 },
4543 Default::default(),
4544 );
4545
4546 let expr = global_expressions.append(Expression::Constant(h), Default::default());
4547 let expr1 = global_expressions.append(Expression::Constant(vec_h), Default::default());
4548
4549 let expr2 = Expression::Unary {
4550 op: UnaryOperator::Negate,
4551 expr,
4552 };
4553
4554 let expr3 = Expression::Unary {
4555 op: UnaryOperator::BitwiseNot,
4556 expr,
4557 };
4558
4559 let expr4 = Expression::Unary {
4560 op: UnaryOperator::BitwiseNot,
4561 expr: expr1,
4562 };
4563
4564 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4565 let mut solver = ConstantEvaluator {
4566 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4567 types: &mut types,
4568 constants: &constants,
4569 overrides: &overrides,
4570 expressions: &mut global_expressions,
4571 expression_kind_tracker,
4572 layouter: &mut crate::proc::Layouter::default(),
4573 };
4574
4575 let res1 = solver
4576 .try_eval_and_append(expr2, Default::default())
4577 .unwrap();
4578 let res2 = solver
4579 .try_eval_and_append(expr3, Default::default())
4580 .unwrap();
4581 let res3 = solver
4582 .try_eval_and_append(expr4, Default::default())
4583 .unwrap();
4584
4585 assert_eq!(
4586 global_expressions[res1],
4587 Expression::Literal(Literal::I32(-4))
4588 );
4589
4590 assert_eq!(
4591 global_expressions[res2],
4592 Expression::Literal(Literal::I32(!4))
4593 );
4594
4595 let res3_inner = &global_expressions[res3];
4596
4597 match *res3_inner {
4598 Expression::Compose {
4599 ref ty,
4600 ref components,
4601 } => {
4602 assert_eq!(*ty, vec_ty);
4603 let mut components_iter = components.iter().copied();
4604 assert_eq!(
4605 global_expressions[components_iter.next().unwrap()],
4606 Expression::Literal(Literal::I32(!4))
4607 );
4608 assert_eq!(
4609 global_expressions[components_iter.next().unwrap()],
4610 Expression::Literal(Literal::I32(!8))
4611 );
4612 assert!(components_iter.next().is_none());
4613 }
4614 _ => panic!("Expected vector"),
4615 }
4616 }
4617
4618 #[test]
4619 fn matrix_op() {
4620 let mut helper = MatrixTestHelper::new();
4621
4622 for nc in 2..=4 {
4623 for nr in 2..=4 {
4624 let evaluated = helper.eval_vector_multiply_matrix(nc, nr);
4627 let expected = (0..nc)
4628 .map(|c| (0..nr).map(|r| (r * (c * nr + r)) as f32).sum())
4629 .collect::<Vec<f32>>();
4630 assert_eq!(evaluated, expected);
4631
4632 let evaluated = helper.eval_matrix_multiply_vector(nc, nr);
4635 let expected = (0..nr)
4636 .map(|r| (0..nc).map(|c| (c * (c * nr + r)) as f32).sum())
4637 .collect::<Vec<f32>>();
4638 assert_eq!(evaluated, expected);
4639
4640 for k in 2..=4 {
4641 let evaluated = helper.eval_matrix_multiply_matrix(nr, nc, k);
4644 let expected = (0..nc)
4645 .flat_map(|c| {
4646 (0..nr).map(move |r| {
4647 (0..k).map(|v| ((v * nr + r) * (c * k + v)) as f32).sum()
4648 })
4649 })
4650 .collect::<Vec<f32>>();
4651 assert_eq!(evaluated, expected);
4652 }
4653 }
4654 }
4655 }
4656
4657 struct MatrixTestHelper {
4661 types: UniqueArena<Type>,
4662 expressions: Arena<Expression>,
4663 vec_exprs: FastHashMap<usize, Handle<Expression>>,
4665 mat_exprs: FastHashMap<(usize, usize), Handle<Expression>>,
4667 }
4668
4669 impl MatrixTestHelper {
4670 fn new() -> Self {
4671 let mut types = UniqueArena::new();
4672 let mut expressions = Arena::new();
4673 let span = crate::Span::default();
4674
4675 let (mut vec_tys, mut mat_tys) = (FastHashMap::default(), FastHashMap::default());
4676 for c in 2..=4 {
4677 let vec_ty = types.insert(
4678 Type {
4679 name: None,
4680 inner: TypeInner::Vector {
4681 size: Self::int_to_vector_size(c),
4682 scalar: crate::Scalar::F32,
4683 },
4684 },
4685 span,
4686 );
4687 vec_tys.insert(c, vec_ty);
4688 for r in 2..=4 {
4689 let mat_ty = types.insert(
4690 Type {
4691 name: None,
4692 inner: TypeInner::Matrix {
4693 columns: Self::int_to_vector_size(c),
4694 rows: Self::int_to_vector_size(r),
4695 scalar: crate::Scalar::F32,
4696 },
4697 },
4698 span,
4699 );
4700 mat_tys.insert((c, r), mat_ty);
4701 }
4702 }
4703
4704 let mut lit_exprs = FastHashMap::default();
4705 for i in 0..16 {
4706 let expr = expressions.append(Expression::Literal(Literal::F32(i as f32)), span);
4707 lit_exprs.insert(i, expr);
4708 }
4709
4710 let mut vec_exprs = FastHashMap::default();
4711 for c in 2..=4 {
4712 let expr = expressions.append(
4713 Expression::Compose {
4714 ty: *vec_tys.get(&c).unwrap(),
4715 components: (0..c)
4716 .map(|i| *lit_exprs.get(&i).unwrap())
4717 .collect::<Vec<_>>(),
4718 },
4719 span,
4720 );
4721 vec_exprs.insert(c, expr);
4722 }
4723
4724 let mut mat_exprs = FastHashMap::default();
4725 for c in 2..=4 {
4726 for r in 2..=4 {
4727 let mut columns = Vec::with_capacity(c);
4728 for cc in 0..c {
4729 let start = cc * r;
4730 let expr = expressions.append(
4731 Expression::Compose {
4732 ty: *vec_tys.get(&r).unwrap(),
4733 components: (start..start + r)
4734 .map(|i| *lit_exprs.get(&i).unwrap())
4735 .collect::<Vec<_>>(),
4736 },
4737 span,
4738 );
4739 columns.push(expr);
4740 }
4741
4742 let expr = expressions.append(
4743 Expression::Compose {
4744 ty: *mat_tys.get(&(c, r)).unwrap(),
4745 components: columns,
4746 },
4747 span,
4748 );
4749 mat_exprs.insert((c, r), expr);
4750 }
4751 }
4752
4753 Self {
4754 types,
4755 expressions,
4756 vec_exprs,
4757 mat_exprs,
4758 }
4759 }
4760
4761 fn eval_vector_multiply_matrix(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4763 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4764 let mut solver = ConstantEvaluator {
4765 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4766 types: &mut self.types,
4767 constants: &Arena::new(),
4768 overrides: &Arena::new(),
4769 expressions: &mut self.expressions,
4770 expression_kind_tracker,
4771 layouter: &mut crate::proc::Layouter::default(),
4772 };
4773
4774 let result = solver
4775 .try_eval_and_append(
4776 Expression::Binary {
4777 op: BinaryOperator::Multiply,
4778 left: *self.vec_exprs.get(&nr).unwrap(),
4779 right: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4780 },
4781 Default::default(),
4782 )
4783 .unwrap();
4784 self.flatten(result)
4785 }
4786
4787 fn eval_matrix_multiply_vector(&mut self, nc: usize, nr: usize) -> Vec<f32> {
4789 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4790 let mut solver = ConstantEvaluator {
4791 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4792 types: &mut self.types,
4793 constants: &Arena::new(),
4794 overrides: &Arena::new(),
4795 expressions: &mut self.expressions,
4796 expression_kind_tracker,
4797 layouter: &mut crate::proc::Layouter::default(),
4798 };
4799
4800 let result = solver
4801 .try_eval_and_append(
4802 Expression::Binary {
4803 op: BinaryOperator::Multiply,
4804 left: *self.mat_exprs.get(&(nc, nr)).unwrap(),
4805 right: *self.vec_exprs.get(&nc).unwrap(),
4806 },
4807 Default::default(),
4808 )
4809 .unwrap();
4810 self.flatten(result)
4811 }
4812
4813 fn eval_matrix_multiply_matrix(&mut self, l_nr: usize, r_nc: usize, k: usize) -> Vec<f32> {
4816 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&self.expressions);
4817 let mut solver = ConstantEvaluator {
4818 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4819 types: &mut self.types,
4820 constants: &Arena::new(),
4821 overrides: &Arena::new(),
4822 expressions: &mut self.expressions,
4823 expression_kind_tracker,
4824 layouter: &mut crate::proc::Layouter::default(),
4825 };
4826
4827 let result = solver
4828 .try_eval_and_append(
4829 Expression::Binary {
4830 op: BinaryOperator::Multiply,
4831 left: *self.mat_exprs.get(&(k, l_nr)).unwrap(),
4832 right: *self.mat_exprs.get(&(r_nc, k)).unwrap(),
4833 },
4834 Default::default(),
4835 )
4836 .unwrap();
4837 self.flatten(result)
4838 }
4839
4840 fn flatten(&self, expr: Handle<Expression>) -> Vec<f32> {
4841 let Expression::Compose {
4842 ref components,
4843 ref ty,
4844 } = self.expressions[expr]
4845 else {
4846 unreachable!()
4847 };
4848
4849 match self.types[*ty].inner {
4850 TypeInner::Vector { .. } => components
4851 .iter()
4852 .map(|&comp| {
4853 let Expression::Literal(Literal::F32(v)) = self.expressions[comp] else {
4854 unreachable!()
4855 };
4856 v
4857 })
4858 .collect(),
4859 TypeInner::Matrix { .. } => components
4860 .iter()
4861 .flat_map(|&comp| self.flatten(comp))
4862 .collect(),
4863 _ => unreachable!(),
4864 }
4865 }
4866
4867 fn int_to_vector_size(int: usize) -> VectorSize {
4868 match int {
4869 2 => VectorSize::Bi,
4870 3 => VectorSize::Tri,
4871 4 => VectorSize::Quad,
4872 _ => unreachable!(),
4873 }
4874 }
4875 }
4876
4877 #[test]
4878 fn cast() {
4879 let mut types = UniqueArena::new();
4880 let mut constants = Arena::new();
4881 let overrides = Arena::new();
4882 let mut global_expressions = Arena::new();
4883
4884 let scalar_ty = types.insert(
4885 Type {
4886 name: None,
4887 inner: TypeInner::Scalar(crate::Scalar::I32),
4888 },
4889 Default::default(),
4890 );
4891
4892 let h = constants.append(
4893 Constant {
4894 name: None,
4895 ty: scalar_ty,
4896 init: global_expressions
4897 .append(Expression::Literal(Literal::I32(4)), Default::default()),
4898 },
4899 Default::default(),
4900 );
4901
4902 let expr = global_expressions.append(Expression::Constant(h), Default::default());
4903
4904 let root = Expression::As {
4905 expr,
4906 target: crate::Scalar::BOOL,
4907 };
4908
4909 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
4910 let mut solver = ConstantEvaluator {
4911 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
4912 types: &mut types,
4913 constants: &constants,
4914 overrides: &overrides,
4915 expressions: &mut global_expressions,
4916 expression_kind_tracker,
4917 layouter: &mut crate::proc::Layouter::default(),
4918 };
4919
4920 let res = solver
4921 .try_eval_and_append(root, Default::default())
4922 .unwrap();
4923
4924 assert_eq!(
4925 global_expressions[res],
4926 Expression::Literal(Literal::Bool(true))
4927 );
4928 }
4929
4930 #[test]
4931 fn access() {
4932 let mut types = UniqueArena::new();
4933 let mut constants = Arena::new();
4934 let overrides = Arena::new();
4935 let mut global_expressions = Arena::new();
4936
4937 let matrix_ty = types.insert(
4938 Type {
4939 name: None,
4940 inner: TypeInner::Matrix {
4941 columns: VectorSize::Bi,
4942 rows: VectorSize::Tri,
4943 scalar: crate::Scalar::F32,
4944 },
4945 },
4946 Default::default(),
4947 );
4948
4949 let vec_ty = types.insert(
4950 Type {
4951 name: None,
4952 inner: TypeInner::Vector {
4953 size: VectorSize::Tri,
4954 scalar: crate::Scalar::F32,
4955 },
4956 },
4957 Default::default(),
4958 );
4959
4960 let mut vec1_components = Vec::with_capacity(3);
4961 let mut vec2_components = Vec::with_capacity(3);
4962
4963 for i in 0..3 {
4964 let h = global_expressions.append(
4965 Expression::Literal(Literal::F32(i as f32)),
4966 Default::default(),
4967 );
4968
4969 vec1_components.push(h)
4970 }
4971
4972 for i in 3..6 {
4973 let h = global_expressions.append(
4974 Expression::Literal(Literal::F32(i as f32)),
4975 Default::default(),
4976 );
4977
4978 vec2_components.push(h)
4979 }
4980
4981 let vec1 = constants.append(
4982 Constant {
4983 name: None,
4984 ty: vec_ty,
4985 init: global_expressions.append(
4986 Expression::Compose {
4987 ty: vec_ty,
4988 components: vec1_components,
4989 },
4990 Default::default(),
4991 ),
4992 },
4993 Default::default(),
4994 );
4995
4996 let vec2 = constants.append(
4997 Constant {
4998 name: None,
4999 ty: vec_ty,
5000 init: global_expressions.append(
5001 Expression::Compose {
5002 ty: vec_ty,
5003 components: vec2_components,
5004 },
5005 Default::default(),
5006 ),
5007 },
5008 Default::default(),
5009 );
5010
5011 let h = constants.append(
5012 Constant {
5013 name: None,
5014 ty: matrix_ty,
5015 init: global_expressions.append(
5016 Expression::Compose {
5017 ty: matrix_ty,
5018 components: vec![constants[vec1].init, constants[vec2].init],
5019 },
5020 Default::default(),
5021 ),
5022 },
5023 Default::default(),
5024 );
5025
5026 let base = global_expressions.append(Expression::Constant(h), Default::default());
5027
5028 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5029 let mut solver = ConstantEvaluator {
5030 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5031 types: &mut types,
5032 constants: &constants,
5033 overrides: &overrides,
5034 expressions: &mut global_expressions,
5035 expression_kind_tracker,
5036 layouter: &mut crate::proc::Layouter::default(),
5037 };
5038
5039 let root1 = Expression::AccessIndex { base, index: 1 };
5040
5041 let res1 = solver
5042 .try_eval_and_append(root1, Default::default())
5043 .unwrap();
5044
5045 let root2 = Expression::AccessIndex {
5046 base: res1,
5047 index: 2,
5048 };
5049
5050 let res2 = solver
5051 .try_eval_and_append(root2, Default::default())
5052 .unwrap();
5053
5054 match global_expressions[res1] {
5055 Expression::Compose {
5056 ref ty,
5057 ref components,
5058 } => {
5059 assert_eq!(*ty, vec_ty);
5060 let mut components_iter = components.iter().copied();
5061 assert_eq!(
5062 global_expressions[components_iter.next().unwrap()],
5063 Expression::Literal(Literal::F32(3.))
5064 );
5065 assert_eq!(
5066 global_expressions[components_iter.next().unwrap()],
5067 Expression::Literal(Literal::F32(4.))
5068 );
5069 assert_eq!(
5070 global_expressions[components_iter.next().unwrap()],
5071 Expression::Literal(Literal::F32(5.))
5072 );
5073 assert!(components_iter.next().is_none());
5074 }
5075 _ => panic!("Expected vector"),
5076 }
5077
5078 assert_eq!(
5079 global_expressions[res2],
5080 Expression::Literal(Literal::F32(5.))
5081 );
5082 }
5083
5084 #[test]
5085 fn compose_of_constants() {
5086 let mut types = UniqueArena::new();
5087 let mut constants = Arena::new();
5088 let overrides = Arena::new();
5089 let mut global_expressions = Arena::new();
5090
5091 let i32_ty = types.insert(
5092 Type {
5093 name: None,
5094 inner: TypeInner::Scalar(crate::Scalar::I32),
5095 },
5096 Default::default(),
5097 );
5098
5099 let vec2_i32_ty = types.insert(
5100 Type {
5101 name: None,
5102 inner: TypeInner::Vector {
5103 size: VectorSize::Bi,
5104 scalar: crate::Scalar::I32,
5105 },
5106 },
5107 Default::default(),
5108 );
5109
5110 let h = constants.append(
5111 Constant {
5112 name: None,
5113 ty: i32_ty,
5114 init: global_expressions
5115 .append(Expression::Literal(Literal::I32(4)), Default::default()),
5116 },
5117 Default::default(),
5118 );
5119
5120 let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5121
5122 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5123 let mut solver = ConstantEvaluator {
5124 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5125 types: &mut types,
5126 constants: &constants,
5127 overrides: &overrides,
5128 expressions: &mut global_expressions,
5129 expression_kind_tracker,
5130 layouter: &mut crate::proc::Layouter::default(),
5131 };
5132
5133 let solved_compose = solver
5134 .try_eval_and_append(
5135 Expression::Compose {
5136 ty: vec2_i32_ty,
5137 components: vec![h_expr, h_expr],
5138 },
5139 Default::default(),
5140 )
5141 .unwrap();
5142 let solved_negate = solver
5143 .try_eval_and_append(
5144 Expression::Unary {
5145 op: UnaryOperator::Negate,
5146 expr: solved_compose,
5147 },
5148 Default::default(),
5149 )
5150 .unwrap();
5151
5152 let pass = match global_expressions[solved_negate] {
5153 Expression::Compose { ty, ref components } => {
5154 ty == vec2_i32_ty
5155 && components.iter().all(|&component| {
5156 let component = &global_expressions[component];
5157 matches!(*component, Expression::Literal(Literal::I32(-4)))
5158 })
5159 }
5160 _ => false,
5161 };
5162 if !pass {
5163 panic!("unexpected evaluation result")
5164 }
5165 }
5166
5167 #[test]
5168 fn splat_of_constant() {
5169 let mut types = UniqueArena::new();
5170 let mut constants = Arena::new();
5171 let overrides = Arena::new();
5172 let mut global_expressions = Arena::new();
5173
5174 let i32_ty = types.insert(
5175 Type {
5176 name: None,
5177 inner: TypeInner::Scalar(crate::Scalar::I32),
5178 },
5179 Default::default(),
5180 );
5181
5182 let vec2_i32_ty = types.insert(
5183 Type {
5184 name: None,
5185 inner: TypeInner::Vector {
5186 size: VectorSize::Bi,
5187 scalar: crate::Scalar::I32,
5188 },
5189 },
5190 Default::default(),
5191 );
5192
5193 let h = constants.append(
5194 Constant {
5195 name: None,
5196 ty: i32_ty,
5197 init: global_expressions
5198 .append(Expression::Literal(Literal::I32(4)), Default::default()),
5199 },
5200 Default::default(),
5201 );
5202
5203 let h_expr = global_expressions.append(Expression::Constant(h), Default::default());
5204
5205 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5206 let mut solver = ConstantEvaluator {
5207 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5208 types: &mut types,
5209 constants: &constants,
5210 overrides: &overrides,
5211 expressions: &mut global_expressions,
5212 expression_kind_tracker,
5213 layouter: &mut crate::proc::Layouter::default(),
5214 };
5215
5216 let solved_compose = solver
5217 .try_eval_and_append(
5218 Expression::Splat {
5219 size: VectorSize::Bi,
5220 value: h_expr,
5221 },
5222 Default::default(),
5223 )
5224 .unwrap();
5225 let solved_negate = solver
5226 .try_eval_and_append(
5227 Expression::Unary {
5228 op: UnaryOperator::Negate,
5229 expr: solved_compose,
5230 },
5231 Default::default(),
5232 )
5233 .unwrap();
5234
5235 let pass = match global_expressions[solved_negate] {
5236 Expression::Compose { ty, ref components } => {
5237 ty == vec2_i32_ty
5238 && components.iter().all(|&component| {
5239 let component = &global_expressions[component];
5240 matches!(*component, Expression::Literal(Literal::I32(-4)))
5241 })
5242 }
5243 _ => false,
5244 };
5245 if !pass {
5246 panic!("unexpected evaluation result")
5247 }
5248 }
5249
5250 #[test]
5251 fn splat_of_zero_value() {
5252 let mut types = UniqueArena::new();
5253 let constants = Arena::new();
5254 let overrides = Arena::new();
5255 let mut global_expressions = Arena::new();
5256
5257 let f32_ty = types.insert(
5258 Type {
5259 name: None,
5260 inner: TypeInner::Scalar(crate::Scalar::F32),
5261 },
5262 Default::default(),
5263 );
5264
5265 let vec2_f32_ty = types.insert(
5266 Type {
5267 name: None,
5268 inner: TypeInner::Vector {
5269 size: VectorSize::Bi,
5270 scalar: crate::Scalar::F32,
5271 },
5272 },
5273 Default::default(),
5274 );
5275
5276 let five =
5277 global_expressions.append(Expression::Literal(Literal::F32(5.0)), Default::default());
5278 let five_splat = global_expressions.append(
5279 Expression::Splat {
5280 size: VectorSize::Bi,
5281 value: five,
5282 },
5283 Default::default(),
5284 );
5285 let zero = global_expressions.append(Expression::ZeroValue(f32_ty), Default::default());
5286 let zero_splat = global_expressions.append(
5287 Expression::Splat {
5288 size: VectorSize::Bi,
5289 value: zero,
5290 },
5291 Default::default(),
5292 );
5293
5294 let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
5295 let mut solver = ConstantEvaluator {
5296 behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
5297 types: &mut types,
5298 constants: &constants,
5299 overrides: &overrides,
5300 expressions: &mut global_expressions,
5301 expression_kind_tracker,
5302 layouter: &mut crate::proc::Layouter::default(),
5303 };
5304
5305 let solved_add = solver
5306 .try_eval_and_append(
5307 Expression::Binary {
5308 op: BinaryOperator::Add,
5309 left: zero_splat,
5310 right: five_splat,
5311 },
5312 Default::default(),
5313 )
5314 .unwrap();
5315
5316 let pass = match global_expressions[solved_add] {
5317 Expression::Compose { ty, ref components } => {
5318 ty == vec2_f32_ty
5319 && components.iter().all(|&component| {
5320 let component = &global_expressions[component];
5321 matches!(*component, Expression::Literal(Literal::F32(5.0)))
5322 })
5323 }
5324 _ => false,
5325 };
5326 if !pass {
5327 panic!("unexpected evaluation result")
5328 }
5329 }
5330}