mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
more lowering
This commit is contained in:
parent
e68ec920f5
commit
8bf9849641
7 changed files with 295 additions and 17 deletions
163
analysis/src/ir/pretty.rs
Normal file
163
analysis/src/ir/pretty.rs
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
use std::fmt::{Display, Formatter, Result, Write};
|
||||||
|
|
||||||
|
use super::{BinKind, Branch, ConstValue, Func, Ir, Operand, StatementKind};
|
||||||
|
use crate::ir::Register;
|
||||||
|
|
||||||
|
pub fn ir_to_string(ir: &Ir) -> String {
|
||||||
|
let mut buf = String::new();
|
||||||
|
PrettyPrinter { out: &mut buf }.ir(ir).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn func_to_string(func: &Func) -> String {
|
||||||
|
let mut buf = String::new();
|
||||||
|
PrettyPrinter { out: &mut buf }.func(func).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrettyPrinter<W> {
|
||||||
|
out: W,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Write> PrettyPrinter<W> {
|
||||||
|
pub fn ir(&mut self, ir: &Ir) -> Result {
|
||||||
|
for (_, func) in &ir.funcs {
|
||||||
|
self.func(func)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn func(&mut self, func: &Func) -> Result {
|
||||||
|
writeln!(self.out, "def {}() {{", func.name)?;
|
||||||
|
|
||||||
|
let print_reg = |reg: Register| {
|
||||||
|
display_fn(move |f| match func.regs[reg.0 as usize].name {
|
||||||
|
None => write!(f, "%{}", reg.0),
|
||||||
|
Some(name) => write!(f, "%{name}"),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let print_op = |op: Operand| {
|
||||||
|
display_fn(move |f| match op {
|
||||||
|
Operand::Const(c) => Display::fmt(&c, f),
|
||||||
|
Operand::Reg(reg) => Display::fmt(&print_reg(reg), f),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i, bb) in func.bbs.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
writeln!(self.out)?;
|
||||||
|
}
|
||||||
|
writeln!(self.out, " {i}:")?;
|
||||||
|
|
||||||
|
for stmt in &bb.statements {
|
||||||
|
match stmt.kind {
|
||||||
|
StatementKind::Alloca { reg, size, align } => {
|
||||||
|
writeln!(
|
||||||
|
self.out,
|
||||||
|
" {} = alloca, size={}, align={}",
|
||||||
|
print_reg(reg),
|
||||||
|
print_op(size),
|
||||||
|
print_op(align)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
StatementKind::Store {
|
||||||
|
ptr_reg,
|
||||||
|
value,
|
||||||
|
size,
|
||||||
|
align,
|
||||||
|
} => writeln!(
|
||||||
|
self.out,
|
||||||
|
" store {}, {}, size={}, align={}",
|
||||||
|
print_reg(ptr_reg),
|
||||||
|
print_op(value),
|
||||||
|
print_op(size),
|
||||||
|
print_op(align)
|
||||||
|
),
|
||||||
|
StatementKind::Load {
|
||||||
|
result,
|
||||||
|
ptr_reg,
|
||||||
|
size,
|
||||||
|
align,
|
||||||
|
} => writeln!(
|
||||||
|
self.out,
|
||||||
|
" {} = load {}, size={}, align={}",
|
||||||
|
print_reg(result),
|
||||||
|
print_reg(ptr_reg),
|
||||||
|
print_op(size),
|
||||||
|
print_op(align)
|
||||||
|
),
|
||||||
|
StatementKind::BinOp {
|
||||||
|
kind,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
result,
|
||||||
|
} => writeln!(
|
||||||
|
self.out,
|
||||||
|
" {} = {} {}, {}",
|
||||||
|
print_reg(result),
|
||||||
|
match kind {
|
||||||
|
BinKind::Add => "add",
|
||||||
|
BinKind::Sub => "sub",
|
||||||
|
BinKind::Mul => "mul",
|
||||||
|
BinKind::Div => "div",
|
||||||
|
BinKind::Mod => "mod",
|
||||||
|
BinKind::Eq => "eq",
|
||||||
|
BinKind::Neq => "neq",
|
||||||
|
BinKind::Gt => "gt",
|
||||||
|
BinKind::Geq => "geq",
|
||||||
|
BinKind::Lt => "gl",
|
||||||
|
BinKind::Leq => "leq",
|
||||||
|
},
|
||||||
|
print_op(lhs),
|
||||||
|
print_op(rhs)
|
||||||
|
),
|
||||||
|
StatementKind::PtrOffset {
|
||||||
|
result,
|
||||||
|
reg,
|
||||||
|
amount,
|
||||||
|
} => writeln!(
|
||||||
|
self.out,
|
||||||
|
" {} = ptroffset {}, {}",
|
||||||
|
print_reg(result),
|
||||||
|
print_reg(reg),
|
||||||
|
print_op(amount)
|
||||||
|
),
|
||||||
|
}?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match bb.term {
|
||||||
|
Branch::Goto(bbn) => writeln!(self.out, " goto {}", bbn)?,
|
||||||
|
Branch::Switch { cond, yes, no } => {
|
||||||
|
writeln!(self.out, " switch {}, {yes}, {no}", print_op(cond))?
|
||||||
|
}
|
||||||
|
Branch::Ret(op) => writeln!(self.out, " ret {}", print_op(op))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ConstValue {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
match self {
|
||||||
|
ConstValue::Int(int) => <_ as Display>::fmt(int, f),
|
||||||
|
ConstValue::Void => f.write_str("void"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_fn<F: Fn(&mut Formatter<'_>) -> Result>(f: F) -> impl Display {
|
||||||
|
struct DisplayFn<F> {
|
||||||
|
f: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Fn(&mut Formatter<'_>) -> Result> Display for DisplayFn<F> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||||
|
(self.f)(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayFn { f }
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,10 @@ pub struct Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn new(msg: String, span: Span) -> Self {
|
pub fn new(msg: impl Into<String>, span: Span) -> Self {
|
||||||
Self { msg, span }
|
Self {
|
||||||
|
msg: msg.into(),
|
||||||
|
span,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
use parser::{
|
use parser::{
|
||||||
ast::{DeclAttr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier},
|
ast::{self, Atom, DeclAttr, Expr, ExternalDecl, Stmt, TranslationUnit, TypeSpecifier},
|
||||||
Span, Symbol,
|
Span, Symbol,
|
||||||
};
|
};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{
|
ir::{
|
||||||
BasicBlock, Branch, ConstValue, Func, Ir, Layout, Operand, Register, RegisterData,
|
self, BasicBlock, BinKind, Branch, ConstValue, Func, Ir, Layout, Operand, Register,
|
||||||
Statement, StatementKind,
|
RegisterData, Statement, StatementKind,
|
||||||
},
|
},
|
||||||
ty::Ty,
|
ty::Ty,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
struct LoweringCx {}
|
struct LoweringCx {}
|
||||||
|
|
||||||
pub fn lower_translation_unit(ast: &TranslationUnit) -> Result<Ir, Error> {
|
pub fn lower_translation_unit(ast: &TranslationUnit) -> Result<Ir, Error> {
|
||||||
|
|
@ -25,7 +27,13 @@ pub fn lower_translation_unit(ast: &TranslationUnit) -> Result<Ir, Error> {
|
||||||
let decl = def.decl.uwnrap_normal();
|
let decl = def.decl.uwnrap_normal();
|
||||||
let body = &def.body;
|
let body = &def.body;
|
||||||
let ret_ty = lower_ty(&decl.decl_spec.ty);
|
let ret_ty = lower_ty(&decl.decl_spec.ty);
|
||||||
lower_body(&mut lcx, body, decl.init_declarators[0].1, ret_ty)?;
|
lower_body(
|
||||||
|
&mut lcx,
|
||||||
|
body,
|
||||||
|
decl.init_declarators[0].1,
|
||||||
|
decl.init_declarators[0].0.declarator.decl.name().0,
|
||||||
|
ret_ty,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,10 +49,18 @@ struct FnLoweringCtxt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnLoweringCtxt {
|
impl FnLoweringCtxt {
|
||||||
|
fn resolve_ident(&self, ident: Symbol) -> Option<&VariableInfo> {
|
||||||
|
self.scopes.iter().rev().find_map(|s| s.get(&ident))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_reg(&mut self, name: Option<Symbol>) -> Register {
|
||||||
|
let reg = Register(self.ir.regs.len().try_into().unwrap());
|
||||||
|
self.ir.regs.push(RegisterData { name });
|
||||||
|
reg
|
||||||
|
}
|
||||||
|
|
||||||
fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register {
|
fn alloca(&mut self, layout: &Layout, name: Option<Symbol>, span: Span) -> Register {
|
||||||
let bb = self.bb_mut();
|
let reg = self.new_reg(name);
|
||||||
let reg = Register(bb.regs.len().try_into().unwrap());
|
|
||||||
bb.regs.push(RegisterData { name });
|
|
||||||
let stmt = Statement {
|
let stmt = Statement {
|
||||||
span,
|
span,
|
||||||
kind: StatementKind::Alloca {
|
kind: StatementKind::Alloca {
|
||||||
|
|
@ -53,10 +69,62 @@ impl FnLoweringCtxt {
|
||||||
align: Operand::Const(ConstValue::u64(layout.align)),
|
align: Operand::Const(ConstValue::u64(layout.align)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
bb.statements.push(stmt);
|
self.bb_mut().statements.push(stmt);
|
||||||
reg
|
reg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(_)) => todo!("no idents"),
|
||||||
|
ast::Expr::Atom(Atom::String(_)) => todo!("no string literals"),
|
||||||
|
ast::Expr::Unary(_) => todo!("no unaries"),
|
||||||
|
ast::Expr::Binary(binary) => {
|
||||||
|
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?;
|
||||||
|
let rhs = self.lower_expr(&binary.rhs.0, binary.rhs.1)?;
|
||||||
|
let kind = match binary.op {
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Mul) => BinKind::Mul,
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Div) => BinKind::Div,
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Mod) => BinKind::Mod,
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Add) => BinKind::Add,
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Sub) => BinKind::Sub,
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => todo!("shl"),
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => todo!("shr"),
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => todo!("&"),
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => todo!("^"),
|
||||||
|
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => todo!("|"),
|
||||||
|
ast::BinaryOp::LogicalAnd => todo!("no logical or"),
|
||||||
|
ast::BinaryOp::LogicalOr => todo!("no logical and"),
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Lt) => BinKind::Lt,
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Gt) => BinKind::Gt,
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::LtEq) => BinKind::Leq,
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::GtEq) => BinKind::Geq,
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Eq) => BinKind::Eq,
|
||||||
|
ast::BinaryOp::Comparison(ast::ComparisonKind::Neq) => BinKind::Neq,
|
||||||
|
ast::BinaryOp::Comma => todo!("no comma"),
|
||||||
|
ast::BinaryOp::Index => todo!("no index"),
|
||||||
|
ast::BinaryOp::Assign(_) => todo!("no assign"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let reg = self.new_reg(None);
|
||||||
|
let stmt = StatementKind::BinOp {
|
||||||
|
kind,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
result: reg,
|
||||||
|
};
|
||||||
|
self.bb_mut()
|
||||||
|
.statements
|
||||||
|
.push(Statement { span, kind: stmt });
|
||||||
|
|
||||||
|
Ok(Operand::Reg(reg))
|
||||||
|
}
|
||||||
|
Expr::Postfix(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn bb_mut(&mut self) -> &mut BasicBlock {
|
fn bb_mut(&mut self) -> &mut BasicBlock {
|
||||||
&mut self.ir.bbs[self.current_bb as usize]
|
&mut self.ir.bbs[self.current_bb as usize]
|
||||||
}
|
}
|
||||||
|
|
@ -76,16 +144,18 @@ fn lower_body(
|
||||||
_lcx: &mut LoweringCx,
|
_lcx: &mut LoweringCx,
|
||||||
body: &[(Stmt, Span)],
|
body: &[(Stmt, Span)],
|
||||||
def_span: Span,
|
def_span: Span,
|
||||||
|
name: Symbol,
|
||||||
ret_ty: Ty,
|
ret_ty: Ty,
|
||||||
) -> Result<Func, Error> {
|
) -> Result<Func, Error> {
|
||||||
let mut cx: FnLoweringCtxt = FnLoweringCtxt {
|
let mut cx: FnLoweringCtxt = FnLoweringCtxt {
|
||||||
scopes: vec![FxHashMap::default()],
|
scopes: vec![FxHashMap::default()],
|
||||||
ir: Func {
|
ir: Func {
|
||||||
|
regs: Vec::new(),
|
||||||
bbs: vec![BasicBlock {
|
bbs: vec![BasicBlock {
|
||||||
regs: Vec::new(),
|
|
||||||
statements: Vec::new(),
|
statements: Vec::new(),
|
||||||
term: Branch::Goto(0),
|
term: Branch::Goto(0),
|
||||||
}],
|
}],
|
||||||
|
name,
|
||||||
def_span,
|
def_span,
|
||||||
ret_ty,
|
ret_ty,
|
||||||
},
|
},
|
||||||
|
|
@ -134,12 +204,44 @@ fn lower_body(
|
||||||
Stmt::Continue => todo!(),
|
Stmt::Continue => todo!(),
|
||||||
Stmt::Break => todo!(),
|
Stmt::Break => todo!(),
|
||||||
Stmt::Return(_) => todo!(),
|
Stmt::Return(_) => todo!(),
|
||||||
Stmt::Expr(_) => todo!(),
|
Stmt::Expr(ast::Expr::Binary(ast::ExprBinary {
|
||||||
|
op: ast::BinaryOp::Assign(assign),
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
})) => {
|
||||||
|
if assign.is_some() {
|
||||||
|
todo!("assign operation");
|
||||||
|
}
|
||||||
|
let rhs = cx.lower_expr(&rhs.0, rhs.1)?;
|
||||||
|
let (Expr::Atom(ast::Atom::Ident((ident, ident_span))), _) = **lhs else {
|
||||||
|
todo!("complex assignments")
|
||||||
|
};
|
||||||
|
let Some(var) = cx.resolve_ident(ident) else {
|
||||||
|
return Err(Error::new(format!("cannot find variable {ident}"), ident_span));
|
||||||
|
};
|
||||||
|
let stmt = StatementKind::Store {
|
||||||
|
ptr_reg: var.ptr_to,
|
||||||
|
value: rhs,
|
||||||
|
size: Operand::const_u64(var.layout.size),
|
||||||
|
align: Operand::const_u64(var.layout.align),
|
||||||
|
};
|
||||||
|
cx.bb_mut().statements.push(Statement {
|
||||||
|
span: *stmt_span,
|
||||||
|
kind: stmt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Stmt::Expr(expr) => {
|
||||||
|
cx.lower_expr(expr, *stmt_span)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx.bb_mut().term = Branch::Ret(Operand::Const(ConstValue::Void));
|
||||||
|
|
||||||
dbg!(&cx);
|
dbg!(&cx);
|
||||||
|
|
||||||
|
println!("{}", ir::func_to_string(&cx.ir));
|
||||||
|
|
||||||
Ok(cx.ir)
|
Ok(cx.ir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ use std::fmt::Debug;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use dbg_pls::DebugPls;
|
use dbg_pls::DebugPls;
|
||||||
|
|
||||||
use crate::{sym::Symbol, Spanned};
|
use crate::sym::Symbol;
|
||||||
|
pub use crate::Spanned;
|
||||||
|
|
||||||
pub type Ident = Spanned<Symbol>;
|
pub type Ident = Spanned<Symbol>;
|
||||||
|
|
||||||
|
|
@ -14,7 +15,7 @@ pub type Ident = Spanned<Symbol>;
|
||||||
#[derive(Debug, DebugPls)]
|
#[derive(Debug, DebugPls)]
|
||||||
pub enum Atom {
|
pub enum Atom {
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
Int(i128),
|
Int(u128),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
String(String),
|
String(String),
|
||||||
Char(u8),
|
Char(u8),
|
||||||
|
|
|
||||||
|
|
@ -512,7 +512,6 @@ where
|
||||||
|
|
||||||
// TODO: recover here
|
// TODO: recover here
|
||||||
let stmt = self.statement()?;
|
let stmt = self.statement()?;
|
||||||
|
|
||||||
stmts.push(stmt);
|
stmts.push(stmt);
|
||||||
};
|
};
|
||||||
Ok((stmts, brace_span.extend(end_span)))
|
Ok((stmts, brace_span.extend(end_span)))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
use std::{cell::RefCell, fmt::Debug, marker::PhantomData};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
use dbg_pls::DebugPls;
|
use dbg_pls::DebugPls;
|
||||||
use lasso::Spur;
|
use lasso::Spur;
|
||||||
|
|
@ -37,3 +41,9 @@ impl DebugPls for Symbol {
|
||||||
self.as_str(|s| f.debug_ident(s))
|
self.as_str(|s| f.debug_ident(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Symbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
INTERNER.with(|i| f.write_str(i.borrow_mut().resolve(&self.spur)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ pub enum Keyword {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Constant {
|
pub enum Constant {
|
||||||
Int(i128),
|
Int(u128),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Char(u8),
|
Char(u8),
|
||||||
// adding enumerations here makes no sense.
|
// adding enumerations here makes no sense.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue