calculate which nodes are comptime evaluable

This commit is contained in:
Janis 2024-09-16 00:15:39 +02:00
parent 888517f2ea
commit 5ad0e9e8e7

View file

@ -1938,6 +1938,37 @@ impl Display for Children {
}
type TypeCache = BTreeMap<Index, intern::Index>;
// type ComptimeCache = BTreeMap<Index, bool>;
#[derive(Debug, Default)]
struct ComptimeCache {
inner: BTreeMap<Index, bool>,
// this is (a,b) where b dominates a
// meaning:
// when a is marked as runtime, b can be updated to be runtime as well.
dependencies: BTreeMap<Index, Index>,
}
impl ComptimeCache {
fn get(&self, key: &Index) -> Option<bool> {
self.inner.get(key).cloned()
}
fn insert(&mut self, key: Index, value: bool) {
self.inner.insert(key, value);
if !value {
self.set_runtime(key);
}
}
fn mark_as_dominated_by(&mut self, a: Index, b: Index) {
self.dependencies.insert(a, b);
}
fn set_runtime(&mut self, key: Index) {
self.inner.insert(key, false);
if let Some(&dom) = self.dependencies.get(&key) {
self.set_runtime(dom);
}
}
}
impl Ast {
fn get_type_of_node(
@ -2241,83 +2272,185 @@ impl Ast {
}
}
fn comptime_value_of_node(
&self,
ip: &InternPool,
pointer_bits: u16,
cache: &mut TypeCache,
index: Index,
) -> crate::comptime::ComptimeNumber {
let tag = self.tags[index.index()];
let data = self.datas[index.index()];
fn is_node_comptime_evaluable(&self, cache: &mut ComptimeCache, index: Index) -> bool {
if let Some(a) = cache.get(&index) {
a
} else {
let tag = self.tags[index.index()];
let data = self.datas[index.index()];
match tag {
Tag::Root => todo!(),
Tag::File => todo!(),
Tag::FunctionProto => todo!(),
Tag::FunctionDecl => todo!(),
Tag::ParameterList => todo!(),
Tag::Parameter => todo!(),
Tag::Block => todo!(),
Tag::BlockTrailingExpr => todo!(),
Tag::Constant => {
let (ty, value) = data.as_index_intern();
let ty = self.get_type_of_node(ip, cache, ty);
interned_type_and_value_to_comptime_number(ip, pointer_bits, ty, value)
}
Tag::ExprStmt => todo!(),
Tag::ReturnStmt => todo!(),
Tag::ReturnExprStmt => todo!(),
Tag::VarDecl => todo!(),
Tag::MutVarDecl => todo!(),
Tag::VarDeclAssignment => todo!(),
Tag::MutVarDeclAssignment => todo!(),
Tag::GlobalDecl => todo!(),
Tag::StructDecl => todo!(),
Tag::FieldDecl => todo!(),
Tag::DeclRef => todo!(),
Tag::DeclRefUnresolved => todo!(),
Tag::InternedType => todo!(),
Tag::TypeDeclRef => todo!(),
Tag::TypeDeclRefUnresolved => todo!(),
Tag::PointerType => todo!(),
Tag::ArrayType => todo!(),
Tag::CallExpr => todo!(),
Tag::FieldAccess => todo!(),
Tag::ArgumentList => todo!(),
Tag::Argument => todo!(),
Tag::NamedArgument => todo!(),
Tag::ExplicitCast => todo!(),
Tag::Deref => todo!(),
Tag::AddressOf => todo!(),
Tag::Not => todo!(),
Tag::Negate => todo!(),
Tag::Or => todo!(),
Tag::And => todo!(),
Tag::BitOr => todo!(),
Tag::BitXOr => todo!(),
Tag::BitAnd => todo!(),
Tag::Eq => todo!(),
Tag::NEq => todo!(),
Tag::Lt => todo!(),
Tag::Gt => todo!(),
Tag::Le => todo!(),
Tag::Ge => todo!(),
Tag::Shl => todo!(),
Tag::Shr => todo!(),
Tag::Add => todo!(),
Tag::Sub => todo!(),
Tag::Mul => todo!(),
Tag::Div => todo!(),
Tag::Rem => todo!(),
Tag::Assign => todo!(),
Tag::SubscriptExpr => todo!(),
Tag::IfExpr => todo!(),
Tag::IfElseExpr => todo!(),
Tag::Error => todo!(),
Tag::Undefined => todo!(),
let children = self.get_node_children(index);
let are_children_comptime = |this: &Self, cache: &mut ComptimeCache| {
children
.iter()
.all(|&i| this.is_node_comptime_evaluable(cache, i))
};
let is_comptime = match tag {
Tag::Parameter => false,
Tag::Block | Tag::BlockTrailingExpr => are_children_comptime(self, cache),
Tag::Constant => true,
Tag::ReturnStmt => true,
Tag::ReturnExprStmt => are_children_comptime(self, cache),
Tag::VarDecl | Tag::MutVarDecl => true,
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
are_children_comptime(self, cache)
}
Tag::GlobalDecl => true,
Tag::StructDecl => true,
Tag::FieldDecl => true,
Tag::DeclRef => self.tags[data.as_index().index()] == Tag::GlobalDecl,
Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true,
Tag::CallExpr => false,
Tag::FieldAccess => {
let parent = data.as_index_intern().0;
cache.mark_as_dominated_by(index, parent);
self.is_node_comptime_evaluable(cache, parent)
}
Tag::ArgumentList => are_children_comptime(self, cache),
Tag::Argument => self.is_node_comptime_evaluable(cache, data.as_index()),
Tag::NamedArgument => {
self.is_node_comptime_evaluable(cache, data.as_index_intern().0)
}
Tag::ExplicitCast => {
self.is_node_comptime_evaluable(cache, data.as_two_indices().0)
}
Tag::Deref | Tag::AddressOf => false,
Tag::Not
| Tag::Negate
| Tag::Or
| Tag::And
| Tag::BitOr
| Tag::BitXOr
| Tag::BitAnd
| Tag::Eq
| Tag::NEq
| Tag::Lt
| Tag::Gt
| Tag::Le
| Tag::Ge
| Tag::Shl
| Tag::Shr
| Tag::Add
| Tag::Sub
| Tag::Mul
| Tag::Div
| Tag::SubscriptExpr
| Tag::Rem => are_children_comptime(self, cache),
Tag::Assign => {
let (left, _) = data.as_two_indices();
cache.mark_as_dominated_by(index, left);
are_children_comptime(self, cache)
}
Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache),
Tag::Root
| Tag::File
| Tag::FunctionProto
| Tag::FunctionDecl
| Tag::ParameterList
| Tag::ExprStmt
| Tag::DeclRefUnresolved
| Tag::TypeDeclRefUnresolved
| Tag::Error
| Tag::Undefined => false,
};
cache.insert(index, is_comptime);
is_comptime
}
}
// fn comptime_value_of_node(
// &self,
// ip: &InternPool,
// pointer_bits: u16,
// cache: &mut TypeCache,
// index: Index,
// ) -> crate::comptime::ComptimeNumber {
// let tag = self.tags[index.index()];
// let data = self.datas[index.index()];
// match tag {
// Tag::Root => todo!(),
// Tag::File => todo!(),
// Tag::FunctionProto => todo!(),
// Tag::FunctionDecl => todo!(),
// Tag::ParameterList => todo!(),
// Tag::Parameter => todo!(),
// Tag::Block => todo!(),
// Tag::BlockTrailingExpr => {
// let (a, b) = data.as_extra_range();
// if a != b {
// self.comptime_value_of_node(
// ip,
// pointer_bits,
// cache,
// Index::new(self.extra[b - 1]),
// )
// } else {
// None
// }
// }
// Tag::Constant => {
// let (ty, value) = data.as_index_intern();
// let ty = self.get_type_of_node(ip, cache, ty);
// interned_type_and_value_to_comptime_number(ip, pointer_bits, ty, value)
// }
// Tag::ExprStmt => todo!(),
// Tag::ReturnStmt => todo!(),
// Tag::ReturnExprStmt => todo!(),
// Tag::VarDecl => todo!(),
// Tag::MutVarDecl => todo!(),
// Tag::VarDeclAssignment => todo!(),
// Tag::MutVarDeclAssignment => todo!(),
// Tag::GlobalDecl => todo!(),
// Tag::StructDecl => todo!(),
// Tag::FieldDecl => todo!(),
// Tag::DeclRef => todo!(),
// Tag::DeclRefUnresolved => todo!(),
// Tag::InternedType => todo!(),
// Tag::TypeDeclRef => todo!(),
// Tag::TypeDeclRefUnresolved => todo!(),
// Tag::PointerType => todo!(),
// Tag::ArrayType => todo!(),
// Tag::CallExpr => todo!(),
// Tag::FieldAccess => todo!(),
// Tag::ArgumentList => todo!(),
// Tag::Argument => todo!(),
// Tag::NamedArgument => todo!(),
// Tag::ExplicitCast => todo!(),
// Tag::Deref => todo!(),
// Tag::AddressOf => todo!(),
// Tag::Not => todo!(),
// Tag::Negate => todo!(),
// Tag::Or => todo!(),
// Tag::And => todo!(),
// Tag::BitOr => todo!(),
// Tag::BitXOr => todo!(),
// Tag::BitAnd => todo!(),
// Tag::Eq => todo!(),
// Tag::NEq => todo!(),
// Tag::Lt => todo!(),
// Tag::Gt => todo!(),
// Tag::Le => todo!(),
// Tag::Ge => todo!(),
// Tag::Shl => todo!(),
// Tag::Shr => todo!(),
// Tag::Add => todo!(),
// Tag::Sub => todo!(),
// Tag::Mul => todo!(),
// Tag::Div => todo!(),
// Tag::Rem => todo!(),
// Tag::Assign => todo!(),
// Tag::SubscriptExpr => todo!(),
// Tag::IfExpr => todo!(),
// Tag::IfElseExpr => todo!(),
// Tag::Error => todo!(),
// Tag::Undefined => todo!(),
// }
// }
}
fn interned_type_and_value_to_comptime_number(
@ -2464,6 +2597,7 @@ pub struct AstRenderer<'a> {
ip: &'a InternPool,
scopes: Vec<Index>,
cache: TypeCache,
comptime_cache: ComptimeCache,
}
impl<'a> AstRenderer<'a> {
@ -2478,6 +2612,7 @@ impl<'a> AstRenderer<'a> {
ip,
scopes: Vec::new(),
cache: TypeCache::new(),
comptime_cache: ComptimeCache::default(),
}
}
@ -2498,7 +2633,15 @@ impl<'a> AstRenderer<'a> {
let children = Children(self.ast.get_node_children(node));
let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node);
writeln_indented!(indent, w, "{node} ({ty}) = ({loc}) {tag:?} {}", children)?;
let is_comptime = self
.ast
.is_node_comptime_evaluable(&mut self.comptime_cache, node);
writeln_indented!(
indent * 2,
w,
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
if is_comptime { "CONST " } else { "" }
)?;
for child in children.0 {
self.render_node(w, indent + 1, child)?;
@ -2577,7 +2720,14 @@ pub mod ast_gen {
AstRenderer::new(&self.ast, &self.intern, &self.syms)
}
pub fn fold_and_typecheck(&mut self) {}
pub fn fold_and_typecheck(&mut self) {
enum Asdf {
Pre(Index),
Post(Index),
}
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
let mut cache = TypeCache::new();
}
pub fn intern_types(&mut self) {
let mut nodes = self
@ -2611,6 +2761,7 @@ pub mod ast_gen {
let pointee = self.ast.datas[pointee.index()].as_intern();
variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags });
// get interened value from constant node
let length = {
let value = self.ast.datas[length.index()].as_index_intern().1;