naga/compact/
functions.rs

1use super::arena::HandleSet;
2use super::{FunctionMap, ModuleMap};
3
4pub struct FunctionTracer<'a> {
5    pub function: &'a crate::Function,
6    pub constants: &'a crate::Arena<crate::Constant>,
7    pub overrides: &'a crate::Arena<crate::Override>,
8
9    pub functions_pending: &'a mut HandleSet<crate::Function>,
10    pub functions_used: &'a mut HandleSet<crate::Function>,
11    pub types_used: &'a mut HandleSet<crate::Type>,
12    pub global_variables_used: &'a mut HandleSet<crate::GlobalVariable>,
13    pub constants_used: &'a mut HandleSet<crate::Constant>,
14    pub overrides_used: &'a mut HandleSet<crate::Override>,
15    pub global_expressions_used: &'a mut HandleSet<crate::Expression>,
16
17    /// Function-local expressions used.
18    pub expressions_used: HandleSet<crate::Expression>,
19}
20
21impl FunctionTracer<'_> {
22    pub fn trace_call(&mut self, function: crate::Handle<crate::Function>) {
23        if !self.functions_used.contains(function) {
24            self.functions_used.insert(function);
25            self.functions_pending.insert(function);
26        }
27    }
28
29    pub fn trace(&mut self) {
30        for argument in self.function.arguments.iter() {
31            self.types_used.insert(argument.ty);
32        }
33
34        if let Some(ref result) = self.function.result {
35            self.types_used.insert(result.ty);
36        }
37
38        for (_, local) in self.function.local_variables.iter() {
39            self.types_used.insert(local.ty);
40            if let Some(init) = local.init {
41                self.expressions_used.insert(init);
42            }
43        }
44
45        // Treat named expressions as alive, for the sake of our test suite,
46        // which uses `let blah = expr;` to exercise lots of things.
47        for (&value, _name) in &self.function.named_expressions {
48            self.expressions_used.insert(value);
49        }
50
51        self.trace_block(&self.function.body);
52
53        // Given that `trace_block` has marked the expressions used
54        // directly by statements, walk the arena to find all
55        // expressions used, directly or indirectly.
56        self.as_expression().trace_expressions();
57    }
58
59    fn as_expression(&mut self) -> super::expressions::ExpressionTracer<'_> {
60        super::expressions::ExpressionTracer {
61            constants: self.constants,
62            overrides: self.overrides,
63            expressions: &self.function.expressions,
64
65            types_used: self.types_used,
66            global_variables_used: self.global_variables_used,
67            constants_used: self.constants_used,
68            overrides_used: self.overrides_used,
69            expressions_used: &mut self.expressions_used,
70            global_expressions_used: Some(&mut self.global_expressions_used),
71        }
72    }
73}
74
75impl FunctionMap {
76    pub fn compact(
77        &self,
78        function: &mut crate::Function,
79        module_map: &ModuleMap,
80        reuse: &mut crate::NamedExpressions,
81    ) {
82        assert!(reuse.is_empty());
83
84        for argument in function.arguments.iter_mut() {
85            module_map.types.adjust(&mut argument.ty);
86        }
87
88        if let Some(ref mut result) = function.result {
89            module_map.types.adjust(&mut result.ty);
90        }
91
92        for (_, local) in function.local_variables.iter_mut() {
93            log::trace!("adjusting local variable {:?}", local.name);
94            module_map.types.adjust(&mut local.ty);
95            if let Some(ref mut init) = local.init {
96                self.expressions.adjust(init);
97            }
98        }
99
100        // Drop unused expressions, reusing existing storage.
101        function.expressions.retain_mut(|handle, expr| {
102            if self.expressions.used(handle) {
103                module_map.adjust_expression(expr, &self.expressions);
104                true
105            } else {
106                false
107            }
108        });
109
110        // Adjust named expressions.
111        for (mut handle, name) in function.named_expressions.drain(..) {
112            self.expressions.adjust(&mut handle);
113            reuse.insert(handle, name);
114        }
115        core::mem::swap(&mut function.named_expressions, reuse);
116        assert!(reuse.is_empty());
117
118        // Adjust statements.
119        self.adjust_body(function, &module_map.functions);
120    }
121}