mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 08:35:08 +01:00
more
This commit is contained in:
parent
542c0daf6a
commit
86b924f5e3
7 changed files with 171 additions and 67 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ pub enum Atom {
|
|||
|
||||
#[derive(Debug, DebugPls)]
|
||||
pub enum UnaryOp {
|
||||
Increment,
|
||||
Decrement,
|
||||
AddrOf,
|
||||
Deref,
|
||||
Plus,
|
||||
|
|
|
|||
|
|
@ -376,6 +376,8 @@ impl<W: Write> PrettyPrinter<W> {
|
|||
|
||||
fn unary(&mut self, unary: &ExprUnary) -> Result {
|
||||
self.string(match unary.op {
|
||||
UnaryOp::Increment => "++",
|
||||
UnaryOp::Decrement => "--",
|
||||
UnaryOp::AddrOf => "&",
|
||||
UnaryOp::Deref => "*",
|
||||
UnaryOp::Plus => "+",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue