forked from koniifer/ableos
implementing codegen for all the operators
This commit is contained in:
parent
3c09a5f23e
commit
78f9eb6acc
|
@ -744,6 +744,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_ctx(&mut self, expr: &'a parser::Expr<'a>, mut ctx: Ctx) -> Option<Value> {
|
fn expr_ctx(&mut self, expr: &'a parser::Expr<'a>, mut ctx: Ctx) -> Option<Value> {
|
||||||
|
use instrs as i;
|
||||||
let value = match *expr {
|
let value = match *expr {
|
||||||
E::Directive {
|
E::Directive {
|
||||||
name: "eca",
|
name: "eca",
|
||||||
|
@ -762,7 +763,7 @@ impl<'a> Codegen<'a> {
|
||||||
let ty = self.ty(ret_ty);
|
let ty = self.ty(ret_ty);
|
||||||
let loc = self.alloc_ret_loc(ty, ctx);
|
let loc = self.alloc_ret_loc(ty, ctx);
|
||||||
|
|
||||||
self.code.encode(instrs::eca());
|
self.code.encode(i::eca());
|
||||||
|
|
||||||
self.post_process_ret_loc(ty, &loc);
|
self.post_process_ret_loc(ty, &loc);
|
||||||
|
|
||||||
|
@ -804,8 +805,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
if from_size < to_size && bt::is_signed(val.ty) {
|
if from_size < to_size && bt::is_signed(val.ty) {
|
||||||
let reg = self.loc_to_reg(val.loc, from_size);
|
let reg = self.loc_to_reg(val.loc, from_size);
|
||||||
let op =
|
let op = [i::sxt8, i::sxt16, i::sxt32][from_size.ilog2() as usize];
|
||||||
[instrs::sxt8, instrs::sxt16, instrs::sxt32][from_size.ilog2() as usize];
|
|
||||||
self.code.encode(op(reg.0, reg.0));
|
self.code.encode(op(reg.0, reg.0));
|
||||||
val.loc = Loc::Reg(reg);
|
val.loc = Loc::Reg(reg);
|
||||||
}
|
}
|
||||||
|
@ -939,7 +939,7 @@ impl<'a> Codegen<'a> {
|
||||||
stack.leak();
|
stack.leak();
|
||||||
let reg = self.alloc_reg();
|
let reg = self.alloc_reg();
|
||||||
self.code
|
self.code
|
||||||
.encode(instrs::addi64(reg.0, STACK_PTR, stack.offset + off));
|
.encode(i::addi64(reg.0, STACK_PTR, stack.offset + off));
|
||||||
Loc::Reg(reg)
|
Loc::Reg(reg)
|
||||||
}
|
}
|
||||||
l => self.report(
|
l => self.report(
|
||||||
|
@ -1052,7 +1052,7 @@ impl<'a> Codegen<'a> {
|
||||||
instr_offset: 1,
|
instr_offset: 1,
|
||||||
size: 4,
|
size: 4,
|
||||||
});
|
});
|
||||||
self.code.encode(instrs::jmp(0));
|
self.code.encode(i::jmp(0));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
E::Block { stmts, .. } => {
|
E::Block { stmts, .. } => {
|
||||||
|
@ -1072,7 +1072,7 @@ impl<'a> Codegen<'a> {
|
||||||
let cond = self.expr_ctx(cond, Ctx::Inferred(bt::BOOL))?;
|
let cond = self.expr_ctx(cond, Ctx::Inferred(bt::BOOL))?;
|
||||||
let reg = self.loc_to_reg(cond.loc, 1);
|
let reg = self.loc_to_reg(cond.loc, 1);
|
||||||
let jump_offset = self.code.code.len() as u32;
|
let jump_offset = self.code.code.len() as u32;
|
||||||
self.code.encode(instrs::jeq(reg.0, 0, 0));
|
self.code.encode(i::jeq(reg.0, 0, 0));
|
||||||
|
|
||||||
log::dbg!("if-then");
|
log::dbg!("if-then");
|
||||||
let then_unreachable = self.expr(then).is_none();
|
let then_unreachable = self.expr(then).is_none();
|
||||||
|
@ -1084,7 +1084,7 @@ impl<'a> Codegen<'a> {
|
||||||
log::dbg!("if-else");
|
log::dbg!("if-else");
|
||||||
let else_jump_offset = self.code.code.len() as u32;
|
let else_jump_offset = self.code.code.len() as u32;
|
||||||
if !then_unreachable {
|
if !then_unreachable {
|
||||||
self.code.encode(instrs::jmp(0));
|
self.code.encode(i::jmp(0));
|
||||||
jump = self.code.code.len() as i16 - jump_offset as i16;
|
jump = self.code.code.len() as i16 - jump_offset as i16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,7 +1122,7 @@ impl<'a> Codegen<'a> {
|
||||||
if !body_unreachable {
|
if !body_unreachable {
|
||||||
let loop_end = self.code.code.len();
|
let loop_end = self.code.code.len();
|
||||||
self.code
|
self.code
|
||||||
.encode(instrs::jmp(loop_start as i32 - loop_end as i32));
|
.encode(i::jmp(loop_start as i32 - loop_end as i32));
|
||||||
}
|
}
|
||||||
|
|
||||||
let loop_end = self.code.code.len() as u32;
|
let loop_end = self.code.code.len() as u32;
|
||||||
|
@ -1149,7 +1149,7 @@ impl<'a> Codegen<'a> {
|
||||||
E::Break { .. } => {
|
E::Break { .. } => {
|
||||||
let loop_ = self.loops.last_mut().unwrap();
|
let loop_ = self.loops.last_mut().unwrap();
|
||||||
let offset = self.code.code.len() as u32;
|
let offset = self.code.code.len() as u32;
|
||||||
self.code.encode(instrs::jmp(0));
|
self.code.encode(i::jmp(0));
|
||||||
loop_.relocs.push(RetReloc {
|
loop_.relocs.push(RetReloc {
|
||||||
offset,
|
offset,
|
||||||
instr_offset: 1,
|
instr_offset: 1,
|
||||||
|
@ -1161,13 +1161,34 @@ impl<'a> Codegen<'a> {
|
||||||
let loop_ = self.loops.last().unwrap();
|
let loop_ = self.loops.last().unwrap();
|
||||||
let offset = self.code.code.len() as u32;
|
let offset = self.code.code.len() as u32;
|
||||||
self.code
|
self.code
|
||||||
.encode(instrs::jmp(loop_.offset as i32 - offset as i32));
|
.encode(i::jmp(loop_.offset as i32 - offset as i32));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
E::BinOp { left, op, right } => 'ops: {
|
E::BinOp {
|
||||||
use instrs as i;
|
left,
|
||||||
|
op: op @ (T::And | T::Or),
|
||||||
|
right,
|
||||||
|
} => {
|
||||||
|
let lhs = self.expr_ctx(left, Ctx::Inferred(bt::BOOL))?;
|
||||||
|
let lhs = self.loc_to_reg(lhs.loc, 1);
|
||||||
|
let jump_offset = self.code.code.len() as u32 + 3;
|
||||||
|
let op = if op == T::And { i::jeq } else { i::jne };
|
||||||
|
self.code.encode(op(lhs.0, 0, 0));
|
||||||
|
|
||||||
log::dbg!("binop: {}", expr);
|
if let Some(rhs) = self.expr_ctx(right, Ctx::Inferred(bt::BOOL)) {
|
||||||
|
let rhs = self.loc_to_reg(rhs.loc, 1);
|
||||||
|
self.code.encode(i::cp(lhs.0, rhs.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let jump = self.code.code.len() as i16 - jump_offset as i16;
|
||||||
|
self.code.code[jump_offset as usize..][..2].copy_from_slice(&jump.to_ne_bytes());
|
||||||
|
|
||||||
|
Some(Value {
|
||||||
|
ty: bt::BOOL,
|
||||||
|
loc: Loc::Reg(lhs),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
E::BinOp { left, op, right } => 'ops: {
|
||||||
let left = self.expr(left)?;
|
let left = self.expr(left)?;
|
||||||
|
|
||||||
if op == T::Assign {
|
if op == T::Assign {
|
||||||
|
@ -1241,9 +1262,9 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let op_fn = if signed { i::cmps } else { i::cmpu };
|
let op_fn = if signed { i::cmps } else { i::cmpu };
|
||||||
self.code.encode(op_fn(lhs.0, lhs.0, rhs.0));
|
self.code.encode(op_fn(lhs.0, lhs.0, rhs.0));
|
||||||
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
|
self.code.encode(i::cmpui(lhs.0, lhs.0, against));
|
||||||
if matches!(op, T::Eq | T::Lt | T::Gt) {
|
if matches!(op, T::Eq | T::Lt | T::Gt) {
|
||||||
self.code.encode(instrs::not(lhs.0, lhs.0));
|
self.code.encode(i::not(lhs.0, lhs.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
break 'ops Some(Value {
|
break 'ops Some(Value {
|
||||||
|
@ -1278,26 +1299,28 @@ impl<'a> Codegen<'a> {
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> Option<fn(u8, u8, u8) -> (usize, [u8; instrs::MAX_SIZE])> {
|
) -> Option<fn(u8, u8, u8) -> (usize, [u8; instrs::MAX_SIZE])> {
|
||||||
use instrs as i;
|
use instrs as i;
|
||||||
Some(
|
|
||||||
match op {
|
macro_rules! div { ($($op:ident),*) => {[$(|a, b, c| i::$op(a, ZERO, b, c)),*]}; }
|
||||||
|
macro_rules! rem { ($($op:ident),*) => {[$(|a, b, c| i::$op(ZERO, a, b, c)),*]}; }
|
||||||
|
|
||||||
|
let ops = match op {
|
||||||
T::Add => [i::add8, i::add16, i::add32, i::add64],
|
T::Add => [i::add8, i::add16, i::add32, i::add64],
|
||||||
T::Sub => [i::sub8, i::sub16, i::sub32, i::sub64],
|
T::Sub => [i::sub8, i::sub16, i::sub32, i::sub64],
|
||||||
T::Mul => [i::mul8, i::mul16, i::mul32, i::mul64],
|
T::Mul => [i::mul8, i::mul16, i::mul32, i::mul64],
|
||||||
T::Div if signed => [
|
T::Div if signed => div!(dirs8, dirs16, dirs32, dirs64),
|
||||||
|a, b, c| i::dirs8(a, ZERO, b, c),
|
T::Div => div!(diru8, diru16, diru32, diru64),
|
||||||
|a, b, c| i::dirs16(a, ZERO, b, c),
|
T::Mod if signed => rem!(dirs8, dirs16, dirs32, dirs64),
|
||||||
|a, b, c| i::dirs32(a, ZERO, b, c),
|
T::Mod => rem!(diru8, diru16, diru32, diru64),
|
||||||
|a, b, c| i::dirs64(a, ZERO, b, c),
|
T::Band => return Some(i::and),
|
||||||
],
|
T::Bor => return Some(i::or),
|
||||||
T::Div => [
|
T::Xor => return Some(i::xor),
|
||||||
|a, b, c| i::diru8(a, ZERO, b, c),
|
T::Shl => [i::slu8, i::slu16, i::slu32, i::slu64],
|
||||||
|a, b, c| i::diru16(a, ZERO, b, c),
|
T::Shr if signed => [i::srs8, i::srs16, i::srs32, i::srs64],
|
||||||
|a, b, c| i::diru32(a, ZERO, b, c),
|
T::Shr => [i::sru8, i::sru16, i::sru32, i::sru64],
|
||||||
|a, b, c| i::diru64(a, ZERO, b, c),
|
|
||||||
],
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}[size.ilog2() as usize],
|
};
|
||||||
)
|
|
||||||
|
Some(ops[size.ilog2() as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_op(&mut self, op: T, ty: Type, ctx: Ctx, left: Loc, right: Loc) -> Option<Value> {
|
fn struct_op(&mut self, op: T, ty: Type, ctx: Ctx, left: Loc, right: Loc) -> Option<Value> {
|
||||||
|
|
Loading…
Reference in a new issue