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::ir::prelude::*;
use crate::{
ir::InstData,
ty::{signal_ty, Type},
};
pub struct ConstantFoldingPass;
impl ConstantFoldingPass {
pub fn run_on_function(func: &mut Function) -> bool {
let mut builder = FunctionBuilder::new(func);
let mut modified = false;
let mut insts = vec![];
for bb in builder.func.layout.blocks() {
for inst in builder.func.layout.insts(bb) {
insts.push(inst);
}
}
for inst in insts {
modified |= Self::run_on_inst(&mut builder, inst);
}
modified
}
pub fn run_on_process(prok: &mut Process) -> bool {
let mut builder = ProcessBuilder::new(prok);
let mut modified = false;
let mut insts = vec![];
for bb in builder.prok.layout.blocks() {
for inst in builder.prok.layout.insts(bb) {
insts.push(inst);
}
}
for inst in insts {
modified |= Self::run_on_inst(&mut builder, inst);
}
modified
}
pub fn run_on_entity(entity: &mut Entity) -> bool {
let mut builder = EntityBuilder::new(entity);
let mut modified = false;
for inst in builder.entity.layout.insts().collect::<Vec<_>>() {
modified |= Self::run_on_inst(&mut builder, inst);
}
modified
}
pub fn run_on_inst(builder: &mut impl UnitBuilder, inst: Inst) -> bool {
if !builder.dfg().has_result(inst) {
return false;
}
builder.insert_after(inst);
let value = builder.dfg().inst_result(inst);
let ty = builder.dfg().value_type(value);
let replacement = match builder.dfg()[inst] {
InstData::Binary { opcode, args, .. } => {
Self::fold_binary(builder, opcode, ty.clone(), args)
}
_ => None,
};
if let Some(replacement) = replacement {
let new_ty = builder.dfg().value_type(replacement);
assert!(
ty == new_ty || ty == signal_ty(new_ty),
"types before (lhs) and after (rhs) folding must match"
);
builder.unit_mut().dfg_mut().replace_use(value, replacement);
builder.prune_if_unused(inst);
true
} else {
false
}
}
fn fold_binary(
builder: &mut impl UnitBuilder,
opcode: Opcode,
ty: Type,
args: [Value; 2],
) -> Option<Value> {
if ty.is_int() {
Self::fold_binary_int(builder, opcode, ty.unwrap_int(), args)
} else if ty.is_signal() && ty.unwrap_signal().is_int() {
Self::fold_binary_int(builder, opcode, ty.unwrap_signal().unwrap_int(), args)
} else {
None
}
}
fn fold_binary_int(
builder: &mut impl UnitBuilder,
opcode: Opcode,
width: usize,
args: [Value; 2],
) -> Option<Value> {
let inst0 = builder.dfg().get_value_inst(args[0])?;
let inst1 = builder.dfg().get_value_inst(args[1])?;
let imm0 = builder.dfg()[inst0].get_const_int()?;
let imm1 = builder.dfg()[inst1].get_const_int()?;
let result = match opcode {
Opcode::Add => imm0 + imm1,
_ => return None,
};
Some(builder.ins().const_int(width, result))
}
}