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