diff --git a/lang/README.md b/lang/README.md index 959ed893..185fd813 100644 --- a/lang/README.md +++ b/lang/README.md @@ -378,7 +378,7 @@ main := fn(): int { gb := 0 foo := fn(a: int, b: int, c: int): int { - if true | gb == 0 return 1 + if false | gb != 0 return 1 return a + b + c } ``` @@ -528,6 +528,99 @@ 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 { diff --git a/lang/src/son.rs b/lang/src/son.rs index a07eb0ed..51fb08f4 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -49,7 +49,7 @@ impl StoreId for Nid { } impl crate::ctx_map::CtxEntry for Nid { - type Ctx = [Result]; + type Ctx = [Result]; type Key<'a> = (Kind, &'a [Nid], ty::Id); fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { @@ -57,9 +57,23 @@ impl crate::ctx_map::CtxEntry for Nid { } } +#[cfg(test)] +type Trace = std::rc::Rc; +#[cfg(not(test))] +type Trace = (); + +fn trace() -> Trace { + #[cfg(test)] + { + std::rc::Rc::new(std::backtrace::Backtrace::capture()) + } + #[cfg(not(test))] + {} +} + #[derive(Clone)] struct Nodes { - values: Vec>, + values: Vec>, visited: BitSet, free: Nid, lookup: Lookup, @@ -130,11 +144,12 @@ impl Nodes { fn remove_low(&mut self, id: Nid) -> Node { if cfg!(debug_assertions) { - let value = mem::replace(&mut self.values[id as usize], Err(self.free)).unwrap(); + let value = + mem::replace(&mut self.values[id as usize], Err((self.free, trace()))).unwrap(); self.free = id; value } else { - mem::replace(&mut self.values[id as usize], Err(Nid::MAX)).unwrap() + mem::replace(&mut self.values[id as usize], Err((Nid::MAX, trace()))).unwrap() } } @@ -162,7 +177,7 @@ impl Nodes { if self.free == Nid::MAX { self.free = self.values.len() as _; - self.values.push(Err(Nid::MAX)); + self.values.push(Err((Nid::MAX, trace()))); } let free = self.free; @@ -170,7 +185,7 @@ impl Nodes { debug_assert_ne!(d, free); self.values[d as usize].as_mut().unwrap_or_else(|_| panic!("{d}")).outputs.push(free); } - self.free = mem::replace(&mut self.values[free as usize], Ok(node)).unwrap_err(); + self.free = mem::replace(&mut self.values[free as usize], Ok(node)).unwrap_err().0; if let Some((entry, hash)) = lookup_meta { entry.insert(crate::ctx_map::Key { value: free, hash }, ()); @@ -219,7 +234,7 @@ impl Nodes { return false; } - debug_assert!(!matches!(self[target].kind, Kind::Call { .. })); + debug_assert!(!matches!(self[target].kind, Kind::Call { .. }), "{:?}", self[target]); for i in 0..self[target].inputs.len() { let inp = self[target].inputs[i]; @@ -935,13 +950,13 @@ impl ops::Index for Nodes { type Output = Node; fn index(&self, index: Nid) -> &Self::Output { - self.values[index as usize].as_ref().unwrap() + self.values[index as usize].as_ref().unwrap_or_else(|(_, bt)| panic!("{index} {bt:#?}")) } } impl ops::IndexMut for Nodes { fn index_mut(&mut self, index: Nid) -> &mut Self::Output { - self.values[index as usize].as_mut().unwrap() + self.values[index as usize].as_mut().unwrap_or_else(|(_, bt)| panic!("{index} {bt:#?}")) } } @@ -2048,14 +2063,17 @@ impl<'a> Codegen<'a> { self.ci.nodes[NEVER].inputs.push(self.ci.ctrl); self.ci.nodes[self.ci.ctrl].outputs.push(NEVER); } else if let Some((pv, ctrl)) = &mut self.ci.inline_ret { + self.ci.nodes.unlock(*ctrl); *ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Region, [self.ci.ctrl, *ctrl]); + self.ci.nodes.lock(*ctrl); self.ci.ctrl = *ctrl; self.ci.nodes.unlock(pv.id); pv.id = self.ci.nodes.new_node(value.ty, Kind::Phi, [*ctrl, value.id, pv.id]); self.ci.nodes.lock(pv.id); } else { self.ci.nodes.lock(value.id); + self.ci.nodes.lock(self.ci.ctrl); self.ci.inline_ret = Some((value, self.ci.ctrl)); } @@ -2501,9 +2519,10 @@ impl<'a> Codegen<'a> { return Value::NEVER; }; - let fuc = &self.tys.ins.funcs[fu as usize]; - let ast = &self.files[fuc.file as usize]; - let &Expr::Closure { args: cargs, body, .. } = fuc.expr.get(ast) else { + let Func { expr, file, .. } = self.tys.ins.funcs[fu as usize]; + + let ast = &self.files[file as usize]; + let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() }; @@ -2550,6 +2569,7 @@ impl<'a> Codegen<'a> { let prev_ret = self.ci.ret.replace(sig.ret); let prev_inline_ret = self.ci.inline_ret.take(); + let prev_file = core::mem::replace(&mut self.ci.file, file); self.ci.inline_depth += 1; if self.expr(body).is_some() && sig.ret == ty::Id::VOID { @@ -2561,12 +2581,14 @@ impl<'a> Codegen<'a> { } self.ci.ret = prev_ret; + 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); } - core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, _)| { + core::mem::replace(&mut self.ci.inline_ret, prev_inline_ret).map(|(v, ctrl)| { + self.ci.nodes.unlock(ctrl); self.ci.nodes.unlock(v.id); v }) @@ -3145,6 +3167,7 @@ impl<'a> Codegen<'a> { 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() { @@ -3170,6 +3193,7 @@ impl<'a> Codegen<'a> { if drop_from { nodes.unlock_remove_scope(from); } + nodes.unlock(ctrl); } #[inline(always)] @@ -4170,6 +4194,7 @@ mod tests { fb_driver; // Purely Testing Examples; + smh_happened; wide_ret; comptime_min_reg_leak; different_types; diff --git a/lang/tests/son_tests_inline.txt b/lang/tests/son_tests_inline.txt index b0629dac..7cc56198 100644 --- a/lang/tests/son_tests_inline.txt +++ b/lang/tests/son_tests_inline.txt @@ -2,13 +2,17 @@ main: LI64 r5, 0d LRA r4, r0, :gb LD r6, r4, 0a, 8h - LI64 r9, 6d - JEQ r6, r5, :0 - LI64 r12, 1d + CMPS r9, r6, r5 + CMPUI r9, r9, 0d + ORI r11, r9, 0d + LI64 r1, 6d + ANDI r11, r11, 255d + JNE r11, r0, :0 + CP r5, r1 JMP :1 - 0: CP r12, r9 - 1: SUB64 r1, r12, r9 + 0: LI64 r5, 1d + 1: SUB64 r1, r5, r1 JALA r0, r31, 0a -code size: 94 +code size: 131 ret: 0 status: Ok(()) diff --git a/lang/tests/son_tests_smh_happened.txt b/lang/tests/son_tests_smh_happened.txt new file mode 100644 index 00000000..e69de29b