adding better dead code elimination
This commit is contained in:
parent
5b23a0661b
commit
3d721812f0
|
@ -1100,3 +1100,19 @@ main := fn(): uint {
|
||||||
return *mem
|
return *mem
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### dead_code_in_loop
|
||||||
|
```hb
|
||||||
|
main := fn(): uint {
|
||||||
|
n := 0
|
||||||
|
|
||||||
|
loop if n < 10 {
|
||||||
|
if n < 10 break
|
||||||
|
n += 1
|
||||||
|
} else break
|
||||||
|
|
||||||
|
loop if n == 0 return n
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -12,7 +12,7 @@ use {
|
||||||
TypeParser, TypedReloc, Types,
|
TypeParser, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{assert_matches::debug_assert_matches, fmt::Display, usize},
|
core::{assert_matches::debug_assert_matches, fmt::Display},
|
||||||
};
|
};
|
||||||
|
|
||||||
type Offset = u32;
|
type Offset = u32;
|
||||||
|
|
|
@ -316,13 +316,10 @@ impl Nodes {
|
||||||
fn iter_peeps(&mut self, mut fuel: usize) {
|
fn iter_peeps(&mut self, mut fuel: usize) {
|
||||||
self.lock(NEVER);
|
self.lock(NEVER);
|
||||||
|
|
||||||
for n in self[VOID].outputs.clone() {
|
let mut stack = self
|
||||||
if self[n].kind == Kind::Arg {
|
.iter()
|
||||||
self.lock(n);
|
.filter_map(|(id, node)| node.kind.is_peeped().then_some(id))
|
||||||
}
|
.collect::<Vec<_>>();
|
||||||
}
|
|
||||||
|
|
||||||
let mut stack = self.iter().map(|(id, ..)| id).collect::<Vec<_>>();
|
|
||||||
stack.iter().for_each(|&s| self.lock(s));
|
stack.iter().for_each(|&s| self.lock(s));
|
||||||
|
|
||||||
while fuel != 0
|
while fuel != 0
|
||||||
|
@ -336,20 +333,14 @@ impl Nodes {
|
||||||
if let Some(new) = new {
|
if let Some(new) = new {
|
||||||
let prev_len = stack.len();
|
let prev_len = stack.len();
|
||||||
for &i in self[new].outputs.iter().chain(self[new].inputs.iter()) {
|
for &i in self[new].outputs.iter().chain(self[new].inputs.iter()) {
|
||||||
if self[i].lock_rc == 0 {
|
if self[i].kind.is_peeped() && self[i].lock_rc == 0 {
|
||||||
stack.push(i)
|
stack.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.iter().skip(prev_len).for_each(|&n| self.lock(n));
|
stack.iter().skip(prev_len).for_each(|&n| self.lock(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for n in self[VOID].outputs.clone() {
|
|
||||||
if self[n].kind == Kind::Arg {
|
|
||||||
self.unlock(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.unlock(NEVER);
|
self.unlock(NEVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,15 +455,74 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K::If => {
|
K::If => {
|
||||||
let cond = self[target].inputs[1];
|
if self[target].ty == ty::Id::VOID {
|
||||||
|
let &[ctrl, cond] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
if let K::CInt { value } = self[cond].kind {
|
if let K::CInt { value } = self[cond].kind {
|
||||||
let ty = if value == 0 {
|
let ty = if value == 0 {
|
||||||
ty::Id::LEFT_UNREACHABLE
|
ty::Id::LEFT_UNREACHABLE
|
||||||
} else {
|
} else {
|
||||||
ty::Id::RIGHT_UNREACHABLE
|
ty::Id::RIGHT_UNREACHABLE
|
||||||
};
|
};
|
||||||
return Some(self.new_node_nop(ty, K::If, [self[target].inputs[0], cond]));
|
return Some(self.new_node_nop(ty, K::If, [ctrl, cond]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'b: {
|
||||||
|
let mut cursor = ctrl;
|
||||||
|
let ty = loop {
|
||||||
|
if cursor == ENTRY {
|
||||||
|
break 'b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do more inteligent checks on the condition
|
||||||
|
if self[cursor].kind == Kind::Then
|
||||||
|
&& self[self[cursor].inputs[0]].inputs[1] == cond
|
||||||
|
{
|
||||||
|
break ty::Id::RIGHT_UNREACHABLE;
|
||||||
|
}
|
||||||
|
if self[cursor].kind == Kind::Else
|
||||||
|
&& self[self[cursor].inputs[0]].inputs[1] == cond
|
||||||
|
{
|
||||||
|
break ty::Id::LEFT_UNREACHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = idom(self, cursor);
|
||||||
|
};
|
||||||
|
|
||||||
|
return Some(self.new_node_nop(ty, K::If, [ctrl, cond]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Then => {
|
||||||
|
if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE {
|
||||||
|
return Some(NEVER);
|
||||||
|
} else if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE {
|
||||||
|
return Some(self[self[target].inputs[0]].inputs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Else => {
|
||||||
|
if self[self[target].inputs[0]].ty == ty::Id::RIGHT_UNREACHABLE {
|
||||||
|
return Some(NEVER);
|
||||||
|
} else if self[self[target].inputs[0]].ty == ty::Id::LEFT_UNREACHABLE {
|
||||||
|
return Some(self[self[target].inputs[0]].inputs[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Region => {
|
||||||
|
let (ctrl, side) = match self[target].inputs.as_slice() {
|
||||||
|
[NEVER, NEVER] => return Some(NEVER),
|
||||||
|
&[NEVER, ctrl] => (ctrl, 2),
|
||||||
|
&[ctrl, NEVER] => (ctrl, 1),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lock(target);
|
||||||
|
for i in self[target].outputs.clone() {
|
||||||
|
if self[i].kind == Kind::Phi {
|
||||||
|
self.replace(i, self[i].inputs[side]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.unlock(target);
|
||||||
|
|
||||||
|
return Some(ctrl);
|
||||||
}
|
}
|
||||||
K::Phi => {
|
K::Phi => {
|
||||||
let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() };
|
let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
|
@ -532,6 +582,10 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K::Loop => {
|
K::Loop => {
|
||||||
|
if self[target].inputs[0] == NEVER {
|
||||||
|
return Some(NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
if self[target].inputs[1] == NEVER {
|
if self[target].inputs[1] == NEVER {
|
||||||
self.lock(target);
|
self.lock(target);
|
||||||
for o in self[target].outputs.clone() {
|
for o in self[target].outputs.clone() {
|
||||||
|
@ -554,6 +608,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace(&mut self, target: Nid, with: Nid) {
|
fn replace(&mut self, target: Nid, with: Nid) {
|
||||||
|
debug_assert_ne!(target, with, "{:?}", self[target]);
|
||||||
let mut back_press = 0;
|
let mut back_press = 0;
|
||||||
for i in 0..self[target].outputs.len() {
|
for i in 0..self[target].outputs.len() {
|
||||||
let out = self[target].outputs[i - back_press];
|
let out = self[target].outputs[i - back_press];
|
||||||
|
@ -570,7 +625,7 @@ impl Nodes {
|
||||||
|
|
||||||
fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid {
|
fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid {
|
||||||
self.remove_node_lookup(target);
|
self.remove_node_lookup(target);
|
||||||
debug_assert_ne!(self[target].inputs[inp_index], with);
|
debug_assert_ne!(self[target].inputs[inp_index], with, "{:?}", self[target]);
|
||||||
|
|
||||||
let prev = self[target].inputs[inp_index];
|
let prev = self[target].inputs[inp_index];
|
||||||
self[target].inputs[inp_index] = with;
|
self[target].inputs[inp_index] = with;
|
||||||
|
@ -1040,6 +1095,10 @@ impl Kind {
|
||||||
fn ends_basic_block(&self) -> bool {
|
fn ends_basic_block(&self) -> bool {
|
||||||
matches!(self, Self::Return | Self::If | Self::End)
|
matches!(self, Self::Return | Self::If | Self::End)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_peeped(&self) -> bool {
|
||||||
|
!matches!(self, Self::End | Self::Arg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Kind {
|
impl fmt::Display for Kind {
|
||||||
|
@ -4735,5 +4794,6 @@ mod tests {
|
||||||
pointer_opts;
|
pointer_opts;
|
||||||
conditional_stores;
|
conditional_stores;
|
||||||
loop_stores;
|
loop_stores;
|
||||||
|
dead_code_in_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,15 +287,6 @@ impl BitSet {
|
||||||
self.data.resize(new_len, 0);
|
self.data.resize(new_len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unset(&mut self, idx: Nid) -> bool {
|
|
||||||
let idx = idx as usize;
|
|
||||||
let data_idx = idx / Self::ELEM_SIZE;
|
|
||||||
let sub_idx = idx % Self::ELEM_SIZE;
|
|
||||||
let prev = self.data[data_idx] & (1 << sub_idx);
|
|
||||||
self.data[data_idx] &= !(1 << sub_idx);
|
|
||||||
prev != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, idx: Nid) -> bool {
|
pub fn set(&mut self, idx: Nid) -> bool {
|
||||||
let idx = idx as usize;
|
let idx = idx as usize;
|
||||||
let data_idx = idx / Self::ELEM_SIZE;
|
let data_idx = idx / Self::ELEM_SIZE;
|
||||||
|
|
6
lang/tests/son_tests_dead_code_in_loop.txt
Normal file
6
lang/tests/son_tests_dead_code_in_loop.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
main:
|
||||||
|
LI64 r1, 0d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 29
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue