moving op instruction selection to token methods
This commit is contained in:
parent
e2a8373c42
commit
da85d91a09
|
@ -1383,35 +1383,11 @@ impl Codegen {
|
||||||
loc: Loc::ct(value as u64),
|
loc: Loc::ct(value as u64),
|
||||||
}),
|
}),
|
||||||
E::If { cond, then, mut else_, .. } => {
|
E::If { cond, then, mut else_, .. } => {
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn cond_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
) -> Option<(fn(u8, u8, i16) -> (usize, [u8; instrs::MAX_SIZE]), bool)>
|
|
||||||
{
|
|
||||||
Some((
|
|
||||||
match op {
|
|
||||||
TokenKind::Le if signed => instrs::jgts,
|
|
||||||
TokenKind::Le => instrs::jgtu,
|
|
||||||
TokenKind::Lt if signed => instrs::jlts,
|
|
||||||
TokenKind::Lt => instrs::jltu,
|
|
||||||
TokenKind::Ge if signed => instrs::jlts,
|
|
||||||
TokenKind::Ge => instrs::jltu,
|
|
||||||
TokenKind::Gt if signed => instrs::jgts,
|
|
||||||
TokenKind::Gt => instrs::jgtu,
|
|
||||||
TokenKind::Eq => instrs::jne,
|
|
||||||
TokenKind::Ne => instrs::jeq,
|
|
||||||
_ => return None,
|
|
||||||
},
|
|
||||||
matches!(op, TokenKind::Lt | TokenKind::Gt),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut then = Some(then);
|
let mut then = Some(then);
|
||||||
let jump_offset;
|
let jump_offset;
|
||||||
if let &E::BinOp { left, op, right } = cond
|
if let &E::BinOp { left, op, right } = cond
|
||||||
&& let ty = self.infer_type(left)
|
&& let ty = self.infer_type(left)
|
||||||
&& let Some((op, swapped)) = cond_op(op, ty.is_signed())
|
&& let Some((op, swapped)) = op.cond_op(ty.is_signed())
|
||||||
{
|
{
|
||||||
let left = self.expr_ctx(left, Ctx::default())?;
|
let left = self.expr_ctx(left, Ctx::default())?;
|
||||||
let right = self.expr_ctx(right, Ctx::default())?;
|
let right = self.expr_ctx(right, Ctx::default())?;
|
||||||
|
@ -1419,7 +1395,7 @@ impl Codegen {
|
||||||
let rsize = self.tys.size_of(right.ty);
|
let rsize = self.tys.size_of(right.ty);
|
||||||
let left_reg = self.loc_to_reg(&left.loc, lsize);
|
let left_reg = self.loc_to_reg(&left.loc, lsize);
|
||||||
let right_reg = self.loc_to_reg(&right.loc, rsize);
|
let right_reg = self.loc_to_reg(&right.loc, rsize);
|
||||||
jump_offset = self.local_offset();
|
jump_offset = self.ci.code.len();
|
||||||
self.ci.emit(op(left_reg.get(), right_reg.get(), 0));
|
self.ci.emit(op(left_reg.get(), right_reg.get(), 0));
|
||||||
self.ci.free_loc(left.loc);
|
self.ci.free_loc(left.loc);
|
||||||
self.ci.free_loc(right.loc);
|
self.ci.free_loc(right.loc);
|
||||||
|
@ -1431,7 +1407,7 @@ impl Codegen {
|
||||||
} else {
|
} else {
|
||||||
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
|
let cond = self.expr_ctx(cond, Ctx::default().with_ty(ty::BOOL))?;
|
||||||
let reg = self.loc_to_reg(&cond.loc, 1);
|
let reg = self.loc_to_reg(&cond.loc, 1);
|
||||||
jump_offset = self.local_offset();
|
jump_offset = self.ci.code.len();
|
||||||
self.ci.emit(jeq(reg.get(), 0, 0));
|
self.ci.emit(jeq(reg.get(), 0, 0));
|
||||||
self.ci.free_loc(cond.loc);
|
self.ci.free_loc(cond.loc);
|
||||||
self.ci.regs.free(reg);
|
self.ci.regs.free(reg);
|
||||||
|
@ -1441,38 +1417,38 @@ impl Codegen {
|
||||||
if let Some(then) = then { self.expr(then).is_none() } else { false };
|
if let Some(then) = then { self.expr(then).is_none() } else { false };
|
||||||
let mut else_unreachable = false;
|
let mut else_unreachable = false;
|
||||||
|
|
||||||
let mut jump = self.local_offset() as i64 - jump_offset as i64;
|
let mut jump = self.ci.code.len() as i64 - jump_offset as i64;
|
||||||
|
|
||||||
if let Some(else_) = else_ {
|
if let Some(else_) = else_ {
|
||||||
let else_jump_offset = self.local_offset();
|
let else_jump_offset = self.ci.code.len();
|
||||||
if !then_unreachable {
|
if !then_unreachable {
|
||||||
self.ci.emit(jmp(0));
|
self.ci.emit(jmp(0));
|
||||||
jump = self.local_offset() as i64 - jump_offset as i64;
|
jump = self.ci.code.len() as i64 - jump_offset as i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
else_unreachable = self.expr(else_).is_none();
|
else_unreachable = self.expr(else_).is_none();
|
||||||
|
|
||||||
if !then_unreachable {
|
if !then_unreachable {
|
||||||
let jump = self.local_offset() as i64 - else_jump_offset as i64;
|
let jump = self.ci.code.len() as i64 - else_jump_offset as i64;
|
||||||
write_reloc(self.local_code(), else_jump_offset as usize + 1, jump, 4);
|
write_reloc(&mut self.ci.code, else_jump_offset + 1, jump, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_reloc(self.local_code(), jump_offset as usize + 3, jump, 2);
|
write_reloc(&mut self.ci.code, jump_offset + 3, jump, 2);
|
||||||
|
|
||||||
(!then_unreachable || !else_unreachable).then_some(Value::void())
|
(!then_unreachable || !else_unreachable).then_some(Value::void())
|
||||||
}
|
}
|
||||||
E::Loop { body, .. } => 'a: {
|
E::Loop { body, .. } => 'a: {
|
||||||
let loop_start = self.local_offset();
|
let loop_start = self.ci.code.len();
|
||||||
self.ci.loops.push(Loop {
|
self.ci.loops.push(Loop {
|
||||||
var_count: self.ci.vars.len() as _,
|
var_count: self.ci.vars.len() as _,
|
||||||
offset: loop_start,
|
offset: loop_start as _,
|
||||||
reloc_base: self.ci.loop_relocs.len() as u32,
|
reloc_base: self.ci.loop_relocs.len() as u32,
|
||||||
});
|
});
|
||||||
let body_unreachable = self.expr(body).is_none();
|
let body_unreachable = self.expr(body).is_none();
|
||||||
|
|
||||||
if !body_unreachable {
|
if !body_unreachable {
|
||||||
let loop_end = self.local_offset();
|
let loop_end = self.ci.code.len();
|
||||||
self.ci.emit(jmp(loop_start as i32 - loop_end as i32));
|
self.ci.emit(jmp(loop_start as i32 - loop_end as i32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1504,7 +1480,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
E::Continue { .. } => {
|
E::Continue { .. } => {
|
||||||
let loop_ = self.ci.loops.last().unwrap();
|
let loop_ = self.ci.loops.last().unwrap();
|
||||||
let offset = self.local_offset();
|
let offset = self.ci.code.len();
|
||||||
self.ci.emit(jmp(loop_.offset as i32 - offset as i32));
|
self.ci.emit(jmp(loop_.offset as i32 - offset as i32));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1570,7 +1546,7 @@ impl Codegen {
|
||||||
let signed = ty.is_signed();
|
let signed = ty.is_signed();
|
||||||
|
|
||||||
if let Loc::Ct { value: CtValue(mut imm), derefed } = right.loc
|
if let Loc::Ct { value: CtValue(mut imm), derefed } = right.loc
|
||||||
&& let Some(oper) = Self::imm_math_op(op, signed, size)
|
&& let Some(oper) = op.imm_math_op(signed, size)
|
||||||
{
|
{
|
||||||
if derefed {
|
if derefed {
|
||||||
let mut dst = [0u8; 8];
|
let mut dst = [0u8; 8];
|
||||||
|
@ -1623,7 +1599,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(op) = Self::math_op(op, signed, size) {
|
if let Some(op) = op.math_op(signed, size) {
|
||||||
self.ci.emit(op(dst.get(), lhs.get(), rhs.get()));
|
self.ci.emit(op(dst.get(), lhs.get(), rhs.get()));
|
||||||
self.ci.regs.free(lhs);
|
self.ci.regs.free(lhs);
|
||||||
self.ci.regs.free(rhs);
|
self.ci.regs.free(rhs);
|
||||||
|
@ -1952,7 +1928,7 @@ impl Codegen {
|
||||||
let lhs = self.loc_to_reg(left, size);
|
let lhs = self.loc_to_reg(left, size);
|
||||||
|
|
||||||
if let Loc::Ct { value, derefed: false } = right
|
if let Loc::Ct { value, derefed: false } = right
|
||||||
&& let Some(op) = Self::imm_math_op(op, signed, size)
|
&& let Some(op) = op.imm_math_op(signed, size)
|
||||||
{
|
{
|
||||||
self.ci.emit(op(lhs.get(), lhs.get(), value.0));
|
self.ci.emit(op(lhs.get(), lhs.get(), value.0));
|
||||||
return Some(if let Some(value) = ctx.into_value() {
|
return Some(if let Some(value) = ctx.into_value() {
|
||||||
|
@ -1965,7 +1941,7 @@ impl Codegen {
|
||||||
|
|
||||||
let rhs = self.loc_to_reg(right, size);
|
let rhs = self.loc_to_reg(right, size);
|
||||||
|
|
||||||
if let Some(op) = Self::math_op(op, signed, size) {
|
if let Some(op) = op.math_op(signed, size) {
|
||||||
self.ci.emit(op(lhs.get(), lhs.get(), rhs.get()));
|
self.ci.emit(op(lhs.get(), lhs.get(), rhs.get()));
|
||||||
self.ci.regs.free(rhs);
|
self.ci.regs.free(rhs);
|
||||||
return if let Some(value) = ctx.into_value() {
|
return if let Some(value) = ctx.into_value() {
|
||||||
|
@ -1979,76 +1955,6 @@ impl Codegen {
|
||||||
unimplemented!("{:#?}", op)
|
unimplemented!("{:#?}", op)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn math_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
size: u32,
|
|
||||||
) -> Option<fn(u8, u8, u8) -> (usize, [u8; instrs::MAX_SIZE])> {
|
|
||||||
use TokenKind as T;
|
|
||||||
|
|
||||||
macro_rules! div { ($($op:ident),*) => {[$(|a, b, c| $op(a, ZERO, b, c)),*]}; }
|
|
||||||
macro_rules! rem { ($($op:ident),*) => {[$(|a, b, c| $op(ZERO, a, b, c)),*]}; }
|
|
||||||
|
|
||||||
let ops = match op {
|
|
||||||
T::Add => [add8, add16, add32, add64],
|
|
||||||
T::Sub => [sub8, sub16, sub32, sub64],
|
|
||||||
T::Mul => [mul8, mul16, mul32, mul64],
|
|
||||||
T::Div if signed => div!(dirs8, dirs16, dirs32, dirs64),
|
|
||||||
T::Div => div!(diru8, diru16, diru32, diru64),
|
|
||||||
T::Mod if signed => rem!(dirs8, dirs16, dirs32, dirs64),
|
|
||||||
T::Mod => rem!(diru8, diru16, diru32, diru64),
|
|
||||||
T::Band => return Some(and),
|
|
||||||
T::Bor => return Some(or),
|
|
||||||
T::Xor => return Some(xor),
|
|
||||||
T::Shl => [slu8, slu16, slu32, slu64],
|
|
||||||
T::Shr if signed => [srs8, srs16, srs32, srs64],
|
|
||||||
T::Shr => [sru8, sru16, sru32, sru64],
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(ops[size.ilog2() as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn imm_math_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
size: u32,
|
|
||||||
) -> Option<fn(u8, u8, u64) -> (usize, [u8; instrs::MAX_SIZE])> {
|
|
||||||
use TokenKind as T;
|
|
||||||
|
|
||||||
macro_rules! def_op {
|
|
||||||
($name:ident |$a:ident, $b:ident, $c:ident| $($tt:tt)*) => {
|
|
||||||
macro_rules! $name {
|
|
||||||
($$($$op:ident),*) => {
|
|
||||||
[$$(
|
|
||||||
|$a, $b, $c: u64| $$op($($tt)*),
|
|
||||||
)*]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
def_op!(basic_op | a, b, c | a, b, c as _);
|
|
||||||
def_op!(sub_op | a, b, c | a, b, c.wrapping_neg() as _);
|
|
||||||
|
|
||||||
let ops = match op {
|
|
||||||
T::Add => basic_op!(addi8, addi16, addi32, addi64),
|
|
||||||
T::Sub => sub_op!(addi8, addi16, addi32, addi64),
|
|
||||||
T::Mul => basic_op!(muli8, muli16, muli32, muli64),
|
|
||||||
T::Band => return Some(andi),
|
|
||||||
T::Bor => return Some(ori),
|
|
||||||
T::Xor => return Some(xori),
|
|
||||||
T::Shr if signed => basic_op!(srui8, srui16, srui32, srui64),
|
|
||||||
T::Shr => basic_op!(srui8, srui16, srui32, srui64),
|
|
||||||
T::Shl => basic_op!(slui8, slui16, slui32, slui64),
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(ops[size.ilog2() as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_global(&mut self, id: ty::Global) -> Option<Value> {
|
fn handle_global(&mut self, id: ty::Global) -> Option<Value> {
|
||||||
let ptr = self.ci.regs.allocate();
|
let ptr = self.ci.regs.allocate();
|
||||||
|
|
||||||
|
@ -2708,14 +2614,6 @@ impl Codegen {
|
||||||
&self.files[self.ci.file as usize]
|
&self.files[self.ci.file as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_code(&mut self) -> &mut [u8] {
|
|
||||||
&mut self.ci.code
|
|
||||||
}
|
|
||||||
|
|
||||||
fn local_offset(&self) -> u32 {
|
|
||||||
self.ci.code.len() as _
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple {
|
fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple {
|
||||||
let needle = &self.tys.args[arg_base..];
|
let needle = &self.tys.args[arg_base..];
|
||||||
if needle.is_empty() {
|
if needle.is_empty() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::instrs;
|
||||||
|
|
||||||
const fn ascii_mask(chars: &[u8]) -> u128 {
|
const fn ascii_mask(chars: &[u8]) -> u128 {
|
||||||
let mut eq = 0;
|
let mut eq = 0;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -168,6 +170,98 @@ pub enum TokenKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenKind {
|
impl TokenKind {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn cond_op(
|
||||||
|
self,
|
||||||
|
signed: bool,
|
||||||
|
) -> Option<(fn(u8, u8, i16) -> (usize, [u8; instrs::MAX_SIZE]), bool)> {
|
||||||
|
Some((
|
||||||
|
match self {
|
||||||
|
Self::Le if signed => instrs::jgts,
|
||||||
|
Self::Le => instrs::jgtu,
|
||||||
|
Self::Lt if signed => instrs::jlts,
|
||||||
|
Self::Lt => instrs::jltu,
|
||||||
|
Self::Ge if signed => instrs::jlts,
|
||||||
|
Self::Ge => instrs::jltu,
|
||||||
|
Self::Gt if signed => instrs::jgts,
|
||||||
|
Self::Gt => instrs::jgtu,
|
||||||
|
Self::Eq => instrs::jne,
|
||||||
|
Self::Ne => instrs::jeq,
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
matches!(self, Self::Lt | TokenKind::Gt),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn math_op(
|
||||||
|
self,
|
||||||
|
signed: bool,
|
||||||
|
size: u32,
|
||||||
|
) -> Option<fn(u8, u8, u8) -> (usize, [u8; instrs::MAX_SIZE])> {
|
||||||
|
use instrs::*;
|
||||||
|
|
||||||
|
macro_rules! div { ($($op:ident),*) => {[$(|a, b, c| $op(a, 0, b, c)),*]}; }
|
||||||
|
macro_rules! rem { ($($op:ident),*) => {[$(|a, b, c| $op(0, a, b, c)),*]}; }
|
||||||
|
|
||||||
|
let ops = match self {
|
||||||
|
Self::Add => [add8, add16, add32, add64],
|
||||||
|
Self::Sub => [sub8, sub16, sub32, sub64],
|
||||||
|
Self::Mul => [mul8, mul16, mul32, mul64],
|
||||||
|
Self::Div if signed => div!(dirs8, dirs16, dirs32, dirs64),
|
||||||
|
Self::Div => div!(diru8, diru16, diru32, diru64),
|
||||||
|
Self::Mod if signed => rem!(dirs8, dirs16, dirs32, dirs64),
|
||||||
|
Self::Mod => rem!(diru8, diru16, diru32, diru64),
|
||||||
|
Self::Band => return Some(and),
|
||||||
|
Self::Bor => return Some(or),
|
||||||
|
Self::Xor => return Some(xor),
|
||||||
|
Self::Shl => [slu8, slu16, slu32, slu64],
|
||||||
|
Self::Shr if signed => [srs8, srs16, srs32, srs64],
|
||||||
|
Self::Shr => [sru8, sru16, sru32, sru64],
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(ops[size.ilog2() as usize])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn imm_math_op(
|
||||||
|
self,
|
||||||
|
signed: bool,
|
||||||
|
size: u32,
|
||||||
|
) -> Option<fn(u8, u8, u64) -> (usize, [u8; instrs::MAX_SIZE])> {
|
||||||
|
use instrs::*;
|
||||||
|
macro_rules! def_op {
|
||||||
|
($name:ident |$a:ident, $b:ident, $c:ident| $($tt:tt)*) => {
|
||||||
|
macro_rules! $name {
|
||||||
|
($$($$op:ident),*) => {
|
||||||
|
[$$(
|
||||||
|
|$a, $b, $c: u64| $$op($($tt)*),
|
||||||
|
)*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
def_op!(basic_op | a, b, c | a, b, c as _);
|
||||||
|
def_op!(sub_op | a, b, c | a, b, c.wrapping_neg() as _);
|
||||||
|
|
||||||
|
let ops = match self {
|
||||||
|
Self::Add => basic_op!(addi8, addi16, addi32, addi64),
|
||||||
|
Self::Sub => sub_op!(addi8, addi16, addi32, addi64),
|
||||||
|
Self::Mul => basic_op!(muli8, muli16, muli32, muli64),
|
||||||
|
Self::Band => return Some(andi),
|
||||||
|
Self::Bor => return Some(ori),
|
||||||
|
Self::Xor => return Some(xori),
|
||||||
|
Self::Shr if signed => basic_op!(srui8, srui16, srui32, srui64),
|
||||||
|
Self::Shr => basic_op!(srui8, srui16, srui32, srui64),
|
||||||
|
Self::Shl => basic_op!(slui8, slui16, slui32, slui64),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(ops[size.ilog2() as usize])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ass_op(self) -> Option<Self> {
|
pub fn ass_op(self) -> Option<Self> {
|
||||||
let id = (self as u8).saturating_sub(128);
|
let id = (self as u8).saturating_sub(128);
|
||||||
if ascii_mask(b"|+-*/%^&79") & (1u128 << id) == 0 {
|
if ascii_mask(b"|+-*/%^&79") & (1u128 << id) == 0 {
|
||||||
|
|
|
@ -332,7 +332,6 @@ impl BitSet {
|
||||||
type Nid = u16;
|
type Nid = u16;
|
||||||
|
|
||||||
pub mod reg {
|
pub mod reg {
|
||||||
|
|
||||||
pub const STACK_PTR: Reg = 254;
|
pub const STACK_PTR: Reg = 254;
|
||||||
pub const ZERO: Reg = 0;
|
pub const ZERO: Reg = 0;
|
||||||
pub const RET: Reg = 1;
|
pub const RET: Reg = 1;
|
||||||
|
@ -2245,8 +2244,7 @@ impl Codegen {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((op, swpd)) =
|
let Some((op, swpd)) = op.cond_op(self.ci.nodes[left].ty.is_signed())
|
||||||
Self::cond_op(op, self.ci.nodes[left].ty.is_signed())
|
|
||||||
else {
|
else {
|
||||||
break 'optimize_cond;
|
break 'optimize_cond;
|
||||||
};
|
};
|
||||||
|
@ -2488,8 +2486,8 @@ impl Codegen {
|
||||||
} else {
|
} else {
|
||||||
self.emit_expr_consume(right);
|
self.emit_expr_consume(right);
|
||||||
|
|
||||||
let op = Self::math_op(op, ty.is_signed(), self.tys.size_of(ty))
|
let op =
|
||||||
.expect("TODO: what now?");
|
op.math_op(ty.is_signed(), self.tys.size_of(ty)).expect("TODO: what now?");
|
||||||
|
|
||||||
let instr = op(
|
let instr = op(
|
||||||
node_loc!(self, expr).reg,
|
node_loc!(self, expr).reg,
|
||||||
|
@ -2564,56 +2562,6 @@ impl Codegen {
|
||||||
Some(ops[size.ilog2() as usize])
|
Some(ops[size.ilog2() as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn cond_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
) -> Option<(fn(u8, u8, i16) -> (usize, [u8; instrs::MAX_SIZE]), bool)> {
|
|
||||||
Some((
|
|
||||||
match op {
|
|
||||||
TokenKind::Le if signed => instrs::jgts,
|
|
||||||
TokenKind::Le => instrs::jgtu,
|
|
||||||
TokenKind::Lt if signed => instrs::jlts,
|
|
||||||
TokenKind::Lt => instrs::jltu,
|
|
||||||
TokenKind::Eq => instrs::jne,
|
|
||||||
TokenKind::Ne => instrs::jeq,
|
|
||||||
_ => return None,
|
|
||||||
},
|
|
||||||
matches!(op, TokenKind::Lt | TokenKind::Gt),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn math_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
size: u32,
|
|
||||||
) -> Option<fn(u8, u8, u8) -> (usize, [u8; instrs::MAX_SIZE])> {
|
|
||||||
use {instrs::*, TokenKind as T};
|
|
||||||
|
|
||||||
macro_rules! div { ($($op:ident),*) => {[$(|a, b, c| $op(a, reg::ZERO, b, c)),*]}; }
|
|
||||||
macro_rules! rem { ($($op:ident),*) => {[$(|a, b, c| $op(reg::ZERO, a, b, c)),*]}; }
|
|
||||||
|
|
||||||
let ops = match op {
|
|
||||||
T::Add => [add8, add16, add32, add64],
|
|
||||||
T::Sub => [sub8, sub16, sub32, sub64],
|
|
||||||
T::Mul => [mul8, mul16, mul32, mul64],
|
|
||||||
T::Div if signed => div!(dirs8, dirs16, dirs32, dirs64),
|
|
||||||
T::Div => div!(diru8, diru16, diru32, diru64),
|
|
||||||
T::Mod if signed => rem!(dirs8, dirs16, dirs32, dirs64),
|
|
||||||
T::Mod => rem!(diru8, diru16, diru32, diru64),
|
|
||||||
T::Band => return Some(and),
|
|
||||||
T::Bor => return Some(or),
|
|
||||||
T::Xor => return Some(xor),
|
|
||||||
T::Shl => [slu8, slu16, slu32, slu64],
|
|
||||||
T::Shr if signed => [srs8, srs16, srs32, srs64],
|
|
||||||
T::Shr => [sru8, sru16, sru32, sru64],
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(ops[size.ilog2() as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: sometimes its better to do this in bulk
|
// TODO: sometimes its better to do this in bulk
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
match *expr {
|
match *expr {
|
||||||
|
|
Loading…
Reference in a new issue