1use alloc::{
2 borrow::Cow,
3 boxed::Box,
4 string::{String, ToString},
5 vec::Vec,
6};
7use core::mem;
8
9use hashbrown::HashSet;
10use thiserror::Error;
11
12use super::PipelineConstants;
13use crate::{
14 arena::HandleVec,
15 compact::{compact, KeepUnused},
16 ir,
17 proc::{ConstantEvaluator, ConstantEvaluatorError, Emitter},
18 valid::{Capabilities, ModuleInfo, ValidationError, ValidationFlags, Validator},
19 Arena, Block, Constant, Expression, Function, Handle, Literal, Module, Override, Range, Scalar,
20 Span, Statement, TypeInner, WithSpan,
21};
22
23#[allow(unused_imports)]
25use num_traits::float::FloatCore as _;
26
27#[derive(Error, Debug, Clone)]
28#[cfg_attr(test, derive(PartialEq))]
29pub enum PipelineConstantError {
30 #[error("Missing value for pipeline-overridable constant with identifier string: '{0}'")]
31 MissingValue(String),
32 #[error("pipeline-overridable constant '{0}' not found in the shader")]
33 NotFound(String),
34 #[error(
35 "Source f64 value needs to be finite ({}) for number destinations",
36 "NaNs and Inifinites are not allowed"
37 )]
38 SrcNeedsToBeFinite,
39 #[error("Source f64 value doesn't fit in destination")]
40 DstRangeTooSmall,
41 #[error(transparent)]
42 ConstantEvaluatorError(#[from] ConstantEvaluatorError),
43 #[error(transparent)]
44 ValidationError(#[from] Box<WithSpan<ValidationError>>),
45 #[error("workgroup_size override isn't strictly positive")]
46 NegativeWorkgroupSize,
47 #[error("max vertices or max primitives is negative")]
48 NegativeMeshOutputMax,
49}
50
51pub fn process_overrides<'a>(
68 module: &'a Module,
69 module_info: &'a ModuleInfo,
70 entry_point: Option<(ir::ShaderStage, &str)>,
71 pipeline_constants: &PipelineConstants,
72) -> Result<(Cow<'a, Module>, Cow<'a, ModuleInfo>), PipelineConstantError> {
73 let mut handles = module
74 .overrides
75 .iter()
76 .map(|(handle, _)| handle)
77 .collect::<Vec<_>>();
78 for c in pipeline_constants.keys() {
79 let c_id = c.parse().ok();
80 if let Some((i, _)) = handles.iter().enumerate().find(|&(_, handle)| {
81 let o = &module.overrides[*handle];
82 if o.id.is_some() {
83 o.id == c_id
84 } else {
85 o.name.as_deref() == Some(c.as_str())
86 }
87 }) {
88 handles.swap_remove(i);
89 } else {
90 return Err(PipelineConstantError::NotFound(c.clone()));
91 }
92 }
93
94 if (entry_point.is_none() || module.entry_points.len() <= 1) && module.overrides.is_empty() {
95 return Ok((Cow::Borrowed(module), Cow::Borrowed(module_info)));
105 }
106
107 let mut module = module.clone();
108 if let Some((ep_stage, ep_name)) = entry_point {
109 module
110 .entry_points
111 .retain(|ep| ep.stage == ep_stage && ep.name == ep_name);
112 }
113
114 compact(&mut module, KeepUnused::No);
118
119 if module.overrides.is_empty() {
121 return revalidate(module);
122 }
123
124 let mut override_map = HandleVec::with_capacity(module.overrides.len());
127
128 let mut adjusted_global_expressions = HandleVec::with_capacity(module.global_expressions.len());
131
132 let mut adjusted_constant_initializers = HashSet::with_capacity(module.constants.len());
143
144 let mut global_expression_kind_tracker = crate::proc::ExpressionKindTracker::new();
145 let mut layouter = crate::proc::Layouter::default();
146
147 let mut overrides = module.overrides.take();
150 let mut override_iter = overrides.iter_mut_span();
151
152 for (old_h, expr, span) in module.global_expressions.drain() {
182 let mut expr = match expr {
183 Expression::Override(h) => {
184 let c_h = if let Some(new_h) = override_map.get(h) {
185 *new_h
186 } else {
187 let mut new_h = None;
188 for entry in override_iter.by_ref() {
189 let stop = entry.0 == h;
190 new_h = Some(process_override(
191 entry,
192 pipeline_constants,
193 &mut module,
194 &mut override_map,
195 &adjusted_global_expressions,
196 &mut adjusted_constant_initializers,
197 &mut global_expression_kind_tracker,
198 )?);
199 if stop {
200 break;
201 }
202 }
203 new_h.unwrap()
204 };
205 Expression::Constant(c_h)
206 }
207 Expression::Constant(c_h) => {
208 if adjusted_constant_initializers.insert(c_h) {
209 let init = &mut module.constants[c_h].init;
210 *init = adjusted_global_expressions[*init];
211 }
212 expr
213 }
214 expr => expr,
215 };
216 let mut evaluator = ConstantEvaluator::for_wgsl_module(
217 &mut module,
218 &mut global_expression_kind_tracker,
219 &mut layouter,
220 false,
221 );
222 adjust_expr(&adjusted_global_expressions, &mut expr);
223 let h = evaluator.try_eval_and_append(expr, span)?;
224 adjusted_global_expressions.insert(old_h, h);
225 }
226
227 for entry in override_iter {
229 match *entry.1 {
230 Override { name: Some(_), .. } | Override { id: Some(_), .. } => {
231 process_override(
232 entry,
233 pipeline_constants,
234 &mut module,
235 &mut override_map,
236 &adjusted_global_expressions,
237 &mut adjusted_constant_initializers,
238 &mut global_expression_kind_tracker,
239 )?;
240 }
241 Override {
242 init: Some(ref mut init),
243 ..
244 } => {
245 *init = adjusted_global_expressions[*init];
246 }
247 _ => {}
248 }
249 }
250
251 for (_, c) in module
255 .constants
256 .iter_mut()
257 .filter(|&(c_h, _)| !adjusted_constant_initializers.contains(&c_h))
258 {
259 c.init = adjusted_global_expressions[c.init];
260 }
261
262 for (_, v) in module.global_variables.iter_mut() {
263 if let Some(ref mut init) = v.init {
264 *init = adjusted_global_expressions[*init];
265 }
266 }
267
268 let mut functions = module.functions.take();
269 for (_, function) in functions.iter_mut() {
270 process_function(&mut module, &override_map, &mut layouter, function)?;
271 }
272 module.functions = functions;
273
274 let mut entry_points = mem::take(&mut module.entry_points);
275 for ep in entry_points.iter_mut() {
276 process_function(&mut module, &override_map, &mut layouter, &mut ep.function)?;
277 process_workgroup_size_override(&mut module, &adjusted_global_expressions, ep)?;
278 process_mesh_shader_overrides(&mut module, &adjusted_global_expressions, ep)?;
279 }
280 module.entry_points = entry_points;
281 module.overrides = overrides;
282
283 revalidate(module)
287}
288
289fn revalidate(
290 module: Module,
291) -> Result<(Cow<'static, Module>, Cow<'static, ModuleInfo>), PipelineConstantError> {
292 let mut validator = Validator::new(ValidationFlags::all(), Capabilities::all());
293 let module_info = validator.validate_resolved_overrides(&module)?;
294 Ok((Cow::Owned(module), Cow::Owned(module_info)))
295}
296
297fn process_workgroup_size_override(
298 module: &mut Module,
299 adjusted_global_expressions: &HandleVec<Expression, Handle<Expression>>,
300 ep: &mut crate::EntryPoint,
301) -> Result<(), PipelineConstantError> {
302 match ep.workgroup_size_overrides {
303 None => {}
304 Some(overrides) => {
305 overrides.iter().enumerate().try_for_each(
306 |(i, overridden)| -> Result<(), PipelineConstantError> {
307 match *overridden {
308 None => Ok(()),
309 Some(h) => {
310 ep.workgroup_size[i] = module
311 .to_ctx()
312 .get_const_val(adjusted_global_expressions[h])
313 .map(|n| {
314 if n == 0 {
315 Err(PipelineConstantError::NegativeWorkgroupSize)
316 } else {
317 Ok(n)
318 }
319 })
320 .map_err(|_| PipelineConstantError::NegativeWorkgroupSize)??;
321 Ok(())
322 }
323 }
324 },
325 )?;
326 ep.workgroup_size_overrides = None;
327 }
328 }
329 Ok(())
330}
331
332fn process_mesh_shader_overrides(
333 module: &mut Module,
334 adjusted_global_expressions: &HandleVec<Expression, Handle<Expression>>,
335 ep: &mut crate::EntryPoint,
336) -> Result<(), PipelineConstantError> {
337 if let Some(ref mut mesh_info) = ep.mesh_info {
338 if let Some(r#override) = mesh_info.max_vertices_override {
339 mesh_info.max_vertices = module
340 .to_ctx()
341 .get_const_val(adjusted_global_expressions[r#override])
342 .map_err(|_| PipelineConstantError::NegativeMeshOutputMax)?;
343 }
344 if let Some(r#override) = mesh_info.max_primitives_override {
345 mesh_info.max_primitives = module
346 .to_ctx()
347 .get_const_val(adjusted_global_expressions[r#override])
348 .map_err(|_| PipelineConstantError::NegativeMeshOutputMax)?;
349 }
350 }
351 Ok(())
352}
353
354fn process_override(
358 (old_h, r#override, span): (Handle<Override>, &mut Override, &Span),
359 pipeline_constants: &PipelineConstants,
360 module: &mut Module,
361 override_map: &mut HandleVec<Override, Handle<Constant>>,
362 adjusted_global_expressions: &HandleVec<Expression, Handle<Expression>>,
363 adjusted_constant_initializers: &mut HashSet<Handle<Constant>>,
364 global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker,
365) -> Result<Handle<Constant>, PipelineConstantError> {
366 let key = if let Some(id) = r#override.id {
368 Cow::Owned(id.to_string())
369 } else if let Some(ref name) = r#override.name {
370 Cow::Borrowed(name)
371 } else {
372 unreachable!();
373 };
374
375 let init = if let Some(value) = pipeline_constants.get::<str>(&key) {
379 let literal = match module.types[r#override.ty].inner {
380 TypeInner::Scalar(scalar) => map_value_to_literal(*value, scalar)?,
381 _ => unreachable!(),
382 };
383 let expr = module
384 .global_expressions
385 .append(Expression::Literal(literal), Span::UNDEFINED);
386 global_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Const);
387 expr
388 } else if let Some(init) = r#override.init {
389 adjusted_global_expressions[init]
390 } else {
391 return Err(PipelineConstantError::MissingValue(key.to_string()));
392 };
393
394 let constant = Constant {
396 name: r#override.name.clone(),
397 ty: r#override.ty,
398 init,
399 };
400 let h = module.constants.append(constant, *span);
401 override_map.insert(old_h, h);
402 adjusted_constant_initializers.insert(h);
403 r#override.init = Some(init);
404 Ok(h)
405}
406
407fn process_function(
417 module: &mut Module,
418 override_map: &HandleVec<Override, Handle<Constant>>,
419 layouter: &mut crate::proc::Layouter,
420 function: &mut Function,
421) -> Result<(), ConstantEvaluatorError> {
422 let mut adjusted_local_expressions = HandleVec::with_capacity(function.expressions.len());
425
426 let mut local_expression_kind_tracker = crate::proc::ExpressionKindTracker::new();
427
428 let mut expressions = function.expressions.take();
429
430 let mut emitter = Emitter::default();
438 let mut block = Block::new();
439
440 let mut evaluator = ConstantEvaluator::for_wgsl_function(
441 module,
442 &mut function.expressions,
443 &mut local_expression_kind_tracker,
444 layouter,
445 &mut emitter,
446 &mut block,
447 false,
448 );
449
450 for (old_h, mut expr, span) in expressions.drain() {
451 if let Expression::Override(h) = expr {
452 expr = Expression::Constant(override_map[h]);
453 }
454 adjust_expr(&adjusted_local_expressions, &mut expr);
455 let h = evaluator.try_eval_and_append(expr, span)?;
456 adjusted_local_expressions.insert(old_h, h);
457 }
458
459 adjust_block(&adjusted_local_expressions, &mut function.body);
460
461 filter_emits_in_block(&mut function.body, &function.expressions);
462
463 for (_, local) in function.local_variables.iter_mut() {
465 if let &mut Some(ref mut init) = &mut local.init {
466 *init = adjusted_local_expressions[*init];
467 }
468 }
469
470 let named_expressions = mem::take(&mut function.named_expressions);
473 for (expr_h, name) in named_expressions {
474 function
475 .named_expressions
476 .insert(adjusted_local_expressions[expr_h], name);
477 }
478
479 Ok(())
480}
481
482fn adjust_expr(new_pos: &HandleVec<Expression, Handle<Expression>>, expr: &mut Expression) {
485 let adjust = |expr: &mut Handle<Expression>| {
486 *expr = new_pos[*expr];
487 };
488 match *expr {
489 Expression::Compose {
490 ref mut components,
491 ty: _,
492 } => {
493 for c in components.iter_mut() {
494 adjust(c);
495 }
496 }
497 Expression::Access {
498 ref mut base,
499 ref mut index,
500 } => {
501 adjust(base);
502 adjust(index);
503 }
504 Expression::AccessIndex {
505 ref mut base,
506 index: _,
507 } => {
508 adjust(base);
509 }
510 Expression::Splat {
511 ref mut value,
512 size: _,
513 } => {
514 adjust(value);
515 }
516 Expression::Swizzle {
517 ref mut vector,
518 size: _,
519 pattern: _,
520 } => {
521 adjust(vector);
522 }
523 Expression::Load { ref mut pointer } => {
524 adjust(pointer);
525 }
526 Expression::ImageSample {
527 ref mut image,
528 ref mut sampler,
529 ref mut coordinate,
530 ref mut array_index,
531 ref mut offset,
532 ref mut level,
533 ref mut depth_ref,
534 gather: _,
535 clamp_to_edge: _,
536 } => {
537 adjust(image);
538 adjust(sampler);
539 adjust(coordinate);
540 if let Some(e) = array_index.as_mut() {
541 adjust(e);
542 }
543 if let Some(e) = offset.as_mut() {
544 adjust(e);
545 }
546 match *level {
547 crate::SampleLevel::Exact(ref mut expr)
548 | crate::SampleLevel::Bias(ref mut expr) => {
549 adjust(expr);
550 }
551 crate::SampleLevel::Gradient {
552 ref mut x,
553 ref mut y,
554 } => {
555 adjust(x);
556 adjust(y);
557 }
558 _ => {}
559 }
560 if let Some(e) = depth_ref.as_mut() {
561 adjust(e);
562 }
563 }
564 Expression::ImageLoad {
565 ref mut image,
566 ref mut coordinate,
567 ref mut array_index,
568 ref mut sample,
569 ref mut level,
570 } => {
571 adjust(image);
572 adjust(coordinate);
573 if let Some(e) = array_index.as_mut() {
574 adjust(e);
575 }
576 if let Some(e) = sample.as_mut() {
577 adjust(e);
578 }
579 if let Some(e) = level.as_mut() {
580 adjust(e);
581 }
582 }
583 Expression::ImageQuery {
584 ref mut image,
585 ref mut query,
586 } => {
587 adjust(image);
588 match *query {
589 crate::ImageQuery::Size { ref mut level } => {
590 if let Some(e) = level.as_mut() {
591 adjust(e);
592 }
593 }
594 crate::ImageQuery::NumLevels
595 | crate::ImageQuery::NumLayers
596 | crate::ImageQuery::NumSamples => {}
597 }
598 }
599 Expression::Unary {
600 ref mut expr,
601 op: _,
602 } => {
603 adjust(expr);
604 }
605 Expression::Binary {
606 ref mut left,
607 ref mut right,
608 op: _,
609 } => {
610 adjust(left);
611 adjust(right);
612 }
613 Expression::Select {
614 ref mut condition,
615 ref mut accept,
616 ref mut reject,
617 } => {
618 adjust(condition);
619 adjust(accept);
620 adjust(reject);
621 }
622 Expression::Derivative {
623 ref mut expr,
624 axis: _,
625 ctrl: _,
626 } => {
627 adjust(expr);
628 }
629 Expression::Relational {
630 ref mut argument,
631 fun: _,
632 } => {
633 adjust(argument);
634 }
635 Expression::Math {
636 ref mut arg,
637 ref mut arg1,
638 ref mut arg2,
639 ref mut arg3,
640 fun: _,
641 } => {
642 adjust(arg);
643 if let Some(e) = arg1.as_mut() {
644 adjust(e);
645 }
646 if let Some(e) = arg2.as_mut() {
647 adjust(e);
648 }
649 if let Some(e) = arg3.as_mut() {
650 adjust(e);
651 }
652 }
653 Expression::As {
654 ref mut expr,
655 kind: _,
656 convert: _,
657 } => {
658 adjust(expr);
659 }
660 Expression::ArrayLength(ref mut expr) => {
661 adjust(expr);
662 }
663 Expression::RayQueryGetIntersection {
664 ref mut query,
665 committed: _,
666 } => {
667 adjust(query);
668 }
669 Expression::Literal(_)
670 | Expression::FunctionArgument(_)
671 | Expression::GlobalVariable(_)
672 | Expression::LocalVariable(_)
673 | Expression::CallResult(_)
674 | Expression::RayQueryProceedResult
675 | Expression::Constant(_)
676 | Expression::Override(_)
677 | Expression::ZeroValue(_)
678 | Expression::AtomicResult {
679 ty: _,
680 comparison: _,
681 }
682 | Expression::WorkGroupUniformLoadResult { ty: _ }
683 | Expression::SubgroupBallotResult
684 | Expression::SubgroupOperationResult { .. } => {}
685 Expression::RayQueryVertexPositions {
686 ref mut query,
687 committed: _,
688 } => {
689 adjust(query);
690 }
691 Expression::CooperativeLoad { ref mut data, .. } => {
692 adjust(&mut data.pointer);
693 adjust(&mut data.stride);
694 }
695 Expression::CooperativeMultiplyAdd {
696 ref mut a,
697 ref mut b,
698 ref mut c,
699 } => {
700 adjust(a);
701 adjust(b);
702 adjust(c);
703 }
704 }
705}
706
707fn adjust_block(new_pos: &HandleVec<Expression, Handle<Expression>>, block: &mut Block) {
710 for stmt in block.iter_mut() {
711 adjust_stmt(new_pos, stmt);
712 }
713}
714
715fn adjust_stmt(new_pos: &HandleVec<Expression, Handle<Expression>>, stmt: &mut Statement) {
718 let adjust = |expr: &mut Handle<Expression>| {
719 *expr = new_pos[*expr];
720 };
721 match *stmt {
722 Statement::Emit(ref mut range) => {
723 if let Some((mut first, mut last)) = range.first_and_last() {
724 adjust(&mut first);
725 adjust(&mut last);
726 *range = Range::new_from_bounds(first, last);
727 }
728 }
729 Statement::Block(ref mut block) => {
730 adjust_block(new_pos, block);
731 }
732 Statement::If {
733 ref mut condition,
734 ref mut accept,
735 ref mut reject,
736 } => {
737 adjust(condition);
738 adjust_block(new_pos, accept);
739 adjust_block(new_pos, reject);
740 }
741 Statement::Switch {
742 ref mut selector,
743 ref mut cases,
744 } => {
745 adjust(selector);
746 for case in cases.iter_mut() {
747 adjust_block(new_pos, &mut case.body);
748 }
749 }
750 Statement::Loop {
751 ref mut body,
752 ref mut continuing,
753 ref mut break_if,
754 } => {
755 adjust_block(new_pos, body);
756 adjust_block(new_pos, continuing);
757 if let Some(e) = break_if.as_mut() {
758 adjust(e);
759 }
760 }
761 Statement::Return { ref mut value } => {
762 if let Some(e) = value.as_mut() {
763 adjust(e);
764 }
765 }
766 Statement::Store {
767 ref mut pointer,
768 ref mut value,
769 } => {
770 adjust(pointer);
771 adjust(value);
772 }
773 Statement::ImageStore {
774 ref mut image,
775 ref mut coordinate,
776 ref mut array_index,
777 ref mut value,
778 } => {
779 adjust(image);
780 adjust(coordinate);
781 if let Some(e) = array_index.as_mut() {
782 adjust(e);
783 }
784 adjust(value);
785 }
786 Statement::Atomic {
787 ref mut pointer,
788 ref mut value,
789 ref mut result,
790 ref mut fun,
791 } => {
792 adjust(pointer);
793 adjust(value);
794 if let Some(ref mut result) = *result {
795 adjust(result);
796 }
797 match *fun {
798 crate::AtomicFunction::Exchange {
799 compare: Some(ref mut compare),
800 } => {
801 adjust(compare);
802 }
803 crate::AtomicFunction::Add
804 | crate::AtomicFunction::Subtract
805 | crate::AtomicFunction::And
806 | crate::AtomicFunction::ExclusiveOr
807 | crate::AtomicFunction::InclusiveOr
808 | crate::AtomicFunction::Min
809 | crate::AtomicFunction::Max
810 | crate::AtomicFunction::Exchange { compare: None } => {}
811 }
812 }
813 Statement::ImageAtomic {
814 ref mut image,
815 ref mut coordinate,
816 ref mut array_index,
817 fun: _,
818 ref mut value,
819 } => {
820 adjust(image);
821 adjust(coordinate);
822 if let Some(ref mut array_index) = *array_index {
823 adjust(array_index);
824 }
825 adjust(value);
826 }
827 Statement::WorkGroupUniformLoad {
828 ref mut pointer,
829 ref mut result,
830 } => {
831 adjust(pointer);
832 adjust(result);
833 }
834 Statement::SubgroupBallot {
835 ref mut result,
836 ref mut predicate,
837 } => {
838 if let Some(ref mut predicate) = *predicate {
839 adjust(predicate);
840 }
841 adjust(result);
842 }
843 Statement::SubgroupCollectiveOperation {
844 ref mut argument,
845 ref mut result,
846 ..
847 } => {
848 adjust(argument);
849 adjust(result);
850 }
851 Statement::SubgroupGather {
852 ref mut mode,
853 ref mut argument,
854 ref mut result,
855 } => {
856 match *mode {
857 crate::GatherMode::BroadcastFirst => {}
858 crate::GatherMode::Broadcast(ref mut index)
859 | crate::GatherMode::Shuffle(ref mut index)
860 | crate::GatherMode::ShuffleDown(ref mut index)
861 | crate::GatherMode::ShuffleUp(ref mut index)
862 | crate::GatherMode::ShuffleXor(ref mut index)
863 | crate::GatherMode::QuadBroadcast(ref mut index) => {
864 adjust(index);
865 }
866 crate::GatherMode::QuadSwap(_) => {}
867 }
868 adjust(argument);
869 adjust(result)
870 }
871 Statement::Call {
872 ref mut arguments,
873 ref mut result,
874 function: _,
875 } => {
876 for argument in arguments.iter_mut() {
877 adjust(argument);
878 }
879 if let Some(e) = result.as_mut() {
880 adjust(e);
881 }
882 }
883 Statement::RayQuery {
884 ref mut query,
885 ref mut fun,
886 } => {
887 adjust(query);
888 match *fun {
889 crate::RayQueryFunction::Initialize {
890 ref mut acceleration_structure,
891 ref mut descriptor,
892 } => {
893 adjust(acceleration_structure);
894 adjust(descriptor);
895 }
896 crate::RayQueryFunction::Proceed { ref mut result } => {
897 adjust(result);
898 }
899 crate::RayQueryFunction::GenerateIntersection { ref mut hit_t } => {
900 adjust(hit_t);
901 }
902 crate::RayQueryFunction::ConfirmIntersection => {}
903 crate::RayQueryFunction::Terminate => {}
904 }
905 }
906 Statement::CooperativeStore {
907 ref mut target,
908 ref mut data,
909 } => {
910 adjust(target);
911 adjust(&mut data.pointer);
912 adjust(&mut data.stride);
913 }
914 Statement::RayPipelineFunction(ref mut func) => match *func {
915 crate::RayPipelineFunction::TraceRay {
916 ref mut acceleration_structure,
917 ref mut descriptor,
918 ref mut payload,
919 } => {
920 adjust(acceleration_structure);
921 adjust(descriptor);
922 adjust(payload);
923 }
924 },
925 Statement::Break
926 | Statement::Continue
927 | Statement::Kill
928 | Statement::ControlBarrier(_)
929 | Statement::MemoryBarrier(_) => {}
930 }
931}
932
933fn filter_emits_in_block(block: &mut Block, expressions: &Arena<Expression>) {
950 let original = mem::replace(block, Block::with_capacity(block.len()));
951 for (stmt, span) in original.span_into_iter() {
952 match stmt {
953 Statement::Emit(range) => {
954 let mut current = None;
955 for expr_h in range {
956 if expressions[expr_h].needs_pre_emit() {
957 if let Some((first, last)) = current {
958 block.push(Statement::Emit(Range::new_from_bounds(first, last)), span);
959 }
960
961 current = None;
962 } else if let Some((_, ref mut last)) = current {
963 *last = expr_h;
964 } else {
965 current = Some((expr_h, expr_h));
966 }
967 }
968 if let Some((first, last)) = current {
969 block.push(Statement::Emit(Range::new_from_bounds(first, last)), span);
970 }
971 }
972 Statement::Block(mut child) => {
973 filter_emits_in_block(&mut child, expressions);
974 block.push(Statement::Block(child), span);
975 }
976 Statement::If {
977 condition,
978 mut accept,
979 mut reject,
980 } => {
981 filter_emits_in_block(&mut accept, expressions);
982 filter_emits_in_block(&mut reject, expressions);
983 block.push(
984 Statement::If {
985 condition,
986 accept,
987 reject,
988 },
989 span,
990 );
991 }
992 Statement::Switch {
993 selector,
994 mut cases,
995 } => {
996 for case in &mut cases {
997 filter_emits_in_block(&mut case.body, expressions);
998 }
999 block.push(Statement::Switch { selector, cases }, span);
1000 }
1001 Statement::Loop {
1002 mut body,
1003 mut continuing,
1004 break_if,
1005 } => {
1006 filter_emits_in_block(&mut body, expressions);
1007 filter_emits_in_block(&mut continuing, expressions);
1008 block.push(
1009 Statement::Loop {
1010 body,
1011 continuing,
1012 break_if,
1013 },
1014 span,
1015 );
1016 }
1017 stmt => block.push(stmt.clone(), span),
1018 }
1019 }
1020}
1021
1022fn map_value_to_literal(value: f64, scalar: Scalar) -> Result<Literal, PipelineConstantError> {
1023 match scalar {
1025 Scalar::BOOL => {
1026 let value = value != 0.0 && !value.is_nan();
1028 Ok(Literal::Bool(value))
1029 }
1030 Scalar::I16 => {
1031 if !value.is_finite() {
1032 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1033 }
1034
1035 let value = value.trunc();
1036 if value < f64::from(i16::MIN) || value > f64::from(i16::MAX) {
1037 return Err(PipelineConstantError::DstRangeTooSmall);
1038 }
1039
1040 let value = value as i16;
1041 Ok(Literal::I16(value))
1042 }
1043 Scalar::U16 => {
1044 if !value.is_finite() {
1045 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1046 }
1047
1048 let value = value.trunc();
1049 if value < f64::from(u16::MIN) || value > f64::from(u16::MAX) {
1050 return Err(PipelineConstantError::DstRangeTooSmall);
1051 }
1052
1053 let value = value as u16;
1054 Ok(Literal::U16(value))
1055 }
1056 Scalar::I32 => {
1057 if !value.is_finite() {
1059 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1060 }
1061
1062 let value = value.trunc();
1063 if value < f64::from(i32::MIN) || value > f64::from(i32::MAX) {
1064 return Err(PipelineConstantError::DstRangeTooSmall);
1065 }
1066
1067 let value = value as i32;
1068 Ok(Literal::I32(value))
1069 }
1070 Scalar::U32 => {
1071 if !value.is_finite() {
1073 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1074 }
1075
1076 let value = value.trunc();
1077 if value < f64::from(u32::MIN) || value > f64::from(u32::MAX) {
1078 return Err(PipelineConstantError::DstRangeTooSmall);
1079 }
1080
1081 let value = value as u32;
1082 Ok(Literal::U32(value))
1083 }
1084 Scalar::F16 => {
1085 if !value.is_finite() {
1087 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1088 }
1089
1090 let value = half::f16::from_f64(value);
1091 if !value.is_finite() {
1092 return Err(PipelineConstantError::DstRangeTooSmall);
1093 }
1094
1095 Ok(Literal::F16(value))
1096 }
1097 Scalar::F32 => {
1098 if !value.is_finite() {
1100 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1101 }
1102
1103 let value = value as f32;
1104 if !value.is_finite() {
1105 return Err(PipelineConstantError::DstRangeTooSmall);
1106 }
1107
1108 Ok(Literal::F32(value))
1109 }
1110 Scalar::F64 => {
1111 if !value.is_finite() {
1113 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1114 }
1115
1116 Ok(Literal::F64(value))
1117 }
1118 Scalar::ABSTRACT_FLOAT | Scalar::ABSTRACT_INT => {
1119 unreachable!("abstract values should not be validated out of override processing")
1120 }
1121 _ => unreachable!("unrecognized scalar type for override"),
1122 }
1123}
1124
1125#[test]
1126fn test_map_value_to_literal() {
1127 let bool_test_cases = [
1128 (0.0, false),
1129 (-0.0, false),
1130 (f64::NAN, false),
1131 (1.0, true),
1132 (f64::INFINITY, true),
1133 (f64::NEG_INFINITY, true),
1134 ];
1135 for (value, out) in bool_test_cases {
1136 let res = Ok(Literal::Bool(out));
1137 assert_eq!(map_value_to_literal(value, Scalar::BOOL), res);
1138 }
1139
1140 for scalar in [Scalar::I32, Scalar::U32, Scalar::F32, Scalar::F64] {
1141 for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
1142 let res = Err(PipelineConstantError::SrcNeedsToBeFinite);
1143 assert_eq!(map_value_to_literal(value, scalar), res);
1144 }
1145 }
1146
1147 assert_eq!(
1149 map_value_to_literal(f64::from(i32::MIN), Scalar::I32),
1150 Ok(Literal::I32(i32::MIN))
1151 );
1152 assert_eq!(
1153 map_value_to_literal(f64::from(i32::MAX), Scalar::I32),
1154 Ok(Literal::I32(i32::MAX))
1155 );
1156 assert_eq!(
1157 map_value_to_literal(f64::from(i32::MIN) - 1.0, Scalar::I32),
1158 Err(PipelineConstantError::DstRangeTooSmall)
1159 );
1160 assert_eq!(
1161 map_value_to_literal(f64::from(i32::MAX) + 1.0, Scalar::I32),
1162 Err(PipelineConstantError::DstRangeTooSmall)
1163 );
1164
1165 assert_eq!(
1167 map_value_to_literal(f64::from(u32::MIN), Scalar::U32),
1168 Ok(Literal::U32(u32::MIN))
1169 );
1170 assert_eq!(
1171 map_value_to_literal(f64::from(u32::MAX), Scalar::U32),
1172 Ok(Literal::U32(u32::MAX))
1173 );
1174 assert_eq!(
1175 map_value_to_literal(f64::from(u32::MIN) - 1.0, Scalar::U32),
1176 Err(PipelineConstantError::DstRangeTooSmall)
1177 );
1178 assert_eq!(
1179 map_value_to_literal(f64::from(u32::MAX) + 1.0, Scalar::U32),
1180 Err(PipelineConstantError::DstRangeTooSmall)
1181 );
1182
1183 assert_eq!(
1185 map_value_to_literal(f64::from(f32::MIN), Scalar::F32),
1186 Ok(Literal::F32(f32::MIN))
1187 );
1188 assert_eq!(
1189 map_value_to_literal(f64::from(f32::MAX), Scalar::F32),
1190 Ok(Literal::F32(f32::MAX))
1191 );
1192 assert_eq!(
1193 map_value_to_literal(-f64::from_bits(0x47efffffefffffff), Scalar::F32),
1194 Ok(Literal::F32(f32::MIN))
1195 );
1196 assert_eq!(
1197 map_value_to_literal(f64::from_bits(0x47efffffefffffff), Scalar::F32),
1198 Ok(Literal::F32(f32::MAX))
1199 );
1200 assert_eq!(
1201 map_value_to_literal(-f64::from_bits(0x47effffff0000000), Scalar::F32),
1202 Err(PipelineConstantError::DstRangeTooSmall)
1203 );
1204 assert_eq!(
1205 map_value_to_literal(f64::from_bits(0x47effffff0000000), Scalar::F32),
1206 Err(PipelineConstantError::DstRangeTooSmall)
1207 );
1208
1209 assert_eq!(
1211 map_value_to_literal(f64::MIN, Scalar::F64),
1212 Ok(Literal::F64(f64::MIN))
1213 );
1214 assert_eq!(
1215 map_value_to_literal(f64::MAX, Scalar::F64),
1216 Ok(Literal::F64(f64::MAX))
1217 );
1218}