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