fixing upcating bugs related to pointers

This commit is contained in:
mlokr 2024-05-13 15:24:48 +02:00
parent 9ccf91d072
commit c14e6c352d
3 changed files with 102 additions and 97 deletions

View file

@ -30,7 +30,7 @@ main := fn(): int {
},
};
if *(&pixel.color.r + 1) != 0 {
if *(&pixel.point.x + 1) != 2 {
return 0;
}

View file

@ -43,7 +43,7 @@ impl CowReg {
}
}
#[derive(Default)]
#[derive(Default, Debug)]
enum Ctx {
#[default]
None,
@ -70,17 +70,17 @@ pub mod bt {
}
builtin_type! {
VOID;
NEVER;
I8;
I16;
I32;
INT;
VOID;
BOOL;
U8;
U16;
U32;
UINT;
BOOL;
I8;
I16;
I32;
INT;
}
pub fn is_signed(ty: Type) -> bool {
@ -93,7 +93,7 @@ pub mod bt {
pub fn strip_pointer(ty: Type) -> Type {
match TypeKind::from_ty(ty) {
TypeKind::Pointer(_) => UINT,
TypeKind::Pointer(_) => INT,
_ => ty,
}
}
@ -102,11 +102,13 @@ pub mod bt {
matches!(TypeKind::from_ty(ty), TypeKind::Pointer(_))
}
pub fn try_upcast(a: Type, b: Type) -> Option<Type> {
Some(match (strip_pointer(a.min(b)), strip_pointer(a.max(b))) {
_ if a == b => a,
_ if is_signed(a) && is_signed(b) || is_unsigned(a) && is_unsigned(b) => a.max(b),
_ if is_unsigned(b) && is_signed(a) && b - U8 < a - I8 => a,
pub fn try_upcast(oa: Type, ob: Type) -> Option<Type> {
let (oa, ob) = (oa.min(ob), oa.max(ob));
let (a, b) = (strip_pointer(oa), strip_pointer(ob));
Some(match () {
_ if oa == ob => oa,
_ if is_signed(a) && is_signed(b) || is_unsigned(a) && is_unsigned(b) => ob,
_ if is_unsigned(a) && is_signed(b) && a - U8 < b - I8 => ob,
_ => return None,
})
}
@ -842,7 +844,7 @@ impl<'a> Codegen<'a> {
Some(Value::VOID)
}
E::Number { value, .. } => Some(Value {
ty: ctx.ty().unwrap_or(bt::INT),
ty: ctx.ty().map(bt::strip_pointer).unwrap_or(bt::INT),
loc: Loc::Imm(value),
}),
E::If {
@ -942,16 +944,17 @@ impl<'a> Codegen<'a> {
.encode(instrs::jmp(loop_.offset as i32 - offset as i32));
None
}
E::BinOp { left, op, right } => {
E::BinOp { left, op, right } => 'ops: {
use instrs as i;
log::dbg!("binop: {}", expr);
let left = self.expr(left)?;
if op == T::Assign {
let left = self.expr(left)?;
self.expr_ctx(right, Ctx::Dest(left))?;
self.expr_ctx(right, Ctx::Dest(left)).unwrap();
return Some(Value::VOID);
}
let left = self.expr(left)?;
let lsize = self.size_of(left.ty);
let lhs = self.loc_to_reg(left.loc, lsize);
let right = self.expr_ctx(right, Ctx::Inferred(left.ty))?;
@ -959,93 +962,93 @@ impl<'a> Codegen<'a> {
let rhs = self.loc_to_reg(right.loc, rsize);
let ty = self.assert_ty(expr.pos(), left.ty, right.ty);
let size = self.size_of(ty);
let signed = bt::is_signed(ty);
let min_size = lsize.min(rsize);
if bt::is_signed(ty) && min_size < size {
let operand = if lsize < rsize { lhs.0 } else { rhs.0 };
let op = [i::sxt8, i::sxt16, i::sxt32][min_size.ilog2() as usize];
self.code.encode(op(operand, operand));
}
log::dbg!(
"binop: {} {} {}",
self.display_ty(ty),
self.display_ty(left.ty),
self.display_ty(right.ty)
);
if bt::is_pointer(left.ty) ^ bt::is_pointer(right.ty) {
let (offset, ty) = if bt::is_pointer(left.ty) {
(lhs.0, left.ty)
} else {
(rhs.0, right.ty)
};
let TypeKind::Pointer(ty) = TypeKind::from_ty(ty) else {
unreachable!()
};
let size = self.size_of(self.pointers[ty as usize]);
self.code.encode(i::mul64(offset, offset, size as _));
}
let ops = match op {
T::Plus => [i::add8, i::add16, i::add32, i::add64],
T::Minus => [i::sub8, i::sub16, i::sub32, i::sub64],
T::Star => [i::mul8, i::mul16, i::mul32, i::mul64],
T::FSlash if signed => [
|a, b, c| i::dirs8(a, ZERO, b, c),
|a, b, c| i::dirs16(a, ZERO, b, c),
|a, b, c| i::dirs32(a, ZERO, b, c),
|a, b, c| i::dirs64(a, ZERO, b, c),
],
T::FSlash => [
|a, b, c| i::diru8(a, ZERO, b, c),
|a, b, c| i::diru16(a, ZERO, b, c),
|a, b, c| i::diru32(a, ZERO, b, c),
|a, b, c| i::diru64(a, ZERO, b, c),
],
T::Le | T::Ge | T::Ne => {
let against = match op {
T::Le => 1,
T::Ne => 0,
T::Ge => (-1i64) as _,
_ => unreachable!(),
};
let op = if signed { i::cmps } else { i::cmpu };
self.code.encode(op(lhs.0, lhs.0, rhs.0));
self.gpa.free(rhs);
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
return Some(Value {
ty: bt::BOOL,
loc: Loc::Reg(lhs),
});
if matches!(op, T::Plus | T::Minus) {
let min_size = lsize.min(rsize);
if bt::is_signed(ty) && min_size < size {
let operand = if lsize < rsize { lhs.0 } else { rhs.0 };
let op = [i::sxt8, i::sxt16, i::sxt32][min_size.ilog2() as usize];
self.code.encode(op(operand, operand));
}
T::Eq | T::Lt | T::Gt => {
let against = match op {
T::Eq => 0,
T::Lt => 1,
T::Gt => (-1i64) as _,
_ => unreachable!(),
if bt::is_pointer(left.ty) ^ bt::is_pointer(right.ty) {
let (offset, ty) = if bt::is_pointer(left.ty) {
(rhs.0, left.ty)
} else {
(lhs.0, right.ty)
};
let op = if signed { i::cmps } else { i::cmpu };
self.code.encode(op(lhs.0, lhs.0, rhs.0));
self.gpa.free(rhs);
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
let TypeKind::Pointer(ty) = TypeKind::from_ty(ty) else {
unreachable!()
};
let size = self.size_of(self.pointers[ty as usize]);
self.code.encode(i::muli64(offset, offset, size as _));
}
}
'math: {
let ops = match op {
T::Plus => [i::add8, i::add16, i::add32, i::add64],
T::Minus => [i::sub8, i::sub16, i::sub32, i::sub64],
T::Star => [i::mul8, i::mul16, i::mul32, i::mul64],
T::FSlash if signed => [
|a, b, c| i::dirs8(a, ZERO, b, c),
|a, b, c| i::dirs16(a, ZERO, b, c),
|a, b, c| i::dirs32(a, ZERO, b, c),
|a, b, c| i::dirs64(a, ZERO, b, c),
],
T::FSlash => [
|a, b, c| i::diru8(a, ZERO, b, c),
|a, b, c| i::diru16(a, ZERO, b, c),
|a, b, c| i::diru32(a, ZERO, b, c),
|a, b, c| i::diru64(a, ZERO, b, c),
],
_ => break 'math,
};
self.code
.encode(ops[size.ilog2() as usize](lhs.0, lhs.0, rhs.0));
self.gpa.free(rhs);
break 'ops Some(Value {
ty,
loc: Loc::Reg(lhs),
});
}
'cmp: {
let against = match op {
T::Le | T::Lt => 1,
T::Ne | T::Eq => 0,
T::Ge | T::Gt => (-1i64) as _,
_ => break 'cmp,
};
let op_fn = if signed { i::cmps } else { i::cmpu };
self.code.encode(op_fn(lhs.0, lhs.0, rhs.0));
self.gpa.free(rhs);
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
if matches!(op, T::Eq | T::Lt | T::Gt) {
self.code.encode(instrs::not(lhs.0, lhs.0));
return Some(Value {
ty: bt::BOOL,
loc: Loc::Reg(lhs),
});
}
_ => unimplemented!("{:#?}", op),
};
self.code
.encode(ops[size.ilog2() as usize](lhs.0, lhs.0, rhs.0));
self.gpa.free(rhs);
break 'ops Some(Value {
ty: bt::BOOL,
loc: Loc::Reg(lhs),
});
}
Some(Value {
ty,
loc: Loc::Reg(lhs),
})
unimplemented!("{:#?}", op)
}
ast => unimplemented!("{:#?}", ast),
}?;
@ -1323,6 +1326,7 @@ impl<'a> Codegen<'a> {
}
}
#[derive(Debug)]
pub struct Value {
ty: Type,
loc: Loc,
@ -1350,6 +1354,7 @@ impl Loc {
fn take_ref(&self) -> Loc {
match self {
Self::Reg(reg) => Self::RegRef(reg.0),
Self::Deref(reg, off) => Self::DerefRef(reg.0, *off),
Self::Stack(off) => Self::StackRef(*off),
un => unreachable!("{:?}", un),
}

View file

@ -1,3 +1,3 @@
code size: 336
code size: 433
ret: 512
status: Ok(())