adding per function dead code elimination

This commit is contained in:
mlokr 2024-05-12 14:56:59 +02:00
parent f87959aacb
commit bc59886428
3 changed files with 68 additions and 42 deletions

View file

@ -1,6 +1,6 @@
Ty := struct { Ty := struct {
a: int a: int,
b: int b: int,
} }
main := fn(): int { main := fn(): int {

View file

@ -42,7 +42,7 @@ pub mod bt {
builtin_type! { builtin_type! {
VOID; VOID;
UNREACHABLE; NEVER;
INT; INT;
BOOL; BOOL;
} }
@ -393,6 +393,8 @@ impl<'a> Codegen<'a> {
match *expr { match *expr {
E::Ident { name: "int", .. } => bt::INT, E::Ident { name: "int", .. } => bt::INT,
E::Ident { name: "bool", .. } => bt::BOOL, E::Ident { name: "bool", .. } => bt::BOOL,
E::Ident { name: "void", .. } => bt::VOID,
E::Ident { name: "never", .. } => bt::NEVER,
E::Ident { id, .. } => { E::Ident { id, .. } => {
let index = self let index = self
.records .records
@ -418,8 +420,9 @@ impl<'a> Codegen<'a> {
let stack = self.alloc_stack(size as u32); let stack = self.alloc_stack(size as u32);
let mut field_values = fields let mut field_values = fields
.iter() .iter()
.map(|(name, field)| (*name, self.expr(field, None).unwrap())) .map(|(name, field)| self.expr(field, None).map(|v| (*name, v)))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()?;
let decl_fields = self.records[idx as usize].fields.clone(); let decl_fields = self.records[idx as usize].fields.clone();
let mut offset = 0; let mut offset = 0;
for (name, ty) in decl_fields.as_ref() { for (name, ty) in decl_fields.as_ref() {
@ -442,7 +445,7 @@ impl<'a> Codegen<'a> {
}) })
} }
E::Field { target, field } => { E::Field { target, field } => {
let target = self.expr(target, None).unwrap(); let target = self.expr(target, None)?;
let TypeKind::Struct(idx) = TypeKind::from_ty(target.ty) else { let TypeKind::Struct(idx) = TypeKind::from_ty(target.ty) else {
panic!("expected struct, got {:?}", target.ty); panic!("expected struct, got {:?}", target.ty);
}; };
@ -479,12 +482,12 @@ impl<'a> Codegen<'a> {
.map(|&(name, ty)| (name.into(), self.ty(&ty))) .map(|&(name, ty)| (name.into(), self.ty(&ty)))
.collect(); .collect();
self.records.push(Struct { id: *id, fields }); self.records.push(Struct { id: *id, fields });
None Some(Value::VOID)
} }
E::UnOp { E::UnOp {
op: T::Amp, val, .. op: T::Amp, val, ..
} => { } => {
let val = self.expr(val, None).unwrap(); let val = self.expr(val, None)?;
match val.loc { match val.loc {
Loc::StackRef(off) => { Loc::StackRef(off) => {
let reg = self.gpa.allocate(); let reg = self.gpa.allocate();
@ -504,7 +507,7 @@ impl<'a> Codegen<'a> {
E::UnOp { E::UnOp {
op: T::Star, val, .. op: T::Star, val, ..
} => { } => {
let val = self.expr(val, None).unwrap(); let val = self.expr(val, None)?;
let reg = self.loc_to_reg(val.loc); let reg = self.loc_to_reg(val.loc);
match TypeKind::from_ty(val.ty) { match TypeKind::from_ty(val.ty) {
TypeKind::Pointer(ty) => Some(Value { TypeKind::Pointer(ty) => Some(Value {
@ -542,7 +545,9 @@ impl<'a> Codegen<'a> {
self.gpa.init_callee(); self.gpa.init_callee();
self.ret = self.ty(ret); self.ret = self.ty(ret);
log::dbg!("fn-body"); log::dbg!("fn-body");
self.expr(body, None); if self.expr(body, None).is_some() {
panic!("expected all paths in the fucntion {name} to return");
}
self.vars.clear(); self.vars.clear();
log::dbg!("fn-relocs"); log::dbg!("fn-relocs");
self.reloc_stack(); self.reloc_stack();
@ -553,28 +558,28 @@ impl<'a> Codegen<'a> {
self.ret(); self.ret();
self.stack_size = 0; self.stack_size = 0;
self.vars.clear(); self.vars.clear();
None Some(Value::VOID)
} }
E::BinOp { E::BinOp {
left: E::Ident { id, .. }, left: E::Ident { id, .. },
op: T::Decl, op: T::Decl,
right, right,
} => { } => {
let val = self.expr(right, None).unwrap(); let val = self.expr(right, None)?;
let loc = self.make_loc_owned(val.loc, val.ty); let loc = self.make_loc_owned(val.loc, val.ty);
let loc = self.ensure_spilled(loc); let loc = self.ensure_spilled(loc);
self.vars.push(Variable { self.vars.push(Variable {
id: *id, id: *id,
value: Value { ty: val.ty, loc }, value: Value { ty: val.ty, loc },
}); });
None Some(Value::VOID)
} }
E::Call { E::Call {
func: E::Ident { id, .. }, func: E::Ident { id, .. },
args, args,
} => { } => {
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
let arg = self.expr(arg, None).unwrap(); let arg = self.expr(arg, None)?;
let reg = self.loc_to_reg(arg.loc); let reg = self.loc_to_reg(arg.loc);
self.code.encode(instrs::cp(i as Reg + 2, reg.0)); self.code.encode(instrs::cp(i as Reg + 2, reg.0));
self.gpa.free(reg); self.gpa.free(reg);
@ -601,7 +606,7 @@ impl<'a> Codegen<'a> {
} }
E::Return { val, .. } => { E::Return { val, .. } => {
if let Some(val) = val { if let Some(val) = val {
let val = self.expr(val, Some(self.ret)).unwrap(); let val = self.expr(val, Some(self.ret))?;
if val.ty != self.ret { if val.ty != self.ret {
panic!("expected {:?}, got {:?}", self.ret, val.ty); panic!("expected {:?}, got {:?}", self.ret, val.ty);
} }
@ -623,11 +628,11 @@ impl<'a> Codegen<'a> {
} }
E::Block { stmts, .. } => { E::Block { stmts, .. } => {
for stmt in stmts { for stmt in stmts {
if let Some(Loc::Reg(reg)) = self.expr(stmt, None).map(|v| v.loc) { if let Loc::Reg(reg) = self.expr(stmt, None)?.loc {
self.gpa.free(reg); self.gpa.free(reg);
} }
} }
None Some(Value::VOID)
} }
E::Number { value, .. } => Some(Value { E::Number { value, .. } => Some(Value {
ty: expeted.unwrap_or(bt::INT), ty: expeted.unwrap_or(bt::INT),
@ -635,58 +640,68 @@ impl<'a> Codegen<'a> {
}), }),
E::If { E::If {
cond, then, else_, .. cond, then, else_, ..
} => { } => 'b: {
log::dbg!("if-cond"); log::dbg!("if-cond");
let cond = self.expr(cond, Some(bt::BOOL)).unwrap(); let cond = self.expr(cond, Some(bt::BOOL))?;
let reg = self.loc_to_reg(cond.loc); let reg = self.loc_to_reg(cond.loc);
let jump_offset = self.code.code.len() as u32; let jump_offset = self.code.code.len() as u32;
self.code.encode(instrs::jeq(reg.0, 0, 0)); self.code.encode(instrs::jeq(reg.0, 0, 0));
self.gpa.free(reg); self.gpa.free(reg);
log::dbg!("if-then"); log::dbg!("if-then");
self.expr(then, None); let then_unreachable = self.expr(then, None).is_none();
let mut else_unreachable = false;
let jump; let mut jump = self.code.code.len() as i16 - jump_offset as i16;
if let Some(else_) = else_ { if let Some(else_) = else_ {
log::dbg!("if-else"); log::dbg!("if-else");
let else_jump_offset = self.code.code.len() as u32; let else_jump_offset = self.code.code.len() as u32;
self.code.encode(instrs::jmp(0)); if !then_unreachable {
self.code.encode(instrs::jmp(0));
jump = self.code.code.len() as i16 - jump_offset as i16;
}
jump = self.code.code.len() as i16 - jump_offset as i16; else_unreachable = self.expr(else_, None).is_none();
self.expr(else_, None); if !then_unreachable {
let jump = self.code.code.len() as i32 - else_jump_offset as i32;
let jump = self.code.code.len() as i32 - else_jump_offset as i32; log::dbg!("if-else-jump: {}", jump);
log::dbg!("if-else-jump: {}", jump); self.code.code[else_jump_offset as usize + 1..][..4]
self.code.code[else_jump_offset as usize + 1..][..4] .copy_from_slice(&jump.to_ne_bytes());
.copy_from_slice(&jump.to_ne_bytes()); }
} else {
jump = self.code.code.len() as i16 - jump_offset as i16;
} }
log::dbg!("if-then-jump: {}", jump); log::dbg!("if-then-jump: {}", jump);
self.code.code[jump_offset as usize + 3..][..2] self.code.code[jump_offset as usize + 3..][..2]
.copy_from_slice(&jump.to_ne_bytes()); .copy_from_slice(&jump.to_ne_bytes());
None if then_unreachable && else_unreachable {
break 'b None;
}
Some(Value::VOID)
} }
E::Loop { body, .. } => { E::Loop { body, .. } => 'a: {
log::dbg!("loop"); log::dbg!("loop");
let loop_start = self.code.code.len() as u32; let loop_start = self.code.code.len() as u32;
self.loops.push(Loop { self.loops.push(Loop {
offset: loop_start, offset: loop_start,
relocs: Default::default(), relocs: Default::default(),
}); });
self.expr(body, None); let body_unreachable = self.expr(body, None).is_none();
log::dbg!("loop-end"); log::dbg!("loop-end");
let loop_end = self.code.code.len(); if !body_unreachable {
self.code let loop_end = self.code.code.len();
.encode(instrs::jmp(loop_start as i32 - loop_end as i32)); self.code
.encode(instrs::jmp(loop_start as i32 - loop_end as i32));
}
let loop_end = self.code.code.len() as u32; let loop_end = self.code.code.len() as u32;
let loop_ = self.loops.pop().unwrap(); let loop_ = self.loops.pop().unwrap();
let is_unreachable = loop_.relocs.is_empty();
for reloc in loop_.relocs { for reloc in loop_.relocs {
let dest = &mut self.code.code let dest = &mut self.code.code
[reloc.offset as usize + reloc.instr_offset as usize..] [reloc.offset as usize + reloc.instr_offset as usize..]
@ -695,7 +710,12 @@ impl<'a> Codegen<'a> {
dest.copy_from_slice(&offset.to_ne_bytes()); dest.copy_from_slice(&offset.to_ne_bytes());
} }
None if is_unreachable {
log::dbg!("infinite loop");
break 'a None;
}
Some(Value::VOID)
} }
E::Break { .. } => { E::Break { .. } => {
let loop_ = self.loops.last_mut().unwrap(); let loop_ = self.loops.last_mut().unwrap();
@ -716,8 +736,8 @@ impl<'a> Codegen<'a> {
None None
} }
E::BinOp { left, op, right } => { E::BinOp { left, op, right } => {
let left = self.expr(left, expeted).unwrap(); let left = self.expr(left, expeted)?;
let right = self.expr(right, Some(left.ty)).unwrap(); let right = self.expr(right, Some(left.ty))?;
if op == T::Assign { if op == T::Assign {
return self.assign(left, right); return self.assign(left, right);
} }
@ -776,7 +796,7 @@ impl<'a> Codegen<'a> {
_ => unimplemented!(), _ => unimplemented!(),
} }
self.gpa.free(rhs); self.gpa.free(rhs);
None Some(Value::VOID)
} }
fn get_or_reserve_label(&mut self, name: Ident) -> LabelId { fn get_or_reserve_label(&mut self, name: Ident) -> LabelId {
@ -912,6 +932,13 @@ pub struct Value {
loc: Loc, loc: Loc,
} }
impl Value {
const VOID: Self = Self {
ty: bt::VOID,
loc: Loc::Imm(0),
};
}
#[derive(Debug)] #[derive(Debug)]
enum Loc { enum Loc {
Reg(LinReg), Reg(LinReg),
@ -1001,7 +1028,6 @@ mod tests {
let mut out = Vec::new(); let mut out = Vec::new();
codegen.dump(&mut out).unwrap(); codegen.dump(&mut out).unwrap();
std::fs::write("test.bin", &out).unwrap();
use std::fmt::Write; use std::fmt::Write;
let mut stack = [0_u64; 128]; let mut stack = [0_u64; 128];

Binary file not shown.