Compare commits

...

4 commits

Author SHA1 Message Date
Jakub Doka f1ea01ef0c
unifiing context key maps 2024-10-01 22:53:03 +02:00
Jakub Doka 2361e166cd
save 2024-10-01 21:39:23 +02:00
Jakub Doka 4d913462cb
save 2024-10-01 21:36:23 +02:00
Jakub Doka bdc2c43773
save 2024-10-01 21:33:30 +02:00
5 changed files with 414 additions and 292 deletions

10
Cargo.lock generated
View file

@ -110,6 +110,12 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]] [[package]]
name = "hbbytecode" name = "hbbytecode"
version = "0.1.0" version = "0.1.0"
@ -123,7 +129,7 @@ name = "hblang"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"hashbrown", "hashbrown 0.15.0",
"hbbytecode", "hbbytecode",
"hbvm", "hbvm",
"log", "log",
@ -191,7 +197,7 @@ source = "git+https://github.com/jakubDoka/regalloc2?branch=reuse-allocations#41
dependencies = [ dependencies = [
"allocator-api2", "allocator-api2",
"bumpalo", "bumpalo",
"hashbrown", "hashbrown 0.14.5",
"log", "log",
"rustc-hash", "rustc-hash",
"smallvec", "smallvec",

View file

@ -8,7 +8,7 @@ name = "hbc"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
hashbrown = { version = "0.14.5", default-features = false } hashbrown = { version = "0.15.0", default-features = false, features = ["raw-entry"] }
hbbytecode = { version = "0.1.0", path = "../hbbytecode" } hbbytecode = { version = "0.1.0", path = "../hbbytecode" }
hbvm = { path = "../hbvm", features = ["nightly"] } hbvm = { path = "../hbvm", features = ["nightly"] }
log = { version = "0.4.22", features = ["release_max_level_error"] } log = { version = "0.4.22", features = ["release_max_level_error"] }

View file

@ -741,32 +741,35 @@ impl Codegen {
fields: &[CommentOr<StructField>], fields: &[CommentOr<StructField>],
) -> ty::Struct { ) -> ty::Struct {
let sym = pos.map(|pos| SymKey::Struct(file, pos)); let sym = pos.map(|pos| SymKey::Struct(file, pos));
if let Some(ref sym) = sym if let Some(sym) = sym
&& let Some(&ty) = self.tys.syms.get(sym) && let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins)
{ {
return ty.expand().inner(); return ty.expand().inner();
} }
let prev_tmp = self.tys.fields_tmp.len(); let prev_tmp = self.tys.tmp.fields.len();
for sf in fields.iter().filter_map(CommentOr::or) { 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) }; let f = Field { name: self.tys.names.intern(sf.name), ty: self.ty(&sf.ty) };
self.tys.fields_tmp.push(f); self.tys.tmp.fields.push(f);
} }
self.tys.structs.push(Struct { self.tys.ins.structs.push(Struct {
field_start: self.tys.fields.len() as _, field_start: self.tys.ins.fields.len() as _,
pos: pos.unwrap_or(Pos::MAX),
explicit_alignment, explicit_alignment,
file, file,
..Default::default() ..Default::default()
}); });
self.tys.fields.extend(self.tys.fields_tmp.drain(prev_tmp..)); self.tys.ins.fields.extend(self.tys.tmp.fields.drain(prev_tmp..));
if let Some(sym) = sym { if let Some(sym) = sym {
self.tys self.tys.syms.insert(
.syms sym,
.insert(sym, ty::Kind::Struct(self.tys.structs.len() as u32 - 1).compress()); ty::Kind::Struct(self.tys.ins.structs.len() as u32 - 1).compress(),
&self.tys.ins,
);
} }
self.tys.structs.len() as u32 - 1 self.tys.ins.structs.len() as u32 - 1
} }
fn expr_ctx(&mut self, expr: &Expr, mut ctx: Ctx) -> Option<Value> { fn expr_ctx(&mut self, expr: &Expr, mut ctx: Ctx) -> Option<Value> {
@ -837,13 +840,13 @@ impl Codegen {
_ = self.assert_ty(index.pos(), index_val.ty, ty::Id::INT, "subsctipt"); _ = self.assert_ty(index.pos(), index_val.ty, ty::Id::INT, "subsctipt");
if let ty::Kind::Ptr(ty) = base_val.ty.expand() { if let ty::Kind::Ptr(ty) = base_val.ty.expand() {
base_val.ty = self.tys.ptrs[ty as usize].base; base_val.ty = self.tys.ins.ptrs[ty as usize].base;
base_val.loc = base_val.loc.into_derefed(); base_val.loc = base_val.loc.into_derefed();
} }
match base_val.ty.expand() { match base_val.ty.expand() {
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let ty = self.tys.arrays[arr as usize].ty; let ty = self.tys.ins.arrays[arr as usize].ty;
let item_size = self.tys.size_of(ty); let item_size = self.tys.size_of(ty);
let Loc::Rt { derefed: true, ref mut reg, ref stack, offset } = let Loc::Rt { derefed: true, ref mut reg, ref stack, offset } =
@ -884,7 +887,7 @@ impl Codegen {
self.report(func_ast.pos(), "first argument of inline needs to be a function"); 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 fast = self.files[fuc.file as usize].clone();
let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } = let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } =
fuc.expr.get(&fast).unwrap() fuc.expr.get(&fast).unwrap()
@ -899,7 +902,7 @@ impl Codegen {
if scope == self.ci.vars.len() { if scope == self.ci.vars.len() {
for ((arg, ti), carg) in args.iter().zip(sig.args.range()).zip(cargs) { 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; let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.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 } });
} }
@ -909,7 +912,7 @@ impl Codegen {
let loc = self.alloc_ret(sig.ret, ctx, true); let loc = self.alloc_ret(sig.ret, ctx, true);
let prev_ret_reg = core::mem::replace(&mut self.ci.inline_ret_loc, loc); 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_file = core::mem::replace(&mut self.ci.file, fuc.file);
let prev_ret = core::mem::replace(&mut self.ci.ret, Some(sig.ret)); let prev_ret = core::mem::replace(&mut self.ci.ret, Some(sig.ret));
self.expr(body); self.expr(body);
@ -1123,8 +1126,8 @@ impl Codegen {
} }
let reloc = Reloc::new(self.ci.code.len() as _, 3, 4); let reloc = Reloc::new(self.ci.code.len() as _, 3, 4);
let glob = self.tys.globals.len() as ty::Global; let glob = self.tys.ins.globals.len() as ty::Global;
self.tys.globals.push(Global { data: str, ..Default::default() }); self.tys.ins.globals.push(Global { data: str, ..Default::default() });
self.ci self.ci
.relocs .relocs
.push(TypedReloc { target: ty::Kind::Global(glob).compress(), reloc }); .push(TypedReloc { target: ty::Kind::Global(glob).compress(), reloc });
@ -1173,7 +1176,7 @@ impl Codegen {
} }
} }
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = self.tys.arrays[arr as usize]; let arr = self.tys.ins.arrays[arr as usize];
let item_size = self.tys.size_of(arr.ty); let item_size = self.tys.size_of(arr.ty);
for (i, value) in fields.iter().enumerate() { for (i, value) in fields.iter().enumerate() {
let loc = loc.as_ref().offset(i as u32 * item_size); let loc = loc.as_ref().offset(i as u32 * item_size);
@ -1204,7 +1207,7 @@ impl Codegen {
let mut tal = self.expr(target)?; let mut tal = self.expr(target)?;
if let ty::Kind::Ptr(ty) = tal.ty.expand() { if let ty::Kind::Ptr(ty) = tal.ty.expand() {
tal.ty = self.tys.ptrs[ty as usize].base; tal.ty = self.tys.ins.ptrs[ty as usize].base;
tal.loc = tal.loc.into_derefed(); tal.loc = tal.loc.into_derefed();
} }
@ -1305,7 +1308,7 @@ impl Codegen {
let val = self.expr(val)?; let val = self.expr(val)?;
match val.ty.expand() { match val.ty.expand() {
ty::Kind::Ptr(ty) => Some(Value { ty::Kind::Ptr(ty) => Some(Value {
ty: self.tys.ptrs[ty as usize].base, ty: self.tys.ins.ptrs[ty as usize].base,
loc: Loc::reg(self.loc_to_reg(val.loc, self.tys.size_of(val.ty))) loc: Loc::reg(self.loc_to_reg(val.loc, self.tys.size_of(val.ty)))
.into_derefed(), .into_derefed(),
}), }),
@ -1347,7 +1350,7 @@ impl Codegen {
//self.output.trunc(&snap); //self.output.trunc(&snap);
self.ci.vars.truncate(scope); 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 ast = self.files[fuc.file as usize].clone();
let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } = let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } =
fuc.expr.get(&ast).unwrap() fuc.expr.get(&ast).unwrap()
@ -1363,7 +1366,7 @@ impl Codegen {
self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "function call"); self.assert_arg_count(expr.pos(), args.len(), cargs.len(), "function call");
for (i, (arg, carg)) in args.iter().zip(cargs).enumerate() { 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); let sym = parser::find_symbol(&ast.symbols, carg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
sig_args.next().unwrap(); sig_args.next().unwrap();
@ -1639,7 +1642,7 @@ impl Codegen {
if matches!(op, T::Add | T::Sub) if matches!(op, T::Add | T::Sub)
&& let ty::Kind::Ptr(ty) = ty::Kind::from_ty(ty) && let ty::Kind::Ptr(ty) = ty::Kind::from_ty(ty)
{ {
let size = self.tys.size_of(self.tys.ptrs[ty as usize].base); let size = self.tys.size_of(self.tys.ins.ptrs[ty as usize].base);
imm *= size as u64; imm *= size as u64;
} }
@ -1675,7 +1678,7 @@ impl Codegen {
let ty::Kind::Ptr(ty) = ty.expand() else { unreachable!() }; let ty::Kind::Ptr(ty) = ty.expand() else { unreachable!() };
let size = self.tys.size_of(self.tys.ptrs[ty as usize].base); let size = self.tys.size_of(self.tys.ins.ptrs[ty as usize].base);
self.ci.emit(muli64(offset, offset, size as _)); self.ci.emit(muli64(offset, offset, size as _));
} }
} }
@ -1740,7 +1743,7 @@ impl Codegen {
} }
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> { fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
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 fast = self.files[fuc.file as usize].clone();
let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } = let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } =
fuc.expr.get(&fast).unwrap() fuc.expr.get(&fast).unwrap()
@ -1751,11 +1754,11 @@ impl Codegen {
Some(if let Some(sig) = fuc.sig { Some(if let Some(sig) = fuc.sig {
sig sig
} else { } else {
let arg_base = self.tys.args.len(); let arg_base = self.tys.ins.args.len();
for (arg, carg) in args.iter().zip(cargs) { for (arg, carg) in args.iter().zip(cargs) {
let ty = self.ty(&carg.ty); 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 sym = parser::find_symbol(&fast.symbols, carg.id);
let loc = if sym.flags & idfl::COMPTIME == 0 { let loc = if sym.flags & idfl::COMPTIME == 0 {
// FIXME: could fuck us // FIXME: could fuck us
@ -1767,7 +1770,7 @@ impl Codegen {
"TODO: we dont support anything except type generics" "TODO: we dont support anything except type generics"
); );
let arg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?; 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 arg.loc
}; };
@ -1778,11 +1781,13 @@ impl Codegen {
let ret = self.ty(ret); let ret = self.ty(ret);
let sym = SymKey::FuncInst(*func, args); let sym = SymKey::FuncInst(*func, args);
let ct = || { let ct = |ins: &mut crate::TypeIns| {
let func_id = self.tys.funcs.len(); let func_id = ins.funcs.len();
let fuc = &self.tys.funcs[*func as usize]; let fuc = &ins.funcs[*func as usize];
self.tys.funcs.push(Func { ins.funcs.push(Func {
file: fuc.file, file: fuc.file,
name: fuc.name,
base: Some(*func),
sig: Some(Sig { args, ret }), sig: Some(Sig { args, ret }),
expr: fuc.expr, expr: fuc.expr,
..Default::default() ..Default::default()
@ -1790,7 +1795,7 @@ impl Codegen {
ty::Kind::Func(func_id as _).compress() 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 } Sig { args, ret }
}) })
@ -1954,7 +1959,7 @@ impl Codegen {
} }
} }
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = &self.tys.arrays[arr as usize]; let arr = &self.tys.ins.arrays[arr as usize];
if arr.len == ArrayLen::MAX { if arr.len == ArrayLen::MAX {
ty = self.tys.make_array(arr.ty, field_len as _); ty = self.tys.make_array(arr.ty, field_len as _);
} else if arr.len != field_len as u32 { } else if arr.len != field_len as u32 {
@ -2043,7 +2048,7 @@ impl Codegen {
let ptr = self.ci.regs.allocate(); let ptr = self.ci.regs.allocate();
let reloc = Reloc::new(self.ci.code.len(), 3, 4); let reloc = Reloc::new(self.ci.code.len(), 3, 4);
let global = &mut self.tys.globals[id as usize]; let global = &mut self.tys.ins.globals[id as usize];
self.ci.relocs.push(TypedReloc { target: ty::Kind::Global(id).compress(), reloc }); self.ci.relocs.push(TypedReloc { target: ty::Kind::Global(id).compress(), reloc });
self.ci.emit(instrs::lra(ptr.get(), 0, 0)); self.ci.emit(instrs::lra(ptr.get(), 0, 0));
@ -2084,7 +2089,7 @@ impl Codegen {
} }
fn handle_task(&mut self, FTask { file, id }: FTask) { 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); debug_assert!(func.file == file);
let sig = func.sig.unwrap(); let sig = func.sig.unwrap();
let ast = self.files[file as usize].clone(); let ast = self.files[file as usize].clone();
@ -2114,10 +2119,10 @@ impl Codegen {
let mut parama = self.tys.parama(sig.ret); let mut parama = self.tys.parama(sig.ret);
let mut sig_args = sig.args.range(); let mut sig_args = sig.args.range();
for arg in args.iter() { for arg in args.iter() {
let ty = self.tys.args[sig_args.next().unwrap()]; let ty = self.tys.ins.args[sig_args.next().unwrap()];
let sym = parser::find_symbol(&ast.symbols, arg.id).flags; let sym = parser::find_symbol(&ast.symbols, arg.id).flags;
let loc = match sym & idfl::COMPTIME != 0 { let loc = match sym & idfl::COMPTIME != 0 {
true => Loc::ty(self.tys.args[sig_args.next().unwrap()]), true => Loc::ty(self.tys.ins.args[sig_args.next().unwrap()]),
false => self.load_arg(sym, 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 } });
@ -2144,8 +2149,8 @@ impl Codegen {
self.ci.finalize(); self.ci.finalize();
self.ci.emit(jala(ZERO, RET_ADDR, 0)); self.ci.emit(jala(ZERO, RET_ADDR, 0));
self.ci.regs.free(core::mem::take(&mut self.ci.ret_reg)); 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.ins.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].relocs.append(&mut self.ci.relocs);
self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci)); self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci));
self.ct.vm.write_reg(reg::STACK_PTR, ct_stack_base); self.ct.vm.write_reg(reg::STACK_PTR, ct_stack_base);
} }
@ -2423,15 +2428,14 @@ impl Codegen {
.compress(); .compress();
self.ci.vars.truncate(prev_len); self.ci.vars.truncate(prev_len);
self.ct.vm.write_reg(1, stru.repr() as u64); self.ct.vm.write_reg(1, stru.repr() as u64);
debug_assert_ne!(stru.expand().inner(), 1);
} }
trap::Trap::MomizedCall(trap::MomizedCall { func }) => { trap::Trap::MomizedCall(trap::MomizedCall { func }) => {
let sym = SymKey::MomizedCall(func); if let Some(ty) = self.tys.ins.funcs[func as usize].computed {
if let Some(&ty) = self.tys.syms.get(&sym) {
self.ct.vm.write_reg(1, ty.repr()); self.ct.vm.write_reg(1, ty.repr());
} else { } else {
self.run_vm(); 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; code_index += jal(0, 0, 0).0 + tx().0;
} }
@ -2463,9 +2467,9 @@ impl Codegen {
}; };
let key = SymKey::Decl(file, ident); 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() 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) && let Err(idx) = task::unpack(func.offset)
&& idx < self.tasks.len() && idx < self.tasks.len()
{ {
@ -2479,22 +2483,23 @@ impl Codegen {
let prev_file = core::mem::replace(&mut self.ci.file, file); let prev_file = core::mem::replace(&mut self.ci.file, file);
let sym = match expr { let sym = match expr {
Expr::BinOp { Expr::BinOp {
left: &Expr::Ident { .. }, left: &Expr::Ident { id, .. },
op: TokenKind::Decl, op: TokenKind::Decl,
right: &Expr::Closure { pos, args, ret, .. }, right: &Expr::Closure { pos, args, ret, .. },
} => { } => {
let func = Func { let func = Func {
file, file,
name: id,
sig: 'b: { sig: 'b: {
let arg_base = self.tys.args.len(); let arg_base = self.tys.ins.args.len();
for arg in args { for arg in args {
let sym = find_symbol(&self.files[file as usize].symbols, arg.id); let sym = find_symbol(&self.files[file as usize].symbols, arg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
self.tys.args.truncate(arg_base); self.tys.ins.args.truncate(arg_base);
break 'b None; break 'b None;
} }
let ty = self.ty(&arg.ty); 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); let args = self.pack_args(pos, arg_base);
@ -2510,8 +2515,8 @@ impl Codegen {
..Default::default() ..Default::default()
}; };
let id = self.tys.funcs.len() as _; let id = self.tys.ins.funcs.len() as _;
self.tys.funcs.push(func); self.tys.ins.funcs.push(func);
ty::Kind::Func(id) ty::Kind::Func(id)
} }
@ -2521,12 +2526,12 @@ impl Codegen {
right: stru @ Expr::Struct { .. }, right: stru @ Expr::Struct { .. },
} => { } => {
let str = self.ty(stru).expand().inner(); let str = self.ty(stru).expand().inner();
self.tys.structs[str as usize].name = id; self.tys.ins.structs[str as usize].name = id;
ty::Kind::Struct(str) ty::Kind::Struct(str)
} }
Expr::BinOp { left, op: TokenKind::Decl, right } => { Expr::BinOp { left, op: TokenKind::Decl, right } => {
let gid = self.tys.globals.len() as ty::Global; let gid = self.tys.ins.globals.len() as ty::Global;
self.tys.globals.push(Global { file, name: ident, ..Default::default() }); self.tys.ins.globals.push(Global { file, name: ident, ..Default::default() });
let ci = ItemCtx { let ci = ItemCtx {
file, file,
@ -2535,7 +2540,7 @@ impl Codegen {
}; };
_ = left.find_pattern_path(ident, right, |expr| { _ = left.find_pattern_path(ident, right, |expr| {
self.tys.globals[gid as usize] = self self.tys.ins.globals[gid as usize] = self
.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr, file, ident))) .ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr, file, ident)))
.into_ok(); .into_ok();
}); });
@ -2545,12 +2550,12 @@ impl Codegen {
e => unimplemented!("{e:#?}"), e => unimplemented!("{e:#?}"),
}; };
self.ci.file = prev_file; self.ci.file = prev_file;
self.tys.syms.insert(key, sym.compress()); self.tys.syms.insert(key, sym.compress(), &self.tys.ins);
sym sym
} }
fn make_func_reachable(&mut self, func: ty::Func) { 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 { if fuc.offset == u32::MAX {
fuc.offset = task::id(self.tasks.len() as _); fuc.offset = task::id(self.tasks.len() as _);
self.tasks.push(Some(FTask { file: fuc.file, id: func })); self.tasks.push(Some(FTask { file: fuc.file, id: func }));
@ -2580,7 +2585,7 @@ impl Codegen {
self.ci.free_loc(ret.loc); self.ci.free_loc(ret.loc);
Global { ty: ret.ty, file, name, data, ast: ExprRef::new(expr), ..Default::default() } Global { ty: ret.ty, file, name, data, ..Default::default() }
} }
fn ct_eval<T, E>( fn ct_eval<T, E>(
@ -2604,11 +2609,11 @@ impl Codegen {
} }
if ret.is_ok() { if ret.is_ok() {
let last_fn = self.tys.funcs.len(); let last_fn = self.tys.ins.funcs.len();
self.tys.funcs.push(Default::default()); self.tys.ins.funcs.push(Default::default());
self.tys.funcs[last_fn].code = core::mem::take(&mut self.ci.code); self.tys.ins.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].relocs = core::mem::take(&mut self.ci.relocs);
if is_on_stack { if is_on_stack {
let size = let size =
@ -2619,7 +2624,8 @@ impl Codegen {
} }
self.tys.dump_reachable(last_fn as _, &mut self.ct.code); 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)) let prev_pc = core::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry))
- self.ct.code.as_ptr() as usize; - self.ct.code.as_ptr() as usize;
@ -2640,7 +2646,7 @@ impl Codegen {
self.run_vm(); self.run_vm();
self.ct.vm.pc = prev_pc + self.ct.code.as_ptr() as usize; 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 = func.code;
self.ci.code.clear(); self.ci.code.clear();
self.ci.relocs = func.relocs; self.ci.relocs = func.relocs;
@ -2729,15 +2735,15 @@ impl Codegen {
} }
fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple { 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() { if needle.is_empty() {
return ty::Tuple::empty(); return ty::Tuple::empty();
} }
let len = needle.len(); let len = needle.len();
// FIXME: maybe later when this becomes a bottleneck we use more // FIXME: maybe later when this becomes a bottleneck we use more
// efficient search (SIMD?, indexing?) // efficient search (SIMD?, indexing?)
let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap(); let sp = self.tys.ins.args.windows(needle.len()).position(|val| val == needle).unwrap();
self.tys.args.truncate((sp + needle.len()).max(arg_base)); self.tys.ins.args.truncate((sp + needle.len()).max(arg_base));
ty::Tuple::new(sp, len) ty::Tuple::new(sp, len)
.unwrap_or_else(|| self.report(pos, "amount of arguments not supported")) .unwrap_or_else(|| self.report(pos, "amount of arguments not supported"))
} }
@ -2753,8 +2759,8 @@ impl Codegen {
} }
pub fn assemble(&mut self, buf: &mut Vec<u8>) { pub fn assemble(&mut self, buf: &mut Vec<u8>) {
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.globals.iter_mut().for_each(|g| g.offset = u32::MAX); self.tys.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX);
self.tys.assemble(buf) self.tys.assemble(buf)
} }
} }
@ -2764,6 +2770,9 @@ mod tests {
use alloc::{string::String, vec::Vec}; use alloc::{string::String, vec::Vec};
fn generate(ident: &'static str, input: &'static str, output: &mut String) { 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 = let mut codegen =
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() }; super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };

View file

@ -36,7 +36,7 @@ use {
ty::ArrayLen, ty::ArrayLen,
}, },
alloc::{collections::BTreeMap, string::String, vec::Vec}, alloc::{collections::BTreeMap, string::String, vec::Vec},
core::{cell::Cell, fmt::Display, hash::BuildHasher, ops::Range, usize}, core::{cell::Cell, fmt::Display, ops::Range},
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode as instrs, hbbytecode as instrs,
}; };
@ -69,6 +69,114 @@ pub mod son;
mod lexer; mod lexer;
mod vc; mod vc;
mod ctx_map {
use core::hash::BuildHasher;
pub type Hash = u64;
pub type HashBuilder = core::hash::BuildHasherDefault<IdentityHasher>;
#[derive(Default)]
pub struct IdentityHasher(u64);
impl core::hash::Hasher for IdentityHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _: &[u8]) {
unimplemented!()
}
fn write_u64(&mut self, i: u64) {
self.0 = i;
}
}
pub struct Key<T> {
pub value: T,
pub hash: Hash,
}
impl<T> core::hash::Hash for Key<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write_u64(self.hash);
}
}
pub trait CtxEntry {
type Ctx: ?Sized;
type Key<'a>: Eq + core::hash::Hash;
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a>;
}
pub struct CtxMap<T> {
inner: hashbrown::HashMap<Key<T>, (), HashBuilder>,
}
impl<T> Default for CtxMap<T> {
fn default() -> Self {
Self { inner: Default::default() }
}
}
impl<T: CtxEntry> CtxMap<T> {
pub fn entry<'a, 'b>(
&'a mut self,
key: T::Key<'b>,
ctx: &'b T::Ctx,
) -> (hashbrown::hash_map::RawEntryMut<'a, Key<T>, (), HashBuilder>, 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, 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) == key)
.map(|(k, _)| &k.value)
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn remove(&mut self, value: &T, ctx: &T::Ctx) -> Option<T> {
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
}
}
}
}
}
mod task { mod task {
use super::Offset; use super::Offset;
@ -122,9 +230,9 @@ mod ty {
crate::{ crate::{
ident, ident,
lexer::TokenKind, lexer::TokenKind,
parser::{self}, parser::{self, Pos},
}, },
core::{num::NonZeroU32, ops::Range, usize}, core::{num::NonZeroU32, ops::Range},
}; };
pub type ArrayLen = u32; pub type ArrayLen = u32;
@ -153,10 +261,6 @@ mod ty {
Some(Self((pos << Self::LEN_BITS | len) as u32)) Some(Self((pos << Self::LEN_BITS | len) as u32))
} }
//pub fn view(self, slice: &[Id]) -> &[Id] {
// &slice[self.0 as usize >> Self::LEN_BITS..][..self.len()]
//}
pub fn range(self) -> Range<usize> { pub fn range(self) -> Range<usize> {
let start = self.0 as usize >> Self::LEN_BITS; let start = self.0 as usize >> Self::LEN_BITS;
start..start + self.len() start..start + self.len()
@ -169,15 +273,41 @@ mod ty {
pub fn empty() -> Self { pub fn empty() -> Self {
Self(0) Self(0)
} }
pub fn repr(&self) -> u32 {
self.0
}
} }
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Id(NonZeroU32); pub struct Id(NonZeroU32);
impl crate::ctx_map::CtxEntry for Id {
type Ctx = crate::TypeIns;
type Key<'a> = crate::SymKey<'a>;
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
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),
}
}
}
impl Default for Id { impl Default for Id {
fn default() -> Self { fn default() -> Self {
Self(unsafe { NonZeroU32::new_unchecked(UNDECLARED) }) Self(unsafe { NonZeroU32::new_unchecked(UNDECLARED) })
@ -387,10 +517,10 @@ mod ty {
TK::Module(idx) => write!(f, "@use({:?})[{}]", self.files[idx as usize].path, idx), TK::Module(idx) => write!(f, "@use({:?})[{}]", self.files[idx as usize].path, idx),
TK::Builtin(ty) => write!(f, "{}", to_str(ty)), TK::Builtin(ty) => write!(f, "{}", to_str(ty)),
TK::Ptr(ty) => { TK::Ptr(ty) => {
write!(f, "^{}", self.rety(self.tys.ptrs[ty as usize].base)) write!(f, "^{}", self.rety(self.tys.ins.ptrs[ty as usize].base))
} }
TK::Struct(idx) => { TK::Struct(idx) => {
let record = &self.tys.structs[idx as usize]; let record = &self.tys.ins.structs[idx as usize];
if ident::is_null(record.name) { if ident::is_null(record.name) {
write!(f, "[{idx}]{{")?; write!(f, "[{idx}]{{")?;
for (i, &super::Field { name, ty }) in for (i, &super::Field { name, ty }) in
@ -399,12 +529,7 @@ mod ty {
if i != 0 { if i != 0 {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!( write!(f, "{}: {}", self.tys.names.ident_str(name), self.rety(ty))?;
f,
"{}: {}",
self.tys.field_names.ident_str(name),
self.rety(ty)
)?;
} }
write!(f, "}}") write!(f, "}}")
} else { } else {
@ -415,7 +540,7 @@ mod ty {
TK::Func(idx) => write!(f, "fn{idx}"), TK::Func(idx) => write!(f, "fn{idx}"),
TK::Global(idx) => write!(f, "global{idx}"), TK::Global(idx) => write!(f, "global{idx}"),
TK::Slice(idx) => { TK::Slice(idx) => {
let array = self.tys.arrays[idx as usize]; let array = self.tys.ins.arrays[idx as usize];
match array.len { match array.len {
ArrayLen::MAX => write!(f, "[{}]", self.rety(array.ty)), ArrayLen::MAX => write!(f, "[{}]", self.rety(array.ty)),
len => write!(f, "[{}; {len}]", self.rety(array.ty)), len => write!(f, "[{}; {len}]", self.rety(array.ty)),
@ -442,15 +567,13 @@ fn emit(out: &mut Vec<u8>, (len, instr): EncodedInstr) {
out.extend_from_slice(&instr[..len]); out.extend_from_slice(&instr[..len]);
} }
#[derive(PartialEq, Eq, Hash, Debug)] #[derive(PartialEq, Eq, Hash, Clone, Copy)]
enum SymKey { pub enum SymKey<'a> {
Pointer(ty::Id), Pointer(&'a Ptr),
Struct(FileId, Pos), Struct(FileId, Pos),
FuncInst(ty::Func, ty::Tuple), FuncInst(ty::Func, ty::Tuple),
MomizedCall(ty::Func),
Decl(FileId, Ident), Decl(FileId, Ident),
Slice(ty::Id), Array(&'a Array),
Array(ty::Id, ArrayLen),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -461,6 +584,9 @@ struct Sig {
struct Func { struct Func {
file: FileId, file: FileId,
name: Ident,
base: Option<ty::Func>,
computed: Option<ty::Id>,
expr: ExprRef, expr: ExprRef,
sig: Option<Sig>, sig: Option<Sig>,
offset: Offset, offset: Offset,
@ -473,6 +599,9 @@ impl Default for Func {
fn default() -> Self { fn default() -> Self {
Self { Self {
file: u32::MAX, file: u32::MAX,
name: 0,
base: None,
computed: None,
expr: Default::default(), expr: Default::default(),
sig: None, sig: None,
offset: u32::MAX, offset: u32::MAX,
@ -491,7 +620,6 @@ struct Global {
file: FileId, file: FileId,
name: Ident, name: Ident,
ty: ty::Id, ty: ty::Id,
ast: ExprRef,
offset: Offset, offset: Offset,
data: Vec<u8>, data: Vec<u8>,
} }
@ -502,7 +630,6 @@ impl Default for Global {
ty: Default::default(), ty: Default::default(),
offset: u32::MAX, offset: u32::MAX,
data: Default::default(), data: Default::default(),
ast: ExprRef::default(),
file: u32::MAX, file: u32::MAX,
name: u32::MAX, name: u32::MAX,
} }
@ -544,6 +671,7 @@ struct Field {
#[derive(Default)] #[derive(Default)]
struct Struct { struct Struct {
name: Ident, name: Ident,
pos: Pos,
file: FileId, file: FileId,
size: Cell<Size>, size: Cell<Size>,
align: Cell<u8>, align: Cell<u8>,
@ -551,12 +679,13 @@ struct Struct {
field_start: u32, field_start: u32,
} }
struct Ptr { #[derive(PartialEq, Eq, Hash)]
pub struct Ptr {
base: ty::Id, base: ty::Id,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct Array { pub struct Array {
ty: ty::Id, ty: ty::Id,
len: ArrayLen, len: ArrayLen,
} }
@ -586,56 +715,30 @@ struct AbleOsExecutableHeader {
metadata_length: u64, metadata_length: u64,
} }
struct IdentEntry { impl ctx_map::CtxEntry for Ident {
hash: u32, type Ctx = str;
ident: Ident, type Key<'a> = &'a str;
}
impl core::hash::Hash for IdentEntry { fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { unsafe { ctx.get_unchecked(ident::range(*self)) }
state.write_u64((self.hash as u64) << 32);
}
}
#[derive(Default)]
struct IdentityHasher(u64);
impl core::hash::Hasher for IdentityHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _: &[u8]) {
unimplemented!()
}
fn write_u64(&mut self, i: u64) {
self.0 = i;
} }
} }
#[derive(Default)] #[derive(Default)]
struct IdentInterner { struct IdentInterner {
lookup: hashbrown::HashMap<IdentEntry, (), core::hash::BuildHasherDefault<IdentityHasher>>, lookup: ctx_map::CtxMap<Ident>,
strings: String, strings: String,
} }
impl IdentInterner { impl IdentInterner {
fn intern(&mut self, ident: &str) -> Ident { fn intern(&mut self, ident: &str) -> Ident {
let hash = FnvBuildHasher::default().hash_one(ident) & 0xFFFFFFFF00000000; let (entry, hash) = self.lookup.entry(ident, &self.strings);
match self.lookup.raw_entry_mut().from_hash( match entry {
hash, hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|k| unsafe { self.strings.get_unchecked(ident::range(k.ident)) } == ident,
) {
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.ident,
hash_map::RawEntryMut::Vacant(v) => { hash_map::RawEntryMut::Vacant(v) => {
let id = ident::new(self.strings.len() as _, ident.len() as _); let id = ident::new(self.strings.len() as _, ident.len() as _);
self.strings.push_str(ident); self.strings.push_str(ident);
v.insert_hashed_nocheck( v.insert(ctx_map::Key { hash, value: id }, ());
hash,
IdentEntry { hash: (hash >> 32) as _, ident: id },
(),
);
id id
} }
} }
@ -646,49 +749,52 @@ impl IdentInterner {
} }
fn project(&self, ident: &str) -> Option<Ident> { fn project(&self, ident: &str) -> Option<Ident> {
let hash = FnvBuildHasher::default().hash_one(ident) & 0xFFFFFFFF00000000; self.lookup.get(ident, &self.strings).copied()
self.lookup
.raw_entry()
.from_hash(
hash,
|k| unsafe { self.strings.get_unchecked(ident::range(k.ident)) } == ident,
)
.map(|(k, _)| k.ident)
} }
} }
#[derive(Default)] #[derive(Default)]
struct Types { struct TypesTmp {
syms: HashMap<SymKey, ty::Id>, fields: Vec<Field>,
frontier: Vec<ty::Id>,
globals: Vec<ty::Global>,
funcs: Vec<ty::Func>,
}
#[derive(Default)]
pub struct TypeIns {
funcs: Vec<Func>, funcs: Vec<Func>,
args: Vec<ty::Id>, args: Vec<ty::Id>,
globals: Vec<Global>, globals: Vec<Global>,
structs: Vec<Struct>, structs: Vec<Struct>,
fields: Vec<Field>, fields: Vec<Field>,
field_names: IdentInterner,
ptrs: Vec<Ptr>, ptrs: Vec<Ptr>,
arrays: Vec<Array>, arrays: Vec<Array>,
}
fields_tmp: Vec<Field>, #[derive(Default)]
frontier_tmp: Vec<ty::Id>, struct Types {
reachable_globals: Vec<ty::Global>, syms: ctx_map::CtxMap<ty::Id>,
reachable_funcs: Vec<ty::Func>, names: IdentInterner,
ins: TypeIns,
tmp: TypesTmp,
} }
const HEADER_SIZE: usize = core::mem::size_of::<AbleOsExecutableHeader>(); const HEADER_SIZE: usize = core::mem::size_of::<AbleOsExecutableHeader>();
impl Types { impl Types {
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> { fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
let start = self.structs[strct as usize].field_start as usize; let start = self.ins.structs[strct as usize].field_start as usize;
let end = self let end = self
.ins
.structs .structs
.get(strct as usize + 1) .get(strct as usize + 1)
.map_or(self.fields.len(), |s| s.field_start as usize); .map_or(self.ins.fields.len(), |s| s.field_start as usize);
start..end start..end
} }
fn struct_fields(&self, strct: ty::Struct) -> &[Field] { fn struct_fields(&self, strct: ty::Struct) -> &[Field] {
&self.fields[self.struct_field_range(strct)] &self.ins.fields[self.struct_field_range(strct)]
} }
fn find_type( fn find_type(
@ -698,10 +804,10 @@ impl Types {
files: &[parser::Ast], files: &[parser::Ast],
) -> Option<ty::Id> { ) -> Option<ty::Id> {
if let Ok(id) = id 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() { if let ty::Kind::Global(g) = ty.expand() {
let g = &self.globals[g as usize]; let g = &self.ins.globals[g as usize];
if g.ty == ty::Id::TYPE { if g.ty == ty::Id::TYPE {
return Some(ty::Id::from( return Some(ty::Id::from(
u32::from_ne_bytes(*g.data.first_chunk().unwrap()) as u64 u32::from_ne_bytes(*g.data.first_chunk().unwrap()) as u64
@ -719,10 +825,10 @@ impl Types {
.find_pattern_path(name, right, |right| self.ty(file, right, files)) .find_pattern_path(name, right, |right| self.ty(file, right, files))
.unwrap_or_else(|_| unreachable!())?; .unwrap_or_else(|_| unreachable!())?;
if let ty::Kind::Struct(s) = ty.expand() { if let ty::Kind::Struct(s) = ty.expand() {
self.structs[s as usize].name = name; 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) Some(ty)
} }
@ -753,29 +859,30 @@ impl Types {
} }
Expr::Struct { pos, fields, packed, .. } => { Expr::Struct { pos, fields, packed, .. } => {
let sym = SymKey::Struct(file, pos); 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); return Some(ty);
} }
let prev_tmp = self.fields_tmp.len(); let prev_tmp = self.tmp.fields.len();
for field in fields.iter().filter_map(CommentOr::or) { for field in fields.iter().filter_map(CommentOr::or) {
let Some(ty) = self.ty(file, &field.ty, files) else { let Some(ty) = self.ty(file, &field.ty, files) else {
self.fields_tmp.truncate(prev_tmp); self.tmp.fields.truncate(prev_tmp);
return None; return None;
}; };
self.fields_tmp.push(Field { name: self.field_names.intern(field.name), ty }); self.tmp.fields.push(Field { name: self.names.intern(field.name), ty });
} }
self.structs.push(Struct { self.ins.structs.push(Struct {
file, file,
field_start: self.fields.len() as _, pos,
field_start: self.ins.fields.len() as _,
explicit_alignment: packed.then_some(1), explicit_alignment: packed.then_some(1),
..Default::default() ..Default::default()
}); });
self.fields.extend(self.fields_tmp.drain(prev_tmp..)); self.ins.fields.extend(self.tmp.fields.drain(prev_tmp..));
let ty = ty::Kind::Struct(self.structs.len() as u32 - 1).compress(); 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 ty
} }
_ => return None, _ => return None,
@ -788,62 +895,62 @@ impl Types {
emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
emit(to, instrs::tx()); emit(to, instrs::tx());
let exe = self.dump_reachable(0, to); 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::<AbleOsExecutableHeader>() = exe } unsafe { *to.as_mut_ptr().cast::<AbleOsExecutableHeader>() = exe }
} }
fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec<u8>) -> AbleOsExecutableHeader { fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec<u8>) -> AbleOsExecutableHeader {
debug_assert!(self.frontier_tmp.is_empty()); debug_assert!(self.tmp.frontier.is_empty());
debug_assert!(self.reachable_funcs.is_empty()); debug_assert!(self.tmp.funcs.is_empty());
debug_assert!(self.reachable_globals.is_empty()); debug_assert!(self.tmp.globals.is_empty());
self.frontier_tmp.push(ty::Kind::Func(from).compress()); self.tmp.frontier.push(ty::Kind::Func(from).compress());
while let Some(itm) = self.frontier_tmp.pop() { while let Some(itm) = self.tmp.frontier.pop() {
match itm.expand() { match itm.expand() {
ty::Kind::Func(func) => { 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) { if task::is_done(fuc.offset) {
continue; continue;
} }
fuc.offset = 0; fuc.offset = 0;
self.reachable_funcs.push(func); self.tmp.funcs.push(func);
self.frontier_tmp.extend(fuc.relocs.iter().map(|r| r.target)); self.tmp.frontier.extend(fuc.relocs.iter().map(|r| r.target));
} }
ty::Kind::Global(glob) => { ty::Kind::Global(glob) => {
let glb = &mut self.globals[glob as usize]; let glb = &mut self.ins.globals[glob as usize];
if task::is_done(glb.offset) { if task::is_done(glb.offset) {
continue; continue;
} }
glb.offset = 0; glb.offset = 0;
self.reachable_globals.push(glob); self.tmp.globals.push(glob);
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
for &func in &self.reachable_funcs { 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 _; fuc.offset = to.len() as _;
to.extend(&fuc.code); to.extend(&fuc.code);
} }
let code_length = to.len(); let code_length = to.len();
for global in self.reachable_globals.drain(..) { for global in self.tmp.globals.drain(..) {
let global = &mut self.globals[global as usize]; let global = &mut self.ins.globals[global as usize];
global.offset = to.len() as _; global.offset = to.len() as _;
to.extend(&global.data); to.extend(&global.data);
} }
let data_length = to.len() - code_length; let data_length = to.len() - code_length;
for func in self.reachable_funcs.drain(..) { 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 { for rel in &fuc.relocs {
let offset = match rel.target.expand() { 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.globals[glo as usize].offset, ty::Kind::Global(glo) => self.ins.globals[glo as usize].offset,
_ => unreachable!(), _ => unreachable!(),
}; };
rel.reloc.apply_jump(to, offset, fuc.offset); rel.reloc.apply_jump(to, offset, fuc.offset);
@ -870,6 +977,7 @@ impl Types {
) -> Result<(), hbbytecode::DisasmError<'a>> { ) -> Result<(), hbbytecode::DisasmError<'a>> {
use instrs::DisasmItem; use instrs::DisasmItem;
let functions = self let functions = self
.ins
.funcs .funcs
.iter() .iter()
.filter(|f| task::is_done(f.offset)) .filter(|f| task::is_done(f.offset))
@ -887,7 +995,7 @@ impl Types {
}; };
(f.offset, (name, f.code.len() as u32, DisasmItem::Func)) (f.offset, (name, f.code.len() as u32, DisasmItem::Func))
}) })
.chain(self.globals.iter().filter(|g| task::is_done(g.offset)).map(|g| { .chain(self.ins.globals.iter().filter(|g| task::is_done(g.offset)).map(|g| {
let name = if g.file == u32::MAX { let name = if g.file == u32::MAX {
core::str::from_utf8(&g.data).unwrap() core::str::from_utf8(&g.data).unwrap()
} else { } else {
@ -909,12 +1017,23 @@ impl Types {
} }
fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr { fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr {
self.syms let ptr = Ptr { base };
.entry(SymKey::Pointer(base)) let (entry, hash) = self.syms.entry(SymKey::Pointer(&ptr), &self.ins);
.or_insert_with(|| { match entry {
self.ptrs.push(Ptr { base }); hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
ty::Kind::Ptr(self.ptrs.len() as u32 - 1).compress() 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() .expand()
.inner() .inner()
} }
@ -925,13 +1044,32 @@ impl Types {
fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice { fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice {
self.syms self.syms
.entry(SymKey::Array(ty, len)) .get_or_insert(SymKey::Array(&Array { ty, len }), &mut self.ins, |ins| {
.or_insert_with(|| { ins.arrays.push(Array { ty, len });
self.arrays.push(Array { ty, len }); ty::Kind::Slice(ins.arrays.len() as u32 - 1).compress()
ty::Kind::Slice(self.arrays.len() as u32 - 1).compress()
}) })
.expand() .expand()
.inner() .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 { fn size_of(&self, ty: ty::Id) -> Size {
@ -944,7 +1082,7 @@ impl Types {
ty::Kind::Builtin(ty::I16 | ty::U16) => 2, ty::Kind::Builtin(ty::I16 | ty::U16) => 2,
ty::Kind::Builtin(ty::I8 | ty::U8 | ty::BOOL) => 1, ty::Kind::Builtin(ty::I8 | ty::U8 | ty::BOOL) => 1,
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = &self.arrays[arr as usize]; let arr = &self.ins.arrays[arr as usize];
match arr.len { match arr.len {
0 => 0, 0 => 0,
ArrayLen::MAX => 16, ArrayLen::MAX => 16,
@ -952,13 +1090,13 @@ impl Types {
} }
} }
ty::Kind::Struct(stru) => { ty::Kind::Struct(stru) => {
if self.structs[stru as usize].size.get() != 0 { if self.ins.structs[stru as usize].size.get() != 0 {
return self.structs[stru as usize].size.get(); return self.ins.structs[stru as usize].size.get();
} }
let mut oiter = OffsetIter::new(stru, self); let mut oiter = OffsetIter::new(stru, self);
while oiter.next(self).is_some() {} while oiter.next(self).is_some() {}
self.structs[stru as usize].size.set(oiter.offset); self.ins.structs[stru as usize].size.set(oiter.offset);
oiter.offset oiter.offset
} }
ty => unimplemented!("size_of: {:?}", ty), ty => unimplemented!("size_of: {:?}", ty),
@ -968,10 +1106,10 @@ impl Types {
fn align_of(&self, ty: ty::Id) -> Size { fn align_of(&self, ty: ty::Id) -> Size {
match ty.expand() { match ty.expand() {
ty::Kind::Struct(stru) => { ty::Kind::Struct(stru) => {
if self.structs[stru as usize].align.get() != 0 { if self.ins.structs[stru as usize].align.get() != 0 {
return self.structs[stru as usize].align.get() as _; return self.ins.structs[stru as usize].align.get() as _;
} }
let align = self.structs[stru as usize].explicit_alignment.map_or_else( let align = self.ins.structs[stru as usize].explicit_alignment.map_or_else(
|| { || {
self.struct_fields(stru) self.struct_fields(stru)
.iter() .iter()
@ -981,11 +1119,11 @@ impl Types {
}, },
|a| a as _, |a| a as _,
); );
self.structs[stru as usize].align.set(align.try_into().unwrap()); self.ins.structs[stru as usize].align.set(align.try_into().unwrap());
align align
} }
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = &self.arrays[arr as usize]; let arr = &self.ins.arrays[arr as usize];
match arr.len { match arr.len {
ArrayLen::MAX => 8, ArrayLen::MAX => 8,
_ => self.align_of(arr.ty), _ => self.align_of(arr.ty),
@ -997,13 +1135,13 @@ impl Types {
fn base_of(&self, ty: ty::Id) -> Option<ty::Id> { fn base_of(&self, ty: ty::Id) -> Option<ty::Id> {
match ty.expand() { match ty.expand() {
ty::Kind::Ptr(p) => Some(self.ptrs[p as usize].base), ty::Kind::Ptr(p) => Some(self.ins.ptrs[p as usize].base),
_ => None, _ => None,
} }
} }
fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> { fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> {
let name = self.field_names.project(name)?; let name = self.names.project(name)?;
self.struct_fields(s).iter().position(|f| f.name == name) self.struct_fields(s).iter().position(|f| f.name == name)
} }
} }
@ -1020,7 +1158,7 @@ impl OffsetIter {
} }
fn offset_of(tys: &Types, idx: ty::Struct, field: &str) -> Option<(Offset, ty::Id)> { fn offset_of(tys: &Types, idx: ty::Struct, field: &str) -> Option<(Offset, ty::Id)> {
let field_id = tys.field_names.project(field)?; let field_id = tys.names.project(field)?;
OffsetIter::new(idx, tys) OffsetIter::new(idx, tys)
.into_iter(tys) .into_iter(tys)
.find(|(f, _)| f.name == field_id) .find(|(f, _)| f.name == field_id)
@ -1028,8 +1166,8 @@ impl OffsetIter {
} }
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> { fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> {
let stru = &tys.structs[self.strct as usize]; let stru = &tys.ins.structs[self.strct as usize];
let field = &tys.fields[self.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); 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); self.offset = (self.offset + align - 1) & !(align - 1);

View file

@ -1,5 +1,6 @@
use { use {
crate::{ crate::{
ctx_map::CtxEntry,
ident::Ident, ident::Ident,
instrs, instrs,
lexer::{self, TokenKind}, lexer::{self, TokenKind},
@ -11,7 +12,7 @@ use {
task, task,
ty::{self}, ty::{self},
vc::{BitSet, Vc}, vc::{BitSet, Vc},
Func, HashMap, IdentityHasher, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types, Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
}, },
alloc::{borrow::ToOwned, string::String, vec::Vec}, alloc::{borrow::ToOwned, string::String, vec::Vec},
core::{ core::{
@ -19,13 +20,10 @@ use {
cell::RefCell, cell::RefCell,
convert::identity, convert::identity,
fmt::{self, Debug, Display, Write}, fmt::{self, Debug, Display, Write},
format_args as fa, format_args as fa, mem, ops,
hash::{BuildHasher, Hasher},
mem, ops,
}, },
hashbrown::hash_map, hashbrown::hash_map,
regalloc2::VReg, regalloc2::VReg,
std::process::id,
}; };
const VOID: Nid = 0; const VOID: Nid = 0;
@ -44,19 +42,17 @@ pub mod reg {
pub type Reg = u8; pub type Reg = u8;
} }
struct LookupEntry { type Lookup = crate::ctx_map::CtxMap<Nid>;
nid: Nid,
hash: u64,
}
impl core::hash::Hash for LookupEntry { impl crate::ctx_map::CtxEntry for Nid {
fn hash<H: Hasher>(&self, state: &mut H) { type Ctx = [Result<Node, Nid>];
state.write_u64(self.hash); type Key<'a> = (Kind, &'a [Nid], ty::Id);
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
ctx[*self as usize].as_ref().unwrap().key()
} }
} }
type Lookup = hashbrown::HashMap<LookupEntry, (), core::hash::BuildHasherDefault<IdentityHasher>>;
struct Nodes { struct Nodes {
values: Vec<Result<Node, Nid>>, values: Vec<Result<Node, Nid>>,
visited: BitSet, visited: BitSet,
@ -106,10 +102,10 @@ impl Nodes {
let mut lookup_meta = None; let mut lookup_meta = None;
if !node.is_lazy_phi() { if !node.is_lazy_phi() {
let (raw_entry, hash) = Self::find_node(&mut self.lookup, &self.values, &node); let (raw_entry, hash) = self.lookup.entry(node.key(), &self.values);
let entry = match raw_entry { let entry = match raw_entry {
hash_map::RawEntryMut::Occupied(o) => return o.get_key_value().0.nid, hash_map::RawEntryMut::Occupied(o) => return o.get_key_value().0.value,
hash_map::RawEntryMut::Vacant(v) => v, hash_map::RawEntryMut::Vacant(v) => v,
}; };
@ -129,38 +125,14 @@ impl Nodes {
self.free = mem::replace(&mut self.values[free as usize], Ok(node)).unwrap_err(); self.free = mem::replace(&mut self.values[free as usize], Ok(node)).unwrap_err();
if let Some((entry, hash)) = lookup_meta { if let Some((entry, hash)) = lookup_meta {
entry.insert(LookupEntry { nid: free, hash }, ()); entry.insert(crate::ctx_map::Key { value: free, hash }, ());
} }
free free
} }
fn find_node<'a>(
lookup: &'a mut Lookup,
values: &[Result<Node, Nid>],
node: &Node,
) -> (
hash_map::RawEntryMut<'a, LookupEntry, (), core::hash::BuildHasherDefault<IdentityHasher>>,
u64,
) {
let hash = crate::FnvBuildHasher::default().hash_one(node.key());
let entry = lookup
.raw_entry_mut()
.from_hash(hash, |n| values[n.nid as usize].as_ref().unwrap().key() == node.key());
(entry, hash)
}
fn remove_node_lookup(&mut self, target: Nid) { fn remove_node_lookup(&mut self, target: Nid) {
if !self[target].is_lazy_phi() { if !self[target].is_lazy_phi() {
match Self::find_node( self.lookup.remove(&target, &self.values).unwrap();
&mut self.lookup,
&self.values,
self.values[target as usize].as_ref().unwrap(),
)
.0
{
hash_map::RawEntryMut::Occupied(o) => o.remove(),
hash_map::RawEntryMut::Vacant(_) => unreachable!(),
};
} }
} }
@ -379,20 +351,16 @@ impl Nodes {
let prev = self[target].inputs[inp_index]; let prev = self[target].inputs[inp_index];
self[target].inputs[inp_index] = with; self[target].inputs[inp_index] = with;
let (entry, hash) = Self::find_node( let (entry, hash) = self.lookup.entry(target.key(&self.values), &self.values);
&mut self.lookup,
&self.values,
self.values[target as usize].as_ref().unwrap(),
);
match entry { match entry {
hash_map::RawEntryMut::Occupied(other) => { hash_map::RawEntryMut::Occupied(other) => {
let rpl = other.get_key_value().0.nid; let rpl = other.get_key_value().0.value;
self[target].inputs[inp_index] = prev; self[target].inputs[inp_index] = prev;
self.replace(target, rpl); self.replace(target, rpl);
rpl rpl
} }
hash_map::RawEntryMut::Vacant(slot) => { hash_map::RawEntryMut::Vacant(slot) => {
slot.insert(LookupEntry { nid: target, hash }, ()); slot.insert(crate::ctx_map::Key { value: target, hash }, ());
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap(); let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
self[prev].outputs.swap_remove(index); self[prev].outputs.swap_remove(index);
self[with].outputs.push(target); self[with].outputs.push(target);
@ -845,7 +813,7 @@ impl fmt::Display for Kind {
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
//#[repr(align(64))] //#[repr(align(64))]
struct Node { pub struct Node {
kind: Kind, kind: Kind,
inputs: Vc, inputs: Vc,
outputs: Vc, outputs: Vc,
@ -1063,7 +1031,7 @@ impl Codegen {
} }
fn make_func_reachable(&mut self, func: ty::Func) { 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 { if fuc.offset == u32::MAX {
fuc.offset = task::id(self.tasks.len() as _); fuc.offset = task::id(self.tasks.len() as _);
self.tasks.push(Some(FTask { file: fuc.file, id: func })); self.tasks.push(Some(FTask { file: fuc.file, id: func }));
@ -1144,7 +1112,7 @@ impl Codegen {
.tys .tys
.struct_fields(s) .struct_fields(s)
.iter() .iter()
.map(|f| self.tys.field_names.ident_str(f.name)) .map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '") .intersperse("', '")
.collect::<String>(); .collect::<String>();
self.report( self.report(
@ -1267,7 +1235,7 @@ impl Codegen {
self.make_func_reachable(func); 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 sig = fuc.sig.expect("TODO: generic functions");
let ast = self.files[fuc.file as usize].clone(); let ast = self.files[fuc.file as usize].clone();
let Expr::BinOp { right: &Expr::Closure { args: cargs, .. }, .. } = let Expr::BinOp { right: &Expr::Closure { args: cargs, .. }, .. } =
@ -1289,7 +1257,7 @@ impl Codegen {
let mut inps = Vc::from([self.ci.ctrl]); let mut inps = Vc::from([self.ci.ctrl]);
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) { 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 { if self.tys.size_of(ty) == 0 {
continue; continue;
} }
@ -1374,7 +1342,7 @@ impl Codegen {
.iter() .iter()
.zip(offs) .zip(offs)
.filter(|&(_, (ty, _))| ty != ty::Id::UNDECLARED) .filter(|&(_, (ty, _))| ty != ty::Id::UNDECLARED)
.map(|(f, _)| self.tys.field_names.ident_str(f.name)) .map(|(f, _)| self.tys.names.ident_str(f.name))
.intersperse(", ") .intersperse(", ")
.collect::<String>(); .collect::<String>();
@ -1669,7 +1637,7 @@ impl Codegen {
} }
fn emit_func(&mut self, FTask { file, id }: FTask) { 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; func.offset = u32::MAX - 1;
debug_assert!(func.file == file); debug_assert!(func.file == file);
let sig = func.sig.unwrap(); let sig = func.sig.unwrap();
@ -1706,7 +1674,7 @@ impl Codegen {
let mut sig_args = sig.args.range(); let mut sig_args = sig.args.range();
for (arg, index) in args.iter().zip(0u32..) { 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]); let value = self.ci.nodes.new_node(ty, Kind::Arg { index }, [VOID]);
self.ci.nodes.lock(value); self.ci.nodes.lock(value);
let sym = parser::find_symbol(&ast.symbols, arg.id); let sym = parser::find_symbol(&ast.symbols, arg.id);
@ -1832,8 +1800,8 @@ impl Codegen {
self.ci.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0)); 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.ins.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].relocs.append(&mut self.ci.relocs);
self.ci.nodes.clear(); self.ci.nodes.clear();
self.ci.filled.clear(); self.ci.filled.clear();
self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci)); self.pool.cis.push(core::mem::replace(&mut self.ci, prev_ci));
@ -2042,9 +2010,9 @@ impl Codegen {
}; };
let key = SymKey::Decl(file, ident); 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() 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) && let Err(idx) = task::unpack(func.offset)
&& idx < self.tasks.len() && idx < self.tasks.len()
{ {
@ -2058,19 +2026,20 @@ impl Codegen {
let prev_file = core::mem::replace(&mut self.ci.file, file); let prev_file = core::mem::replace(&mut self.ci.file, file);
let sym = match expr { let sym = match expr {
Expr::BinOp { Expr::BinOp {
left: Expr::Ident { .. }, left: &Expr::Ident { id, .. },
op: TokenKind::Decl, op: TokenKind::Decl,
right: &Expr::Closure { pos, args, ret, .. }, right: &Expr::Closure { pos, args, ret, .. },
} => { } => {
let func = Func { let func = Func {
file, file,
name: id,
sig: '_b: { sig: '_b: {
let arg_base = self.tys.args.len(); let arg_base = self.tys.ins.args.len();
for arg in args { for arg in args {
let sym = parser::find_symbol(&f.symbols, arg.id); let sym = parser::find_symbol(&f.symbols, arg.id);
assert!(sym.flags & idfl::COMPTIME == 0, "TODO"); assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
let ty = self.ty(&arg.ty); 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 { let Some(args) = self.pack_args(arg_base) else {
@ -2091,8 +2060,8 @@ impl Codegen {
..Default::default() ..Default::default()
}; };
let id = self.tys.funcs.len() as _; let id = self.tys.ins.funcs.len() as _;
self.tys.funcs.push(func); self.tys.ins.funcs.push(func);
ty::Kind::Func(id) ty::Kind::Func(id)
} }
@ -2104,7 +2073,7 @@ impl Codegen {
e => unimplemented!("{e:#?}"), e => unimplemented!("{e:#?}"),
}; };
self.ci.file = prev_file; self.ci.file = prev_file;
self.tys.syms.insert(key, sym.compress()); self.tys.syms.insert(key, sym.compress(), &self.tys.ins);
sym sym
} }
@ -2183,15 +2152,15 @@ impl Codegen {
} }
fn pack_args(&mut self, arg_base: usize) -> Option<ty::Tuple> { fn pack_args(&mut self, arg_base: usize) -> Option<ty::Tuple> {
let needle = &self.tys.args[arg_base..]; let needle = &self.tys.ins.args[arg_base..];
if needle.is_empty() { if needle.is_empty() {
return Some(ty::Tuple::empty()); return Some(ty::Tuple::empty());
} }
let len = needle.len(); let len = needle.len();
// FIXME: maybe later when this becomes a bottleneck we use more // FIXME: maybe later when this becomes a bottleneck we use more
// efficient search (SIMD?, indexing?) // efficient search (SIMD?, indexing?)
let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap(); let sp = self.tys.ins.args.windows(needle.len()).position(|val| val == needle).unwrap();
self.tys.args.truncate((sp + needle.len()).max(arg_base)); self.tys.ins.args.truncate((sp + needle.len()).max(arg_base));
ty::Tuple::new(sp, len) ty::Tuple::new(sp, len)
} }
@ -2427,7 +2396,7 @@ impl<'a> Function<'a> {
for (arg, ti) in for (arg, ti) in
self.nodes[VOID].clone().outputs.into_iter().skip(2).zip(self.sig.args.range()) 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) { match self.tys.size_of(ty) {
0 => continue, 0 => continue,
1..=8 => { 1..=8 => {
@ -2476,7 +2445,7 @@ impl<'a> Function<'a> {
self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref;
let mut ops = vec![]; 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 { if self.tys.size_of(fuc.ret) != 0 {
self.def_nid(nid); self.def_nid(nid);
ops.push(regalloc2::Operand::reg_fixed_def( ops.push(regalloc2::Operand::reg_fixed_def(
@ -2487,7 +2456,7 @@ impl<'a> Function<'a> {
let mut parama = self.tys.parama(fuc.ret); let mut parama = self.tys.parama(fuc.ret);
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) { 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 { loop {
match self.nodes[i].kind { match self.nodes[i].kind {
Kind::Stre { .. } => i = self.nodes[i].inputs[2], Kind::Stre { .. } => i = self.nodes[i].inputs[2],