Compare commits

..

No commits in common. "6ad0b41759dacd5767b5c9cfbc1b3b11c025396a" and "58578dd4b2904a5b8df39c14ca6fc4bb519c1dec" have entirely different histories.

5 changed files with 206 additions and 343 deletions

View file

@ -452,8 +452,6 @@ mod ty {
builtin_type! { builtin_type! {
UNDECLARED; UNDECLARED;
LEFT_UNREACHABLE;
RIGHT_UNREACHABLE;
NEVER; NEVER;
VOID; VOID;
TYPE; TYPE;
@ -466,7 +464,8 @@ mod ty {
I16; I16;
I32; I32;
INT; INT;
LEFT_UNREACHABLE;
RIGHT_UNREACHABLE;
} }
macro_rules! type_kind { macro_rules! type_kind {

View file

@ -210,9 +210,7 @@ impl<'a, 'b> Parser<'a, 'b> {
); );
} }
let Ok(index) = self.ctx.idents.binary_search_by_key(&id, |s| s.ident) else { let index = self.ctx.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up");
self.report(pos, "the identifier is rezerved for a builtin (proably)");
};
if core::mem::replace(&mut self.ctx.idents[index].declared, true) { if core::mem::replace(&mut self.ctx.idents[index].declared, true) {
self.report( self.report(
pos, pos,

View file

@ -9,7 +9,8 @@ use {
idfl::{self}, idfl::{self},
Expr, ExprRef, FileId, Pos, Expr, ExprRef, FileId, Pos,
}, },
reg, task, ty, reg, task,
ty::{self},
vc::{BitSet, Vc}, vc::{BitSet, Vc},
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types, Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
}, },
@ -34,16 +35,6 @@ type Nid = u16;
type Lookup = crate::ctx_map::CtxMap<Nid>; type Lookup = crate::ctx_map::CtxMap<Nid>;
trait StoreId: Sized {
fn to_store(self) -> Option<Self>;
}
impl StoreId for Nid {
fn to_store(self) -> Option<Self> {
(self != NEVER).then_some(self)
}
}
impl crate::ctx_map::CtxEntry for Nid { impl crate::ctx_map::CtxEntry for Nid {
type Ctx = [Result<Node, Nid>]; type Ctx = [Result<Node, Nid>];
type Key<'a> = (Kind, &'a [Nid], ty::Id); type Key<'a> = (Kind, &'a [Nid], ty::Id);
@ -425,7 +416,7 @@ impl Nodes {
Kind::Stck => write!(out, "stck: "), Kind::Stck => write!(out, "stck: "),
Kind::Load => write!(out, "load: "), Kind::Load => write!(out, "load: "),
Kind::Stre => write!(out, "stre: "), Kind::Stre => write!(out, "stre: "),
Kind::Mem => write!(out, " mem: "), _ => unreachable!(),
}?; }?;
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
@ -622,48 +613,26 @@ impl Nodes {
target target
} }
fn load_loop_var(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) { fn load_loop_value(&mut self, index: usize, value: &mut Value, loops: &mut [Loop]) {
self.load_loop_value( if value.id != 0 {
&mut |l| { debug_assert!(!value.var);
l.scope
.vars
.get_mut(index)
.map_or((ty::Id::VOID, &mut l.scope.store), |v| (v.ty, &mut v.value))
},
value,
loops,
);
}
fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) {
self.load_loop_value(&mut |l| (ty::Id::VOID, &mut l.scope.store), value, loops);
}
fn load_loop_value(
&mut self,
get_lvalue: &mut impl FnMut(&mut Loop) -> (ty::Id, &mut Nid),
value: &mut Nid,
loops: &mut [Loop],
) {
if *value != VOID {
return; return;
} }
let [loob, loops @ ..] = loops else { unreachable!() }; let [loob, loops @ ..] = loops else { unreachable!() };
let node = loob.node; let lvalue = &mut loob.scope.vars[index].value;
let (ty, lvalue) = get_lvalue(loob);
self.load_loop_value(get_lvalue, lvalue, loops); self.load_loop_value(index, lvalue, loops);
if !self[*lvalue].is_lazy_phi() { if !self[lvalue.id].is_lazy_phi() {
self.unlock(*value); self.unlock(value.id);
let inps = [node, *lvalue, VOID]; let inps = [loob.node, lvalue.id, VOID];
self.unlock(*lvalue); self.unlock(lvalue.id);
*lvalue = self.new_node_nop(ty, Kind::Phi, inps); lvalue.id = self.new_node_nop(lvalue.ty, Kind::Phi, inps);
self[*lvalue].lock_rc += 2; self[lvalue.id].lock_rc += 2;
} else { } else {
self.lock(*lvalue); self.lock(lvalue.id);
self.unlock(*value); self.unlock(value.id);
} }
*value = *lvalue; *value = *lvalue;
} }
@ -710,26 +679,26 @@ impl Nodes {
} }
fn lock_scope(&mut self, scope: &Scope) { fn lock_scope(&mut self, scope: &Scope) {
if let Some(str) = scope.store.to_store() { if let Some(str) = scope.store {
self.lock(str); self.lock(str);
} }
for &load in &scope.loads { for &load in &scope.loads {
self.lock(load); self.lock(load);
} }
for var in &scope.vars { for var in &scope.vars {
self.lock(var.value); self.lock(var.value.id);
} }
} }
fn unlock_remove_scope(&mut self, scope: &Scope) { fn unlock_remove_scope(&mut self, scope: &Scope) {
if let Some(str) = scope.store.to_store() { if let Some(str) = scope.store {
self.unlock_remove(str); self.unlock_remove(str);
} }
for &load in &scope.loads { for &load in &scope.loads {
self.unlock_remove(load); self.unlock_remove(load);
} }
for var in &scope.vars { for var in &scope.vars {
self.unlock_remove(var.value); self.unlock_remove(var.value.id);
} }
} }
} }
@ -799,7 +768,7 @@ pub enum Kind {
impl Kind { impl Kind {
fn is_pinned(&self) -> bool { fn is_pinned(&self) -> bool {
self.is_cfg() || matches!(self, Self::Phi | Self::Mem | Self::Arg { .. }) self.is_cfg() || matches!(self, Self::Phi | Self::Mem)
} }
fn is_cfg(&self) -> bool { fn is_cfg(&self) -> bool {
@ -811,6 +780,7 @@ impl Kind {
| Self::Entry | Self::Entry
| Self::Then | Self::Then
| Self::Else | Self::Else
| Self::Arg { .. }
| Self::Call { .. } | Self::Call { .. }
| Self::If | Self::If
| Self::Region | Self::Region
@ -880,24 +850,14 @@ struct Loop {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Variable { struct Variable {
id: Ident, id: Ident,
ty: ty::Id, value: Value,
value: Nid,
} }
#[derive(Default, Clone)] #[derive(Default, Clone)]
struct Scope { struct Scope {
vars: Vec<Variable>, vars: Vec<Variable>,
loads: Vec<Nid>, loads: Vec<Nid>,
store: Nid, store: Option<Nid>,
}
impl Scope {
pub fn iter_elems_mut(&mut self) -> impl Iterator<Item = (ty::Id, &mut Nid)> {
self.vars
.iter_mut()
.map(|v| (v.ty, &mut v.value))
.chain(core::iter::once((ty::Id::VOID, &mut self.store)))
}
} }
#[derive(Default)] #[derive(Default)]
@ -983,7 +943,7 @@ impl Default for Regalloc {
} }
} }
#[derive(Default, Clone, Copy, PartialEq, Eq)] #[derive(Default, Clone, Copy)]
struct Value { struct Value {
ty: ty::Id, ty: ty::Id,
var: bool, var: bool,
@ -1065,13 +1025,8 @@ impl Codegen {
} }
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid { fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
if value == NEVER {
return NEVER;
}
let mut vc = Vc::from([VOID, value, region]); let mut vc = Vc::from([VOID, value, region]);
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); if let Some(str) = self.ci.scope.store {
if let Some(str) = self.ci.scope.store.to_store() {
self.ci.nodes.unlock(str); self.ci.nodes.unlock(str);
vc.push(str); vc.push(str);
} }
@ -1086,15 +1041,13 @@ 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.scope.store = 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 {
debug_assert_ne!(region, VOID);
let mut vc = Vc::from([VOID, region]); let mut vc = Vc::from([VOID, region]);
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); if let Some(str) = self.ci.scope.store {
if let Some(str) = self.ci.scope.store.to_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);
@ -1133,13 +1086,14 @@ impl Codegen {
return Value::NEVER; return Value::NEVER;
}; };
self.ci.nodes.load_loop_var( self.ci.nodes.load_loop_value(
index, index,
&mut self.ci.scope.vars[index].value, &mut self.ci.scope.vars[index].value,
&mut self.ci.loops, &mut self.ci.loops,
); );
debug_assert_ne!(self.ci.scope.vars[index].value.ty, ty::Id::VOID);
Some(Value::var(index).ty(self.ci.scope.vars[index].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),
@ -1154,9 +1108,8 @@ impl Codegen {
}; };
let mut inps = Vc::from([self.ci.ctrl, value.id]); let mut inps = Vc::from([self.ci.ctrl, value.id]);
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); for &m in self.ci.scope.store.iter() {
if let Some(str) = self.ci.scope.store.to_store() { inps.push(m);
inps.push(str);
} }
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Return, inps); self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Return, inps);
@ -1249,7 +1202,7 @@ 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.scope.vars.push(Variable { id, value: value.id, ty: value.ty }); 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 } => {
@ -1261,8 +1214,8 @@ impl Codegen {
if dest.var { if dest.var {
self.ci.nodes.lock(value.id); self.ci.nodes.lock(value.id);
let var = &mut self.ci.scope.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.id); let prev = core::mem::replace(&mut var.value, value);
self.ci.nodes.unlock_remove(prev); self.ci.nodes.unlock_remove(prev.id);
} else if dest.ptr { } else if dest.ptr {
self.store_mem(dest.id, value.id); self.store_mem(dest.id, value.id);
} else { } else {
@ -1289,10 +1242,6 @@ impl Codegen {
[VOID], [VOID],
)) ))
} }
Expr::Directive { name: "as", args: [ty, expr], .. } => {
let ctx = Ctx::default().with_ty(self.ty(ty));
self.expr_ctx(expr, ctx)
}
Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => { Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => {
self.ci.call_count += 1; self.ci.call_count += 1;
let cfile = self.cfile().clone(); let cfile = self.cfile().clone();
@ -1345,7 +1294,7 @@ impl Codegen {
inps.push(value.id); inps.push(value.id);
} }
if let Some(str) = self.ci.scope.store.to_store() { if let Some(str) = self.ci.scope.store {
inps.push(str); inps.push(str);
} }
for load in self.ci.scope.loads.drain(..) { for load in self.ci.scope.loads.drain(..) {
@ -1368,59 +1317,6 @@ impl Codegen {
Some(Value::new(self.ci.ctrl).ty(sig.ret)) Some(Value::new(self.ci.ctrl).ty(sig.ret))
} }
Expr::Tupl { pos, ty, fields, .. } => {
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
self.report(
pos,
"the type of struct cannot be inferred from context, \
use an explicit type instead: <type>.{ ... }",
);
return Value::NEVER;
};
let ty::Kind::Struct(s) = sty.expand() else {
let inferred = if ty.is_some() { "" } else { "inferred " };
self.report(
pos,
fa!(
"the {inferred}type of the constructor is `{}`, \
but thats not a struct",
self.ty_display(sty)
),
);
return Value::NEVER;
};
// TODO: dont allocate
let mut offs = OffsetIter::new(s, &self.tys);
let mem = self.ci.nodes.new_node(sty, Kind::Stck, [VOID, MEM]);
for field in fields {
let Some((ty, offset)) = offs.next_ty(&self.tys) else {
self.report(field.pos(), "this init argumen overflows the field count");
break;
};
let value = self.expr_ctx(field, Ctx::default().with_ty(ty))?;
let mem = self.offset(mem, ty, offset);
self.store_mem(mem, value.id);
}
let field_list = offs
.into_iter(&self.tys)
.map(|(f, ..)| self.tys.names.ident_str(f.name))
.intersperse(", ")
.collect::<String>();
if !field_list.is_empty() {
self.report(
pos,
fa!("the struct initializer is missing {field_list} \
(append them to the end of the constructor)"),
);
}
Some(Value::ptr(mem).ty(sty))
}
Expr::Ctor { pos, ty, fields, .. } => { Expr::Ctor { pos, ty, fields, .. } => {
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else { let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
self.report( self.report(
@ -1504,7 +1400,7 @@ impl Codegen {
self.ci.nodes.lock(self.ci.ctrl); self.ci.nodes.lock(self.ci.ctrl);
for var in self.ci.scope.vars.drain(base..) { for var in self.ci.scope.vars.drain(base..) {
self.ci.nodes.unlock_remove(var.value); self.ci.nodes.unlock_remove(var.value.id);
} }
self.ci.nodes.unlock(self.ci.ctrl); self.ci.nodes.unlock(self.ci.ctrl);
@ -1519,8 +1415,8 @@ impl Codegen {
scope: self.ci.scope.clone(), scope: self.ci.scope.clone(),
}); });
for (_, var) in &mut self.ci.scope.iter_elems_mut() { for var in &mut self.ci.scope.vars {
*var = VOID; var.value = Value::VOID;
} }
self.ci.nodes.lock_scope(&self.ci.scope); self.ci.nodes.lock_scope(&self.ci.scope);
@ -1565,50 +1461,65 @@ impl Codegen {
core::mem::swap(&mut self.ci.scope, &mut bres); core::mem::swap(&mut self.ci.scope, &mut bres);
for (((_, dest_value), (_, &mut mut scope_value)), (_, &mut loop_value)) in self for ((dest_var, mut scope_var), loop_var) in
.ci self.ci.scope.vars.iter_mut().zip(scope.vars.drain(..)).zip(bres.vars.drain(..))
.scope
.iter_elems_mut()
.zip(scope.iter_elems_mut())
.zip(bres.iter_elems_mut())
{ {
self.ci.nodes.unlock(loop_value); self.ci.nodes.unlock(loop_var.value.id);
if loop_value != VOID { if loop_var.value.id != VOID {
self.ci.nodes.unlock(scope_value); self.ci.nodes.unlock(scope_var.value.id);
if loop_value != scope_value { if loop_var.value.id != scope_var.value.id {
scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value); scope_var.value.id = self.ci.nodes.modify_input(
self.ci.nodes.lock(scope_value); scope_var.value.id,
2,
loop_var.value.id,
);
self.ci.nodes.lock(scope_var.value.id);
} else { } else {
if *dest_value == scope_value { if dest_var.value.id == scope_var.value.id {
self.ci.nodes.unlock(*dest_value); self.ci.nodes.unlock(dest_var.value.id);
*dest_value = VOID; dest_var.value.id = VOID;
self.ci.nodes.lock(*dest_value); self.ci.nodes.lock(dest_var.value.id);
} }
let phi = &self.ci.nodes[scope_value]; let phi = &self.ci.nodes[scope_var.value.id];
debug_assert_eq!(phi.kind, Kind::Phi); debug_assert_eq!(phi.kind, Kind::Phi);
debug_assert_eq!(phi.inputs[2], VOID); debug_assert_eq!(phi.inputs[2], VOID);
debug_assert_eq!(phi.ty, scope_var.value.ty);
let prev = phi.inputs[1]; let prev = phi.inputs[1];
self.ci.nodes.replace(scope_value, prev); self.ci.nodes.replace(scope_var.value.id, prev);
scope_value = prev; scope_var.value.id = prev;
self.ci.nodes.lock(prev); self.ci.nodes.lock(prev);
} }
} }
if *dest_value == VOID { if dest_var.value.id == VOID {
self.ci.nodes.unlock(*dest_value); self.ci.nodes.unlock(dest_var.value.id);
*dest_value = scope_value; dest_var.value = scope_var.value;
self.ci.nodes.lock(*dest_value); self.ci.nodes.lock(dest_var.value.id);
} }
debug_assert!( debug_assert!(
self.ci.nodes[*dest_value].kind != Kind::Phi self.ci.nodes[dest_var.value.id].kind != Kind::Phi
|| self.ci.nodes[*dest_value].inputs[2] != 0 || self.ci.nodes[dest_var.value.id].inputs[2] != 0
); );
self.ci.nodes.unlock_remove(scope_value); self.ci.nodes.unlock_remove(scope_var.value.id);
} }
if bres.store != scope.store {
let (to_store, from_store) = (bres.store.unwrap(), scope.store.unwrap());
self.ci.nodes.unlock(to_store);
bres.store = Some(
self.ci
.nodes
.new_node(ty::Id::VOID, Kind::Phi, [node, from_store, to_store]),
);
self.ci.nodes.lock(bres.store.unwrap());
}
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)
@ -1639,9 +1550,8 @@ impl Codegen {
} }
} }
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
let orig_store = self.ci.scope.store; let orig_store = self.ci.scope.store;
if let Some(str) = orig_store.to_store() { if let Some(str) = orig_store {
self.ci.nodes.lock(str); self.ci.nodes.lock(str);
} }
let else_scope = self.ci.scope.clone(); let else_scope = self.ci.scope.clone();
@ -1658,7 +1568,7 @@ impl Codegen {
self.ci.ctrl self.ci.ctrl
}; };
if let Some(str) = orig_store.to_store() { if let Some(str) = orig_store {
self.ci.nodes.unlock_remove(str); self.ci.nodes.unlock_remove(str);
} }
@ -1717,8 +1627,12 @@ impl Codegen {
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_var(id, &mut self.ci.scope.vars[id].value, &mut self.ci.loops); self.ci.nodes.load_loop_value(
n.id = self.ci.scope.vars[id].value; id,
&mut self.ci.scope.vars[id].value,
&mut self.ci.loops,
);
*n = self.ci.scope.vars[id].value;
} }
} }
@ -1768,26 +1682,32 @@ impl Codegen {
from: &mut Scope, from: &mut Scope,
drop_from: bool, drop_from: bool,
) { ) {
for (i, ((ty, to_value), (_, from_value))) in for (i, (to_var, from_var)) in to.vars.iter_mut().zip(&mut from.vars).enumerate() {
to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate() if to_var.value.id != from_var.value.id {
{ nodes.load_loop_value(i, &mut from_var.value, loops);
if to_value != from_value { nodes.load_loop_value(i, &mut to_var.value, loops);
nodes.load_loop_var(i, from_value, loops); if to_var.value.id != from_var.value.id {
nodes.load_loop_var(i, to_value, loops); let ty = nodes[to_var.value.id].ty;
if to_value != from_value { debug_assert_eq!(ty, nodes[from_var.value.id].ty, "TODO: typecheck properly");
let inps = [ctrl, *from_value, *to_value];
nodes.unlock(*to_value); let inps = [ctrl, from_var.value.id, to_var.value.id];
*to_value = nodes.new_node(ty, Kind::Phi, inps); nodes.unlock(to_var.value.id);
nodes.lock(*to_value); to_var.value.id = nodes.new_node(ty, Kind::Phi, inps);
nodes.lock(to_var.value.id);
} }
} }
} }
for load in to.loads.drain(..) { if to.store != from.store {
nodes.unlock_remove(load); 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());
} }
for load in from.loads.drain(..) {
nodes.unlock_remove(load); to.loads.extend(&from.loads);
for &load in &from.loads {
nodes.lock(load);
} }
if drop_from { if drop_from {
@ -1835,8 +1755,6 @@ impl Codegen {
let mem = self.ci.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]); let mem = self.ci.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]);
debug_assert_eq!(mem, MEM); debug_assert_eq!(mem, MEM);
self.ci.nodes.lock(mem); self.ci.nodes.lock(mem);
self.ci.nodes.lock(end);
self.ci.scope.store = end;
let Expr::BinOp { let Expr::BinOp {
left: Expr::Ident { .. }, left: Expr::Ident { .. },
@ -1854,7 +1772,7 @@ 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.scope.vars.push(Variable { id: arg.id, value, ty }); self.ci.scope.vars.push(Variable { id: arg.id, value: Value::new(value).ty(ty) });
} }
let orig_vars = self.ci.scope.vars.clone(); let orig_vars = self.ci.scope.vars.clone();
@ -1863,7 +1781,6 @@ impl Codegen {
self.report(body.pos(), "expected all paths in the fucntion to return"); self.report(body.pos(), "expected all paths in the fucntion to return");
} }
self.ci.nodes.unlock(end);
self.ci.nodes.unlock(end); self.ci.nodes.unlock(end);
self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope)); self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope));
@ -2289,13 +2206,16 @@ impl Codegen {
#[track_caller] #[track_caller]
fn report(&self, pos: Pos, msg: impl core::fmt::Display) { fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
let mut buf = self.errors.borrow_mut(); let mut buf = self.errors.borrow_mut();
write!(buf, "{}", self.cfile().report(pos, msg)).unwrap(); writeln!(buf, "{}", self.cfile().report(pos, msg)).unwrap();
} }
#[track_caller] #[track_caller]
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) { fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
log::debug!("{ast:#?}"); log::debug!("{ast:#?}");
self.fatal_report(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})")); self.fatal_report(
ast.pos(),
fa!("compiler does not (yet) know how to handle ({hint}):\n{}", self.ast_display(ast)),
);
} }
fn cfile(&self) -> &parser::Ast { fn cfile(&self) -> &parser::Ast {
@ -2309,7 +2229,7 @@ impl Codegen {
fn gcm(&mut self) { fn gcm(&mut self) {
self.ci.nodes.visited.clear(self.ci.nodes.values.len()); self.ci.nodes.visited.clear(self.ci.nodes.values.len());
push_up(&mut self.ci.nodes); push_up(&mut self.ci.nodes, NEVER);
// TODO: handle infinte loops // TODO: handle infinte loops
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);
@ -2665,8 +2585,8 @@ 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 { .. } if node.inputs[2] == VOID => self.nodes.lock(nid),
Kind::Stre => { Kind::Stre { .. } => {
let mut region = node.inputs[2]; let mut region = node.inputs[2];
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add }) if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
&& self.nodes.is_const(self.nodes[region].inputs[2]) && self.nodes.is_const(self.nodes[region].inputs[2])
@ -2830,12 +2750,18 @@ fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
depth depth
} }
Kind::Start | Kind::End => 1, Kind::Start | Kind::End => 1,
u => unreachable!("{u:?}"), _ => unreachable!(),
}; };
nodes[target].loop_depth nodes[target].loop_depth
} }
fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool {
loop_depth(is, nodes) < loop_depth(then, nodes)
|| idepth(nodes, is) > idepth(nodes, then)
|| nodes[then].kind == Kind::If
}
fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth { fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
if target == VOID { if target == VOID {
return 0; return 0;
@ -2852,116 +2778,71 @@ fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
nodes[target].depth nodes[target].depth
} }
fn push_up(nodes: &mut Nodes) { fn push_up(nodes: &mut Nodes, node: Nid) {
fn collect_rpo(node: Nid, nodes: &mut Nodes, rpo: &mut Vec<Nid>) {
if !nodes.is_cfg(node) || !nodes.visited.set(node) {
return;
}
for i in 0..nodes[node].outputs.len() {
collect_rpo(nodes[node].outputs[i], nodes, rpo);
}
rpo.push(node);
}
fn push_up_impl(node: Nid, nodes: &mut Nodes) {
if !nodes.visited.set(node) { if !nodes.visited.set(node) {
return; return;
} }
for i in 0..nodes[node].inputs.len() {
let inp = nodes[node].inputs[i];
if !nodes[inp].kind.is_pinned() {
push_up_impl(inp, nodes);
}
}
if nodes[node].kind.is_pinned() { if nodes[node].kind.is_pinned() {
return; for i in 0..nodes[node].inputs.len() {
let i = nodes[node].inputs[i];
push_up(nodes, i);
} }
} else {
let mut deepest = VOID; let mut max = VOID;
for i in 1..nodes[node].inputs.len() { for i in 0..nodes[node].inputs.len() {
let inp = nodes[node].inputs[i]; let i = nodes[node].inputs[i];
if idepth(nodes, inp) > idepth(nodes, deepest) { let is_call = matches!(nodes[i].kind, Kind::Call { .. });
deepest = idom(nodes, inp); if nodes.is_cfg(i) && !is_call {
continue;
}
push_up(nodes, i);
if idepth(nodes, i) > idepth(nodes, max) {
max = if is_call { i } else { idom(nodes, i) };
} }
} }
if deepest == VOID { #[cfg(debug_assertions)]
{
nodes.check_dominance(node, max, false);
}
if max == VOID {
return; return;
} }
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap(); let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap();
nodes[0].outputs.remove(index); nodes[0].outputs.remove(index);
nodes[node].inputs[0] = deepest; nodes[node].inputs[0] = max;
debug_assert!( debug_assert!(
!nodes[deepest].outputs.contains(&node) !nodes[max].outputs.contains(&node) || matches!(nodes[max].kind, Kind::Call { .. }),
|| matches!(nodes[deepest].kind, Kind::Call { .. }), "{node} {:?} {max} {:?}",
"{node} {:?} {deepest} {:?}",
nodes[node], nodes[node],
nodes[deepest] nodes[max]
); );
nodes[deepest].outputs.push(node); nodes[max].outputs.push(node);
}
let mut rpo = vec![];
collect_rpo(VOID, nodes, &mut rpo);
for node in rpo.into_iter().rev() {
loop_depth(node, nodes);
for i in 0..nodes[node].inputs.len() {
push_up_impl(nodes[node].inputs[i], nodes);
}
if matches!(nodes[node].kind, Kind::Loop | Kind::Region) {
for i in 0..nodes[node].outputs.len() {
let usage = nodes[node].outputs[i];
if nodes[usage].kind == Kind::Phi {
push_up_impl(usage, nodes);
}
}
}
} }
} }
fn push_down(nodes: &mut Nodes, node: Nid) { fn push_down(nodes: &mut Nodes, node: Nid) {
fn is_forward_edge(usage: Nid, def: Nid, nodes: &mut Nodes) -> bool {
match nodes[usage].kind {
Kind::Phi => {
nodes[usage].inputs[2] != def || nodes[nodes[usage].inputs[0]].kind != Kind::Loop
}
Kind::Loop => nodes[usage].inputs[1] != def,
_ => true,
}
}
fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool {
loop_depth(is, nodes) < loop_depth(then, nodes)
|| idepth(nodes, is) > idepth(nodes, then)
|| nodes[then].kind == Kind::If
}
if !nodes.visited.set(node) { if !nodes.visited.set(node) {
return; return;
} }
for usage in nodes[node].outputs.clone() { // TODO: handle memory nodes first
if is_forward_edge(usage, node, nodes) {
push_down(nodes, usage);
}
}
if nodes[node].kind.is_pinned() { if nodes[node].kind.is_pinned() {
return; // TODO: use buffer to avoid allocation or better yet queue the location changes
for i in nodes[node].outputs.clone() {
push_down(nodes, i);
} }
} else {
let mut min = None::<Nid>; let mut min = None::<Nid>;
for i in 0..nodes[node].outputs.len() { for i in 0..nodes[node].outputs.len() {
let usage = nodes[node].outputs[i]; let i = nodes[node].outputs[i];
let ub = use_block(node, usage, nodes); push_down(nodes, i);
min = min.map(|m| common_dom(ub, m, nodes)).or(Some(ub)); let i = use_block(node, i, nodes);
min = min.map(|m| common_dom(i, m, nodes)).or(Some(i));
} }
let mut min = min.unwrap(); let mut min = min.unwrap();
@ -2994,6 +2875,7 @@ fn push_down(nodes: &mut Nodes, node: Nid) {
nodes[node].inputs[0] = min; nodes[node].inputs[0] = min;
nodes[min].outputs.push(node); nodes[min].outputs.push(node);
} }
}
fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid { fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid {
if nodes[from].kind != Kind::Phi { if nodes[from].kind != Kind::Phi {
@ -3083,7 +2965,7 @@ mod tests {
//generic_functions; //generic_functions;
//c_strings; //c_strings;
//struct_patterns; //struct_patterns;
arrays; //arrays;
//struct_return_from_module_function; //struct_return_from_module_function;
////comptime_pointers; ////comptime_pointers;
//sort_something_viredly; //sort_something_viredly;

View file

@ -38,15 +38,16 @@ odher_pass:
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
pass: pass:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -40d
ST r31, r254, 0a, 32h ST r31, r254, 0a, 40h
CP r32, r2 CP r32, r2
LD r33, r32, 0a, 8h CP r33, r32
LD r34, r32, 8a, 8h LD r34, r33, 0a, 8h
SUB64 r1, r33, r34 LD r35, r33, 8a, 8h
LD r31, r254, 0a, 32h SUB64 r1, r34, r35
ADDI64 r254, r254, 32d LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 437 code size: 440
ret: 3 ret: 3
status: Ok(()) status: Ok(())

View file

@ -1,17 +0,0 @@
main:
ADDI64 r254, r254, -8d
LI64 r4, 0d
LI64 r2, 10d
ADDI64 r5, r254, 0d
ST r2, r254, 0a, 8h
2: LD r1, r254, 0a, 8h
JNE r1, r4, :0
JMP :1
0: ADDI64 r1, r1, -1d
ST r1, r254, 0a, 8h
JMP :2
1: ADDI64 r254, r254, 8d
JALA r0, r31, 0a
code size: 137
ret: 0
status: Ok(())