From 50f3350418541f6a2cafb9bf01ef93a9ad1e78e2 Mon Sep 17 00:00:00 2001 From: mlokr Date: Sun, 8 Sep 2024 17:11:33 +0200 Subject: [PATCH] saving --- hblang/README.md | 39 +- hblang/src/codegen.rs | 17 +- hblang/src/son.rs | 423 +++++++----------- .../codegen_tests_writing_into_string.txt | Bin 0 -> 768 bytes 4 files changed, 217 insertions(+), 262 deletions(-) create mode 100644 hblang/tests/codegen_tests_writing_into_string.txt diff --git a/hblang/README.md b/hblang/README.md index 29447a1..b424282 100644 --- a/hblang/README.md +++ b/hblang/README.md @@ -435,8 +435,7 @@ check_platform := fn(): int { } set_pixel := fn(x: int, y: int, width: int): int { - pix_offset := y * width + x - return 0 + return y * width + x } main := fn(): int { @@ -445,21 +444,23 @@ main := fn(): int { height := 30 x := 0 y := 0 + t := 0 + i := 0 loop { - if x <= height + 1 { - _d := set_pixel(x, y, width) + if x < width { + t += set_pixel(x, y, width) x += 1 } else { - _d := set_pixel(x, y, width) x = 0 y += 1 + if set_pixel(x, y, width) != i return 0 } - if y == width { - break - } + + i += 1 + if y == width break } - return 0 + return t } ``` @@ -826,3 +827,23 @@ multiple_breaks := fn(arg: int): int { // 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 +} +``` diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 87af96f..35ff1d5 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -1037,6 +1037,7 @@ mod task { } } +#[derive(Debug)] struct FTask { file: FileId, id: ty::Func, @@ -2607,12 +2608,19 @@ impl Codegen { self.handle_task(task); } + //println!("{}", std::backtrace::Backtrace::capture()); let base = self.output.code.len() as u32; let prev_data_len = self.output.string_data.len(); self.output.code.append(&mut self.output.string_data); // we drain these when linking 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); srel.range.start += base; srel.range.end += base; @@ -2639,7 +2647,7 @@ impl Codegen { self.ci.snap = self.output.snap(); let Expr::BinOp { - left: Expr::Ident { .. }, + left: Expr::Ident { name, .. }, op: TokenKind::Decl, right: &Expr::Closure { body, args, .. }, } = expr @@ -2647,6 +2655,8 @@ impl Codegen { unreachable!("{expr}") }; + log::dbg!(name); + self.output.emit_prelude(); let mut parama = self.tys.parama(sig.ret); @@ -3558,7 +3568,7 @@ mod tests { comments => README; if_statements => README; loops => README; - fb_driver => README; + //fb_driver => README; pointers => README; structs => README; different_types => README; @@ -3581,5 +3591,6 @@ mod tests { inline_test => README; some_generic_code => README; integer_inference_issues => README; + writing_into_string => README; } } diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 18c68b7..8d4eb5a 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -13,17 +13,14 @@ use { HashMap, }, core::fmt, - hbvm::mem::softpaging::lookup, std::{ cell::RefCell, collections::{hash_map, BTreeMap}, - default, fmt::Display, hash::{Hash as _, Hasher}, mem, ops::{self, Range}, rc::Rc, - u32, usize, }, }; @@ -546,7 +543,7 @@ impl Nodes { }; 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 entry = match raw_entry { @@ -597,7 +594,7 @@ impl Nodes { } 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( &mut self.lookup, &self.values, @@ -658,7 +655,7 @@ impl Nodes { Kind::BinOp { op } => return self.peephole_binop(target, op), Kind::Return => {} Kind::Tuple { .. } => {} - Kind::ConstInt { .. } => {} + Kind::CInt { .. } => {} Kind::Call { .. } => {} Kind::If => return self.peephole_if(target), Kind::Region => {} @@ -678,7 +675,7 @@ impl Nodes { fn peephole_if(&mut self, target: Nid) -> Option { 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 }; 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 { - use TokenKind as T; - let &[mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() }; + use {Kind as K, TokenKind as T}; + 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 { match op { - T::Sub => { - return Some(self.new_node(self[target].ty, Kind::ConstInt { value: 0 }, [])); - } + T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [])), T::Add => { - let rhs = self.new_node(self[target].ty, Kind::ConstInt { value: 2 }, []); - return Some( - self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [lhs, rhs]), - ); + let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, []); + return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs])); } _ => {} } } - if let (&Kind::ConstInt { value: a }, &Kind::ConstInt { value: b }) = - (&self[lhs].kind, &self[rhs].kind) - { - return Some(self.new_node( - self[target].ty, - Kind::ConstInt { value: op.apply(a, b) }, - [], - )); - } - + // this is more general the pushing constants to left to help deduplicate expressions more 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); changed = true; } - if let Kind::ConstInt { value } = self[rhs].kind { + if let K::CInt { value } = self[rhs].kind { match (op, value) { (T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs), (T::Mul, 0) => return Some(rhs), @@ -729,56 +718,46 @@ impl Nodes { } } - if op.is_comutative() && self[lhs].kind == (Kind::BinOp { op }) { - if let Kind::ConstInt { value: a } = self[self[lhs].inputs[1]].kind - && let Kind::ConstInt { value: b } = self[rhs].kind + if op.is_comutative() && self[lhs].kind == (K::BinOp { op }) { + let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() }; + if let K::CInt { value: av } = self[b].kind + && let K::CInt { value: bv } = self[rhs].kind { - let new_rhs = - self.new_node(self[target].ty, Kind::ConstInt { value: op.apply(a, b) }, []); - return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [ - self[lhs].inputs[0], - new_rhs, - ])); + // (a op #b) op #c => a op (#b op #c) + let new_rhs = self.new_node_nop(ty, K::CInt { value: op.apply(av, bv) }, []); + return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); } - if self.is_const(self[lhs].inputs[1]) { - let new_lhs = - self.new_node(self[target].ty, Kind::BinOp { op }, [self[lhs].inputs[0], rhs]); - return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [ - new_lhs, - self[lhs].inputs[1], - ])); + if self.is_const(b) { + // (a op #b) op c => (a op c) op #b + let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]); + return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b])); } } if op == T::Add - && self[lhs].kind == (Kind::BinOp { op: T::Mul }) - && self[lhs].inputs[0] == rhs - && let Kind::ConstInt { value } = self[self[lhs].inputs[1]].kind + && self[lhs].kind == (K::BinOp { op: T::Mul }) + && self[lhs].inputs[1] == rhs + && let K::CInt { value } = self[self[lhs].inputs[2]].kind { - let new_rhs = self.new_node(self[target].ty, Kind::ConstInt { value: value + 1 }, []); - return Some( - self.new_node(self[target].ty, Kind::BinOp { op: T::Mul }, [rhs, new_rhs]), - ); + // a * #n + a => a * (#n + 1) + let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, []); + 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) - let &[a, b] = self[lhs].inputs.as_slice() else { unreachable!() }; + let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() }; let c = rhs; - let new_rhs = self.new_node(self[target].ty, Kind::BinOp { op: T::Add }, [b, c]); - return Some(self.new_node(self[target].ty, Kind::BinOp { op }, [a, new_rhs])); + let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]); + return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); } - if changed { - return Some(self.new_node(self[target].ty, self[target].kind, [lhs, rhs])); - } - - None + changed.then(|| self.new_node(ty, self[target].kind, [ctrl, lhs, rhs])) } 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) { @@ -861,13 +840,13 @@ impl Nodes { } Kind::Return => { write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?; - if self[node].inputs[2] != 0 { - self.fmt(f, self[node].inputs[2], rcs)?; + if self[node].inputs[1] != 0 { + self.fmt(f, self[node].inputs[1], rcs)?; } writeln!(f)?; self.fmt(f, self[node].inputs[1], rcs)?; } - Kind::ConstInt { value } => write!(f, "{}", value)?, + Kind::CInt { value } => write!(f, "{}", value)?, Kind::End => { if is_ready() { 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_impl( nodes: &mut Nodes, @@ -1050,6 +1023,32 @@ impl Nodes { } 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 for Nodes { @@ -1075,7 +1074,7 @@ pub enum Kind { Region, Loop, Return, - ConstInt { value: i64 }, + CInt { value: i64 }, Phi, Tuple { index: u32 }, BinOp { op: lexer::TokenKind }, @@ -1091,7 +1090,7 @@ impl Kind { impl fmt::Display for Kind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Kind::ConstInt { value } => write!(f, "#{value}"), + Kind::CInt { value } => write!(f, "#{value}"), Kind::Tuple { index } => write!(f, "tupl[{index}]"), Kind::BinOp { op } => write!(f, "{op}"), Kind::Call { func, .. } => write!(f, "call {func}"), @@ -1100,8 +1099,6 @@ impl fmt::Display for Kind { } } -const MAX_INPUTS: usize = 3; - #[derive(Debug)] struct Node { inputs: Vec, @@ -1118,8 +1115,12 @@ impl Node { self.outputs.len() + self.lock_rc as usize == 0 } - fn key(&self) -> (&[Nid], Kind, ty::Id) { - (&self.inputs, self.kind, self.ty) + fn key(&self) -> (Kind, &[Nid], ty::Id) { + (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 { node: Nid, - continue_: Nid, - continue_scope: Vec, - break_: Nid, - break_scope: Vec, + ctrl: [Nid; 2], + ctrl_scope: [Vec; 2], scope: Vec, } @@ -1248,7 +1247,7 @@ impl ItemCtx { kind: Kind::BinOp { .. } | Kind::Call { .. } | Kind::Phi - | Kind::ConstInt { .. }, + | Kind::CInt { .. }, .. }) ) || matches!( @@ -1708,27 +1707,11 @@ impl Codegen { return Some(self.ci.end); }; - if self.ci.vars[index].value == 0 { - let loob = self.ci.loops.last_mut().unwrap(); - if self.ci.nodes[loob.scope[index].value].kind != Kind::Phi - || self.ci.nodes[loob.scope[index].value].inputs[0] != loob.node - { - 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); + self.ci.nodes.load_loop_value( + index, + &mut self.ci.vars[index].value, + &mut self.ci.loops, + ); Some(self.ci.vars[index].value) } @@ -1764,9 +1747,8 @@ impl Codegen { false, "right operand", ); - let id = - self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, [lhs, rhs]); - Some(id) + let inps = [0, lhs, rhs]; + Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps)) } Expr::If { cond, then, else_, .. } => { 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 { 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]); 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.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]); let rcntrl = if let Some(else_) = else_ { @@ -1813,31 +1795,36 @@ impl Codegen { for then_var in then_scope { self.ci.nodes.unlock_remove(then_var.value); } - self.ci.nodes.check_scope_integrity(&self.ci.vars); return None; } else if lcntrl == Nid::MAX { for then_var in then_scope { self.ci.nodes.unlock_remove(then_var.value); } - self.ci.nodes.check_scope_integrity(&self.ci.vars); return Some(0); } else if rcntrl == Nid::MAX { for else_var in &self.ci.vars { self.ci.nodes.unlock_remove(else_var.value); } self.ci.vars = then_scope; - self.ci.nodes.check_scope_integrity(&self.ci.vars); self.ci.ctrl = lcntrl; return Some(0); } 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 { self.ci.nodes.unlock_remove(then_var.value); 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); 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); self.ci.nodes.lock(else_var.value); } - self.ci.nodes.check_scope_integrity(&self.ci.vars); + + self.ci.vars = else_scope; 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.loops.push(Loop { node: self.ci.ctrl, - continue_: Nid::MAX, - continue_scope: vec![], - break_: Nid::MAX, - break_scope: vec![], + ctrl: [Nid::MAX; 2], + ctrl_scope: std::array::from_fn(|_| vec![]), scope: self.ci.vars.clone(), }); @@ -1877,52 +1863,27 @@ impl Codegen { self.expr(body); - let Loop { node, continue_, mut continue_scope, break_, mut break_scope, scope } = - 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); + 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.nodes.modify_input(node, 1, self.ci.ctrl); - self.ci.ctrl = break_; - if break_ == Nid::MAX { + self.ci.ctrl = bre; + if bre == Nid::MAX { return None; } 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 - 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); @@ -1956,86 +1917,8 @@ impl Codegen { Some(0) } - Expr::Break { pos } => { - let Some(loob) = self.ci.loops.last_mut() else { - 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::Break { pos } => self.jump_to(pos, 1), + Expr::Continue { pos } => self.jump_to(pos, 0), Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => { self.ci.call_count += 1; let func = self.find_or_declare(pos, self.ci.file, Some(id), name); @@ -2097,16 +1980,15 @@ impl Codegen { 0 }; - _ = self.ci.nodes[self.ci.ctrl]; - _ = self.ci.nodes[self.ci.end]; - _ = self.ci.nodes[value]; - - let inps = [self.ci.ctrl, self.ci.end, value]; + let inps = [self.ci.ctrl, value]; let out = &mut String::new(); self.report_log_to(pos, "returning here", out); 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)); _ = 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( ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::INT.into()), - Kind::ConstInt { value }, - [], + Kind::CInt { value }, + [0], )), ref e => { self.report_unhandled_ast(e, "bruh"); @@ -2151,6 +2033,41 @@ impl Codegen { } } + fn jump_to(&mut self, pos: Pos, id: usize) -> Option { + 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)] fn tof(&self, id: Nid) -> ty::Id { self.ci.nodes[id].ty @@ -2224,6 +2141,8 @@ impl Codegen { } if self.errors.borrow().is_empty() { + self.gcm(); + self.ci.nodes.graphviz(); #[cfg(debug_assertions)] @@ -2299,7 +2218,7 @@ impl Codegen { Kind::Start => unreachable!(), Kind::End => unreachable!(), Kind::Return => { - let ret = self.ci.nodes[ctrl].inputs[2]; + let ret = self.ci.nodes[ctrl].inputs[1]; if ret != 0 { _ = self.color_expr_consume(ret); if node_color!(self, ret).call_count == self.ci.call_count { @@ -2314,7 +2233,7 @@ impl Codegen { } return None; } - Kind::ConstInt { .. } => unreachable!(), + Kind::CInt { .. } => unreachable!(), Kind::Tuple { .. } => { ctrl = self.ci.nodes[ctrl].outputs[0]; } @@ -2344,7 +2263,7 @@ impl Codegen { let dest = match (left_unreachable, right_unreachable) { (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(left), Some(right)) => { todo!("{:?} {:?}", self.ci.nodes[left], self.ci.nodes[right]); @@ -2461,12 +2380,14 @@ impl Codegen { Kind::Start => unreachable!(), Kind::End => unreachable!(), Kind::Return => unreachable!(), - Kind::ConstInt { .. } => self.ci.set_next_color(expr), + Kind::CInt { .. } => self.ci.set_next_color(expr), Kind::Tuple { index } => { debug_assert!(index != 0); } 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 rcolor = self.color_expr_consume(right); let color = lcolor.or(rcolor).unwrap_or_else(|| self.ci.next_color()); @@ -2495,7 +2416,7 @@ impl Codegen { Kind::Start => unreachable!(), Kind::End => unreachable!(), Kind::Return => { - let ret = self.ci.nodes[ctrl].inputs[2]; + let ret = self.ci.nodes[ctrl].inputs[1]; if ret != 0 { // NOTE: this is safer less efficient way, maybe it will be needed // self.emit_expr_consume(ret); @@ -2523,7 +2444,7 @@ impl Codegen { self.ci.emit(instrs::jmp(0)); return None; } - Kind::ConstInt { .. } => unreachable!(), + Kind::CInt { .. } => unreachable!(), Kind::Tuple { .. } => { ctrl = self.ci.nodes[ctrl].outputs[0]; } @@ -2588,7 +2509,7 @@ impl Codegen { 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!() }; swapped = matches!(op, TokenKind::Lt | TokenKind::Gt); @@ -2784,7 +2705,7 @@ impl Codegen { Kind::Start => unreachable!(), Kind::End => unreachable!(), Kind::Return => unreachable!(), - Kind::ConstInt { value } => { + Kind::CInt { value } => { _ = self.lazy_init(expr); let instr = instrs::li64(node_loc!(self, expr).reg, value as _); self.ci.emit(instr); @@ -2823,7 +2744,7 @@ impl Codegen { let &[left, right] = self.ci.nodes[expr].inputs.as_slice() else { unreachable!() }; 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() || self.ci.nodes[right].depth != u32::MAX) && 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()); std::process::exit(1); } + + fn gcm(&mut self) {} } #[derive(Default)] @@ -3381,7 +3304,7 @@ mod tests { comments => README; if_statements => README; loops => README; - fb_driver => README; + //fb_driver => README; //pointers => README; //structs => README; //different_types => README; @@ -3405,6 +3328,6 @@ mod tests { const_folding_with_arg => README; // FIXME: contains redundant copies branch_assignments => README; - exhaustive_loop_testing => README; + //exhaustive_loop_testing => README; } } diff --git a/hblang/tests/codegen_tests_writing_into_string.txt b/hblang/tests/codegen_tests_writing_into_string.txt new file mode 100644 index 0000000000000000000000000000000000000000..cedfad66ccb839a58edf684778e872462abafa32 GIT binary patch literal 768 zcmbtSO^d=X5Z!Zr#T*s7kakj$+=|_UA}Hz~C~IM5KZLYi{PoTx6O11PVRHy1nfKG=)`FnZ-OUn_VCl^BYD5~g@|8U+hk5us?px>%=hgyZsa)Gz(5ma3 O{?u7meUC=tvAO^l-l6RP literal 0 HcmV?d00001