From 601625e43f7384c8f79680149d9511506c906f8f Mon Sep 17 00:00:00 2001 From: mlokr Date: Mon, 9 Sep 2024 19:36:53 +0200 Subject: [PATCH] fixing more bugs and also adding uninig memory and also optimizing cong jumps --- hblang/README.md | 13 + hblang/src/codegen.rs | 215 ++++++++-- hblang/src/lexer.rs | 36 +- hblang/src/parser.rs | 56 +-- hblang/src/son.rs | 375 +++++++++++++++--- hblang/tests/codegen_tests_arrays.txt | 15 +- hblang/tests/codegen_tests_c_strings.txt | 29 +- .../tests/codegen_tests_different_types.txt | 79 ++-- hblang/tests/codegen_tests_generic_types.txt | 80 ++-- hblang/tests/codegen_tests_idk.txt | 30 ++ hblang/tests/codegen_tests_if_statements.txt | 17 +- hblang/tests/codegen_tests_inline_test.txt | 21 +- hblang/tests/codegen_tests_loops.txt | 10 +- .../tests/codegen_tests_struct_patterns.txt | 31 +- hblang/tests/codegen_tests_structs.txt | 32 +- hblang/tests/son_tests_if_statements.txt | 2 +- hblang/tests/son_tests_loops.txt | 33 +- hbvm/src/lib.rs | 2 +- hbvm/src/value.rs | 2 +- main.hb | 3 + 20 files changed, 721 insertions(+), 360 deletions(-) create mode 100644 hblang/tests/codegen_tests_idk.txt create mode 100644 main.hb diff --git a/hblang/README.md b/hblang/README.md index 5619078..accc9ce 100644 --- a/hblang/README.md +++ b/hblang/README.md @@ -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 diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 6600d5b..a4faeb5 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -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 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 to cast to is unknown, use `@as(, @bitcast())`", ); }; @@ -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(, 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) -> 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; diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index 03406ea..54cff14 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -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 { 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 = ".(", diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index 809c913..f9da066 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -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, diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 8d4eb5a..510a743 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -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)] diff --git a/hblang/tests/codegen_tests_arrays.txt b/hblang/tests/codegen_tests_arrays.txt index c8b2e09..a543182 100644 --- a/hblang/tests/codegen_tests_arrays.txt +++ b/hblang/tests/codegen_tests_arrays.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_c_strings.txt b/hblang/tests/codegen_tests_c_strings.txt index 82a34a5..d8e2346 100644 --- a/hblang/tests/codegen_tests_c_strings.txt +++ b/hblang/tests/codegen_tests_c_strings.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_different_types.txt b/hblang/tests/codegen_tests_different_types.txt index 05bd4ea..d1668ad 100644 --- a/hblang/tests/codegen_tests_different_types.txt +++ b/hblang/tests/codegen_tests_different_types.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_generic_types.txt b/hblang/tests/codegen_tests_generic_types.txt index e5b747c..156a337 100644 --- a/hblang/tests/codegen_tests_generic_types.txt +++ b/hblang/tests/codegen_tests_generic_types.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_idk.txt b/hblang/tests/codegen_tests_idk.txt new file mode 100644 index 0000000..b7d25d2 --- /dev/null +++ b/hblang/tests/codegen_tests_idk.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_if_statements.txt b/hblang/tests/codegen_tests_if_statements.txt index 1b9a128..040814e 100644 --- a/hblang/tests/codegen_tests_if_statements.txt +++ b/hblang/tests/codegen_tests_if_statements.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_inline_test.txt b/hblang/tests/codegen_tests_inline_test.txt index 8234e49..a12d1df 100644 --- a/hblang/tests/codegen_tests_inline_test.txt +++ b/hblang/tests/codegen_tests_inline_test.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_loops.txt b/hblang/tests/codegen_tests_loops.txt index c2c67d4..4a9bf49 100644 --- a/hblang/tests/codegen_tests_loops.txt +++ b/hblang/tests/codegen_tests_loops.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_struct_patterns.txt b/hblang/tests/codegen_tests_struct_patterns.txt index 0f12e3f..21a0402 100644 --- a/hblang/tests/codegen_tests_struct_patterns.txt +++ b/hblang/tests/codegen_tests_struct_patterns.txt @@ -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(()) diff --git a/hblang/tests/codegen_tests_structs.txt b/hblang/tests/codegen_tests_structs.txt index 6be0f57..3058a99 100644 --- a/hblang/tests/codegen_tests_structs.txt +++ b/hblang/tests/codegen_tests_structs.txt @@ -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(()) diff --git a/hblang/tests/son_tests_if_statements.txt b/hblang/tests/son_tests_if_statements.txt index b522299..45520c0 100644 --- a/hblang/tests/son_tests_if_statements.txt +++ b/hblang/tests/son_tests_if_statements.txt @@ -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 diff --git a/hblang/tests/son_tests_loops.txt b/hblang/tests/son_tests_loops.txt index 4bc890d..01a87a2 100644 --- a/hblang/tests/son_tests_loops.txt +++ b/hblang/tests/son_tests_loops.txt @@ -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) diff --git a/hbvm/src/lib.rs b/hbvm/src/lib.rs index 0527c73..979fea1 100644 --- a/hbvm/src/lib.rs +++ b/hbvm/src/lib.rs @@ -36,7 +36,7 @@ use { pub struct Vm { /// 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], diff --git a/hbvm/src/value.rs b/hbvm/src/value.rs index b3d24e8..4becee4 100644 --- a/hbvm/src/value.rs +++ b/hbvm/src/value.rs @@ -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 diff --git a/main.hb b/main.hb new file mode 100644 index 0000000..0506b7b --- /dev/null +++ b/main.hb @@ -0,0 +1,3 @@ +main := fn(): int { + return 0; +}