This commit is contained in:
nora 2023-05-23 17:28:04 +02:00
parent 86b924f5e3
commit ffd3dad040
2 changed files with 73 additions and 64 deletions

View file

@ -2,7 +2,10 @@ mod builder;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use parser::{ast, Span, Symbol}; use parser::{
ast::{self, IntTy, IntTyKind, IntTySignedness},
Span, Symbol,
};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use self::builder::FuncBuilder; use self::builder::FuncBuilder;
@ -144,6 +147,14 @@ struct FnLoweringCtxt<'a, 'cx> {
} }
impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> { impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
fn dummy_tyl(&self) -> TyLayout<'cx> {
self.ty_layout(TyKind::Void)
}
fn ty_layout(&self, ty_kind: TyKind<'cx>) -> TyLayout<'cx> {
self.lcx.layout_of(self.lcx.intern_ty(ty_kind))
}
fn resolve_ident(&self, ident: Symbol) -> Option<&VariableInfo<'cx>> { fn resolve_ident(&self, ident: Symbol) -> Option<&VariableInfo<'cx>> {
self.scopes.iter().rev().find_map(|s| s.get(&ident)) self.scopes.iter().rev().find_map(|s| s.get(&ident))
} }
@ -183,7 +194,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
} }
if let Some((init, init_span)) = &var.init { if let Some((init, init_span)) = &var.init {
let init = self.lower_expr(init, *init_span)?; let init = self.lower_expr(init, *init_span)?;
self.build.store(ptr_to, init, tyl.layout, *init_span); self.build.store(ptr_to, init.0, tyl.layout, *init_span);
} }
} }
Ok(()) Ok(())
@ -235,7 +246,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
None => cont, None => cont,
}; };
self.build.bb_mut(pred).term = Branch::Switch { self.build.bb_mut(pred).term = Branch::Switch {
cond, cond: cond.0,
yes: then, yes: then,
no: false_branch, no: false_branch,
}; };
@ -249,7 +260,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
ast::Stmt::Break => todo!(), ast::Stmt::Break => todo!(),
ast::Stmt::Return(expr) => { ast::Stmt::Return(expr) => {
let ret = match expr { let ret = match expr {
Some(expr) => self.lower_expr(&expr.0, expr.1)?, Some(expr) => self.lower_expr(&expr.0, expr.1)?.0,
None => Operand::Const(ConstValue::Void), None => Operand::Const(ConstValue::Void),
}; };
self.build.cur_bb_mut().term = Branch::Ret(ret); self.build.cur_bb_mut().term = Branch::Ret(ret);
@ -269,7 +280,8 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
let Some(var) = self.resolve_ident(ident) else { let Some(var) = self.resolve_ident(ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), ident_span)); return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
}; };
self.build.store(var.ptr_to, rhs, var.tyl.layout, stmt_span); self.build
.store(var.ptr_to, rhs.0, var.tyl.layout, stmt_span);
} }
ast::Stmt::Expr(expr) => { ast::Stmt::Expr(expr) => {
self.lower_expr(expr, stmt_span)?; self.lower_expr(expr, stmt_span)?;
@ -279,17 +291,27 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
Ok(()) 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, TyLayout<'cx>)> {
match expr { match expr {
ast::Expr::Atom(ast::Atom::Char(c)) => Ok(Operand::Const(ConstValue::Int((*c).into()))), ast::Expr::Atom(ast::Atom::Char(c)) => Ok((
ast::Expr::Atom(ast::Atom::Int(i)) => Ok(Operand::Const(ConstValue::Int(*i as _))), Operand::Const(ConstValue::Int((*c).into())),
self.ty_layout(TyKind::Char),
)),
ast::Expr::Atom(ast::Atom::Int(i)) => Ok((
Operand::Const(ConstValue::Int(*i as _)),
self.ty_layout(TyKind::Integer(IntTy {
sign: IntTySignedness::Signed,
kind: IntTyKind::Int,
})),
)),
ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"), ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"),
ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => { ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => {
let Some(var) = self.resolve_ident(*ident) else { let Some(var) = self.resolve_ident(*ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), *ident_span)); return Err(Error::new(format!("cannot find variable {ident}"), *ident_span));
}; };
let tyl = var.tyl;
let op = self.build.load(var.tyl, var.ptr_to, span); let op = self.build.load(var.tyl, var.ptr_to, span);
Ok(Operand::Reg(op)) Ok((Operand::Reg(op), tyl))
} }
ast::Expr::Atom(ast::Atom::String(_)) => todo!("no string literals"), ast::Expr::Atom(ast::Atom::String(_)) => todo!("no string literals"),
ast::Expr::Unary(ast::ExprUnary { ast::Expr::Unary(ast::ExprUnary {
@ -297,33 +319,29 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
rhs: rhs_expr, rhs: rhs_expr,
}) => { }) => {
// First increment/decrement, then return the value. // First increment/decrement, then return the value.
let rhs = self.lower_expr(&rhs_expr.0, rhs_expr.1)?; let (rhs, rhs_tyl) = self.lower_expr(&rhs_expr.0, rhs_expr.1)?;
let lvalue = self.expr_as_lvalue(&rhs_expr.0)?; let is_incr = matches!(op, ast::UnaryOp::Increment);
let bin_kind = if let ast::UnaryOp::Increment = op {
BinKind::Add
} else {
BinKind::Sub
};
let lhs = self.build.load(
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)),
lvalue,
span,
);
let result = self.build.binary(
bin_kind,
Operand::Reg(lhs),
rhs,
span,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)),
);
self.build.store(
lhs,
rhs,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)).layout,
span,
);
Ok(Operand::Reg(result)) if !rhs_tyl.ty.is_integral() {
return Err(Error::new(
format!(
"cannot {} {}",
if is_incr { "increment" } else { "decrement" },
rhs_tyl.ty
),
rhs_expr.1,
));
}
let lvalue = self.expr_as_lvalue(&rhs_expr.0)?;
let bin_kind = if is_incr { BinKind::Add } else { BinKind::Sub };
let lhs = self.build.load(self.dummy_tyl(), lvalue, span);
let result =
self.build
.binary(bin_kind, Operand::Reg(lhs), rhs, span, self.dummy_tyl());
self.build.store(lhs, rhs, self.dummy_tyl().layout, span);
Ok((Operand::Reg(result), self.dummy_tyl()))
} }
ast::Expr::Unary(unary) => { ast::Expr::Unary(unary) => {
let rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?; let rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?;
@ -338,13 +356,8 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
ast::UnaryOp::Bang => UnaryKind::LogicalNot, ast::UnaryOp::Bang => UnaryKind::LogicalNot,
}; };
let reg = self.build.unary( let reg = self.build.unary(kind, rhs.0, span, self.dummy_tyl());
kind, Ok((Operand::Reg(reg), self.dummy_tyl()))
rhs,
span,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)),
);
Ok(Operand::Reg(reg))
} }
ast::Expr::Binary(ast::ExprBinary { ast::Expr::Binary(ast::ExprBinary {
lhs, lhs,
@ -357,12 +370,8 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
let rhs = self.lower_expr(&rhs.0, rhs.1)?; let rhs = self.lower_expr(&rhs.0, rhs.1)?;
let ptr_to = self.expr_as_lvalue(&lhs.0)?; let ptr_to = self.expr_as_lvalue(&lhs.0)?;
self.build.store( self.build
ptr_to, .store(ptr_to, rhs.0, self.dummy_tyl().layout, span);
rhs,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)).layout,
span,
);
Ok(rhs) Ok(rhs)
} }
ast::Expr::Binary(binary) => { ast::Expr::Binary(binary) => {
@ -395,15 +404,11 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
ast::BinaryOp::Assign(_) => unreachable!("assign handled above"), ast::BinaryOp::Assign(_) => unreachable!("assign handled above"),
}; };
let reg = self.build.binary( let reg = self
kind, .build
lhs, .binary(kind, lhs.0, rhs.0, span, self.dummy_tyl());
rhs,
span,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)),
);
Ok(Operand::Reg(reg)) Ok((Operand::Reg(reg), self.dummy_tyl()))
} }
ast::Expr::Postfix(postfix) => { ast::Expr::Postfix(postfix) => {
let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?; let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?;
@ -411,16 +416,11 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
ast::PostfixOp::Call(args) => { ast::PostfixOp::Call(args) => {
let args = args let args = args
.iter() .iter()
.map(|(arg, sp)| self.lower_expr(arg, *sp)) .map(|(arg, sp)| self.lower_expr(arg, *sp).map(|o| o.0))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let reg = self.build.call( let reg = self.build.call(self.dummy_tyl(), lhs.0, args, span);
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)), Ok((Operand::Reg(reg), self.dummy_tyl()))
lhs,
args,
span,
);
Ok(Operand::Reg(reg))
} }
ast::PostfixOp::Member(_) => todo!("member expr"), ast::PostfixOp::Member(_) => todo!("member expr"),
ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"), ast::PostfixOp::ArrowMember(_) => todo!("arrow member expr"),

View file

@ -112,3 +112,12 @@ impl Display for Ty<'_> {
} }
} }
} }
impl<'cx> Ty<'cx> {
pub fn is_integral(self) -> bool {
matches!(
*self,
TyKind::Char | TyKind::SChar | TyKind::UChar | TyKind::Integer(_)
)
}
}