From b2254e982079760ca9e2452a1ff6c4079684622f Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Tue, 1 Oct 2024 17:43:15 +0200 Subject: [PATCH] making compiler a bit smarter about evaluating types (more shortcuts) --- hblang/src/codegen.rs | 84 ++++++++++++++++++++++------------ hblang/src/lib.rs | 104 ++++++++++++++++++++++++++---------------- hblang/src/parser.rs | 45 +++++++++--------- hblang/src/son.rs | 9 +++- 4 files changed, 149 insertions(+), 93 deletions(-) diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index 396381b..fb58703 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -736,9 +736,17 @@ impl Codegen { fn build_struct( &mut self, file: FileId, + pos: Option, explicit_alignment: Option, fields: &[CommentOr], ) -> ty::Struct { + let sym = pos.map(|pos| SymKey::Struct(file, pos)); + if let Some(ref sym) = sym + && let Some(&ty) = self.tys.syms.get(sym) + { + return ty.expand().inner(); + } + let prev_tmp = self.tys.fields_tmp.len(); for sf in fields.iter().filter_map(CommentOr::or) { let f = Field { name: self.tys.field_names.intern(sf.name), ty: self.ty(&sf.ty) }; @@ -752,6 +760,12 @@ impl Codegen { }); self.tys.fields.extend(self.tys.fields_tmp.drain(prev_tmp..)); + if let Some(sym) = sym { + self.tys + .syms + .insert(sym, ty::Kind::Struct(self.tys.structs.len() as u32 - 1).compress()); + } + self.tys.structs.len() as u32 - 1 } @@ -759,11 +773,12 @@ impl Codegen { use {Expr as E, TokenKind as T}; let value = match *expr { E::Mod { id, .. } => Some(Value::ty(ty::Kind::Module(id).compress())), - E::Struct { captured, packed, fields, .. } => { + E::Struct { captured, packed, fields, pos, .. } => { if captured.is_empty() { Some(Value::ty( ty::Kind::Struct(self.build_struct( self.ci.file, + Some(pos), packed.then_some(1), fields, )) @@ -902,7 +917,7 @@ impl Codegen { self.ci.file = prev_file; self.ci.ret = prev_ret; - let mut vars = std::mem::take(&mut self.ci.vars); + let mut vars = core::mem::take(&mut self.ci.vars); for var in vars.drain(scope..) { self.ci.free_loc(var.value.loc); } @@ -1204,7 +1219,7 @@ impl Codegen { ty::Kind::Builtin(ty::TYPE) => { self.ci.free_loc(tal.loc); self.ci.revert(checkpoint); - match ty::Kind::from_ty(self.ty(target)) { + match self.ty(target).expand() { ty::Kind::Module(idx) => { match self.find_or_declare(target.pos(), idx, Err(field), "") { ty::Kind::Global(idx) => self.handle_global(idx), @@ -1393,17 +1408,12 @@ impl Codegen { let loc = var.value.loc.as_ref(); Some(Value { ty: self.ci.vars[var_index].value.ty, loc }) } - E::Ident { id, name, .. } => match self - .tys - .syms - .get(&SymKey { ident: id, file: self.ci.file }) - .copied() - .map(ty::Kind::from_ty) - .unwrap_or_else(|| self.find_or_declare(ident::pos(id), self.ci.file, Ok(id), name)) - { - ty::Kind::Global(id) => self.handle_global(id), - tk => Some(Value::ty(tk.compress())), - }, + E::Ident { id, name, .. } => { + match self.find_or_declare(ident::pos(id), self.ci.file, Ok(id), name) { + ty::Kind::Global(id) => self.handle_global(id), + tk => Some(Value::ty(tk.compress())), + } + } E::Return { pos, val, .. } => { let size = self.ci.ret.map_or(17, |ty| self.tys.size_of(ty)); let loc = match size { @@ -1767,7 +1777,7 @@ impl Codegen { let args = self.pack_args(pos, arg_base); let ret = self.ty(ret); - let sym = SymKey { file: !args.repr(), ident: ty::Kind::Func(*func).compress().repr() }; + let sym = SymKey::FuncInst(*func, args); let ct = || { let func_id = self.tys.funcs.len(); let fuc = &self.tys.funcs[*func as usize]; @@ -2125,7 +2135,7 @@ impl Codegen { self.report(body.pos(), "expected all paths in the fucntion to return"); } - let mut vars = std::mem::take(&mut self.ci.vars); + let mut vars = core::mem::take(&mut self.ci.vars); for var in vars.drain(..) { self.ci.free_loc(var.value.loc); } @@ -2350,9 +2360,18 @@ impl Codegen { } fn ty(&mut self, expr: &Expr) -> ty::Id { - self.tys - .ty(self.ci.file, expr, &self.files) - .unwrap_or_else(|| ty::Id::from(self.eval_const(expr, ty::TYPE))) + let ty = self.tys.ty(self.ci.file, expr, &self.files); + let evaled_ty = ty::Id::from(self.eval_const(expr, ty::TYPE)); + if let Some(ty) = ty { + debug_assert_eq!( + ty, + evaled_ty, + "{} {}", + self.ty_display(ty), + self.ty_display(evaled_ty) + ); + } + evaled_ty } fn read_trap(addr: u64) -> Option<&'static trap::Trap> { @@ -2395,15 +2414,19 @@ impl Codegen { }); } - let stru = - ty::Kind::Struct(self.build_struct(self.ci.file, packed.then_some(1), fields)) - .compress(); + let stru = ty::Kind::Struct(self.build_struct( + self.ci.file, + packed.then_some(1), + None, + fields, + )) + .compress(); self.ci.vars.truncate(prev_len); self.ct.vm.write_reg(1, stru.repr() as u64); debug_assert_ne!(stru.expand().inner(), 1); } trap::Trap::MomizedCall(trap::MomizedCall { func }) => { - let sym = SymKey { file: u32::MAX, ident: ty::Kind::Func(func).compress().repr() }; + let sym = SymKey::MomizedCall(func); if let Some(&ty) = self.tys.syms.get(&sym) { self.ct.vm.write_reg(1, ty.repr()); } else { @@ -2426,6 +2449,10 @@ impl Codegen { lit_name: &str, ) -> ty::Kind { log::trace!("find_or_declare: {lit_name} {file}"); + if let Some(ty) = self.tys.find_type(file, name, &self.files) { + return ty.expand(); + } + let f = self.files[file as usize].clone(); let Some((expr, ident)) = f.find_decl(name) else { match name { @@ -2435,7 +2462,8 @@ impl Codegen { } }; - if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) { + let key = SymKey::Decl(file, ident); + if let Some(existing) = self.tys.syms.get(&key) { if let ty::Kind::Func(id) = existing.expand() && let func = &mut self.tys.funcs[id as usize] && let Err(idx) = task::unpack(func.offset) @@ -2517,7 +2545,7 @@ impl Codegen { e => unimplemented!("{e:#?}"), }; self.ci.file = prev_file; - self.tys.syms.insert(SymKey { ident, file }, sym.compress()); + self.tys.syms.insert(key, sym.compress()); sym } @@ -2552,7 +2580,7 @@ impl Codegen { self.ci.free_loc(ret.loc); - Global { ty: ret.ty, file, name, data, ..Default::default() } + Global { ty: ret.ty, file, name, data, ast: ExprRef::new(expr), ..Default::default() } } fn ct_eval( @@ -2579,8 +2607,8 @@ impl Codegen { let last_fn = self.tys.funcs.len(); self.tys.funcs.push(Default::default()); - self.tys.funcs[last_fn].code = std::mem::take(&mut self.ci.code); - self.tys.funcs[last_fn].relocs = std::mem::take(&mut self.ci.relocs); + self.tys.funcs[last_fn].code = core::mem::take(&mut self.ci.code); + self.tys.funcs[last_fn].relocs = core::mem::take(&mut self.ci.relocs); if is_on_stack { let size = diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index 2e6e0ee..d10598e 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -31,12 +31,12 @@ use { self::{ ident::Ident, lexer::TokenKind, - parser::{CommentOr, Expr, ExprRef, FileId}, + parser::{CommentOr, Expr, ExprRef, FileId, Pos}, son::reg, ty::ArrayLen, }, alloc::{collections::BTreeMap, string::String, vec::Vec}, - core::{cell::Cell, fmt::Display, hash::BuildHasher, ops::Range}, + core::{cell::Cell, fmt::Display, hash::BuildHasher, ops::Range, usize}, hashbrown::hash_map, hbbytecode as instrs, }; @@ -124,7 +124,7 @@ mod ty { lexer::TokenKind, parser::{self}, }, - core::{num::NonZeroU32, ops::Range}, + core::{num::NonZeroU32, ops::Range, usize}, }; pub type ArrayLen = u32; @@ -137,7 +137,7 @@ mod ty { pub type Module = u32; pub type Slice = u32; - #[derive(Clone, Copy)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct Tuple(pub u32); impl Tuple { @@ -384,7 +384,7 @@ mod ty { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { use Kind as TK; match TK::from_ty(self.ty) { - TK::Module(idx) => write!(f, "module{}", idx), + TK::Module(idx) => write!(f, "@use({:?})[{}]", self.files[idx as usize].path, idx), TK::Builtin(ty) => write!(f, "{}", to_str(ty)), TK::Ptr(ty) => { write!(f, "^{}", self.rety(self.tys.ptrs[ty as usize].base)) @@ -443,15 +443,14 @@ fn emit(out: &mut Vec, (len, instr): EncodedInstr) { } #[derive(PartialEq, Eq, Hash, Debug)] -struct SymKey { - file: u32, - ident: u32, -} - -impl SymKey { - pub fn pointer_to(ty: ty::Id) -> Self { - Self { file: u32::MAX, ident: ty.repr() } - } +enum SymKey { + Pointer(ty::Id), + Struct(FileId, Pos), + FuncInst(ty::Func, ty::Tuple), + MomizedCall(ty::Func), + Decl(FileId, Ident), + Slice(ty::Id), + Array(ty::Id, ArrayLen), } #[derive(Clone, Copy)] @@ -492,6 +491,7 @@ struct Global { file: FileId, name: Ident, ty: ty::Id, + ast: ExprRef, offset: Offset, data: Vec, } @@ -502,6 +502,7 @@ impl Default for Global { ty: Default::default(), offset: u32::MAX, data: Default::default(), + ast: ExprRef::default(), file: u32::MAX, name: u32::MAX, } @@ -690,35 +691,68 @@ impl Types { &self.fields[self.struct_field_range(strct)] } + fn find_type( + &mut self, + file: FileId, + id: Result, + files: &[parser::Ast], + ) -> Option { + if let Ok(id) = id + && let Some(&ty) = self.syms.get(&SymKey::Decl(file, id)) + { + if let ty::Kind::Global(g) = ty.expand() { + let g = &self.globals[g as usize]; + if g.ty == ty::Id::TYPE { + return Some(ty::Id::from( + u32::from_ne_bytes(*g.data.first_chunk().unwrap()) as u64 + )); + } + } + + return Some(ty); + } + + let f = &files[file as usize]; + let (Expr::BinOp { left, right, .. }, name) = f.find_decl(id)? else { unreachable!() }; + + let ty = left + .find_pattern_path(name, right, |right| self.ty(file, right, files)) + .unwrap_or_else(|_| unreachable!())?; + if let ty::Kind::Struct(s) = ty.expand() { + self.structs[s as usize].name = name; + } + + self.syms.insert(SymKey::Decl(file, name), ty); + Some(ty) + } + /// returns none if comptime eval is required fn ty(&mut self, file: FileId, expr: &Expr, files: &[parser::Ast]) -> Option { Some(match *expr { + Expr::Mod { id, .. } => ty::Kind::Module(id).compress(), Expr::UnOp { op: TokenKind::Xor, val, .. } => { let base = self.ty(file, val, files)?; self.make_ptr(base) } Expr::Ident { id, .. } if ident::is_null(id) => id.into(), - Expr::Ident { id, .. } => { - let f = &files[file as usize]; - let (Expr::BinOp { right, .. }, name) = f.find_decl(Ok(id))? else { - unreachable!() + Expr::Ident { id, .. } => self.find_type(file, Ok(id), files)?, + Expr::Field { target, name, .. } => { + let ty::Kind::Module(file) = self.ty(file, target, files)?.expand() else { + return None; }; - let ty = self.ty(file, right, files)?; - if let ty::Kind::Struct(s) = ty.expand() { - self.structs[s as usize].name = name; - } - ty + + self.find_type(file, Err(name), files)? } Expr::Slice { size: None, item, .. } => { let ty = self.ty(file, item, files)?; self.make_array(ty, ArrayLen::MAX) } - //Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => { - // let ty = self.ty(file, item, files)?; - // self.make_array(ty, value as _) - //} + Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => { + let ty = self.ty(file, item, files)?; + self.make_array(ty, value as _) + } Expr::Struct { pos, fields, packed, .. } => { - let sym = SymKey { file, ident: pos }; + let sym = SymKey::Struct(file, pos); if let Some(&ty) = self.syms.get(&sym) { return Some(ty); } @@ -875,10 +909,8 @@ impl Types { } fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr { - let id = SymKey::pointer_to(base); - self.syms - .entry(id) + .entry(SymKey::Pointer(base)) .or_insert_with(|| { self.ptrs.push(Ptr { base }); ty::Kind::Ptr(self.ptrs.len() as u32 - 1).compress() @@ -892,16 +924,8 @@ impl Types { } fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice { - let id = SymKey { - file: match len { - ArrayLen::MAX => ArrayLen::MAX - 1, - len => ArrayLen::MAX - len - 2, - }, - ident: ty.repr(), - }; - self.syms - .entry(id) + .entry(SymKey::Array(ty, len)) .or_insert_with(|| { self.arrays.push(Array { ty, len }); ty::Kind::Slice(self.arrays.len() as u32 - 1).compress() diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index 4fe0584..7888543 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -7,12 +7,12 @@ use { core::{ cell::UnsafeCell, fmt::{self}, + intrinsics::unlikely, marker::PhantomData, ops::Deref, ptr::NonNull, sync::atomic::AtomicUsize, }, - std::intrinsics::unlikely, }; pub type Pos = u32; @@ -54,6 +54,7 @@ pub struct Symbol { struct ScopeIdent { ident: Ident, declared: bool, + ordered: bool, flags: IdentFlags, } @@ -195,7 +196,9 @@ impl<'a, 'b> Parser<'a, 'b> { fn declare_rec(&mut self, expr: &Expr, top_level: bool) { match *expr { - Expr::Ident { pos, id, is_first, .. } => self.declare(pos, id, is_first || top_level), + Expr::Ident { pos, id, is_first, .. } => { + self.declare(pos, id, !top_level, is_first || top_level) + } Expr::Ctor { fields, .. } => { for CtorField { value, .. } in fields { self.declare_rec(value, top_level) @@ -205,7 +208,7 @@ impl<'a, 'b> Parser<'a, 'b> { } } - fn declare(&mut self, pos: Pos, id: Ident, valid_order: bool) { + fn declare(&mut self, pos: Pos, id: Ident, ordered: bool, valid_order: bool) { if !valid_order { self.report( pos, @@ -223,6 +226,8 @@ impl<'a, 'b> Parser<'a, 'b> { format_args!("redeclaration of identifier: {}", self.lexer.slice(ident::range(id))), ) } + + self.idents[index].ordered = ordered; } fn resolve_ident(&mut self, token: Token) -> (Ident, bool) { @@ -242,13 +247,18 @@ impl<'a, 'b> Parser<'a, 'b> { Some((i, elem)) => (i, elem, false), None => { let id = ident::new(token.start, name.len() as _); - self.idents.push(ScopeIdent { ident: id, declared: false, flags: 0 }); + self.idents.push(ScopeIdent { + ident: id, + declared: false, + ordered: false, + flags: 0, + }); (self.idents.len() - 1, self.idents.last_mut().unwrap(), true) } }; id.flags |= idfl::COMPTIME * is_ct as u32; - if id.declared && self.ns_bound > i { + if id.declared && id.ordered && self.ns_bound > i { id.flags |= idfl::COMPTIME; self.captured.push(id.ident); } @@ -374,7 +384,7 @@ impl<'a, 'b> Parser<'a, 'b> { self.collect_list(T::Comma, T::RParen, |s| { let name = s.advance_ident(); let (id, _) = s.resolve_ident(name); - s.declare(name.start, id, true); + s.declare(name.start, id, true, true); s.expect_advance(T::Colon); Arg { pos: name.start, @@ -839,17 +849,14 @@ impl<'a> Expr<'a> { } } - pub fn find_pattern_path( + pub fn find_pattern_path T>( &self, ident: Ident, target: &Expr, mut with_final: F, - ) -> Result<(), F> { + ) -> Result { match *self { - Self::Ident { id, .. } if id == ident => { - with_final(target); - Ok(()) - } + Self::Ident { id, .. } if id == ident => Ok(with_final(target)), Self::Ctor { fields, .. } => { for &CtorField { name, value, pos } in fields { match value.find_pattern_path( @@ -857,7 +864,7 @@ impl<'a> Expr<'a> { &Expr::Field { pos, target, name }, with_final, ) { - Ok(()) => return Ok(()), + Ok(value) => return Ok(value), Err(e) => with_final = e, } } @@ -1457,7 +1464,7 @@ impl StackAlloc { unsafe fn push(&mut self, _view: &mut StackAllocView, value: T) { if unlikely(self.len + core::mem::size_of::() > self.cap) { - let next_cap = self.cap.max(16 * 32).max(std::mem::size_of::()) * 2; + let next_cap = self.cap.max(16 * 32).max(core::mem::size_of::()) * 2; if self.cap == 0 { let layout = core::alloc::Layout::from_size_align_unchecked(next_cap, Self::MAX_ALIGN); @@ -1471,15 +1478,7 @@ impl StackAlloc { } let dst = self.data.add(self.len) as *mut T; - debug_assert!( - dst.is_aligned(), - "{:?} {:?} {} {} {}", - dst, - std::mem::size_of::(), - std::mem::align_of::(), - self.len, - self.cap - ); + debug_assert!(dst.is_aligned(),); self.len += core::mem::size_of::(); core::ptr::write(dst, value); } diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 468af74..c51ec03 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -25,6 +25,7 @@ use { }, hashbrown::hash_map, regalloc2::VReg, + std::process::id, }; const VOID: Nid = 0; @@ -2016,6 +2017,9 @@ impl Codegen { lit_name: &str, ) -> ty::Kind { log::trace!("find_or_declare: {lit_name} {file}"); + if let Some(ty) = self.tys.find_type(file, name.ok_or(lit_name), &self.files) { + return ty.expand(); + } let f = self.files[file as usize].clone(); let Some((expr, ident)) = f.find_decl(name.ok_or(lit_name)) else { @@ -2037,7 +2041,8 @@ impl Codegen { return ty::Kind::Builtin(ty::NEVER); }; - if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) { + let key = SymKey::Decl(file, ident); + if let Some(existing) = self.tys.syms.get(&key) { if let ty::Kind::Func(id) = existing.expand() && let func = &mut self.tys.funcs[id as usize] && let Err(idx) = task::unpack(func.offset) @@ -2099,7 +2104,7 @@ impl Codegen { e => unimplemented!("{e:#?}"), }; self.ci.file = prev_file; - self.tys.syms.insert(SymKey { ident, file }, sym.compress()); + self.tys.syms.insert(key, sym.compress()); sym }