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 target: _,
660 } => {
661 adjust(expr);
662 }
663 Expression::Bitcast {
664 ref mut expr,
665 ty: _,
666 } => {
667 adjust(expr);
668 }
669 Expression::ArrayLength(ref mut expr) => {
670 adjust(expr);
671 }
672 Expression::RayQueryGetIntersection {
673 ref mut query,
674 committed: _,
675 } => {
676 adjust(query);
677 }
678 Expression::Literal(_)
679 | Expression::FunctionArgument(_)
680 | Expression::GlobalVariable(_)
681 | Expression::LocalVariable(_)
682 | Expression::CallResult(_)
683 | Expression::RayQueryProceedResult
684 | Expression::Constant(_)
685 | Expression::Override(_)
686 | Expression::ZeroValue(_)
687 | Expression::AtomicResult {
688 ty: _,
689 comparison: _,
690 }
691 | Expression::WorkGroupUniformLoadResult { ty: _ }
692 | Expression::SubgroupBallotResult
693 | Expression::SubgroupOperationResult { .. } => {}
694 Expression::RayQueryVertexPositions {
695 ref mut query,
696 committed: _,
697 } => {
698 adjust(query);
699 }
700 Expression::CooperativeLoad { ref mut data, .. } => {
701 adjust(&mut data.pointer);
702 adjust(&mut data.stride);
703 }
704 Expression::CooperativeMultiplyAdd {
705 ref mut a,
706 ref mut b,
707 ref mut c,
708 } => {
709 adjust(a);
710 adjust(b);
711 adjust(c);
712 }
713 }
714}
715
716fn adjust_block(new_pos: &HandleVec<Expression, Handle<Expression>>, block: &mut Block) {
719 for stmt in block.iter_mut() {
720 adjust_stmt(new_pos, stmt);
721 }
722}
723
724fn adjust_stmt(new_pos: &HandleVec<Expression, Handle<Expression>>, stmt: &mut Statement) {
727 let adjust = |expr: &mut Handle<Expression>| {
728 *expr = new_pos[*expr];
729 };
730 match *stmt {
731 Statement::Emit(ref mut range) => {
732 if let Some((mut first, mut last)) = range.first_and_last() {
733 adjust(&mut first);
734 adjust(&mut last);
735 *range = Range::new_from_bounds(first, last);
736 }
737 }
738 Statement::Block(ref mut block) => {
739 adjust_block(new_pos, block);
740 }
741 Statement::If {
742 ref mut condition,
743 ref mut accept,
744 ref mut reject,
745 } => {
746 adjust(condition);
747 adjust_block(new_pos, accept);
748 adjust_block(new_pos, reject);
749 }
750 Statement::Switch {
751 ref mut selector,
752 ref mut cases,
753 } => {
754 adjust(selector);
755 for case in cases.iter_mut() {
756 adjust_block(new_pos, &mut case.body);
757 }
758 }
759 Statement::Loop {
760 ref mut body,
761 ref mut continuing,
762 ref mut break_if,
763 } => {
764 adjust_block(new_pos, body);
765 adjust_block(new_pos, continuing);
766 if let Some(e) = break_if.as_mut() {
767 adjust(e);
768 }
769 }
770 Statement::Return { ref mut value } => {
771 if let Some(e) = value.as_mut() {
772 adjust(e);
773 }
774 }
775 Statement::Store {
776 ref mut pointer,
777 ref mut value,
778 } => {
779 adjust(pointer);
780 adjust(value);
781 }
782 Statement::ImageStore {
783 ref mut image,
784 ref mut coordinate,
785 ref mut array_index,
786 ref mut value,
787 } => {
788 adjust(image);
789 adjust(coordinate);
790 if let Some(e) = array_index.as_mut() {
791 adjust(e);
792 }
793 adjust(value);
794 }
795 Statement::Atomic {
796 ref mut pointer,
797 ref mut value,
798 ref mut result,
799 ref mut fun,
800 } => {
801 adjust(pointer);
802 adjust(value);
803 if let Some(ref mut result) = *result {
804 adjust(result);
805 }
806 match *fun {
807 crate::AtomicFunction::Exchange {
808 compare: Some(ref mut compare),
809 } => {
810 adjust(compare);
811 }
812 crate::AtomicFunction::Add
813 | crate::AtomicFunction::Subtract
814 | crate::AtomicFunction::And
815 | crate::AtomicFunction::ExclusiveOr
816 | crate::AtomicFunction::InclusiveOr
817 | crate::AtomicFunction::Min
818 | crate::AtomicFunction::Max
819 | crate::AtomicFunction::Exchange { compare: None } => {}
820 }
821 }
822 Statement::ImageAtomic {
823 ref mut image,
824 ref mut coordinate,
825 ref mut array_index,
826 fun: _,
827 ref mut value,
828 } => {
829 adjust(image);
830 adjust(coordinate);
831 if let Some(ref mut array_index) = *array_index {
832 adjust(array_index);
833 }
834 adjust(value);
835 }
836 Statement::WorkGroupUniformLoad {
837 ref mut pointer,
838 ref mut result,
839 } => {
840 adjust(pointer);
841 adjust(result);
842 }
843 Statement::SubgroupBallot {
844 ref mut result,
845 ref mut predicate,
846 } => {
847 if let Some(ref mut predicate) = *predicate {
848 adjust(predicate);
849 }
850 adjust(result);
851 }
852 Statement::SubgroupCollectiveOperation {
853 ref mut argument,
854 ref mut result,
855 ..
856 } => {
857 adjust(argument);
858 adjust(result);
859 }
860 Statement::SubgroupGather {
861 ref mut mode,
862 ref mut argument,
863 ref mut result,
864 } => {
865 match *mode {
866 crate::GatherMode::BroadcastFirst => {}
867 crate::GatherMode::Broadcast(ref mut index)
868 | crate::GatherMode::Shuffle(ref mut index)
869 | crate::GatherMode::ShuffleDown(ref mut index)
870 | crate::GatherMode::ShuffleUp(ref mut index)
871 | crate::GatherMode::ShuffleXor(ref mut index)
872 | crate::GatherMode::QuadBroadcast(ref mut index) => {
873 adjust(index);
874 }
875 crate::GatherMode::QuadSwap(_) => {}
876 }
877 adjust(argument);
878 adjust(result)
879 }
880 Statement::Call {
881 ref mut arguments,
882 ref mut result,
883 function: _,
884 } => {
885 for argument in arguments.iter_mut() {
886 adjust(argument);
887 }
888 if let Some(e) = result.as_mut() {
889 adjust(e);
890 }
891 }
892 Statement::RayQuery {
893 ref mut query,
894 ref mut fun,
895 } => {
896 adjust(query);
897 match *fun {
898 crate::RayQueryFunction::Initialize {
899 ref mut acceleration_structure,
900 ref mut descriptor,
901 } => {
902 adjust(acceleration_structure);
903 adjust(descriptor);
904 }
905 crate::RayQueryFunction::Proceed { ref mut result } => {
906 adjust(result);
907 }
908 crate::RayQueryFunction::GenerateIntersection { ref mut hit_t } => {
909 adjust(hit_t);
910 }
911 crate::RayQueryFunction::ConfirmIntersection => {}
912 crate::RayQueryFunction::Terminate => {}
913 crate::RayQueryFunction::Begin => {}
914 }
915 }
916 Statement::CooperativeStore {
917 ref mut target,
918 ref mut data,
919 } => {
920 adjust(target);
921 adjust(&mut data.pointer);
922 adjust(&mut data.stride);
923 }
924 Statement::RayPipelineFunction(ref mut func) => match *func {
925 crate::RayPipelineFunction::TraceRay {
926 ref mut acceleration_structure,
927 ref mut descriptor,
928 ref mut payload,
929 } => {
930 adjust(acceleration_structure);
931 adjust(descriptor);
932 adjust(payload);
933 }
934 },
935 Statement::DebugPrintf {
936 format: _,
937 ref mut arguments,
938 } => {
939 for argument in arguments.iter_mut() {
940 adjust(argument);
941 }
942 }
943 Statement::Break
944 | Statement::Continue
945 | Statement::Kill
946 | Statement::ControlBarrier(_)
947 | Statement::MemoryBarrier(_) => {}
948 }
949}
950
951fn filter_emits_in_block(block: &mut Block, expressions: &Arena<Expression>) {
968 let original = mem::replace(block, Block::with_capacity(block.len()));
969 for (stmt, span) in original.span_into_iter() {
970 match stmt {
971 Statement::Emit(range) => {
972 let mut current = None;
973 for expr_h in range {
974 if expressions[expr_h].needs_pre_emit() {
975 if let Some((first, last)) = current {
976 block.push(Statement::Emit(Range::new_from_bounds(first, last)), span);
977 }
978
979 current = None;
980 } else if let Some((_, ref mut last)) = current {
981 *last = expr_h;
982 } else {
983 current = Some((expr_h, expr_h));
984 }
985 }
986 if let Some((first, last)) = current {
987 block.push(Statement::Emit(Range::new_from_bounds(first, last)), span);
988 }
989 }
990 Statement::Block(mut child) => {
991 filter_emits_in_block(&mut child, expressions);
992 block.push(Statement::Block(child), span);
993 }
994 Statement::If {
995 condition,
996 mut accept,
997 mut reject,
998 } => {
999 filter_emits_in_block(&mut accept, expressions);
1000 filter_emits_in_block(&mut reject, expressions);
1001 block.push(
1002 Statement::If {
1003 condition,
1004 accept,
1005 reject,
1006 },
1007 span,
1008 );
1009 }
1010 Statement::Switch {
1011 selector,
1012 mut cases,
1013 } => {
1014 for case in &mut cases {
1015 filter_emits_in_block(&mut case.body, expressions);
1016 }
1017 block.push(Statement::Switch { selector, cases }, span);
1018 }
1019 Statement::Loop {
1020 mut body,
1021 mut continuing,
1022 break_if,
1023 } => {
1024 filter_emits_in_block(&mut body, expressions);
1025 filter_emits_in_block(&mut continuing, expressions);
1026 block.push(
1027 Statement::Loop {
1028 body,
1029 continuing,
1030 break_if,
1031 },
1032 span,
1033 );
1034 }
1035 stmt => block.push(stmt.clone(), span),
1036 }
1037 }
1038}
1039
1040fn map_value_to_literal(value: f64, scalar: Scalar) -> Result<Literal, PipelineConstantError> {
1041 match scalar {
1043 Scalar::BOOL => {
1044 let value = value != 0.0 && !value.is_nan();
1046 Ok(Literal::Bool(value))
1047 }
1048 Scalar::I16 => {
1049 if !value.is_finite() {
1050 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1051 }
1052
1053 let value = value.trunc();
1054 if value < f64::from(i16::MIN) || value > f64::from(i16::MAX) {
1055 return Err(PipelineConstantError::DstRangeTooSmall);
1056 }
1057
1058 let value = value as i16;
1059 Ok(Literal::I16(value))
1060 }
1061 Scalar::U16 => {
1062 if !value.is_finite() {
1063 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1064 }
1065
1066 let value = value.trunc();
1067 if value < f64::from(u16::MIN) || value > f64::from(u16::MAX) {
1068 return Err(PipelineConstantError::DstRangeTooSmall);
1069 }
1070
1071 let value = value as u16;
1072 Ok(Literal::U16(value))
1073 }
1074 Scalar::I32 => {
1075 if !value.is_finite() {
1077 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1078 }
1079
1080 let value = value.trunc();
1081 if value < f64::from(i32::MIN) || value > f64::from(i32::MAX) {
1082 return Err(PipelineConstantError::DstRangeTooSmall);
1083 }
1084
1085 let value = value as i32;
1086 Ok(Literal::I32(value))
1087 }
1088 Scalar::U32 => {
1089 if !value.is_finite() {
1091 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1092 }
1093
1094 let value = value.trunc();
1095 if value < f64::from(u32::MIN) || value > f64::from(u32::MAX) {
1096 return Err(PipelineConstantError::DstRangeTooSmall);
1097 }
1098
1099 let value = value as u32;
1100 Ok(Literal::U32(value))
1101 }
1102 Scalar::F16 => {
1103 if !value.is_finite() {
1105 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1106 }
1107
1108 let value = half::f16::from_f64(value);
1109 if !value.is_finite() {
1110 return Err(PipelineConstantError::DstRangeTooSmall);
1111 }
1112
1113 Ok(Literal::F16(value))
1114 }
1115 Scalar::F32 => {
1116 if !value.is_finite() {
1118 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1119 }
1120
1121 let value = value as f32;
1122 if !value.is_finite() {
1123 return Err(PipelineConstantError::DstRangeTooSmall);
1124 }
1125
1126 Ok(Literal::F32(value))
1127 }
1128 Scalar::F64 => {
1129 if !value.is_finite() {
1131 return Err(PipelineConstantError::SrcNeedsToBeFinite);
1132 }
1133
1134 Ok(Literal::F64(value))
1135 }
1136 Scalar::ABSTRACT_FLOAT | Scalar::ABSTRACT_INT => {
1137 unreachable!("abstract values should not be validated out of override processing")
1138 }
1139 _ => unreachable!("unrecognized scalar type for override"),
1140 }
1141}
1142
1143#[test]
1144fn test_map_value_to_literal() {
1145 let bool_test_cases = [
1146 (0.0, false),
1147 (-0.0, false),
1148 (f64::NAN, false),
1149 (1.0, true),
1150 (f64::INFINITY, true),
1151 (f64::NEG_INFINITY, true),
1152 ];
1153 for (value, out) in bool_test_cases {
1154 let res = Ok(Literal::Bool(out));
1155 assert_eq!(map_value_to_literal(value, Scalar::BOOL), res);
1156 }
1157
1158 for scalar in [Scalar::I32, Scalar::U32, Scalar::F32, Scalar::F64] {
1159 for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
1160 let res = Err(PipelineConstantError::SrcNeedsToBeFinite);
1161 assert_eq!(map_value_to_literal(value, scalar), res);
1162 }
1163 }
1164
1165 assert_eq!(
1167 map_value_to_literal(f64::from(i32::MIN), Scalar::I32),
1168 Ok(Literal::I32(i32::MIN))
1169 );
1170 assert_eq!(
1171 map_value_to_literal(f64::from(i32::MAX), Scalar::I32),
1172 Ok(Literal::I32(i32::MAX))
1173 );
1174 assert_eq!(
1175 map_value_to_literal(f64::from(i32::MIN) - 1.0, Scalar::I32),
1176 Err(PipelineConstantError::DstRangeTooSmall)
1177 );
1178 assert_eq!(
1179 map_value_to_literal(f64::from(i32::MAX) + 1.0, Scalar::I32),
1180 Err(PipelineConstantError::DstRangeTooSmall)
1181 );
1182
1183 assert_eq!(
1185 map_value_to_literal(f64::from(u32::MIN), Scalar::U32),
1186 Ok(Literal::U32(u32::MIN))
1187 );
1188 assert_eq!(
1189 map_value_to_literal(f64::from(u32::MAX), Scalar::U32),
1190 Ok(Literal::U32(u32::MAX))
1191 );
1192 assert_eq!(
1193 map_value_to_literal(f64::from(u32::MIN) - 1.0, Scalar::U32),
1194 Err(PipelineConstantError::DstRangeTooSmall)
1195 );
1196 assert_eq!(
1197 map_value_to_literal(f64::from(u32::MAX) + 1.0, Scalar::U32),
1198 Err(PipelineConstantError::DstRangeTooSmall)
1199 );
1200
1201 assert_eq!(
1203 map_value_to_literal(f64::from(f32::MIN), Scalar::F32),
1204 Ok(Literal::F32(f32::MIN))
1205 );
1206 assert_eq!(
1207 map_value_to_literal(f64::from(f32::MAX), Scalar::F32),
1208 Ok(Literal::F32(f32::MAX))
1209 );
1210 assert_eq!(
1211 map_value_to_literal(-f64::from_bits(0x47efffffefffffff), Scalar::F32),
1212 Ok(Literal::F32(f32::MIN))
1213 );
1214 assert_eq!(
1215 map_value_to_literal(f64::from_bits(0x47efffffefffffff), Scalar::F32),
1216 Ok(Literal::F32(f32::MAX))
1217 );
1218 assert_eq!(
1219 map_value_to_literal(-f64::from_bits(0x47effffff0000000), Scalar::F32),
1220 Err(PipelineConstantError::DstRangeTooSmall)
1221 );
1222 assert_eq!(
1223 map_value_to_literal(f64::from_bits(0x47effffff0000000), Scalar::F32),
1224 Err(PipelineConstantError::DstRangeTooSmall)
1225 );
1226
1227 assert_eq!(
1229 map_value_to_literal(f64::MIN, Scalar::F64),
1230 Ok(Literal::F64(f64::MIN))
1231 );
1232 assert_eq!(
1233 map_value_to_literal(f64::MAX, Scalar::F64),
1234 Ok(Literal::F64(f64::MAX))
1235 );
1236}