mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
more stuff
This commit is contained in:
parent
77e18126e7
commit
c84fdfaf3a
12 changed files with 270 additions and 38 deletions
|
|
@ -32,19 +32,21 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
mod pretty;
|
mod pretty;
|
||||||
|
mod validate;
|
||||||
|
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use parser::{Span, Symbol};
|
use parser::{Span, Symbol};
|
||||||
pub use pretty::{func_to_string, ir_to_string};
|
pub use pretty::{func_to_string, ir_to_string};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
pub use validate::validate;
|
||||||
|
|
||||||
use crate::ty::Ty;
|
use crate::ty::Ty;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct DefId(u32);
|
pub struct DefId(pub u32);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TyLayout<'cx> {
|
pub struct TyLayout<'cx> {
|
||||||
pub ty: Ty<'cx>,
|
pub ty: Ty<'cx>,
|
||||||
pub layout: &'cx Layout,
|
pub layout: &'cx Layout,
|
||||||
|
|
@ -160,6 +162,11 @@ pub enum BinKind {
|
||||||
Geq,
|
Geq,
|
||||||
Lt,
|
Lt,
|
||||||
Leq,
|
Leq,
|
||||||
|
Shl,
|
||||||
|
Shr,
|
||||||
|
BitAnd,
|
||||||
|
BitOr,
|
||||||
|
BitXor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -212,3 +219,9 @@ impl Operand {
|
||||||
Self::Const(ConstValue::u64(int))
|
Self::Const(ConstValue::u64(int))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Branch {
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
Branch::Goto(BbIdx(u32::MAX))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt::{Display, Formatter, Result, Write};
|
use std::fmt::{Display, Formatter, Result, Write};
|
||||||
|
|
||||||
use super::{BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind, BbIdx};
|
use super::{BbIdx, BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind};
|
||||||
use crate::ir::Register;
|
use crate::ir::Register;
|
||||||
|
|
||||||
pub fn ir_to_string(ir: &Ir<'_>) -> String {
|
pub fn ir_to_string(ir: &Ir<'_>) -> String {
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct PrettyPrinter<W> {
|
||||||
|
|
||||||
impl<W: Write> PrettyPrinter<W> {
|
impl<W: Write> PrettyPrinter<W> {
|
||||||
pub fn ir(&mut self, ir: &Ir<'_>) -> Result {
|
pub fn ir(&mut self, ir: &Ir<'_>) -> Result {
|
||||||
for (_, func) in &ir.funcs {
|
for func in ir.funcs.values() {
|
||||||
self.func(func)?;
|
self.func(func)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -108,6 +108,11 @@ impl<W: Write> PrettyPrinter<W> {
|
||||||
BinKind::Geq => "geq",
|
BinKind::Geq => "geq",
|
||||||
BinKind::Lt => "gl",
|
BinKind::Lt => "gl",
|
||||||
BinKind::Leq => "leq",
|
BinKind::Leq => "leq",
|
||||||
|
BinKind::Shl => "shl",
|
||||||
|
BinKind::Shr => "shr",
|
||||||
|
BinKind::BitAnd => "bitand",
|
||||||
|
BinKind::BitOr => "bitor",
|
||||||
|
BinKind::BitXor => "bitxor",
|
||||||
},
|
},
|
||||||
print_op(lhs),
|
print_op(lhs),
|
||||||
print_op(rhs)
|
print_op(rhs)
|
||||||
|
|
|
||||||
12
analysis/src/ir/validate.rs
Normal file
12
analysis/src/ir/validate.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
use super::{Branch, Ir};
|
||||||
|
use crate::ir::BbIdx;
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,17 @@ mod ty;
|
||||||
pub use lower::lower_translation_unit;
|
pub use lower::lower_translation_unit;
|
||||||
use parser::Span;
|
use parser::Span;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
msg: String,
|
msg: String,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
notes: Vec<Note>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Note {
|
||||||
|
msg: String,
|
||||||
|
span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
|
@ -18,6 +26,15 @@ impl Error {
|
||||||
Self {
|
Self {
|
||||||
msg: msg.into(),
|
msg: msg.into(),
|
||||||
span,
|
span,
|
||||||
|
notes: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn note_spanned(mut self, msg: impl Into<String>, span: Span) -> Self {
|
||||||
|
self.notes.push(Note {
|
||||||
|
msg: msg.into(),
|
||||||
|
span: Some(span),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
mod builder;
|
mod builder;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::{Cell, RefCell};
|
||||||
|
|
||||||
use parser::{
|
use parser::{
|
||||||
ast::{self, Atom, DeclAttr, Expr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier},
|
ast::{
|
||||||
|
self, Atom, DeclAttr, Expr, ExprBinary, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier,
|
||||||
|
},
|
||||||
Span, Symbol,
|
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::{BinKind, Branch, ConstValue, Func, Ir, Layout, Operand, Register, TyLayout},
|
ir::{
|
||||||
|
self, BbIdx, BinKind, Branch, ConstValue, DefId, Func, Ir, Layout, Operand, Register,
|
||||||
|
TyLayout,
|
||||||
|
},
|
||||||
ty::{Ty, TyKind},
|
ty::{Ty, TyKind},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
@ -22,9 +27,15 @@ struct LoweringCx<'cx> {
|
||||||
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
|
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
|
||||||
layouts: RefCell<FxHashSet<&'cx Layout>>,
|
layouts: RefCell<FxHashSet<&'cx Layout>>,
|
||||||
arena: &'cx bumpalo::Bump,
|
arena: &'cx bumpalo::Bump,
|
||||||
|
next_def_id: Cell<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx> LoweringCx<'cx> {
|
impl<'cx> LoweringCx<'cx> {
|
||||||
|
fn next_def_id(&self) -> DefId {
|
||||||
|
let def_id = self.next_def_id.get();
|
||||||
|
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: &TypeSpecifier) -> Ty<'cx> {
|
||||||
let kind = match ty {
|
let kind = match ty {
|
||||||
TypeSpecifier::Void => TyKind::Void,
|
TypeSpecifier::Void => TyKind::Void,
|
||||||
|
|
@ -94,10 +105,15 @@ pub fn lower_translation_unit<'cx>(
|
||||||
arena: &'cx bumpalo::Bump,
|
arena: &'cx bumpalo::Bump,
|
||||||
ast: &TranslationUnit,
|
ast: &TranslationUnit,
|
||||||
) -> Result<Ir<'cx>, Error> {
|
) -> Result<Ir<'cx>, Error> {
|
||||||
let mut lcx = LoweringCx {
|
let lcx = LoweringCx {
|
||||||
tys: RefCell::default(),
|
tys: RefCell::default(),
|
||||||
layouts: RefCell::default(),
|
layouts: RefCell::default(),
|
||||||
arena,
|
arena,
|
||||||
|
next_def_id: Cell::new(DefId(0)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ir = Ir {
|
||||||
|
funcs: FxHashMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (decl, _) in ast {
|
for (decl, _) in ast {
|
||||||
|
|
@ -107,18 +123,21 @@ pub fn lower_translation_unit<'cx>(
|
||||||
let decl = def.decl.uwnrap_normal();
|
let decl = def.decl.uwnrap_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);
|
||||||
lower_body(
|
let func = lower_body(
|
||||||
&mut lcx,
|
&lcx,
|
||||||
body,
|
body,
|
||||||
decl.init_declarators[0].1,
|
decl.init_declarators[0].1,
|
||||||
decl.init_declarators[0].0.declarator.decl.name().0,
|
decl.init_declarators[0].0.declarator.decl.name().0,
|
||||||
ret_ty,
|
ret_ty,
|
||||||
)?;
|
)?;
|
||||||
|
ir.funcs.insert(lcx.next_def_id(), func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!("building is not really")
|
ir::validate(&ir);
|
||||||
|
|
||||||
|
Ok(ir)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -133,10 +152,12 @@ 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_body(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
|
fn lower_block(&mut self, body: &[(Stmt, Span)]) -> Result<()> {
|
||||||
|
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)?;
|
||||||
}
|
}
|
||||||
|
self.scopes.pop();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,9 +169,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
let decl_attr = decl.decl_spec.attrs;
|
let decl_attr = decl.decl_spec.attrs;
|
||||||
|
|
||||||
for (var, def_span) in &decl.init_declarators {
|
for (var, def_span) in &decl.init_declarators {
|
||||||
let tyl = self.lcx.layout_of(ty.clone());
|
let tyl = self.lcx.layout_of(ty);
|
||||||
let (name, _) = var.declarator.decl.name();
|
let (name, name_span) = var.declarator.decl.name();
|
||||||
let ptr_to = self.build.alloca(&tyl.layout, Some(name), stmt_span);
|
let ptr_to = self.build.alloca(tyl.layout, Some(name), stmt_span);
|
||||||
|
|
||||||
let variable_info = VariableInfo {
|
let variable_info = VariableInfo {
|
||||||
def_span: *def_span,
|
def_span: *def_span,
|
||||||
|
|
@ -158,7 +179,14 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
decl_attr,
|
decl_attr,
|
||||||
tyl: tyl.clone(),
|
tyl: tyl.clone(),
|
||||||
};
|
};
|
||||||
self.scopes.last_mut().unwrap().insert(name, variable_info);
|
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 {
|
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, tyl.layout, *init_span);
|
||||||
|
|
@ -166,7 +194,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Labeled { .. } => todo!("labels are not implemented"),
|
Stmt::Labeled { .. } => todo!("labels are not implemented"),
|
||||||
Stmt::Compound(_) => todo!("blocks are not implemented"),
|
Stmt::Compound(block) => {
|
||||||
|
self.lower_block(block)?;
|
||||||
|
}
|
||||||
Stmt::If {
|
Stmt::If {
|
||||||
cond,
|
cond,
|
||||||
then: then_body,
|
then: then_body,
|
||||||
|
|
@ -181,13 +211,13 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
let cont = self.build.new_block();
|
let cont = self.build.new_block();
|
||||||
|
|
||||||
self.build.current_bb = then;
|
self.build.current_bb = then;
|
||||||
self.lower_body(&then_body)?;
|
self.lower_block(then_body)?;
|
||||||
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
||||||
|
|
||||||
let false_branch = match els {
|
let false_branch = match els {
|
||||||
Some((otherwise, els)) => {
|
Some((otherwise, els)) => {
|
||||||
self.build.current_bb = els;
|
self.build.current_bb = els;
|
||||||
self.lower_body(&otherwise)?;
|
self.lower_block(otherwise)?;
|
||||||
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
self.build.cur_bb_mut().term = Branch::Goto(cont);
|
||||||
els
|
els
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +242,13 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
Stmt::Goto(_) => todo!(),
|
Stmt::Goto(_) => todo!(),
|
||||||
Stmt::Continue => todo!(),
|
Stmt::Continue => todo!(),
|
||||||
Stmt::Break => todo!(),
|
Stmt::Break => todo!(),
|
||||||
Stmt::Return(_) => todo!(),
|
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 {
|
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
|
||||||
op: ast::BinaryOp::Assign(assign),
|
op: ast::BinaryOp::Assign(assign),
|
||||||
lhs,
|
lhs,
|
||||||
|
|
@ -243,9 +279,43 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
ast::Expr::Atom(Atom::Char(c)) => Ok(Operand::Const(ConstValue::Int((*c).into()))),
|
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::Int(i)) => Ok(Operand::Const(ConstValue::Int(*i as _))),
|
||||||
ast::Expr::Atom(Atom::Float(_)) => todo!("no floats"),
|
ast::Expr::Atom(Atom::Float(_)) => todo!("no floats"),
|
||||||
ast::Expr::Atom(Atom::Ident(_)) => todo!("no idents"),
|
ast::Expr::Atom(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(Atom::String(_)) => todo!("no string literals"),
|
||||||
ast::Expr::Unary(_) => todo!("no unaries"),
|
ast::Expr::Unary(unary) => {
|
||||||
|
let _rhs = self.lower_expr(&unary.rhs.0, unary.rhs.1)?;
|
||||||
|
match unary.op {
|
||||||
|
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::Expr::Binary(ExprBinary {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
op: ast::BinaryOp::Assign(assign),
|
||||||
|
}) => {
|
||||||
|
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, span);
|
||||||
|
Ok(rhs)
|
||||||
|
}
|
||||||
ast::Expr::Binary(binary) => {
|
ast::Expr::Binary(binary) => {
|
||||||
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?;
|
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?;
|
||||||
let rhs = self.lower_expr(&binary.rhs.0, binary.rhs.1)?;
|
let rhs = self.lower_expr(&binary.rhs.0, binary.rhs.1)?;
|
||||||
|
|
@ -255,11 +325,11 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::Mod) => BinKind::Mod,
|
ast::BinaryOp::Arith(ast::ArithOpKind::Mod) => BinKind::Mod,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::Add) => BinKind::Add,
|
ast::BinaryOp::Arith(ast::ArithOpKind::Add) => BinKind::Add,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::Sub) => BinKind::Sub,
|
ast::BinaryOp::Arith(ast::ArithOpKind::Sub) => BinKind::Sub,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => todo!("shl"),
|
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => BinKind::Shl,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => todo!("shr"),
|
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => BinKind::Shr,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => todo!("&"),
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => BinKind::BitAnd,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => todo!("^"),
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => BinKind::BitXor,
|
||||||
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => todo!("|"),
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => BinKind::BitOr,
|
||||||
ast::BinaryOp::LogicalAnd => todo!("no logical or"),
|
ast::BinaryOp::LogicalAnd => todo!("no logical or"),
|
||||||
ast::BinaryOp::LogicalOr => todo!("no logical and"),
|
ast::BinaryOp::LogicalOr => todo!("no logical and"),
|
||||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Lt) => BinKind::Lt,
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Lt) => BinKind::Lt,
|
||||||
|
|
@ -268,9 +338,12 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
|
||||||
ast::BinaryOp::Comparison(ast::ComparisonKind::GtEq) => BinKind::Geq,
|
ast::BinaryOp::Comparison(ast::ComparisonKind::GtEq) => BinKind::Geq,
|
||||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Eq) => BinKind::Eq,
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Eq) => BinKind::Eq,
|
||||||
ast::BinaryOp::Comparison(ast::ComparisonKind::Neq) => BinKind::Neq,
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Neq) => BinKind::Neq,
|
||||||
ast::BinaryOp::Comma => todo!("no comma"),
|
ast::BinaryOp::Comma => {
|
||||||
|
// Discard the lhs, evaluate to the rhs.
|
||||||
|
return Ok(rhs);
|
||||||
|
}
|
||||||
ast::BinaryOp::Index => todo!("no index"),
|
ast::BinaryOp::Index => todo!("no index"),
|
||||||
ast::BinaryOp::Assign(_) => todo!("no assign"),
|
ast::BinaryOp::Assign(_) => unreachable!("assign handled above"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let reg = self.build.binary(
|
let reg = self.build.binary(
|
||||||
|
|
@ -329,12 +402,16 @@ fn lower_body<'cx>(
|
||||||
ret_ty: Ty<'cx>,
|
ret_ty: Ty<'cx>,
|
||||||
) -> Result<Func<'cx>, Error> {
|
) -> Result<Func<'cx>, Error> {
|
||||||
let mut cx = FnLoweringCtxt {
|
let mut cx = FnLoweringCtxt {
|
||||||
scopes: vec![FxHashMap::default()],
|
scopes: vec![],
|
||||||
build: FuncBuilder::new(name, def_span, ret_ty, lcx),
|
build: FuncBuilder::new(name, def_span, ret_ty, lcx),
|
||||||
lcx,
|
lcx,
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.lower_body(body)?;
|
cx.lower_block(body)?;
|
||||||
|
|
||||||
|
if let Branch::Goto(BbIdx(u32::MAX)) = cx.build.cur_bb_mut().term {
|
||||||
|
cx.build.cur_bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(cx.build.finish())
|
Ok(cx.build.finish())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
||||||
regs: Vec::new(),
|
regs: Vec::new(),
|
||||||
bbs: vec![BasicBlock {
|
bbs: vec![BasicBlock {
|
||||||
statements: Vec::new(),
|
statements: Vec::new(),
|
||||||
term: Branch::Goto(BbIdx(0)),
|
term: Branch::dummy(),
|
||||||
}],
|
}],
|
||||||
name,
|
name,
|
||||||
def_span,
|
def_span,
|
||||||
|
|
@ -134,14 +134,12 @@ impl<'a, 'cx> FuncBuilder<'a, 'cx> {
|
||||||
pub fn new_block(&mut self) -> BbIdx {
|
pub fn new_block(&mut self) -> BbIdx {
|
||||||
self.ir.bbs.push(BasicBlock {
|
self.ir.bbs.push(BasicBlock {
|
||||||
statements: vec![],
|
statements: vec![],
|
||||||
term: Branch::Goto(BbIdx(0)),
|
term: Branch::dummy(),
|
||||||
});
|
});
|
||||||
BbIdx::from_usize(self.ir.bbs.len() - 1)
|
BbIdx::from_usize(self.ir.bbs.len() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(mut self) -> Func<'cx> {
|
pub fn finish(self) -> Func<'cx> {
|
||||||
self.cur_bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
|
|
||||||
|
|
||||||
println!("{}", ir::func_to_string(&self.ir));
|
println!("{}", ir::func_to_string(&self.ir));
|
||||||
|
|
||||||
self.ir
|
self.ir
|
||||||
|
|
|
||||||
|
|
@ -484,6 +484,16 @@ where
|
||||||
return self.if_statement();
|
return self.if_statement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some((_, span)) = eat!(self, Tok::Kw(Kw::Return)) {
|
||||||
|
if let Some((_, semi_span)) = eat!(self, Tok::Punct(P::Semicolon)) {
|
||||||
|
return Ok((Stmt::Return(None), span.extend(semi_span)));
|
||||||
|
} else {
|
||||||
|
let expr = self.expr()?;
|
||||||
|
let semi_span = expect!(self, Tok::Punct(P::Semicolon));
|
||||||
|
return Ok((Stmt::Return(Some(expr)), span.extend(semi_span)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// it must be an expression stmt
|
// it must be an expression stmt
|
||||||
let (expr, span) = self.expr()?;
|
let (expr, span) = self.expr()?;
|
||||||
expect!(self, Tok::Punct(P::Semicolon));
|
expect!(self, Tok::Punct(P::Semicolon));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
source: parser/src/parser/tests.rs
|
||||||
|
expression: "(parsed_pretty, pretty_printed_source)"
|
||||||
|
---
|
||||||
|
(
|
||||||
|
Ok([
|
||||||
|
(
|
||||||
|
FunctionDef(FunctionDef {
|
||||||
|
decl: Normal(NormalDecl {
|
||||||
|
decl_spec: DeclSpec {
|
||||||
|
ty: Integer(IntTy { sign: Signed, kind: Int }),
|
||||||
|
attrs: "(empty)",
|
||||||
|
},
|
||||||
|
init_declarators: [
|
||||||
|
(
|
||||||
|
InitDecl {
|
||||||
|
declarator: Declarator {
|
||||||
|
decl: WithParams {
|
||||||
|
ident: (main, 5..9),
|
||||||
|
params: [],
|
||||||
|
},
|
||||||
|
pointer: false,
|
||||||
|
},
|
||||||
|
init: None,
|
||||||
|
},
|
||||||
|
5..9,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
body: [(Return(None), 18..25)],
|
||||||
|
}),
|
||||||
|
1..27,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
"int main() {\n return\n}\n",
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
source: parser/src/parser/tests.rs
|
||||||
|
expression: "(parsed_pretty, pretty_printed_source)"
|
||||||
|
---
|
||||||
|
(
|
||||||
|
Ok([
|
||||||
|
(
|
||||||
|
FunctionDef(FunctionDef {
|
||||||
|
decl: Normal(NormalDecl {
|
||||||
|
decl_spec: DeclSpec {
|
||||||
|
ty: Integer(IntTy { sign: Signed, kind: Int }),
|
||||||
|
attrs: "(empty)",
|
||||||
|
},
|
||||||
|
init_declarators: [
|
||||||
|
(
|
||||||
|
InitDecl {
|
||||||
|
declarator: Declarator {
|
||||||
|
decl: WithParams {
|
||||||
|
ident: (main, 5..9),
|
||||||
|
params: [],
|
||||||
|
},
|
||||||
|
pointer: false,
|
||||||
|
},
|
||||||
|
init: None,
|
||||||
|
},
|
||||||
|
5..9,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
body: [(Return(Some((Atom(Int(0)), 25..26))), 18..27)],
|
||||||
|
}),
|
||||||
|
1..29,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
"int main() {\n return 0\n}\n",
|
||||||
|
)
|
||||||
|
|
@ -202,3 +202,25 @@ int main() {
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_empty() {
|
||||||
|
parse_test!(
|
||||||
|
r#"
|
||||||
|
int main() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_expr() {
|
||||||
|
parse_test!(
|
||||||
|
r#"
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ impl CLexExt for u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_c_identifier_digit(&self) -> bool {
|
fn is_c_identifier_digit(&self) -> bool {
|
||||||
matches!(self, b'0'..=b'9')
|
self.is_ascii_digit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_c_whitespace(&self) -> bool {
|
fn is_c_whitespace(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,11 @@ fn main() {
|
||||||
|
|
||||||
let arena = bumpalo::Bump::new();
|
let arena = bumpalo::Bump::new();
|
||||||
|
|
||||||
let _ = analysis::lower_translation_unit(&arena, &ast);
|
let ir = analysis::lower_translation_unit(&arena, &ast);
|
||||||
|
match ir {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
dbg!(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue