1mod expressions;
2mod functions;
3mod handle_set_map;
4mod statements;
5mod types;
6
7use alloc::vec::Vec;
8
9use crate::{
10 arena::{self, HandleSet},
11 compact::functions::FunctionTracer,
12 ir,
13};
14use handle_set_map::HandleMap;
15
16#[cfg(test)]
17use alloc::{format, string::ToString};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum KeepUnused {
22 No,
23 Yes,
24}
25
26impl From<KeepUnused> for bool {
27 fn from(keep_unused: KeepUnused) -> Self {
28 match keep_unused {
29 KeepUnused::No => false,
30 KeepUnused::Yes => true,
31 }
32 }
33}
34
35pub fn compact(module: &mut crate::Module, keep_unused: KeepUnused) {
69 let mut module_tracer = ModuleTracer::new(module);
120
121 log::trace!("tracing entry points");
123 let entry_point_maps = module
124 .entry_points
125 .iter()
126 .map(|e| {
127 log::trace!("tracing entry point {:?}", e.function.name);
128
129 if let Some(sizes) = e.workgroup_size_overrides {
130 for size in sizes.iter().filter_map(|x| *x) {
131 module_tracer.global_expressions_used.insert(size);
132 }
133 }
134
135 let mut used = module_tracer.as_function(&e.function);
136 used.trace();
137 FunctionMap::from(used)
138 })
139 .collect::<Vec<_>>();
140
141 log::trace!("tracing functions");
160 let mut function_maps = HandleMap::with_capacity(module.functions.len());
161 if keep_unused.into() {
162 module_tracer.functions_used.add_all();
163 module_tracer.functions_pending.add_all();
164 }
165 while let Some(handle) = module_tracer.functions_pending.pop() {
166 let function = &module.functions[handle];
167 log::trace!("tracing function {function:?}");
168 let mut function_tracer = module_tracer.as_function(function);
169 function_tracer.trace();
170 function_maps.insert(handle, FunctionMap::from(function_tracer));
171 }
172
173 log::trace!("tracing special types");
175 module_tracer.trace_special_types(&module.special_types);
176
177 log::trace!("tracing global variables");
178 if keep_unused.into() {
179 module_tracer.global_variables_used.add_all();
180 }
181 for global in module_tracer.global_variables_used.iter() {
182 log::trace!("tracing global {:?}", module.global_variables[global].name);
183 module_tracer
184 .types_used
185 .insert(module.global_variables[global].ty);
186 if let Some(init) = module.global_variables[global].init {
187 module_tracer.global_expressions_used.insert(init);
188 }
189 }
190
191 log::trace!("tracing named constants");
194 for (handle, constant) in module.constants.iter() {
195 if constant.name.is_none() || module.types[constant.ty].inner.is_abstract(&module.types) {
196 continue;
197 }
198
199 log::trace!("tracing constant {:?}", constant.name.as_ref().unwrap());
200 module_tracer.constants_used.insert(handle);
201 module_tracer.types_used.insert(constant.ty);
202 module_tracer.global_expressions_used.insert(constant.init);
203 }
204
205 if keep_unused.into() {
206 for (handle, r#override) in module.overrides.iter() {
208 if r#override.name.is_some() && module_tracer.overrides_used.insert(handle) {
209 module_tracer.types_used.insert(r#override.ty);
210 if let Some(init) = r#override.init {
211 module_tracer.global_expressions_used.insert(init);
212 }
213 }
214 }
215
216 for (handle, ty) in module.types.iter() {
218 if ty.name.is_some() {
219 module_tracer.types_used.insert(handle);
220 }
221 }
222 }
223
224 module_tracer.type_expression_tandem();
225
226 let module_map = ModuleMap::from(module_tracer);
231
232 log::trace!("compacting types");
238 let mut new_types = arena::UniqueArena::new();
239 for (old_handle, mut ty, span) in module.types.drain_all() {
240 if let Some(expected_new_handle) = module_map.types.try_adjust(old_handle) {
241 module_map.adjust_type(&mut ty);
242 let actual_new_handle = new_types.insert(ty, span);
243 assert_eq!(actual_new_handle, expected_new_handle);
244 }
245 }
246 module.types = new_types;
247 log::trace!("adjusting special types");
248 module_map.adjust_special_types(&mut module.special_types);
249
250 log::trace!("adjusting constant expressions");
252 module.global_expressions.retain_mut(|handle, expr| {
253 if module_map.global_expressions.used(handle) {
254 module_map.adjust_expression(expr, &module_map.global_expressions);
255 true
256 } else {
257 false
258 }
259 });
260
261 log::trace!("adjusting constants");
263 module.constants.retain_mut(|handle, constant| {
264 if module_map.constants.used(handle) {
265 module_map.types.adjust(&mut constant.ty);
266 module_map.global_expressions.adjust(&mut constant.init);
267 true
268 } else {
269 false
270 }
271 });
272
273 log::trace!("adjusting overrides");
275 module.overrides.retain_mut(|handle, r#override| {
276 if module_map.overrides.used(handle) {
277 module_map.types.adjust(&mut r#override.ty);
278 if let Some(ref mut init) = r#override.init {
279 module_map.global_expressions.adjust(init);
280 }
281 true
282 } else {
283 false
284 }
285 });
286
287 log::trace!("adjusting workgroup_size_overrides");
289 for e in module.entry_points.iter_mut() {
290 if let Some(sizes) = e.workgroup_size_overrides.as_mut() {
291 for size in sizes.iter_mut() {
292 if let Some(expr) = size.as_mut() {
293 module_map.global_expressions.adjust(expr);
294 }
295 }
296 }
297 }
298
299 log::trace!("adjusting global variables");
302 module.global_variables.retain_mut(|handle, global| {
303 if module_map.globals.used(handle) {
304 log::trace!("retaining global variable {:?}", global.name);
305 module_map.types.adjust(&mut global.ty);
306 if let Some(ref mut init) = global.init {
307 module_map.global_expressions.adjust(init);
308 }
309 true
310 } else {
311 log::trace!("dropping global variable {:?}", global.name);
312 false
313 }
314 });
315
316 if let Some(ref mut doc_comments) = module.doc_comments {
318 module_map.adjust_doc_comments(doc_comments.as_mut());
319 }
320
321 let mut reused_named_expressions = crate::NamedExpressions::default();
324
325 module.functions.retain_mut(|handle, function| {
327 if let Some(map) = function_maps.get(handle) {
328 log::trace!("retaining and compacting function {:?}", function.name);
329 map.compact(function, &module_map, &mut reused_named_expressions);
330 true
331 } else {
332 log::trace!("dropping function {:?}", function.name);
333 false
334 }
335 });
336
337 for (entry, map) in module.entry_points.iter_mut().zip(entry_point_maps.iter()) {
339 log::trace!("compacting entry point {:?}", entry.function.name);
340 map.compact(
341 &mut entry.function,
342 &module_map,
343 &mut reused_named_expressions,
344 );
345 }
346}
347
348struct ModuleTracer<'module> {
349 module: &'module crate::Module,
350
351 functions_pending: HandleSet<crate::Function>,
354
355 functions_used: HandleSet<crate::Function>,
356 types_used: HandleSet<crate::Type>,
357 global_variables_used: HandleSet<crate::GlobalVariable>,
358 constants_used: HandleSet<crate::Constant>,
359 overrides_used: HandleSet<crate::Override>,
360 global_expressions_used: HandleSet<crate::Expression>,
361}
362
363impl<'module> ModuleTracer<'module> {
364 fn new(module: &'module crate::Module) -> Self {
365 Self {
366 module,
367 functions_pending: HandleSet::for_arena(&module.functions),
368 functions_used: HandleSet::for_arena(&module.functions),
369 types_used: HandleSet::for_arena(&module.types),
370 global_variables_used: HandleSet::for_arena(&module.global_variables),
371 constants_used: HandleSet::for_arena(&module.constants),
372 overrides_used: HandleSet::for_arena(&module.overrides),
373 global_expressions_used: HandleSet::for_arena(&module.global_expressions),
374 }
375 }
376
377 fn trace_special_types(&mut self, special_types: &crate::SpecialTypes) {
378 let crate::SpecialTypes {
379 ref ray_desc,
380 ref ray_intersection,
381 ref ray_vertex_return,
382 ref predeclared_types,
383 } = *special_types;
384
385 if let Some(ray_desc) = *ray_desc {
386 self.types_used.insert(ray_desc);
387 }
388 if let Some(ray_intersection) = *ray_intersection {
389 self.types_used.insert(ray_intersection);
390 }
391 if let Some(ray_vertex_return) = *ray_vertex_return {
392 self.types_used.insert(ray_vertex_return);
393 }
394 for (_, &handle) in predeclared_types {
395 self.types_used.insert(handle);
396 }
397 }
398
399 fn type_expression_tandem(&mut self) {
409 let mut max_dep = Vec::with_capacity(self.module.types.len());
415 let mut previous = None;
416 for (_handle, ty) in self.module.types.iter() {
417 previous = core::cmp::max(
418 previous,
419 match ty.inner {
420 crate::TypeInner::Array { size, .. }
421 | crate::TypeInner::BindingArray { size, .. } => match size {
422 crate::ArraySize::Constant(_) | crate::ArraySize::Dynamic => None,
423 crate::ArraySize::Pending(handle) => self.module.overrides[handle].init,
424 },
425 _ => None,
426 },
427 );
428 max_dep.push(previous);
429 }
430
431 let mut exprs = self.module.global_expressions.iter().rev().peekable();
444
445 for ((ty_handle, ty), dep) in self.module.types.iter().zip(max_dep).rev() {
446 while let Some((expr_handle, expr)) = exprs.next_if(|&(h, _)| Some(h) > dep) {
447 if self.global_expressions_used.contains(expr_handle) {
448 self.as_const_expression().trace_expression(expr);
449 }
450 }
451 if self.types_used.contains(ty_handle) {
452 self.as_type().trace_type(ty);
453 }
454 }
455 for (expr_handle, expr) in exprs {
457 if self.global_expressions_used.contains(expr_handle) {
458 self.as_const_expression().trace_expression(expr);
459 }
460 }
461 }
462
463 fn as_type(&mut self) -> types::TypeTracer<'_> {
464 types::TypeTracer {
465 overrides: &self.module.overrides,
466 types_used: &mut self.types_used,
467 expressions_used: &mut self.global_expressions_used,
468 overrides_used: &mut self.overrides_used,
469 }
470 }
471
472 fn as_const_expression(&mut self) -> expressions::ExpressionTracer<'_> {
473 expressions::ExpressionTracer {
474 constants: &self.module.constants,
475 overrides: &self.module.overrides,
476 expressions: &self.module.global_expressions,
477 types_used: &mut self.types_used,
478 global_variables_used: &mut self.global_variables_used,
479 constants_used: &mut self.constants_used,
480 expressions_used: &mut self.global_expressions_used,
481 overrides_used: &mut self.overrides_used,
482 global_expressions_used: None,
483 }
484 }
485
486 pub fn as_function<'tracer>(
487 &'tracer mut self,
488 function: &'tracer crate::Function,
489 ) -> FunctionTracer<'tracer> {
490 FunctionTracer {
491 function,
492 constants: &self.module.constants,
493 overrides: &self.module.overrides,
494 functions_pending: &mut self.functions_pending,
495 functions_used: &mut self.functions_used,
496 types_used: &mut self.types_used,
497 global_variables_used: &mut self.global_variables_used,
498 constants_used: &mut self.constants_used,
499 overrides_used: &mut self.overrides_used,
500 global_expressions_used: &mut self.global_expressions_used,
501 expressions_used: HandleSet::for_arena(&function.expressions),
502 }
503 }
504}
505
506struct ModuleMap {
507 functions: HandleMap<crate::Function>,
508 types: HandleMap<crate::Type>,
509 globals: HandleMap<crate::GlobalVariable>,
510 constants: HandleMap<crate::Constant>,
511 overrides: HandleMap<crate::Override>,
512 global_expressions: HandleMap<crate::Expression>,
513}
514
515impl From<ModuleTracer<'_>> for ModuleMap {
516 fn from(used: ModuleTracer) -> Self {
517 ModuleMap {
518 functions: HandleMap::from_set(used.functions_used),
519 types: HandleMap::from_set(used.types_used),
520 globals: HandleMap::from_set(used.global_variables_used),
521 constants: HandleMap::from_set(used.constants_used),
522 overrides: HandleMap::from_set(used.overrides_used),
523 global_expressions: HandleMap::from_set(used.global_expressions_used),
524 }
525 }
526}
527
528impl ModuleMap {
529 fn adjust_special_types(&self, special: &mut crate::SpecialTypes) {
530 let crate::SpecialTypes {
531 ref mut ray_desc,
532 ref mut ray_intersection,
533 ref mut ray_vertex_return,
534 ref mut predeclared_types,
535 } = *special;
536
537 if let Some(ref mut ray_desc) = *ray_desc {
538 self.types.adjust(ray_desc);
539 }
540 if let Some(ref mut ray_intersection) = *ray_intersection {
541 self.types.adjust(ray_intersection);
542 }
543
544 if let Some(ref mut ray_vertex_return) = *ray_vertex_return {
545 self.types.adjust(ray_vertex_return);
546 }
547
548 for handle in predeclared_types.values_mut() {
549 self.types.adjust(handle);
550 }
551 }
552
553 fn adjust_doc_comments(&self, doc_comments: &mut ir::DocComments) {
554 let crate::DocComments {
555 module: _,
556 types: ref mut doc_types,
557 struct_members: ref mut doc_struct_members,
558 entry_points: _,
559 functions: ref mut doc_functions,
560 constants: ref mut doc_constants,
561 global_variables: ref mut doc_globals,
562 } = *doc_comments;
563 log::trace!("adjusting doc comments for types");
564 for (mut ty, doc_comment) in core::mem::take(doc_types) {
565 if !self.types.used(ty) {
566 continue;
567 }
568 self.types.adjust(&mut ty);
569 doc_types.insert(ty, doc_comment);
570 }
571 log::trace!("adjusting doc comments for struct members");
572 for ((mut ty, index), doc_comment) in core::mem::take(doc_struct_members) {
573 if !self.types.used(ty) {
574 continue;
575 }
576 self.types.adjust(&mut ty);
577 doc_struct_members.insert((ty, index), doc_comment);
578 }
579 log::trace!("adjusting doc comments for functions");
580 for (mut handle, doc_comment) in core::mem::take(doc_functions) {
581 if !self.functions.used(handle) {
582 continue;
583 }
584 self.functions.adjust(&mut handle);
585 doc_functions.insert(handle, doc_comment);
586 }
587 log::trace!("adjusting doc comments for constants");
588 for (mut constant, doc_comment) in core::mem::take(doc_constants) {
589 if !self.constants.used(constant) {
590 continue;
591 }
592 self.constants.adjust(&mut constant);
593 doc_constants.insert(constant, doc_comment);
594 }
595 log::trace!("adjusting doc comments for globals");
596 for (mut handle, doc_comment) in core::mem::take(doc_globals) {
597 if !self.globals.used(handle) {
598 continue;
599 }
600 self.globals.adjust(&mut handle);
601 doc_globals.insert(handle, doc_comment);
602 }
603 }
604}
605
606struct FunctionMap {
607 expressions: HandleMap<crate::Expression>,
608}
609
610impl From<FunctionTracer<'_>> for FunctionMap {
611 fn from(used: FunctionTracer) -> Self {
612 FunctionMap {
613 expressions: HandleMap::from_set(used.expressions_used),
614 }
615 }
616}
617
618#[test]
619fn type_expression_interdependence() {
620 let mut module: crate::Module = Default::default();
621 let u32 = module.types.insert(
622 crate::Type {
623 name: None,
624 inner: crate::TypeInner::Scalar(crate::Scalar {
625 kind: crate::ScalarKind::Uint,
626 width: 4,
627 }),
628 },
629 crate::Span::default(),
630 );
631 let expr = module.global_expressions.append(
632 crate::Expression::Literal(crate::Literal::U32(0)),
633 crate::Span::default(),
634 );
635 let type_needs_expression = |module: &mut crate::Module, handle| {
636 let override_handle = module.overrides.append(
637 crate::Override {
638 name: None,
639 id: None,
640 ty: u32,
641 init: Some(handle),
642 },
643 crate::Span::default(),
644 );
645 module.types.insert(
646 crate::Type {
647 name: None,
648 inner: crate::TypeInner::Array {
649 base: u32,
650 size: crate::ArraySize::Pending(override_handle),
651 stride: 4,
652 },
653 },
654 crate::Span::default(),
655 )
656 };
657 let expression_needs_type = |module: &mut crate::Module, handle| {
658 module
659 .global_expressions
660 .append(crate::Expression::ZeroValue(handle), crate::Span::default())
661 };
662 let expression_needs_expression = |module: &mut crate::Module, handle| {
663 module.global_expressions.append(
664 crate::Expression::Load { pointer: handle },
665 crate::Span::default(),
666 )
667 };
668 let type_needs_type = |module: &mut crate::Module, handle| {
669 module.types.insert(
670 crate::Type {
671 name: None,
672 inner: crate::TypeInner::Array {
673 base: handle,
674 size: crate::ArraySize::Dynamic,
675 stride: 0,
676 },
677 },
678 crate::Span::default(),
679 )
680 };
681 let mut type_name_counter = 0;
682 let mut type_needed = |module: &mut crate::Module, handle| {
683 let name = Some(format!("type{type_name_counter}"));
684 type_name_counter += 1;
685 module.types.insert(
686 crate::Type {
687 name,
688 inner: crate::TypeInner::Array {
689 base: handle,
690 size: crate::ArraySize::Dynamic,
691 stride: 0,
692 },
693 },
694 crate::Span::default(),
695 )
696 };
697 let mut override_name_counter = 0;
698 let mut expression_needed = |module: &mut crate::Module, handle| {
699 let name = Some(format!("override{override_name_counter}"));
700 override_name_counter += 1;
701 module.overrides.append(
702 crate::Override {
703 name,
704 id: None,
705 ty: u32,
706 init: Some(handle),
707 },
708 crate::Span::default(),
709 )
710 };
711 let cmp_modules = |mod0: &crate::Module, mod1: &crate::Module| {
712 (mod0.types.iter().collect::<Vec<_>>() == mod1.types.iter().collect::<Vec<_>>())
713 && (mod0.global_expressions.iter().collect::<Vec<_>>()
714 == mod1.global_expressions.iter().collect::<Vec<_>>())
715 };
716 let expr_end = type_needs_expression(&mut module, expr);
718 let ty_trace = type_needs_type(&mut module, expr_end);
719 let expr_init = expression_needs_type(&mut module, ty_trace);
720 expression_needed(&mut module, expr_init);
721 let ty_end = expression_needs_type(&mut module, u32);
722 let expr_trace = expression_needs_expression(&mut module, ty_end);
723 let ty_init = type_needs_expression(&mut module, expr_trace);
724 type_needed(&mut module, ty_init);
725 let untouched = module.clone();
726 compact(&mut module, KeepUnused::Yes);
727 assert!(cmp_modules(&module, &untouched));
728 let unused_expr = module.global_expressions.append(
729 crate::Expression::Literal(crate::Literal::U32(1)),
730 crate::Span::default(),
731 );
732 type_needs_expression(&mut module, unused_expr);
733 assert!(!cmp_modules(&module, &untouched));
734 compact(&mut module, KeepUnused::Yes);
735 assert!(cmp_modules(&module, &untouched));
736}
737
738#[test]
739fn array_length_override() {
740 let mut module: crate::Module = Default::default();
741 let ty_bool = module.types.insert(
742 crate::Type {
743 name: None,
744 inner: crate::TypeInner::Scalar(crate::Scalar::BOOL),
745 },
746 crate::Span::default(),
747 );
748 let ty_u32 = module.types.insert(
749 crate::Type {
750 name: None,
751 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
752 },
753 crate::Span::default(),
754 );
755 let one = module.global_expressions.append(
756 crate::Expression::Literal(crate::Literal::U32(1)),
757 crate::Span::default(),
758 );
759 let _unused_override = module.overrides.append(
760 crate::Override {
761 name: None,
762 id: Some(40),
763 ty: ty_u32,
764 init: None,
765 },
766 crate::Span::default(),
767 );
768 let o = module.overrides.append(
769 crate::Override {
770 name: None,
771 id: Some(42),
772 ty: ty_u32,
773 init: Some(one),
774 },
775 crate::Span::default(),
776 );
777 let _ty_array = module.types.insert(
778 crate::Type {
779 name: Some("array<bool, o>".to_string()),
780 inner: crate::TypeInner::Array {
781 base: ty_bool,
782 size: crate::ArraySize::Pending(o),
783 stride: 4,
784 },
785 },
786 crate::Span::default(),
787 );
788
789 let mut validator = super::valid::Validator::new(
790 super::valid::ValidationFlags::all(),
791 super::valid::Capabilities::all(),
792 );
793
794 assert!(validator.validate(&module).is_ok());
795 compact(&mut module, KeepUnused::Yes);
796 assert!(validator.validate(&module).is_ok());
797}
798
799#[test]
802fn array_length_override_mutual() {
803 use crate::Expression as Ex;
804 use crate::Scalar as Sc;
805 use crate::TypeInner as Ti;
806
807 let nowhere = crate::Span::default();
808 let mut module = crate::Module::default();
809 let ty_u32 = module.types.insert(
810 crate::Type {
811 name: None,
812 inner: Ti::Scalar(Sc::U32),
813 },
814 nowhere,
815 );
816
817 let ty_i32 = module.types.insert(
821 crate::Type {
822 name: None,
823 inner: Ti::Scalar(Sc::I32),
824 },
825 nowhere,
826 );
827
828 let first_override = module.overrides.append(
830 crate::Override {
831 name: None, id: Some(41),
833 ty: ty_i32,
834 init: None,
835 },
836 nowhere,
837 );
838
839 let first_override_expr = module
848 .global_expressions
849 .append(Ex::Override(first_override), nowhere);
850 let zero = module
851 .global_expressions
852 .append(Ex::ZeroValue(ty_i32), nowhere);
853 let sum = module.global_expressions.append(
854 Ex::Binary {
855 op: crate::BinaryOperator::Add,
856 left: first_override_expr,
857 right: zero,
858 },
859 nowhere,
860 );
861 let init = module.global_expressions.append(
862 Ex::As {
863 expr: sum,
864 kind: crate::ScalarKind::Uint,
865 convert: None,
866 },
867 nowhere,
868 );
869
870 let second_override = module.overrides.append(
872 crate::Override {
873 name: None, id: Some(42),
875 ty: ty_u32,
876 init: Some(init),
877 },
878 nowhere,
879 );
880
881 let _ty_array = module.types.insert(
884 crate::Type {
885 name: Some("delicious_array".to_string()),
886 inner: Ti::Array {
887 base: ty_u32,
888 size: crate::ArraySize::Pending(second_override),
889 stride: 4,
890 },
891 },
892 nowhere,
893 );
894
895 let mut validator = super::valid::Validator::new(
896 super::valid::ValidationFlags::all(),
897 super::valid::Capabilities::all(),
898 );
899
900 assert!(validator.validate(&module).is_ok());
901 compact(&mut module, KeepUnused::Yes);
902 assert!(validator.validate(&module).is_ok());
903}
904
905#[test]
906fn array_length_expression() {
907 let mut module: crate::Module = Default::default();
908 let ty_u32 = module.types.insert(
909 crate::Type {
910 name: None,
911 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
912 },
913 crate::Span::default(),
914 );
915 let _unused_zero = module.global_expressions.append(
916 crate::Expression::Literal(crate::Literal::U32(0)),
917 crate::Span::default(),
918 );
919 let one = module.global_expressions.append(
920 crate::Expression::Literal(crate::Literal::U32(1)),
921 crate::Span::default(),
922 );
923 let override_one = module.overrides.append(
924 crate::Override {
925 name: None,
926 id: None,
927 ty: ty_u32,
928 init: Some(one),
929 },
930 crate::Span::default(),
931 );
932 let _ty_array = module.types.insert(
933 crate::Type {
934 name: Some("array<u32, 1>".to_string()),
935 inner: crate::TypeInner::Array {
936 base: ty_u32,
937 size: crate::ArraySize::Pending(override_one),
938 stride: 4,
939 },
940 },
941 crate::Span::default(),
942 );
943
944 let mut validator = super::valid::Validator::new(
945 super::valid::ValidationFlags::all(),
946 super::valid::Capabilities::all(),
947 );
948
949 assert!(validator.validate(&module).is_ok());
950 compact(&mut module, KeepUnused::Yes);
951 assert!(validator.validate(&module).is_ok());
952}
953
954#[test]
955fn global_expression_override() {
956 let mut module: crate::Module = Default::default();
957 let ty_u32 = module.types.insert(
958 crate::Type {
959 name: None,
960 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
961 },
962 crate::Span::default(),
963 );
964
965 let expr1 = module.global_expressions.append(
969 crate::Expression::Literal(crate::Literal::U32(1)),
970 crate::Span::default(),
971 );
972
973 let o = module.overrides.append(
975 crate::Override {
976 name: None,
977 id: Some(42),
978 ty: ty_u32,
979 init: Some(expr1),
980 },
981 crate::Span::default(),
982 );
983
984 let expr2 = module
986 .global_expressions
987 .append(crate::Expression::Override(o), crate::Span::default());
988
989 let _p = module.overrides.append(
991 crate::Override {
992 name: Some("p".to_string()),
993 id: None,
994 ty: ty_u32,
995 init: Some(expr2),
996 },
997 crate::Span::default(),
998 );
999
1000 let mut validator = super::valid::Validator::new(
1001 super::valid::ValidationFlags::all(),
1002 super::valid::Capabilities::all(),
1003 );
1004
1005 assert!(validator.validate(&module).is_ok());
1006 compact(&mut module, KeepUnused::Yes);
1007 assert!(validator.validate(&module).is_ok());
1008}
1009
1010#[test]
1011fn local_expression_override() {
1012 let mut module: crate::Module = Default::default();
1013 let ty_u32 = module.types.insert(
1014 crate::Type {
1015 name: None,
1016 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1017 },
1018 crate::Span::default(),
1019 );
1020
1021 let expr1 = module.global_expressions.append(
1024 crate::Expression::Literal(crate::Literal::U32(1)),
1025 crate::Span::default(),
1026 );
1027
1028 let _unused_override = module.overrides.append(
1030 crate::Override {
1031 name: None,
1032 id: Some(41),
1033 ty: ty_u32,
1034 init: None,
1035 },
1036 crate::Span::default(),
1037 );
1038
1039 let o = module.overrides.append(
1041 crate::Override {
1042 name: None,
1043 id: Some(42),
1044 ty: ty_u32,
1045 init: Some(expr1),
1046 },
1047 crate::Span::default(),
1048 );
1049
1050 let mut fun = crate::Function {
1051 result: Some(crate::FunctionResult {
1052 ty: ty_u32,
1053 binding: None,
1054 }),
1055 ..crate::Function::default()
1056 };
1057
1058 let o_expr = fun
1060 .expressions
1061 .append(crate::Expression::Override(o), crate::Span::default());
1062 fun.body.push(
1063 crate::Statement::Return {
1064 value: Some(o_expr),
1065 },
1066 crate::Span::default(),
1067 );
1068
1069 module.functions.append(fun, crate::Span::default());
1070
1071 let mut validator = super::valid::Validator::new(
1072 super::valid::ValidationFlags::all(),
1073 super::valid::Capabilities::all(),
1074 );
1075
1076 assert!(validator.validate(&module).is_ok());
1077 compact(&mut module, KeepUnused::Yes);
1078 assert!(validator.validate(&module).is_ok());
1079}
1080
1081#[test]
1082fn unnamed_constant_type() {
1083 let mut module = crate::Module::default();
1084 let nowhere = crate::Span::default();
1085
1086 let ty_u32 = module.types.insert(
1088 crate::Type {
1089 name: None,
1090 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1091 },
1092 nowhere,
1093 );
1094
1095 let ty_vec_u32 = module.types.insert(
1097 crate::Type {
1098 name: None,
1099 inner: crate::TypeInner::Vector {
1100 size: crate::VectorSize::Bi,
1101 scalar: crate::Scalar::U32,
1102 },
1103 },
1104 nowhere,
1105 );
1106
1107 let unnamed_init = module
1108 .global_expressions
1109 .append(crate::Expression::Literal(crate::Literal::U32(0)), nowhere);
1110
1111 let unnamed_constant = module.constants.append(
1112 crate::Constant {
1113 name: None,
1114 ty: ty_u32,
1115 init: unnamed_init,
1116 },
1117 nowhere,
1118 );
1119
1120 let unnamed_constant_expr = module
1124 .global_expressions
1125 .append(crate::Expression::Constant(unnamed_constant), nowhere);
1126 let named_init = module.global_expressions.append(
1127 crate::Expression::Splat {
1128 size: crate::VectorSize::Bi,
1129 value: unnamed_constant_expr,
1130 },
1131 nowhere,
1132 );
1133
1134 let _named_constant = module.constants.append(
1135 crate::Constant {
1136 name: Some("totally_named".to_string()),
1137 ty: ty_vec_u32,
1138 init: named_init,
1139 },
1140 nowhere,
1141 );
1142
1143 let mut validator = super::valid::Validator::new(
1144 super::valid::ValidationFlags::all(),
1145 super::valid::Capabilities::all(),
1146 );
1147
1148 assert!(validator.validate(&module).is_ok());
1149 compact(&mut module, KeepUnused::Yes);
1150 assert!(validator.validate(&module).is_ok());
1151}
1152
1153#[test]
1154fn unnamed_override_type() {
1155 let mut module = crate::Module::default();
1156 let nowhere = crate::Span::default();
1157
1158 let ty_u32 = module.types.insert(
1160 crate::Type {
1161 name: None,
1162 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1163 },
1164 nowhere,
1165 );
1166
1167 let ty_i32 = module.types.insert(
1169 crate::Type {
1170 name: None,
1171 inner: crate::TypeInner::Scalar(crate::Scalar::I32),
1172 },
1173 nowhere,
1174 );
1175
1176 let unnamed_init = module
1177 .global_expressions
1178 .append(crate::Expression::Literal(crate::Literal::U32(0)), nowhere);
1179
1180 let unnamed_override = module.overrides.append(
1181 crate::Override {
1182 name: None,
1183 id: Some(42),
1184 ty: ty_u32,
1185 init: Some(unnamed_init),
1186 },
1187 nowhere,
1188 );
1189
1190 let unnamed_override_expr = module
1194 .global_expressions
1195 .append(crate::Expression::Override(unnamed_override), nowhere);
1196 let named_init = module.global_expressions.append(
1197 crate::Expression::As {
1198 expr: unnamed_override_expr,
1199 kind: crate::ScalarKind::Sint,
1200 convert: None,
1201 },
1202 nowhere,
1203 );
1204
1205 let _named_override = module.overrides.append(
1206 crate::Override {
1207 name: Some("totally_named".to_string()),
1208 id: None,
1209 ty: ty_i32,
1210 init: Some(named_init),
1211 },
1212 nowhere,
1213 );
1214
1215 let mut validator = super::valid::Validator::new(
1216 super::valid::ValidationFlags::all(),
1217 super::valid::Capabilities::all(),
1218 );
1219
1220 assert!(validator.validate(&module).is_ok());
1221 compact(&mut module, KeepUnused::Yes);
1222 assert!(validator.validate(&module).is_ok());
1223}