This commit is contained in:
nora 2023-05-23 21:16:49 +02:00
parent 54226ad499
commit 05c617f6de
8 changed files with 150 additions and 72 deletions

View file

@ -178,6 +178,8 @@ pub enum BinKind {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum UnaryKind { pub enum UnaryKind {
Zext,
Sext,
Negate, Negate,
BitNot, BitNot,
LogicalNot, LogicalNot,

View file

@ -130,6 +130,8 @@ impl<W: Write> PrettyPrinter<W> {
" {} = {} {}", " {} = {} {}",
print_reg(result), print_reg(result),
match kind { match kind {
UnaryKind::Zext => "zext",
UnaryKind::Sext => "sext",
UnaryKind::Negate => "negate", UnaryKind::Negate => "negate",
UnaryKind::BitNot => "bitnot", UnaryKind::BitNot => "bitnot",
UnaryKind::LogicalNot => "logicalnot", UnaryKind::LogicalNot => "logicalnot",

View file

@ -4,12 +4,12 @@ mod typeck;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use parser::{ use parser::{
ast::{self, IntTy, IntTyKind, IntTySignedness}, ast::{self, ExprBinary, IntTy, IntTyKind, IntSign},
Span, Symbol, Span, Symbol,
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use self::builder::FuncBuilder; use self::{builder::FuncBuilder, typeck::Coercion};
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,
@ -40,7 +40,7 @@ impl<'cx> LoweringCx<'cx> {
let kind = match ty { let kind = match ty {
ast::TypeSpecifier::Void => TyKind::Void, ast::TypeSpecifier::Void => TyKind::Void,
ast::TypeSpecifier::Char => TyKind::Char, ast::TypeSpecifier::Char => TyKind::Char,
ast::TypeSpecifier::Integer(int) => TyKind::Integer(*int), ast::TypeSpecifier::Integer(int) => TyKind::Int(*int),
ast::TypeSpecifier::Float => TyKind::Float, ast::TypeSpecifier::Float => TyKind::Float,
ast::TypeSpecifier::Double => TyKind::Double, ast::TypeSpecifier::Double => TyKind::Double,
ast::TypeSpecifier::LongDouble => TyKind::LongDouble, ast::TypeSpecifier::LongDouble => TyKind::LongDouble,
@ -89,7 +89,7 @@ impl<'cx> LoweringCx<'cx> {
let layout = match *ty { let layout = match *ty {
TyKind::Void => Layout::size_align(0, 1), TyKind::Void => Layout::size_align(0, 1),
TyKind::Char => Layout::size_align(1, 1), TyKind::Char => Layout::size_align(1, 1),
TyKind::Integer(int) => match int.kind { TyKind::Int(int) => match int.kind {
IntTyKind::Bool => Layout::size_align(1, 1), IntTyKind::Bool => Layout::size_align(1, 1),
IntTyKind::Char => Layout::size_align(1, 1), IntTyKind::Char => Layout::size_align(1, 1),
IntTyKind::Short => Layout::size_align(2, 2), IntTyKind::Short => Layout::size_align(2, 2),
@ -403,34 +403,66 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
.store(ptr_to, rhs.0, self.dummy_tyl().layout, span); .store(ptr_to, rhs.0, self.dummy_tyl().layout, span);
rhs rhs
} }
ast::Expr::Binary(binary) => { ast::Expr::Binary(ExprBinary {
let lhs = self.lower_expr(&binary.lhs.0, binary.lhs.1)?; op: ast::BinaryOp::Arith(arith),
let rhs = self.lower_expr(&binary.rhs.0, binary.rhs.1)?; lhs: lhs_expr,
let kind = match binary.op { rhs: rhs_expr,
ast::BinaryOp::Arith(ast::ArithOpKind::Mul) => BinKind::Mul, }) => {
ast::BinaryOp::Arith(ast::ArithOpKind::Div) => BinKind::Div, let (mut lhs, lhs_tyl) = self.lower_expr(&lhs_expr.0, lhs_expr.1)?;
ast::BinaryOp::Arith(ast::ArithOpKind::Mod) => BinKind::Mod, let (mut rhs, rhs_tyl) = self.lower_expr(&rhs_expr.0, rhs_expr.1)?;
ast::BinaryOp::Arith(ast::ArithOpKind::Add) => BinKind::Add,
ast::BinaryOp::Arith(ast::ArithOpKind::Sub) => BinKind::Sub, let (result, lhs_coerce, rhs_coerce) =
ast::BinaryOp::Arith(ast::ArithOpKind::Shl) => BinKind::Shl, self.arith_op(lhs_tyl.ty, rhs_tyl.ty, span)?;
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => BinKind::Shr,
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => BinKind::BitAnd, let mut do_coerce = |reg, coerce, span, ty| {
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => BinKind::BitXor, let kind = match coerce {
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => BinKind::BitOr, Coercion::ZeroExt => UnaryKind::Zext,
ast::BinaryOp::LogicalAnd => todo!("no logical or"), Coercion::SignExt => UnaryKind::Sext,
ast::BinaryOp::LogicalOr => todo!("no logical and"), Coercion::SignToUnsigned => todo!("hm, what should this do"),
ast::BinaryOp::Comparison(ast::ComparisonKind::Lt) => BinKind::Lt, };
ast::BinaryOp::Comparison(ast::ComparisonKind::Gt) => BinKind::Gt, Operand::Reg(self.build.unary(kind, reg, span, self.lcx.layout_of(ty)))
ast::BinaryOp::Comparison(ast::ComparisonKind::LtEq) => BinKind::Leq, };
ast::BinaryOp::Comparison(ast::ComparisonKind::GtEq) => BinKind::Geq,
ast::BinaryOp::Comparison(ast::ComparisonKind::Eq) => BinKind::Eq, for (coerce, ty) in lhs_coerce {
ast::BinaryOp::Comparison(ast::ComparisonKind::Neq) => BinKind::Neq, lhs = do_coerce(lhs, coerce, span, ty);
ast::BinaryOp::Comma => { }
// Discard the lhs, evaluate to the rhs. for (coerce, ty) in rhs_coerce {
return Ok(rhs); rhs = do_coerce(rhs, coerce, span, ty);
} }
ast::BinaryOp::Index => todo!("no index"),
ast::BinaryOp::Assign(_) => unreachable!("assign handled above"), let kind = match arith {
ast::ArithOpKind::Mul => BinKind::Mul,
ast::ArithOpKind::Div => BinKind::Div,
ast::ArithOpKind::Mod => BinKind::Mod,
ast::ArithOpKind::Add => BinKind::Add,
ast::ArithOpKind::Sub => BinKind::Sub,
ast::ArithOpKind::Shl => BinKind::Shl,
ast::ArithOpKind::Shr => BinKind::Shr,
ast::ArithOpKind::BitAnd => BinKind::BitAnd,
ast::ArithOpKind::BitXor => BinKind::BitXor,
ast::ArithOpKind::BitOr => BinKind::BitOr,
};
let reg = self
.build
.binary(kind, lhs, rhs, span, self.lcx.layout_of(result));
(Operand::Reg(reg), self.dummy_tyl())
}
ast::Expr::Binary(ExprBinary {
op: ast::BinaryOp::Comparison(comp),
lhs,
rhs,
}) => {
let lhs = self.lower_expr(&lhs.0, lhs.1)?;
let rhs = self.lower_expr(&rhs.0, rhs.1)?;
let kind = match comp {
ast::ComparisonKind::Lt => BinKind::Lt,
ast::ComparisonKind::Gt => BinKind::Gt,
ast::ComparisonKind::LtEq => BinKind::Leq,
ast::ComparisonKind::GtEq => BinKind::Geq,
ast::ComparisonKind::Eq => BinKind::Eq,
ast::ComparisonKind::Neq => BinKind::Neq,
}; };
let reg = self let reg = self
@ -439,6 +471,16 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
(Operand::Reg(reg), self.dummy_tyl()) (Operand::Reg(reg), self.dummy_tyl())
} }
ast::Expr::Binary(ExprBinary {
op: ast::BinaryOp::Comma,
lhs,
rhs,
}) => {
let _lhs = self.lower_expr(&lhs.0, lhs.1)?;
// Discard the lhs, evaluate to the rhs.
self.lower_expr(&rhs.0, rhs.1)?
}
ast::Expr::Binary(_) => todo!("other binary"),
ast::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 {
@ -546,10 +588,10 @@ fn lower_func<'cx>(
impl<'cx> CommonTypes<'cx> { impl<'cx> CommonTypes<'cx> {
fn new(lcx: &LoweringCx<'cx>) -> Self { fn new(lcx: &LoweringCx<'cx>) -> Self {
let int = |sign, kind| lcx.intern_ty(TyKind::Integer(IntTy { sign, kind })); let int = |sign, kind| lcx.intern_ty(TyKind::Int(IntTy { sign, kind }));
let int_pair = |kind| CommonInt { let int_pair = |kind| CommonInt {
signed: int(IntTySignedness::Signed, kind), signed: int(IntSign::Signed, kind),
unsigned: int(IntTySignedness::Unsigned, kind), unsigned: int(IntSign::Unsigned, kind),
}; };
Self { Self {

View file

@ -1,5 +1,5 @@
use parser::{ use parser::{
ast::{IntTy, IntTyKind, IntTySignedness}, ast::{IntSign, IntTy, IntTyKind},
Span, Span,
}; };
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -109,9 +109,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
} else { } else {
rhs_kind rhs_kind
}; };
let ty = self.lcx.intern_ty(TyKind::Integer(IntTy { let ty = self.lcx.intern_ty(TyKind::Int(IntTy {
kind, kind,
sign: IntTySignedness::Unsigned, sign: IntSign::Unsigned,
})); }));
lhs_coerce.extend(self.coerce(lhs_prom, ty)?); lhs_coerce.extend(self.coerce(lhs_prom, ty)?);
ty ty
@ -123,23 +123,58 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
} }
fn coerce(&mut self, from: Ty<'cx>, to: Ty<'cx>) -> Result<Coercions<'cx>> { fn coerce(&mut self, from: Ty<'cx>, to: Ty<'cx>) -> Result<Coercions<'cx>> {
if from != to { if from == to {
todo!("coerce.") return Ok(smallvec![]);
} }
Ok(smallvec![]) Ok(match (*from, *to) {
(
TyKind::Char,
TyKind::Int(IntTy {
sign: IntSign::Signed,
..
}),
) => {
smallvec![(Coercion::SignExt, to)]
}
(
TyKind::Int(IntTy {
sign: IntSign::Signed,
kind: from_kind,
}),
TyKind::Int(IntTy {
sign: IntSign::Signed,
kind: to_kind,
}),
) if from_kind < to_kind => {
smallvec![(Coercion::SignExt, to)]
}
(
TyKind::Int(IntTy {
sign: IntSign::Unsigned,
kind: from_kind,
}),
TyKind::Int(IntTy {
sign: IntSign::Unsigned,
kind: to_kind,
}),
) if from_kind < to_kind => {
smallvec![(Coercion::ZeroExt, to)]
}
_ => panic!("i cant coerce that"),
})
} }
// §6.3.1.1 Boolean, characters, and integers // §6.3.1.1 Boolean, characters, and integers
fn promote(&self, ty: Ty<'cx>, span: Span) -> Result<Coercions<'cx>> { fn promote(&self, ty: Ty<'cx>, span: Span) -> Result<Coercions<'cx>> {
Ok(match *ty { Ok(match *ty {
TyKind::Char => smallvec![(Coercion::SignExt, self.types.int.signed)], TyKind::Char => smallvec![(Coercion::SignExt, self.types.int.signed)],
TyKind::Integer(int) if int.kind < IntTyKind::Int => match int.sign { TyKind::Int(int) if int.kind < IntTyKind::Int => match int.sign {
IntTySignedness::Signed => smallvec![(Coercion::SignExt, self.types.int.signed)], IntSign::Signed => smallvec![(Coercion::SignExt, self.types.int.signed)],
IntTySignedness::Unsigned => { IntSign::Unsigned => {
smallvec![(Coercion::ZeroExt, self.types.int.unsigned)] smallvec![(Coercion::ZeroExt, self.types.int.unsigned)]
} }
}, },
TyKind::Integer(_) => smallvec![], TyKind::Int(_) => smallvec![],
TyKind::Enum(_) => todo!("enums are unimplemented"), TyKind::Enum(_) => todo!("enums are unimplemented"),
_ => return Err(Error::new(format!("cannot convert {ty} to integer"), span)), _ => return Err(Error::new(format!("cannot convert {ty} to integer"), span)),
}) })

View file

@ -6,7 +6,7 @@ use std::{
use indexmap::IndexMap; use indexmap::IndexMap;
use parser::{ use parser::{
ast::{IntTy, IntTyKind, IntTySignedness}, ast::{IntTy, IntTyKind, IntSign},
Symbol, Symbol,
}; };
@ -19,7 +19,7 @@ pub struct Ty<'cx>(&'cx TyKind<'cx>);
pub enum TyKind<'cx> { pub enum TyKind<'cx> {
Void, Void,
Char, Char,
Integer(IntTy), Int(IntTy),
Float, Float,
Double, Double,
LongDouble, LongDouble,
@ -47,12 +47,6 @@ pub struct EnumTy {
pub variants: IndexMap<Symbol, i128>, pub variants: IndexMap<Symbol, i128>,
} }
impl<'cx> Ty<'cx> {
pub fn new_unchecked(kind: &'cx TyKind<'cx>) -> Self {
Self(kind)
}
}
impl<'cx> Deref for Ty<'cx> { impl<'cx> Deref for Ty<'cx> {
type Target = &'cx TyKind<'cx>; type Target = &'cx TyKind<'cx>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -81,10 +75,10 @@ impl Display for Ty<'_> {
match **self { match **self {
TyKind::Void => f.write_str("void"), TyKind::Void => f.write_str("void"),
TyKind::Char => f.write_str("char"), TyKind::Char => f.write_str("char"),
TyKind::Integer(int) => { TyKind::Int(int) => {
match int.sign { match int.sign {
IntTySignedness::Signed => f.write_str("signed "), IntSign::Signed => f.write_str("signed "),
IntTySignedness::Unsigned => f.write_str("unsigned "), IntSign::Unsigned => f.write_str("unsigned "),
}?; }?;
match int.kind { match int.kind {
IntTyKind::Bool => f.write_str("_Bool"), IntTyKind::Bool => f.write_str("_Bool"),
@ -112,25 +106,28 @@ impl Display for Ty<'_> {
impl PartialEq for Ty<'_> { impl PartialEq for Ty<'_> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
// Interning. // Interning.
std::ptr::eq(&self.0, &other.0) std::ptr::eq(self.0, other.0)
} }
} }
impl Hash for Ty<'_> { impl Hash for Ty<'_> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
// Interning. // Interning.
std::ptr::hash(&self.0, state) std::ptr::hash(self.0, state)
} }
} }
impl<'cx> Ty<'cx> { impl<'cx> Ty<'cx> {
pub fn new_unchecked(kind: &'cx TyKind<'cx>) -> Self {
Self(kind)
}
pub fn is_integral(self) -> bool { pub fn is_integral(self) -> bool {
matches!(*self, TyKind::Char | TyKind::Integer(_)) matches!(*self, TyKind::Char | TyKind::Int(_))
} }
pub fn unwrap_int(self) -> IntTy { pub fn unwrap_int(self) -> IntTy {
match *self { match *self {
TyKind::Integer(int) => *int, TyKind::Int(int) => *int,
_ => panic!("expected integer type, found {self}"), _ => panic!("expected integer type, found {self}"),
} }
} }

View file

@ -145,12 +145,12 @@ pub enum Stmt {
// //
#[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IntTySignedness { pub enum IntSign {
Signed, Signed,
Unsigned, Unsigned,
} }
impl Default for IntTySignedness { impl Default for IntSign {
fn default() -> Self { fn default() -> Self {
// C defaults to unsigned for integers. // C defaults to unsigned for integers.
Self::Signed Self::Signed
@ -170,7 +170,7 @@ pub enum IntTyKind {
#[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, DebugPls, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IntTy { pub struct IntTy {
pub sign: IntTySignedness, pub sign: IntSign,
pub kind: IntTyKind, pub kind: IntTyKind,
} }
@ -295,7 +295,7 @@ impl DirectDeclarator {
} }
} }
impl IntTySignedness { impl IntSign {
pub fn signed(self) -> bool { pub fn signed(self) -> bool {
matches!(self, Self::Signed) matches!(self, Self::Signed)
} }

View file

@ -4,7 +4,7 @@ use peekmore::PeekMoreIterator;
use crate::{ use crate::{
ast::{ ast::{
Decl, DeclAttr, DeclSpec, Declarator, DirectDeclarator, ExternalDecl, FunctionDef, Decl, DeclAttr, DeclSpec, Declarator, DirectDeclarator, ExternalDecl, FunctionDef,
FunctionParamDecl, Ident, InitDecl, IntTy, IntTyKind, IntTySignedness, NormalDecl, Stmt, FunctionParamDecl, Ident, InitDecl, IntTy, IntTyKind, IntSign, NormalDecl, Stmt,
TranslationUnit, TypeSpecifier, TranslationUnit, TypeSpecifier,
}, },
pre::Punctuator as P, pre::Punctuator as P,
@ -335,11 +335,11 @@ where
self.peek_t() self.peek_t()
{ {
// the signed is an integer qualifier // the signed is an integer qualifier
signedness = Some(IntTySignedness::Signed); signedness = Some(IntSign::Signed);
continue; continue;
} }
TypeSpecifier::Integer(IntTy { TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Signed, sign: IntSign::Signed,
kind: IntTyKind::Int, kind: IntTyKind::Int,
}) })
} }
@ -354,18 +354,18 @@ where
self.peek_t() self.peek_t()
{ {
// the unsigned is an integer qualifier // the unsigned is an integer qualifier
signedness = Some(IntTySignedness::Unsigned); signedness = Some(IntSign::Unsigned);
continue; continue;
} }
TypeSpecifier::Integer(IntTy { TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Unsigned, sign: IntSign::Unsigned,
kind: IntTyKind::Int, kind: IntTyKind::Int,
}) })
} }
Tok::Kw(Kw::Float) => TypeSpecifier::Float, Tok::Kw(Kw::Float) => TypeSpecifier::Float,
Tok::Kw(Kw::Double) => TypeSpecifier::Double, Tok::Kw(Kw::Double) => TypeSpecifier::Double,
Tok::Kw(Kw::Bool) => TypeSpecifier::Integer(IntTy { Tok::Kw(Kw::Bool) => TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Unsigned, sign: IntSign::Unsigned,
kind: IntTyKind::Bool, kind: IntTyKind::Bool,
}), }),
Tok::Kw(Kw::Complex) => { Tok::Kw(Kw::Complex) => {

View file

@ -6,7 +6,7 @@ use crate::{
ast::{ ast::{
ArithOpKind, Atom, BinaryOp, ComparisonKind, Decl, DeclAttr, DeclSpec, Declarator, ArithOpKind, Atom, BinaryOp, ComparisonKind, Decl, DeclAttr, DeclSpec, Declarator,
DirectDeclarator, Expr, ExprBinary, ExprPostfix, ExprUnary, ExternalDecl, FunctionDef, DirectDeclarator, Expr, ExprBinary, ExprPostfix, ExprUnary, ExternalDecl, FunctionDef,
FunctionParamDecl, InitDecl, IntTyKind, IntTySignedness, NormalDecl, PostfixOp, Stmt, FunctionParamDecl, InitDecl, IntTyKind, IntSign, NormalDecl, PostfixOp, Stmt,
TypeSpecifier, UnaryOp, TypeSpecifier, UnaryOp,
}, },
sym::Symbol, sym::Symbol,
@ -233,7 +233,7 @@ impl<W: Write> PrettyPrinter<W> {
TypeSpecifier::Char => self.string("char"), TypeSpecifier::Char => self.string("char"),
TypeSpecifier::Integer(int) => { TypeSpecifier::Integer(int) => {
// prefix the unsignedness if desired // prefix the unsignedness if desired
if let IntTySignedness::Unsigned = int.sign { if let IntSign::Unsigned = int.sign {
self.string("unsigned ")?; self.string("unsigned ")?;
} }