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
122
123
124
125
126
127
128
use super::*;
use std::ops::*;
/// Default optimizer.
pub struct StandardOptimizer;
impl StandardOptimizer {
pub fn new() -> Self {
Self
}
}
impl Optimizer for StandardOptimizer {
fn postprocess(&mut self, code: &mut Vec<LirElement>) {
let vp = ValidPath::scan(code);
for off in (0..code.len()).rev() {
if !vp.is_valid(off) {
code.remove(off);
}
}
}
fn transform(&mut self, code: &mut Vec<LirElement>) {
while let Some(last) = code.last() {
let scan_back = self.scan_back_for(last);
if scan_back == 0 {
break;
}
let l = code.len().saturating_sub(scan_back);
let view = &mut code[l..];
match view {
// if `Not` is in front of a conditional jump, change condition
// and remove `Not`
[LirElement::Operation(Operator::Operator1(Operator1::Not)), LirElement::Jump {
condition: Some(cond),
..
}] => {
*cond = !*cond;
view.swap(0, 1);
code.pop();
}
// if a constant is pushed before a conditional jump, change condition
// and remove constant
[LirElement::PushConstant { value }, LirElement::Jump {
condition: cond @ Some(_),
..
}] => {
let bval: bool = value.as_ref().clone().into();
if bval == cond.unwrap() {
// always jump
*cond = None;
view.swap(0, 1);
code.pop();
} else {
// never jump
code.pop();
code.pop();
}
}
// if an iterator creation was requested but the instruction before
// already covers it, remove the last create
[LirElement::IterCreateRanged, LirElement::IterCreate]
| [LirElement::IterCreate, LirElement::IterCreate] => {
code.pop();
}
/*
// a jump should not target the next instruction
[LirElement::Jump {
label: jlabel,
..
}, LirElement::Label(tlabel)] if jlabel == tlabel => {
}
*/
// if two constants were pushed before an operation, remove all three instructions
// and push the computed value instead
[LirElement::PushConstant { value: left }, LirElement::PushConstant { value: right }, LirElement::Operation(Operator::Operator2(op))] =>
{
// TODO: avoid clone here
let (left, right) = (left.as_ref().clone(), right.as_ref().clone());
let newval = match op {
Operator2::Add => left.add(right),
Operator2::Sub => left.sub(right),
Operator2::Mul => left.mul(right),
Operator2::Div => left.div(right),
Operator2::Pow => left.pow(right),
Operator2::Rem => left.rem(right),
Operator2::Shl => left.shl(right),
Operator2::Shr => left.shr(right),
Operator2::And => left.bitand(right),
Operator2::Or => left.bitor(right),
Operator2::XOr => left.bitxor(right),
Operator2::Equal => Ok(left.eq(&right).into()),
Operator2::NotEqual => Ok(left.ne(&right).into()),
Operator2::GreaterEqual => Ok(left.ge(&right).into()),
Operator2::GreaterThan => Ok(left.gt(&right).into()),
Operator2::LessEqual => Ok(left.le(&right).into()),
Operator2::LessThan => Ok(left.lt(&right).into()),
}
.unwrap();
view[0] = LirElement::push_constant_owned(newval);
code.pop();
code.pop();
}
_ => break,
}
}
}
fn scan_back_for(&self, lir_element: &LirElement) -> usize {
match lir_element {
LirElement::Jump { .. } => 2,
LirElement::Operation(Operator::Operator2(_)) => 3,
LirElement::IterCreate => 2,
//LirElement::Label(_) => 2,
_ => 0,
}
}
}