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; return 0;
} }

View file

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

View file

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