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