This commit is contained in:
nora 2023-05-23 09:11:23 +02:00
parent 8bf9849641
commit d3846e3357
5 changed files with 265 additions and 133 deletions

View file

@ -43,6 +43,12 @@ use crate::ty::Ty;
pub struct DefId(u32); pub struct DefId(u32);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TyLayout {
pub ty: Ty,
pub layout: Layout,
}
#[derive(Debug, Clone, Copy)]
pub struct Layout { pub struct Layout {
pub size: u64, pub size: u64,
pub align: u64, pub align: u64,
@ -69,6 +75,7 @@ pub struct BasicBlock {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RegisterData { pub struct RegisterData {
pub tyl: TyLayout,
pub name: Option<Symbol>, pub name: Option<Symbol>,
} }
@ -111,6 +118,11 @@ pub enum StatementKind {
reg: Register, reg: Register,
amount: Operand, amount: Operand,
}, },
Call {
result: Register,
func: Operand,
args: Vec<Operand>,
},
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View file

@ -123,6 +123,22 @@ impl<W: Write> PrettyPrinter<W> {
print_reg(reg), print_reg(reg),
print_op(amount) print_op(amount)
), ),
StatementKind::Call {
result,
func,
ref args,
} => {
writeln!(
self.out,
" {} = call {} ({})",
print_reg(result),
print_op(func),
args.iter()
.map(|arg| print_op(*arg).to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
}?; }?;
} }

View file

@ -1,14 +1,14 @@
mod builder;
use parser::{ use parser::{
ast::{self, Atom, DeclAttr, Expr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier}, ast::{self, Atom, DeclAttr, Expr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier},
Span, Symbol, Span, Symbol,
}; };
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use self::builder::FuncBuilder;
use crate::{ use crate::{
ir::{ ir::{BinKind, ConstValue, Func, Ir, Layout, Operand, Register, TyLayout},
self, BasicBlock, BinKind, Branch, ConstValue, Func, Ir, Layout, Operand, Register,
RegisterData, Statement, StatementKind,
},
ty::Ty, ty::Ty,
Error, Error,
}; };
@ -44,8 +44,7 @@ pub fn lower_translation_unit(ast: &TranslationUnit) -> Result<Ir, Error> {
#[derive(Debug)] #[derive(Debug)]
struct FnLoweringCtxt { struct FnLoweringCtxt {
scopes: Vec<FxHashMap<Symbol, VariableInfo>>, scopes: Vec<FxHashMap<Symbol, VariableInfo>>,
ir: Func, build: FuncBuilder,
current_bb: u32,
} }
impl FnLoweringCtxt { impl FnLoweringCtxt {
@ -53,24 +52,77 @@ impl FnLoweringCtxt {
self.scopes.iter().rev().find_map(|s| s.get(&ident)) self.scopes.iter().rev().find_map(|s| s.get(&ident))
} }
fn new_reg(&mut self, name: Option<Symbol>) -> Register { fn lower_body(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
let reg = Register(self.ir.regs.len().try_into().unwrap()); for (stmt, stmt_span) in body {
self.ir.regs.push(RegisterData { name }); self.lower_stmt(stmt, *stmt_span)?;
reg }
Ok(())
} }
fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register { fn lower_stmt(&mut self, stmt: &ast::Stmt, stmt_span: Span) -> Result<()> {
let reg = self.new_reg(name); match stmt {
let stmt = Statement { Stmt::Decl(decl) => {
span, let decl = decl.uwnrap_normal();
kind: StatementKind::Alloca { let ty = lower_ty(&decl.decl_spec.ty);
reg, let decl_attr = decl.decl_spec.attrs;
size: Operand::Const(ConstValue::u64(layout.size)),
align: Operand::Const(ConstValue::u64(layout.align)), for (var, def_span) in &decl.init_declarators {
}, let tyl = layout_of(ty.clone());
}; let (name, _) = var.declarator.decl.name();
self.bb_mut().statements.push(stmt); let ptr_to = self.build.alloca(&tyl.layout, Some(name), stmt_span);
reg
let variable_info = VariableInfo {
def_span: *def_span,
ptr_to,
decl_attr,
tyl,
};
self.scopes.last_mut().unwrap().insert(name, variable_info);
}
}
Stmt::Labeled { .. } => todo!("labels are not implemented"),
Stmt::Compound(_) => todo!("blocks are not implemented"),
Stmt::If {
cond,
then,
otherwise,
} => todo!(),
Stmt::Switch => todo!(),
Stmt::While { cond, body } => todo!(),
Stmt::For {
init_decl,
init_expr,
cond,
post,
body,
} => todo!(),
Stmt::Goto(_) => todo!(),
Stmt::Continue => todo!(),
Stmt::Break => todo!(),
Stmt::Return(_) => todo!(),
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
op: ast::BinaryOp::Assign(assign),
lhs,
rhs,
})) => {
if assign.is_some() {
todo!("assign operation");
}
let rhs = self.lower_expr(&rhs.0, rhs.1)?;
let (Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
todo!("complex assignments")
};
let Some(var) = self.resolve_ident(ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
};
self.build.store(var.ptr_to, rhs, var.tyl.layout, stmt_span);
}
Stmt::Expr(expr) => {
self.lower_expr(expr, stmt_span)?;
}
}
Ok(())
} }
fn lower_expr(&mut self, expr: &ast::Expr, span: Span) -> Result<Operand> { fn lower_expr(&mut self, expr: &ast::Expr, span: Span) -> Result<Operand> {
@ -108,35 +160,40 @@ impl FnLoweringCtxt {
ast::BinaryOp::Assign(_) => todo!("no assign"), ast::BinaryOp::Assign(_) => todo!("no assign"),
}; };
let reg = self.new_reg(None); let reg = self.build.binary(kind, lhs, rhs, span, layout_of(Ty::Void));
let stmt = StatementKind::BinOp {
kind,
lhs,
rhs,
result: reg,
};
self.bb_mut()
.statements
.push(Statement { span, kind: stmt });
Ok(Operand::Reg(reg)) Ok(Operand::Reg(reg))
} }
Expr::Postfix(_) => todo!(), Expr::Postfix(postfix) => {
} let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?;
} match &postfix.op {
ast::PostfixOp::Call(args) => {
let args = args
.iter()
.map(|(arg, sp)| self.lower_expr(arg, *sp))
.collect::<Result<_, _>>()?;
fn bb_mut(&mut self) -> &mut BasicBlock { let reg = self.build.call(layout_of(Ty::Void), lhs, args, span);
&mut self.ir.bbs[self.current_bb as usize] Ok(Operand::Reg(reg))
}
ast::PostfixOp::Member(_) => todo!("member expr"),
ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"),
ast::PostfixOp::Increment => {
todo!("gotta have lvalues")
}
ast::PostfixOp::Decrement => todo!(),
}
}
}
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct VariableInfo { struct VariableInfo {
def_span: Span, def_span: Span,
ty: Ty, tyl: TyLayout,
ptr_to: Register, ptr_to: Register,
decl_attr: DeclAttr, decl_attr: DeclAttr,
layout: Layout,
} }
fn lower_body( fn lower_body(
@ -149,100 +206,12 @@ fn lower_body(
) -> Result<Func, Error> { ) -> Result<Func, Error> {
let mut cx: FnLoweringCtxt = FnLoweringCtxt { let mut cx: FnLoweringCtxt = FnLoweringCtxt {
scopes: vec![FxHashMap::default()], scopes: vec![FxHashMap::default()],
ir: Func { build: FuncBuilder::new(name, def_span, ret_ty),
regs: Vec::new(),
bbs: vec![BasicBlock {
statements: Vec::new(),
term: Branch::Goto(0),
}],
name,
def_span,
ret_ty,
},
current_bb: 0,
}; };
for (stmt, stmt_span) in body { cx.lower_body(body)?;
match stmt {
Stmt::Decl(decl) => {
let decl = decl.uwnrap_normal();
let ty = lower_ty(&decl.decl_spec.ty);
let decl_attr = decl.decl_spec.attrs;
for (var, def_span) in &decl.init_declarators { Ok(cx.build.finish())
let layout = layout_of(&ty);
let (name, _) = var.declarator.decl.name();
let ptr_to = cx.alloca(&layout, Some(name), *stmt_span);
let variable_info = VariableInfo {
def_span: *def_span,
ty: ty.clone(),
ptr_to,
decl_attr,
layout,
};
cx.scopes.last_mut().unwrap().insert(name, variable_info);
}
}
Stmt::Labeled { .. } => todo!("labels are not implemented"),
Stmt::Compound(_) => todo!("blocks are not implemented"),
Stmt::If {
cond,
then,
otherwise,
} => todo!(),
Stmt::Switch => todo!(),
Stmt::While { cond, body } => todo!(),
Stmt::For {
init_decl,
init_expr,
cond,
post,
body,
} => todo!(),
Stmt::Goto(_) => todo!(),
Stmt::Continue => todo!(),
Stmt::Break => todo!(),
Stmt::Return(_) => todo!(),
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
op: ast::BinaryOp::Assign(assign),
lhs,
rhs,
})) => {
if assign.is_some() {
todo!("assign operation");
}
let rhs = cx.lower_expr(&rhs.0, rhs.1)?;
let (Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
todo!("complex assignments")
};
let Some(var) = cx.resolve_ident(ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
};
let stmt = StatementKind::Store {
ptr_reg: var.ptr_to,
value: rhs,
size: Operand::const_u64(var.layout.size),
align: Operand::const_u64(var.layout.align),
};
cx.bb_mut().statements.push(Statement {
span: *stmt_span,
kind: stmt,
});
}
Stmt::Expr(expr) => {
cx.lower_expr(expr, *stmt_span)?;
}
}
}
cx.bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
dbg!(&cx);
println!("{}", ir::func_to_string(&cx.ir));
Ok(cx.ir)
} }
fn lower_ty(ty: &TypeSpecifier) -> Ty { fn lower_ty(ty: &TypeSpecifier) -> Ty {
@ -259,8 +228,8 @@ fn lower_ty(ty: &TypeSpecifier) -> Ty {
} }
} }
fn layout_of(ty: &Ty) -> Layout { fn layout_of(ty: Ty) -> TyLayout {
match ty { let layout = match ty {
Ty::Void => Layout::size_align(0, 1), Ty::Void => Layout::size_align(0, 1),
Ty::Char => Layout::size_align(1, 1), Ty::Char => Layout::size_align(1, 1),
Ty::SChar => Layout::size_align(1, 1), Ty::SChar => Layout::size_align(1, 1),
@ -278,5 +247,7 @@ fn layout_of(ty: &Ty) -> Layout {
Ty::Struct(_) => todo!("layout_of struct"), Ty::Struct(_) => todo!("layout_of struct"),
Ty::Union(_) => todo!("layout_of union"), Ty::Union(_) => todo!("layout_of union"),
Ty::Enum(_) => todo!("layout_of enum"), Ty::Enum(_) => todo!("layout_of enum"),
} Ty::Ptr(_) => Layout::size_align(8, 8),
};
TyLayout { ty, layout }
} }

View file

@ -0,0 +1,132 @@
use parser::{Span, Symbol};
use super::layout_of;
use crate::{
ir::{
self, BasicBlock, BinKind, Branch, ConstValue, Func, Layout, Operand, Register,
RegisterData, Statement, StatementKind, TyLayout,
},
ty::Ty,
};
#[derive(Debug)]
pub struct FuncBuilder {
pub ir: Func,
current_bb: u32,
}
impl FuncBuilder {
pub fn new(name: Symbol, def_span: Span, ret_ty: Ty) -> Self {
Self {
ir: Func {
regs: Vec::new(),
bbs: vec![BasicBlock {
statements: Vec::new(),
term: Branch::Goto(0),
}],
name,
def_span,
ret_ty,
},
current_bb: 0,
}
}
pub fn new_reg(&mut self, name: Option<Symbol>, tyl: TyLayout) -> Register {
let reg = Register(self.ir.regs.len().try_into().unwrap());
self.ir.regs.push(RegisterData { name, tyl });
reg
}
pub fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register {
let reg = self.new_reg(name, layout_of(Ty::Ptr(Box::new(Ty::Void))));
let stmt = Statement {
span,
kind: StatementKind::Alloca {
reg,
size: Operand::Const(ConstValue::u64(layout.size)),
align: Operand::Const(ConstValue::u64(layout.align)),
},
};
self.bb_mut().statements.push(stmt);
reg
}
pub fn binary(
&mut self,
kind: BinKind,
lhs: Operand,
rhs: Operand,
span: Span,
result_tyl: TyLayout,
) -> Register {
let reg = self.new_reg(None, result_tyl);
let stmt = StatementKind::BinOp {
kind,
lhs,
rhs,
result: reg,
};
self.bb_mut()
.statements
.push(Statement { span, kind: stmt });
reg
}
pub fn load(&mut self, tyl: TyLayout, ptr_reg: Register, span: Span) -> Register {
let reg = self.new_reg(None, tyl.clone());
let stmt = StatementKind::Load {
result: reg,
ptr_reg,
size: Operand::const_u64(tyl.layout.size),
align: Operand::const_u64(tyl.layout.align),
};
self.bb_mut()
.statements
.push(Statement { span, kind: stmt });
reg
}
pub fn store(&mut self, ptr_reg: Register, rhs: Operand, layout: Layout, span: Span) {
let stmt = StatementKind::Store {
ptr_reg,
value: rhs,
size: Operand::const_u64(layout.size),
align: Operand::const_u64(layout.align),
};
self.bb_mut()
.statements
.push(Statement { span, kind: stmt });
}
pub fn call(
&mut self,
ret_tyl: TyLayout,
func: Operand,
args: Vec<Operand>,
span: Span,
) -> Register {
let reg = self.new_reg(None, ret_tyl);
let stmt = StatementKind::Call {
result: reg,
func,
args,
};
self.bb_mut()
.statements
.push(Statement { span, kind: stmt });
reg
}
pub fn bb_mut(&mut self) -> &mut BasicBlock {
&mut self.ir.bbs[self.current_bb as usize]
}
pub fn finish(mut self) -> Func {
self.bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
println!("{}", ir::func_to_string(&self.ir));
self.ir
}
}

View file

@ -14,6 +14,7 @@ pub enum Ty {
Double, Double,
LongDouble, LongDouble,
Bool, Bool,
Ptr(Box<Ty>),
Union(UnionTy), Union(UnionTy),
Struct(StructTy), Struct(StructTy),
Enum(EnumTy), Enum(EnumTy),