From 4a7b4e4eadef3296de9cd39279cb529ee9835a08 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Fri, 18 Oct 2024 13:11:11 +0200 Subject: [PATCH] handling conditional stores --- lang/README.md | 17 + lang/src/son.rs | 450 ++++++++++++-------- lang/tests/son_tests_conditional_stores.txt | 24 ++ lang/tests/son_tests_if_statements.txt | 6 +- lang/tests/son_tests_loops.txt | 19 +- lang/tests/son_tests_pointer_opts.txt | 20 +- 6 files changed, 325 insertions(+), 211 deletions(-) create mode 100644 lang/tests/son_tests_conditional_stores.txt diff --git a/lang/README.md b/lang/README.md index 7fd0cbe..86c3c0c 100644 --- a/lang/README.md +++ b/lang/README.md @@ -999,3 +999,20 @@ clobber := fn(cb: ^int): void { return } ``` + +#### conditional_stores +```hb +main := fn(): int { + mem := &1 + + if cond() == 0 { + *mem = 0 + } else { + *mem = 2 + } + + return *mem +} + +cond := fn(): int return 0 +``` diff --git a/lang/src/son.rs b/lang/src/son.rs index 7a3b19a..83c7435 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -14,7 +14,7 @@ use { vc::{BitSet, Vc}, Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types, }, - alloc::{borrow::ToOwned, string::String, vec::Vec}, + alloc::{string::String, vec::Vec}, core::{ assert_matches::debug_assert_matches, cell::RefCell, @@ -279,8 +279,53 @@ impl Nodes { } } K::Phi => { - if self[target].inputs[1] == self[target].inputs[2] { - return Some(self[target].inputs[1]); + let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() }; + + if lhs == rhs { + return Some(lhs); + } + + if self[lhs].kind == Kind::Stre + && self[rhs].kind == Kind::Stre + && self[lhs].ty == self[rhs].ty + && self[lhs].inputs[2] == self[rhs].inputs[2] + && self[lhs].inputs.get(3) == self[rhs].inputs.get(3) + { + let pick_value = self.new_node(self[lhs].ty, Kind::Phi, [ + ctrl, + self[lhs].inputs[1], + self[rhs].inputs[1], + ]); + let mut vc = Vc::from([VOID, pick_value, self[lhs].inputs[2]]); + for &rest in &self[lhs].inputs[3..] { + vc.push(rest); + } + for &rest in &self[rhs].inputs[4..] { + vc.push(rest); + } + return Some(self.new_node(self[lhs].ty, Kind::Stre, vc)); + } + } + K::Stre => { + if self[target].inputs[2] != VOID + && self[target].inputs.len() == 4 + && self[self[target].inputs[3]].kind == Kind::Stre + && self[self[target].inputs[3]].inputs[2] == self[target].inputs[2] + { + return Some(self.modify_input( + self[target].inputs[3], + 1, + self[target].inputs[1], + )); + } + } + K::Load => { + if self[target].inputs.len() == 3 + && self[self[target].inputs[2]].kind == Kind::Stre + && self[self[target].inputs[2]].inputs[2] == self[target].inputs[1] + && self[self[target].inputs[2]].ty == self[target].ty + { + return Some(self[self[target].inputs[2]].inputs[1]); } } _ => {} @@ -574,7 +619,7 @@ impl Nodes { } let [loob, loops @ ..] = loops else { unreachable!() }; - let lvalue = &mut loob.scope[index].value; + let lvalue = &mut loob.scope.vars[index].value; self.load_loop_value(index, lvalue, loops); @@ -631,6 +676,30 @@ impl Nodes { fn iter_mut(&mut self) -> impl Iterator { self.values.iter_mut().flat_map(Result::as_mut) } + + fn lock_scope(&mut self, scope: &Scope) { + if let Some(str) = scope.store { + self.lock(str); + } + for &load in &scope.loads { + self.lock(load); + } + for var in &scope.vars { + self.lock(var.value.id); + } + } + + fn unlock_remove_scope(&mut self, scope: &Scope) { + if let Some(str) = scope.store { + self.unlock_remove(str); + } + for &load in &scope.loads { + self.unlock_remove(load); + } + for var in &scope.vars { + self.unlock_remove(var.value.id); + } + } } impl ops::Index for Nodes { @@ -773,8 +842,8 @@ type IDomDepth = u16; struct Loop { node: Nid, ctrl: [Nid; 2], - ctrl_scope: [Vec; 2], - scope: Vec, + ctrl_scope: [Scope; 2], + scope: Scope, } #[derive(Clone, Copy)] @@ -783,6 +852,13 @@ struct Variable { value: Value, } +#[derive(Default, Clone)] +struct Scope { + vars: Vec, + loads: Vec, + store: Option, +} + #[derive(Default)] struct ItemCtx { file: FileId, @@ -799,9 +875,7 @@ struct ItemCtx { filled: Vec, loops: Vec, - vars: Vec, - store: Option, - loads: Vec, + scope: Scope, clobbered: Vec, ret_relocs: Vec, relocs: Vec, @@ -871,7 +945,6 @@ impl Default for Regalloc { #[derive(Default, Clone, Copy)] struct Value { ty: ty::Id, - off: Offset, var: bool, ptr: bool, id: Nid, @@ -879,8 +952,8 @@ struct Value { impl Value { const NEVER: Option = - Some(Self { ty: ty::Id::NEVER, off: 0, var: false, ptr: false, id: NEVER }); - const VOID: Value = Self { ty: ty::Id::VOID, off: 0, var: false, ptr: false, id: VOID }; + Some(Self { ty: ty::Id::NEVER, var: false, ptr: false, id: NEVER }); + const VOID: Value = Self { ty: ty::Id::VOID, var: false, ptr: false, id: VOID }; pub fn new(id: Nid) -> Self { Self { id, ..Default::default() } @@ -898,11 +971,6 @@ impl Value { pub fn ty(self, ty: impl Into) -> Self { Self { ty: ty.into(), ..self } } - - #[inline(always)] - pub fn off(self, off: Offset) -> Self { - Self { off, ..self } - } } #[derive(Default)] @@ -957,11 +1025,11 @@ impl Codegen { fn store_mem(&mut self, region: Nid, value: Nid) -> Nid { let mut vc = Vc::from([VOID, value, region]); - if let Some(str) = self.ci.store { + if let Some(str) = self.ci.scope.store { self.ci.nodes.unlock(str); vc.push(str); } - for load in self.ci.loads.drain(..) { + for load in self.ci.scope.loads.drain(..) { if load == value { self.ci.nodes.unlock(load); continue; @@ -972,18 +1040,18 @@ impl Codegen { } let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc); self.ci.nodes.lock(store); - self.ci.store = Some(store); + self.ci.scope.store = Some(store); store } fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid { let mut vc = Vc::from([VOID, region]); - if let Some(str) = self.ci.store { + if let Some(str) = self.ci.scope.store { vc.push(str); } let load = self.ci.nodes.new_node(ty, Kind::Load, vc); self.ci.nodes.lock(load); - self.ci.loads.push(load); + self.ci.scope.loads.push(load); load } @@ -1012,20 +1080,19 @@ impl Codegen { match *expr { Expr::Comment { .. } => Some(Value::VOID), Expr::Ident { pos, id, .. } => { - let Some(index) = self.ci.vars.iter().position(|v| v.id == id) else { + let Some(index) = self.ci.scope.vars.iter().position(|v| v.id == id) else { self.report(pos, msg); return Value::NEVER; }; - log::info!("{}", self.ty_display(self.ci.nodes[self.ci.vars[index].value.id].ty)); self.ci.nodes.load_loop_value( index, - &mut self.ci.vars[index].value, + &mut self.ci.scope.vars[index].value, &mut self.ci.loops, ); - debug_assert_ne!(self.ci.vars[index].value.ty, ty::Id::VOID); + debug_assert_ne!(self.ci.scope.vars[index].value.ty, ty::Id::VOID); - Some(Value::var(index).ty(self.ci.vars[index].value.ty)) + Some(Value::var(index).ty(self.ci.scope.vars[index].value.ty)) } Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit( ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT), @@ -1040,7 +1107,7 @@ impl Codegen { }; let mut inps = Vc::from([self.ci.ctrl, value.id]); - for &m in self.ci.store.iter() { + for &m in self.ci.scope.store.iter() { inps.push(m); } @@ -1090,7 +1157,7 @@ impl Codegen { return Value::NEVER; }; - Some(Value::ptr(vtarget.id).off(offset).ty(ty)) + Some(Value::ptr(self.offset(vtarget.id, ty, offset)).ty(ty)) } Expr::UnOp { op: TokenKind::Band, val, .. } => { let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; @@ -1101,7 +1168,6 @@ impl Codegen { if val.ptr { val.ptr = false; val.ty = self.tys.make_ptr(val.ty); - self.offset(&mut val); return Some(val); } @@ -1135,22 +1201,21 @@ impl Codegen { Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => { let value = self.expr(right)?; self.ci.nodes.lock(value.id); - self.ci.vars.push(Variable { id, value }); + self.ci.scope.vars.push(Variable { id, value }); Some(Value::VOID) } Expr::BinOp { left, op: TokenKind::Assign, right } => { - let mut dest = self.raw_expr(left)?; + let dest = self.raw_expr(left)?; let value = self.expr(right)?; _ = self.assert_ty(left.pos(), value.ty, dest.ty, true, "assignment dest"); if dest.var { self.ci.nodes.lock(value.id); - let var = &mut self.ci.vars[(u16::MAX - dest.id) as usize]; + let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize]; let prev = core::mem::replace(&mut var.value, value); self.ci.nodes.unlock_remove(prev.id); } else if dest.ptr { - self.offset(&mut dest); self.store_mem(dest.id, value.id); } else { self.report(left.pos(), "cannot assign to this expression"); @@ -1158,26 +1223,6 @@ impl Codegen { Some(Value::VOID) } - //Expr::BinOp { - // left: &Expr::UnOp { pos, op: TokenKind::Mul, val }, - // op: TokenKind::Assign, - // right, - //} => { - // //let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) }; - // //let val = self.expr_ctx(val, ctx)?; - // //let base = self.get_load_type(val).unwrap_or_else(|| { - // // self.report( - // // pos, - // // fa!("the '{}' can not be dereferneced", self.ty_display(self.tof(val))), - // // ); - // // ty::Id::NEVER - // //}); - // //let value = self.expr_ctx(right, Ctx::default().with_ty(base))?; - // //_ = self.assert_ty(right.pos(), self.tof(value), base, true, "stored value"); - // //self.store_mem(val, 0, value); - // //Some(Value::VOID) - // todo!() - //} Expr::BinOp { left, op, right } if op != TokenKind::Assign => { let lhs = self.expr_ctx(left, ctx)?; self.ci.nodes.lock(lhs.id); @@ -1248,17 +1293,17 @@ impl Codegen { inps.push(value.id); } - if let Some(str) = self.ci.store { + if let Some(str) = self.ci.scope.store { inps.push(str); } - for load in self.ci.loads.drain(..) { + for load in self.ci.scope.loads.drain(..) { if !self.ci.nodes.unlock_remove(load) { inps.push(load); } } self.store_mem(VOID, VOID); - for load in self.ci.loads.drain(..) { + for load in self.ci.scope.loads.drain(..) { if !self.ci.nodes.unlock_remove(load) { inps.push(load); } @@ -1319,9 +1364,8 @@ impl Codegen { } let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?; - let mut mem = Value::ptr(mem).ty(ty).off(offset); - self.offset(&mut mem); - self.store_mem(mem.id, value.id); + let mem = self.offset(mem, ty, offset); + self.store_mem(mem, value.id); } let field_list = self @@ -1341,7 +1385,7 @@ impl Codegen { Some(Value::ptr(mem).ty(sty)) } Expr::Block { stmts, .. } => { - let base = self.ci.vars.len(); + let base = self.ci.scope.vars.len(); let mut ret = Some(Value::VOID); for stmt in stmts { @@ -1354,7 +1398,7 @@ impl Codegen { } self.ci.nodes.lock(self.ci.ctrl); - for var in self.ci.vars.drain(base..) { + for var in self.ci.scope.vars.drain(base..) { self.ci.nodes.unlock_remove(var.value.id); } self.ci.nodes.unlock(self.ci.ctrl); @@ -1366,19 +1410,23 @@ impl Codegen { self.ci.loops.push(Loop { node: self.ci.ctrl, ctrl: [Nid::MAX; 2], - ctrl_scope: core::array::from_fn(|_| vec![]), - scope: self.ci.vars.clone(), + ctrl_scope: core::array::from_fn(|_| Default::default()), + scope: self.ci.scope.clone(), }); - for var in &mut self.ci.vars { + for var in &mut self.ci.scope.vars { var.value = Value::VOID; } - self.ci.nodes[VOID].lock_rc += self.ci.vars.len() as LockRc; + self.ci.nodes.lock_scope(&self.ci.scope); self.expr(body); - let Loop { node, ctrl: [mut con, bre], ctrl_scope: [mut cons, mut bres], scope } = - self.ci.loops.pop().unwrap(); + let Loop { + node, + ctrl: [mut con, bre], + ctrl_scope: [mut cons, mut bres], + mut scope, + } = self.ci.loops.pop().unwrap(); if con != Nid::MAX { con = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [con, self.ci.ctrl]); @@ -1386,7 +1434,7 @@ impl Codegen { &mut self.ci.nodes, &mut self.ci.loops, con, - &mut self.ci.vars, + &mut self.ci.scope, &mut cons, true, ); @@ -1410,10 +1458,10 @@ impl Codegen { self.ci.nodes.lock(self.ci.ctrl); - core::mem::swap(&mut self.ci.vars, &mut bres); + core::mem::swap(&mut self.ci.scope, &mut bres); for ((dest_var, mut scope_var), loop_var) in - self.ci.vars.iter_mut().zip(scope).zip(bres) + self.ci.scope.vars.iter_mut().zip(scope.vars.drain(..)).zip(bres.vars.drain(..)) { self.ci.nodes.unlock(loop_var.value.id); @@ -1457,6 +1505,9 @@ impl Codegen { self.ci.nodes.unlock_remove(scope_var.value.id); } + self.ci.nodes.unlock_remove_scope(&scope); + self.ci.nodes.unlock_remove_scope(&bres); + self.ci.nodes.unlock(self.ci.ctrl); Some(Value::VOID) @@ -1487,15 +1538,13 @@ impl Codegen { } } - let mut else_scope = self.ci.vars.clone(); - for &el in &self.ci.vars { - self.ci.nodes.lock(el.value.id); - } + let mut else_scope = self.ci.scope.clone(); + self.ci.nodes.lock_scope(&else_scope); self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node]); let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl); - let mut then_scope = core::mem::replace(&mut self.ci.vars, else_scope); + let mut then_scope = core::mem::replace(&mut self.ci.scope, else_scope); self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node]); let rcntrl = if let Some(else_) = else_ { self.expr(else_).map_or(Nid::MAX, |_| self.ci.ctrl) @@ -1504,27 +1553,21 @@ impl Codegen { }; if lcntrl == Nid::MAX && rcntrl == Nid::MAX { - for then_var in then_scope { - self.ci.nodes.unlock_remove(then_var.value.id); - } + self.ci.nodes.unlock_remove_scope(&then_scope); return None; } else if lcntrl == Nid::MAX { - for then_var in then_scope { - self.ci.nodes.unlock_remove(then_var.value.id); - } + self.ci.nodes.unlock_remove_scope(&then_scope); return Some(Value::VOID); } else if rcntrl == Nid::MAX { - for else_var in &self.ci.vars { - self.ci.nodes.unlock_remove(else_var.value.id); - } - self.ci.vars = then_scope; + self.ci.nodes.unlock_remove_scope(&self.ci.scope); + self.ci.scope = then_scope; self.ci.ctrl = lcntrl; return Some(Value::VOID); } self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [lcntrl, rcntrl]); - else_scope = core::mem::take(&mut self.ci.vars); + else_scope = core::mem::take(&mut self.ci.scope); Self::merge_scopes( &mut self.ci.nodes, @@ -1535,7 +1578,7 @@ impl Codegen { true, ); - self.ci.vars = else_scope; + self.ci.scope = else_scope; Some(Value::VOID) } @@ -1550,31 +1593,30 @@ impl Codegen { let mut n = self.raw_expr_ctx(expr, ctx)?; self.strip_var(&mut n); if core::mem::take(&mut n.ptr) { - self.offset(&mut n); n.id = self.load_mem(n.id, n.ty); } Some(n) } - fn offset(&mut self, val: &mut Value) { - if val.off == 0 { - return; + fn offset(&mut self, val: Nid, ty: ty::Id, off: Offset) -> Nid { + if off == 0 { + return val; } - let off = self.ci.nodes.new_node_nop( - ty::Id::INT, - Kind::CInt { value: core::mem::take(&mut val.off) as i64 }, - [VOID], - ); - let inps = [VOID, val.id, off]; - val.id = self.ci.nodes.new_node(val.ty, Kind::BinOp { op: TokenKind::Add }, inps) + let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]); + let inps = [VOID, val, off]; + self.ci.nodes.new_node(ty, Kind::BinOp { op: TokenKind::Add }, inps) } fn strip_var(&mut self, n: &mut Value) { if core::mem::take(&mut n.var) { let id = (u16::MAX - n.id) as usize; - self.ci.nodes.load_loop_value(id, &mut self.ci.vars[id].value, &mut self.ci.loops); - *n = self.ci.vars[id].value; + self.ci.nodes.load_loop_value( + id, + &mut self.ci.scope.vars[id].value, + &mut self.ci.loops, + ); + *n = self.ci.scope.vars[id].value; } } @@ -1590,10 +1632,9 @@ impl Codegen { if loob.ctrl[id] == Nid::MAX { loob.ctrl[id] = self.ci.ctrl; - loob.ctrl_scope[id] = self.ci.vars[..loob.scope.len()].to_owned(); - for v in &loob.ctrl_scope[id] { - self.ci.nodes.lock(v.value.id) - } + loob.ctrl_scope[id] = self.ci.scope.clone(); + loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len()); + self.ci.nodes.lock_scope(&loob.ctrl_scope[id]); } else { let reg = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]); @@ -1604,7 +1645,7 @@ impl Codegen { &mut self.ci.loops, reg, &mut scope, - &mut self.ci.vars, + &mut self.ci.scope, false, ); @@ -1621,28 +1662,40 @@ impl Codegen { nodes: &mut Nodes, loops: &mut [Loop], ctrl: Nid, - to: &mut [Variable], - from: &mut [Variable], + to: &mut Scope, + from: &mut Scope, drop_from: bool, ) { - for (i, (else_var, then_var)) in to.iter_mut().zip(from).enumerate() { - if else_var.value.id != then_var.value.id { - nodes.load_loop_value(i, &mut then_var.value, loops); - nodes.load_loop_value(i, &mut else_var.value, loops); - if else_var.value.id != then_var.value.id { - let ty = nodes[else_var.value.id].ty; - debug_assert_eq!(ty, nodes[then_var.value.id].ty, "TODO: typecheck properly"); + for (i, (to_var, from_var)) in to.vars.iter_mut().zip(&mut from.vars).enumerate() { + if to_var.value.id != from_var.value.id { + nodes.load_loop_value(i, &mut from_var.value, loops); + nodes.load_loop_value(i, &mut to_var.value, loops); + if to_var.value.id != from_var.value.id { + let ty = nodes[to_var.value.id].ty; + debug_assert_eq!(ty, nodes[from_var.value.id].ty, "TODO: typecheck properly"); - let inps = [ctrl, then_var.value.id, else_var.value.id]; - nodes.unlock(else_var.value.id); - else_var.value.id = nodes.new_node(ty, Kind::Phi, inps); - nodes.lock(else_var.value.id); + let inps = [ctrl, from_var.value.id, to_var.value.id]; + nodes.unlock(to_var.value.id); + to_var.value.id = nodes.new_node(ty, Kind::Phi, inps); + nodes.lock(to_var.value.id); } } + } - if drop_from { - nodes.unlock_remove(then_var.value.id); - } + if to.store != from.store { + let (to_store, from_store) = (to.store.unwrap(), from.store.unwrap()); + nodes.unlock(to_store); + to.store = Some(nodes.new_node(ty::Id::VOID, Kind::Phi, [ctrl, from_store, to_store])); + nodes.lock(to.store.unwrap()); + } + + to.loads.extend(&from.loads); + for &load in &from.loads { + nodes.lock(load); + } + + if drop_from { + nodes.unlock_remove_scope(from); } } @@ -1703,10 +1756,10 @@ impl Codegen { self.ci.nodes.lock(value); let sym = parser::find_symbol(&ast.symbols, arg.id); assert!(sym.flags & idfl::COMPTIME == 0, "TODO"); - self.ci.vars.push(Variable { id: arg.id, value: Value::new(value).ty(ty) }); + self.ci.scope.vars.push(Variable { id: arg.id, value: Value::new(value).ty(ty) }); } - let orig_vars = self.ci.vars.clone(); + let orig_vars = self.ci.scope.vars.clone(); if self.expr(body).is_some() { self.report(body.pos(), "expected all paths in the fucntion to return"); @@ -1714,18 +1767,9 @@ impl Codegen { self.ci.nodes.unlock(end); - if let Some(mem) = self.ci.store.take() { - self.ci.nodes.unlock_remove(mem); - } - for load in self.ci.loads.drain(..) { - self.ci.nodes.unlock_remove(load); - } + self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope)); self.ci.nodes.unlock(mem); - for var in self.ci.vars.drain(..) { - self.ci.nodes.unlock(var.value.id); - } - if self.errors.borrow().is_empty() { self.graphviz(); self.gcm(); @@ -1756,10 +1800,10 @@ impl Codegen { self.ci.nodes[mem].outputs = mems; } - self.ci.vars = orig_vars; + self.ci.scope.vars = orig_vars; self.ci.nodes.visited.clear(self.ci.nodes.values.len()); let saved = self.emit_body(sig); - self.ci.vars.clear(); + self.ci.scope.vars.clear(); if let Some(last_ret) = self.ci.ret_relocs.last() && last_ret.offset as usize == self.ci.code.len() - 5 @@ -1917,6 +1961,7 @@ impl Codegen { let &[.., rhs] = node.inputs.as_slice() else { unreachable!() }; if let Kind::CInt { value } = func.nodes[rhs].kind + && func.nodes[rhs].lock_rc != 0 && let Some(op) = op.imm_binop(node.ty.is_signed(), func.tys.size_of(node.ty)) { @@ -1945,30 +1990,45 @@ impl Codegen { self.ci.emit(instrs::addi64(atr(allocs[0]), base, offset as _)); } Kind::Load => { - let region = node.inputs[1]; + let mut region = node.inputs[1]; + let mut offset = 0; + if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) + && let Kind::CInt { value } = + func.nodes[func.nodes[region].inputs[2]].kind + { + region = func.nodes[region].inputs[1]; + offset = value as Offset; + } let size = self.tys.size_of(node.ty); if size <= 8 { let (base, offset) = match func.nodes[region].kind { - Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset), - _ => (atr(allocs[1]), func.nodes[region].offset), + Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset + offset), + _ => (atr(allocs[1]), offset), }; self.ci.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _)); } } + Kind::Stre if node.inputs[2] == VOID => {} Kind::Stre => { - let region = node.inputs[2]; - if region != VOID { - let size = u16::try_from(self.tys.size_of(node.ty)).expect("TODO"); - let nd = &func.nodes[region]; - let (base, offset, src) = match nd.kind { - Kind::Stck => (reg::STACK_PTR, nd.offset, allocs[0]), - _ => (atr(allocs[0]), 0, allocs[1]), - }; - if size > 8 { - self.ci.emit(instrs::bmc(base, atr(src), size)); - } else { - self.ci.emit(instrs::st(atr(src), base, offset as _, size)); - } + let mut region = node.inputs[2]; + let mut offset = 0; + if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) + && let Kind::CInt { value } = + func.nodes[func.nodes[region].inputs[2]].kind + { + region = func.nodes[region].inputs[1]; + offset = value as Offset; + } + let size = u16::try_from(self.tys.size_of(node.ty)).expect("TODO"); + let nd = &func.nodes[region]; + let (base, offset, src) = match nd.kind { + Kind::Stck => (reg::STACK_PTR, nd.offset + offset, allocs[0]), + _ => (atr(allocs[0]), offset, allocs[1]), + }; + if size > 8 { + self.ci.emit(instrs::bmc(base, atr(src), size)); + } else { + self.ci.emit(instrs::st(atr(src), base, offset as _, size)); } } _ => unreachable!(), @@ -2158,16 +2218,6 @@ impl Codegen { self.ci.nodes.visited.clear(self.ci.nodes.values.len()); push_down(&mut self.ci.nodes, VOID); } - - //fn get_load_type(&self, val: Nid) -> Option { - // Some(match self.ci.nodes[val].kind { - // Kind::Stre { .. } | Kind::Load { .. } | Kind::Stck | Kind::Arg { .. } => { - // self.ci.nodes[val].ty - // } - // Kind::Ptr { .. } => self.tys.base_of(self.ci.nodes[val].ty).unwrap(), - // _ => return None, - // }) - //} } // FIXME: make this more efficient (allocated with arena) @@ -2272,7 +2322,7 @@ impl<'a> Function<'a> { let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap(); for ph in node.outputs { - if self.nodes[ph].kind != Kind::Phi { + if self.nodes[ph].kind != Kind::Phi || self.nodes[ph].ty == ty::Id::VOID { continue; } @@ -2334,7 +2384,7 @@ impl<'a> Function<'a> { } let mut block = vec![]; for ph in node.outputs.clone() { - if self.nodes[ph].kind != Kind::Phi { + if self.nodes[ph].kind != Kind::Phi || self.nodes[ph].ty == ty::Id::VOID { continue; } self.def_nid(ph); @@ -2357,19 +2407,20 @@ impl<'a> Function<'a> { self.add_instr(nid, ops); self.emit_node(node.outputs[0], nid); } - Kind::CInt { .. } => { - let unused = node.outputs.into_iter().all(|o| { + Kind::CInt { .. } + if node.outputs.iter().all(|&o| { let ond = &self.nodes[o]; matches!(ond.kind, Kind::BinOp { op } if op.imm_binop(ond.ty.is_signed(), 8).is_some() && self.nodes.is_const(ond.inputs[2]) && op.cond_op(ond.ty.is_signed()).is_none()) - }); - - if !unused { - let ops = vec![self.drg(nid)]; - self.add_instr(nid, ops); - } + }) => + { + self.nodes.lock(nid) + } + Kind::CInt { .. } => { + let ops = vec![self.drg(nid)]; + self.add_instr(nid, ops); } Kind::Entry => { self.nodes[nid].ralloc_backref = self.add_block(nid); @@ -2410,11 +2461,20 @@ impl<'a> Function<'a> { self.emit_node(o, nid); } } + Kind::BinOp { op: TokenKind::Add } + if self.nodes.is_const(node.inputs[2]) + && node + .outputs + .iter() + .all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)) => + { + self.nodes.lock(nid) + } Kind::BinOp { op } => { let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() }; let ops = if let Kind::CInt { .. } = self.nodes[rhs].kind - && op.imm_binop(node.ty.is_signed(), 8).is_some() + && self.nodes[rhs].lock_rc != 0 { vec![self.drg(nid), self.urg(lhs)] } else if op.binop(node.ty.is_signed(), 8).is_some() { @@ -2479,13 +2539,28 @@ impl<'a> Function<'a> { } } } + //Kind::Stck + // if node.outputs.iter().all(|&n| { + // matches!(self.nodes[n].kind, Kind::Stre | Kind::Load) + // || matches!(self.nodes[n].kind, Kind::BinOp { op: TokenKind::Add } + // if self.nodes.is_const(self.nodes[n].inputs[2]) + // && self.nodes[n] + // .outputs + // .iter() + // .all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load))) + // }) => {} Kind::Stck => { let ops = vec![self.drg(nid)]; self.add_instr(nid, ops); } Kind::Phi | Kind::Arg { .. } | Kind::Mem => {} Kind::Load { .. } => { - let region = node.inputs[1]; + let mut region = node.inputs[1]; + if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) + && self.nodes.is_const(self.nodes[region].inputs[2]) + { + region = self.nodes[region].inputs[1] + } if self.tys.size_of(node.ty) <= 8 { let ops = match self.nodes[region].kind { Kind::Stck => vec![self.drg(nid)], @@ -2494,18 +2569,22 @@ impl<'a> Function<'a> { self.add_instr(nid, ops); } } + Kind::Stre { .. } if node.inputs[2] == VOID => self.nodes.lock(nid), Kind::Stre { .. } => { - let region = node.inputs[2]; - if region != VOID { - let ops = match self.nodes[region].kind { - _ if self.tys.size_of(node.ty) > 8 => { - vec![self.urg(region), self.urg(self.nodes[node.inputs[1]].inputs[1])] - } - Kind::Stck => vec![self.urg(node.inputs[1])], - _ => vec![self.urg(region), self.urg(node.inputs[1])], - }; - self.add_instr(nid, ops); + let mut region = node.inputs[2]; + if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) + && self.nodes.is_const(self.nodes[region].inputs[2]) + { + region = self.nodes[region].inputs[1] } + let ops = match self.nodes[region].kind { + _ if self.tys.size_of(node.ty) > 8 => { + vec![self.urg(region), self.urg(self.nodes[node.inputs[1]].inputs[1])] + } + Kind::Stck => vec![self.urg(node.inputs[1])], + _ => vec![self.urg(region), self.urg(node.inputs[1])], + }; + self.add_instr(nid, ops); } } } @@ -2849,8 +2928,6 @@ mod tests { return; } - //println!("{output}"); - crate::test_run_vm(&out, output); } @@ -2894,5 +2971,6 @@ mod tests { //tests_ptr_to_ptr_copy; //wide_ret; pointer_opts; + conditional_stores; } } diff --git a/lang/tests/son_tests_conditional_stores.txt b/lang/tests/son_tests_conditional_stores.txt new file mode 100644 index 0000000..9d9b5e4 --- /dev/null +++ b/lang/tests/son_tests_conditional_stores.txt @@ -0,0 +1,24 @@ +cond: + LI64 r1, 0d + JALA r0, r31, 0a +main: + ADDI64 r254, r254, -48d + ST r31, r254, 8a, 40h + LI64 r32, 1d + ADDI64 r33, r254, 0d + ST r32, r254, 0a, 8h + JAL r31, r0, :cond + LI64 r34, 0d + CP r35, r34 + JNE r1, r35, :0 + CP r34, r35 + CP r1, r34 + JMP :1 + 0: LI64 r1, 2d + 1: ST r1, r254, 0a, 8h + LD r31, r254, 8a, 40h + ADDI64 r254, r254, 48d + JALA r0, r31, 0a +code size: 181 +ret: 0 +status: Ok(()) diff --git a/lang/tests/son_tests_if_statements.txt b/lang/tests/son_tests_if_statements.txt index 0664f98..852e400 100644 --- a/lang/tests/son_tests_if_statements.txt +++ b/lang/tests/son_tests_if_statements.txt @@ -6,12 +6,12 @@ fib: JGTU r2, r32, :0 JMP :1 0: CP r33, r2 - ADDI64 r2, r33, -1d + SUB64 r2, r33, r1 CP r34, r33 JAL r31, r0, :fib CP r2, r34 CP r35, r1 - ADDI64 r2, r2, -2d + SUB64 r2, r2, r32 JAL r31, r0, :fib ADD64 r1, r1, r35 1: LD r31, r254, 0a, 40h @@ -25,6 +25,6 @@ main: LD r31, r254, 0a, 8h ADDI64 r254, r254, 8d JALA r0, r31, 0a -code size: 225 +code size: 211 ret: 55 status: Ok(()) diff --git a/lang/tests/son_tests_loops.txt b/lang/tests/son_tests_loops.txt index f07df75..c4c1039 100644 --- a/lang/tests/son_tests_loops.txt +++ b/lang/tests/son_tests_loops.txt @@ -1,13 +1,14 @@ fib: - LI64 r7, 1d - LI64 r4, 0d - CP r1, r4 - 2: JNE r2, r4, :0 + LI64 r4, 1d + LI64 r5, 0d + CP r1, r5 + CP r10, r4 + 2: JNE r2, r5, :0 JMP :1 - 0: ADD64 r3, r7, r1 - ADDI64 r2, r2, -1d - CP r1, r7 - CP r7, r3 + 0: ADD64 r3, r10, r1 + SUB64 r2, r2, r4 + CP r1, r10 + CP r10, r3 JMP :2 1: JALA r0, r31, 0a main: @@ -18,6 +19,6 @@ main: LD r31, r254, 0a, 8h ADDI64 r254, r254, 8d JALA r0, r31, 0a -code size: 154 +code size: 150 ret: 55 status: Ok(()) diff --git a/lang/tests/son_tests_pointer_opts.txt b/lang/tests/son_tests_pointer_opts.txt index 76af8c1..a478596 100644 --- a/lang/tests/son_tests_pointer_opts.txt +++ b/lang/tests/son_tests_pointer_opts.txt @@ -3,23 +3,17 @@ clobber: ST r3, r2, 0a, 8h JALA r0, r31, 0a main: - ADDI64 r254, r254, -64d - ST r31, r254, 8a, 56h + ADDI64 r254, r254, -32d + ST r31, r254, 8a, 24h LI64 r32, 2d - LI64 r33, 1d - LI64 r34, 0d ADDI64 r2, r254, 0d - ST r34, r254, 0a, 8h - ST r33, r254, 0a, 8h ST r32, r254, 0a, 8h - LD r35, r254, 0a, 8h JAL r31, r0, :clobber - LD r36, r254, 0a, 8h - MULI64 r37, r35, 2d - SUB64 r1, r37, r36 - LD r31, r254, 8a, 56h - ADDI64 r254, r254, 64d + LD r33, r254, 0a, 8h + ADDI64 r1, r33, -4d + LD r31, r254, 8a, 24h + ADDI64 r254, r254, 32d JALA r0, r31, 0a -code size: 229 +code size: 166 ret: 0 status: Ok(())