From 1a20acd76303642485785879dfc30618697adf04 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 4 Mar 2025 18:58:55 +0100 Subject: [PATCH] ast visiting for IR building --- src/ast2/intern.rs | 11 + src/ast2/mod.rs | 1195 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + src/triples.rs | 4 +- 4 files changed, 1210 insertions(+), 2 deletions(-) diff --git a/src/ast2/intern.rs b/src/ast2/intern.rs index 1795b9a..bb15a39 100644 --- a/src/ast2/intern.rs +++ b/src/ast2/intern.rs @@ -574,6 +574,17 @@ pub struct TypeInfo { pub signed: bool, } +impl TypeInfo { + /// byte size + pub fn size(&self) -> u32 { + self.bitsize.div_ceil(8) + } + /// byte align + pub fn align(&self) -> u32 { + self.bitalign.div_ceil(8) + } +} + impl InternPool { pub fn peer_type(&mut self, lhs: Index, rhs: Index) -> Option { if lhs == rhs { diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 02690a1..0e9b4f6 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -4225,6 +4225,1201 @@ pub mod ast_gen { } } +impl Ast { + fn visit_all_functions_mut(&mut self, visitor: &mut impl AstVisitorTrait) { + for i in + (0..self.tags.functions.len()).map(|i| Index::new(Kind::Function, i as u32).unwrap()) + { + visitor.visit_function_decl(self, i); + } + } + + fn visit_function_mut(&mut self) {} +} + +pub trait AstVisitorTrait { + type Error; + type Value; + const UNIMPL: Self::Error; + + fn visit_function_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_parameter(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_parameter_list( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block_trailing_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block_maybe_trailing( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::BlockTrailingExpr => self.visit_block(ast, idx), + Tag::Block => self.visit_block_trailing_expr(ast, idx), + _ => unreachable!(), + } + } + fn visit_function_proto( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_call_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_add_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_sub_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mul_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_div_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_rem_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_eq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_neq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_lt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_gt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_le_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_ge_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_shl_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_shr_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitxor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitand_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_or_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_and_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_not_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_negate_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_deref_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_address_of_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_explicit_cast_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_assign(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_subscript_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_if_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_if_else_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_argument(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_any_argument( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::Argument => self.visit_argument(ast, idx), + Tag::NamedArgument => self.visit_named_argument(ast, idx), + _ => unreachable!(), + } + } + + fn visit_named_argument( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_argument_list( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_constant(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_return(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_global_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_var_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mut_var_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_var_assign_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mut_var_assign_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_decl_ref(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_any(&mut self, ast: &mut Ast, idx: Index) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::FunctionProto => self.visit_function_proto(ast, idx), + Tag::FunctionDecl => self.visit_function_decl(ast, idx), + Tag::ParameterList => self.visit_parameter_list(ast, idx), + Tag::Parameter => self.visit_parameter(ast, idx), + Tag::Block => self.visit_block(ast, idx), + Tag::BlockTrailingExpr => self.visit_block_trailing_expr(ast, idx), + Tag::Constant => self.visit_constant(ast, idx), + Tag::ExprStmt => todo!(), + Tag::ReturnStmt => self.visit_return(ast, idx), + Tag::ReturnExprStmt => self.visit_return_expr(ast, idx), + Tag::VarDecl => self.visit_var_decl(ast, idx), + Tag::MutVarDecl => self.visit_mut_var_decl(ast, idx), + Tag::VarDeclAssignment => self.visit_var_assign_decl(ast, idx), + Tag::MutVarDeclAssignment => self.visit_mut_var_assign_decl(ast, idx), + Tag::GlobalDecl => self.visit_global_decl(ast, idx), + Tag::StructDecl => todo!(), + Tag::FieldDecl => todo!(), + Tag::DeclRef => self.visit_decl_ref(ast, idx), + Tag::DeclRefUnresolved => todo!(), + Tag::InternedType => todo!(), + Tag::TypeDeclRef => todo!(), + Tag::TypeDeclRefUnresolved => todo!(), + Tag::PointerType => todo!(), + Tag::ArrayType => todo!(), + Tag::CallExpr => self.visit_call_expr(ast, idx), + Tag::FieldAccess => todo!(), + Tag::ArgumentList => self.visit_argument_list(ast, idx), + Tag::Argument => self.visit_argument(ast, idx), + Tag::NamedArgument => self.visit_named_argument(ast, idx), + Tag::ExplicitCast => self.visit_explicit_cast_expr(ast, idx), + Tag::Deref => self.visit_deref_expr(ast, idx), + Tag::AddressOf => self.visit_add_expr(ast, idx), + Tag::Not => self.visit_not_expr(ast, idx), + Tag::Negate => self.visit_negate_expr(ast, idx), + Tag::Or => self.visit_or_expr(ast, idx), + Tag::And => self.visit_and_expr(ast, idx), + Tag::BitOr => self.visit_bitor_expr(ast, idx), + Tag::BitXOr => self.visit_bitxor_expr(ast, idx), + Tag::BitAnd => self.visit_bitand_expr(ast, idx), + Tag::Eq => self.visit_eq_expr(ast, idx), + Tag::NEq => self.visit_neq_expr(ast, idx), + Tag::Lt => self.visit_lt_expr(ast, idx), + Tag::Gt => self.visit_gt_expr(ast, idx), + Tag::Le => self.visit_le_expr(ast, idx), + Tag::Ge => self.visit_ge_expr(ast, idx), + Tag::Shl => self.visit_shl_expr(ast, idx), + Tag::Shr => self.visit_shr_expr(ast, idx), + Tag::Add => self.visit_add_expr(ast, idx), + Tag::Sub => self.visit_sub_expr(ast, idx), + Tag::Mul => self.visit_mul_expr(ast, idx), + Tag::Div => self.visit_div_expr(ast, idx), + Tag::Rem => self.visit_rem_expr(ast, idx), + Tag::Assign => self.visit_assign(ast, idx), + Tag::SubscriptExpr => self.visit_subscript_expr(ast, idx), + Tag::IfExpr => self.visit_if_expr(ast, idx), + Tag::IfElseExpr => self.visit_if_else_expr(ast, idx), + Tag::Error => todo!(), + Tag::Undefined => todo!(), + _ => todo!(), + } + } +} + +impl Ast { + fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option { + use visitor::AstExt; + let (t, data) = self.get_node_tag_and_data(idx); + if t == tag { + Some(data) + } else { + None + } + } + + fn expect_node_data_for_tag(&self, idx: Index, tag: Tag) -> Data { + self.get_node_data_for_tag(idx, tag) + .expect(&format!("node {idx} is not a {tag:?}")) + } +} + +pub mod ir { + use std::collections::HashMap; + + use crate::{ + ast2::{ + intern::{self, AMD64_POINTER_TYPE_INFO}, + Index, + }, + triples::{self, Inst, IR}, + }; + + #[derive(Debug, thiserror::Error)] + enum Error { + #[error("This visitor does not implement visiting this tag.")] + Unimplemented, + } + + use super::{intern::InternPool, visitor::AstExt, AstVisitorTrait, TypeCache}; + + struct IrBuilder { + functions: Vec, + } + + struct Function { + ir: IR, + } + + struct IrFunctionBuilder<'a> { + ir: &'a mut IR, + type_cache: &'a mut TypeCache, + ref_lookup: &'a mut HashMap, + ip: &'a InternPool, + function: Function, + } + + impl<'a> AstVisitorTrait for IrFunctionBuilder<'a> { + type Error = Error; + type Value = Option; + const UNIMPL: Self::Error = Error::Unimplemented; + + fn visit_block( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Block); + let (a, b) = data.as_extra_range(); + + ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_any(ast, i)) + .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(None) + } + + fn visit_decl_ref( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::DeclRef); + let decl = data.as_index(); + + todo!() + } + + fn visit_var_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::VarDecl); + let (a, _) = data.as_extra_range(); + + let ty = Index::from_u32(ast.extra[a + 1]).unwrap(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + self.ref_lookup.insert(idx, alloca); + + Ok(Some(alloca)) + } + fn visit_mut_var_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::MutVarDecl); + let (a, _) = data.as_extra_range(); + + let ty = Index::from_u32(ast.extra[a + 1]).unwrap(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + self.ref_lookup.insert(idx, alloca); + + Ok(Some(alloca)) + } + fn visit_var_assign_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::VarDeclAssignment); + let (a, b) = data.as_extra_range(); + + let range = &ast.extra[a..b]; + let _name = range.get(0).unwrap(); + let expr = range + .get(1) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap(); + let ty = range + .get(2) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap_or(expr); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + + let expr = self.visit_any(ast, expr)?.unwrap(); + self.ir + .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); + + self.ref_lookup.insert(idx, alloca); + + Ok(Some(alloca)) + } + fn visit_mut_var_assign_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::MutVarDeclAssignment); + let (a, b) = data.as_extra_range(); + + let range = &ast.extra[a..b]; + let _name = range.get(0).unwrap(); + let expr = range + .get(1) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap(); + let ty = range + .get(2) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap_or(expr); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + + let expr = self.visit_any(ast, expr)?.unwrap(); + self.ir + .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); + + self.ref_lookup.insert(idx, alloca); + + Ok(Some(alloca)) + } + + fn visit_return( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + + let ir = self.ir.push(Inst::Return, None); + Ok(Some(ir)) + } + fn visit_return_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ReturnExprStmt); + let expr = data.as_index(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + + let expr = self.visit_any(ast, expr)?.unwrap(); + + let ir = self + .ir + .push(Inst::ReturnValue(ty), Some(triples::Data::lhs(expr))); + Ok(Some(ir)) + } + + fn visit_constant( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Constant); + let (ty, value) = data.as_index_intern(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let ir = self.ir.push(Inst::Constant, Some((ty, value).into())); + + Ok(Some(ir)) + } + + fn visit_subscript_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::SubscriptExpr); + let (lhs, index) = data.as_two_indices(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let lhs = self.visit_any(ast, lhs)?.unwrap(); + let index = self.visit_any(ast, index)?.unwrap(); + + // TODO: make getelementptr take a variable instead of a constant index. + let ir = self.ir.push( + Inst::GetElementPtr(ty), + Some(triples::Data::new(lhs, index)), + ); + + Ok(Some(ir)) + } + + fn visit_call_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::CallExpr); + let (func, arguments) = data.as_two_indices(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let len = self.visit_parameter_list(ast, arguments)?.unwrap(); + _ = self.ir.push(Inst::InlineType(ty), None); + let end = self.ir.nodes.len() as u32; + + let func = self.visit_any(ast, func)?.unwrap(); + + let result = self + .ir + .push(Inst::Call(func), Some(triples::Data::new(end - len, end))); + + Ok(Some(result)) + } + + fn visit_argument( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Argument); + let expr = data.as_index(); + + let arg = self.visit_any(ast, expr)?.unwrap(); + + // let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + // self.ir.push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); + + Ok(Some(arg)) + } + + // fn visit_named_argument( + // &mut self, + // ast: &mut super::Ast, + // idx: Index, + // ) -> Result { + // todo!() + // } + + fn visit_argument_list( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ArgumentList); + let (a, b) = data.as_extra_range(); + + let args = ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| { + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, i); + let arg = self.visit_any_argument(ast, i)?.unwrap(); + Ok((ty, arg)) + }) + .collect::, _>>()?; + let count = args.len(); + for (ty, arg) in args { + _ = self + .ir + .push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); + } + // .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(Some(count as u32)) + } + + fn visit_block_trailing_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::BlockTrailingExpr); + + let (a, b) = data.as_extra_range(); + + let expr = ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_any(ast, i)) + // the last node is the trailing + .try_fold(None, |_, e| e)?; + + Ok(expr) + } + + fn visit_function_proto( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionProto); + + let (_, extra) = data.as_intern_and_extra_offset(); + let (_return_type, parameter_list) = ( + Index::from_u32(ast.extra[extra]).unwrap(), + Index::from_u32(ast.extra[extra + 1]).unwrap(), + ); + + self.visit_parameter_list(ast, parameter_list)?; + // push parameters to ir + Ok(None) + } + + fn visit_parameter_list( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ParameterList); + let (a, b) = data.as_extra_range(); + + ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_parameter(ast, i)) + .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(None) + } + + fn visit_parameter( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Parameter); + let (ty, _name) = data.as_index_intern(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + let ir = self.ir.push( + Inst::Parameter(ty), + Some(triples::Data::new(info.size(), info.align())), + ); + self.ref_lookup.insert(idx, ir); + + Ok(None) + } + + fn visit_address_of_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::AddressOf); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let r = self + .ir + .push(Inst::GetElementPtr(ty), Some(triples::Data::new(expr, 0))); + + Ok(Some(r)) + } + + fn visit_assign( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Assign); + let (dst, src) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + let dst = self.visit_any(ast, dst)?.unwrap(); + let src = self.visit_any(ast, src)?.unwrap(); + + let ir = self + .ir + .push(Inst::Store(ty.into()), Some(triples::Data::new(src, dst))); + + Ok(Some(ir)) + } + + fn visit_explicit_cast_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ExplicitCast); + let (lhs, ty) = data.as_two_indices(); + + let lty = ast.get_type_of_node(&self.ip, &mut self.type_cache, lhs); + let rty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + + let lhs = self.visit_any(ast, lhs)?.unwrap(); + + // TODO: if bitwidth is the same, then this is a noop? + let cast = self + .ir + .push(Inst::ExplicitCast(lty, rty), Some(triples::Data::lhs(lhs))); + + Ok(Some(cast)) + } + + fn visit_if_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::IfExpr); + let (cond, body) = data.as_two_indices(); + + let cond = self.visit_any(ast, cond)?.unwrap(); + let br = self.ir.push(Inst::Branch(cond), None); + + let lbody = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + _ = self.visit_any(ast, body); + let jmp = self.ir.push(Inst::Jump, None); + let skip = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lbody, skip)); + self.ir.data[jmp as usize] = Some(triples::Data::lhs(skip)); + + Ok(Some(br)) + } + + fn visit_if_else_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::IfElseExpr); + let (cond, extra) = data.as_index_and_extra_offset(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let [a, b] = ast.extra[extra..][..2] else { + unreachable!() + }; + + let cond = self.visit_any(ast, cond)?.unwrap(); + let br = self.ir.push(Inst::Branch(cond), None); + + let la = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let a = self.visit_any(ast, Index::from_u32(a).unwrap())?.unwrap(); + let jmpa = self.ir.push(Inst::Jump, None); + + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let b = self.visit_any(ast, Index::from_u32(b).unwrap())?.unwrap(); + let jmpb = self.ir.push(Inst::Jump, None); + + let lphi = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + let phi = if ty == intern::Index::VOID { + br + } else { + self.ir.push(Inst::Phi2(ty), Some(triples::Data::new(a, b))) + }; + + self.ir.data[br as usize] = Some(triples::Data::new(la, lb)); + self.ir.data[jmpa as usize] = Some(triples::Data::lhs(lphi)); + self.ir.data[jmpb as usize] = Some(triples::Data::lhs(lphi)); + + Ok(Some(phi)) + } + + fn visit_deref_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_not_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_negate_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Negate); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self + .ir + .push(Inst::Negate(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_or_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); + let (a, b) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + // TODO: make this an error instead of a panic + let a = self.visit_any(ast, a)?.unwrap(); + let not_a = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(a))); + + // branch taken if a + let br = self.ir.push(Inst::Branch(not_a), None); + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + let b = self.visit_any(ast, b)?.unwrap(); + let jmp = self.ir.push(Inst::Jump, None); + + let la = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lb, la)); + self.ir.data[jmp as usize] = Some(triples::Data::lhs(la)); + + let or = self.ir.push( + Inst::Phi2(intern::Index::BOOL), + Some(triples::Data::new(a, b)), + ); + + Ok(Some(or)) + } + + fn visit_and_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); + let (a, b) = data.as_two_indices(); + + // TODO: make this an error instead of a panic + let a = self.visit_any(ast, a)?.unwrap(); + + // branch taken if a + let br = self.ir.push(Inst::Branch(a), None); + + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let b = self.visit_any(ast, b)?.unwrap(); + + let skip = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lb, skip)); + let and = self.ir.push( + Inst::Phi2(intern::Index::BOOL), + Some(triples::Data::new(a, b)), + ); + + Ok(Some(and)) + } + + fn visit_add_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_sub_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_div_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_rem_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_mul_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitand_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitor_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitxor_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_eq_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_neq_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_lt_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_gt_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_le_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_ge_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_shl_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_shr_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + } + + impl IrFunctionBuilder<'_> { + /// handles all binary operations that don't short circuit and visit + /// both lhs and rhs. + fn visit_binop_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result, Error> { + use triples::Data; + let (tag, data) = ast.get_node_tag_and_data(idx); + let (lhs, rhs) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + // TODO: make this an error instead of a panic + let lhs = self.visit_any(ast, lhs)?.unwrap(); + let rhs = self.visit_any(ast, rhs)?.unwrap(); + + let (inst, data) = match tag { + super::Tag::BitOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), + super::Tag::BitXOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), + super::Tag::BitAnd => (Inst::BitOr(ty), Data::new(lhs, rhs)), + + super::Tag::Eq => (Inst::Eq(ty), Data::new(lhs, rhs)), + super::Tag::NEq => (Inst::Neq(ty), Data::new(lhs, rhs)), + super::Tag::Lt => (Inst::Lt(ty), Data::new(lhs, rhs)), + super::Tag::Gt => (Inst::Gt(ty), Data::new(lhs, rhs)), + super::Tag::Le => (Inst::Le(ty), Data::new(lhs, rhs)), + super::Tag::Ge => (Inst::Ge(ty), Data::new(lhs, rhs)), + + super::Tag::Shl => (Inst::ShiftLeft(ty), Data::new(lhs, rhs)), + super::Tag::Shr => (Inst::ShiftRight(ty), Data::new(lhs, rhs)), + super::Tag::Add => (Inst::Add(ty), Data::new(lhs, rhs)), + super::Tag::Sub => (Inst::Sub(ty), Data::new(lhs, rhs)), + super::Tag::Div => (Inst::Div(ty), Data::new(lhs, rhs)), + super::Tag::Rem => (Inst::Rem(ty), Data::new(lhs, rhs)), + super::Tag::Mul => (Inst::Mul(ty), Data::new(lhs, rhs)), + _ => panic!("not a binop"), + }; + + Ok(Some(self.ir.push(inst, Some(data)))) + } + } + + impl AstVisitorTrait for IrBuilder { + type Value = (); + type Error = Error; + const UNIMPL: Self::Error = Error::Unimplemented; + + fn visit_function_decl( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result<(), Self::Error> { + let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionDecl); + let (proto, block) = data.as_two_indices(); + + // visit proto + + // visit block + + todo!() + } + } +} + pub mod irgen { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 6cd1907..9553eab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,3 +70,5 @@ impl BitSize for &[u8] { bits as u32 } } + +pub fn unit(_: T) {} diff --git a/src/triples.rs b/src/triples.rs index 9d90e05..393e31e 100644 --- a/src/triples.rs +++ b/src/triples.rs @@ -759,8 +759,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { } pub struct IR { - nodes: Vec, - data: Vec>, + pub(crate) nodes: Vec, + pub(crate) data: Vec>, // intern_pool: &'a mut InternPool, }