fixing more bugs and also adding uninig memory and also optimizing cong jumps

This commit is contained in:
mlokr 2024-09-09 19:36:53 +02:00
parent e8a5027cab
commit 73727c2383
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
20 changed files with 721 additions and 360 deletions

View file

@ -335,6 +335,19 @@ foo := fn(a: int, b: int, c: int): int {
} }
``` ```
#### idk
```hb
main := fn(): int {
big_array := @as([u8; 128], idk)
i := 0
loop if i >= 128 break else {
big_array[i] = 69
i += 1
}
return big_array[42]
}
```
### Incomplete Examples ### Incomplete Examples
#### comptime_pointers #### comptime_pointers

View file

@ -8,7 +8,7 @@ use {
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos}, parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
HashMap, HashMap,
}, },
std::{collections::BTreeMap, fmt::Display, ops::Range, rc::Rc}, std::{collections::BTreeMap, fmt::Display, ops::Range, rc::Rc, u32},
}; };
type Offset = u32; type Offset = u32;
@ -688,6 +688,10 @@ impl Loc {
Self::Rt { .. } => None, Self::Rt { .. } => None,
} }
} }
fn is_stack(&self) -> bool {
matches!(self, Self::Rt { derefed: true, reg, stack: Some(_), offset: 0 } if reg.get() == STACK_PTR)
}
} }
impl From<reg::Id> for Loc { impl From<reg::Id> for Loc {
@ -702,6 +706,7 @@ impl Default for Loc {
} }
} }
#[derive(Clone, Copy)]
struct Loop { struct Loop {
var_count: u32, var_count: u32,
offset: u32, offset: u32,
@ -710,6 +715,7 @@ struct Loop {
struct Variable { struct Variable {
id: Ident, id: Ident,
uses_left: u32,
value: Value, value: Value,
} }
@ -1419,7 +1425,9 @@ impl Codegen {
// TODO: we need to check if index is in bounds on debug builds // TODO: we need to check if index is in bounds on debug builds
let mut base_val = self.expr(base)?; let mut base_val = self.expr(base)?;
base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty); if base_val.ty.is_pointer() {
base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty);
}
let index_val = self.expr(index)?; let index_val = self.expr(index)?;
_ = self.assert_ty(index.pos(), index_val.ty, ty::INT.into(), "subsctipt"); _ = self.assert_ty(index.pos(), index_val.ty, ty::INT.into(), "subsctipt");
@ -1449,7 +1457,9 @@ impl Codegen {
let idx = self.loc_to_reg(index_val.loc, 8); let idx = self.loc_to_reg(index_val.loc, 8);
self.output.emit(muli64(idx.get(), idx.get(), item_size as _)); if item_size != 1 {
self.output.emit(muli64(idx.get(), idx.get(), item_size as _));
}
self.output.emit(add64(reg.get(), reg.get(), idx.get())); self.output.emit(add64(reg.get(), reg.get(), idx.get()));
self.ci.regs.free(idx); self.ci.regs.free(idx);
@ -1491,7 +1501,13 @@ impl Codegen {
args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs) args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs)
{ {
let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc; let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc;
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } });
let sym = parser::find_symbol(&fast.symbols, carg.id).flags;
self.ci.vars.push(Variable {
id: carg.id,
value: Value { ty, loc },
uses_left: idfl::count(sym) as u32,
});
} }
} }
@ -1524,11 +1540,7 @@ impl Codegen {
return Some(Value { ty: sig.ret, loc }); return Some(Value { ty: sig.ret, loc });
} }
E::Directive { name: "TypeOf", args: [expr], .. } => { E::Directive { name: "TypeOf", args: [expr], .. } => {
let snap = self.output.snap(); Some(Value::ty(self.infer_type(expr)))
let value = self.expr(expr).unwrap();
self.ci.free_loc(value.loc);
self.output.trunc(&snap);
Some(Value::ty(value.ty))
} }
E::Directive { name: "eca", args: [ret_ty, args @ ..], .. } => { E::Directive { name: "eca", args: [ret_ty, args @ ..], .. } => {
let ty = self.ty(ret_ty); let ty = self.ty(ret_ty);
@ -1585,7 +1597,7 @@ impl Codegen {
let Some(ty) = ctx.ty else { let Some(ty) = ctx.ty else {
self.report( self.report(
expr.pos(), expr.pos(),
"type to cast to is unknown, use `@as(<type>, <expr>)`", "type to cast to is unknown, use `@as(<type>, @bitcast(<expr>))`",
); );
}; };
@ -1623,6 +1635,31 @@ impl Codegen {
E::Bool { value, .. } => { E::Bool { value, .. } => {
Some(Value { ty: ty::BOOL.into(), loc: Loc::ct(value as u64) }) Some(Value { ty: ty::BOOL.into(), loc: Loc::ct(value as u64) })
} }
E::Idk { pos } => {
let Some(ty) = ctx.ty else {
self.report(
pos,
"`idk` can be used only when type can be inferred, use @as(<type>, idk)",
);
};
if ctx.loc.is_some() {
self.report(
pos,
"`idk` would be written to an existing memory location \
which at ths point does notthing so its prohibited. TODO: make debug \
builds write 0xAA instead.",
);
}
let loc = match self.tys.size_of(ty) {
0 => Loc::default(),
1..=8 => Loc::reg(self.ci.regs.allocate()),
size => Loc::stack(self.ci.stack.allocate(size)),
};
Some(Value { ty, loc })
}
E::String { pos, mut literal } => { E::String { pos, mut literal } => {
literal = literal.trim_matches('"'); literal = literal.trim_matches('"');
@ -1917,12 +1954,12 @@ impl Codegen {
return Some(Value { ty: sig.ret, loc }); return Some(Value { ty: sig.ret, loc });
} }
E::Ident { id, .. } if ident::is_null(id) => Some(Value::ty(id.into())), E::Ident { id, .. } if ident::is_null(id) => Some(Value::ty(id.into())),
E::Ident { id, index, .. } E::Ident { id, .. }
if let Some((var_index, var)) = if let Some((var_index, var)) =
self.ci.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) => self.ci.vars.iter_mut().enumerate().find(|(_, v)| v.id == id) =>
{ {
let sym = parser::find_symbol(&self.files[self.ci.file as usize].symbols, id); var.uses_left -= 1;
let loc = match idfl::index(sym.flags) == index let loc = match var.uses_left == 0
&& !self.ci.loops.last().is_some_and(|l| l.var_count > var_index as u32) && !self.ci.loops.last().is_some_and(|l| l.var_count > var_index as u32)
{ {
true => std::mem::take(&mut var.value.loc), true => std::mem::take(&mut var.value.loc),
@ -1990,15 +2027,59 @@ impl Codegen {
}, },
loc: Loc::ct(value as u64), loc: Loc::ct(value as u64),
}), }),
E::If { cond, then, else_, .. } => { E::If { cond, then, mut else_, .. } => {
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?; #[allow(clippy::type_complexity)]
let reg = self.loc_to_reg(&cond.loc, 1); fn cond_op(
let jump_offset = self.local_offset(); op: TokenKind,
self.output.emit(jeq(reg.get(), 0, 0)); signed: bool,
self.ci.free_loc(cond.loc); ) -> Option<(fn(u8, u8, i16) -> (usize, [u8; instrs::MAX_SIZE]), bool)>
self.ci.regs.free(reg); {
Some((
match op {
TokenKind::Le if signed => instrs::jgts,
TokenKind::Le => instrs::jgtu,
TokenKind::Lt if signed => instrs::jlts,
TokenKind::Lt => instrs::jltu,
TokenKind::Eq => instrs::jne,
TokenKind::Ne => instrs::jeq,
_ => return None,
},
matches!(op, TokenKind::Lt | TokenKind::Gt),
))
}
let then_unreachable = self.expr(then).is_none(); let mut then = Some(then);
let jump_offset;
if let &E::BinOp { left, op, right } = cond
&& let ty = self.infer_type(left)
&& let Some((op, swapped)) = cond_op(op, ty.is_signed())
{
let left = self.expr_ctx(left, Ctx::default())?;
let right = self.expr_ctx(right, Ctx::default())?;
let lsize = self.tys.size_of(left.ty);
let rsize = self.tys.size_of(right.ty);
let left_reg = self.loc_to_reg(&left.loc, lsize);
let right_reg = self.loc_to_reg(&right.loc, rsize);
jump_offset = self.local_offset();
self.output.emit(op(left_reg.get(), right_reg.get(), 0));
self.ci.free_loc(left.loc);
self.ci.free_loc(right.loc);
self.ci.regs.free(left_reg);
self.ci.regs.free(right_reg);
if swapped {
std::mem::swap(&mut then, &mut else_);
}
} else {
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
let reg = self.loc_to_reg(&cond.loc, 1);
jump_offset = self.local_offset();
self.output.emit(jeq(reg.get(), 0, 0));
self.ci.free_loc(cond.loc);
self.ci.regs.free(reg);
}
let then_unreachable =
if let Some(then) = then { self.expr(then).is_none() } else { false };
let mut else_unreachable = false; let mut else_unreachable = false;
let mut jump = self.local_offset() as i64 - jump_offset as i64; let mut jump = self.local_offset() as i64 - jump_offset as i64;
@ -2196,9 +2277,8 @@ impl Codegen {
Some(match ctx.loc { Some(match ctx.loc {
Some(dest) => { Some(dest) => {
let ty = ctx.ty.unwrap_or(value.ty); self.store_typed(value.loc, dest, value.ty);
self.store_typed(value.loc, dest, ty); Value { ty: value.ty, loc: Loc::ct(0) }
Value { ty, loc: Loc::ct(0) }
} }
None => value, None => value,
}) })
@ -2236,7 +2316,11 @@ impl Codegen {
arg.loc arg.loc
}; };
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } }); self.ci.vars.push(Variable {
id: carg.id,
value: Value { ty, loc },
uses_left: idfl::count(sym.flags) as u32,
});
} }
let args = self.pack_args(pos, arg_base); let args = self.pack_args(pos, arg_base);
@ -2266,6 +2350,38 @@ impl Codegen {
expr.has_ct(&self.cfile().symbols) expr.has_ct(&self.cfile().symbols)
} }
fn infer_type(&mut self, expr: &Expr) -> ty::Id {
let mut snap = self.output.snap();
snap._sub(&self.ci.snap);
let mut ci = ItemCtx {
file: self.ci.file,
id: self.ci.id,
ret: self.ci.ret,
task_base: self.ci.task_base,
snap: self.ci.snap,
loops: self.ci.loops.clone(),
vars: self
.ci
.vars
.iter()
.map(|v| Variable {
id: v.id,
value: Value { ty: v.value.ty, loc: v.value.loc.as_ref() },
uses_left: v.uses_left,
})
.collect(),
..Default::default()
};
ci.regs.init();
std::mem::swap(&mut self.ci, &mut ci);
let value = self.expr(expr).unwrap();
self.ci.free_loc(value.loc);
std::mem::swap(&mut self.ci, &mut ci);
snap._add(&self.ci.snap);
self.output.trunc(&snap);
value.ty
}
fn eval_const(&mut self, expr: &Expr, ty: impl Into<ty::Id>) -> u64 { fn eval_const(&mut self, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
self.eval_const_low(expr, Some(ty.into())).0 self.eval_const_low(expr, Some(ty.into())).0
} }
@ -2321,11 +2437,15 @@ impl Codegen {
&& size <= 8 => && size <= 8 =>
{ {
let loc = Loc::ct(load_value(offset, size)); let loc = Loc::ct(load_value(offset, size));
self.ci.vars.push(Variable { id, value: Value { ty, loc } }); self.ci.vars.push(Variable { id, value: Value { ty, loc }, uses_left: u32::MAX });
true true
} }
Expr::Ident { id, .. } => { Expr::Ident { id, .. } => {
let var = Variable { id, value: Value { ty, loc: Loc::ct_ptr(offset as _) } }; let var = Variable {
id,
value: Value { ty, loc: Loc::ct_ptr(offset as _) },
uses_left: u32::MAX,
};
self.ci.vars.push(var); self.ci.vars.push(var);
false false
} }
@ -2337,11 +2457,15 @@ impl Codegen {
match *pat { match *pat {
Expr::Ident { id, .. } => { Expr::Ident { id, .. } => {
let mut loc = self.make_loc_owned(right.loc, right.ty); let mut loc = self.make_loc_owned(right.loc, right.ty);
let sym = parser::find_symbol(&self.cfile().symbols, id); let sym = parser::find_symbol(&self.cfile().symbols, id).flags;
if sym.flags & idfl::REFERENCED != 0 { if sym & idfl::REFERENCED != 0 {
loc = self.spill(loc, self.tys.size_of(right.ty)); loc = self.spill(loc, self.tys.size_of(right.ty));
} }
self.ci.vars.push(Variable { id, value: Value { ty: right.ty, loc } }); self.ci.vars.push(Variable {
id,
value: Value { ty: right.ty, loc },
uses_left: idfl::count(sym) as u32,
});
} }
Expr::Ctor { pos, fields, .. } => { Expr::Ctor { pos, fields, .. } => {
let ty::Kind::Struct(idx) = right.ty.expand() else { let ty::Kind::Struct(idx) = right.ty.expand() else {
@ -2553,9 +2677,13 @@ impl Codegen {
} }
fn spill(&mut self, loc: Loc, size: Size) -> Loc { fn spill(&mut self, loc: Loc, size: Size) -> Loc {
let stack = Loc::stack(self.ci.stack.allocate(size)); if loc.is_ref() || !loc.is_stack() {
self.store_sized(loc, &stack, size); let stack = Loc::stack(self.ci.stack.allocate(size));
stack self.store_sized(loc, &stack, size);
stack
} else {
loc
}
} }
fn make_loc_owned(&mut self, loc: Loc, ty: ty::Id) -> Loc { fn make_loc_owned(&mut self, loc: Loc, ty: ty::Id) -> Loc {
@ -2595,7 +2723,6 @@ impl Codegen {
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) {
dbg!(&srel.range);
debug_assert!( debug_assert!(
srel.range.end <= prev_data_len as u32, srel.range.end <= prev_data_len as u32,
"{} <= {}", "{} <= {}",
@ -2628,7 +2755,7 @@ impl Codegen {
self.ci.snap = self.output.snap(); self.ci.snap = self.output.snap();
let Expr::BinOp { let Expr::BinOp {
left: Expr::Ident { name, .. }, left: Expr::Ident { .. },
op: TokenKind::Decl, op: TokenKind::Decl,
right: &Expr::Closure { body, args, .. }, right: &Expr::Closure { body, args, .. },
} = expr } = expr
@ -2636,20 +2763,22 @@ 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);
let mut sig_args = sig.args.range(); let mut sig_args = sig.args.range();
for arg in args.iter() { for arg in args.iter() {
let ty = self.tys.args[sig_args.next().unwrap()]; let ty = self.tys.args[sig_args.next().unwrap()];
let sym = parser::find_symbol(&ast.symbols, arg.id); let sym = parser::find_symbol(&ast.symbols, arg.id).flags;
let loc = match sym.flags & idfl::COMPTIME != 0 { let loc = match sym & idfl::COMPTIME != 0 {
true => Loc::ty(self.tys.args[sig_args.next().unwrap()]), true => Loc::ty(self.tys.args[sig_args.next().unwrap()]),
false => self.load_arg(sym.flags, ty, &mut parama), false => self.load_arg(sym, ty, &mut parama),
}; };
self.ci.vars.push(Variable { id: arg.id, value: Value { ty, loc } }); self.ci.vars.push(Variable {
id: arg.id,
value: Value { ty, loc },
uses_left: idfl::count(sym) as u32,
});
} }
if self.tys.size_of(sig.ret) > 16 { if self.tys.size_of(sig.ret) > 16 {
@ -2980,6 +3109,7 @@ impl Codegen {
self.ci.vars.push(Variable { self.ci.vars.push(Variable {
id, id,
value: Value::new(ty, Loc::ct(u64::from_ne_bytes(imm))), value: Value::new(ty, Loc::ct(u64::from_ne_bytes(imm))),
uses_left: u32::MAX,
}); });
} }
@ -3555,6 +3685,7 @@ mod tests {
generic_types => README; generic_types => README;
generic_functions => README; generic_functions => README;
c_strings => README; c_strings => README;
idk => README;
struct_patterns => README; struct_patterns => README;
arrays => README; arrays => README;
struct_return_from_module_function => README; struct_return_from_module_function => README;
@ -3562,7 +3693,7 @@ mod tests {
sort_something_viredly => README; sort_something_viredly => README;
hex_octal_binary_literals => README; hex_octal_binary_literals => README;
comptime_min_reg_leak => README; comptime_min_reg_leak => README;
// structs_in_registers => README; // structs_in_registers => README;
comptime_function_from_another_file => README; comptime_function_from_another_file => README;
inline => README; inline => README;
inline_test => README; inline_test => README;

View file

@ -44,19 +44,23 @@ macro_rules! gen_token_kind {
) => { ) => {
impl std::fmt::Display for $name { impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let sf = *self as u8; f.write_str(self.name())
f.write_str(match *self { }
}
impl $name {
pub fn name(&self) -> &str {
let sf = unsafe { &*(self as *const _ as *const u8) } ;
match *self {
$( Self::$pattern => concat!('<', stringify!($pattern), '>'), )* $( Self::$pattern => concat!('<', stringify!($pattern), '>'), )*
$( Self::$keyword => stringify!($keyword_lit), )* $( Self::$keyword => stringify!($keyword_lit), )*
$( Self::$punkt => stringify!($punkt_lit), )* $( Self::$punkt => stringify!($punkt_lit), )*
$($( Self::$op => $op_lit, $($( Self::$op => $op_lit,
$(Self::$assign => concat!($op_lit, "="),)?)*)* $(Self::$assign => concat!($op_lit, "="),)?)*)*
_ => unsafe { std::str::from_utf8_unchecked(std::slice::from_ref(&sf)) }, _ => unsafe { std::str::from_utf8_unchecked(std::slice::from_ref(&sf)) },
}) }
} }
}
impl $name {
#[inline(always)] #[inline(always)]
pub fn precedence(&self) -> Option<u8> { pub fn precedence(&self) -> Option<u8> {
Some(match self { Some(match self {
@ -124,6 +128,8 @@ pub enum TokenKind {
Fn, Fn,
Struct, Struct,
True, True,
False,
Idk,
Ctor, Ctor,
Tupl, Tupl,
@ -204,15 +210,17 @@ gen_token_kind! {
Eof, Eof,
Directive, Directive,
#[keywords] #[keywords]
Return = b"return", Return = b"return",
If = b"if", If = b"if",
Else = b"else", Else = b"else",
Loop = b"loop", Loop = b"loop",
Break = b"break", Break = b"break",
Continue = b"continue", Continue = b"continue",
Fn = b"fn", Fn = b"fn",
Struct = b"struct", Struct = b"struct",
True = b"true", True = b"true",
False = b"false",
Idk = b"idk",
#[punkt] #[punkt]
Ctor = ".{", Ctor = ".{",
Tupl = ".(", Tupl = ".(",

View file

@ -36,7 +36,7 @@ pub mod idfl {
COMPTIME, COMPTIME,
} }
pub fn index(i: IdentFlags) -> IdentIndex { pub fn count(i: IdentFlags) -> IdentIndex {
(i & !ALL) as _ (i & !ALL) as _
} }
} }
@ -251,7 +251,7 @@ impl<'a, 'b> Parser<'a, 'b> {
self.captured.push(id.ident); self.captured.push(id.ident);
} }
(id.ident, idfl::index(id.flags)) (id.ident, idfl::count(id.flags))
} }
fn move_str(&mut self, range: Token) -> &'a str { fn move_str(&mut self, range: Token) -> &'a str {
@ -261,11 +261,11 @@ impl<'a, 'b> Parser<'a, 'b> {
fn unit_expr(&mut self) -> Expr<'a> { fn unit_expr(&mut self) -> Expr<'a> {
use {Expr as E, TokenKind as T}; use {Expr as E, TokenKind as T};
let frame = self.idents.len(); let frame = self.idents.len();
let token = self.next(); let token @ Token { start: pos, .. } = self.next();
let prev_boundary = self.ns_bound; let prev_boundary = self.ns_bound;
let prev_captured = self.captured.len(); let prev_captured = self.captured.len();
let mut expr = match token.kind { let mut expr = match token.kind {
T::Ct => E::Ct { pos: token.start, value: self.ptr_expr() }, T::Ct => E::Ct { pos, value: self.ptr_expr() },
T::Directive if self.lexer.slice(token.range()) == "use" => { T::Directive if self.lexer.slice(token.range()) == "use" => {
self.expect_advance(TokenKind::LParen); self.expect_advance(TokenKind::LParen);
let str = self.expect_advance(TokenKind::DQuote); let str = self.expect_advance(TokenKind::DQuote);
@ -273,7 +273,7 @@ impl<'a, 'b> Parser<'a, 'b> {
let path = self.lexer.slice(str.range()).trim_matches('"'); let path = self.lexer.slice(str.range()).trim_matches('"');
E::Mod { E::Mod {
pos: token.start, pos,
path: self.arena.alloc_str(path), path: self.arena.alloc_str(path),
id: match (self.loader)(path, self.path) { id: match (self.loader)(path, self.path) {
Ok(id) => id, Ok(id) => id,
@ -282,15 +282,17 @@ impl<'a, 'b> Parser<'a, 'b> {
} }
} }
T::Directive => E::Directive { T::Directive => E::Directive {
pos: token.start, pos,
name: self.move_str(token), name: self.move_str(token),
args: { args: {
self.expect_advance(T::LParen); self.expect_advance(T::LParen);
self.collect_list(T::Comma, T::RParen, Self::expr) self.collect_list(T::Comma, T::RParen, Self::expr)
}, },
}, },
T::True => E::Bool { pos: token.start, value: true }, T::True => E::Bool { pos, value: true },
T::DQuote => E::String { pos: token.start, literal: self.move_str(token) }, T::False => E::Bool { pos, value: false },
T::Idk => E::Idk { pos },
T::DQuote => E::String { pos, literal: self.move_str(token) },
T::Struct => E::Struct { T::Struct => E::Struct {
fields: { fields: {
self.ns_bound = self.idents.len(); self.ns_bound = self.idents.len();
@ -313,26 +315,26 @@ impl<'a, 'b> Parser<'a, 'b> {
// we might save some memory // we might save some memory
self.captured.clear(); self.captured.clear();
} }
token.start pos
}, },
trailing_comma: std::mem::take(&mut self.trailing_sep), trailing_comma: std::mem::take(&mut self.trailing_sep),
}, },
T::Ident | T::CtIdent => { T::Ident | T::CtIdent => {
let (id, index) = self.resolve_ident(token); let (id, index) = self.resolve_ident(token);
let name = self.move_str(token); let name = self.move_str(token);
E::Ident { pos: token.start, is_ct: token.kind == T::CtIdent, name, id, index } E::Ident { pos, is_ct: token.kind == T::CtIdent, name, id, index }
} }
T::If => E::If { T::If => E::If {
pos: token.start, pos,
cond: self.ptr_expr(), cond: self.ptr_expr(),
then: self.ptr_expr(), then: self.ptr_expr(),
else_: self.advance_if(T::Else).then(|| self.ptr_expr()), else_: self.advance_if(T::Else).then(|| self.ptr_expr()),
}, },
T::Loop => E::Loop { pos: token.start, body: self.ptr_expr() }, T::Loop => E::Loop { pos, body: self.ptr_expr() },
T::Break => E::Break { pos: token.start }, T::Break => E::Break { pos },
T::Continue => E::Continue { pos: token.start }, T::Continue => E::Continue { pos },
T::Return => E::Return { T::Return => E::Return {
pos: token.start, pos,
val: (!matches!( val: (!matches!(
self.token.kind, self.token.kind,
T::Semi | T::RBrace | T::RBrack | T::RParen | T::Comma T::Semi | T::RBrace | T::RBrack | T::RParen | T::Comma
@ -340,7 +342,7 @@ impl<'a, 'b> Parser<'a, 'b> {
.then(|| self.ptr_expr()), .then(|| self.ptr_expr()),
}, },
T::Fn => E::Closure { T::Fn => E::Closure {
pos: token.start, pos,
args: { args: {
self.expect_advance(T::LParen); self.expect_advance(T::LParen);
self.collect_list(T::Comma, T::RParen, |s| { self.collect_list(T::Comma, T::RParen, |s| {
@ -363,18 +365,18 @@ impl<'a, 'b> Parser<'a, 'b> {
}, },
body: self.ptr_expr(), body: self.ptr_expr(),
}, },
T::Ctor => self.ctor(token.start, None), T::Ctor => self.ctor(pos, None),
T::Tupl => self.tupl(token.start, None), T::Tupl => self.tupl(pos, None),
T::LBrack => E::Slice { T::LBrack => E::Slice {
item: self.ptr_unit_expr(), item: self.ptr_unit_expr(),
size: self.advance_if(T::Semi).then(|| self.ptr_expr()), size: self.advance_if(T::Semi).then(|| self.ptr_expr()),
pos: { pos: {
self.expect_advance(T::RBrack); self.expect_advance(T::RBrack);
token.start pos
}, },
}, },
T::Band | T::Mul | T::Xor => E::UnOp { T::Band | T::Mul | T::Xor => E::UnOp {
pos: token.start, pos,
op: token.kind, op: token.kind,
val: { val: {
let expr = self.ptr_unit_expr(); let expr = self.ptr_unit_expr();
@ -384,10 +386,7 @@ impl<'a, 'b> Parser<'a, 'b> {
expr expr
}, },
}, },
T::LBrace => E::Block { T::LBrace => E::Block { pos, stmts: self.collect_list(T::Semi, T::RBrace, Self::expr) },
pos: token.start,
stmts: self.collect_list(T::Semi, T::RBrace, Self::expr),
},
T::Number => { T::Number => {
let slice = self.lexer.slice(token.range()); let slice = self.lexer.slice(token.range());
let (slice, radix) = match &slice.get(0..2) { let (slice, radix) = match &slice.get(0..2) {
@ -397,7 +396,7 @@ impl<'a, 'b> Parser<'a, 'b> {
_ => (slice, Radix::Decimal), _ => (slice, Radix::Decimal),
}; };
E::Number { E::Number {
pos: token.start, pos,
value: match u64::from_str_radix(slice, radix as u32) { value: match u64::from_str_radix(slice, radix as u32) {
Ok(value) => value, Ok(value) => value,
Err(e) => self.report(format_args!("invalid number: {e}")), Err(e) => self.report(format_args!("invalid number: {e}")),
@ -410,7 +409,7 @@ impl<'a, 'b> Parser<'a, 'b> {
self.expect_advance(T::RParen); self.expect_advance(T::RParen);
expr expr
} }
T::Comment => Expr::Comment { pos: token.start, literal: self.move_str(token) }, T::Comment => Expr::Comment { pos, literal: self.move_str(token) },
tok => self.report(format_args!("unexpected token: {tok:?}")), tok => self.report(format_args!("unexpected token: {tok:?}")),
}; };
@ -773,6 +772,10 @@ generate_expr! {
pos: Pos, pos: Pos,
value: bool, value: bool,
}, },
/// `'idk'`
Idk {
pos: Pos,
},
/// `'@' Ident List('(', ',', ')', Expr)` /// `'@' Ident List('(', ',', ')', Expr)`
Directive { Directive {
pos: u32, pos: u32,
@ -1047,6 +1050,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
Radix::Binary => write!(f, "{value:#b}"), Radix::Binary => write!(f, "{value:#b}"),
}, },
Self::Bool { value, .. } => write!(f, "{value}"), Self::Bool { value, .. } => write!(f, "{value}"),
Self::Idk { .. } => write!(f, "idk"),
Self::BinOp { Self::BinOp {
left, left,
op: TokenKind::Assign, op: TokenKind::Assign,

View file

@ -15,12 +15,14 @@ use {
core::fmt, core::fmt,
std::{ std::{
cell::RefCell, cell::RefCell,
cmp,
collections::{hash_map, BTreeMap}, collections::{hash_map, BTreeMap},
fmt::Display, fmt::{Display, Write},
hash::{Hash as _, Hasher}, hash::{Hash as _, Hasher},
mem, mem,
ops::{self, Range}, ops::{self, Range},
rc::Rc, rc::Rc,
u32,
}, },
}; };
@ -58,6 +60,7 @@ impl BitSet {
self.data.resize(new_len, 0); self.data.resize(new_len, 0);
} }
#[track_caller]
pub fn set(&mut self, idx: usize) -> bool { pub fn set(&mut self, idx: usize) -> bool {
let data_idx = idx / Self::ELEM_SIZE; let data_idx = idx / Self::ELEM_SIZE;
let sub_idx = idx % Self::ELEM_SIZE; let sub_idx = idx % Self::ELEM_SIZE;
@ -65,6 +68,12 @@ impl BitSet {
self.data[data_idx] |= 1 << sub_idx; self.data[data_idx] |= 1 << sub_idx;
prev == 0 prev == 0
} }
fn unset(&mut self, idx: usize) {
let data_idx = idx / Self::ELEM_SIZE;
let sub_idx = idx % Self::ELEM_SIZE;
self.data[data_idx] &= !(1 << sub_idx);
}
} }
type Nid = u32; type Nid = u32;
@ -532,15 +541,8 @@ impl Nodes {
) -> Nid { ) -> Nid {
let ty = ty.into(); let ty = ty.into();
let node = Node { let node =
inputs: inps.into(), Node { inputs: inps.into(), kind, color: 0, depth: 0, lock_rc: 0, ty, outputs: vec![] };
kind,
color: 0,
depth: u32::MAX,
lock_rc: 0,
ty,
outputs: vec![],
};
let mut lookup_meta = None; let mut lookup_meta = None;
if !node.is_lazy_phi() { if !node.is_lazy_phi() {
@ -689,14 +691,14 @@ impl Nodes {
let ty = self[target].ty; let ty = self[target].ty;
if let (&K::CInt { value: a }, &K::CInt { value: b }) = (&self[lhs].kind, &self[rhs].kind) { 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) }, [])); return Some(self.new_node(ty, K::CInt { value: op.apply(a, b) }, [ctrl]));
} }
if lhs == rhs { if lhs == rhs {
match op { match op {
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [])), T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])),
T::Add => { T::Add => {
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, []); let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]);
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs])); return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]));
} }
_ => {} _ => {}
@ -724,7 +726,7 @@ impl Nodes {
&& let K::CInt { value: bv } = self[rhs].kind && let K::CInt { value: bv } = self[rhs].kind
{ {
// (a op #b) op #c => a op (#b op #c) // (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) }, []); let new_rhs = self.new_node_nop(ty, K::CInt { value: op.apply(av, bv) }, [ctrl]);
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs])); return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
} }
@ -741,7 +743,7 @@ impl Nodes {
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind && let K::CInt { value } = self[self[lhs].inputs[2]].kind
{ {
// a * #n + a => a * (#n + 1) // a * #n + a => a * (#n + 1)
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, []); let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]);
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs])); return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
} }
@ -786,14 +788,12 @@ impl Nodes {
); );
match entry { match entry {
hash_map::RawEntryMut::Occupied(mut other) => { hash_map::RawEntryMut::Occupied(mut other) => {
log::dbg!("rplc");
let rpl = other.get_key_value().0.nid; let rpl = other.get_key_value().0.nid;
self[target].inputs[inp_index] = prev; self[target].inputs[inp_index] = prev;
self.replace(target, rpl); self.replace(target, rpl);
rpl rpl
} }
hash_map::RawEntryMut::Vacant(slot) => { hash_map::RawEntryMut::Vacant(slot) => {
log::dbg!("mod");
slot.insert(LookupEntry { nid: target, hash }, ()); slot.insert(LookupEntry { nid: target, hash }, ());
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap(); let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
self[prev].outputs.swap_remove(index); self[prev].outputs.swap_remove(index);
@ -804,13 +804,6 @@ impl Nodes {
} }
} }
fn add_deps(&mut self, id: Nid, deps: &[Nid]) {
for &d in deps {
debug_assert_ne!(d, id);
self[d].outputs.push(id);
}
}
#[track_caller] #[track_caller]
fn unlock_remove(&mut self, id: Nid) -> bool { fn unlock_remove(&mut self, id: Nid) -> bool {
self[id].lock_rc -= 1; self[id].lock_rc -= 1;
@ -909,15 +902,151 @@ impl Nodes {
for (i, node) in self.iter() { for (i, node) in self.iter() {
let color = if self.is_cfg(i) { "yellow" } else { "white" }; let color = if self.is_cfg(i) { "yellow" } else { "white" };
writeln!(out, "node{i}[label=\"{}\" color={color}]", node.kind)?; writeln!(out, "node{i}[label=\"{}\" color={color}]", node.kind)?;
for &o in &node.outputs { for (j, &o) in node.outputs.iter().enumerate() {
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "black" }; let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" };
writeln!(out, "node{o} -> node{i}[color={color}]",)?; 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}]",
)?;
} }
} }
Ok(()) Ok(())
} }
#[allow(clippy::format_in_format_args)]
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result {
if !self.visited.set(node as _) {
return Ok(());
}
write!(out, " {node:>2}: ")?;
match self[node].kind {
Kind::Start => unreachable!(),
Kind::End => unreachable!(),
Kind::If => write!(out, " if: "),
Kind::Region => unreachable!(),
Kind::Loop => unreachable!(),
Kind::Return => write!(out, " ret: "),
Kind::CInt { value } => write!(out, "cint: #{value:<4}"),
Kind::Phi => write!(out, " phi: "),
Kind::Tuple { index } => write!(out, " arg: {index:<5}"),
Kind::BinOp { op } => {
write!(out, "{:>4}: ", op.name())
}
Kind::Call { func } => {
write!(out, "call: {func} {}", self[node].depth)
}
}?;
writeln!(
out,
" {:<14} {}",
format!("{:?}", self[node].inputs),
format!("{:?}", self[node].outputs)
)
}
fn basic_blocks_low(&mut self, out: &mut String, mut node: Nid) -> std::fmt::Result {
while self.visited.set(node as _) {
match dbg!(self[node].kind) {
Kind::Start => {
writeln!(out, "start: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone() {
if self[o].kind == (Kind::Tuple { index: 0 }) {
cfg_index = o;
continue;
}
self.basic_blocks_instr(out, o)?;
}
node = cfg_index;
}
Kind::End => break,
Kind::If => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
self.basic_blocks_low(out, self[node].outputs[0])?;
node = self[node].outputs[1];
}
Kind::Region => {
let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone().into_iter() {
if self.is_cfg(o) {
cfg_index = o;
continue;
}
self.basic_blocks_instr(out, o)?;
}
node = cfg_index;
}
Kind::Loop => {
writeln!(out, "loop{node} {}", self[node].depth)?;
let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone().into_iter() {
if self.is_cfg(o) {
cfg_index = o;
continue;
}
self.basic_blocks_instr(out, o)?;
}
node = cfg_index;
}
Kind::Return => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
node = self[node].outputs[0];
}
Kind::CInt { .. } => unreachable!(),
Kind::Phi => unreachable!(),
Kind::Tuple { .. } => {
writeln!(out, "b{node}: {}", self[node].depth)?;
let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone().into_iter() {
if self.is_cfg(o) {
cfg_index = o;
continue;
}
self.basic_blocks_instr(out, o)?;
}
if !self[cfg_index].kind.ends_basic_block()
&& !matches!(self[cfg_index].kind, Kind::Call { .. })
{
writeln!(out, " goto: {cfg_index}")?;
}
node = cfg_index;
}
Kind::BinOp { .. } => unreachable!(),
Kind::Call { .. } => {
self.visited.unset(node as _);
self.basic_blocks_instr(out, node)?;
let mut cfg_index = Nid::MAX;
for o in self[node].outputs.clone().into_iter() {
if self.is_cfg(o) {
cfg_index = o;
continue;
}
if self[o].inputs[0] == node {
self.basic_blocks_instr(out, o)?;
}
}
node = cfg_index;
}
}
}
Ok(())
}
fn basic_blocks(&mut self) {
let mut out = String::new();
self.visited.clear(self.values.len());
self.basic_blocks_low(&mut out, 0).unwrap();
println!("{out}");
}
fn graphviz(&self) { fn graphviz(&self) {
let out = &mut String::new(); let out = &mut String::new();
_ = self.graphviz_low(out); _ = self.graphviz_low(out);
@ -925,17 +1054,7 @@ impl Nodes {
} }
fn is_cfg(&self, o: Nid) -> bool { fn is_cfg(&self, o: Nid) -> bool {
matches!( self[o].kind.is_cfg()
self[o].kind,
Kind::Start
| Kind::End
| Kind::Return
| Kind::Tuple { .. }
| Kind::Call { .. }
| Kind::If
| Kind::Region
| Kind::Loop
)
} }
fn check_final_integrity(&self) { fn check_final_integrity(&self) {
@ -1082,8 +1201,30 @@ pub enum Kind {
} }
impl Kind { impl Kind {
fn disc(&self) -> u8 { fn is_pinned(&self) -> bool {
unsafe { *(self as *const _ as *const u8) } self.is_cfg() || matches!(self, Kind::Phi)
}
fn is_cfg(&self) -> bool {
matches!(
self,
Kind::Start
| Kind::End
| Kind::Return
| Kind::Tuple { .. }
| Kind::Call { .. }
| Kind::If
| Kind::Region
| Kind::Loop
)
}
fn ends_basic_block(&self) -> bool {
matches!(self, Kind::Return | Kind::If | Kind::End)
}
fn starts_basic_block(&self) -> bool {
matches!(self, Kind::Start | Kind::End | Kind::Tuple { .. } | Kind::Region | Kind::Loop)
} }
} }
@ -1933,6 +2074,8 @@ impl Codegen {
return Some(self.ci.end); return Some(self.ci.end);
}; };
self.make_func_reachable(func);
let fuc = &self.tys.funcs[func as usize]; let fuc = &self.tys.funcs[func as usize];
let sig = fuc.sig.expect("TODO: generic functions"); let sig = fuc.sig.expect("TODO: generic functions");
let ast = self.files[fuc.file as usize].clone(); let ast = self.files[fuc.file as usize].clone();
@ -2107,7 +2250,7 @@ impl Codegen {
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]); self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]);
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
@ -2143,7 +2286,11 @@ impl Codegen {
if self.errors.borrow().is_empty() { if self.errors.borrow().is_empty() {
self.gcm(); self.gcm();
self.ci.nodes.graphviz(); //self.ci.nodes.graphviz();
log::inf!("{id} {name}: ");
self.ci.nodes.basic_blocks();
return;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
@ -2470,7 +2617,6 @@ impl Codegen {
.relocs .relocs
.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc }); .push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc });
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
self.make_func_reachable(func);
self.ci.call_count -= 1; self.ci.call_count -= 1;
@ -2512,17 +2658,13 @@ impl Codegen {
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);
let signed = self.ci.nodes[left].ty.is_signed(); let Some((op, swpd)) =
let op = match op { Self::cond_op(op, self.ci.nodes[left].ty.is_signed())
TokenKind::Le if signed => instrs::jgts, else {
TokenKind::Le => instrs::jgtu, break 'optimize_cond;
TokenKind::Lt if signed => instrs::jlts,
TokenKind::Lt => instrs::jltu,
TokenKind::Eq => instrs::jne,
TokenKind::Ne => instrs::jeq,
_ => break 'optimize_cond,
}; };
swapped = swpd;
self.emit_expr_consume(left); self.emit_expr_consume(left);
self.emit_expr_consume(right); self.emit_expr_consume(right);
@ -2741,7 +2883,9 @@ impl Codegen {
Kind::BinOp { op } => { Kind::BinOp { op } => {
_ = self.lazy_init(expr); _ = self.lazy_init(expr);
let ty = self.tof(expr); let ty = self.tof(expr);
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::CInt { value } = self.ci.nodes[right].kind if let Kind::CInt { value } = self.ci.nodes[right].kind
@ -2831,6 +2975,25 @@ impl Codegen {
Some(ops[size.ilog2() as usize]) Some(ops[size.ilog2() as usize])
} }
#[allow(clippy::type_complexity)]
fn cond_op(
op: TokenKind,
signed: bool,
) -> Option<(fn(u8, u8, i16) -> (usize, [u8; instrs::MAX_SIZE]), bool)> {
Some((
match op {
TokenKind::Le if signed => instrs::jgts,
TokenKind::Le => instrs::jgtu,
TokenKind::Lt if signed => instrs::jlts,
TokenKind::Lt => instrs::jltu,
TokenKind::Eq => instrs::jne,
TokenKind::Ne => instrs::jeq,
_ => return None,
},
matches!(op, TokenKind::Lt | TokenKind::Gt),
))
}
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn math_op( fn math_op(
op: TokenKind, op: TokenKind,
@ -2887,7 +3050,7 @@ impl Codegen {
match name.ok_or(lit_name) { match name.ok_or(lit_name) {
Ok(name) => { Ok(name) => {
let name = self.cfile().ident_str(name); let name = self.cfile().ident_str(name);
self.report(pos, format_args!("undefined indentifier: {name}")) self.report(pos, format_args!("idk indentifier: {name}"))
} }
Err("main") => self.report( Err("main") => self.report(
pos, pos,
@ -2897,7 +3060,7 @@ impl Codegen {
f.path f.path
), ),
), ),
Err(name) => self.report(pos, format_args!("undefined indentifier: {name}")), Err(name) => self.report(pos, format_args!("idk indentifier: {name}")),
} }
return ty::Kind::Builtin(ty::NEVER); return ty::Kind::Builtin(ty::NEVER);
}; };
@ -3093,7 +3256,105 @@ impl Codegen {
std::process::exit(1); std::process::exit(1);
} }
fn gcm(&mut self) {} fn gcm(&mut self) {
fn idepth(nodes: &mut Nodes, target: Nid) -> u32 {
if target == 0 {
return 0;
}
if nodes[target].depth == 0 {
let dm = idom(nodes, target);
nodes[target].depth = idepth(nodes, dm) + 1;
}
nodes[target].depth
}
fn idom(nodes: &mut Nodes, target: Nid) -> Nid {
match nodes[target].kind {
Kind::Start => 0,
Kind::End => unreachable!(),
Kind::Loop
| Kind::CInt { .. }
| Kind::BinOp { .. }
| Kind::Call { .. }
| Kind::Phi
| Kind::Tuple { .. }
| Kind::Return
| Kind::If => nodes[target].inputs[0],
Kind::Region => {
let &[mut lcfg, mut rcfg] = nodes[target].inputs.as_slice() else {
unreachable!()
};
while lcfg != rcfg {
let [ldepth, rdepth] = [idepth(nodes, lcfg), idepth(nodes, rcfg)];
if ldepth >= rdepth {
lcfg = idom(nodes, lcfg);
}
if ldepth <= rdepth {
rcfg = idom(nodes, rcfg);
}
}
lcfg
}
}
}
fn push_up(nodes: &mut Nodes, node: Nid) {
if !nodes.visited.set(node as _) {
return;
}
if nodes[node].kind.is_pinned() {
for i in 0..nodes[node].inputs.len() {
let i = nodes[node].inputs[i];
push_up(nodes, i);
}
} else {
let mut max = 0;
for i in 0..nodes[node].inputs.len() {
let i = nodes[node].inputs[i];
let is_call = matches!(nodes[i].kind, Kind::Call { .. });
if nodes.is_cfg(i) && !is_call {
continue;
}
push_up(nodes, i);
if idepth(nodes, i) > idepth(nodes, max) {
max = if is_call { i } else { idom(nodes, i) };
}
}
if max == 0 {
return;
}
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap();
nodes[0].outputs.remove(index);
nodes[node].inputs[0] = max;
debug_assert!(
!nodes[max].outputs.contains(&node)
|| matches!(nodes[max].kind, Kind::Call { .. }),
"{node} {:?} {max} {:?}",
nodes[node],
nodes[max]
);
nodes[max].outputs.push(node);
}
}
fn push_down(nodes: &mut Nodes, node: Nid) {
if !nodes.visited.set(node as _) {
return;
}
// TODO: handle memory nodes first
}
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
push_up(&mut self.ci.nodes, self.ci.end);
// TODO: handle infinte loops
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
}
} }
#[derive(Default)] #[derive(Default)]

View file

@ -1,6 +1,6 @@
main: main:
ADDI64 r254, r254, -72d ADDI64 r254, r254, -40d
ST r31, r254, 48a, 24h ST r31, r254, 24a, 16h
LI64 r32, 1d LI64 r32, 1d
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
LI64 r32, 2d LI64 r32, 2d
@ -8,13 +8,10 @@ main:
LI64 r32, 4d LI64 r32, 4d
ST r32, r254, 16a, 8h ST r32, r254, 16a, 8h
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
ADDI64 r33, r254, 24d CP r2, r32
BMC r32, r33, 24h
ADDI64 r33, r254, 24d
CP r2, r33
JAL r31, r0, :pass JAL r31, r0, :pass
LD r31, r254, 48a, 24h LD r31, r254, 24a, 16h
ADDI64 r254, r254, 72d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
pass: pass:
ADDI64 r254, r254, -40d ADDI64 r254, r254, -40d
@ -44,6 +41,6 @@ pass:
LD r31, r254, 0a, 40h LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 408 code size: 381
ret: 7 ret: 7
status: Ok(()) status: Ok(())

View file

@ -16,30 +16,27 @@ main:
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
str_len: str_len:
ADDI64 r254, r254, -40d ADDI64 r254, r254, -48d
ST r31, r254, 0a, 40h ST r31, r254, 0a, 48h
CP r32, r2 CP r32, r2
LI64 r33, 0d LI64 r33, 0d
2: CP r34, r32 2: CP r34, r32
CP r35, r0 CP r35, r0
LD r35, r34, 0a, 1h LD r35, r34, 0a, 1h
LI64 r34, 0d LI64 r36, 0d
CMPU r35, r35, r34 JNE r35, r36, :0
CMPUI r35, r35, 0d
NOT r35, r35
JEQ r35, r0, :0
JMP :1 JMP :1
0: CP r35, r33 0: CP r36, r33
ADDI64 r35, r35, 1d ADDI64 r36, r36, 1d
CP r33, r35 CP r33, r36
CP r35, r32 CP r36, r32
ADDI64 r35, r35, 1d ADDI64 r36, r36, 1d
CP r32, r35 CP r32, r36
JMP :2 JMP :2
1: CP r1, r33 1: CP r1, r33
LD r31, r254, 0a, 40h LD r31, r254, 0a, 48h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 48d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 303 code size: 285
ret: 16 ret: 16
status: Ok(()) status: Ok(())

View file

@ -1,6 +1,6 @@
main: main:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -44d
ST r31, r254, 24a, 24h ST r31, r254, 12a, 32h
LI64 r32, 255d LI64 r32, 255d
ST r32, r254, 0a, 1h ST r32, r254, 0a, 1h
LI64 r32, 0d LI64 r32, 0d
@ -13,52 +13,45 @@ main:
ST r32, r254, 4a, 4h ST r32, r254, 4a, 4h
LI64 r32, 2d LI64 r32, 2d
ST r32, r254, 8a, 4h ST r32, r254, 8a, 4h
ADDI64 r32, r254, 0d LI64 r32, 1d
ADDI64 r33, r254, 12d ADDI64 r33, r254, 4d
BMC r32, r33, 12h MULI64 r32, r32, 4d
LI64 r33, 1d ADD64 r33, r33, r32
ADDI64 r32, r254, 16d
MULI64 r33, r33, 4d
ADD64 r32, r32, r33
CP r33, r0
LD r33, r32, 0a, 4h
LI64 r32, 2d
CMPU r33, r33, r32
CMPUI r33, r33, 0d
JEQ r33, r0, :0
LI64 r1, 0d
JMP :1
0: ADDI64 r33, r254, 20d
ADDI64 r33, r33, -4d
CP r32, r0 CP r32, r0
LD r32, r33, 0a, 4h LD r32, r33, 0a, 4h
LI64 r34, 2d
JEQ r32, r34, :0
LI64 r1, 0d
JMP :1
0: ADDI64 r34, r254, 8d
ADDI64 r34, r34, -4d
CP r32, r0
LD r32, r34, 0a, 4h
LI64 r33, 0d LI64 r33, 0d
CMPU r32, r32, r33 JEQ r32, r33, :2
CMPUI r32, r32, 0d
JEQ r32, r0, :2
LI64 r1, 64d LI64 r1, 64d
JMP :1 JMP :1
2: CP r32, r0 2: CP r33, r0
LD r32, r254, 16a, 4h LD r33, r254, 4a, 4h
CP r33, r0 CP r32, r0
LD r33, r254, 20a, 4h LD r32, r254, 8a, 4h
ADD32 r32, r32, r33 ADD32 r33, r33, r32
CP r33, r0 CP r32, r0
LD r33, r254, 12a, 1h LD r32, r254, 0a, 1h
ADD32 r32, r32, r33 ADD32 r33, r33, r32
CP r33, r0 CP r32, r0
LD r33, r254, 13a, 1h LD r32, r254, 1a, 1h
ADD32 r32, r32, r33 ADD32 r33, r33, r32
CP r33, r0 CP r32, r0
LD r33, r254, 14a, 1h LD r32, r254, 2a, 1h
ADD32 r32, r32, r33 ADD32 r33, r33, r32
CP r33, r0 CP r32, r0
LD r33, r254, 15a, 1h LD r32, r254, 3a, 1h
ADD32 r32, r32, r33 ADD32 r33, r33, r32
CP r1, r32 CP r1, r33
1: LD r31, r254, 24a, 24h 1: LD r31, r254, 12a, 32h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 44d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 531 code size: 474
ret: 512 ret: 512
status: Ok(()) status: Ok(())

View file

@ -1,23 +1,20 @@
main: main:
ADDI64 r254, r254, -72d ADDI64 r254, r254, -48d
ST r31, r254, 48a, 24h ST r31, r254, 24a, 24h
ADDI64 r1, r254, 0d ADDI64 r1, r254, 0d
JAL r31, r0, :new JAL r31, r0, :new
ADDI64 r32, r254, 0d ADDI64 r32, r254, 0d
ADDI64 r33, r254, 24d CP r2, r32
BMC r32, r33, 24h
ADDI64 r33, r254, 24d
CP r2, r33
LI64 r3, 69d LI64 r3, 69d
JAL r31, r0, :push JAL r31, r0, :push
LD r33, r254, 24a, 8h LD r32, r254, 0a, 8h
LD r32, r33, 0a, 8h LD r33, r32, 0a, 8h
ADDI64 r33, r254, 24d ADDI64 r32, r254, 0d
CP r2, r33 CP r2, r32
JAL r31, r0, :deinit JAL r31, r0, :deinit
CP r1, r32 CP r1, r33
LD r31, r254, 48a, 24h LD r31, r254, 24a, 24h
ADDI64 r254, r254, 72d ADDI64 r254, r254, 48d
JALA r0, r31, 0a JALA r0, r31, 0a
deinit: deinit:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -24d
@ -56,16 +53,10 @@ push:
CP r33, r3 CP r33, r3
LD r34, r32, 8a, 8h LD r34, r32, 8a, 8h
LD r35, r32, 16a, 8h LD r35, r32, 16a, 8h
CMPU r34, r34, r35 JNE r34, r35, :0
CMPUI r34, r34, 0d LD r35, r32, 16a, 8h
NOT r34, r34 LI64 r34, 0d
JEQ r34, r0, :0 JNE r35, r34, :1
LD r34, r32, 16a, 8h
LI64 r35, 0d
CMPU r34, r34, r35
CMPUI r34, r34, 0d
NOT r34, r34
JEQ r34, r0, :1
LI64 r34, 1d LI64 r34, 1d
ST r34, r32, 16a, 8h ST r34, r32, 16a, 8h
JMP :2 JMP :2
@ -78,12 +69,8 @@ push:
LI64 r3, 8d LI64 r3, 8d
JAL r31, r0, :malloc JAL r31, r0, :malloc
CP r34, r1 CP r34, r1
CP r35, r34 LI64 r35, 0d
LI64 r36, 0d JNE r34, r35, :3
CMPU r35, r35, r36
CMPUI r35, r35, 0d
NOT r35, r35
JEQ r35, r0, :3
LI64 r1, 0d LI64 r1, 0d
JMP :4 JMP :4
3: LD r35, r32, 0a, 8h 3: LD r35, r32, 0a, 8h
@ -92,12 +79,7 @@ push:
LD r38, r32, 8a, 8h LD r38, r32, 8a, 8h
MULI64 r38, r38, 8d MULI64 r38, r38, 8d
ADD64 r37, r37, r38 ADD64 r37, r37, r38
7: CP r38, r35 7: JNE r35, r37, :5
CP r39, r37
CMPU r38, r38, r39
CMPUI r38, r38, 0d
NOT r38, r38
JEQ r38, r0, :5
JMP :6 JMP :6
5: CP r38, r36 5: CP r38, r36
CP r39, r35 CP r39, r35
@ -113,25 +95,23 @@ push:
JMP :7 JMP :7
6: LD r38, r32, 8a, 8h 6: LD r38, r32, 8a, 8h
LI64 r39, 0d LI64 r39, 0d
CMPU r38, r38, r39 JEQ r38, r39, :8
CMPUI r38, r38, 0d
JEQ r38, r0, :8
LD r2, r32, 0a, 8h LD r2, r32, 0a, 8h
LD r38, r32, 8a, 8h LD r39, r32, 8a, 8h
MULI64 r38, r38, 8d MULI64 r39, r39, 8d
CP r3, r38 CP r3, r39
LI64 r4, 8d LI64 r4, 8d
JAL r31, r0, :free JAL r31, r0, :free
8: ST r34, r32, 0a, 8h 8: ST r34, r32, 0a, 8h
0: LD r34, r32, 0a, 8h 0: LD r34, r32, 0a, 8h
LD r38, r32, 8a, 8h LD r39, r32, 8a, 8h
MULI64 r38, r38, 8d MULI64 r39, r39, 8d
ADD64 r34, r34, r38 ADD64 r34, r34, r39
CP r38, r34 CP r39, r34
ST r33, r38, 0a, 8h ST r33, r39, 0a, 8h
LD r38, r32, 8a, 8h LD r39, r32, 8a, 8h
ADDI64 r38, r38, 1d ADDI64 r39, r39, 1d
ST r38, r32, 8a, 8h ST r39, r32, 8a, 8h
CP r1, r34 CP r1, r34
4: LD r31, r254, 0a, 88h 4: LD r31, r254, 0a, 88h
ADDI64 r254, r254, 88d ADDI64 r254, r254, 88d
@ -162,6 +142,6 @@ new:
LD r31, r254, 0a, 24h LD r31, r254, 0a, 24h
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 1470 code size: 1347
ret: 69 ret: 69
status: Ok(()) status: Ok(())

View file

@ -0,0 +1,30 @@
main:
ADDI64 r254, r254, -160d
ST r31, r254, 128a, 32h
LI64 r32, 0d
2: CP r33, r32
LI64 r34, 128d
CMPS r33, r33, r34
CMPUI r33, r33, -1d
JEQ r33, r0, :0
JMP :1
0: ADDI64 r33, r254, 0d
CP r34, r32
ADD64 r33, r33, r34
LI64 r34, 69d
ST r34, r33, 0a, 1h
CP r33, r32
ADDI64 r33, r33, 1d
CP r32, r33
JMP :2
1: ADDI64 r33, r254, 0d
LI64 r34, 42d
ADD64 r33, r33, r34
CP r1, r0
LD r1, r33, 0a, 1h
LD r31, r254, 128a, 32h
ADDI64 r254, r254, 160d
JALA r0, r31, 0a
code size: 219
ret: 69
status: Ok(())

View file

@ -7,14 +7,11 @@ main:
ADDI64 r254, r254, 8d ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
fib: fib:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -24d
ST r31, r254, 0a, 32h ST r31, r254, 0a, 24h
CP r32, r2 CP r32, r2
CP r33, r32 LI64 r33, 2d
LI64 r34, 2d JGTS r32, r33, :0
CMPS r33, r33, r34
CMPUI r33, r33, 1d
JEQ r33, r0, :0
LI64 r1, 1d LI64 r1, 1d
JMP :1 JMP :1
0: CP r33, r32 0: CP r33, r32
@ -28,9 +25,9 @@ fib:
CP r32, r1 CP r32, r1
ADD64 r33, r33, r32 ADD64 r33, r33, r32
CP r1, r33 CP r1, r33
1: LD r31, r254, 0a, 32h 1: LD r31, r254, 0a, 24h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 252 code size: 234
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -116,23 +116,14 @@ rect_line:
LI64 r33, 0d LI64 r33, 0d
LI64 r34, 0d LI64 r34, 0d
LI64 r35, 0d LI64 r35, 0d
5: CP r36, r33 5: JNE r33, r32, :0
CP r37, r32
CMPS r36, r36, r37
CMPUI r36, r36, 0d
NOT r36, r36
JEQ r36, r0, :0
JMP :1 JMP :1
0: LD r34, r254, 8a, 8h 0: LD r34, r254, 8a, 8h
LD r35, r254, 0a, 8h LD r35, r254, 0a, 8h
4: CP r36, r34 4: LD r36, r254, 8a, 8h
LD r37, r254, 8a, 8h LD r37, r254, 16a, 8h
LD r38, r254, 16a, 8h ADD64 r36, r36, r37
ADD64 r37, r37, r38 JNE r34, r36, :2
CMPS r36, r36, r37
CMPUI r36, r36, 0d
NOT r36, r36
JEQ r36, r0, :2
JMP :3 JMP :3
2: LI64 r36, 1d 2: LI64 r36, 1d
LI64 r37, 10d LI64 r37, 10d
@ -179,6 +170,6 @@ line:
2: LD r31, r254, 48a, 32h 2: LD r31, r254, 48a, 32h
ADDI64 r254, r254, 80d ADDI64 r254, r254, 80d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 1521 code size: 1476
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -12,12 +12,8 @@ fib:
CP r32, r2 CP r32, r2
LI64 r33, 0d LI64 r33, 0d
LI64 r34, 1d LI64 r34, 1d
2: CP r35, r32 2: LI64 r35, 0d
LI64 r36, 0d JNE r32, r35, :0
CMPS r35, r35, r36
CMPUI r35, r35, 0d
NOT r35, r35
JEQ r35, r0, :0
JMP :1 JMP :1
0: CP r35, r33 0: CP r35, r33
CP r36, r34 CP r36, r34
@ -32,6 +28,6 @@ fib:
LD r31, r254, 0a, 48h LD r31, r254, 0a, 48h
ADDI64 r254, r254, 48d ADDI64 r254, r254, 48d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 248 code size: 227
ret: 55 ret: 55
status: Ok(()) status: Ok(())

View file

@ -26,12 +26,8 @@ fib_iter:
CP r32, r2 CP r32, r2
LI64 r33, 0d LI64 r33, 0d
LI64 r34, 1d LI64 r34, 1d
2: CP r35, r32 2: LI64 r35, 0d
LI64 r36, 0d JNE r32, r35, :0
CMPS r35, r35, r36
CMPUI r35, r35, 0d
NOT r35, r35
JEQ r35, r0, :0
JMP :1 JMP :1
0: CP r35, r33 0: CP r35, r33
CP r36, r34 CP r36, r34
@ -50,28 +46,25 @@ fib:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -32d
ST r31, r254, 0a, 32h ST r31, r254, 0a, 32h
CP r32, r2 CP r32, r2
LI64 r33, 2d
JLTS r32, r33, :0
CP r33, r32 CP r33, r32
LI64 r34, 2d
CMPS r33, r33, r34
CMPUI r33, r33, -1d
NOT r33, r33
JEQ r33, r0, :0
CP r1, r32
JMP :1
0: CP r33, r32
ADDI64 r33, r33, -1d ADDI64 r33, r33, -1d
CP r2, r33 CP r2, r33
JAL r31, r0, :fib JAL r31, r0, :fib
CP r33, r1 CP r33, r1
ADDI64 r32, r32, -2d CP r34, r32
CP r2, r32 ADDI64 r34, r34, -2d
CP r2, r34
JAL r31, r0, :fib JAL r31, r0, :fib
CP r32, r1 CP r34, r1
ADD64 r33, r33, r32 ADD64 r33, r33, r34
CP r1, r33 CP r1, r33
JMP :1
0: CP r1, r32
1: LD r31, r254, 0a, 32h 1: LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d ADDI64 r254, r254, 32d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 518 code size: 479
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,31 +1,25 @@
main: main:
ADDI64 r254, r254, -72d ADDI64 r254, r254, -48d
ST r31, r254, 48a, 24h ST r31, r254, 24a, 24h
LI64 r32, 4d LI64 r32, 4d
ST r32, r254, 24a, 8h ST r32, r254, 0a, 8h
LI64 r32, 1d LI64 r32, 1d
ST r32, r254, 32a, 8h ST r32, r254, 8a, 8h
LI64 r32, 3d LI64 r32, 3d
ST r32, r254, 40a, 8h ST r32, r254, 16a, 8h
ADDI64 r2, r254, 24d ADDI64 r2, r254, 0d
ADDI64 r1, r254, 0d ADDI64 r1, r254, 0d
JAL r31, r0, :odher_pass JAL r31, r0, :odher_pass
ADDI64 r32, r254, 0d LD r32, r254, 16a, 8h
ADDI64 r33, r254, 24d LI64 r33, 3d
BMC r32, r33, 24h JNE r32, r33, :0
LD r33, r254, 40a, 8h ADDI64 r33, r254, 0d
LI64 r32, 3d
CMPS r33, r33, r32
CMPUI r33, r33, 0d
NOT r33, r33
JEQ r33, r0, :0
ADDI64 r33, r254, 24d
CP r2, r33 CP r2, r33
JAL r31, r0, :pass JAL r31, r0, :pass
JMP :1 JMP :1
0: LI64 r1, 0d 0: LI64 r1, 0d
1: LD r31, r254, 48a, 24h 1: LD r31, r254, 24a, 24h
ADDI64 r254, r254, 72d ADDI64 r254, r254, 48d
JALA r0, r31, 0a JALA r0, r31, 0a
pass: pass:
ADDI64 r254, r254, -32d ADDI64 r254, r254, -32d
@ -49,6 +43,6 @@ odher_pass:
LD r31, r254, 0a, 40h LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 445 code size: 400
ret: 3 ret: 3
status: Ok(()) status: Ok(())

View file

@ -22,7 +22,7 @@ fib:
SUB64 r35, r32, r33 SUB64 r35, r32, r33
CP r2, r35 CP r2, r35
JAL r31, r0, :fib JAL r31, r0, :fib
ADD64 r1, r34, r1 ADD64 r1, r1, r34
1: LD r31, r254, 0a, 40h 1: LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -1,31 +1,4 @@
main: main:
ADDI64 r254, r254, -16d code size: 8
ST r31, r254, 0a, 16h ret: 0
LI64 r32, 10d status: Err(Unreachable)
CP r2, r32
JAL r31, r0, :fib
LD r31, r254, 0a, 16h
ADDI64 r254, r254, 16d
JALA r0, r31, 0a
fib:
ADDI64 r254, r254, -56d
ST r31, r254, 0a, 56h
CP r32, r2
CP r33, r32
LI64 r34, 0d
CP r1, r34
LI64 r35, 1d
CP r36, r35
2: JNE r33, r34, :0
JMP :1
0: SUB64 r33, r33, r35
ADD64 r37, r1, r36
CP r1, r36
CP r36, r37
JMP :2
1: LD r31, r254, 0a, 56h
ADDI64 r254, r254, 56d
JALA r0, r31, 0a
code size: 207
ret: 55
status: Ok(())

View file

@ -36,7 +36,7 @@ use {
pub struct Vm<Mem, const TIMER_QUOTIENT: usize> { pub struct Vm<Mem, const TIMER_QUOTIENT: usize> {
/// Holds 256 registers /// Holds 256 registers
/// ///
/// Writing to register 0 is considered undefined behaviour /// Writing to register 0 is considered idk behaviour
/// in terms of HoleyBytes program execution /// in terms of HoleyBytes program execution
pub registers: [Value; 256], pub registers: [Value; 256],

View file

@ -6,7 +6,7 @@ use crate::utils::static_assert;
/// ///
/// # Safety /// # Safety
/// Its variants have to be sound to byte-reinterpretate /// Its variants have to be sound to byte-reinterpretate
/// between each other. Otherwise the behaviour is undefined. /// between each other. Otherwise the behaviour is idk.
macro_rules! value_def { macro_rules! value_def {
($($ty:ident),* $(,)?) => { ($($ty:ident),* $(,)?) => {
/// HBVM register value /// HBVM register value

3
main.hb Normal file
View file

@ -0,0 +1,3 @@
main := fn(): int {
return 0;
}