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 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, 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;

View file

@ -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;
} }
} }

View file

@ -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;

View file

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