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)]
pub enum UnaryKind {
Zext,
Sext,
Negate,
BitNot,
LogicalNot,

View file

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

View file

@ -4,12 +4,12 @@ mod typeck;
use std::cell::{Cell, RefCell};
use parser::{
ast::{self, IntTy, IntTyKind, IntTySignedness},
ast::{self, ExprBinary, IntTy, IntTyKind, IntSign},
Span, Symbol,
};
use rustc_hash::{FxHashMap, FxHashSet};
use self::builder::FuncBuilder;
use self::{builder::FuncBuilder, typeck::Coercion};
use crate::{
ir::{
self, BbIdx, BinKind, Branch, ConstValue, DefId, Func, Ir, Layout, Operand, Register,
@ -40,7 +40,7 @@ impl<'cx> LoweringCx<'cx> {
let kind = match ty {
ast::TypeSpecifier::Void => TyKind::Void,
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::Double => TyKind::Double,
ast::TypeSpecifier::LongDouble => TyKind::LongDouble,
@ -89,7 +89,7 @@ impl<'cx> LoweringCx<'cx> {
let layout = match *ty {
TyKind::Void => Layout::size_align(0, 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::Char => Layout::size_align(1, 1),
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);
rhs
}
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) => BinKind::Shl,
ast::BinaryOp::Arith(ast::ArithOpKind::Shr) => BinKind::Shr,
ast::BinaryOp::Arith(ast::ArithOpKind::BitAnd) => BinKind::BitAnd,
ast::BinaryOp::Arith(ast::ArithOpKind::BitXor) => BinKind::BitXor,
ast::BinaryOp::Arith(ast::ArithOpKind::BitOr) => BinKind::BitOr,
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 => {
// Discard the lhs, evaluate to the rhs.
return Ok(rhs);
}
ast::BinaryOp::Index => todo!("no index"),
ast::BinaryOp::Assign(_) => unreachable!("assign handled above"),
ast::Expr::Binary(ExprBinary {
op: ast::BinaryOp::Arith(arith),
lhs: lhs_expr,
rhs: rhs_expr,
}) => {
let (mut lhs, lhs_tyl) = self.lower_expr(&lhs_expr.0, lhs_expr.1)?;
let (mut rhs, rhs_tyl) = self.lower_expr(&rhs_expr.0, rhs_expr.1)?;
let (result, lhs_coerce, rhs_coerce) =
self.arith_op(lhs_tyl.ty, rhs_tyl.ty, span)?;
let mut do_coerce = |reg, coerce, span, ty| {
let kind = match coerce {
Coercion::ZeroExt => UnaryKind::Zext,
Coercion::SignExt => UnaryKind::Sext,
Coercion::SignToUnsigned => todo!("hm, what should this do"),
};
Operand::Reg(self.build.unary(kind, reg, span, self.lcx.layout_of(ty)))
};
for (coerce, ty) in lhs_coerce {
lhs = do_coerce(lhs, coerce, span, ty);
}
for (coerce, ty) in rhs_coerce {
rhs = do_coerce(rhs, coerce, span, ty);
}
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
@ -439,6 +471,16 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
(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) => {
let lhs = self.lower_expr(&postfix.lhs.0, postfix.lhs.1)?;
match &postfix.op {
@ -546,10 +588,10 @@ fn lower_func<'cx>(
impl<'cx> CommonTypes<'cx> {
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 {
signed: int(IntTySignedness::Signed, kind),
unsigned: int(IntTySignedness::Unsigned, kind),
signed: int(IntSign::Signed, kind),
unsigned: int(IntSign::Unsigned, kind),
};
Self {

View file

@ -1,5 +1,5 @@
use parser::{
ast::{IntTy, IntTyKind, IntTySignedness},
ast::{IntSign, IntTy, IntTyKind},
Span,
};
use smallvec::{smallvec, SmallVec};
@ -109,9 +109,9 @@ impl<'a, 'cx> FnLoweringCtxt<'a, 'cx> {
} else {
rhs_kind
};
let ty = self.lcx.intern_ty(TyKind::Integer(IntTy {
let ty = self.lcx.intern_ty(TyKind::Int(IntTy {
kind,
sign: IntTySignedness::Unsigned,
sign: IntSign::Unsigned,
}));
lhs_coerce.extend(self.coerce(lhs_prom, 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>> {
if from != to {
todo!("coerce.")
if from == to {
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
fn promote(&self, ty: Ty<'cx>, span: Span) -> Result<Coercions<'cx>> {
Ok(match *ty {
TyKind::Char => smallvec![(Coercion::SignExt, self.types.int.signed)],
TyKind::Integer(int) if int.kind < IntTyKind::Int => match int.sign {
IntTySignedness::Signed => smallvec![(Coercion::SignExt, self.types.int.signed)],
IntTySignedness::Unsigned => {
TyKind::Int(int) if int.kind < IntTyKind::Int => match int.sign {
IntSign::Signed => smallvec![(Coercion::SignExt, self.types.int.signed)],
IntSign::Unsigned => {
smallvec![(Coercion::ZeroExt, self.types.int.unsigned)]
}
},
TyKind::Integer(_) => smallvec![],
TyKind::Int(_) => smallvec![],
TyKind::Enum(_) => todo!("enums are unimplemented"),
_ => return Err(Error::new(format!("cannot convert {ty} to integer"), span)),
})

View file

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

View file

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

View file

@ -4,7 +4,7 @@ use peekmore::PeekMoreIterator;
use crate::{
ast::{
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,
},
pre::Punctuator as P,
@ -335,11 +335,11 @@ where
self.peek_t()
{
// the signed is an integer qualifier
signedness = Some(IntTySignedness::Signed);
signedness = Some(IntSign::Signed);
continue;
}
TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Signed,
sign: IntSign::Signed,
kind: IntTyKind::Int,
})
}
@ -354,18 +354,18 @@ where
self.peek_t()
{
// the unsigned is an integer qualifier
signedness = Some(IntTySignedness::Unsigned);
signedness = Some(IntSign::Unsigned);
continue;
}
TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Unsigned,
sign: IntSign::Unsigned,
kind: IntTyKind::Int,
})
}
Tok::Kw(Kw::Float) => TypeSpecifier::Float,
Tok::Kw(Kw::Double) => TypeSpecifier::Double,
Tok::Kw(Kw::Bool) => TypeSpecifier::Integer(IntTy {
sign: IntTySignedness::Unsigned,
sign: IntSign::Unsigned,
kind: IntTyKind::Bool,
}),
Tok::Kw(Kw::Complex) => {

View file

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