This commit is contained in:
nora 2023-05-23 16:33:10 +02:00
parent c84fdfaf3a
commit 542c0daf6a
6 changed files with 160 additions and 50 deletions

View file

@ -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)]

View file

@ -28,8 +28,6 @@ impl<W: Write> PrettyPrinter<W> {
}
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<W: Write> PrettyPrinter<W> {
})
};
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),

View file

@ -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<Func<'cx>, 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 = &param.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 = &param.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 {

View file

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

View file

@ -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!(),
}
}
}

View file

@ -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<Spanned<InitDecl>>,
}
#[derive(Debug, DebugPls)]
#[derive(Debug, DebugPls, Clone)]
pub struct FunctionParamDecl {
pub decl_spec: Spanned<DeclSpec>,
pub declarator: Spanned<Declarator>,
}
#[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<Spanned<ExternalDecl>>;
impl Decl {
pub fn uwnrap_normal(&self) -> &NormalDecl {
pub fn unwrap_normal(&self) -> &NormalDecl {
match self {
Decl::Normal(decl) => decl,
Decl::StaticAssert => {