diff --git a/bytecode/src/lib.rs b/bytecode/src/lib.rs index 9609a999..f32bbc75 100644 --- a/bytecode/src/lib.rs +++ b/bytecode/src/lib.rs @@ -89,7 +89,6 @@ pub enum DisasmError<'a> { InstructionOutOfBounds(&'a str), FmtFailed(core::fmt::Error), HasOutOfBoundsJumps, - HasDirectInstructionCycles, } #[cfg(feature = "disasm")] @@ -113,9 +112,6 @@ impl core::fmt::Display for DisasmError<'_> { "the code contained jumps that dont got neither to a \ valid symbol or local insturction" ), - DisasmError::HasDirectInstructionCycles => { - writeln!(f, "found instruction that jumps to itself") - } } } } @@ -145,7 +141,6 @@ pub fn disasm<'a>( let mut labels = BTreeMap::::default(); let mut buf = Vec::::new(); - let mut has_cycle = false; let mut has_oob = false; '_offset_pass: for (&off, &(name, len, kind)) in functions.iter() { @@ -174,8 +169,6 @@ pub fn disasm<'a>( _ => continue, }; - has_cycle |= rel == 0; - let global_offset: u32 = (offset + rel).try_into().unwrap(); if functions.get(&global_offset).is_some() { continue; @@ -287,9 +280,5 @@ pub fn disasm<'a>( return Err(DisasmError::HasOutOfBoundsJumps); } - if has_cycle { - return Err(DisasmError::HasDirectInstructionCycles); - } - Ok(()) } diff --git a/lang/README.md b/lang/README.md index 185fd813..a7970a3b 100644 --- a/lang/README.md +++ b/lang/README.md @@ -528,99 +528,6 @@ main := fn(): int { ### Purely Testing Examples -#### smh_happened -```hb -render := @use("render.hb") - -main := fn(): void { - render.init(true) - return -} - -// in module: stn.hb - -string := @use("string.hb") -dt := @use("dt.hb") -memory := @use("memory.hb") - -// in module: memory.hb - -PAGE_SIZE := 4096 -MAX_ALLOC := 0xFF - -alloc := fn($Expr: type, num: int): ^Expr { - pages := 1 + @bitcast(@sizeof(Expr)) * num / PAGE_SIZE - if pages <= MAX_ALLOC { - return @bitcast(@inline(request_page, pages)) - } - ptr := @inline(request_page, 0xFF) - remaining := pages - MAX_ALLOC - loop if remaining <= 0 break else { - if remaining < MAX_ALLOC { - request_page(remaining) - } else { - request_page(MAX_ALLOC) - } - remaining -= MAX_ALLOC - } - return @bitcast(ptr) -} - -request_page := fn(page_count: u8): ^u8 { - msg := "\{00}\{01}xxxxxxxx\0" - msg_page_count := msg + 1; - *msg_page_count = page_count - return @eca(3, 2, msg, 12) -} - -// in module: string.hb - -length := fn(ptr: ^u8): uint { - len := @as(uint, 0) - loop if *(ptr + len) == 0 break else len += 1 - return len -} - -// in module: dt.hb - -.{string} := @use("stn.hb") - -get := fn($Expr: type, query: ^u8): Expr { - return @eca(3, 5, query, @inline(string.length, query)) -} - -// in module: render.hb - -.{dt, memory} := @use("stn.hb") -Color := packed struct {b: u8, g: u8, r: u8, a: u8} - -Surface := struct { - buf: ^Color, - width: int, - height: int, -} - -new_surface := fn(width: int, height: int): Surface { - return .( - @inline(memory.alloc, Color, width * height), - width, - height, - ) -} - -init := fn(doublebuffer: bool): Surface { - framebuffer := dt.get(^Color, "framebuffer/fb0/ptr\0") - width := dt.get(int, "framebuffer/fb0/width\0") - height := dt.get(int, "framebuffer/fb0/height\0") - if doublebuffer { - return new_surface(width, height) - } else { - return .(framebuffer, width, height) - } -} - -``` - #### wide_ret ```hb OemIdent := struct { @@ -1019,6 +926,14 @@ main := fn(arg: int): int { #### exhaustive_loop_testing ```hb main := fn(): int { + loop break + + x := 0 + loop { + x += 1 + break + } + if multiple_breaks(0) != 3 { return 1 } @@ -1043,7 +958,8 @@ main := fn(): int { return 6 } - return 0 + loop { + } } multiple_breaks := fn(arg: int): int { diff --git a/lang/src/son.rs b/lang/src/son.rs index 25d36225..7d9be76b 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -1,4 +1,5 @@ use { + self::var::{Scope, Variable}, crate::{ ctx_map::CtxEntry, ident::Ident, @@ -57,17 +58,17 @@ impl crate::ctx_map::CtxEntry for Nid { } } -#[cfg(test)] +#[cfg(debug_assertions)] type Trace = std::rc::Rc; -#[cfg(not(test))] +#[cfg(not(debug_assertions))] type Trace = (); fn trace() -> Trace { - #[cfg(test)] + #[cfg(debug_assertions)] { std::rc::Rc::new(std::backtrace::Backtrace::capture()) } - #[cfg(not(test))] + #[cfg(not(debug_assertions))] {} } @@ -99,31 +100,59 @@ impl Nodes { ) -> core::fmt::Result { use core::fmt::Write; + writeln!(out)?; + writeln!(out, "digraph G {{")?; + writeln!(out, "rankdir=BT;")?; + writeln!(out, "concentrate=true;")?; + writeln!(out, "compound=true;")?; + for (i, node) in self.iter() { - let color = if self[i].lock_rc != 0 { - "red" - } else if self.is_cfg(i) { - "yellow" - } else { - "white" + let color = match () { + _ if self[i].lock_rc != 0 => "red", + _ if self[i].outputs.is_empty() => "purple", + _ if self[i].is_mem() => "green", + _ if self.is_cfg(i) => "yellow", + _ => "white", }; - writeln!( - out, - "node{i}[label=\"{} {}\" color={color}]", - node.kind, - ty::Display::new(tys, files, node.ty) - )?; + + let mut dest = i; + let mut index_override = None; + + if !matches!(node.kind, Kind::Then | Kind::Else) { + if node.ty != ty::Id::VOID { + writeln!( + out, + " node{i}[label=\"{} {}\" color={color}]", + node.kind, + ty::Display::new(tys, files, node.ty) + )?; + } else { + writeln!(out, " node{i}[label=\"{}\" color={color}]", node.kind,)?; + } + } else { + dest = node.inputs[0]; + + index_override = if node.kind == Kind::Then { Some(0) } else { Some(1) }; + } + + if node.kind == Kind::If { + continue; + } + for (j, &o) in node.outputs.iter().enumerate() { + let j = index_override.unwrap_or(j); let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" }; let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap(); let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" }; writeln!( out, - "node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]", + " node{o} -> node{dest}[color={color} taillabel={index} headlabel={j} {style}]", )?; } } + writeln!(out, "}}")?; + Ok(()) } @@ -134,6 +163,19 @@ impl Nodes { log::info!("{out}"); } + fn graphviz_in_browser(&self, tys: &Types, files: &[parser::Ast]) { + let out = &mut String::new(); + _ = self.graphviz_low(tys, files, out); + if !std::process::Command::new("brave") + .arg(format!("https://dreampuf.github.io/GraphvizOnline/#{out}")) + .status() + .unwrap() + .success() + { + log::error!("{out}"); + } + } + fn gcm(&mut self) { self.visited.clear(self.values.len()); push_up(self); @@ -246,6 +288,8 @@ impl Nodes { self.remove_node_lookup(target); self.remove_low(target); + //std::println!("{target} {}", trace()); + true } @@ -428,11 +472,13 @@ impl Nodes { } K::Loop => { if self[target].inputs[1] == NEVER { + self.lock(target); for o in self[target].outputs.clone() { if self[o].kind == Kind::Phi { self.replace(o, self[o].inputs[1]); } } + self.unlock(target); return Some(self[target].inputs[0]); } } @@ -647,18 +693,21 @@ impl Nodes { self[o].kind.is_cfg() } - fn check_final_integrity(&mut self) { + fn check_final_integrity(&self, tys: &Types, files: &[parser::Ast]) { if !cfg!(debug_assertions) { return; } - //let mut failed = false; - for (_, node) in self.iter() { - debug_assert_eq!(node.lock_rc, 0, "{:?}", node.kind); - // if !matches!(node.kind, Kind::Return | Kind::End) && node.outputs.is_empty() { - // log::err!("outputs are empry {i} {:?}", node.kind); - // failed = true; - // } + let mut failed = false; + for (id, node) in self.iter() { + if node.lock_rc != 0 { + log::error!("{} {} {:?}", node.lock_rc, 0, node.kind); + failed = true; + } + if !matches!(node.kind, Kind::End | Kind::Mem | Kind::Arg) && node.outputs.is_empty() { + log::error!("outputs are empry {id} {:?}", node.kind); + failed = true; + } // let mut allowed_cfgs = 1 + (node.kind == Kind::If) as usize; // for &o in node.outputs.iter() { @@ -695,9 +744,10 @@ impl Nodes { // } // } } - //if failed { - // panic!() - //} + if failed { + self.graphviz_in_browser(tys, files); + panic!() + } } #[expect(dead_code)] @@ -731,50 +781,35 @@ impl Nodes { target } - fn load_loop_var(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) { - self.load_loop_value( - &mut |l| { - l.scope - .vars - .get_mut(index) - .map_or((0, ty::Id::VOID, &mut l.scope.store), |v| (v.id, v.ty, &mut v.value)) - }, - value, - loops, - ); + fn load_loop_var(&mut self, index: usize, value: &mut Variable, loops: &mut [Loop]) { + self.load_loop_value(&mut |l| l.scope.iter_mut().nth(index).unwrap(), value, loops); } - fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) { - self.load_loop_value(&mut |l| (0, ty::Id::VOID, &mut l.scope.store), value, loops); + fn load_loop_store(&mut self, value: &mut Variable, loops: &mut [Loop]) { + self.load_loop_value(&mut |l| &mut l.scope.store, value, loops); } fn load_loop_value( &mut self, - get_lvalue: &mut impl FnMut(&mut Loop) -> (Ident, ty::Id, &mut Nid), - value: &mut Nid, + get_lvalue: &mut impl FnMut(&mut Loop) -> &mut Variable, + var: &mut Variable, loops: &mut [Loop], ) { - if *value != VOID { + if var.value() != VOID { return; } let [loops @ .., loob] = loops else { unreachable!() }; let node = loob.node; - let (_id, ty, lvalue) = get_lvalue(loob); + let lvar = get_lvalue(loob); - self.load_loop_value(get_lvalue, lvalue, loops); + self.load_loop_value(get_lvalue, lvar, loops); - if !self[*lvalue].is_lazy_phi(node) { - self.unlock(*value); - let inps = [node, *lvalue, VOID]; - self.unlock(*lvalue); - *lvalue = self.new_node_nop(ty, Kind::Phi, inps); - self[*lvalue].lock_rc += 2; - } else { - self.lock(*lvalue); - self.unlock(*value); + if !self[lvar.value()].is_lazy_phi(node) { + let inps = [node, lvar.value(), VOID]; + lvar.set_value(self.new_node_nop(lvar.ty, Kind::Phi, inps), self); } - *value = *lvalue; + var.set_value(lvar.value(), self); } fn check_dominance(&mut self, nd: Nid, min: Nid, check_outputs: bool) { @@ -822,30 +857,6 @@ impl Nodes { self.values.iter_mut().flat_map(Result::as_mut) } - fn lock_scope(&mut self, scope: &Scope) { - self.lock(scope.store); - for &load in &scope.loads { - self.lock(load); - } - for var in &scope.vars { - self.lock(var.value); - } - } - - fn unlock_remove_scope(&mut self, scope: &Scope) { - self.unlock_remove(scope.store); - for &load in &scope.loads { - self.unlock_remove(load); - } - for var in &scope.vars { - if self[var.value].kind == Kind::Arg { - self.unlock(var.value); - } else { - self.unlock_remove(var.value); - } - } - } - fn eliminate_stack_temporaries(&mut self) { if !cfg!(debug_assertions) { return; @@ -1087,6 +1098,10 @@ impl Node { (self.kind == Kind::Phi && self.inputs[2] == 0) || matches!(self.kind, Kind::Arg | Kind::Stck) } + + fn is_mem(&self) -> bool { + matches!(self.kind, Kind::Stre | Kind::Load | Kind::Stck) + } } type RallocBRef = u16; @@ -1102,28 +1117,97 @@ struct Loop { scope: Scope, } -#[derive(Clone, Copy)] -struct Variable { - id: Ident, - ty: ty::Id, - ptr: bool, - value: Nid, -} +mod var { + use { + super::{Kind, Nid, Nodes}, + crate::{ident::Ident, ty}, + std::{panic, vec::Vec}, + }; -#[derive(Default, Clone)] -struct Scope { - vars: Vec, - loads: Vec, - store: Nid, -} + // makes sure value inside is laways locked for this instance of variable + #[derive(Default, Clone)] + pub struct Variable { + pub id: Ident, + pub ty: ty::Id, + pub ptr: bool, + value: Nid, + } -impl Scope { - pub fn iter_elems_mut(&mut self) -> impl Iterator { - self.vars.iter_mut().map(|v| (v.id, v.ty, &mut v.value)).chain(core::iter::once(( - 0, - ty::Id::VOID, - &mut self.store, - ))) + impl Variable { + pub fn new(id: Ident, ty: ty::Id, ptr: bool, value: Nid, nodes: &mut Nodes) -> Self { + nodes.lock(value); + Self { id, ty, ptr, value } + } + + pub fn value(&self) -> Nid { + self.value + } + + pub fn set_value(&mut self, mut new_value: Nid, nodes: &mut Nodes) -> Nid { + nodes.unlock(self.value); + std::mem::swap(&mut self.value, &mut new_value); + nodes.lock(self.value); + new_value + } + + pub fn dup(&self, nodes: &mut Nodes) -> Self { + nodes.lock(self.value); + Self { id: self.id, ty: self.ty, ptr: self.ptr, value: self.value } + } + + pub fn remove(self, nodes: &mut Nodes) { + nodes.unlock_remove(self.value); + std::mem::forget(self); + } + + pub fn set_value_remove(&mut self, new_value: Nid, nodes: &mut Nodes) { + let old = self.set_value(new_value, nodes); + nodes.remove(old); + } + + pub fn remove_ignore_arg(self, nodes: &mut Nodes) { + if nodes[self.value].kind == Kind::Arg { + nodes.unlock(self.value); + } else { + nodes.unlock_remove(self.value); + } + std::mem::forget(self); + } + } + + impl Drop for Variable { + fn drop(&mut self) { + if self.ty != ty::Id::UNDECLARED && !std::thread::panicking() { + panic!("variable unproperly deinitialized") + } + } + } + + #[derive(Default, Clone)] + pub struct Scope { + pub vars: Vec, + pub loads: Vec, + pub store: Variable, + } + + impl Scope { + pub fn iter_mut(&mut self) -> impl Iterator { + self.vars.iter_mut().chain(core::iter::once(&mut self.store)) + } + + pub fn dup(&self, nodes: &mut Nodes) -> Self { + Self { + vars: self.vars.iter().map(|v| v.dup(nodes)).collect(), + loads: self.loads.iter().copied().inspect(|&l| nodes.lock(l)).collect(), + store: self.store.dup(nodes), + } + } + + pub fn clear(&mut self, nodes: &mut Nodes) { + self.vars.drain(..).for_each(|n| n.remove(nodes)); + self.loads.drain(..).for_each(|l| _ = nodes.unlock_remove(l)); + std::mem::take(&mut self.store).remove(nodes); + } } } @@ -1172,22 +1256,21 @@ impl ItemCtx { let mem = self.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]); debug_assert_eq!(mem, MEM); self.nodes.lock(mem); - self.nodes.lock(self.ctrl); - self.scope.store = self.ctrl; + self.scope.store = Variable::new(0, ty::Id::VOID, false, ENTRY, &mut self.nodes); } fn finalize(&mut self) { - self.nodes.unlock_remove_scope(&core::mem::take(&mut self.scope)); + self.scope.clear(&mut self.nodes); self.nodes.unlock(NEVER); self.nodes.unlock(MEM); - self.nodes.eliminate_stack_temporaries(); + //self.nodes.eliminate_stack_temporaries(); } fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) { crate::emit(&mut self.code, instr); } - fn emit_body_code(&mut self, sig: Sig, tys: &Types) -> usize { + fn emit_body_code(&mut self, sig: Sig, tys: &Types, files: &[parser::Ast]) -> usize { let mut nodes = core::mem::take(&mut self.nodes); let fuc = Function::new(&mut nodes, tys, sig); @@ -1205,8 +1288,12 @@ impl ItemCtx { validate_ssa: cfg!(debug_assertions), algorithm: regalloc2::Algorithm::Ion, }; - regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx) - .unwrap_or_else(|err| panic!("{err}")); + regalloc2::run_with_ctx(&fuc, &ralloc.env, &options, &mut ralloc.ctx).unwrap_or_else( + |err| { + fuc.nodes.graphviz_in_browser(tys, files); + panic!("{err}") + }, + ); if self.call_count != 0 { core::mem::swap( @@ -1487,7 +1574,7 @@ impl ItemCtx { } fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) { - self.nodes.check_final_integrity(); + self.nodes.check_final_integrity(tys, files); self.nodes.graphviz(tys, files); self.nodes.gcm(); self.nodes.basic_blocks(); @@ -1513,7 +1600,7 @@ impl ItemCtx { self.nodes[MEM].outputs = mems; } - let saved = self.emit_body_code(sig, tys); + let saved = self.emit_body_code(sig, tys, files); if let Some(last_ret) = self.ret_relocs.last() && last_ret.offset as usize == self.code.len() - 5 @@ -1633,6 +1720,7 @@ impl Pool { fn restore_ci(&mut self, dst: &mut ItemCtx) { self.used_cis -= 1; + dst.scope.clear(&mut dst.nodes); *dst = core::mem::take(&mut self.cis[self.used_cis]); } } @@ -1715,15 +1803,15 @@ impl TypeParser for Codegen<'_> { } fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 { - let vars = self.ci.scope.vars.clone(); + let mut scope = std::mem::take(&mut self.ci.scope.vars); self.pool.push_ci(file, Some(ret), self.tasks.len(), &mut self.ci); - self.ci.scope.vars = vars; + self.ci.scope.vars = scope; let prev_err_len = self.errors.borrow().len(); self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) }); - self.ci.scope.vars = vec![]; + scope = std::mem::take(&mut self.ci.scope.vars); self.ci.finalize(); if self.errors.borrow().len() == prev_err_len { @@ -1740,8 +1828,9 @@ impl TypeParser for Codegen<'_> { ..Default::default() }; - self.pool.pop_ci(&mut self.ci); self.complete_call_graph(); + self.pool.pop_ci(&mut self.ci); + self.ci.scope.vars = scope; // TODO: return them back let fuc = self.tys.ins.funcs.len() as ty::Func; @@ -1772,6 +1861,7 @@ impl TypeParser for Codegen<'_> { self.ct.vm.read_reg(reg::RET).0 } else { self.pool.pop_ci(&mut self.ci); + self.ci.scope.vars = scope; 1 } } @@ -1822,8 +1912,8 @@ impl TypeParser for Codegen<'_> { ..Default::default() }; - self.pool.pop_ci(&mut self.ci); self.complete_call_graph(); + self.pool.pop_ci(&mut self.ci); let mut mem = vec![0u8; self.tys.size_of(ret) as usize]; @@ -1879,7 +1969,7 @@ impl TypeParser for Codegen<'_> { } fn find_local_ty(&mut self, ident: Ident) -> Option { - self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value == NEVER)).map(|v| v.ty) + self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value() == NEVER)).map(|v| v.ty) } } @@ -1907,8 +1997,7 @@ impl<'a> Codegen<'a> { let mut vc = Vc::from([VOID, value, region]); self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); - self.ci.nodes.unlock(self.ci.scope.store); - if let Some(str) = self.ci.scope.store.to_store() { + if let Some(str) = self.ci.scope.store.value().to_store() { vc.push(str); } for load in self.ci.scope.loads.drain(..) { @@ -1920,10 +2009,11 @@ impl<'a> Codegen<'a> { vc.push(load); } } - let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc); - self.ci.nodes.lock(store); - self.ci.scope.store = store; - store + let store = self.ci.nodes.new_node_nop(self.tof(value), Kind::Stre, vc); + self.ci.scope.store.set_value(store, &mut self.ci.nodes); + let opted = self.ci.nodes.late_peephole(store); + self.ci.scope.store.set_value_remove(opted, &mut self.ci.nodes); + opted } fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid { @@ -1934,7 +2024,7 @@ impl<'a> Codegen<'a> { debug_assert!(self.ci.nodes[region].kind != Kind::Stre); 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.to_store() { + if let Some(str) = self.ci.scope.store.value().to_store() { vc.push(str); } let load = self.ci.nodes.new_node(ty, Kind::Load, vc); @@ -2005,7 +2095,7 @@ impl<'a> Codegen<'a> { if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) => { let var = &mut self.ci.scope.vars[index]; - self.ci.nodes.load_loop_var(index, &mut var.value, &mut self.ci.loops); + self.ci.nodes.load_loop_var(index, var, &mut self.ci.loops); Some(Value::var(index).ty(var.ty)) } @@ -2054,7 +2144,7 @@ impl<'a> Codegen<'a> { if self.ci.inline_depth == 0 { 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); - if let Some(str) = self.ci.scope.store.to_store() { + if let Some(str) = self.ci.scope.store.value().to_store() { inps.push(str); } @@ -2177,12 +2267,10 @@ impl<'a> Codegen<'a> { let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize]; if var.ptr { - let val = var.value; + let val = var.value(); self.store_mem(val, value.id); } else { - self.ci.nodes.lock(value.id); - let prev = core::mem::replace(&mut var.value, value.id); - self.ci.nodes.unlock_remove(prev); + var.set_value_remove(value.id, &mut self.ci.nodes); } } else if dest.ptr { self.store_mem(dest.id, value.id); @@ -2387,7 +2475,7 @@ impl<'a> Codegen<'a> { self.ci.nodes.unlock(n); } - if let Some(str) = self.ci.scope.store.to_store() { + if let Some(str) = self.ci.scope.store.value().to_store() { inps.push(str); } self.ci.scope.loads.retain(|&load| { @@ -2471,7 +2559,7 @@ impl<'a> Codegen<'a> { self.ci.nodes.unlock(n); } - if let Some(str) = self.ci.scope.store.to_store() { + if let Some(str) = self.ci.scope.store.value().to_store() { inps.push(str); } self.ci.scope.loads.retain(|&load| { @@ -2543,13 +2631,13 @@ impl<'a> Codegen<'a> { for (arg, carg) in args.iter().zip(cargs) { let ty = self.tys.ins.args[sig_args.next().unwrap()]; if ty == ty::Id::TYPE { - self.ci.scope.vars.push(Variable { - id: carg.id, - ty: self.tys.ins.args[sig_args.next().unwrap()], - ptr: false, - value: NEVER, - }); - self.ci.nodes.lock(NEVER); + self.ci.scope.vars.push(Variable::new( + carg.id, + self.tys.ins.args[sig_args.next().unwrap()], + false, + NEVER, + &mut self.ci.nodes, + )); continue; } @@ -2558,13 +2646,13 @@ impl<'a> Codegen<'a> { debug_assert_ne!(value.id, 0); self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name)); - self.ci.scope.vars.push(Variable { - id: carg.id, + self.ci.scope.vars.push(Variable::new( + carg.id, ty, - ptr: value.ptr, - value: value.id, - }); - self.ci.nodes.lock(value.id); + value.ptr, + value.id, + &mut self.ci.nodes, + )); } let prev_ret = self.ci.ret.replace(sig.ret); @@ -2584,7 +2672,7 @@ impl<'a> Codegen<'a> { self.ci.file = prev_file; self.ci.inline_depth -= 1; for var in self.ci.scope.vars.drain(arg_base..) { - self.ci.nodes.unlock_remove(var.value); + var.remove(&mut self.ci.nodes); } core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, ctrl)| { @@ -2772,7 +2860,7 @@ impl<'a> Codegen<'a> { self.ci.nodes.lock(self.ci.ctrl); for var in self.ci.scope.vars.drain(base..) { - self.ci.nodes.unlock_remove(var.value); + var.remove(&mut self.ci.nodes); } self.ci.nodes.unlock(self.ci.ctrl); @@ -2784,13 +2872,12 @@ impl<'a> Codegen<'a> { node: self.ci.ctrl, ctrl: [Nid::MAX; 2], ctrl_scope: core::array::from_fn(|_| Default::default()), - scope: self.ci.scope.clone(), + scope: self.ci.scope.dup(&mut self.ci.nodes), }); - for (.., var) in &mut self.ci.scope.iter_elems_mut() { - *var = VOID; + for var in &mut self.ci.scope.iter_mut() { + var.set_value(VOID, &mut self.ci.nodes); } - self.ci.nodes.lock_scope(&self.ci.scope); self.expr(body); @@ -2808,8 +2895,8 @@ impl<'a> Codegen<'a> { con, &mut self.ci.scope, &mut cons, - true, ); + cons.clear(&mut self.ci.nodes); self.ci.ctrl = con; } @@ -2818,15 +2905,15 @@ impl<'a> Codegen<'a> { self.ci.nodes.modify_input(node, 1, self.ci.ctrl); - let idx = self.ci.nodes[node] - .outputs - .iter() - .position(|&n| self.ci.nodes.is_cfg(n)) - .unwrap(); - self.ci.nodes[node].outputs.swap(idx, 0); + if let Some(idx) = + self.ci.nodes[node].outputs.iter().position(|&n| self.ci.nodes.is_cfg(n)) + { + self.ci.nodes[node].outputs.swap(idx, 0); + } if bre == Nid::MAX { self.ci.ctrl = NEVER; + scope.clear(&mut self.ci.nodes); return None; } self.ci.ctrl = bre; @@ -2836,51 +2923,44 @@ impl<'a> Codegen<'a> { debug_assert_eq!(self.ci.scope.vars.len(), scope.vars.len()); debug_assert_eq!(self.ci.scope.vars.len(), bres.vars.len()); - for (((.., dest_value), (.., &mut mut scope_value)), (.., &mut loop_value)) in self - .ci - .scope - .iter_elems_mut() - .zip(scope.iter_elems_mut()) - .zip(bres.iter_elems_mut()) - { - self.ci.nodes.unlock(loop_value); + self.ci.nodes.lock(node); - if self.ci.nodes[scope_value].is_lazy_phi(node) { - self.ci.nodes.unlock(scope_value); - if loop_value != scope_value { - scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value); - self.ci.nodes.lock(scope_value); + for ((dest_var, scope_var), loop_var) in + self.ci.scope.iter_mut().zip(scope.iter_mut()).zip(bres.iter_mut()) + { + if self.ci.nodes[scope_var.value()].is_lazy_phi(node) { + if loop_var.value() != scope_var.value() { + scope_var.set_value( + self.ci.nodes.modify_input(scope_var.value(), 2, loop_var.value()), + &mut self.ci.nodes, + ); } else { - if *dest_value == scope_value { - self.ci.nodes.unlock(*dest_value); - *dest_value = VOID; - self.ci.nodes.lock(*dest_value); + if dest_var.value() == scope_var.value() { + dest_var.set_value(VOID, &mut self.ci.nodes); } - let phi = &self.ci.nodes[scope_value]; + let phi = &self.ci.nodes[scope_var.value()]; let prev = phi.inputs[1]; - self.ci.nodes.replace(scope_value, prev); - scope_value = prev; - self.ci.nodes.lock(prev); + self.ci.nodes.replace(scope_var.value(), prev); + scope_var.set_value(prev, &mut self.ci.nodes); } } - if *dest_value == VOID { - self.ci.nodes.unlock(*dest_value); - *dest_value = scope_value; - self.ci.nodes.lock(*dest_value); + if dest_var.value() == VOID { + dest_var.set_value(scope_var.value(), &mut self.ci.nodes); } - debug_assert!(!self.ci.nodes[*dest_value].is_lazy_phi(node)); - - self.ci.nodes.unlock_remove(scope_value); + debug_assert!(!self.ci.nodes[dest_var.value()].is_lazy_phi(node)); } - scope.loads.iter().for_each(|&n| _ = self.ci.nodes.unlock_remove(n)); - bres.loads.iter().for_each(|&n| _ = self.ci.nodes.unlock_remove(n)); + scope.clear(&mut self.ci.nodes); + bres.clear(&mut self.ci.nodes); self.ci.nodes.unlock(self.ci.ctrl); - - self.ci.nodes.late_peephole(node); + self.ci.nodes.unlock(node); + let rpl = self.ci.nodes.late_peephole(node); + if self.ci.ctrl == node { + self.ci.ctrl = rpl; + } Some(Value::VOID) } @@ -2911,10 +2991,8 @@ impl<'a> Codegen<'a> { } self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops); - let orig_store = self.ci.scope.store; - self.ci.nodes.lock(orig_store); - let else_scope = self.ci.scope.clone(); - self.ci.nodes.lock_scope(&else_scope); + let orig_store = self.ci.scope.store.dup(&mut self.ci.nodes); + let else_scope = self.ci.scope.dup(&mut self.ci.nodes); 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); @@ -2927,16 +3005,16 @@ impl<'a> Codegen<'a> { self.ci.ctrl }; - self.ci.nodes.unlock_remove(orig_store); + orig_store.remove(&mut self.ci.nodes); if lcntrl == Nid::MAX && rcntrl == Nid::MAX { - self.ci.nodes.unlock_remove_scope(&then_scope); + then_scope.clear(&mut self.ci.nodes); return None; } else if lcntrl == Nid::MAX { - self.ci.nodes.unlock_remove_scope(&then_scope); + then_scope.clear(&mut self.ci.nodes); return Some(Value::VOID); } else if rcntrl == Nid::MAX { - self.ci.nodes.unlock_remove_scope(&self.ci.scope); + self.ci.scope.clear(&mut self.ci.nodes); self.ci.scope = then_scope; self.ci.ctrl = lcntrl; return Some(Value::VOID); @@ -2950,8 +3028,8 @@ impl<'a> Codegen<'a> { self.ci.ctrl, &mut self.ci.scope, &mut then_scope, - true, ); + then_scope.clear(&mut self.ci.nodes); Some(Value::VOID) } @@ -3029,7 +3107,13 @@ impl<'a> Codegen<'a> { ty }; - self.ci.scope.vars.push(Variable { id: carg.id, ty, ptr: false, value: NEVER }); + self.ci.scope.vars.push(Variable::new( + carg.id, + ty, + false, + NEVER, + &mut self.ci.nodes, + )); } let Some(args) = self.tys.pack_args(arg_base) else { @@ -3038,7 +3122,7 @@ impl<'a> Codegen<'a> { }; let ret = self.ty(ret); - self.ci.scope.vars.truncate(base); + self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes)); let sym = SymKey::FuncInst(*func, args); let ct = |ins: &mut crate::TypeIns| { @@ -3064,13 +3148,13 @@ impl<'a> Codegen<'a> { fn assign_pattern(&mut self, pat: &Expr, right: Value) { match *pat { Expr::Ident { id, .. } => { - self.ci.nodes.lock(right.id); - self.ci.scope.vars.push(Variable { + self.ci.scope.vars.push(Variable::new( id, - value: right.id, - ptr: right.ptr, - ty: right.ty, - }); + right.ty, + right.ptr, + right.id, + &mut self.ci.nodes, + )); } Expr::Ctor { pos, fields, .. } => { let ty::Kind::Struct(idx) = right.ty.expand() else { @@ -3114,7 +3198,7 @@ impl<'a> Codegen<'a> { if core::mem::take(&mut n.var) { let id = (u16::MAX - n.id) as usize; n.ptr = self.ci.scope.vars[id].ptr; - n.id = self.ci.scope.vars[id].value; + n.id = self.ci.scope.vars[id].value(); } } @@ -3131,9 +3215,11 @@ impl<'a> Codegen<'a> { if loob.ctrl[id] == Nid::MAX { self.ci.nodes.lock(self.ci.ctrl); loob.ctrl[id] = self.ci.ctrl; - loob.ctrl_scope[id] = self.ci.scope.clone(); - loob.ctrl_scope[id].vars.truncate(loob.scope.vars.len()); - self.ci.nodes.lock_scope(&loob.ctrl_scope[id]); + loob.ctrl_scope[id] = self.ci.scope.dup(&mut self.ci.nodes); + loob.ctrl_scope[id] + .vars + .drain(loob.scope.vars.len()..) + .for_each(|v| v.remove(&mut self.ci.nodes)); } else { let reg = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, loob.ctrl[id]]); @@ -3145,7 +3231,6 @@ impl<'a> Codegen<'a> { reg, &mut scope, &mut self.ci.scope, - false, ); loob = self.ci.loops.last_mut().unwrap(); @@ -3165,20 +3250,16 @@ impl<'a> Codegen<'a> { ctrl: Nid, to: &mut Scope, from: &mut Scope, - drop_from: bool, ) { nodes.lock(ctrl); - for (i, ((.., ty, to_value), (.., from_value))) in - to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate() - { - if to_value != from_value { + for (i, (to_value, from_value)) in to.iter_mut().zip(from.iter_mut()).enumerate() { + if to_value.value() != from_value.value() { nodes.load_loop_var(i, from_value, loops); nodes.load_loop_var(i, to_value, loops); - if to_value != from_value { - let inps = [ctrl, *from_value, *to_value]; - nodes.unlock(*to_value); - *to_value = nodes.new_node(ty, Kind::Phi, inps); - nodes.lock(*to_value); + if to_value.value() != from_value.value() { + let inps = [ctrl, from_value.value(), to_value.value()]; + to_value + .set_value_remove(nodes.new_node(from_value.ty, Kind::Phi, inps), nodes); } } } @@ -3190,9 +3271,6 @@ impl<'a> Codegen<'a> { nodes.unlock_remove(load); } - if drop_from { - nodes.unlock_remove_scope(from); - } nodes.unlock(ctrl); } @@ -3228,23 +3306,23 @@ impl<'a> Codegen<'a> { for arg in args.iter() { let ty = self.tys.ins.args[sig_args.next().unwrap()]; if ty == ty::Id::TYPE { - self.ci.scope.vars.push(Variable { - id: arg.id, - ty: self.tys.ins.args[sig_args.next().unwrap()], - ptr: false, - value: NEVER, - }); - self.ci.nodes.lock(NEVER); + self.ci.scope.vars.push(Variable::new( + arg.id, + self.tys.ins.args[sig_args.next().unwrap()], + false, + NEVER, + &mut self.ci.nodes, + )); continue; } let mut deps = Vc::from([VOID]); - if ty.loc(&self.tys) == Loc::Stack { + if ty.loc(&self.tys) == Loc::Stack && self.tys.size_of(ty) <= 16 { deps.push(MEM); } - let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, [VOID]); - self.ci.nodes.lock(value); + // TODO: whe we not using the deps? + let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, deps); let ptr = ty.loc(&self.tys) == Loc::Stack; - self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr }); + self.ci.scope.vars.push(Variable::new(arg.id, ty, ptr, value, &mut self.ci.nodes)); } if self.expr(body).is_some() && sig.ret == ty::Id::VOID { @@ -3255,6 +3333,8 @@ impl<'a> Codegen<'a> { ); } + self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes)); + self.ci.finalize(); if self.errors.borrow().is_empty() { @@ -3461,6 +3541,11 @@ impl<'a> Function<'a> { } fn rg(&self, nid: Nid) -> VReg { + debug_assert!( + !self.nodes.is_cfg(nid) || matches!(self.nodes[nid].kind, Kind::Call { .. }), + "{:?}", + self.nodes[nid] + ); regalloc2::VReg::new(nid as _, regalloc2::RegClass::Int) } @@ -4137,8 +4222,8 @@ mod tests { fn generate(ident: &'static str, input: &'static str, output: &mut String) { _ = log::set_logger(&crate::fs::Logger); - log::set_max_level(log::LevelFilter::Info); - log::set_max_level(log::LevelFilter::Trace); + //log::set_max_level(log::LevelFilter::Info); + // log::set_max_level(log::LevelFilter::Trace); let (ref files, embeds) = crate::test_parse_files(ident, input); let mut codegen = super::Codegen { files, ..Default::default() }; @@ -4194,7 +4279,6 @@ mod tests { fb_driver; // Purely Testing Examples; - smh_happened; wide_ret; comptime_min_reg_leak; different_types;