adding imm operations is come cases

This commit is contained in:
mlokr 2024-05-16 13:29:16 +02:00
parent 2dff9f7244
commit ca1d471646

View file

@ -1231,6 +1231,7 @@ impl<'a> Codegen<'a> {
let lsize = self.size_of(left.ty);
let ty = ctx.ty().unwrap_or(left.ty);
let lhs = match std::mem::take(&mut ctx).loc() {
Some(Loc::RegRef(reg)) if Loc::RegRef(reg) == left.loc => LinReg(reg, None),
Some(loc) => {
@ -1241,12 +1242,30 @@ impl<'a> Codegen<'a> {
};
let right = self.expr_ctx(right, Ctx::Inferred(left.ty))?;
let rsize = self.size_of(right.ty);
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);
if let Loc::Imm(mut imm) = right.loc
&& let Some(oper) = Self::imm_math_op(op, signed, size, false)
{
if matches!(op, T::Add | T::Sub) {
if bt::is_pointer(left.ty) {
let size = self.size_of(self.pointers[ty as usize]);
imm *= size;
}
}
self.code.encode(oper(lhs.0, lhs.0, imm));
break 'ops Some(Value {
ty,
loc: Loc::Reg(lhs),
});
}
let rhs = self.loc_to_reg(right.loc, rsize);
log::dbg!(
"binop: {} {} {}",
self.display_ty(ty),
@ -1358,6 +1377,45 @@ impl<'a> Codegen<'a> {
Some(ops[size.ilog2() as usize])
}
fn imm_math_op(
op: T,
signed: bool,
size: u64,
first_imm: bool,
) -> Option<fn(u8, u8, u64) -> (usize, [u8; instrs::MAX_SIZE])> {
use instrs as i;
macro_rules! def_op {
($name:ident |$a:ident, $b:ident, $c:ident| $($tt:tt)*) => {
macro_rules! $name {
($$($$op:ident),*) => {
[$$(
|$a, $b, $c: u64| i::$$op($($tt)*),
)*]
}
}
};
}
def_op!(basic_op | a, b, c | a, b, c as _);
def_op!(sub_op | a, b, c | b, a, c.wrapping_neg() as _);
let ops = match op {
T::Add => basic_op!(addi8, addi16, addi32, addi64),
T::Sub if !first_imm => sub_op!(addi8, addi16, addi32, addi64),
T::Mul => basic_op!(muli8, muli16, muli32, muli64),
T::Band => return Some(i::andi),
T::Bor => return Some(i::ori),
T::Xor => return Some(i::xori),
T::Shr if signed && !first_imm => basic_op!(srui8, srui16, srui32, srui64),
T::Shr if !first_imm => basic_op!(srui8, srui16, srui32, srui64),
T::Shl if !first_imm => basic_op!(slui8, slui16, slui32, slui64),
_ => return None,
};
Some(ops[size.ilog2() as usize])
}
fn struct_op(&mut self, op: T, ty: Type, ctx: Ctx, left: Loc, right: Loc) -> Option<Value> {
if let TypeKind::Struct(stuct) = TypeKind::from_ty(ty) {
let dst = match ctx {
@ -1380,9 +1438,22 @@ impl<'a> Codegen<'a> {
}
let size = self.size_of(ty);
let (lhs, owned) = self.loc_to_reg_ref(&left, size);
let rhs = self.loc_to_reg(right, size);
let signed = bt::is_signed(ty);
let (lhs, owned) = self.loc_to_reg_ref(&left, size);
if let Loc::Imm(imm) = right
&& let Some(op) = Self::imm_math_op(op, signed, size, false)
{
self.code.encode(op(lhs, lhs, imm));
return if let Ctx::Dest(dest) = ctx {
self.assign(dest.ty, dest.loc, owned.map_or(Loc::RegRef(lhs), Loc::Reg));
Some(Value::VOID)
} else {
Some(Value::new(ty, owned.map_or(Loc::RegRef(lhs), Loc::Reg)))
};
}
let rhs = self.loc_to_reg(right, size);
if let Some(op) = Self::math_op(op, signed, size) {
self.code.encode(op(lhs, lhs, rhs.0));