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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::{Block, Context, Function, Instruction, IrError, Module, Value, ValueDatum};
use std::collections::{HashMap, HashSet};
fn can_eliminate_instruction(context: &Context, val: Value) -> bool {
let inst = val.get_instruction(context).unwrap();
!inst.is_terminator() && !inst.may_have_side_effect()
}
pub fn dce(context: &mut Context, function: &Function) -> Result<bool, IrError> {
let mut num_uses: HashMap<Value, (Block, u32)> = HashMap::new();
for (block, inst) in function.instruction_iter(context) {
let opds = inst.get_instruction(context).unwrap().get_operands();
for v in opds {
match context.values[v.0].value {
ValueDatum::Instruction(_) => {
num_uses
.entry(v)
.and_modify(|(_block, count)| *count += 1)
.or_insert((block, 1));
}
ValueDatum::Constant(_) | ValueDatum::Argument(_) => (),
}
}
}
let mut worklist = function
.instruction_iter(context)
.filter(|(_block, inst)| num_uses.get(inst).is_none())
.collect::<Vec<_>>();
let mut modified = false;
while !worklist.is_empty() {
let (in_block, dead) = worklist.pop().unwrap();
if !can_eliminate_instruction(context, dead) {
continue;
}
let opds = dead.get_instruction(context).unwrap().get_operands();
for v in opds {
match context.values[v.0].value {
ValueDatum::Instruction(_) => {
let (block, nu) = num_uses.get_mut(&v).unwrap();
*nu -= 1;
if *nu == 0 {
worklist.push((*block, v));
}
}
ValueDatum::Constant(_) | ValueDatum::Argument(_) => (),
}
}
in_block.remove_instruction(context, dead);
modified = true;
}
Ok(modified)
}
pub fn func_dce(context: &mut Context, module: &Module, entry_fns: &[Function]) -> bool {
fn grow_called_function_set(
context: &Context,
caller: Function,
called_set: &mut HashSet<Function>,
) {
if called_set.insert(caller) {
for func in caller
.instruction_iter(context)
.filter_map(|(_block, ins_value)| {
ins_value
.get_instruction(context)
.and_then(|ins| match ins {
Instruction::Call(f, _args) => Some(f),
_otherwise => None,
})
})
{
grow_called_function_set(context, *func, called_set);
}
}
}
let mut called_fns: HashSet<Function> = HashSet::new();
for entry_fn in entry_fns {
grow_called_function_set(context, *entry_fn, &mut called_fns);
}
let dead_fns = module
.function_iter(context)
.filter(|f| !called_fns.contains(f))
.collect::<Vec<_>>();
let modified = !dead_fns.is_empty();
for dead_fn in dead_fns {
module.remove_function(context, &dead_fn);
}
modified
}