This commit is contained in:
mlokr 2024-09-08 17:11:33 +02:00
parent bb41da484f
commit 50f3350418
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
4 changed files with 217 additions and 262 deletions

View file

@ -435,8 +435,7 @@ check_platform := fn(): int {
} }
set_pixel := fn(x: int, y: int, width: int): int { set_pixel := fn(x: int, y: int, width: int): int {
pix_offset := y * width + x return y * width + x
return 0
} }
main := fn(): int { main := fn(): int {
@ -445,21 +444,23 @@ main := fn(): int {
height := 30 height := 30
x := 0 x := 0
y := 0 y := 0
t := 0
i := 0
loop { loop {
if x <= height + 1 { if x < width {
_d := set_pixel(x, y, width) t += set_pixel(x, y, width)
x += 1 x += 1
} else { } else {
_d := set_pixel(x, y, width)
x = 0 x = 0
y += 1 y += 1
if set_pixel(x, y, width) != i return 0
} }
if y == width {
break i += 1
if y == width break
} }
} return t
return 0
} }
``` ```
@ -826,3 +827,23 @@ multiple_breaks := fn(arg: int): int {
// return arg // return arg
//} //}
``` ```
#### writing_into_string
```hb
outl := fn(): void {
msg := "\0\0\0\0\0\0\0\0"
@as(u8, 0)
return
}
inl := fn(): void {
msg := "\0\0\0\0"
return
}
main := fn(): void {
outl()
inl()
return
}
```

View file

@ -1037,6 +1037,7 @@ mod task {
} }
} }
#[derive(Debug)]
struct FTask { struct FTask {
file: FileId, file: FileId,
id: ty::Func, id: ty::Func,
@ -2607,12 +2608,19 @@ impl Codegen {
self.handle_task(task); self.handle_task(task);
} }
//println!("{}", std::backtrace::Backtrace::capture());
let base = self.output.code.len() as u32; let base = self.output.code.len() as u32;
let prev_data_len = self.output.string_data.len(); let prev_data_len = self.output.string_data.len();
self.output.code.append(&mut self.output.string_data); self.output.code.append(&mut self.output.string_data);
// we drain these when linking // we drain these when linking
for srel in self.output.strings.iter_mut().filter(|s| !s.shifted) { for srel in self.output.strings.iter_mut().filter(|s| !s.shifted) {
debug_assert!(srel.range.end <= prev_data_len as u32); dbg!(&srel.range);
debug_assert!(
srel.range.end <= prev_data_len as u32,
"{} <= {}",
srel.range.end,
prev_data_len as u32
);
debug_assert!(srel.range.start <= srel.range.end); debug_assert!(srel.range.start <= srel.range.end);
srel.range.start += base; srel.range.start += base;
srel.range.end += base; srel.range.end += base;
@ -2639,7 +2647,7 @@ impl Codegen {
self.ci.snap = self.output.snap(); self.ci.snap = self.output.snap();
let Expr::BinOp { let Expr::BinOp {
left: Expr::Ident { .. }, left: Expr::Ident { name, .. },
op: TokenKind::Decl, op: TokenKind::Decl,
right: &Expr::Closure { body, args, .. }, right: &Expr::Closure { body, args, .. },
} = expr } = expr
@ -2647,6 +2655,8 @@ impl Codegen {
unreachable!("{expr}") unreachable!("{expr}")
}; };
log::dbg!(name);
self.output.emit_prelude(); self.output.emit_prelude();
let mut parama = self.tys.parama(sig.ret); let mut parama = self.tys.parama(sig.ret);
@ -3558,7 +3568,7 @@ mod tests {
comments => README; comments => README;
if_statements => README; if_statements => README;
loops => README; loops => README;
fb_driver => README; //fb_driver => README;
pointers => README; pointers => README;
structs => README; structs => README;
different_types => README; different_types => README;
@ -3581,5 +3591,6 @@ mod tests {
inline_test => README; inline_test => README;
some_generic_code => README; some_generic_code => README;
integer_inference_issues => README; integer_inference_issues => README;
writing_into_string => README;
} }
} }

View file

@ -13,17 +13,14 @@ use {
HashMap, HashMap,
}, },
core::fmt, core::fmt,
hbvm::mem::softpaging::lookup,
std::{ std::{
cell::RefCell, cell::RefCell,
collections::{hash_map, BTreeMap}, collections::{hash_map, BTreeMap},
default,
fmt::Display, fmt::Display,
hash::{Hash as _, Hasher}, hash::{Hash as _, Hasher},
mem, mem,
ops::{self, Range}, ops::{self, Range},
rc::Rc, rc::Rc,
u32, usize,
}, },
}; };
@ -546,7 +543,7 @@ impl Nodes {
}; };
let mut lookup_meta = None; let mut lookup_meta = None;
if node.kind != Kind::Phi || node.inputs[2] != 0 { if !node.is_lazy_phi() {
let (raw_entry, hash) = Self::find_node(&mut self.lookup, &self.values, &node); let (raw_entry, hash) = Self::find_node(&mut self.lookup, &self.values, &node);
let entry = match raw_entry { let entry = match raw_entry {
@ -597,7 +594,7 @@ impl Nodes {
} }
fn remove_node_lookup(&mut self, target: Nid) { fn remove_node_lookup(&mut self, target: Nid) {
if self[target].kind != Kind::Phi || self[target].inputs[2] != 0 { if !self[target].is_lazy_phi() {
match Self::find_node( match Self::find_node(
&mut self.lookup, &mut self.lookup,
&self.values, &self.values,
@ -658,7 +655,7 @@ impl Nodes {
Kind::BinOp { op } => return self.peephole_binop(target, op), Kind::BinOp { op } => return self.peephole_binop(target, op),
Kind::Return => {} Kind::Return => {}
Kind::Tuple { .. } => {} Kind::Tuple { .. } => {}
Kind::ConstInt { .. } => {} Kind::CInt { .. } => {}
Kind::Call { .. } => {} Kind::Call { .. } => {}
Kind::If => return self.peephole_if(target), Kind::If => return self.peephole_if(target),
Kind::Region => {} Kind::Region => {}
@ -678,7 +675,7 @@ impl Nodes {
fn peephole_if(&mut self, target: Nid) -> Option<Nid> { fn peephole_if(&mut self, target: Nid) -> Option<Nid> {
let cond = self[target].inputs[1]; let cond = self[target].inputs[1];
if let Kind::ConstInt { value } = self[cond].kind { if let Kind::CInt { value } = self[cond].kind {
let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE }; let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE };
return Some(self.new_node_nop(ty, Kind::If, [self[target].inputs[0], cond])); return Some(self.new_node_nop(ty, Kind::If, [self[target].inputs[0], cond]));
} }
@ -687,41 +684,33 @@ impl Nodes {
} }
fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> { fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
use TokenKind as T; use {Kind as K, TokenKind as T};
let &[mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() }; let &[ctrl, mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() };
let ty = self[target].ty;
if let (&K::CInt { value: a }, &K::CInt { value: b }) = (&self[lhs].kind, &self[rhs].kind) {
return Some(self.new_node(ty, K::CInt { value: op.apply(a, b) }, []));
}
if lhs == rhs { if lhs == rhs {
match op { match op {
T::Sub => { T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [])),
return Some(self.new_node(self[target].ty, Kind::ConstInt { value: 0 }, []));
}
T::Add => { T::Add => {
let rhs = self.new_node(self[target].ty, Kind::ConstInt { value: 2 }, []); let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, []);
return Some( return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]));
self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [lhs, rhs]),
);
} }
_ => {} _ => {}
} }
} }
if let (&Kind::ConstInt { value: a }, &Kind::ConstInt { value: b }) = // this is more general the pushing constants to left to help deduplicate expressions more
(&self[lhs].kind, &self[rhs].kind)
{
return Some(self.new_node(
self[target].ty,
Kind::ConstInt { value: op.apply(a, b) },
[],
));
}
let mut changed = false; let mut changed = false;
if op.is_comutative() && self[lhs].kind < self[rhs].kind { if op.is_comutative() && self[lhs].key() < self[rhs].key() {
std::mem::swap(&mut lhs, &mut rhs); std::mem::swap(&mut lhs, &mut rhs);
changed = true; changed = true;
} }
if let Kind::ConstInt { value } = self[rhs].kind { if let K::CInt { value } = self[rhs].kind {
match (op, value) { match (op, value) {
(T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs), (T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs),
(T::Mul, 0) => return Some(rhs), (T::Mul, 0) => return Some(rhs),
@ -729,56 +718,46 @@ impl Nodes {
} }
} }
if op.is_comutative() && self[lhs].kind == (Kind::BinOp { op }) { if op.is_comutative() && self[lhs].kind == (K::BinOp { op }) {
if let Kind::ConstInt { value: a } = self[self[lhs].inputs[1]].kind let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
&& let Kind::ConstInt { value: b } = self[rhs].kind if let K::CInt { value: av } = self[b].kind
&& let K::CInt { value: bv } = self[rhs].kind
{ {
let new_rhs = // (a op #b) op #c => a op (#b op #c)
self.new_node(self[target].ty, Kind::ConstInt { value: op.apply(a, b) }, []); let new_rhs = self.new_node_nop(ty, K::CInt { value: op.apply(av, bv) }, []);
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [ return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
self[lhs].inputs[0],
new_rhs,
]));
} }
if self.is_const(self[lhs].inputs[1]) { if self.is_const(b) {
let new_lhs = // (a op #b) op c => (a op c) op #b
self.new_node(self[target].ty, Kind::BinOp { op }, [self[lhs].inputs[0], rhs]); let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]);
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [ return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b]));
new_lhs,
self[lhs].inputs[1],
]));
} }
} }
if op == T::Add if op == T::Add
&& self[lhs].kind == (Kind::BinOp { op: T::Mul }) && self[lhs].kind == (K::BinOp { op: T::Mul })
&& self[lhs].inputs[0] == rhs && self[lhs].inputs[1] == rhs
&& let Kind::ConstInt { value } = self[self[lhs].inputs[1]].kind && let K::CInt { value } = self[self[lhs].inputs[2]].kind
{ {
let new_rhs = self.new_node(self[target].ty, Kind::ConstInt { value: value + 1 }, []); // a * #n + a => a * (#n + 1)
return Some( let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, []);
self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [rhs, new_rhs]), return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
);
} }
if op == T::Sub && self[lhs].kind == (Kind::BinOp { op }) { if op == T::Sub && self[lhs].kind == (K::BinOp { op }) {
// (a - b) - c => a - (b + c) // (a - b) - c => a - (b + c)
let &[a, b] = self[lhs].inputs.as_slice() else { unreachable!() }; let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
let c = rhs; let c = rhs;
let new_rhs = self.new_node(self[target].ty, Kind::BinOp { op: T::Add }, [b, c]); let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]);
return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [a, new_rhs])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
} }
if changed { changed.then(|| self.new_node(ty, self[target].kind, [ctrl, lhs, rhs]))
return Some(self.new_node(self[target].ty, self[target].kind, [lhs, rhs]));
}
None
} }
fn is_const(&self, id: Nid) -> bool { fn is_const(&self, id: Nid) -> bool {
matches!(self[id].kind, Kind::ConstInt { .. }) matches!(self[id].kind, Kind::CInt { .. })
} }
fn replace(&mut self, target: Nid, with: Nid) { fn replace(&mut self, target: Nid, with: Nid) {
@ -861,13 +840,13 @@ impl Nodes {
} }
Kind::Return => { Kind::Return => {
write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?; write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?;
if self[node].inputs[2] != 0 { if self[node].inputs[1] != 0 {
self.fmt(f, self[node].inputs[2], rcs)?; self.fmt(f, self[node].inputs[1], rcs)?;
} }
writeln!(f)?; writeln!(f)?;
self.fmt(f, self[node].inputs[1], rcs)?; self.fmt(f, self[node].inputs[1], rcs)?;
} }
Kind::ConstInt { value } => write!(f, "{}", value)?, Kind::CInt { value } => write!(f, "{}", value)?,
Kind::End => { Kind::End => {
if is_ready() { if is_ready() {
writeln!(f, "{}: {:?}", node, self[node].kind)?; writeln!(f, "{}: {:?}", node, self[node].kind)?;
@ -1015,12 +994,6 @@ impl Nodes {
} }
} }
fn check_scope_integrity(&self, scope: &[Variable]) {
for v in scope {
debug_assert!(self[v.value].lock_rc > 0);
}
}
fn climb_expr(&mut self, from: Nid, mut for_each: impl FnMut(Nid, &Node) -> bool) -> bool { fn climb_expr(&mut self, from: Nid, mut for_each: impl FnMut(Nid, &Node) -> bool) -> bool {
fn climb_impl( fn climb_impl(
nodes: &mut Nodes, nodes: &mut Nodes,
@ -1050,6 +1023,32 @@ impl Nodes {
} }
target target
} }
fn load_loop_value(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) {
if *value != 0 {
return;
}
let [loob, loops @ ..] = loops else { unreachable!() };
let lvalue = &mut loob.scope[index].value;
self.load_loop_value(index, lvalue, loops);
if !self[*lvalue].is_lazy_phi() {
self.unlock(*value);
let inps = [loob.node, *lvalue, 0];
self.unlock(inps[1]);
let ty = self[inps[1]].ty;
let phi = self.new_node_nop(ty, Kind::Phi, inps);
self[phi].lock_rc += 2;
*value = phi;
*lvalue = phi;
} else {
self.unlock_remove(*value);
*value = *lvalue;
self.lock(*value);
}
}
} }
impl ops::Index<u32> for Nodes { impl ops::Index<u32> for Nodes {
@ -1075,7 +1074,7 @@ pub enum Kind {
Region, Region,
Loop, Loop,
Return, Return,
ConstInt { value: i64 }, CInt { value: i64 },
Phi, Phi,
Tuple { index: u32 }, Tuple { index: u32 },
BinOp { op: lexer::TokenKind }, BinOp { op: lexer::TokenKind },
@ -1091,7 +1090,7 @@ impl Kind {
impl fmt::Display for Kind { impl fmt::Display for Kind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Kind::ConstInt { value } => write!(f, "#{value}"), Kind::CInt { value } => write!(f, "#{value}"),
Kind::Tuple { index } => write!(f, "tupl[{index}]"), Kind::Tuple { index } => write!(f, "tupl[{index}]"),
Kind::BinOp { op } => write!(f, "{op}"), Kind::BinOp { op } => write!(f, "{op}"),
Kind::Call { func, .. } => write!(f, "call {func}"), Kind::Call { func, .. } => write!(f, "call {func}"),
@ -1100,8 +1099,6 @@ impl fmt::Display for Kind {
} }
} }
const MAX_INPUTS: usize = 3;
#[derive(Debug)] #[derive(Debug)]
struct Node { struct Node {
inputs: Vec<Nid>, inputs: Vec<Nid>,
@ -1118,8 +1115,12 @@ impl Node {
self.outputs.len() + self.lock_rc as usize == 0 self.outputs.len() + self.lock_rc as usize == 0
} }
fn key(&self) -> (&[Nid], Kind, ty::Id) { fn key(&self) -> (Kind, &[Nid], ty::Id) {
(&self.inputs, self.kind, self.ty) (self.kind, &self.inputs, self.ty)
}
fn is_lazy_phi(&self) -> bool {
self.kind == Kind::Phi && self.inputs[2] == 0
} }
} }
@ -1148,10 +1149,8 @@ type ArrayLen = u32;
struct Loop { struct Loop {
node: Nid, node: Nid,
continue_: Nid, ctrl: [Nid; 2],
continue_scope: Vec<Variable>, ctrl_scope: [Vec<Variable>; 2],
break_: Nid,
break_scope: Vec<Variable>,
scope: Vec<Variable>, scope: Vec<Variable>,
} }
@ -1248,7 +1247,7 @@ impl ItemCtx {
kind: Kind::BinOp { .. } kind: Kind::BinOp { .. }
| Kind::Call { .. } | Kind::Call { .. }
| Kind::Phi | Kind::Phi
| Kind::ConstInt { .. }, | Kind::CInt { .. },
.. ..
}) })
) || matches!( ) || matches!(
@ -1708,27 +1707,11 @@ impl Codegen {
return Some(self.ci.end); return Some(self.ci.end);
}; };
if self.ci.vars[index].value == 0 { self.ci.nodes.load_loop_value(
let loob = self.ci.loops.last_mut().unwrap(); index,
if self.ci.nodes[loob.scope[index].value].kind != Kind::Phi &mut self.ci.vars[index].value,
|| self.ci.nodes[loob.scope[index].value].inputs[0] != loob.node &mut self.ci.loops,
{ );
self.ci.nodes.unlock(self.ci.vars[index].value);
let inps = [loob.node, loob.scope[index].value, 0];
self.ci.nodes.unlock(inps[1]);
let ty = self.ci.nodes[inps[1]].ty;
let phi = self.ci.nodes.new_node_nop(ty, Kind::Phi, inps);
self.ci.nodes[phi].lock_rc += 2;
self.ci.vars[index].value = phi;
loob.scope[index].value = phi;
} else {
self.ci.nodes.unlock_remove(self.ci.vars[index].value);
self.ci.vars[index].value = loob.scope[index].value;
self.ci.nodes.lock(self.ci.vars[index].value);
}
}
self.ci.nodes.check_scope_integrity(&self.ci.vars);
Some(self.ci.vars[index].value) Some(self.ci.vars[index].value)
} }
@ -1764,9 +1747,8 @@ impl Codegen {
false, false,
"right operand", "right operand",
); );
let id = let inps = [0, lhs, rhs];
self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, [lhs, rhs]); Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
Some(id)
} }
Expr::If { cond, then, else_, .. } => { Expr::If { cond, then, else_, .. } => {
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?; let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
@ -1791,7 +1773,7 @@ impl Codegen {
} }
} }
let else_scope = self.ci.vars.clone(); let mut else_scope = self.ci.vars.clone();
for &el in &self.ci.vars { for &el in &self.ci.vars {
self.ci.nodes.lock(el.value); self.ci.nodes.lock(el.value);
} }
@ -1800,7 +1782,7 @@ impl Codegen {
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [if_node]); self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [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 then_scope = std::mem::replace(&mut self.ci.vars, else_scope); let mut then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
self.ci.ctrl = self.ci.ctrl =
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]); self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]);
let rcntrl = if let Some(else_) = else_ { let rcntrl = if let Some(else_) = else_ {
@ -1813,31 +1795,36 @@ impl Codegen {
for then_var in then_scope { for then_var in then_scope {
self.ci.nodes.unlock_remove(then_var.value); self.ci.nodes.unlock_remove(then_var.value);
} }
self.ci.nodes.check_scope_integrity(&self.ci.vars);
return None; return None;
} else if lcntrl == Nid::MAX { } else if lcntrl == Nid::MAX {
for then_var in then_scope { for then_var in then_scope {
self.ci.nodes.unlock_remove(then_var.value); self.ci.nodes.unlock_remove(then_var.value);
} }
self.ci.nodes.check_scope_integrity(&self.ci.vars);
return Some(0); return Some(0);
} else if rcntrl == Nid::MAX { } else if rcntrl == Nid::MAX {
for else_var in &self.ci.vars { for else_var in &self.ci.vars {
self.ci.nodes.unlock_remove(else_var.value); self.ci.nodes.unlock_remove(else_var.value);
} }
self.ci.vars = then_scope; self.ci.vars = then_scope;
self.ci.nodes.check_scope_integrity(&self.ci.vars);
self.ci.ctrl = lcntrl; self.ci.ctrl = lcntrl;
return Some(0); return Some(0);
} }
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Region, [lcntrl, rcntrl]); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Region, [lcntrl, rcntrl]);
for (else_var, then_var) in self.ci.vars.iter_mut().zip(then_scope) { else_scope = std::mem::take(&mut self.ci.vars);
for (i, (else_var, then_var)) in
else_scope.iter_mut().zip(&mut then_scope).enumerate()
{
if else_var.value == then_var.value { if else_var.value == then_var.value {
self.ci.nodes.unlock_remove(then_var.value); self.ci.nodes.unlock_remove(then_var.value);
continue; continue;
} }
self.ci.nodes.load_loop_value(i, &mut then_var.value, &mut self.ci.loops);
self.ci.nodes.load_loop_value(i, &mut else_var.value, &mut self.ci.loops);
self.ci.nodes.unlock(then_var.value); self.ci.nodes.unlock(then_var.value);
let ty = self.ci.nodes[else_var.value].ty; let ty = self.ci.nodes[else_var.value].ty;
@ -1855,7 +1842,8 @@ impl Codegen {
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps); else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value); self.ci.nodes.lock(else_var.value);
} }
self.ci.nodes.check_scope_integrity(&self.ci.vars);
self.ci.vars = else_scope;
Some(0) Some(0)
} }
@ -1863,10 +1851,8 @@ impl Codegen {
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Loop, [self.ci.ctrl; 2]); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Loop, [self.ci.ctrl; 2]);
self.ci.loops.push(Loop { self.ci.loops.push(Loop {
node: self.ci.ctrl, node: self.ci.ctrl,
continue_: Nid::MAX, ctrl: [Nid::MAX; 2],
continue_scope: vec![], ctrl_scope: std::array::from_fn(|_| vec![]),
break_: Nid::MAX,
break_scope: vec![],
scope: self.ci.vars.clone(), scope: self.ci.vars.clone(),
}); });
@ -1877,52 +1863,27 @@ impl Codegen {
self.expr(body); self.expr(body);
let Loop { node, continue_, mut continue_scope, break_, mut break_scope, scope } = if self.ci.loops.last_mut().unwrap().ctrl[0] != Nid::MAX {
self.jump_to(0, 0);
self.ci.ctrl = self.ci.loops.last_mut().unwrap().ctrl[0];
}
let Loop { node, ctrl: [.., bre], ctrl_scope: [.., mut bre_scope], scope } =
self.ci.loops.pop().unwrap(); self.ci.loops.pop().unwrap();
if continue_ != Nid::MAX {
self.ci.ctrl =
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, continue_]);
std::mem::swap(&mut self.ci.vars, &mut continue_scope);
for (else_var, then_var) in self.ci.vars.iter_mut().zip(continue_scope) {
if else_var.value == then_var.value {
self.ci.nodes.unlock_remove(then_var.value);
continue;
}
self.ci.nodes.unlock(then_var.value);
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [self.ci.ctrl, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
self.ci.nodes.check_scope_integrity(&self.ci.vars);
}
self.ci.nodes.modify_input(node, 1, self.ci.ctrl); self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
self.ci.ctrl = break_; self.ci.ctrl = bre;
if break_ == Nid::MAX { if bre == Nid::MAX {
return None; return None;
} }
self.ci.nodes.lock(self.ci.ctrl); self.ci.nodes.lock(self.ci.ctrl);
std::mem::swap(&mut self.ci.vars, &mut break_scope); std::mem::swap(&mut self.ci.vars, &mut bre_scope);
self.ci.nodes.check_scope_integrity(&self.ci.vars);
self.ci.nodes.check_scope_integrity(&break_scope);
self.ci.nodes.check_scope_integrity(&scope);
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(break_scope) self.ci.vars.iter_mut().zip(scope).zip(bre_scope)
{ {
self.ci.nodes.unlock(loop_var.value); self.ci.nodes.unlock(loop_var.value);
@ -1956,86 +1917,8 @@ impl Codegen {
Some(0) Some(0)
} }
Expr::Break { pos } => { Expr::Break { pos } => self.jump_to(pos, 1),
let Some(loob) = self.ci.loops.last_mut() else { Expr::Continue { pos } => self.jump_to(pos, 0),
self.report(pos, "break outside a loop");
return None;
};
if loob.break_ == Nid::MAX {
loob.break_ = self.ci.ctrl;
loob.break_scope = self.ci.vars[..loob.scope.len()].to_owned();
for v in &loob.break_scope {
self.ci.nodes.lock(v.value)
}
} else {
loob.break_ =
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.break_]);
for (else_var, then_var) in loob.break_scope.iter_mut().zip(&self.ci.vars) {
if else_var.value == then_var.value {
continue;
}
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [loob.break_, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
self.ci.nodes.check_scope_integrity(&self.ci.vars);
self.ci.nodes.check_scope_integrity(&loob.break_scope);
}
self.ci.ctrl = self.ci.end;
None
}
Expr::Continue { pos } => {
todo!();
let Some(loob) = self.ci.loops.last_mut() else {
self.report(pos, "break outside a loop");
return None;
};
if loob.continue_ == Nid::MAX {
loob.continue_ = self.ci.ctrl;
loob.continue_scope = self.ci.vars[..loob.scope.len()].to_owned();
for v in &loob.continue_scope {
self.ci.nodes.lock(v.value)
}
} else {
loob.continue_ = self
.ci
.nodes
.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.continue_]);
for (else_var, then_var) in loob.continue_scope.iter_mut().zip(&self.ci.vars) {
if else_var.value == then_var.value {
continue;
}
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(
ty, self.ci.nodes[then_var.value].ty,
"TODO: typecheck properly"
);
let inps = [loob.continue_, then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
self.ci.nodes.check_scope_integrity(&self.ci.vars);
}
self.ci.ctrl = self.ci.end;
None
}
Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => { Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => {
self.ci.call_count += 1; self.ci.call_count += 1;
let func = self.find_or_declare(pos, self.ci.file, Some(id), name); let func = self.find_or_declare(pos, self.ci.file, Some(id), name);
@ -2097,16 +1980,15 @@ impl Codegen {
0 0
}; };
_ = self.ci.nodes[self.ci.ctrl]; let inps = [self.ci.ctrl, value];
_ = self.ci.nodes[self.ci.end];
_ = self.ci.nodes[value];
let inps = [self.ci.ctrl, self.ci.end, value];
let out = &mut String::new(); let out = &mut String::new();
self.report_log_to(pos, "returning here", out); self.report_log_to(pos, "returning here", out);
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
self.ci.nodes[self.ci.end].inputs.push(self.ci.ctrl);
self.ci.nodes[self.ci.ctrl].outputs.push(self.ci.end);
let expected = *self.ci.ret.get_or_insert(self.tof(value)); let expected = *self.ci.ret.get_or_insert(self.tof(value));
_ = self.assert_ty(pos, self.tof(value), expected, true, "return value"); _ = self.assert_ty(pos, self.tof(value), expected, true, "return value");
@ -2141,8 +2023,8 @@ impl Codegen {
} }
Expr::Number { value, .. } => Some(self.ci.nodes.new_node( Expr::Number { value, .. } => Some(self.ci.nodes.new_node(
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::INT.into()), ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::INT.into()),
Kind::ConstInt { value }, Kind::CInt { value },
[], [0],
)), )),
ref e => { ref e => {
self.report_unhandled_ast(e, "bruh"); self.report_unhandled_ast(e, "bruh");
@ -2151,6 +2033,41 @@ impl Codegen {
} }
} }
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Nid> {
let Some(loob) = self.ci.loops.last_mut() else {
self.report(pos, "break outside a loop");
return None;
};
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)
}
} else {
loob.ctrl[id] =
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]);
for (else_var, then_var) in loob.ctrl_scope[id].iter_mut().zip(&self.ci.vars) {
if else_var.value == then_var.value {
continue;
}
let ty = self.ci.nodes[else_var.value].ty;
debug_assert_eq!(ty, self.ci.nodes[then_var.value].ty, "TODO: typecheck properly");
let inps = [loob.ctrl[id], then_var.value, else_var.value];
self.ci.nodes.unlock(else_var.value);
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
self.ci.nodes.lock(else_var.value);
}
}
self.ci.ctrl = self.ci.end;
None
}
#[inline(always)] #[inline(always)]
fn tof(&self, id: Nid) -> ty::Id { fn tof(&self, id: Nid) -> ty::Id {
self.ci.nodes[id].ty self.ci.nodes[id].ty
@ -2224,6 +2141,8 @@ impl Codegen {
} }
if self.errors.borrow().is_empty() { if self.errors.borrow().is_empty() {
self.gcm();
self.ci.nodes.graphviz(); self.ci.nodes.graphviz();
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -2299,7 +2218,7 @@ impl Codegen {
Kind::Start => unreachable!(), Kind::Start => unreachable!(),
Kind::End => unreachable!(), Kind::End => unreachable!(),
Kind::Return => { Kind::Return => {
let ret = self.ci.nodes[ctrl].inputs[2]; let ret = self.ci.nodes[ctrl].inputs[1];
if ret != 0 { if ret != 0 {
_ = self.color_expr_consume(ret); _ = self.color_expr_consume(ret);
if node_color!(self, ret).call_count == self.ci.call_count { if node_color!(self, ret).call_count == self.ci.call_count {
@ -2314,7 +2233,7 @@ impl Codegen {
} }
return None; return None;
} }
Kind::ConstInt { .. } => unreachable!(), Kind::CInt { .. } => unreachable!(),
Kind::Tuple { .. } => { Kind::Tuple { .. } => {
ctrl = self.ci.nodes[ctrl].outputs[0]; ctrl = self.ci.nodes[ctrl].outputs[0];
} }
@ -2344,7 +2263,7 @@ impl Codegen {
let dest = match (left_unreachable, right_unreachable) { let dest = match (left_unreachable, right_unreachable) {
(None, None) => return None, (None, None) => return None,
(None, Some(n)) | (Some(n), None) => n, (None, Some(n)) | (Some(n), None) => return Some(n),
(Some(l), Some(r)) if l == r => l, (Some(l), Some(r)) if l == r => l,
(Some(left), Some(right)) => { (Some(left), Some(right)) => {
todo!("{:?} {:?}", self.ci.nodes[left], self.ci.nodes[right]); todo!("{:?} {:?}", self.ci.nodes[left], self.ci.nodes[right]);
@ -2461,12 +2380,14 @@ impl Codegen {
Kind::Start => unreachable!(), Kind::Start => unreachable!(),
Kind::End => unreachable!(), Kind::End => unreachable!(),
Kind::Return => unreachable!(), Kind::Return => unreachable!(),
Kind::ConstInt { .. } => self.ci.set_next_color(expr), Kind::CInt { .. } => self.ci.set_next_color(expr),
Kind::Tuple { index } => { Kind::Tuple { index } => {
debug_assert!(index != 0); debug_assert!(index != 0);
} }
Kind::BinOp { .. } => { Kind::BinOp { .. } => {
let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() }; let &[_, left, right] = self.ci.nodes[expr].inputs.as_slice() else {
unreachable!()
};
let lcolor = self.color_expr_consume(left); let lcolor = self.color_expr_consume(left);
let rcolor = self.color_expr_consume(right); let rcolor = self.color_expr_consume(right);
let color = lcolor.or(rcolor).unwrap_or_else(|| self.ci.next_color()); let color = lcolor.or(rcolor).unwrap_or_else(|| self.ci.next_color());
@ -2495,7 +2416,7 @@ impl Codegen {
Kind::Start => unreachable!(), Kind::Start => unreachable!(),
Kind::End => unreachable!(), Kind::End => unreachable!(),
Kind::Return => { Kind::Return => {
let ret = self.ci.nodes[ctrl].inputs[2]; let ret = self.ci.nodes[ctrl].inputs[1];
if ret != 0 { if ret != 0 {
// NOTE: this is safer less efficient way, maybe it will be needed // NOTE: this is safer less efficient way, maybe it will be needed
// self.emit_expr_consume(ret); // self.emit_expr_consume(ret);
@ -2523,7 +2444,7 @@ impl Codegen {
self.ci.emit(instrs::jmp(0)); self.ci.emit(instrs::jmp(0));
return None; return None;
} }
Kind::ConstInt { .. } => unreachable!(), Kind::CInt { .. } => unreachable!(),
Kind::Tuple { .. } => { Kind::Tuple { .. } => {
ctrl = self.ci.nodes[ctrl].outputs[0]; ctrl = self.ci.nodes[ctrl].outputs[0];
} }
@ -2588,7 +2509,7 @@ impl Codegen {
break 'optimize_cond; break 'optimize_cond;
}; };
let &[left, right] = self.ci.nodes[cond].inputs.as_slice() else { let &[_, left, right] = self.ci.nodes[cond].inputs.as_slice() else {
unreachable!() unreachable!()
}; };
swapped = matches!(op, TokenKind::Lt | TokenKind::Gt); swapped = matches!(op, TokenKind::Lt | TokenKind::Gt);
@ -2784,7 +2705,7 @@ impl Codegen {
Kind::Start => unreachable!(), Kind::Start => unreachable!(),
Kind::End => unreachable!(), Kind::End => unreachable!(),
Kind::Return => unreachable!(), Kind::Return => unreachable!(),
Kind::ConstInt { value } => { Kind::CInt { value } => {
_ = self.lazy_init(expr); _ = self.lazy_init(expr);
let instr = instrs::li64(node_loc!(self, expr).reg, value as _); let instr = instrs::li64(node_loc!(self, expr).reg, value as _);
self.ci.emit(instr); self.ci.emit(instr);
@ -2823,7 +2744,7 @@ impl Codegen {
let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() }; let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() };
self.emit_expr_consume(left); self.emit_expr_consume(left);
if let Kind::ConstInt { value } = self.ci.nodes[right].kind if let Kind::CInt { value } = self.ci.nodes[right].kind
&& (node_loc!(self, right) == Loc::default() && (node_loc!(self, right) == Loc::default()
|| self.ci.nodes[right].depth != u32::MAX) || self.ci.nodes[right].depth != u32::MAX)
&& let Some(op) = Self::imm_math_op(op, ty.is_signed(), self.tys.size_of(ty)) && let Some(op) = Self::imm_math_op(op, ty.is_signed(), self.tys.size_of(ty))
@ -3171,6 +3092,8 @@ impl Codegen {
eprintln!("{}", self.errors.borrow()); eprintln!("{}", self.errors.borrow());
std::process::exit(1); std::process::exit(1);
} }
fn gcm(&mut self) {}
} }
#[derive(Default)] #[derive(Default)]
@ -3381,7 +3304,7 @@ mod tests {
comments => README; comments => README;
if_statements => README; if_statements => README;
loops => README; loops => README;
fb_driver => README; //fb_driver => README;
//pointers => README; //pointers => README;
//structs => README; //structs => README;
//different_types => README; //different_types => README;
@ -3405,6 +3328,6 @@ mod tests {
const_folding_with_arg => README; const_folding_with_arg => README;
// FIXME: contains redundant copies // FIXME: contains redundant copies
branch_assignments => README; branch_assignments => README;
exhaustive_loop_testing => README; //exhaustive_loop_testing => README;
} }
} }

Binary file not shown.