handling conditional stores

This commit is contained in:
Jakub Doka 2024-10-18 13:11:11 +02:00
parent c900f4ef5c
commit 4a7b4e4ead
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 325 additions and 211 deletions

View file

@ -999,3 +999,20 @@ clobber := fn(cb: ^int): void {
return return
} }
``` ```
#### conditional_stores
```hb
main := fn(): int {
mem := &1
if cond() == 0 {
*mem = 0
} else {
*mem = 2
}
return *mem
}
cond := fn(): int return 0
```

View file

@ -14,7 +14,7 @@ use {
vc::{BitSet, Vc}, vc::{BitSet, Vc},
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types, Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
}, },
alloc::{borrow::ToOwned, string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{ core::{
assert_matches::debug_assert_matches, assert_matches::debug_assert_matches,
cell::RefCell, cell::RefCell,
@ -279,8 +279,53 @@ impl Nodes {
} }
} }
K::Phi => { K::Phi => {
if self[target].inputs[1] == self[target].inputs[2] { let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() };
return Some(self[target].inputs[1]);
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 [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); self.load_loop_value(index, lvalue, loops);
@ -631,6 +676,30 @@ impl Nodes {
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Node> { fn iter_mut(&mut self) -> impl Iterator<Item = &mut Node> {
self.values.iter_mut().flat_map(Result::as_mut) 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<Nid> for Nodes { impl ops::Index<Nid> for Nodes {
@ -773,8 +842,8 @@ type IDomDepth = u16;
struct Loop { struct Loop {
node: Nid, node: Nid,
ctrl: [Nid; 2], ctrl: [Nid; 2],
ctrl_scope: [Vec<Variable>; 2], ctrl_scope: [Scope; 2],
scope: Vec<Variable>, scope: Scope,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -783,6 +852,13 @@ struct Variable {
value: Value, value: Value,
} }
#[derive(Default, Clone)]
struct Scope {
vars: Vec<Variable>,
loads: Vec<Nid>,
store: Option<Nid>,
}
#[derive(Default)] #[derive(Default)]
struct ItemCtx { struct ItemCtx {
file: FileId, file: FileId,
@ -799,9 +875,7 @@ struct ItemCtx {
filled: Vec<Nid>, filled: Vec<Nid>,
loops: Vec<Loop>, loops: Vec<Loop>,
vars: Vec<Variable>, scope: Scope,
store: Option<Nid>,
loads: Vec<Nid>,
clobbered: Vec<Nid>, clobbered: Vec<Nid>,
ret_relocs: Vec<Reloc>, ret_relocs: Vec<Reloc>,
relocs: Vec<TypedReloc>, relocs: Vec<TypedReloc>,
@ -871,7 +945,6 @@ impl Default for Regalloc {
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
struct Value { struct Value {
ty: ty::Id, ty: ty::Id,
off: Offset,
var: bool, var: bool,
ptr: bool, ptr: bool,
id: Nid, id: Nid,
@ -879,8 +952,8 @@ struct Value {
impl Value { impl Value {
const NEVER: Option<Value> = const NEVER: Option<Value> =
Some(Self { ty: ty::Id::NEVER, off: 0, var: false, ptr: false, id: NEVER }); Some(Self { ty: ty::Id::NEVER, var: false, ptr: false, id: NEVER });
const VOID: Value = Self { ty: ty::Id::VOID, off: 0, var: false, ptr: false, id: VOID }; const VOID: Value = Self { ty: ty::Id::VOID, var: false, ptr: false, id: VOID };
pub fn new(id: Nid) -> Self { pub fn new(id: Nid) -> Self {
Self { id, ..Default::default() } Self { id, ..Default::default() }
@ -898,11 +971,6 @@ impl Value {
pub fn ty(self, ty: impl Into<ty::Id>) -> Self { pub fn ty(self, ty: impl Into<ty::Id>) -> Self {
Self { ty: ty.into(), ..self } Self { ty: ty.into(), ..self }
} }
#[inline(always)]
pub fn off(self, off: Offset) -> Self {
Self { off, ..self }
}
} }
#[derive(Default)] #[derive(Default)]
@ -957,11 +1025,11 @@ impl Codegen {
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid { fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
let mut vc = Vc::from([VOID, value, region]); 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); self.ci.nodes.unlock(str);
vc.push(str); vc.push(str);
} }
for load in self.ci.loads.drain(..) { for load in self.ci.scope.loads.drain(..) {
if load == value { if load == value {
self.ci.nodes.unlock(load); self.ci.nodes.unlock(load);
continue; continue;
@ -972,18 +1040,18 @@ impl Codegen {
} }
let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc); let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc);
self.ci.nodes.lock(store); self.ci.nodes.lock(store);
self.ci.store = Some(store); self.ci.scope.store = Some(store);
store store
} }
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid { fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
let mut vc = Vc::from([VOID, region]); 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); vc.push(str);
} }
let load = self.ci.nodes.new_node(ty, Kind::Load, vc); let load = self.ci.nodes.new_node(ty, Kind::Load, vc);
self.ci.nodes.lock(load); self.ci.nodes.lock(load);
self.ci.loads.push(load); self.ci.scope.loads.push(load);
load load
} }
@ -1012,20 +1080,19 @@ impl Codegen {
match *expr { match *expr {
Expr::Comment { .. } => Some(Value::VOID), Expr::Comment { .. } => Some(Value::VOID),
Expr::Ident { pos, id, .. } => { 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); self.report(pos, msg);
return Value::NEVER; return Value::NEVER;
}; };
log::info!("{}", self.ty_display(self.ci.nodes[self.ci.vars[index].value.id].ty));
self.ci.nodes.load_loop_value( self.ci.nodes.load_loop_value(
index, index,
&mut self.ci.vars[index].value, &mut self.ci.scope.vars[index].value,
&mut self.ci.loops, &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( 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), 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]); 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); inps.push(m);
} }
@ -1090,7 +1157,7 @@ impl Codegen {
return Value::NEVER; 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, .. } => { Expr::UnOp { op: TokenKind::Band, val, .. } => {
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
@ -1101,7 +1168,6 @@ impl Codegen {
if val.ptr { if val.ptr {
val.ptr = false; val.ptr = false;
val.ty = self.tys.make_ptr(val.ty); val.ty = self.tys.make_ptr(val.ty);
self.offset(&mut val);
return Some(val); return Some(val);
} }
@ -1135,22 +1201,21 @@ impl Codegen {
Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => { Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => {
let value = self.expr(right)?; let value = self.expr(right)?;
self.ci.nodes.lock(value.id); self.ci.nodes.lock(value.id);
self.ci.vars.push(Variable { id, value }); self.ci.scope.vars.push(Variable { id, value });
Some(Value::VOID) Some(Value::VOID)
} }
Expr::BinOp { left, op: TokenKind::Assign, right } => { 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)?; let value = self.expr(right)?;
_ = self.assert_ty(left.pos(), value.ty, dest.ty, true, "assignment dest"); _ = self.assert_ty(left.pos(), value.ty, dest.ty, true, "assignment dest");
if dest.var { if dest.var {
self.ci.nodes.lock(value.id); 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); let prev = core::mem::replace(&mut var.value, value);
self.ci.nodes.unlock_remove(prev.id); self.ci.nodes.unlock_remove(prev.id);
} else if dest.ptr { } else if dest.ptr {
self.offset(&mut dest);
self.store_mem(dest.id, value.id); self.store_mem(dest.id, value.id);
} else { } else {
self.report(left.pos(), "cannot assign to this expression"); self.report(left.pos(), "cannot assign to this expression");
@ -1158,26 +1223,6 @@ impl Codegen {
Some(Value::VOID) 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 => { Expr::BinOp { left, op, right } if op != TokenKind::Assign => {
let lhs = self.expr_ctx(left, ctx)?; let lhs = self.expr_ctx(left, ctx)?;
self.ci.nodes.lock(lhs.id); self.ci.nodes.lock(lhs.id);
@ -1248,17 +1293,17 @@ impl Codegen {
inps.push(value.id); inps.push(value.id);
} }
if let Some(str) = self.ci.store { if let Some(str) = self.ci.scope.store {
inps.push(str); 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) { if !self.ci.nodes.unlock_remove(load) {
inps.push(load); inps.push(load);
} }
} }
self.store_mem(VOID, VOID); 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) { if !self.ci.nodes.unlock_remove(load) {
inps.push(load); inps.push(load);
} }
@ -1319,9 +1364,8 @@ impl Codegen {
} }
let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?; let value = self.expr_ctx(&field.value, Ctx::default().with_ty(ty))?;
let mut mem = Value::ptr(mem).ty(ty).off(offset); let mem = self.offset(mem, ty, offset);
self.offset(&mut mem); self.store_mem(mem, value.id);
self.store_mem(mem.id, value.id);
} }
let field_list = self let field_list = self
@ -1341,7 +1385,7 @@ impl Codegen {
Some(Value::ptr(mem).ty(sty)) Some(Value::ptr(mem).ty(sty))
} }
Expr::Block { stmts, .. } => { Expr::Block { stmts, .. } => {
let base = self.ci.vars.len(); let base = self.ci.scope.vars.len();
let mut ret = Some(Value::VOID); let mut ret = Some(Value::VOID);
for stmt in stmts { for stmt in stmts {
@ -1354,7 +1398,7 @@ impl Codegen {
} }
self.ci.nodes.lock(self.ci.ctrl); 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_remove(var.value.id);
} }
self.ci.nodes.unlock(self.ci.ctrl); self.ci.nodes.unlock(self.ci.ctrl);
@ -1366,19 +1410,23 @@ impl Codegen {
self.ci.loops.push(Loop { self.ci.loops.push(Loop {
node: self.ci.ctrl, node: self.ci.ctrl,
ctrl: [Nid::MAX; 2], ctrl: [Nid::MAX; 2],
ctrl_scope: core::array::from_fn(|_| vec![]), ctrl_scope: core::array::from_fn(|_| Default::default()),
scope: self.ci.vars.clone(), scope: self.ci.scope.clone(),
}); });
for var in &mut self.ci.vars { for var in &mut self.ci.scope.vars {
var.value = Value::VOID; 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); self.expr(body);
let Loop { node, ctrl: [mut con, bre], ctrl_scope: [mut cons, mut bres], scope } = let Loop {
self.ci.loops.pop().unwrap(); node,
ctrl: [mut con, bre],
ctrl_scope: [mut cons, mut bres],
mut scope,
} = self.ci.loops.pop().unwrap();
if con != Nid::MAX { if con != Nid::MAX {
con = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [con, self.ci.ctrl]); 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.nodes,
&mut self.ci.loops, &mut self.ci.loops,
con, con,
&mut self.ci.vars, &mut self.ci.scope,
&mut cons, &mut cons,
true, true,
); );
@ -1410,10 +1458,10 @@ impl Codegen {
self.ci.nodes.lock(self.ci.ctrl); 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 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); 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_var.value.id);
} }
self.ci.nodes.unlock_remove_scope(&scope);
self.ci.nodes.unlock_remove_scope(&bres);
self.ci.nodes.unlock(self.ci.ctrl); self.ci.nodes.unlock(self.ci.ctrl);
Some(Value::VOID) Some(Value::VOID)
@ -1487,15 +1538,13 @@ impl Codegen {
} }
} }
let mut else_scope = self.ci.vars.clone(); let mut else_scope = self.ci.scope.clone();
for &el in &self.ci.vars { self.ci.nodes.lock_scope(&else_scope);
self.ci.nodes.lock(el.value.id);
}
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Then, [if_node]); 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 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]); self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Else, [if_node]);
let rcntrl = if let Some(else_) = else_ { let rcntrl = if let Some(else_) = else_ {
self.expr(else_).map_or(Nid::MAX, |_| self.ci.ctrl) self.expr(else_).map_or(Nid::MAX, |_| self.ci.ctrl)
@ -1504,27 +1553,21 @@ impl Codegen {
}; };
if lcntrl == Nid::MAX && rcntrl == Nid::MAX { if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
for then_var in then_scope { self.ci.nodes.unlock_remove_scope(&then_scope);
self.ci.nodes.unlock_remove(then_var.value.id);
}
return None; return None;
} else if lcntrl == Nid::MAX { } else if lcntrl == Nid::MAX {
for then_var in then_scope { self.ci.nodes.unlock_remove_scope(&then_scope);
self.ci.nodes.unlock_remove(then_var.value.id);
}
return Some(Value::VOID); return Some(Value::VOID);
} else if rcntrl == Nid::MAX { } else if rcntrl == Nid::MAX {
for else_var in &self.ci.vars { self.ci.nodes.unlock_remove_scope(&self.ci.scope);
self.ci.nodes.unlock_remove(else_var.value.id); self.ci.scope = then_scope;
}
self.ci.vars = then_scope;
self.ci.ctrl = lcntrl; self.ci.ctrl = lcntrl;
return Some(Value::VOID); return Some(Value::VOID);
} }
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [lcntrl, rcntrl]); 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( Self::merge_scopes(
&mut self.ci.nodes, &mut self.ci.nodes,
@ -1535,7 +1578,7 @@ impl Codegen {
true, true,
); );
self.ci.vars = else_scope; self.ci.scope = else_scope;
Some(Value::VOID) Some(Value::VOID)
} }
@ -1550,31 +1593,30 @@ impl Codegen {
let mut n = self.raw_expr_ctx(expr, ctx)?; let mut n = self.raw_expr_ctx(expr, ctx)?;
self.strip_var(&mut n); self.strip_var(&mut n);
if core::mem::take(&mut n.ptr) { if core::mem::take(&mut n.ptr) {
self.offset(&mut n);
n.id = self.load_mem(n.id, n.ty); n.id = self.load_mem(n.id, n.ty);
} }
Some(n) Some(n)
} }
fn offset(&mut self, val: &mut Value) { fn offset(&mut self, val: Nid, ty: ty::Id, off: Offset) -> Nid {
if val.off == 0 { if off == 0 {
return; return val;
} }
let off = self.ci.nodes.new_node_nop( let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]);
ty::Id::INT, let inps = [VOID, val, off];
Kind::CInt { value: core::mem::take(&mut val.off) as i64 }, self.ci.nodes.new_node(ty, Kind::BinOp { op: TokenKind::Add }, inps)
[VOID],
);
let inps = [VOID, val.id, off];
val.id = self.ci.nodes.new_node(val.ty, Kind::BinOp { op: TokenKind::Add }, inps)
} }
fn strip_var(&mut self, n: &mut Value) { fn strip_var(&mut self, n: &mut Value) {
if core::mem::take(&mut n.var) { if core::mem::take(&mut n.var) {
let id = (u16::MAX - n.id) as usize; 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); self.ci.nodes.load_loop_value(
*n = self.ci.vars[id].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 { if loob.ctrl[id] == Nid::MAX {
loob.ctrl[id] = self.ci.ctrl; loob.ctrl[id] = self.ci.ctrl;
loob.ctrl_scope[id] = self.ci.vars[..loob.scope.len()].to_owned(); loob.ctrl_scope[id] = self.ci.scope.clone();
for v in &loob.ctrl_scope[id] { loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len());
self.ci.nodes.lock(v.value.id) self.ci.nodes.lock_scope(&loob.ctrl_scope[id]);
}
} else { } else {
let reg = let reg =
self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]); 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, &mut self.ci.loops,
reg, reg,
&mut scope, &mut scope,
&mut self.ci.vars, &mut self.ci.scope,
false, false,
); );
@ -1621,28 +1662,40 @@ impl Codegen {
nodes: &mut Nodes, nodes: &mut Nodes,
loops: &mut [Loop], loops: &mut [Loop],
ctrl: Nid, ctrl: Nid,
to: &mut [Variable], to: &mut Scope,
from: &mut [Variable], from: &mut Scope,
drop_from: bool, drop_from: bool,
) { ) {
for (i, (else_var, then_var)) in to.iter_mut().zip(from).enumerate() { for (i, (to_var, from_var)) in to.vars.iter_mut().zip(&mut from.vars).enumerate() {
if else_var.value.id != then_var.value.id { if to_var.value.id != from_var.value.id {
nodes.load_loop_value(i, &mut then_var.value, loops); nodes.load_loop_value(i, &mut from_var.value, loops);
nodes.load_loop_value(i, &mut else_var.value, loops); nodes.load_loop_value(i, &mut to_var.value, loops);
if else_var.value.id != then_var.value.id { if to_var.value.id != from_var.value.id {
let ty = nodes[else_var.value.id].ty; let ty = nodes[to_var.value.id].ty;
debug_assert_eq!(ty, nodes[then_var.value.id].ty, "TODO: typecheck properly"); debug_assert_eq!(ty, nodes[from_var.value.id].ty, "TODO: typecheck properly");
let inps = [ctrl, then_var.value.id, else_var.value.id]; let inps = [ctrl, from_var.value.id, to_var.value.id];
nodes.unlock(else_var.value.id); nodes.unlock(to_var.value.id);
else_var.value.id = nodes.new_node(ty, Kind::Phi, inps); to_var.value.id = nodes.new_node(ty, Kind::Phi, inps);
nodes.lock(else_var.value.id); nodes.lock(to_var.value.id);
} }
} }
}
if drop_from { if to.store != from.store {
nodes.unlock_remove(then_var.value.id); 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); self.ci.nodes.lock(value);
let sym = parser::find_symbol(&ast.symbols, arg.id); let sym = parser::find_symbol(&ast.symbols, arg.id);
assert!(sym.flags & idfl::COMPTIME == 0, "TODO"); 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() { if self.expr(body).is_some() {
self.report(body.pos(), "expected all paths in the fucntion to return"); self.report(body.pos(), "expected all paths in the fucntion to return");
@ -1714,18 +1767,9 @@ impl Codegen {
self.ci.nodes.unlock(end); self.ci.nodes.unlock(end);
if let Some(mem) = self.ci.store.take() { self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope));
self.ci.nodes.unlock_remove(mem);
}
for load in self.ci.loads.drain(..) {
self.ci.nodes.unlock_remove(load);
}
self.ci.nodes.unlock(mem); 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() { if self.errors.borrow().is_empty() {
self.graphviz(); self.graphviz();
self.gcm(); self.gcm();
@ -1756,10 +1800,10 @@ impl Codegen {
self.ci.nodes[mem].outputs = mems; 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()); self.ci.nodes.visited.clear(self.ci.nodes.values.len());
let saved = self.emit_body(sig); 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() if let Some(last_ret) = self.ci.ret_relocs.last()
&& last_ret.offset as usize == self.ci.code.len() - 5 && last_ret.offset as usize == self.ci.code.len() - 5
@ -1917,6 +1961,7 @@ impl Codegen {
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() }; let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
if let Kind::CInt { value } = func.nodes[rhs].kind if let Kind::CInt { value } = func.nodes[rhs].kind
&& func.nodes[rhs].lock_rc != 0
&& let Some(op) = && let Some(op) =
op.imm_binop(node.ty.is_signed(), func.tys.size_of(node.ty)) 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 _)); self.ci.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
} }
Kind::Load => { 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); let size = self.tys.size_of(node.ty);
if size <= 8 { if size <= 8 {
let (base, offset) = match func.nodes[region].kind { let (base, offset) = match func.nodes[region].kind {
Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset), Kind::Stck => (reg::STACK_PTR, func.nodes[region].offset + offset),
_ => (atr(allocs[1]), func.nodes[region].offset), _ => (atr(allocs[1]), offset),
}; };
self.ci.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _)); self.ci.emit(instrs::ld(atr(allocs[0]), base, offset as _, size as _));
} }
} }
Kind::Stre if node.inputs[2] == VOID => {}
Kind::Stre => { Kind::Stre => {
let region = node.inputs[2]; let mut region = node.inputs[2];
if region != VOID { let mut offset = 0;
let size = u16::try_from(self.tys.size_of(node.ty)).expect("TODO"); if func.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
let nd = &func.nodes[region]; && let Kind::CInt { value } =
let (base, offset, src) = match nd.kind { func.nodes[func.nodes[region].inputs[2]].kind
Kind::Stck => (reg::STACK_PTR, nd.offset, allocs[0]), {
_ => (atr(allocs[0]), 0, allocs[1]), region = func.nodes[region].inputs[1];
}; offset = value as Offset;
if size > 8 { }
self.ci.emit(instrs::bmc(base, atr(src), size)); let size = u16::try_from(self.tys.size_of(node.ty)).expect("TODO");
} else { let nd = &func.nodes[region];
self.ci.emit(instrs::st(atr(src), base, offset as _, size)); 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!(), _ => unreachable!(),
@ -2158,16 +2218,6 @@ impl Codegen {
self.ci.nodes.visited.clear(self.ci.nodes.values.len()); self.ci.nodes.visited.clear(self.ci.nodes.values.len());
push_down(&mut self.ci.nodes, VOID); push_down(&mut self.ci.nodes, VOID);
} }
//fn get_load_type(&self, val: Nid) -> Option<ty::Id> {
// 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) // 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(); let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap();
for ph in node.outputs { 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; continue;
} }
@ -2334,7 +2384,7 @@ impl<'a> Function<'a> {
} }
let mut block = vec![]; let mut block = vec![];
for ph in node.outputs.clone() { 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; continue;
} }
self.def_nid(ph); self.def_nid(ph);
@ -2357,19 +2407,20 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops); self.add_instr(nid, ops);
self.emit_node(node.outputs[0], nid); self.emit_node(node.outputs[0], nid);
} }
Kind::CInt { .. } => { Kind::CInt { .. }
let unused = node.outputs.into_iter().all(|o| { if node.outputs.iter().all(|&o| {
let ond = &self.nodes[o]; let ond = &self.nodes[o];
matches!(ond.kind, Kind::BinOp { op } matches!(ond.kind, Kind::BinOp { op }
if op.imm_binop(ond.ty.is_signed(), 8).is_some() if op.imm_binop(ond.ty.is_signed(), 8).is_some()
&& self.nodes.is_const(ond.inputs[2]) && self.nodes.is_const(ond.inputs[2])
&& op.cond_op(ond.ty.is_signed()).is_none()) && op.cond_op(ond.ty.is_signed()).is_none())
}); }) =>
{
if !unused { self.nodes.lock(nid)
let ops = vec![self.drg(nid)]; }
self.add_instr(nid, ops); Kind::CInt { .. } => {
} let ops = vec![self.drg(nid)];
self.add_instr(nid, ops);
} }
Kind::Entry => { Kind::Entry => {
self.nodes[nid].ralloc_backref = self.add_block(nid); self.nodes[nid].ralloc_backref = self.add_block(nid);
@ -2410,11 +2461,20 @@ impl<'a> Function<'a> {
self.emit_node(o, nid); 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 } => { Kind::BinOp { op } => {
let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() }; let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() };
let ops = if let Kind::CInt { .. } = self.nodes[rhs].kind 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)] vec![self.drg(nid), self.urg(lhs)]
} else if op.binop(node.ty.is_signed(), 8).is_some() { } 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 => { Kind::Stck => {
let ops = vec![self.drg(nid)]; let ops = vec![self.drg(nid)];
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Phi | Kind::Arg { .. } | Kind::Mem => {} Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
Kind::Load { .. } => { 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 { if self.tys.size_of(node.ty) <= 8 {
let ops = match self.nodes[region].kind { let ops = match self.nodes[region].kind {
Kind::Stck => vec![self.drg(nid)], Kind::Stck => vec![self.drg(nid)],
@ -2494,18 +2569,22 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
} }
Kind::Stre { .. } if node.inputs[2] == VOID => self.nodes.lock(nid),
Kind::Stre { .. } => { Kind::Stre { .. } => {
let region = node.inputs[2]; let mut region = node.inputs[2];
if region != VOID { if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
let ops = match self.nodes[region].kind { && self.nodes.is_const(self.nodes[region].inputs[2])
_ if self.tys.size_of(node.ty) > 8 => { {
vec![self.urg(region), self.urg(self.nodes[node.inputs[1]].inputs[1])] region = self.nodes[region].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 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; return;
} }
//println!("{output}");
crate::test_run_vm(&out, output); crate::test_run_vm(&out, output);
} }
@ -2894,5 +2971,6 @@ mod tests {
//tests_ptr_to_ptr_copy; //tests_ptr_to_ptr_copy;
//wide_ret; //wide_ret;
pointer_opts; pointer_opts;
conditional_stores;
} }
} }

View file

@ -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(())

View file

@ -6,12 +6,12 @@ fib:
JGTU r2, r32, :0 JGTU r2, r32, :0
JMP :1 JMP :1
0: CP r33, r2 0: CP r33, r2
ADDI64 r2, r33, -1d SUB64 r2, r33, r1
CP r34, r33 CP r34, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r2, r34 CP r2, r34
CP r35, r1 CP r35, r1
ADDI64 r2, r2, -2d SUB64 r2, r2, r32
JAL r31, r0, :fib JAL r31, r0, :fib
ADD64 r1, r1, r35 ADD64 r1, r1, r35
1: LD r31, r254, 0a, 40h 1: LD r31, r254, 0a, 40h
@ -25,6 +25,6 @@ main:
LD r31, r254, 0a, 8h LD r31, r254, 0a, 8h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 225 code size: 211
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -1,13 +1,14 @@
fib: fib:
LI64 r7, 1d LI64 r4, 1d
LI64 r4, 0d LI64 r5, 0d
CP r1, r4 CP r1, r5
2: JNE r2, r4, :0 CP r10, r4
2: JNE r2, r5, :0
JMP :1 JMP :1
0: ADD64 r3, r7, r1 0: ADD64 r3, r10, r1
ADDI64 r2, r2, -1d SUB64 r2, r2, r4
CP r1, r7 CP r1, r10
CP r7, r3 CP r10, r3
JMP :2 JMP :2
1: JALA r0, r31, 0a 1: JALA r0, r31, 0a
main: main:
@ -18,6 +19,6 @@ main:
LD r31, r254, 0a, 8h LD r31, r254, 0a, 8h
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 154 code size: 150
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -3,23 +3,17 @@ clobber:
ST r3, r2, 0a, 8h ST r3, r2, 0a, 8h
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -64d ADDI64 r254, r254, -32d
ST r31, r254, 8a, 56h ST r31, r254, 8a, 24h
LI64 r32, 2d LI64 r32, 2d
LI64 r33, 1d
LI64 r34, 0d
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
ST r34, r254, 0a, 8h
ST r33, r254, 0a, 8h
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
LD r35, r254, 0a, 8h
JAL r31, r0, :clobber JAL r31, r0, :clobber
LD r36, r254, 0a, 8h LD r33, r254, 0a, 8h
MULI64 r37, r35, 2d ADDI64 r1, r33, -4d
SUB64 r1, r37, r36 LD r31, r254, 8a, 24h
LD r31, r254, 8a, 56h ADDI64 r254, r254, 32d
ADDI64 r254, r254, 64d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 229 code size: 166
ret: 0 ret: 0
status: Ok(()) status: Ok(())