adding better dead code elimination

This commit is contained in:
Jakub Doka 2024-10-26 20:29:31 +02:00
parent 5b23a0661b
commit 3d721812f0
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 107 additions and 34 deletions

View file

@ -1100,3 +1100,19 @@ main := fn(): uint {
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
}
```

View file

@ -12,7 +12,7 @@ use {
TypeParser, TypedReloc, Types,
},
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;

View file

@ -316,13 +316,10 @@ impl Nodes {
fn iter_peeps(&mut self, mut fuel: usize) {
self.lock(NEVER);
for n in self[VOID].outputs.clone() {
if self[n].kind == Kind::Arg {
self.lock(n);
}
}
let mut stack = self.iter().map(|(id, ..)| id).collect::<Vec<_>>();
let mut stack = self
.iter()
.filter_map(|(id, node)| node.kind.is_peeped().then_some(id))
.collect::<Vec<_>>();
stack.iter().for_each(|&s| self.lock(s));
while fuel != 0
@ -336,20 +333,14 @@ impl Nodes {
if let Some(new) = new {
let prev_len = stack.len();
for &i in self[new].outputs.iter().chain(self[new].inputs.iter()) {
if self[i].lock_rc == 0 {
stack.push(i)
if self[i].kind.is_peeped() && self[i].lock_rc == 0 {
stack.push(i);
}
}
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);
}
@ -464,16 +455,75 @@ impl Nodes {
}
}
K::If => {
let cond = self[target].inputs[1];
if let K::CInt { value } = self[cond].kind {
let ty = if value == 0 {
ty::Id::LEFT_UNREACHABLE
} else {
ty::Id::RIGHT_UNREACHABLE
};
return Some(self.new_node_nop(ty, K::If, [self[target].inputs[0], cond]));
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 {
let ty = if value == 0 {
ty::Id::LEFT_UNREACHABLE
} else {
ty::Id::RIGHT_UNREACHABLE
};
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 => {
let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() };
@ -532,6 +582,10 @@ impl Nodes {
}
}
K::Loop => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
if self[target].inputs[1] == NEVER {
self.lock(target);
for o in self[target].outputs.clone() {
@ -554,6 +608,7 @@ impl Nodes {
}
fn replace(&mut self, target: Nid, with: Nid) {
debug_assert_ne!(target, with, "{:?}", self[target]);
let mut back_press = 0;
for i in 0..self[target].outputs.len() {
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 {
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];
self[target].inputs[inp_index] = with;
@ -1040,6 +1095,10 @@ impl Kind {
fn ends_basic_block(&self) -> bool {
matches!(self, Self::Return | Self::If | Self::End)
}
fn is_peeped(&self) -> bool {
!matches!(self, Self::End | Self::Arg)
}
}
impl fmt::Display for Kind {
@ -4735,5 +4794,6 @@ mod tests {
pointer_opts;
conditional_stores;
loop_stores;
dead_code_in_loop;
}
}

View file

@ -287,15 +287,6 @@ impl BitSet {
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 {
let idx = idx as usize;
let data_idx = idx / Self::ELEM_SIZE;

View file

@ -0,0 +1,6 @@
main:
LI64 r1, 0d
JALA r0, r31, 0a
code size: 29
ret: 0
status: Ok(())