fixing small struct return

This commit is contained in:
Jakub Doka 2024-10-24 13:25:30 +02:00
parent 78ebc3292c
commit e0d4955bd5
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 137 additions and 67 deletions

View file

@ -527,6 +527,19 @@ main := fn(): int {
### Purely Testing Examples ### Purely Testing Examples
#### returning_global_struct
```hb
Color := struct {r: u8, g: u8, b: u8, a: u8}
white := Color.(255, 255, 255, 255)
random_color := fn(): Color {
return white
}
main := fn(): int {
val := random_color()
return @as(int, val.r) + val.g + val.b + val.a
}
```
#### wide_ret #### wide_ret
```hb ```hb
OemIdent := struct { OemIdent := struct {

View file

@ -37,6 +37,7 @@ fn ensure_loaded(value: CtValue, derefed: bool, size: u32) -> u64 {
mod stack { mod stack {
use { use {
super::{Offset, Size}, super::{Offset, Size},
crate::debug,
alloc::vec::Vec, alloc::vec::Vec,
core::num::NonZeroU32, core::num::NonZeroU32,
}; };
@ -81,17 +82,7 @@ mod stack {
impl Drop for Id { impl Drop for Id {
fn drop(&mut self) { fn drop(&mut self) {
let is_panicking = { if !debug::panicking() && !self.is_ref() {
#[cfg(feature = "std")]
{
std::thread::panicking()
}
#[cfg(not(feature = "std"))]
{
false
}
};
if !is_panicking && !self.is_ref() {
unreachable!("stack id leaked: {:?}", self.0); unreachable!("stack id leaked: {:?}", self.0);
} }
} }
@ -163,7 +154,10 @@ mod stack {
} }
mod rall { mod rall {
use {crate::reg::*, alloc::vec::Vec}; use {
crate::{debug, reg::*},
alloc::vec::Vec,
};
type Reg = u8; type Reg = u8;
@ -208,17 +202,9 @@ mod rall {
#[cfg(all(debug_assertions, feature = "std"))] #[cfg(all(debug_assertions, feature = "std"))]
impl Drop for Id { impl Drop for Id {
fn drop(&mut self) { fn drop(&mut self) {
let is_panicking = { if !debug::panicking()
#[cfg(all(debug_assertions, feature = "std"))] && let Some(bt) = self.1.take()
{ {
std::thread::panicking()
}
#[cfg(not(all(debug_assertions, feature = "std")))]
{
false
}
};
if !is_panicking && let Some(bt) = self.1.take() {
unreachable!("reg id leaked: {:?} {bt}", self.0); unreachable!("reg id leaked: {:?} {bt}", self.0);
} }
} }

View file

@ -75,6 +75,34 @@ pub mod lexer;
#[cfg(feature = "opts")] #[cfg(feature = "opts")]
mod vc; mod vc;
mod debug {
pub fn panicking() -> bool {
#[cfg(feature = "std")]
{
std::thread::panicking()
}
#[cfg(not(feature = "std"))]
{
false
}
}
#[cfg(all(debug_assertions, feature = "std"))]
pub type Trace = std::rc::Rc<std::backtrace::Backtrace>;
#[cfg(not(all(debug_assertions, feature = "std")))]
pub type Trace = ();
pub fn trace() -> Trace {
#[cfg(all(debug_assertions, feature = "std"))]
{
std::rc::Rc::new(std::backtrace::Backtrace::capture())
}
#[cfg(not(all(debug_assertions, feature = "std")))]
{}
}
}
pub mod reg { pub mod reg {
pub const STACK_PTR: Reg = 254; pub const STACK_PTR: Reg = 254;
pub const ZERO: Reg = 0; pub const ZERO: Reg = 0;
@ -252,7 +280,7 @@ mod ty {
parser::{self, Pos}, parser::{self, Pos},
Size, Types, Size, Types,
}, },
core::{num::NonZeroU32, ops::Range, usize}, core::{num::NonZeroU32, ops::Range},
}; };
pub type ArrayLen = u32; pub type ArrayLen = u32;
@ -1268,7 +1296,7 @@ impl Types {
}) })
.chain(self.ins.globals.iter().filter(|g| task::is_done(g.offset)).map(|g| { .chain(self.ins.globals.iter().filter(|g| task::is_done(g.offset)).map(|g| {
let name = if g.file == u32::MAX { let name = if g.file == u32::MAX {
core::str::from_utf8(&g.data).unwrap() core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else { } else {
let file = &files[g.file as usize]; let file = &files[g.file as usize];
file.ident_str(g.name) file.ident_str(g.name)

View file

@ -2,6 +2,7 @@ use {
self::var::{Scope, Variable}, self::var::{Scope, Variable},
crate::{ crate::{
ctx_map::CtxEntry, ctx_map::CtxEntry,
debug,
ident::Ident, ident::Ident,
instrs, instrs,
lexer::{self, TokenKind}, lexer::{self, TokenKind},
@ -23,6 +24,7 @@ use {
fmt::{self, Debug, Display, Write}, fmt::{self, Debug, Display, Write},
format_args as fa, mem, format_args as fa, mem,
ops::{self}, ops::{self},
u16,
}, },
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode::DisasmError, hbbytecode::DisasmError,
@ -49,7 +51,7 @@ impl StoreId for Nid {
} }
impl crate::ctx_map::CtxEntry for Nid { impl crate::ctx_map::CtxEntry for Nid {
type Ctx = [Result<Node, (Nid, Trace)>]; type Ctx = [Result<Node, (Nid, debug::Trace)>];
type Key<'a> = (Kind, &'a [Nid], ty::Id); type Key<'a> = (Kind, &'a [Nid], ty::Id);
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
@ -57,23 +59,9 @@ impl crate::ctx_map::CtxEntry for Nid {
} }
} }
#[cfg(debug_assertions)]
type Trace = std::rc::Rc<std::backtrace::Backtrace>;
#[cfg(not(debug_assertions))]
type Trace = ();
fn trace() -> Trace {
#[cfg(debug_assertions)]
{
std::rc::Rc::new(std::backtrace::Backtrace::capture())
}
#[cfg(not(debug_assertions))]
{}
}
#[derive(Clone)] #[derive(Clone)]
struct Nodes { struct Nodes {
values: Vec<Result<Node, (Nid, Trace)>>, values: Vec<Result<Node, (Nid, debug::Trace)>>,
visited: BitSet, visited: BitSet,
free: Nid, free: Nid,
lookup: Lookup, lookup: Lookup,
@ -165,15 +153,18 @@ impl Nodes {
} }
fn graphviz_in_browser(&self, tys: &Types, files: &[parser::Ast]) { fn graphviz_in_browser(&self, tys: &Types, files: &[parser::Ast]) {
let out = &mut String::new(); #[cfg(all(debug_assertions, feature = "std"))]
_ = 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}"); 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}");
}
} }
} }
@ -188,11 +179,12 @@ impl Nodes {
fn remove_low(&mut self, id: Nid) -> Node { fn remove_low(&mut self, id: Nid) -> Node {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
let value = let value =
mem::replace(&mut self.values[id as usize], Err((self.free, trace()))).unwrap(); mem::replace(&mut self.values[id as usize], Err((self.free, debug::trace())))
.unwrap();
self.free = id; self.free = id;
value value
} else { } else {
mem::replace(&mut self.values[id as usize], Err((Nid::MAX, trace()))).unwrap() mem::replace(&mut self.values[id as usize], Err((Nid::MAX, debug::trace()))).unwrap()
} }
} }
@ -240,7 +232,7 @@ impl Nodes {
if self.free == Nid::MAX { if self.free == Nid::MAX {
self.free = self.values.len() as _; self.free = self.values.len() as _;
self.values.push(Err((Nid::MAX, trace()))); self.values.push(Err((Nid::MAX, debug::trace())));
} }
let free = self.free; let free = self.free;
@ -1132,7 +1124,7 @@ struct Loop {
mod var { mod var {
use { use {
super::{Kind, Nid, Nodes}, super::{Kind, Nid, Nodes},
crate::{ident::Ident, ty}, crate::{debug, ident::Ident, ty},
alloc::vec::Vec, alloc::vec::Vec,
}; };
@ -1189,7 +1181,7 @@ mod var {
impl Drop for Variable { impl Drop for Variable {
fn drop(&mut self) { fn drop(&mut self) {
if self.ty != ty::Id::UNDECLARED && !std::thread::panicking() { if self.ty != ty::Id::UNDECLARED && !debug::panicking() {
panic!("variable unproperly deinitialized") panic!("variable unproperly deinitialized")
} }
} }
@ -1427,11 +1419,19 @@ impl ItemCtx {
self.emit(instrs::ld(r, atr(allocs[0]), 0, size)) self.emit(instrs::ld(r, atr(allocs[0]), 0, size))
} }
Some(PLoc::Ref(_, size)) => { Some(PLoc::Ref(_, size)) => {
self.emit(instrs::bmc( let [src, dst] = [atr(allocs[0]), atr(allocs[1])];
atr(allocs[0]), if let Ok(size) = u16::try_from(size) {
atr(allocs[1]), self.emit(instrs::bmc(src, dst, size));
size.try_into().expect("TODO: handle huge copies"), } else {
)); for _ in 0..size / u16::MAX as u32 {
self.emit(instrs::bmc(src, dst, u16::MAX));
self.emit(instrs::addi64(src, src, u16::MAX as _));
self.emit(instrs::addi64(dst, dst, u16::MAX as _));
}
self.emit(instrs::bmc(src, dst, size as u16));
self.emit(instrs::addi64(src, src, size.wrapping_neg() as _));
self.emit(instrs::addi64(dst, dst, size.wrapping_neg() as _));
}
} }
} }
@ -1522,6 +1522,12 @@ impl ItemCtx {
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset; let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size)); self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
} }
if let Some(PLoc::Reg(r, size)) = ret
&& node.ty.loc(tys) == Loc::Stack
{
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
}
} }
Kind::Global { global } => { Kind::Global { global } => {
let reloc = Reloc::new(self.code.len(), 3, 4); let reloc = Reloc::new(self.code.len(), 3, 4);
@ -2523,8 +2529,7 @@ impl<'a> Codegen<'a> {
Expr::Directive { name: "as", args: [ty, expr], .. } => { Expr::Directive { name: "as", args: [ty, expr], .. } => {
let ty = self.ty(ty); let ty = self.ty(ty);
let ctx = Ctx::default().with_ty(ty); let ctx = Ctx::default().with_ty(ty);
let mut val = self.raw_expr_ctx(expr, ctx)?; let mut val = self.expr_ctx(expr, ctx)?;
self.strip_var(&mut val);
self.assert_ty(expr.pos(), &mut val, ty, "hinted expr"); self.assert_ty(expr.pos(), &mut val, ty, "hinted expr");
Some(val) Some(val)
} }
@ -3230,11 +3235,18 @@ impl<'a> Codegen<'a> {
// FIXME: could fuck us // FIXME: could fuck us
ty::Id::UNDECLARED ty::Id::UNDECLARED
} else { } else {
debug_assert_eq!( if ty != ty::Id::TYPE {
ty, self.report(
ty::Id::TYPE, arg.pos(),
"TODO: we dont support anything except type generics" fa!(
); "arbitrary comptime types are not supported yet \
(expected '{}' got '{}')",
self.ty_display(ty::Id::TYPE),
self.ty_display(ty)
),
);
return None;
}
let ty = self.ty(arg); let ty = self.ty(arg);
self.tys.tmp.args.push(ty); self.tys.tmp.args.push(ty);
ty ty
@ -4437,6 +4449,7 @@ mod tests {
fb_driver; fb_driver;
// Purely Testing Examples; // Purely Testing Examples;
returning_global_struct;
wide_ret; wide_ret;
comptime_min_reg_leak; comptime_min_reg_leak;
different_types; different_types;

View file

@ -0,0 +1,29 @@
main:
ADDI64 r254, r254, -24d
ST r31, r254, 8a, 16h
ADDI64 r32, r254, 4d
JAL r31, r0, :random_color
ST r1, r254, 4a, 4h
ADDI64 r5, r254, 0d
BMC r32, r5, 4h
LD r4, r254, 3a, 1h
ANDI r6, r4, 255d
LD r3, r254, 2a, 1h
ANDI r5, r3, 255d
LD r2, r254, 1a, 1h
ANDI r4, r2, 255d
LD r2, r254, 0a, 1h
ANDI r7, r2, 255d
ADD64 r8, r4, r7
ADD64 r12, r8, r5
ADD64 r1, r12, r6
LD r31, r254, 8a, 16h
ADDI64 r254, r254, 24d
JALA r0, r31, 0a
random_color:
LRA r1, r0, :white
LD r1, r1, 0a, 4h
JALA r0, r31, 0a
code size: 257
ret: 1020
status: Ok(())

View file

@ -20,6 +20,7 @@ maina:
ST r31, r254, 32a, 16h ST r31, r254, 32a, 16h
ADDI64 r32, r254, 28d ADDI64 r32, r254, 28d
JAL r31, r0, :small_struct JAL r31, r0, :small_struct
ST r1, r254, 28a, 4h
LI64 r2, 1d LI64 r2, 1d
LI64 r4, 3d LI64 r4, 3d
LI64 r1, 0d LI64 r1, 0d
@ -51,6 +52,6 @@ small_struct:
LD r1, r3, 0a, 4h LD r1, r3, 0a, 4h
ADDI64 r254, r254, 4d ADDI64 r254, r254, 4d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 544 code size: 557
ret: 2 ret: 2
status: Ok(()) status: Ok(())