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
#### comptime_pointers

View file

@ -8,7 +8,7 @@ use {
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
HashMap,
},
std::{collections::BTreeMap, fmt::Display, ops::Range, rc::Rc},
std::{collections::BTreeMap, fmt::Display, ops::Range, rc::Rc, u32},
};
type Offset = u32;
@ -688,6 +688,10 @@ impl Loc {
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 {
@ -702,6 +706,7 @@ impl Default for Loc {
}
}
#[derive(Clone, Copy)]
struct Loop {
var_count: u32,
offset: u32,
@ -710,6 +715,7 @@ struct Loop {
struct Variable {
id: Ident,
uses_left: u32,
value: Value,
}
@ -1419,7 +1425,9 @@ impl Codegen {
// TODO: we need to check if index is in bounds on debug builds
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)?;
_ = 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);
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.ci.regs.free(idx);
@ -1491,7 +1501,13 @@ impl Codegen {
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;
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 });
}
E::Directive { name: "TypeOf", args: [expr], .. } => {
let snap = self.output.snap();
let value = self.expr(expr).unwrap();
self.ci.free_loc(value.loc);
self.output.trunc(&snap);
Some(Value::ty(value.ty))
Some(Value::ty(self.infer_type(expr)))
}
E::Directive { name: "eca", args: [ret_ty, args @ ..], .. } => {
let ty = self.ty(ret_ty);
@ -1585,7 +1597,7 @@ impl Codegen {
let Some(ty) = ctx.ty else {
self.report(
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, .. } => {
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 } => {
literal = literal.trim_matches('"');
@ -1917,12 +1954,12 @@ impl Codegen {
return Some(Value { ty: sig.ret, loc });
}
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)) =
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);
let loc = match idfl::index(sym.flags) == index
var.uses_left -= 1;
let loc = match var.uses_left == 0
&& !self.ci.loops.last().is_some_and(|l| l.var_count > var_index as u32)
{
true => std::mem::take(&mut var.value.loc),
@ -1990,15 +2027,59 @@ impl Codegen {
},
loc: Loc::ct(value as u64),
}),
E::If { cond, then, else_, .. } => {
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
let reg = self.loc_to_reg(&cond.loc, 1);
let jump_offset = self.local_offset();
self.output.emit(jeq(reg.get(), 0, 0));
self.ci.free_loc(cond.loc);
self.ci.regs.free(reg);
E::If { cond, then, mut else_, .. } => {
#[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),
))
}
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 jump = self.local_offset() as i64 - jump_offset as i64;
@ -2196,9 +2277,8 @@ impl Codegen {
Some(match ctx.loc {
Some(dest) => {
let ty = ctx.ty.unwrap_or(value.ty);
self.store_typed(value.loc, dest, ty);
Value { ty, loc: Loc::ct(0) }
self.store_typed(value.loc, dest, value.ty);
Value { ty: value.ty, loc: Loc::ct(0) }
}
None => value,
})
@ -2236,7 +2316,11 @@ impl Codegen {
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);
@ -2266,6 +2350,38 @@ impl Codegen {
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 {
self.eval_const_low(expr, Some(ty.into())).0
}
@ -2321,11 +2437,15 @@ impl Codegen {
&& size <= 8 =>
{
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
}
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);
false
}
@ -2337,11 +2457,15 @@ impl Codegen {
match *pat {
Expr::Ident { id, .. } => {
let mut loc = self.make_loc_owned(right.loc, right.ty);
let sym = parser::find_symbol(&self.cfile().symbols, id);
if sym.flags & idfl::REFERENCED != 0 {
let sym = parser::find_symbol(&self.cfile().symbols, id).flags;
if sym & idfl::REFERENCED != 0 {
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, .. } => {
let ty::Kind::Struct(idx) = right.ty.expand() else {
@ -2553,9 +2677,13 @@ impl Codegen {
}
fn spill(&mut self, loc: Loc, size: Size) -> Loc {
let stack = Loc::stack(self.ci.stack.allocate(size));
self.store_sized(loc, &stack, size);
stack
if loc.is_ref() || !loc.is_stack() {
let stack = Loc::stack(self.ci.stack.allocate(size));
self.store_sized(loc, &stack, size);
stack
} else {
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);
// we drain these when linking
for srel in self.output.strings.iter_mut().filter(|s| !s.shifted) {
dbg!(&srel.range);
debug_assert!(
srel.range.end <= prev_data_len as u32,
"{} <= {}",
@ -2628,7 +2755,7 @@ impl Codegen {
self.ci.snap = self.output.snap();
let Expr::BinOp {
left: Expr::Ident { name, .. },
left: Expr::Ident { .. },
op: TokenKind::Decl,
right: &Expr::Closure { body, args, .. },
} = expr
@ -2636,20 +2763,22 @@ impl Codegen {
unreachable!("{expr}")
};
log::dbg!(name);
self.output.emit_prelude();
let mut parama = self.tys.parama(sig.ret);
let mut sig_args = sig.args.range();
for arg in args.iter() {
let ty = self.tys.args[sig_args.next().unwrap()];
let sym = parser::find_symbol(&ast.symbols, arg.id);
let loc = match sym.flags & idfl::COMPTIME != 0 {
let sym = parser::find_symbol(&ast.symbols, arg.id).flags;
let loc = match sym & idfl::COMPTIME != 0 {
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 {
@ -2980,6 +3109,7 @@ impl Codegen {
self.ci.vars.push(Variable {
id,
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_functions => README;
c_strings => README;
idk => README;
struct_patterns => README;
arrays => README;
struct_return_from_module_function => README;
@ -3562,7 +3693,7 @@ mod tests {
sort_something_viredly => README;
hex_octal_binary_literals => README;
comptime_min_reg_leak => README;
// structs_in_registers => README;
// structs_in_registers => README;
comptime_function_from_another_file => README;
inline => README;
inline_test => README;

View file

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

View file

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

View file

@ -15,12 +15,14 @@ use {
core::fmt,
std::{
cell::RefCell,
cmp,
collections::{hash_map, BTreeMap},
fmt::Display,
fmt::{Display, Write},
hash::{Hash as _, Hasher},
mem,
ops::{self, Range},
rc::Rc,
u32,
},
};
@ -58,6 +60,7 @@ impl BitSet {
self.data.resize(new_len, 0);
}
#[track_caller]
pub fn set(&mut self, idx: usize) -> bool {
let data_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;
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;
@ -532,15 +541,8 @@ impl Nodes {
) -> Nid {
let ty = ty.into();
let node = Node {
inputs: inps.into(),
kind,
color: 0,
depth: u32::MAX,
lock_rc: 0,
ty,
outputs: vec![],
};
let node =
Node { inputs: inps.into(), kind, color: 0, depth: 0, lock_rc: 0, ty, outputs: vec![] };
let mut lookup_meta = None;
if !node.is_lazy_phi() {
@ -689,14 +691,14 @@ impl Nodes {
let ty = self[target].ty;
if let (&K::CInt { value: a }, &K::CInt { value: b }) = (&self[lhs].kind, &self[rhs].kind) {
return Some(self.new_node(ty, K::CInt { value: op.apply(a, b) }, []));
return Some(self.new_node(ty, K::CInt { value: op.apply(a, b) }, [ctrl]));
}
if lhs == rhs {
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 => {
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]));
}
_ => {}
@ -724,7 +726,7 @@ impl Nodes {
&& let K::CInt { value: bv } = self[rhs].kind
{
// (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]));
}
@ -741,7 +743,7 @@ impl Nodes {
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
{
// 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]));
}
@ -786,14 +788,12 @@ impl Nodes {
);
match entry {
hash_map::RawEntryMut::Occupied(mut other) => {
log::dbg!("rplc");
let rpl = other.get_key_value().0.nid;
self[target].inputs[inp_index] = prev;
self.replace(target, rpl);
rpl
}
hash_map::RawEntryMut::Vacant(slot) => {
log::dbg!("mod");
slot.insert(LookupEntry { nid: target, hash }, ());
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
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]
fn unlock_remove(&mut self, id: Nid) -> bool {
self[id].lock_rc -= 1;
@ -909,15 +902,151 @@ impl Nodes {
for (i, node) in self.iter() {
let color = if self.is_cfg(i) { "yellow" } else { "white" };
writeln!(out, "node{i}[label=\"{}\" color={color}]", node.kind)?;
for &o in &node.outputs {
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "black" };
writeln!(out, "node{o} -> node{i}[color={color}]",)?;
for (j, &o) in node.outputs.iter().enumerate() {
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}]",
)?;
}
}
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) {
let out = &mut String::new();
_ = self.graphviz_low(out);
@ -925,17 +1054,7 @@ impl Nodes {
}
fn is_cfg(&self, o: Nid) -> bool {
matches!(
self[o].kind,
Kind::Start
| Kind::End
| Kind::Return
| Kind::Tuple { .. }
| Kind::Call { .. }
| Kind::If
| Kind::Region
| Kind::Loop
)
self[o].kind.is_cfg()
}
fn check_final_integrity(&self) {
@ -1082,8 +1201,30 @@ pub enum Kind {
}
impl Kind {
fn disc(&self) -> u8 {
unsafe { *(self as *const _ as *const u8) }
fn is_pinned(&self) -> bool {
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);
};
self.make_func_reachable(func);
let fuc = &self.tys.funcs[func as usize];
let sig = fuc.sig.expect("TODO: generic functions");
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]);
let Expr::BinOp {
left: Expr::Ident { .. },
left: Expr::Ident { name, .. },
op: TokenKind::Decl,
right: &Expr::Closure { body, args, .. },
} = expr
@ -2143,7 +2286,11 @@ impl Codegen {
if self.errors.borrow().is_empty() {
self.gcm();
self.ci.nodes.graphviz();
//self.ci.nodes.graphviz();
log::inf!("{id} {name}: ");
self.ci.nodes.basic_blocks();
return;
#[cfg(debug_assertions)]
{
@ -2470,7 +2617,6 @@ impl Codegen {
.relocs
.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc });
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
self.make_func_reachable(func);
self.ci.call_count -= 1;
@ -2512,17 +2658,13 @@ impl Codegen {
let &[_, left, right] = self.ci.nodes[cond].inputs.as_slice() else {
unreachable!()
};
swapped = matches!(op, TokenKind::Lt | TokenKind::Gt);
let signed = self.ci.nodes[left].ty.is_signed();
let op = 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,
_ => break 'optimize_cond,
let Some((op, swpd)) =
Self::cond_op(op, self.ci.nodes[left].ty.is_signed())
else {
break 'optimize_cond;
};
swapped = swpd;
self.emit_expr_consume(left);
self.emit_expr_consume(right);
@ -2741,7 +2883,9 @@ impl Codegen {
Kind::BinOp { op } => {
_ = self.lazy_init(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);
if let Kind::CInt { value } = self.ci.nodes[right].kind
@ -2831,6 +2975,25 @@ impl Codegen {
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)]
fn math_op(
op: TokenKind,
@ -2887,7 +3050,7 @@ impl Codegen {
match name.ok_or(lit_name) {
Ok(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(
pos,
@ -2897,7 +3060,7 @@ impl Codegen {
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);
};
@ -3093,7 +3256,105 @@ impl Codegen {
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)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,31 +1,4 @@
main:
ADDI64 r254, r254, -16d
ST r31, r254, 0a, 16h
LI64 r32, 10d
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(())
code size: 8
ret: 0
status: Err(Unreachable)

View file

@ -36,7 +36,7 @@ use {
pub struct Vm<Mem, const TIMER_QUOTIENT: usize> {
/// 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
pub registers: [Value; 256],

View file

@ -6,7 +6,7 @@ use crate::utils::static_assert;
///
/// # Safety
/// 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 {
($($ty:ident),* $(,)?) => {
/// HBVM register value

3
main.hb Normal file
View file

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