This commit is contained in:
nora 2023-05-23 17:09:08 +02:00
parent 542c0daf6a
commit 86b924f5e3
7 changed files with 171 additions and 67 deletions

View file

@ -122,6 +122,11 @@ pub enum StatementKind {
rhs: Operand,
result: Register,
},
UnaryOperation {
rhs: Operand,
kind: UnaryKind,
result: Register,
},
PtrOffset {
result: Register,
reg: Register,
@ -171,6 +176,13 @@ pub enum BinKind {
BitXor,
}
#[derive(Debug, Clone, Copy)]
pub enum UnaryKind {
Negate,
BitNot,
LogicalNot,
}
#[derive(Debug, Clone, Copy)]
pub enum ConstValue {
Void,

View file

@ -1,6 +1,6 @@
use std::fmt::{Display, Formatter, Result, Write};
use super::{BbIdx, BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind};
use super::{BbIdx, BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind, UnaryKind};
use crate::ir::Register;
pub fn ir_to_string(ir: &Ir<'_>) -> String {
@ -125,6 +125,17 @@ impl<W: Write> PrettyPrinter<W> {
print_op(lhs),
print_op(rhs)
),
StatementKind::UnaryOperation { rhs, kind, result } => writeln!(
self.out,
" {} = {} {}",
print_reg(result),
match kind {
UnaryKind::Negate => "negate",
UnaryKind::BitNot => "bitnot",
UnaryKind::LogicalNot => "logicalnot",
},
print_op(rhs)
),
StatementKind::PtrOffset {
result,
reg,

View file

@ -1,3 +1,5 @@
use rustc_hash::FxHashSet;
use super::{Branch, Ir};
use crate::ir::BbIdx;
@ -5,7 +7,21 @@ pub fn validate(ir: &Ir<'_>) {
for fun in ir.funcs.values() {
for (i, bb) in fun.bbs.iter().enumerate() {
if let Branch::Goto(BbIdx(u32::MAX)) = bb.term {
panic!("found dummy term in {} in {}", BbIdx::from_usize(i), fun.name)
panic!(
"found dummy term in {} in {}",
BbIdx::from_usize(i),
fun.name
)
}
}
let mut reg_names = FxHashSet::default();
for reg in &fun.regs {
if let Some(name) = reg.name {
let is_new = reg_names.insert(name);
if !is_new {
panic!("register name {name} is used twice");
}
}
}
}

View file

@ -2,20 +2,14 @@ mod builder;
use std::cell::{Cell, RefCell};
use parser::{
ast::{
self, Atom, DeclAttr, Expr, ExprBinary, ExternalDecl, InitDecl, Stmt, TranslationUnit,
TypeSpecifier,
},
Span, Symbol,
};
use parser::{ast, Span, Symbol};
use rustc_hash::{FxHashMap, FxHashSet};
use self::builder::FuncBuilder;
use crate::{
ir::{
self, BbIdx, BinKind, Branch, ConstValue, DefId, Func, Ir, Layout, Operand, Register,
TyLayout,
TyLayout, UnaryKind,
},
ty::{Ty, TyKind},
Error,
@ -37,17 +31,17 @@ impl<'cx> LoweringCx<'cx> {
self.next_def_id.set(DefId(def_id.0 + 1));
def_id
}
fn lower_ty(&self, ty: &TypeSpecifier) -> Ty<'cx> {
fn lower_ty(&self, ty: &ast::TypeSpecifier) -> Ty<'cx> {
let kind = match ty {
TypeSpecifier::Void => TyKind::Void,
TypeSpecifier::Char => TyKind::Char,
TypeSpecifier::SChar => TyKind::SChar,
TypeSpecifier::UChar => TyKind::UChar,
TypeSpecifier::Integer(int) => TyKind::Integer(*int),
TypeSpecifier::Float => TyKind::Float,
TypeSpecifier::Double => TyKind::Double,
TypeSpecifier::LongDouble => TyKind::LongDouble,
TypeSpecifier::Bool => TyKind::Bool,
ast::TypeSpecifier::Void => TyKind::Void,
ast::TypeSpecifier::Char => TyKind::Char,
ast::TypeSpecifier::SChar => TyKind::SChar,
ast::TypeSpecifier::UChar => TyKind::UChar,
ast::TypeSpecifier::Integer(int) => TyKind::Integer(*int),
ast::TypeSpecifier::Float => TyKind::Float,
ast::TypeSpecifier::Double => TyKind::Double,
ast::TypeSpecifier::LongDouble => TyKind::LongDouble,
ast::TypeSpecifier::Bool => TyKind::Bool,
};
self.intern_ty(kind)
}
@ -104,7 +98,7 @@ impl<'cx> LoweringCx<'cx> {
pub fn lower_translation_unit<'cx>(
arena: &'cx bumpalo::Bump,
ast: &TranslationUnit,
ast: &ast::TranslationUnit,
) -> Result<Ir<'cx>, Error> {
let lcx = LoweringCx {
tys: RefCell::default(),
@ -119,8 +113,8 @@ pub fn lower_translation_unit<'cx>(
for (decl, _) in ast {
match decl {
ExternalDecl::Decl(_) => todo!("decl is unsupported"),
ExternalDecl::FunctionDef(def) => {
ast::ExternalDecl::Decl(_) => todo!("decl is unsupported"),
ast::ExternalDecl::FunctionDef(def) => {
let decl = def.decl.unwrap_normal();
let body = &def.body;
let ret_ty = lcx.lower_ty(&decl.decl_spec.ty);
@ -154,7 +148,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
self.scopes.iter().rev().find_map(|s| s.get(&ident))
}
fn lower_block(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
fn lower_block(&mut self, body: &[(ast::Stmt, Span)]) -> Result<()> {
self.scopes.push(Default::default());
for (stmt, stmt_span) in body {
self.lower_stmt(stmt, *stmt_span)?;
@ -195,16 +189,26 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
Ok(())
}
fn expr_as_lvalue(&mut self, expr: &ast::Expr) -> Result<Register> {
let ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) = *expr else {
todo!("complex lvalues")
};
let Some(var) = self.resolve_ident(ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
};
Ok(var.ptr_to)
}
fn lower_stmt(&mut self, stmt: &ast::Stmt, stmt_span: Span) -> Result<()> {
match stmt {
Stmt::Decl(decl) => {
ast::Stmt::Decl(decl) => {
self.declare_local(decl, stmt_span)?;
}
Stmt::Labeled { .. } => todo!("labels are not implemented"),
Stmt::Compound(block) => {
ast::Stmt::Labeled { .. } => todo!("labels are not implemented"),
ast::Stmt::Compound(block) => {
self.lower_block(block)?;
}
Stmt::If {
ast::Stmt::If {
cond,
then: then_body,
otherwise,
@ -237,26 +241,20 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
};
self.build.current_bb = cont;
}
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(expr) => {
ast::Stmt::Switch => todo!(),
ast::Stmt::While { .. } => todo!(),
ast::Stmt::For { .. } => todo!(),
ast::Stmt::Goto(_) => todo!(),
ast::Stmt::Continue => todo!(),
ast::Stmt::Break => todo!(),
ast::Stmt::Return(expr) => {
let ret = match expr {
Some(expr) => self.lower_expr(&expr.0, expr.1)?,
None => Operand::Const(ConstValue::Void),
};
self.build.cur_bb_mut().term = Branch::Ret(ret);
}
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
ast::Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
op: ast::BinaryOp::Assign(assign),
lhs,
rhs,
@ -265,7 +263,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
todo!("assign operation");
}
let rhs = self.lower_expr(&rhs.0, rhs.1)?;
let (Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
let (ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
todo!("complex assignments")
};
let Some(var) = self.resolve_ident(ident) else {
@ -273,7 +271,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
};
self.build.store(var.ptr_to, rhs, var.tyl.layout, stmt_span);
}
Stmt::Expr(expr) => {
ast::Stmt::Expr(expr) => {
self.lower_expr(expr, stmt_span)?;
}
}
@ -283,29 +281,72 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
fn lower_expr(&mut self, expr: &ast::Expr, span: Span) -> Result<Operand> {
match expr {
ast::Expr::Atom(Atom::Char(c)) => Ok(Operand::Const(ConstValue::Int((*c).into()))),
ast::Expr::Atom(Atom::Int(i)) => Ok(Operand::Const(ConstValue::Int(*i as _))),
ast::Expr::Atom(Atom::Float(_)) => todo!("no floats"),
ast::Expr::Atom(Atom::Ident((ident, ident_span))) => {
ast::Expr::Atom(ast::Atom::Char(c)) => Ok(Operand::Const(ConstValue::Int((*c).into()))),
ast::Expr::Atom(ast::Atom::Int(i)) => Ok(Operand::Const(ConstValue::Int(*i as _))),
ast::Expr::Atom(ast::Atom::Float(_)) => todo!("no floats"),
ast::Expr::Atom(ast::Atom::Ident((ident, ident_span))) => {
let Some(var) = self.resolve_ident(*ident) else {
return Err(Error::new(format!("cannot find variable {ident}"), *ident_span));
};
let op = self.build.load(var.tyl, var.ptr_to, span);
Ok(Operand::Reg(op))
}
ast::Expr::Atom(Atom::String(_)) => todo!("no string literals"),
ast::Expr::Atom(ast::Atom::String(_)) => todo!("no string literals"),
ast::Expr::Unary(ast::ExprUnary {
op: op @ (ast::UnaryOp::Increment | ast::UnaryOp::Decrement),
rhs: rhs_expr,
}) => {
// First increment/decrement, then return the value.
let rhs = self.lower_expr(&rhs_expr.0, rhs_expr.1)?;
let lvalue = self.expr_as_lvalue(&rhs_expr.0)?;
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))
}
ast::Expr::Unary(unary) => {
let _rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?;
match unary.op {
let rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?;
let kind = match unary.op {
ast::UnaryOp::Increment => unreachable!("handled prefix increment above"),
ast::UnaryOp::Decrement => unreachable!("handled prefix increment above"),
ast::UnaryOp::AddrOf => todo!("addr of"),
ast::UnaryOp::Deref => todo!("deref?"),
ast::UnaryOp::Plus => todo!("unary plus lol"),
ast::UnaryOp::Minus => todo!("unary minus!"),
ast::UnaryOp::Tilde => todo!("tilde"),
ast::UnaryOp::Bang => todo!("bang bang bang"),
}
ast::UnaryOp::Minus => UnaryKind::Negate,
ast::UnaryOp::Tilde => UnaryKind::BitNot,
ast::UnaryOp::Bang => UnaryKind::LogicalNot,
};
let reg = self.build.unary(
kind,
rhs,
span,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)),
);
Ok(Operand::Reg(reg))
}
ast::Expr::Binary(ExprBinary {
ast::Expr::Binary(ast::ExprBinary {
lhs,
rhs,
op: ast::BinaryOp::Assign(assign),
@ -314,13 +355,14 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
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, span);
let ptr_to = self.expr_as_lvalue(&lhs.0)?;
self.build.store(
ptr_to,
rhs,
self.lcx.layout_of(self.lcx.intern_ty(TyKind::Void)).layout,
span,
);
Ok(rhs)
}
ast::Expr::Binary(binary) => {
@ -363,7 +405,7 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
Ok(Operand::Reg(reg))
}
Expr::Postfix(postfix) => {
ast::Expr::Postfix(postfix) => {
let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?;
match &postfix.op {
ast::PostfixOp::Call(args) => {
@ -397,13 +439,13 @@ struct VariableInfo<'cx> {
def_span: Span,
tyl: TyLayout<'cx>,
ptr_to: Register,
decl_attr: DeclAttr,
decl_attr: ast::DeclAttr,
}
fn lower_func<'cx>(
// may be used later
lcx: &LoweringCx<'cx>,
body: &[(Stmt, Span)],
body: &[(ast::Stmt, Span)],
def_span: Span,
name: Symbol,
ret_ty: Ty<'cx>,

View file

@ -4,7 +4,7 @@ use super::LoweringCx;
use crate::{
ir::{
self, BasicBlock, BbIdx, BinKind, Branch, ConstValue, Func, Layout, Operand, Register,
RegisterData, Statement, StatementKind, TyLayout,
RegisterData, Statement, StatementKind, TyLayout, UnaryKind,
},
ty::{Ty, TyKind},
};
@ -85,6 +85,25 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
reg
}
pub fn unary(
&mut self,
kind: UnaryKind,
rhs: Operand,
span: Span,
result_tyl: TyLayout<'cx>,
) -> Register {
let reg = self.new_reg(None, result_tyl);
let stmt = StatementKind::UnaryOperation {
kind,
rhs,
result: reg,
};
self.cur_bb_mut()
.statements
.push(Statement { span, kind: stmt });
reg
}
pub fn load(&mut self, tyl: TyLayout<'cx>, ptr_reg: Register, span: Span) -> Register {
let reg = self.new_reg(None, tyl.clone());
let stmt = StatementKind::Load {