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 if let Some(task_payload) = e.task_payload {
136 module_tracer.global_variables_used.insert(task_payload);
137 }
138 if let Some(ref mesh_info) = e.mesh_info {
139 module_tracer
140 .global_variables_used
141 .insert(mesh_info.output_variable);
142 module_tracer
143 .types_used
144 .insert(mesh_info.vertex_output_type);
145 module_tracer
146 .types_used
147 .insert(mesh_info.primitive_output_type);
148 if let Some(max_vertices_override) = mesh_info.max_vertices_override {
149 module_tracer
150 .global_expressions_used
151 .insert(max_vertices_override);
152 }
153 if let Some(max_primitives_override) = mesh_info.max_primitives_override {
154 module_tracer
155 .global_expressions_used
156 .insert(max_primitives_override);
157 }
158 }
159 if e.stage == crate::ShaderStage::Task || e.stage == crate::ShaderStage::Mesh {
160 let u32_type = module
162 .types
163 .iter()
164 .find_map(|tuple| {
165 if tuple.1.inner == crate::TypeInner::Scalar(crate::Scalar::U32) {
166 Some(tuple.0)
167 } else {
168 None
169 }
170 })
171 .unwrap();
172 module_tracer.types_used.insert(u32_type);
173 }
174
175 let mut used = module_tracer.as_function(&e.function);
176 used.trace();
177 FunctionMap::from(used)
178 })
179 .collect::<Vec<_>>();
180
181 log::trace!("tracing functions");
200 let mut function_maps = HandleMap::with_capacity(module.functions.len());
201 if keep_unused.into() {
202 module_tracer.functions_used.add_all();
203 module_tracer.functions_pending.add_all();
204 }
205 while let Some(handle) = module_tracer.functions_pending.pop() {
206 let function = &module.functions[handle];
207 log::trace!("tracing function {function:?}");
208 let mut function_tracer = module_tracer.as_function(function);
209 function_tracer.trace();
210 function_maps.insert(handle, FunctionMap::from(function_tracer));
211 }
212
213 log::trace!("tracing special types");
215 module_tracer.trace_special_types(&module.special_types);
216
217 log::trace!("tracing global variables");
218 if keep_unused.into() {
219 module_tracer.global_variables_used.add_all();
220 }
221 for global in module_tracer.global_variables_used.iter() {
222 log::trace!("tracing global {:?}", module.global_variables[global].name);
223 module_tracer
224 .types_used
225 .insert(module.global_variables[global].ty);
226 if let Some(init) = module.global_variables[global].init {
227 module_tracer.global_expressions_used.insert(init);
228 }
229 }
230
231 log::trace!("tracing named constants");
234 for (handle, constant) in module.constants.iter() {
235 if constant.name.is_none() || module.types[constant.ty].inner.is_abstract(&module.types) {
236 continue;
237 }
238
239 log::trace!("tracing constant {:?}", constant.name.as_ref().unwrap());
240 module_tracer.constants_used.insert(handle);
241 module_tracer.types_used.insert(constant.ty);
242 module_tracer.global_expressions_used.insert(constant.init);
243 }
244
245 if keep_unused.into() {
246 for (handle, r#override) in module.overrides.iter() {
248 if r#override.name.is_some() && module_tracer.overrides_used.insert(handle) {
249 module_tracer.types_used.insert(r#override.ty);
250 if let Some(init) = r#override.init {
251 module_tracer.global_expressions_used.insert(init);
252 }
253 }
254 }
255
256 for (handle, ty) in module.types.iter() {
258 if ty.name.is_some() {
259 module_tracer.types_used.insert(handle);
260 }
261 }
262 }
263
264 module_tracer.type_expression_tandem();
265
266 let module_map = ModuleMap::from(module_tracer);
271
272 log::trace!("compacting types");
278 let mut new_types = arena::UniqueArena::new();
279 for (old_handle, mut ty, span) in module.types.drain_all() {
280 if let Some(expected_new_handle) = module_map.types.try_adjust(old_handle) {
281 module_map.adjust_type(&mut ty);
282 let actual_new_handle = new_types.insert(ty, span);
283 assert_eq!(actual_new_handle, expected_new_handle);
284 }
285 }
286 module.types = new_types;
287 log::trace!("adjusting special types");
288 module_map.adjust_special_types(&mut module.special_types);
289
290 log::trace!("adjusting constant expressions");
292 module.global_expressions.retain_mut(|handle, expr| {
293 if module_map.global_expressions.used(handle) {
294 module_map.adjust_expression(expr, &module_map.global_expressions);
295 true
296 } else {
297 false
298 }
299 });
300
301 log::trace!("adjusting constants");
303 module.constants.retain_mut(|handle, constant| {
304 if module_map.constants.used(handle) {
305 module_map.types.adjust(&mut constant.ty);
306 module_map.global_expressions.adjust(&mut constant.init);
307 true
308 } else {
309 false
310 }
311 });
312
313 log::trace!("adjusting overrides");
315 module.overrides.retain_mut(|handle, r#override| {
316 if module_map.overrides.used(handle) {
317 module_map.types.adjust(&mut r#override.ty);
318 if let Some(ref mut init) = r#override.init {
319 module_map.global_expressions.adjust(init);
320 }
321 true
322 } else {
323 false
324 }
325 });
326
327 log::trace!("adjusting workgroup_size_overrides");
329 for e in module.entry_points.iter_mut() {
330 if let Some(sizes) = e.workgroup_size_overrides.as_mut() {
331 for size in sizes.iter_mut() {
332 if let Some(expr) = size.as_mut() {
333 module_map.global_expressions.adjust(expr);
334 }
335 }
336 }
337 }
338
339 log::trace!("adjusting global variables");
342 module.global_variables.retain_mut(|handle, global| {
343 if module_map.globals.used(handle) {
344 log::trace!("retaining global variable {:?}", global.name);
345 module_map.types.adjust(&mut global.ty);
346 if let Some(ref mut init) = global.init {
347 module_map.global_expressions.adjust(init);
348 }
349 true
350 } else {
351 log::trace!("dropping global variable {:?}", global.name);
352 false
353 }
354 });
355
356 if let Some(ref mut doc_comments) = module.doc_comments {
358 module_map.adjust_doc_comments(doc_comments.as_mut());
359 }
360
361 let mut reused_named_expressions = crate::NamedExpressions::default();
364
365 module.functions.retain_mut(|handle, function| {
367 if let Some(map) = function_maps.get(handle) {
368 log::trace!("retaining and compacting function {:?}", function.name);
369 map.compact(function, &module_map, &mut reused_named_expressions);
370 true
371 } else {
372 log::trace!("dropping function {:?}", function.name);
373 false
374 }
375 });
376
377 for (entry, map) in module.entry_points.iter_mut().zip(entry_point_maps.iter()) {
379 log::trace!("compacting entry point {:?}", entry.function.name);
380 map.compact(
381 &mut entry.function,
382 &module_map,
383 &mut reused_named_expressions,
384 );
385 if let Some(ref mut task_payload) = entry.task_payload {
386 module_map.globals.adjust(task_payload);
387 }
388 if let Some(ref mut mesh_info) = entry.mesh_info {
389 module_map.globals.adjust(&mut mesh_info.output_variable);
390 module_map.types.adjust(&mut mesh_info.vertex_output_type);
391 module_map
392 .types
393 .adjust(&mut mesh_info.primitive_output_type);
394 if let Some(ref mut max_vertices_override) = mesh_info.max_vertices_override {
395 module_map.global_expressions.adjust(max_vertices_override);
396 }
397 if let Some(ref mut max_primitives_override) = mesh_info.max_primitives_override {
398 module_map
399 .global_expressions
400 .adjust(max_primitives_override);
401 }
402 }
403 }
404}
405
406struct ModuleTracer<'module> {
407 module: &'module crate::Module,
408
409 functions_pending: HandleSet<crate::Function>,
412
413 functions_used: HandleSet<crate::Function>,
414 types_used: HandleSet<crate::Type>,
415 global_variables_used: HandleSet<crate::GlobalVariable>,
416 constants_used: HandleSet<crate::Constant>,
417 overrides_used: HandleSet<crate::Override>,
418 global_expressions_used: HandleSet<crate::Expression>,
419}
420
421impl<'module> ModuleTracer<'module> {
422 fn new(module: &'module crate::Module) -> Self {
423 Self {
424 module,
425 functions_pending: HandleSet::for_arena(&module.functions),
426 functions_used: HandleSet::for_arena(&module.functions),
427 types_used: HandleSet::for_arena(&module.types),
428 global_variables_used: HandleSet::for_arena(&module.global_variables),
429 constants_used: HandleSet::for_arena(&module.constants),
430 overrides_used: HandleSet::for_arena(&module.overrides),
431 global_expressions_used: HandleSet::for_arena(&module.global_expressions),
432 }
433 }
434
435 fn trace_special_types(&mut self, special_types: &crate::SpecialTypes) {
436 let crate::SpecialTypes {
437 ref ray_desc,
438 ref ray_intersection,
439 ref ray_vertex_return,
440 ref predeclared_types,
441 ref external_texture_params,
442 ref external_texture_transfer_function,
443 } = *special_types;
444
445 if let Some(ray_desc) = *ray_desc {
446 self.types_used.insert(ray_desc);
447 }
448 if let Some(ray_intersection) = *ray_intersection {
449 self.types_used.insert(ray_intersection);
450 }
451 if let Some(ray_vertex_return) = *ray_vertex_return {
452 self.types_used.insert(ray_vertex_return);
453 }
454 if let Some(external_texture_params) = *external_texture_params {
458 self.types_used.insert(external_texture_params);
459 }
460 if let Some(external_texture_transfer_function) = *external_texture_transfer_function {
461 self.types_used.insert(external_texture_transfer_function);
462 }
463 for (_, &handle) in predeclared_types {
464 self.types_used.insert(handle);
465 }
466 }
467
468 fn type_expression_tandem(&mut self) {
478 let mut max_dep = Vec::with_capacity(self.module.types.len());
484 let mut previous = None;
485 for (_handle, ty) in self.module.types.iter() {
486 previous = core::cmp::max(
487 previous,
488 match ty.inner {
489 crate::TypeInner::Array { size, .. }
490 | crate::TypeInner::BindingArray { size, .. } => match size {
491 crate::ArraySize::Constant(_) | crate::ArraySize::Dynamic => None,
492 crate::ArraySize::Pending(handle) => self.module.overrides[handle].init,
493 },
494 _ => None,
495 },
496 );
497 max_dep.push(previous);
498 }
499
500 let mut exprs = self.module.global_expressions.iter().rev().peekable();
513
514 for ((ty_handle, ty), dep) in self.module.types.iter().zip(max_dep).rev() {
515 while let Some((expr_handle, expr)) = exprs.next_if(|&(h, _)| Some(h) > dep) {
516 if self.global_expressions_used.contains(expr_handle) {
517 self.as_const_expression().trace_expression(expr);
518 }
519 }
520 if self.types_used.contains(ty_handle) {
521 self.as_type().trace_type(ty);
522 }
523 }
524 for (expr_handle, expr) in exprs {
526 if self.global_expressions_used.contains(expr_handle) {
527 self.as_const_expression().trace_expression(expr);
528 }
529 }
530 }
531
532 fn as_type(&mut self) -> types::TypeTracer<'_> {
533 types::TypeTracer {
534 overrides: &self.module.overrides,
535 types_used: &mut self.types_used,
536 expressions_used: &mut self.global_expressions_used,
537 overrides_used: &mut self.overrides_used,
538 }
539 }
540
541 fn as_const_expression(&mut self) -> expressions::ExpressionTracer<'_> {
542 expressions::ExpressionTracer {
543 constants: &self.module.constants,
544 overrides: &self.module.overrides,
545 expressions: &self.module.global_expressions,
546 types_used: &mut self.types_used,
547 global_variables_used: &mut self.global_variables_used,
548 constants_used: &mut self.constants_used,
549 expressions_used: &mut self.global_expressions_used,
550 overrides_used: &mut self.overrides_used,
551 global_expressions_used: None,
552 }
553 }
554
555 pub fn as_function<'tracer>(
556 &'tracer mut self,
557 function: &'tracer crate::Function,
558 ) -> FunctionTracer<'tracer> {
559 FunctionTracer {
560 function,
561 constants: &self.module.constants,
562 overrides: &self.module.overrides,
563 functions_pending: &mut self.functions_pending,
564 functions_used: &mut self.functions_used,
565 types_used: &mut self.types_used,
566 global_variables_used: &mut self.global_variables_used,
567 constants_used: &mut self.constants_used,
568 overrides_used: &mut self.overrides_used,
569 global_expressions_used: &mut self.global_expressions_used,
570 expressions_used: HandleSet::for_arena(&function.expressions),
571 }
572 }
573}
574
575struct ModuleMap {
576 functions: HandleMap<crate::Function>,
577 types: HandleMap<crate::Type>,
578 globals: HandleMap<crate::GlobalVariable>,
579 constants: HandleMap<crate::Constant>,
580 overrides: HandleMap<crate::Override>,
581 global_expressions: HandleMap<crate::Expression>,
582}
583
584impl From<ModuleTracer<'_>> for ModuleMap {
585 fn from(used: ModuleTracer) -> Self {
586 ModuleMap {
587 functions: HandleMap::from_set(used.functions_used),
588 types: HandleMap::from_set(used.types_used),
589 globals: HandleMap::from_set(used.global_variables_used),
590 constants: HandleMap::from_set(used.constants_used),
591 overrides: HandleMap::from_set(used.overrides_used),
592 global_expressions: HandleMap::from_set(used.global_expressions_used),
593 }
594 }
595}
596
597impl ModuleMap {
598 fn adjust_special_types(&self, special: &mut crate::SpecialTypes) {
599 let crate::SpecialTypes {
600 ref mut ray_desc,
601 ref mut ray_intersection,
602 ref mut ray_vertex_return,
603 ref mut predeclared_types,
604 ref mut external_texture_params,
605 ref mut external_texture_transfer_function,
606 } = *special;
607
608 if let Some(ref mut ray_desc) = *ray_desc {
609 self.types.adjust(ray_desc);
610 }
611 if let Some(ref mut ray_intersection) = *ray_intersection {
612 self.types.adjust(ray_intersection);
613 }
614
615 if let Some(ref mut ray_vertex_return) = *ray_vertex_return {
616 self.types.adjust(ray_vertex_return);
617 }
618
619 if let Some(ref mut external_texture_params) = *external_texture_params {
620 self.types.adjust(external_texture_params);
621 }
622
623 if let Some(ref mut external_texture_transfer_function) =
624 *external_texture_transfer_function
625 {
626 self.types.adjust(external_texture_transfer_function);
627 }
628
629 for handle in predeclared_types.values_mut() {
630 self.types.adjust(handle);
631 }
632 }
633
634 fn adjust_doc_comments(&self, doc_comments: &mut ir::DocComments) {
635 let crate::DocComments {
636 module: _,
637 types: ref mut doc_types,
638 struct_members: ref mut doc_struct_members,
639 entry_points: _,
640 functions: ref mut doc_functions,
641 constants: ref mut doc_constants,
642 global_variables: ref mut doc_globals,
643 } = *doc_comments;
644 log::trace!("adjusting doc comments for types");
645 for (mut ty, doc_comment) in core::mem::take(doc_types) {
646 if !self.types.used(ty) {
647 continue;
648 }
649 self.types.adjust(&mut ty);
650 doc_types.insert(ty, doc_comment);
651 }
652 log::trace!("adjusting doc comments for struct members");
653 for ((mut ty, index), doc_comment) in core::mem::take(doc_struct_members) {
654 if !self.types.used(ty) {
655 continue;
656 }
657 self.types.adjust(&mut ty);
658 doc_struct_members.insert((ty, index), doc_comment);
659 }
660 log::trace!("adjusting doc comments for functions");
661 for (mut handle, doc_comment) in core::mem::take(doc_functions) {
662 if !self.functions.used(handle) {
663 continue;
664 }
665 self.functions.adjust(&mut handle);
666 doc_functions.insert(handle, doc_comment);
667 }
668 log::trace!("adjusting doc comments for constants");
669 for (mut constant, doc_comment) in core::mem::take(doc_constants) {
670 if !self.constants.used(constant) {
671 continue;
672 }
673 self.constants.adjust(&mut constant);
674 doc_constants.insert(constant, doc_comment);
675 }
676 log::trace!("adjusting doc comments for globals");
677 for (mut handle, doc_comment) in core::mem::take(doc_globals) {
678 if !self.globals.used(handle) {
679 continue;
680 }
681 self.globals.adjust(&mut handle);
682 doc_globals.insert(handle, doc_comment);
683 }
684 }
685}
686
687struct FunctionMap {
688 expressions: HandleMap<crate::Expression>,
689}
690
691impl From<FunctionTracer<'_>> for FunctionMap {
692 fn from(used: FunctionTracer) -> Self {
693 FunctionMap {
694 expressions: HandleMap::from_set(used.expressions_used),
695 }
696 }
697}
698
699#[test]
700fn type_expression_interdependence() {
701 let mut module: crate::Module = Default::default();
702 let u32 = module.types.insert(
703 crate::Type {
704 name: None,
705 inner: crate::TypeInner::Scalar(crate::Scalar {
706 kind: crate::ScalarKind::Uint,
707 width: 4,
708 }),
709 },
710 crate::Span::default(),
711 );
712 let expr = module.global_expressions.append(
713 crate::Expression::Literal(crate::Literal::U32(0)),
714 crate::Span::default(),
715 );
716 let type_needs_expression = |module: &mut crate::Module, handle| {
717 let override_handle = module.overrides.append(
718 crate::Override {
719 name: None,
720 id: None,
721 ty: u32,
722 init: Some(handle),
723 },
724 crate::Span::default(),
725 );
726 module.types.insert(
727 crate::Type {
728 name: None,
729 inner: crate::TypeInner::Array {
730 base: u32,
731 size: crate::ArraySize::Pending(override_handle),
732 stride: 4,
733 },
734 },
735 crate::Span::default(),
736 )
737 };
738 let expression_needs_type = |module: &mut crate::Module, handle| {
739 module
740 .global_expressions
741 .append(crate::Expression::ZeroValue(handle), crate::Span::default())
742 };
743 let expression_needs_expression = |module: &mut crate::Module, handle| {
744 module.global_expressions.append(
745 crate::Expression::Load { pointer: handle },
746 crate::Span::default(),
747 )
748 };
749 let type_needs_type = |module: &mut crate::Module, handle| {
750 module.types.insert(
751 crate::Type {
752 name: None,
753 inner: crate::TypeInner::Array {
754 base: handle,
755 size: crate::ArraySize::Dynamic,
756 stride: 0,
757 },
758 },
759 crate::Span::default(),
760 )
761 };
762 let mut type_name_counter = 0;
763 let mut type_needed = |module: &mut crate::Module, handle| {
764 let name = Some(format!("type{type_name_counter}"));
765 type_name_counter += 1;
766 module.types.insert(
767 crate::Type {
768 name,
769 inner: crate::TypeInner::Array {
770 base: handle,
771 size: crate::ArraySize::Dynamic,
772 stride: 0,
773 },
774 },
775 crate::Span::default(),
776 )
777 };
778 let mut override_name_counter = 0;
779 let mut expression_needed = |module: &mut crate::Module, handle| {
780 let name = Some(format!("override{override_name_counter}"));
781 override_name_counter += 1;
782 module.overrides.append(
783 crate::Override {
784 name,
785 id: None,
786 ty: u32,
787 init: Some(handle),
788 },
789 crate::Span::default(),
790 )
791 };
792 let cmp_modules = |mod0: &crate::Module, mod1: &crate::Module| {
793 (mod0.types.iter().collect::<Vec<_>>() == mod1.types.iter().collect::<Vec<_>>())
794 && (mod0.global_expressions.iter().collect::<Vec<_>>()
795 == mod1.global_expressions.iter().collect::<Vec<_>>())
796 };
797 let expr_end = type_needs_expression(&mut module, expr);
799 let ty_trace = type_needs_type(&mut module, expr_end);
800 let expr_init = expression_needs_type(&mut module, ty_trace);
801 expression_needed(&mut module, expr_init);
802 let ty_end = expression_needs_type(&mut module, u32);
803 let expr_trace = expression_needs_expression(&mut module, ty_end);
804 let ty_init = type_needs_expression(&mut module, expr_trace);
805 type_needed(&mut module, ty_init);
806 let untouched = module.clone();
807 compact(&mut module, KeepUnused::Yes);
808 assert!(cmp_modules(&module, &untouched));
809 let unused_expr = module.global_expressions.append(
810 crate::Expression::Literal(crate::Literal::U32(1)),
811 crate::Span::default(),
812 );
813 type_needs_expression(&mut module, unused_expr);
814 assert!(!cmp_modules(&module, &untouched));
815 compact(&mut module, KeepUnused::Yes);
816 assert!(cmp_modules(&module, &untouched));
817}
818
819#[test]
820fn array_length_override() {
821 let mut module: crate::Module = Default::default();
822 let ty_bool = module.types.insert(
823 crate::Type {
824 name: None,
825 inner: crate::TypeInner::Scalar(crate::Scalar::BOOL),
826 },
827 crate::Span::default(),
828 );
829 let ty_u32 = module.types.insert(
830 crate::Type {
831 name: None,
832 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
833 },
834 crate::Span::default(),
835 );
836 let one = module.global_expressions.append(
837 crate::Expression::Literal(crate::Literal::U32(1)),
838 crate::Span::default(),
839 );
840 let _unused_override = module.overrides.append(
841 crate::Override {
842 name: None,
843 id: Some(40),
844 ty: ty_u32,
845 init: None,
846 },
847 crate::Span::default(),
848 );
849 let o = module.overrides.append(
850 crate::Override {
851 name: None,
852 id: Some(42),
853 ty: ty_u32,
854 init: Some(one),
855 },
856 crate::Span::default(),
857 );
858 let _ty_array = module.types.insert(
859 crate::Type {
860 name: Some("array<bool, o>".to_string()),
861 inner: crate::TypeInner::Array {
862 base: ty_bool,
863 size: crate::ArraySize::Pending(o),
864 stride: 4,
865 },
866 },
867 crate::Span::default(),
868 );
869
870 let mut validator = super::valid::Validator::new(
871 super::valid::ValidationFlags::all(),
872 super::valid::Capabilities::all(),
873 );
874
875 assert!(validator.validate(&module).is_ok());
876 compact(&mut module, KeepUnused::Yes);
877 assert!(validator.validate(&module).is_ok());
878}
879
880#[test]
883fn array_length_override_mutual() {
884 use crate::Expression as Ex;
885 use crate::Scalar as Sc;
886 use crate::TypeInner as Ti;
887
888 let nowhere = crate::Span::default();
889 let mut module = crate::Module::default();
890 let ty_u32 = module.types.insert(
891 crate::Type {
892 name: None,
893 inner: Ti::Scalar(Sc::U32),
894 },
895 nowhere,
896 );
897
898 let ty_i32 = module.types.insert(
902 crate::Type {
903 name: None,
904 inner: Ti::Scalar(Sc::I32),
905 },
906 nowhere,
907 );
908
909 let first_override = module.overrides.append(
911 crate::Override {
912 name: None, id: Some(41),
914 ty: ty_i32,
915 init: None,
916 },
917 nowhere,
918 );
919
920 let first_override_expr = module
929 .global_expressions
930 .append(Ex::Override(first_override), nowhere);
931 let zero = module
932 .global_expressions
933 .append(Ex::ZeroValue(ty_i32), nowhere);
934 let sum = module.global_expressions.append(
935 Ex::Binary {
936 op: crate::BinaryOperator::Add,
937 left: first_override_expr,
938 right: zero,
939 },
940 nowhere,
941 );
942 let init = module.global_expressions.append(
943 Ex::As {
944 expr: sum,
945 kind: crate::ScalarKind::Uint,
946 convert: None,
947 },
948 nowhere,
949 );
950
951 let second_override = module.overrides.append(
953 crate::Override {
954 name: None, id: Some(42),
956 ty: ty_u32,
957 init: Some(init),
958 },
959 nowhere,
960 );
961
962 let _ty_array = module.types.insert(
965 crate::Type {
966 name: Some("delicious_array".to_string()),
967 inner: Ti::Array {
968 base: ty_u32,
969 size: crate::ArraySize::Pending(second_override),
970 stride: 4,
971 },
972 },
973 nowhere,
974 );
975
976 let mut validator = super::valid::Validator::new(
977 super::valid::ValidationFlags::all(),
978 super::valid::Capabilities::all(),
979 );
980
981 assert!(validator.validate(&module).is_ok());
982 compact(&mut module, KeepUnused::Yes);
983 assert!(validator.validate(&module).is_ok());
984}
985
986#[test]
987fn array_length_expression() {
988 let mut module: crate::Module = Default::default();
989 let ty_u32 = module.types.insert(
990 crate::Type {
991 name: None,
992 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
993 },
994 crate::Span::default(),
995 );
996 let _unused_zero = module.global_expressions.append(
997 crate::Expression::Literal(crate::Literal::U32(0)),
998 crate::Span::default(),
999 );
1000 let one = module.global_expressions.append(
1001 crate::Expression::Literal(crate::Literal::U32(1)),
1002 crate::Span::default(),
1003 );
1004 let override_one = module.overrides.append(
1005 crate::Override {
1006 name: None,
1007 id: None,
1008 ty: ty_u32,
1009 init: Some(one),
1010 },
1011 crate::Span::default(),
1012 );
1013 let _ty_array = module.types.insert(
1014 crate::Type {
1015 name: Some("array<u32, 1>".to_string()),
1016 inner: crate::TypeInner::Array {
1017 base: ty_u32,
1018 size: crate::ArraySize::Pending(override_one),
1019 stride: 4,
1020 },
1021 },
1022 crate::Span::default(),
1023 );
1024
1025 let mut validator = super::valid::Validator::new(
1026 super::valid::ValidationFlags::all(),
1027 super::valid::Capabilities::all(),
1028 );
1029
1030 assert!(validator.validate(&module).is_ok());
1031 compact(&mut module, KeepUnused::Yes);
1032 assert!(validator.validate(&module).is_ok());
1033}
1034
1035#[test]
1036fn global_expression_override() {
1037 let mut module: crate::Module = Default::default();
1038 let ty_u32 = module.types.insert(
1039 crate::Type {
1040 name: None,
1041 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1042 },
1043 crate::Span::default(),
1044 );
1045
1046 let expr1 = module.global_expressions.append(
1050 crate::Expression::Literal(crate::Literal::U32(1)),
1051 crate::Span::default(),
1052 );
1053
1054 let o = module.overrides.append(
1056 crate::Override {
1057 name: None,
1058 id: Some(42),
1059 ty: ty_u32,
1060 init: Some(expr1),
1061 },
1062 crate::Span::default(),
1063 );
1064
1065 let expr2 = module
1067 .global_expressions
1068 .append(crate::Expression::Override(o), crate::Span::default());
1069
1070 let _p = module.overrides.append(
1072 crate::Override {
1073 name: Some("p".to_string()),
1074 id: None,
1075 ty: ty_u32,
1076 init: Some(expr2),
1077 },
1078 crate::Span::default(),
1079 );
1080
1081 let mut validator = super::valid::Validator::new(
1082 super::valid::ValidationFlags::all(),
1083 super::valid::Capabilities::all(),
1084 );
1085
1086 assert!(validator.validate(&module).is_ok());
1087 compact(&mut module, KeepUnused::Yes);
1088 assert!(validator.validate(&module).is_ok());
1089}
1090
1091#[test]
1092fn local_expression_override() {
1093 let mut module: crate::Module = Default::default();
1094 let ty_u32 = module.types.insert(
1095 crate::Type {
1096 name: None,
1097 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1098 },
1099 crate::Span::default(),
1100 );
1101
1102 let expr1 = module.global_expressions.append(
1105 crate::Expression::Literal(crate::Literal::U32(1)),
1106 crate::Span::default(),
1107 );
1108
1109 let _unused_override = module.overrides.append(
1111 crate::Override {
1112 name: None,
1113 id: Some(41),
1114 ty: ty_u32,
1115 init: None,
1116 },
1117 crate::Span::default(),
1118 );
1119
1120 let o = module.overrides.append(
1122 crate::Override {
1123 name: None,
1124 id: Some(42),
1125 ty: ty_u32,
1126 init: Some(expr1),
1127 },
1128 crate::Span::default(),
1129 );
1130
1131 let mut fun = crate::Function {
1132 result: Some(crate::FunctionResult {
1133 ty: ty_u32,
1134 binding: None,
1135 }),
1136 ..crate::Function::default()
1137 };
1138
1139 let o_expr = fun
1141 .expressions
1142 .append(crate::Expression::Override(o), crate::Span::default());
1143 fun.body.push(
1144 crate::Statement::Return {
1145 value: Some(o_expr),
1146 },
1147 crate::Span::default(),
1148 );
1149
1150 module.functions.append(fun, crate::Span::default());
1151
1152 let mut validator = super::valid::Validator::new(
1153 super::valid::ValidationFlags::all(),
1154 super::valid::Capabilities::all(),
1155 );
1156
1157 assert!(validator.validate(&module).is_ok());
1158 compact(&mut module, KeepUnused::Yes);
1159 assert!(validator.validate(&module).is_ok());
1160}
1161
1162#[test]
1163fn unnamed_constant_type() {
1164 let mut module = crate::Module::default();
1165 let nowhere = crate::Span::default();
1166
1167 let ty_u32 = module.types.insert(
1169 crate::Type {
1170 name: None,
1171 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1172 },
1173 nowhere,
1174 );
1175
1176 let ty_vec_u32 = module.types.insert(
1178 crate::Type {
1179 name: None,
1180 inner: crate::TypeInner::Vector {
1181 size: crate::VectorSize::Bi,
1182 scalar: crate::Scalar::U32,
1183 },
1184 },
1185 nowhere,
1186 );
1187
1188 let unnamed_init = module
1189 .global_expressions
1190 .append(crate::Expression::Literal(crate::Literal::U32(0)), nowhere);
1191
1192 let unnamed_constant = module.constants.append(
1193 crate::Constant {
1194 name: None,
1195 ty: ty_u32,
1196 init: unnamed_init,
1197 },
1198 nowhere,
1199 );
1200
1201 let unnamed_constant_expr = module
1205 .global_expressions
1206 .append(crate::Expression::Constant(unnamed_constant), nowhere);
1207 let named_init = module.global_expressions.append(
1208 crate::Expression::Splat {
1209 size: crate::VectorSize::Bi,
1210 value: unnamed_constant_expr,
1211 },
1212 nowhere,
1213 );
1214
1215 let _named_constant = module.constants.append(
1216 crate::Constant {
1217 name: Some("totally_named".to_string()),
1218 ty: ty_vec_u32,
1219 init: named_init,
1220 },
1221 nowhere,
1222 );
1223
1224 let mut validator = super::valid::Validator::new(
1225 super::valid::ValidationFlags::all(),
1226 super::valid::Capabilities::all(),
1227 );
1228
1229 assert!(validator.validate(&module).is_ok());
1230 compact(&mut module, KeepUnused::Yes);
1231 assert!(validator.validate(&module).is_ok());
1232}
1233
1234#[test]
1235fn unnamed_override_type() {
1236 let mut module = crate::Module::default();
1237 let nowhere = crate::Span::default();
1238
1239 let ty_u32 = module.types.insert(
1241 crate::Type {
1242 name: None,
1243 inner: crate::TypeInner::Scalar(crate::Scalar::U32),
1244 },
1245 nowhere,
1246 );
1247
1248 let ty_i32 = module.types.insert(
1250 crate::Type {
1251 name: None,
1252 inner: crate::TypeInner::Scalar(crate::Scalar::I32),
1253 },
1254 nowhere,
1255 );
1256
1257 let unnamed_init = module
1258 .global_expressions
1259 .append(crate::Expression::Literal(crate::Literal::U32(0)), nowhere);
1260
1261 let unnamed_override = module.overrides.append(
1262 crate::Override {
1263 name: None,
1264 id: Some(42),
1265 ty: ty_u32,
1266 init: Some(unnamed_init),
1267 },
1268 nowhere,
1269 );
1270
1271 let unnamed_override_expr = module
1275 .global_expressions
1276 .append(crate::Expression::Override(unnamed_override), nowhere);
1277 let named_init = module.global_expressions.append(
1278 crate::Expression::As {
1279 expr: unnamed_override_expr,
1280 kind: crate::ScalarKind::Sint,
1281 convert: None,
1282 },
1283 nowhere,
1284 );
1285
1286 let _named_override = module.overrides.append(
1287 crate::Override {
1288 name: Some("totally_named".to_string()),
1289 id: None,
1290 ty: ty_i32,
1291 init: Some(named_init),
1292 },
1293 nowhere,
1294 );
1295
1296 let mut validator = super::valid::Validator::new(
1297 super::valid::ValidationFlags::all(),
1298 super::valid::Capabilities::all(),
1299 );
1300
1301 assert!(validator.validate(&module).is_ok());
1302 compact(&mut module, KeepUnused::Yes);
1303 assert!(validator.validate(&module).is_ok());
1304}