making compiler a bit smarter about evaluating types (more shortcuts)

This commit is contained in:
Jakub Doka 2024-10-01 17:43:15 +02:00
parent d293e02f62
commit b2254e9820
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
4 changed files with 149 additions and 93 deletions

View file

@ -736,9 +736,17 @@ impl Codegen {
fn build_struct(
&mut self,
file: FileId,
pos: Option<Pos>,
explicit_alignment: Option<u8>,
fields: &[CommentOr<StructField>],
) -> 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))
{
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))
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<T, E>(
@ -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 =

View file

@ -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<u8>, (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<u8>,
}
@ -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<Ident, &str>,
files: &[parser::Ast],
) -> Option<ty::Id> {
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<ty::Id> {
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()

View file

@ -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<F: FnOnce(&Expr)>(
pub fn find_pattern_path<T, F: FnOnce(&Expr) -> T>(
&self,
ident: Ident,
target: &Expr,
mut with_final: F,
) -> Result<(), F> {
) -> Result<T, F> {
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<T: Copy>(&mut self, _view: &mut StackAllocView<T>, value: T) {
if unlikely(self.len + core::mem::size_of::<T>() > self.cap) {
let next_cap = self.cap.max(16 * 32).max(std::mem::size_of::<T>()) * 2;
let next_cap = self.cap.max(16 * 32).max(core::mem::size_of::<T>()) * 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::<T>(),
std::mem::align_of::<T>(),
self.len,
self.cap
);
debug_assert!(dst.is_aligned(),);
self.len += core::mem::size_of::<T>();
core::ptr::write(dst, value);
}

View file

@ -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
}