diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index abad808..7a158ca 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -741,29 +741,32 @@ impl Codegen { 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) + if let Some(sym) = sym + && let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) { return ty.expand().inner(); } - let prev_tmp = self.tys.ins.fields.len(); + let prev_tmp = self.tys.tmp.fields.len(); for sf in fields.iter().filter_map(CommentOr::or) { let f = Field { name: self.tys.names.intern(sf.name), ty: self.ty(&sf.ty) }; - self.tys.ins.fields.push(f); + self.tys.tmp.fields.push(f); } self.tys.ins.structs.push(Struct { field_start: self.tys.ins.fields.len() as _, + pos: pos.unwrap_or(Pos::MAX), explicit_alignment, file, ..Default::default() }); - self.tys.ins.fields.extend(self.tys.ins.fields.drain(prev_tmp..)); + self.tys.ins.fields.extend(self.tys.tmp.fields.drain(prev_tmp..)); if let Some(sym) = sym { - self.tys - .syms - .insert(sym, ty::Kind::Struct(self.tys.ins.structs.len() as u32 - 1).compress()); + self.tys.syms.insert( + sym, + ty::Kind::Struct(self.tys.ins.structs.len() as u32 - 1).compress(), + &self.tys.ins, + ); } self.tys.ins.structs.len() as u32 - 1 @@ -884,7 +887,7 @@ impl Codegen { self.report(func_ast.pos(), "first argument of inline needs to be a function"); }; - let fuc = &self.tys.funcs[func as usize]; + let fuc = &self.tys.ins.funcs[func as usize]; let fast = self.files[fuc.file as usize].clone(); let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } = fuc.expr.get(&fast).unwrap() @@ -899,7 +902,7 @@ impl Codegen { if scope == self.ci.vars.len() { for ((arg, ti), carg) in args.iter().zip(sig.args.range()).zip(cargs) { - let ty = self.tys.args[ti]; + let ty = self.tys.ins.args[ti]; let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc; self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } }); } @@ -909,7 +912,7 @@ impl Codegen { let loc = self.alloc_ret(sig.ret, ctx, true); let prev_ret_reg = core::mem::replace(&mut self.ci.inline_ret_loc, loc); - let fuc = &self.tys.funcs[func as usize]; + let fuc = &self.tys.ins.funcs[func as usize]; let prev_file = core::mem::replace(&mut self.ci.file, fuc.file); let prev_ret = core::mem::replace(&mut self.ci.ret, Some(sig.ret)); self.expr(body); @@ -1347,7 +1350,7 @@ impl Codegen { //self.output.trunc(&snap); self.ci.vars.truncate(scope); - let fuc = &self.tys.funcs[func as usize]; + let fuc = &self.tys.ins.funcs[func as usize]; let ast = self.files[fuc.file as usize].clone(); let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } = fuc.expr.get(&ast).unwrap() @@ -1363,7 +1366,7 @@ impl Codegen { self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "function call"); for (i, (arg, carg)) in args.iter().zip(cargs).enumerate() { - let ty = self.tys.args[sig_args.next().unwrap()]; + let ty = self.tys.ins.args[sig_args.next().unwrap()]; let sym = parser::find_symbol(&ast.symbols, carg.id); if sym.flags & idfl::COMPTIME != 0 { sig_args.next().unwrap(); @@ -1740,7 +1743,7 @@ impl Codegen { } fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option { - let fuc = &self.tys.funcs[*func as usize]; + let fuc = &self.tys.ins.funcs[*func as usize]; let fast = self.files[fuc.file as usize].clone(); let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } = fuc.expr.get(&fast).unwrap() @@ -1751,11 +1754,11 @@ impl Codegen { Some(if let Some(sig) = fuc.sig { sig } else { - let arg_base = self.tys.args.len(); + let arg_base = self.tys.ins.args.len(); for (arg, carg) in args.iter().zip(cargs) { let ty = self.ty(&carg.ty); - self.tys.args.push(ty); + self.tys.ins.args.push(ty); let sym = parser::find_symbol(&fast.symbols, carg.id); let loc = if sym.flags & idfl::COMPTIME == 0 { // FIXME: could fuck us @@ -1767,7 +1770,7 @@ impl Codegen { "TODO: we dont support anything except type generics" ); let arg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; - self.tys.args.push(arg.loc.to_ty().unwrap()); + self.tys.ins.args.push(arg.loc.to_ty().unwrap()); arg.loc }; @@ -1778,11 +1781,13 @@ impl Codegen { let ret = self.ty(ret); let sym = SymKey::FuncInst(*func, args); - let ct = || { - let func_id = self.tys.funcs.len(); - let fuc = &self.tys.funcs[*func as usize]; - self.tys.funcs.push(Func { + let ct = |ins: &mut crate::TypeIns| { + let func_id = ins.funcs.len(); + let fuc = &ins.funcs[*func as usize]; + ins.funcs.push(Func { file: fuc.file, + name: fuc.name, + base: Some(*func), sig: Some(Sig { args, ret }), expr: fuc.expr, ..Default::default() @@ -1790,7 +1795,7 @@ impl Codegen { ty::Kind::Func(func_id as _).compress() }; - *func = self.tys.syms.entry(sym).or_insert_with(ct).expand().inner(); + *func = self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand().inner(); Sig { args, ret } }) @@ -2084,7 +2089,7 @@ impl Codegen { } fn handle_task(&mut self, FTask { file, id }: FTask) { - let func = &self.tys.funcs[id as usize]; + let func = &self.tys.ins.funcs[id as usize]; debug_assert!(func.file == file); let sig = func.sig.unwrap(); let ast = self.files[file as usize].clone(); @@ -2114,10 +2119,10 @@ impl Codegen { 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 ty = self.tys.ins.args[sig_args.next().unwrap()]; 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()]), + true => Loc::ty(self.tys.ins.args[sig_args.next().unwrap()]), false => self.load_arg(sym, ty, &mut parama), }; self.ci.vars.push(Variable { id: arg.id, value: Value { ty, loc } }); @@ -2144,8 +2149,8 @@ impl Codegen { self.ci.finalize(); self.ci.emit(jala(ZERO, RET_ADDR, 0)); self.ci.regs.free(core::mem::take(&mut self.ci.ret_reg)); - self.tys.funcs[id as usize].code.append(&mut self.ci.code); - self.tys.funcs[id as usize].relocs.append(&mut self.ci.relocs); + self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code); + self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs); self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci)); self.ct.vm.write_reg(reg::STACK_PTR, ct_stack_base); } @@ -2423,15 +2428,14 @@ impl Codegen { .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::MomizedCall(func); - if let Some(&ty) = self.tys.syms.get(&sym) { + if let Some(ty) = self.tys.ins.funcs[func as usize].computed { self.ct.vm.write_reg(1, ty.repr()); } else { self.run_vm(); - self.tys.syms.insert(sym, self.ct.vm.read_reg(1).0.into()); + self.tys.ins.funcs[func as usize].computed = + Some(self.ct.vm.read_reg(1).0.into()); } code_index += jal(0, 0, 0).0 + tx().0; } @@ -2463,9 +2467,9 @@ impl Codegen { }; let key = SymKey::Decl(file, ident); - if let Some(existing) = self.tys.syms.get(&key) { + if let Some(existing) = self.tys.syms.get(key, &self.tys.ins) { if let ty::Kind::Func(id) = existing.expand() - && let func = &mut self.tys.funcs[id as usize] + && let func = &mut self.tys.ins.funcs[id as usize] && let Err(idx) = task::unpack(func.offset) && idx < self.tasks.len() { @@ -2479,22 +2483,23 @@ impl Codegen { let prev_file = core::mem::replace(&mut self.ci.file, file); let sym = match expr { Expr::BinOp { - left: &Expr::Ident { .. }, + left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right: &Expr::Closure { pos, args, ret, .. }, } => { let func = Func { file, + name: id, sig: 'b: { - let arg_base = self.tys.args.len(); + let arg_base = self.tys.ins.args.len(); for arg in args { let sym = find_symbol(&self.files[file as usize].symbols, arg.id); if sym.flags & idfl::COMPTIME != 0 { - self.tys.args.truncate(arg_base); + self.tys.ins.args.truncate(arg_base); break 'b None; } let ty = self.ty(&arg.ty); - self.tys.args.push(ty); + self.tys.ins.args.push(ty); } let args = self.pack_args(pos, arg_base); @@ -2510,8 +2515,8 @@ impl Codegen { ..Default::default() }; - let id = self.tys.funcs.len() as _; - self.tys.funcs.push(func); + let id = self.tys.ins.funcs.len() as _; + self.tys.ins.funcs.push(func); ty::Kind::Func(id) } @@ -2545,12 +2550,12 @@ impl Codegen { e => unimplemented!("{e:#?}"), }; self.ci.file = prev_file; - self.tys.syms.insert(key, sym.compress()); + self.tys.syms.insert(key, sym.compress(), &self.tys.ins); sym } fn make_func_reachable(&mut self, func: ty::Func) { - let fuc = &mut self.tys.funcs[func as usize]; + let fuc = &mut self.tys.ins.funcs[func as usize]; if fuc.offset == u32::MAX { fuc.offset = task::id(self.tasks.len() as _); self.tasks.push(Some(FTask { file: fuc.file, id: func })); @@ -2604,11 +2609,11 @@ impl Codegen { } if ret.is_ok() { - let last_fn = self.tys.funcs.len(); - self.tys.funcs.push(Default::default()); + let last_fn = self.tys.ins.funcs.len(); + self.tys.ins.funcs.push(Default::default()); - 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); + self.tys.ins.funcs[last_fn].code = core::mem::take(&mut self.ci.code); + self.tys.ins.funcs[last_fn].relocs = core::mem::take(&mut self.ci.relocs); if is_on_stack { let size = @@ -2619,7 +2624,8 @@ impl Codegen { } self.tys.dump_reachable(last_fn as _, &mut self.ct.code); - let entry = &mut self.ct.code[self.tys.funcs[last_fn].offset as usize] as *mut _ as _; + let entry = + &mut self.ct.code[self.tys.ins.funcs[last_fn].offset as usize] as *mut _ as _; let prev_pc = core::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry)) - self.ct.code.as_ptr() as usize; @@ -2640,7 +2646,7 @@ impl Codegen { self.run_vm(); self.ct.vm.pc = prev_pc + self.ct.code.as_ptr() as usize; - let func = self.tys.funcs.pop().unwrap(); + let func = self.tys.ins.funcs.pop().unwrap(); self.ci.code = func.code; self.ci.code.clear(); self.ci.relocs = func.relocs; @@ -2729,15 +2735,15 @@ impl Codegen { } fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple { - let needle = &self.tys.args[arg_base..]; + let needle = &self.tys.ins.args[arg_base..]; if needle.is_empty() { return ty::Tuple::empty(); } let len = needle.len(); // FIXME: maybe later when this becomes a bottleneck we use more // efficient search (SIMD?, indexing?) - let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap(); - self.tys.args.truncate((sp + needle.len()).max(arg_base)); + let sp = self.tys.ins.args.windows(needle.len()).position(|val| val == needle).unwrap(); + self.tys.ins.args.truncate((sp + needle.len()).max(arg_base)); ty::Tuple::new(sp, len) .unwrap_or_else(|| self.report(pos, "amount of arguments not supported")) } @@ -2753,7 +2759,7 @@ impl Codegen { } pub fn assemble(&mut self, buf: &mut Vec) { - self.tys.funcs.iter_mut().for_each(|f| f.offset = u32::MAX); + self.tys.ins.funcs.iter_mut().for_each(|f| f.offset = u32::MAX); self.tys.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX); self.tys.assemble(buf) } @@ -2764,6 +2770,9 @@ mod tests { use alloc::{string::String, vec::Vec}; fn generate(ident: &'static str, input: &'static str, output: &mut String) { + _ = log::set_logger(&crate::fs::Logger); + log::set_max_level(log::LevelFilter::Error); + let mut codegen = super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() }; diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index 7d40a93..39fcd29 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -123,18 +123,18 @@ mod ctx_map { impl CtxMap { pub fn entry<'a, 'b>( &'a mut self, - value: T::Key<'b>, + key: T::Key<'b>, ctx: &'b T::Ctx, ) -> (hashbrown::hash_map::RawEntryMut<'a, Key, (), HashBuilder>, Hash) { - let hash = crate::FnvBuildHasher::default().hash_one(&value); - (self.inner.raw_entry_mut().from_hash(hash, |k| k.value.key(ctx) == value), hash) + let hash = crate::FnvBuildHasher::default().hash_one(&key); + (self.inner.raw_entry_mut().from_hash(hash, |k| k.value.key(ctx) == key), hash) } - pub fn get<'a>(&self, value: T::Key<'a>, ctx: &'a T::Ctx) -> Option<&T> { - let hash = crate::FnvBuildHasher::default().hash_one(&value); + pub fn get<'a>(&self, key: T::Key<'a>, ctx: &'a T::Ctx) -> Option<&T> { + let hash = crate::FnvBuildHasher::default().hash_one(&key); self.inner .raw_entry() - .from_hash(hash, |k| k.value.key(ctx) == value) + .from_hash(hash, |k| k.value.key(ctx) == key) .map(|(k, _)| &k.value) } @@ -142,13 +142,38 @@ mod ctx_map { self.inner.clear(); } - pub fn remove<'a>(&mut self, value: &T, ctx: &'a T::Ctx) -> Option { + pub fn remove(&mut self, value: &T, ctx: &T::Ctx) -> Option { let (entry, _) = self.entry(value.key(ctx), ctx); match entry { hashbrown::hash_map::RawEntryMut::Occupied(o) => Some(o.remove_entry().0.value), hashbrown::hash_map::RawEntryMut::Vacant(_) => None, } } + + pub fn insert<'a>(&mut self, key: T::Key<'a>, value: T, ctx: &'a T::Ctx) { + let (entry, hash) = self.entry(key, ctx); + match entry { + hashbrown::hash_map::RawEntryMut::Occupied(_) => unreachable!(), + hashbrown::hash_map::RawEntryMut::Vacant(v) => { + _ = v.insert(Key { hash, value }, ()) + } + } + } + + pub fn get_or_insert<'a>( + &mut self, + key: T::Key<'a>, + ctx: &'a mut T::Ctx, + with: impl FnOnce(&'a mut T::Ctx) -> T, + ) -> &mut T { + let (entry, hash) = self.entry(key, unsafe { &mut *(&mut *ctx as *mut _) }); + match entry { + hashbrown::hash_map::RawEntryMut::Occupied(o) => &mut o.into_key_value().0.value, + hashbrown::hash_map::RawEntryMut::Vacant(v) => { + &mut v.insert(Key { hash, value: with(ctx) }, ()).0.value + } + } + } } } @@ -205,7 +230,7 @@ mod ty { crate::{ ident, lexer::TokenKind, - parser::{self}, + parser::{self, Pos}, }, core::{num::NonZeroU32, ops::Range}, }; @@ -254,11 +279,32 @@ mod ty { pub struct Id(NonZeroU32); impl crate::ctx_map::CtxEntry for Id { - type Ctx = TypeInsts; + type Ctx = crate::TypeIns; type Key<'a> = crate::SymKey<'a>; fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { - todo!() + match self.expand() { + Kind::Struct(s) => { + let st = &ctx.structs[s as usize]; + debug_assert_ne!(st.pos, Pos::MAX); + crate::SymKey::Struct(st.file, st.pos) + } + Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]), + Kind::Func(f) => { + let fc = &ctx.funcs[f as usize]; + if let Some(base) = fc.base { + crate::SymKey::FuncInst(base, fc.sig.unwrap().args) + } else { + crate::SymKey::Decl(fc.file, fc.name) + } + } + Kind::Global(g) => { + let gb = &ctx.globals[g as usize]; + crate::SymKey::Decl(gb.file, gb.name) + } + Kind::Slice(s) => crate::SymKey::Array(&ctx.arrays[s as usize]), + Kind::Module(_) | Kind::Builtin(_) => crate::SymKey::Decl(u32::MAX, u32::MAX), + } } } @@ -521,12 +567,11 @@ fn emit(out: &mut Vec, (len, instr): EncodedInstr) { out.extend_from_slice(&instr[..len]); } -#[derive(PartialEq, Eq, Hash)] -enum SymKey<'a> { +#[derive(PartialEq, Eq, Hash, Clone, Copy)] +pub enum SymKey<'a> { Pointer(&'a Ptr), Struct(FileId, Pos), FuncInst(ty::Func, ty::Tuple), - MomizedCall(ty::Func), Decl(FileId, Ident), Array(&'a Array), } @@ -539,6 +584,9 @@ struct Sig { struct Func { file: FileId, + name: Ident, + base: Option, + computed: Option, expr: ExprRef, sig: Option, offset: Offset, @@ -551,6 +599,9 @@ impl Default for Func { fn default() -> Self { Self { file: u32::MAX, + name: 0, + base: None, + computed: None, expr: Default::default(), sig: None, offset: u32::MAX, @@ -620,6 +671,7 @@ struct Field { #[derive(Default)] struct Struct { name: Ident, + pos: Pos, file: FileId, size: Cell, align: Cell, @@ -628,12 +680,12 @@ struct Struct { } #[derive(PartialEq, Eq, Hash)] -struct Ptr { +pub struct Ptr { base: ty::Id, } #[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Array { +pub struct Array { ty: ty::Id, len: ArrayLen, } @@ -710,7 +762,7 @@ struct TypesTmp { } #[derive(Default)] -struct TypeIns { +pub struct TypeIns { funcs: Vec, args: Vec, globals: Vec, @@ -734,7 +786,8 @@ impl Types { fn struct_field_range(&self, strct: ty::Struct) -> Range { let start = self.ins.structs[strct as usize].field_start as usize; let end = self - .ins.structs + .ins + .structs .get(strct as usize + 1) .map_or(self.ins.fields.len(), |s| s.field_start as usize); start..end @@ -751,7 +804,7 @@ impl Types { files: &[parser::Ast], ) -> Option { if let Ok(id) = id - && let Some(&ty) = self.syms.get(&SymKey::Decl(file, id)) + && let Some(&ty) = self.syms.get(SymKey::Decl(file, id), &self.ins) { if let ty::Kind::Global(g) = ty.expand() { let g = &self.ins.globals[g as usize]; @@ -775,7 +828,7 @@ impl Types { self.ins.structs[s as usize].name = name; } - self.syms.insert(SymKey::Decl(file, name), ty); + self.syms.insert(SymKey::Decl(file, name), ty, &self.ins); Some(ty) } @@ -806,29 +859,30 @@ impl Types { } Expr::Struct { pos, fields, packed, .. } => { let sym = SymKey::Struct(file, pos); - if let Some(&ty) = self.syms.get(&sym) { + if let Some(&ty) = self.syms.get(sym, &self.ins) { return Some(ty); } - let prev_tmp = self.ins.fields.len(); + let prev_tmp = self.tmp.fields.len(); for field in fields.iter().filter_map(CommentOr::or) { let Some(ty) = self.ty(file, &field.ty, files) else { - self.ins.fields.truncate(prev_tmp); + self.tmp.fields.truncate(prev_tmp); return None; }; - self.ins.fields.push(Field { name: self.names.intern(field.name), ty }); + self.tmp.fields.push(Field { name: self.names.intern(field.name), ty }); } self.ins.structs.push(Struct { file, + pos, field_start: self.ins.fields.len() as _, explicit_alignment: packed.then_some(1), ..Default::default() }); - self.ins.fields.extend(self.ins.fields.drain(prev_tmp..)); + self.ins.fields.extend(self.tmp.fields.drain(prev_tmp..)); let ty = ty::Kind::Struct(self.ins.structs.len() as u32 - 1).compress(); - self.syms.insert(sym, ty); + self.syms.insert(sym, ty, &self.ins); ty } _ => return None, @@ -841,7 +895,7 @@ impl Types { emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); emit(to, instrs::tx()); let exe = self.dump_reachable(0, to); - Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, self.funcs[0].offset, 0); + Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, self.ins.funcs[0].offset, 0); unsafe { *to.as_mut_ptr().cast::() = exe } } @@ -849,13 +903,13 @@ impl Types { fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec) -> AbleOsExecutableHeader { debug_assert!(self.tmp.frontier.is_empty()); debug_assert!(self.tmp.funcs.is_empty()); - debug_assert!(self.ins.globals.is_empty()); + debug_assert!(self.tmp.globals.is_empty()); self.tmp.frontier.push(ty::Kind::Func(from).compress()); while let Some(itm) = self.tmp.frontier.pop() { match itm.expand() { ty::Kind::Func(func) => { - let fuc = &mut self.funcs[func as usize]; + let fuc = &mut self.ins.funcs[func as usize]; if task::is_done(fuc.offset) { continue; } @@ -869,21 +923,21 @@ impl Types { continue; } glb.offset = 0; - self.ins.globals.push(glob); + self.tmp.globals.push(glob); } _ => unreachable!(), } } for &func in &self.tmp.funcs { - let fuc = &mut self.funcs[func as usize]; + let fuc = &mut self.ins.funcs[func as usize]; fuc.offset = to.len() as _; to.extend(&fuc.code); } let code_length = to.len(); - for global in self.ins.globals.drain(..) { + for global in self.tmp.globals.drain(..) { let global = &mut self.ins.globals[global as usize]; global.offset = to.len() as _; to.extend(&global.data); @@ -892,10 +946,10 @@ impl Types { let data_length = to.len() - code_length; for func in self.tmp.funcs.drain(..) { - let fuc = &self.funcs[func as usize]; + let fuc = &self.ins.funcs[func as usize]; for rel in &fuc.relocs { let offset = match rel.target.expand() { - ty::Kind::Func(fun) => self.funcs[fun as usize].offset, + ty::Kind::Func(fun) => self.ins.funcs[fun as usize].offset, ty::Kind::Global(glo) => self.ins.globals[glo as usize].offset, _ => unreachable!(), }; @@ -923,6 +977,7 @@ impl Types { ) -> Result<(), hbbytecode::DisasmError<'a>> { use instrs::DisasmItem; let functions = self + .ins .funcs .iter() .filter(|f| task::is_done(f.offset)) @@ -962,14 +1017,25 @@ impl Types { } fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr { - self.syms - .entry(SymKey::Pointer(base)) - .or_insert_with(|| { - self.ins.ptrs.push(Ptr { base }); - ty::Kind::Ptr(self.ins.ptrs.len() as u32 - 1).compress() - }) - .expand() - .inner() + let ptr = Ptr { base }; + let (entry, hash) = self.syms.entry(SymKey::Pointer(&ptr), &self.ins); + match entry { + hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value, + hash_map::RawEntryMut::Vacant(v) => { + self.ins.ptrs.push(ptr); + v.insert( + ctx_map::Key { + value: ty::Kind::Ptr(self.ins.ptrs.len() as u32 - 1).compress(), + hash, + }, + (), + ) + .0 + .value + } + } + .expand() + .inner() } fn make_array(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Id { @@ -978,13 +1044,32 @@ impl Types { fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice { self.syms - .entry(SymKey::Array(ty, len)) - .or_insert_with(|| { - self.ins.arrays.push(Array { ty, len }); - ty::Kind::Slice(self.ins.arrays.len() as u32 - 1).compress() + .get_or_insert(SymKey::Array(&Array { ty, len }), &mut self.ins, |ins| { + ins.arrays.push(Array { ty, len }); + ty::Kind::Slice(ins.arrays.len() as u32 - 1).compress() }) .expand() .inner() + + //let array = Array { ty, len }; + //let (entry, hash) = self.syms.entry(SymKey::Array(&array), &self.ins); + //match entry { + // hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value, + // hash_map::RawEntryMut::Vacant(v) => { + // self.ins.arrays.push(array); + // v.insert( + // ctx_map::Key { + // value: ty::Kind::Slice(self.ins.ptrs.len() as u32 - 1).compress(), + // hash, + // }, + // (), + // ) + // .0 + // .value + // } + //} + //.expand() + //.inner() } fn size_of(&self, ty: ty::Id) -> Size { @@ -1082,7 +1167,7 @@ impl OffsetIter { fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> { let stru = &tys.ins.structs[self.strct as usize]; - let field = &tys.ins.fields[self.ins.fields.next()?]; + let field = &tys.ins.fields[self.fields.next()?]; let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32); self.offset = (self.offset + align - 1) & !(align - 1); diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 7895fa2..d5cb0d0 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -20,9 +20,7 @@ use { cell::RefCell, convert::identity, fmt::{self, Debug, Display, Write}, - format_args as fa, - hash::BuildHasher, - mem, ops, usize, + format_args as fa, mem, ops, }, hashbrown::hash_map, regalloc2::VReg, @@ -1033,7 +1031,7 @@ impl Codegen { } fn make_func_reachable(&mut self, func: ty::Func) { - let fuc = &mut self.tys.funcs[func as usize]; + let fuc = &mut self.tys.ins.funcs[func as usize]; if fuc.offset == u32::MAX { fuc.offset = task::id(self.tasks.len() as _); self.tasks.push(Some(FTask { file: fuc.file, id: func })); @@ -1237,7 +1235,7 @@ impl Codegen { self.make_func_reachable(func); - let fuc = &self.tys.funcs[func as usize]; + let fuc = &self.tys.ins.funcs[func as usize]; let sig = fuc.sig.expect("TODO: generic functions"); let ast = self.files[fuc.file as usize].clone(); let Expr::BinOp { right: &Expr::Closure { args: cargs, .. }, .. } = @@ -1259,7 +1257,7 @@ impl Codegen { let mut inps = Vc::from([self.ci.ctrl]); for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) { - let ty = self.tys.args[tyx]; + let ty = self.tys.ins.args[tyx]; if self.tys.size_of(ty) == 0 { continue; } @@ -1639,7 +1637,7 @@ impl Codegen { } fn emit_func(&mut self, FTask { file, id }: FTask) { - let func = &mut self.tys.funcs[id as usize]; + let func = &mut self.tys.ins.funcs[id as usize]; func.offset = u32::MAX - 1; debug_assert!(func.file == file); let sig = func.sig.unwrap(); @@ -1676,7 +1674,7 @@ impl Codegen { let mut sig_args = sig.args.range(); for (arg, index) in args.iter().zip(0u32..) { - let ty = self.tys.args[sig_args.next().unwrap()]; + let ty = self.tys.ins.args[sig_args.next().unwrap()]; let value = self.ci.nodes.new_node(ty, Kind::Arg { index }, [VOID]); self.ci.nodes.lock(value); let sym = parser::find_symbol(&ast.symbols, arg.id); @@ -1802,8 +1800,8 @@ impl Codegen { self.ci.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0)); } - self.tys.funcs[id as usize].code.append(&mut self.ci.code); - self.tys.funcs[id as usize].relocs.append(&mut self.ci.relocs); + self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code); + self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs); self.ci.nodes.clear(); self.ci.filled.clear(); self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci)); @@ -2012,9 +2010,9 @@ impl Codegen { }; let key = SymKey::Decl(file, ident); - if let Some(existing) = self.tys.syms.get(&key) { + if let Some(existing) = self.tys.syms.get(key, &self.tys.ins) { if let ty::Kind::Func(id) = existing.expand() - && let func = &mut self.tys.funcs[id as usize] + && let func = &mut self.tys.ins.funcs[id as usize] && let Err(idx) = task::unpack(func.offset) && idx < self.tasks.len() { @@ -2028,19 +2026,20 @@ impl Codegen { let prev_file = core::mem::replace(&mut self.ci.file, file); let sym = match expr { Expr::BinOp { - left: Expr::Ident { .. }, + left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right: &Expr::Closure { pos, args, ret, .. }, } => { let func = Func { file, + name: id, sig: '_b: { - let arg_base = self.tys.args.len(); + let arg_base = self.tys.ins.args.len(); for arg in args { let sym = parser::find_symbol(&f.symbols, arg.id); assert!(sym.flags & idfl::COMPTIME == 0, "TODO"); let ty = self.ty(&arg.ty); - self.tys.args.push(ty); + self.tys.ins.args.push(ty); } let Some(args) = self.pack_args(arg_base) else { @@ -2061,8 +2060,8 @@ impl Codegen { ..Default::default() }; - let id = self.tys.funcs.len() as _; - self.tys.funcs.push(func); + let id = self.tys.ins.funcs.len() as _; + self.tys.ins.funcs.push(func); ty::Kind::Func(id) } @@ -2074,7 +2073,7 @@ impl Codegen { e => unimplemented!("{e:#?}"), }; self.ci.file = prev_file; - self.tys.syms.insert(key, sym.compress()); + self.tys.syms.insert(key, sym.compress(), &self.tys.ins); sym } @@ -2153,15 +2152,15 @@ impl Codegen { } fn pack_args(&mut self, arg_base: usize) -> Option { - let needle = &self.tys.args[arg_base..]; + let needle = &self.tys.ins.args[arg_base..]; if needle.is_empty() { return Some(ty::Tuple::empty()); } let len = needle.len(); // FIXME: maybe later when this becomes a bottleneck we use more // efficient search (SIMD?, indexing?) - let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap(); - self.tys.args.truncate((sp + needle.len()).max(arg_base)); + let sp = self.tys.ins.args.windows(needle.len()).position(|val| val == needle).unwrap(); + self.tys.ins.args.truncate((sp + needle.len()).max(arg_base)); ty::Tuple::new(sp, len) } @@ -2397,7 +2396,7 @@ impl<'a> Function<'a> { for (arg, ti) in self.nodes[VOID].clone().outputs.into_iter().skip(2).zip(self.sig.args.range()) { - let ty = self.tys.args[ti]; + let ty = self.tys.ins.args[ti]; match self.tys.size_of(ty) { 0 => continue, 1..=8 => { @@ -2446,7 +2445,7 @@ impl<'a> Function<'a> { self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; let mut ops = vec![]; - let fuc = self.tys.funcs[func as usize].sig.unwrap(); + let fuc = self.tys.ins.funcs[func as usize].sig.unwrap(); if self.tys.size_of(fuc.ret) != 0 { self.def_nid(nid); ops.push(regalloc2::Operand::reg_fixed_def( @@ -2457,7 +2456,7 @@ impl<'a> Function<'a> { let mut parama = self.tys.parama(fuc.ret); for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) { - let ty = self.tys.args[ti]; + let ty = self.tys.ins.args[ti]; loop { match self.nodes[i].kind { Kind::Stre { .. } => i = self.nodes[i].inputs[2],