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, rhs: Operand,
result: Register, result: Register,
}, },
UnaryOperation {
rhs: Operand,
kind: UnaryKind,
result: Register,
},
PtrOffset { PtrOffset {
result: Register, result: Register,
reg: Register, reg: Register,
@ -171,6 +176,13 @@ pub enum BinKind {
BitXor, BitXor,
} }
#[derive(Debug, Clone, Copy)]
pub enum UnaryKind {
Negate,
BitNot,
LogicalNot,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum ConstValue { pub enum ConstValue {
Void, Void,

View file

@ -1,6 +1,6 @@
use std::fmt::{Display, Formatter, Result, Write}; 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; use crate::ir::Register;
pub fn ir_to_string(ir: &Ir<'_>) -> String { pub fn ir_to_string(ir: &Ir<'_>) -> String {
@ -125,6 +125,17 @@ impl<W: Write> PrettyPrinter<W> {
print_op(lhs), print_op(lhs),
print_op(rhs) 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 { StatementKind::PtrOffset {
result, result,
reg, reg,

View file

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

View file

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

View file

@ -23,6 +23,8 @@ pub enum Atom {
#[derive(Debug, DebugPls)] #[derive(Debug, DebugPls)]
pub enum UnaryOp { pub enum UnaryOp {
Increment,
Decrement,
AddrOf, AddrOf,
Deref, Deref,
Plus, Plus,

View file

@ -376,6 +376,8 @@ impl<W: Write> PrettyPrinter<W> {
fn unary(&mut self, unary: &ExprUnary) -> Result { fn unary(&mut self, unary: &ExprUnary) -> Result {
self.string(match unary.op { self.string(match unary.op {
UnaryOp::Increment => "++",
UnaryOp::Decrement => "--",
UnaryOp::AddrOf => "&", UnaryOp::AddrOf => "&",
UnaryOp::Deref => "*", UnaryOp::Deref => "*",
UnaryOp::Plus => "+", UnaryOp::Plus => "+",