diff --git a/analysis/src/ir.rs b/analysis/src/ir.rs index 2748257..99ce179 100644 --- a/analysis/src/ir.rs +++ b/analysis/src/ir.rs @@ -69,6 +69,8 @@ pub struct Func<'cx> { pub name: Symbol, pub def_span: Span, pub ret_ty: Ty<'cx>, + /// The amount of function parameters. regs[..arity] are the parameters. + pub arity: u32, } #[derive(Clone, Copy)] diff --git a/analysis/src/ir/pretty.rs b/analysis/src/ir/pretty.rs index 616220a..ef2da7e 100644 --- a/analysis/src/ir/pretty.rs +++ b/analysis/src/ir/pretty.rs @@ -28,8 +28,6 @@ impl PrettyPrinter { } pub fn func(&mut self, func: &Func<'_>) -> Result { - writeln!(self.out, "def {}() {{", func.name)?; - let print_reg = |reg: Register| { display_fn(move |f| match func.regs[reg.0 as usize].name { None => write!(f, "%{}", reg.0), @@ -37,6 +35,16 @@ impl PrettyPrinter { }) }; + write!(self.out, "def {}(", func.name)?; + for param in 0..func.arity { + let reg = &func.regs[param as usize]; + write!(self.out, "{} {}", reg.tyl.ty, print_reg(Register(param)))?; + if (param + 1) != func.arity { + write!(self.out, ", ")?; + } + } + writeln!(self.out, ") {{",)?; + let print_op = |op: Operand| { display_fn(move |f| match op { Operand::Const(c) => Display::fmt(&c, f), diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index fd7f4ac..e1eb4c5 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -4,7 +4,8 @@ use std::cell::{Cell, RefCell}; use parser::{ ast::{ - self, Atom, DeclAttr, Expr, ExprBinary, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier, + self, Atom, DeclAttr, Expr, ExprBinary, ExternalDecl, InitDecl, Stmt, TranslationUnit, + TypeSpecifier, }, Span, Symbol, }; @@ -120,16 +121,17 @@ pub fn lower_translation_unit<'cx>( match decl { ExternalDecl::Decl(_) => todo!("decl is unsupported"), ExternalDecl::FunctionDef(def) => { - let decl = def.decl.uwnrap_normal(); + let decl = def.decl.unwrap_normal(); let body = &def.body; let ret_ty = lcx.lower_ty(&decl.decl_spec.ty); - let func = lower_body( - &lcx, - body, - decl.init_declarators[0].1, - decl.init_declarators[0].0.declarator.decl.name().0, - ret_ty, - )?; + + let (ref declarator, def_span) = decl.init_declarators[0]; + + let ast::DirectDeclarator::WithParams { ident, params } = &declarator.declarator.decl else { + unreachable!("function def needs withparams declarator"); + }; + + let func = lower_func(&lcx, body, def_span, ident.0, ret_ty, params)?; ir.funcs.insert(lcx.next_def_id(), func); } } @@ -161,37 +163,42 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { Ok(()) } + fn declare_local(&mut self, decl: &ast::Decl, span: Span) -> Result<()> { + let decl = decl.unwrap_normal(); + let ty = self.lcx.lower_ty(&decl.decl_spec.ty); + let decl_attr = decl.decl_spec.attrs; + + for (var, def_span) in &decl.init_declarators { + let tyl = self.lcx.layout_of(ty); + let (name, name_span) = var.declarator.decl.name(); + let ptr_to = self.build.alloca(tyl.layout, Some(name), span); + + let variable_info = VariableInfo { + def_span: *def_span, + ptr_to, + decl_attr, + tyl: tyl.clone(), + }; + let predeclared = self.scopes.last_mut().unwrap().insert(name, variable_info); + if let Some(predeclared) = predeclared { + return Err(Error::new( + format!("variable {name} has already been declared"), + name_span, + ) + .note_spanned("already declared here", predeclared.def_span)); + } + if let Some((init, init_span)) = &var.init { + let init = self.lower_expr(init, *init_span)?; + self.build.store(ptr_to, init, tyl.layout, *init_span); + } + } + Ok(()) + } + fn lower_stmt(&mut self, stmt: &ast::Stmt, stmt_span: Span) -> Result<()> { match stmt { Stmt::Decl(decl) => { - let decl = decl.uwnrap_normal(); - let ty = self.lcx.lower_ty(&decl.decl_spec.ty); - let decl_attr = decl.decl_spec.attrs; - - for (var, def_span) in &decl.init_declarators { - let tyl = self.lcx.layout_of(ty); - let (name, name_span) = var.declarator.decl.name(); - let ptr_to = self.build.alloca(tyl.layout, Some(name), stmt_span); - - let variable_info = VariableInfo { - def_span: *def_span, - ptr_to, - decl_attr, - tyl: tyl.clone(), - }; - let predeclared = self.scopes.last_mut().unwrap().insert(name, variable_info); - if let Some(predeclared) = predeclared { - return Err(Error::new( - format!("variable {name} has already been declared"), - name_span, - ) - .note_spanned("already declared here", predeclared.def_span)); - } - if let Some((init, init_span)) = &var.init { - let init = self.lower_expr(init, *init_span)?; - self.build.store(ptr_to, init, tyl.layout, *init_span); - } - } + self.declare_local(decl, stmt_span)?; } Stmt::Labeled { .. } => todo!("labels are not implemented"), Stmt::Compound(block) => { @@ -393,20 +400,68 @@ struct VariableInfo<'cx> { decl_attr: DeclAttr, } -fn lower_body<'cx>( +fn lower_func<'cx>( // may be used later lcx: &LoweringCx<'cx>, body: &[(Stmt, Span)], def_span: Span, name: Symbol, ret_ty: Ty<'cx>, + params: &[ast::FunctionParamDecl], ) -> Result, Error> { let mut cx = FnLoweringCtxt { - scopes: vec![], - build: FuncBuilder::new(name, def_span, ret_ty, lcx), + scopes: vec![Default::default()], + build: FuncBuilder::new( + name, + def_span, + ret_ty, + lcx, + params.len().try_into().unwrap(), + ), lcx, }; + for param in params { + let decl_spec = ¶m.decl_spec.0; + let ty = lcx.lower_ty(&decl_spec.ty); + let tyl = lcx.layout_of(ty); + // Create all the parameter registers. + let _ = cx + .build + .new_reg(Some(param.declarator.0.decl.name().0), tyl); + } + + for (i, param) in params.iter().enumerate() { + // For every param, we create an allocation and store the register into it. + let param_reg_data = &cx.build.ir.regs[i]; + let name = param.declarator.0.decl.name().0; + + let decl_spec = ¶m.decl_spec.0; + let decl_attr = decl_spec.attrs; + let tyl = param_reg_data.tyl; + let span = param.declarator.1; + + let alloca_name = Symbol::intern(&format!("{}.local", name)); + let ptr_to = cx.build.alloca(tyl.layout, Some(alloca_name), span); + + let variable_info = VariableInfo { + def_span: span, + ptr_to, + decl_attr, + tyl, + }; + let predeclared = cx.scopes.last_mut().unwrap().insert(name, variable_info); + if let Some(predeclared) = predeclared { + return Err( + Error::new(format!("parameter {name} has already been declared"), span) + .note_spanned("already declared here", predeclared.def_span), + ); + } + + cx.build + .store(ptr_to, Operand::Reg(Register(i as _)), tyl.layout, span); + } + cx.lower_block(body)?; if let Branch::Goto(BbIdx(u32::MAX)) = cx.build.cur_bb_mut().term { diff --git a/analysis/src/lower/builder.rs b/analysis/src/lower/builder.rs index d02f94c..b379a3b 100644 --- a/analysis/src/lower/builder.rs +++ b/analysis/src/lower/builder.rs @@ -17,7 +17,13 @@ pub(super) struct FuncBuilder<'a, 'cx> { } impl<'a, 'cx> FuncBuilder<'a, 'cx> { - pub fn new(name: Symbol, def_span: Span, ret_ty: Ty<'cx>, lcx: &'a LoweringCx<'cx>) -> Self { + pub fn new( + name: Symbol, + def_span: Span, + ret_ty: Ty<'cx>, + lcx: &'a LoweringCx<'cx>, + arity: u32, + ) -> Self { Self { ir: Func { regs: Vec::new(), @@ -28,6 +34,7 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> { name, def_span, ret_ty, + arity, }, current_bb: BbIdx(0), lcx, diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index ee6a6b7..f031500 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -1,10 +1,14 @@ use std::{ + fmt::Display, hash::{Hash, Hasher}, ops::Deref, }; use indexmap::IndexMap; -use parser::{ast::IntTy, Symbol}; +use parser::{ + ast::{IntTy, IntTyKind, IntTySignedness}, + Symbol, +}; use crate::ir::DefId; @@ -74,3 +78,37 @@ impl Hash for EnumTy { self.def_id.hash(state) } } + +impl Display for Ty<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match **self { + TyKind::Void => f.write_str("void"), + TyKind::Char => f.write_str("char"), + TyKind::SChar => f.write_str("signed char"), + TyKind::UChar => f.write_str("unsigned char"), + TyKind::Integer(int) => { + match int.sign { + IntTySignedness::Signed => f.write_str("signed "), + IntTySignedness::Unsigned => f.write_str("unsigned "), + }?; + match int.kind { + IntTyKind::Short => f.write_str("short"), + IntTyKind::Int => f.write_str("int"), + IntTyKind::Long => f.write_str("long"), + IntTyKind::LongLong => f.write_str("long long"), + }?; + Ok(()) + } + TyKind::Float => f.write_str("float"), + TyKind::Double => f.write_str("double"), + TyKind::LongDouble => f.write_str("long double"), + TyKind::Bool => f.write_str("_Bool"), + TyKind::Ptr(ty) => { + write!(f, "{ty}*") + } + TyKind::Union(_) => todo!(), + TyKind::Struct(_) => todo!(), + TyKind::Enum(_) => todo!(), + } + } +} diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 4fc3eff..740100e 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -169,7 +169,7 @@ pub struct IntTy { pub kind: IntTyKind, } -#[derive(Debug, DebugPls)] +#[derive(Debug, DebugPls, Clone)] pub enum TypeSpecifier { Void, Char, @@ -205,7 +205,7 @@ impl DebugPls for DeclAttr { } } -#[derive(Debug, DebugPls)] +#[derive(Debug, DebugPls, Clone)] pub struct DeclSpec { pub ty: TypeSpecifier, pub attrs: DeclAttr, @@ -229,13 +229,13 @@ pub struct NormalDecl { pub init_declarators: Vec>, } -#[derive(Debug, DebugPls)] +#[derive(Debug, DebugPls, Clone)] pub struct FunctionParamDecl { pub decl_spec: Spanned, pub declarator: Spanned, } -#[derive(Debug, DebugPls)] +#[derive(Debug, DebugPls, Clone)] pub enum DirectDeclarator { Ident(Ident), WithParams { @@ -244,7 +244,7 @@ pub enum DirectDeclarator { }, } -#[derive(Debug, DebugPls)] +#[derive(Debug, DebugPls, Clone)] pub struct Declarator { pub decl: DirectDeclarator, pub pointer: bool, @@ -265,7 +265,7 @@ pub enum ExternalDecl { pub type TranslationUnit = Vec>; impl Decl { - pub fn uwnrap_normal(&self) -> &NormalDecl { + pub fn unwrap_normal(&self) -> &NormalDecl { match self { Decl::Normal(decl) => decl, Decl::StaticAssert => {