forked from AbleOS/holey-bytes
adding floating point arithmetic
This commit is contained in:
parent
348d9014e3
commit
80558ea7e6
|
@ -51,6 +51,13 @@ main := fn(): uint {
|
|||
}
|
||||
```
|
||||
|
||||
#### floating_point_arithmetic
|
||||
```hb
|
||||
main := fn(): f32 {
|
||||
return 10. - 20. / 2. + 4. * (2. + 2.) - 4. * 4. + -1.
|
||||
}
|
||||
```
|
||||
|
||||
#### functions
|
||||
```hb
|
||||
main := fn(): uint {
|
||||
|
|
|
@ -366,6 +366,9 @@ impl<'a> Formatter<'a> {
|
|||
let mut buf = [0u8; 64];
|
||||
f.write_str(display_radix(radix, value as u64, &mut buf))
|
||||
}
|
||||
Expr::Float { pos, .. } => {
|
||||
f.write_str(&self.source[Lexer::restore(self.source, pos).eat().range()])
|
||||
}
|
||||
Expr::Bool { value, .. } => f.write_str(if value { "true" } else { "false" }),
|
||||
Expr::Idk { .. } => f.write_str("idk"),
|
||||
Expr::Null { .. } => f.write_str("null"),
|
||||
|
@ -475,7 +478,8 @@ pub mod test {
|
|||
let len = crate::fmt::minify(&mut minned);
|
||||
minned.truncate(len);
|
||||
|
||||
let ast = parser::Ast::new(ident, minned, &mut Ctx::default(), &mut parser::no_loader);
|
||||
let mut ctx = Ctx::default();
|
||||
let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader);
|
||||
//log::error!(
|
||||
// "{} / {} = {} | {} / {} = {}",
|
||||
// ast.mem.size(),
|
||||
|
|
|
@ -116,6 +116,7 @@ pub enum TokenKind {
|
|||
|
||||
Ident,
|
||||
Number,
|
||||
Float,
|
||||
Eof,
|
||||
|
||||
Ct,
|
||||
|
@ -190,7 +191,43 @@ impl TokenKind {
|
|||
matches!(self, S::Eq | S::Ne | S::Bor | S::Xor | S::Band | S::Add | S::Mul)
|
||||
}
|
||||
|
||||
pub fn apply_binop(self, a: i64, b: i64) -> i64 {
|
||||
pub fn is_supported_float_op(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Add
|
||||
| Self::Sub
|
||||
| Self::Mul
|
||||
| Self::Div
|
||||
| Self::Eq
|
||||
| Self::Ne
|
||||
| Self::Le
|
||||
| Self::Ge
|
||||
| Self::Lt
|
||||
| Self::Gt
|
||||
)
|
||||
}
|
||||
|
||||
pub fn apply_binop(self, a: i64, b: i64, float: bool) -> i64 {
|
||||
if float {
|
||||
debug_assert!(self.is_supported_float_op());
|
||||
let [a, b] = [f64::from_bits(a as _), f64::from_bits(b as _)];
|
||||
let res = match self {
|
||||
Self::Add => a + b,
|
||||
Self::Sub => a - b,
|
||||
Self::Mul => a * b,
|
||||
Self::Div => a / b,
|
||||
Self::Eq => return (a == b) as i64,
|
||||
Self::Ne => return (a != b) as i64,
|
||||
Self::Lt => return (a < b) as i64,
|
||||
Self::Gt => return (a > b) as i64,
|
||||
Self::Le => return (a >= b) as i64,
|
||||
Self::Ge => return (a <= b) as i64,
|
||||
_ => todo!("floating point op: {self}"),
|
||||
};
|
||||
|
||||
return res.to_bits() as _;
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Add => a.wrapping_add(b),
|
||||
Self::Sub => a.wrapping_sub(b),
|
||||
|
@ -214,15 +251,6 @@ impl TokenKind {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cmp_against(self) -> Option<u64> {
|
||||
Some(match self {
|
||||
TokenKind::Le | TokenKind::Gt => 1,
|
||||
TokenKind::Ne | TokenKind::Eq => 0,
|
||||
TokenKind::Ge | TokenKind::Lt => (-1i64) as _,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_homogenous(&self) -> bool {
|
||||
self.precedence() != Self::Eq.precedence()
|
||||
&& self.precedence() != Self::Gt.precedence()
|
||||
|
@ -254,6 +282,7 @@ gen_token_kind! {
|
|||
CtIdent,
|
||||
Ident,
|
||||
Number,
|
||||
Float,
|
||||
Eof,
|
||||
Directive,
|
||||
#[keywords]
|
||||
|
@ -418,7 +447,15 @@ impl<'a> Lexer<'a> {
|
|||
while let Some(b'0'..=b'9') = self.peek() {
|
||||
self.advance();
|
||||
}
|
||||
T::Number
|
||||
|
||||
if self.advance_if(b'.') {
|
||||
while let Some(b'0'..=b'9') = self.peek() {
|
||||
self.advance();
|
||||
}
|
||||
T::Float
|
||||
} else {
|
||||
T::Number
|
||||
}
|
||||
}
|
||||
b'a'..=b'z' | b'A'..=b'Z' | b'_' | 127.. => {
|
||||
advance_ident(self);
|
||||
|
|
|
@ -409,6 +409,10 @@ mod ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_float(self) -> bool {
|
||||
matches!(self.repr(), F32 | F64) || self.is_never()
|
||||
}
|
||||
|
||||
pub fn is_signed(self) -> bool {
|
||||
matches!(self.repr(), I8..=INT) || self.is_never()
|
||||
}
|
||||
|
@ -465,8 +469,8 @@ mod ty {
|
|||
Kind::Ptr(_) => 8,
|
||||
Kind::Builtin(VOID) => 0,
|
||||
Kind::Builtin(NEVER) => 0,
|
||||
Kind::Builtin(INT | UINT) => 8,
|
||||
Kind::Builtin(I32 | U32 | TYPE) => 4,
|
||||
Kind::Builtin(INT | UINT | F64) => 8,
|
||||
Kind::Builtin(I32 | U32 | TYPE | F32) => 4,
|
||||
Kind::Builtin(I16 | U16) => 2,
|
||||
Kind::Builtin(I8 | U8 | BOOL) => 1,
|
||||
_ => return None,
|
||||
|
@ -547,7 +551,6 @@ mod ty {
|
|||
};)*
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
impl Id {
|
||||
$(pub const $name: Self = Kind::Builtin($name).compress();)*
|
||||
}
|
||||
|
@ -584,7 +587,8 @@ mod ty {
|
|||
I16;
|
||||
I32;
|
||||
INT;
|
||||
|
||||
F32;
|
||||
F64;
|
||||
}
|
||||
|
||||
macro_rules! type_kind {
|
||||
|
|
|
@ -472,6 +472,14 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
radix,
|
||||
}
|
||||
}
|
||||
T::Float => E::Float {
|
||||
pos,
|
||||
value: match <f64 as core::str::FromStr>::from_str(self.lexer.slice(token.range()))
|
||||
{
|
||||
Ok(f) => f.to_bits(),
|
||||
Err(e) => self.report(token.start, format_args!("invalid float: {e}"))?,
|
||||
},
|
||||
},
|
||||
T::LParen => {
|
||||
let expr = self.expr()?;
|
||||
self.expect_advance(T::RParen)?;
|
||||
|
@ -811,6 +819,11 @@ generate_expr! {
|
|||
value: i64,
|
||||
radix: Radix,
|
||||
},
|
||||
/// `'[0-9]+.[0-9]*'`
|
||||
Float {
|
||||
pos: Pos,
|
||||
value: u64,
|
||||
},
|
||||
/// node: precedence defined in `OP` applies
|
||||
/// `Expr OP Expr`
|
||||
BinOp {
|
||||
|
|
|
@ -692,12 +692,16 @@ impl Nodes {
|
|||
};
|
||||
let ty = self[target].ty;
|
||||
|
||||
let is_float = self[lhs].ty.is_float();
|
||||
|
||||
if let (&K::CInt { value: a }, &K::CInt { value: b }) =
|
||||
(&self[lhs].kind, &self[rhs].kind)
|
||||
{
|
||||
return Some(
|
||||
self.new_node(ty, K::CInt { value: op.apply_binop(a, b) }, [ctrl]),
|
||||
);
|
||||
return Some(self.new_node(
|
||||
ty,
|
||||
K::CInt { value: op.apply_binop(a, b, is_float) },
|
||||
[ctrl],
|
||||
));
|
||||
}
|
||||
|
||||
if lhs == rhs {
|
||||
|
@ -734,10 +738,11 @@ impl Nodes {
|
|||
&& let K::CInt { value: bv } = self[rhs].kind
|
||||
{
|
||||
// (a op #b) op #c => a op (#b op #c)
|
||||
let new_rhs =
|
||||
self.new_node_nop(ty, K::CInt { value: op.apply_binop(av, bv) }, [
|
||||
ctrl,
|
||||
]);
|
||||
let new_rhs = self.new_node_nop(
|
||||
ty,
|
||||
K::CInt { value: op.apply_binop(av, bv, is_float) },
|
||||
[ctrl],
|
||||
);
|
||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||
}
|
||||
|
||||
|
@ -2235,6 +2240,11 @@ impl<'a> Codegen<'a> {
|
|||
Kind::CInt { value },
|
||||
[VOID],
|
||||
)),
|
||||
Expr::Float { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
|
||||
Kind::CInt { value: value as _ },
|
||||
[VOID],
|
||||
)),
|
||||
Expr::Ident { id, .. }
|
||||
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
||||
{
|
||||
|
@ -2425,10 +2435,21 @@ impl<'a> Codegen<'a> {
|
|||
Expr::UnOp { pos, op: op @ TokenKind::Sub, val } => {
|
||||
let val =
|
||||
self.expr_ctx(val, Ctx::default().with_ty(ctx.ty.unwrap_or(ty::Id::INT)))?;
|
||||
if !val.ty.is_integer() {
|
||||
if val.ty.is_integer() {
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
||||
} else if val.ty.is_float() {
|
||||
let value = self.ci.nodes.new_node_nop(
|
||||
val.ty,
|
||||
Kind::CInt { value: (-1f64).to_bits() as _ },
|
||||
[VOID],
|
||||
);
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [
|
||||
VOID, val.id, value,
|
||||
]))
|
||||
} else {
|
||||
self.report(pos, fa!("cant negate '{}'", self.ty_display(val.ty)));
|
||||
Value::NEVER
|
||||
}
|
||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
||||
}
|
||||
Expr::BinOp { left, op: TokenKind::Decl, right, .. } => {
|
||||
let mut right = self.expr(right)?;
|
||||
|
@ -2473,7 +2494,11 @@ impl<'a> Codegen<'a> {
|
|||
self.strip_var(&mut lhs);
|
||||
|
||||
match lhs.ty.expand() {
|
||||
_ if lhs.ty.is_pointer() || lhs.ty.is_integer() || lhs.ty == ty::Id::BOOL => {
|
||||
_ if lhs.ty.is_pointer()
|
||||
|| lhs.ty.is_integer()
|
||||
|| lhs.ty == ty::Id::BOOL
|
||||
|| (lhs.ty.is_float() && op.is_supported_float_op()) =>
|
||||
{
|
||||
self.strip_ptr(&mut lhs);
|
||||
self.ci.nodes.lock(lhs.id);
|
||||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(lhs.ty));
|
||||
|
@ -3924,6 +3949,7 @@ mod tests {
|
|||
// Tour Examples
|
||||
main_fn;
|
||||
arithmetic;
|
||||
floating_point_arithmetic;
|
||||
functions;
|
||||
comments;
|
||||
if_statements;
|
||||
|
|
|
@ -247,7 +247,7 @@ impl ItemCtx {
|
|||
let &[_, cnd] = node.inputs.as_slice() else { unreachable!() };
|
||||
if let Kind::BinOp { op } = fuc.nodes[cnd].kind
|
||||
&& let Some((op, swapped)) =
|
||||
op.cond_op(fuc.nodes[fuc.nodes[cnd].inputs[1]].ty.is_signed())
|
||||
op.cond_op(fuc.nodes[fuc.nodes[cnd].inputs[1]].ty)
|
||||
{
|
||||
let &[lhs, rhs] = allocs else { unreachable!() };
|
||||
let &[_, lh, rh] = fuc.nodes[cnd].inputs.as_slice() else {
|
||||
|
@ -306,6 +306,16 @@ impl ItemCtx {
|
|||
self.emit(instrs::jmp(0));
|
||||
}
|
||||
}
|
||||
Kind::CInt { value } if node.ty.is_float() => {
|
||||
self.emit(match node.ty {
|
||||
ty::Id::F32 => instrs::li32(
|
||||
atr(allocs[0]),
|
||||
(f64::from_bits(value as _) as f32).to_bits(),
|
||||
),
|
||||
ty::Id::F64 => instrs::li64(atr(allocs[0]), value as _),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
Kind::CInt { value } => self.emit(match tys.size_of(node.ty) {
|
||||
1 => instrs::li8(atr(allocs[0]), value as _),
|
||||
2 => instrs::li16(atr(allocs[0]), value as _),
|
||||
|
@ -319,33 +329,48 @@ impl ItemCtx {
|
|||
}
|
||||
Kind::BinOp { .. } if node.lock_rc != 0 => {}
|
||||
Kind::BinOp { op } => {
|
||||
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||
let &[.., lh, rh] = node.inputs.as_slice() else { unreachable!() };
|
||||
|
||||
if let Kind::CInt { value } = fuc.nodes[rhs].kind
|
||||
&& fuc.nodes[rhs].lock_rc != 0
|
||||
&& let Some(op) =
|
||||
op.imm_binop(node.ty.is_signed(), fuc.tys.size_of(node.ty))
|
||||
if let Kind::CInt { value } = fuc.nodes[rh].kind
|
||||
&& fuc.nodes[rh].lock_rc != 0
|
||||
&& let Some(op) = op.imm_binop(node.ty)
|
||||
{
|
||||
let &[dst, lhs] = allocs else { unreachable!() };
|
||||
self.emit(op(atr(dst), atr(lhs), value as _));
|
||||
} else if let Some(op) =
|
||||
op.binop(node.ty.is_signed(), fuc.tys.size_of(node.ty))
|
||||
op.binop(node.ty).or(op.float_cmp(fuc.nodes[lh].ty))
|
||||
{
|
||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||
self.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||
} else if let Some(against) = op.cmp_against() {
|
||||
let &[_, lh, rh] = node.inputs.as_slice() else { unreachable!() };
|
||||
let op_ty = fuc.nodes[lh].ty;
|
||||
|
||||
self.emit(extend(fuc.nodes[lh].ty, fuc.nodes[lh].ty.extend(), 0, 0));
|
||||
self.emit(extend(fuc.nodes[rh].ty, fuc.nodes[rh].ty.extend(), 1, 1));
|
||||
|
||||
let signed = fuc.nodes[lh].ty.is_signed();
|
||||
let op_fn = if signed { instrs::cmps } else { instrs::cmpu };
|
||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||
self.emit(op_fn(atr(dst), atr(lhs), atr(rhs)));
|
||||
self.emit(instrs::cmpui(atr(dst), atr(dst), against));
|
||||
if matches!(op, TokenKind::Eq | TokenKind::Lt | TokenKind::Gt) {
|
||||
|
||||
if op_ty.is_float() && matches!(op, TokenKind::Le | TokenKind::Ge) {
|
||||
let opop = match op {
|
||||
TokenKind::Le => TokenKind::Gt,
|
||||
TokenKind::Ge => TokenKind::Lt,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let op_fn = opop.float_cmp(op_ty).unwrap();
|
||||
self.emit(op_fn(atr(dst), atr(lhs), atr(rhs)));
|
||||
self.emit(instrs::not(atr(dst), atr(dst)));
|
||||
} else if op_ty.is_integer() {
|
||||
let op_fn =
|
||||
if op_ty.is_signed() { instrs::cmps } else { instrs::cmpu };
|
||||
self.emit(op_fn(atr(dst), atr(lhs), atr(rhs)));
|
||||
self.emit(instrs::cmpui(atr(dst), atr(dst), against));
|
||||
if matches!(op, TokenKind::Eq | TokenKind::Lt | TokenKind::Gt) {
|
||||
self.emit(instrs::not(atr(dst), atr(dst)));
|
||||
}
|
||||
} else {
|
||||
todo!("unhandled operator: {op}");
|
||||
}
|
||||
} else {
|
||||
todo!("unhandled operator: {op}");
|
||||
}
|
||||
}
|
||||
Kind::Call { args, func } => {
|
||||
|
@ -725,7 +750,7 @@ impl<'a> Function<'a> {
|
|||
let &[mut then, mut else_] = node.outputs.as_slice() else { unreachable!() };
|
||||
|
||||
if let Kind::BinOp { op } = self.nodes[cond].kind
|
||||
&& let Some((_, swapped)) = op.cond_op(node.ty.is_signed())
|
||||
&& let Some((_, swapped)) = op.cond_op(node.ty)
|
||||
{
|
||||
if swapped {
|
||||
mem::swap(&mut then, &mut else_);
|
||||
|
@ -789,9 +814,9 @@ impl<'a> Function<'a> {
|
|||
if node.outputs.iter().all(|&o| {
|
||||
let ond = &self.nodes[o];
|
||||
matches!(ond.kind, Kind::BinOp { op }
|
||||
if op.imm_binop(ond.ty.is_signed(), 8).is_some()
|
||||
if op.imm_binop(ond.ty).is_some()
|
||||
&& self.nodes.is_const(ond.inputs[2])
|
||||
&& op.cond_op(ond.ty.is_signed()).is_none())
|
||||
&& op.cond_op(ond.ty).is_none())
|
||||
}) =>
|
||||
{
|
||||
self.nodes.lock(nid)
|
||||
|
@ -853,7 +878,7 @@ impl<'a> Function<'a> {
|
|||
self.nodes.lock(nid)
|
||||
}
|
||||
Kind::BinOp { op }
|
||||
if op.cond_op(node.ty.is_signed()).is_some()
|
||||
if op.cond_op(node.ty).is_some()
|
||||
&& node.outputs.iter().all(|&n| self.nodes[n].kind == Kind::If) =>
|
||||
{
|
||||
self.nodes.lock(nid)
|
||||
|
@ -955,8 +980,8 @@ impl<'a> Function<'a> {
|
|||
Kind::Stck | Kind::Arg
|
||||
if node.outputs.iter().all(|&n| {
|
||||
matches!(self.nodes[n].kind, Kind::Load
|
||||
if self.nodes[n].ty.loc(self.tys) == Loc::Reg)
|
||||
|| matches!(self.nodes[n].kind, Kind::Stre
|
||||
if self.nodes[n].ty.loc(self.tys) == Loc::Reg)
|
||||
|| matches!(self.nodes[n].kind, Kind::Stre
|
||||
if self.nodes[n].ty.loc(self.tys) == Loc::Reg
|
||||
&& self.nodes[n].inputs[1] != nid)
|
||||
|| matches!(self.nodes[n].kind, Kind::BinOp { op: TokenKind::Add }
|
||||
|
@ -1183,8 +1208,36 @@ impl regalloc2::Function for Function<'_> {
|
|||
}
|
||||
|
||||
impl TokenKind {
|
||||
pub fn cmp_against(self) -> Option<u64> {
|
||||
Some(match self {
|
||||
TokenKind::Le | TokenKind::Gt => 1,
|
||||
TokenKind::Ne | TokenKind::Eq => 0,
|
||||
TokenKind::Ge | TokenKind::Lt => (-1i64) as _,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn float_cmp(self, ty: ty::Id) -> Option<fn(u8, u8, u8) -> EncodedInstr> {
|
||||
if !ty.is_float() {
|
||||
return None;
|
||||
}
|
||||
let size = ty.simple_size().unwrap();
|
||||
|
||||
let ops = match self {
|
||||
TokenKind::Gt => [instrs::fcmpgt32, instrs::fcmpgt64],
|
||||
TokenKind::Lt => [instrs::fcmplt32, instrs::fcmplt64],
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(ops[size.ilog2() as usize - 2])
|
||||
}
|
||||
|
||||
#[expect(clippy::type_complexity)]
|
||||
fn cond_op(self, signed: bool) -> Option<(fn(u8, u8, i16) -> EncodedInstr, bool)> {
|
||||
fn cond_op(self, ty: ty::Id) -> Option<(fn(u8, u8, i16) -> EncodedInstr, bool)> {
|
||||
if ty.is_float() {
|
||||
return None;
|
||||
}
|
||||
let signed = ty.is_signed();
|
||||
Some((
|
||||
match self {
|
||||
Self::Le if signed => instrs::jgts,
|
||||
|
@ -1203,31 +1256,45 @@ impl TokenKind {
|
|||
))
|
||||
}
|
||||
|
||||
fn binop(self, signed: bool, size: u32) -> Option<fn(u8, u8, u8) -> EncodedInstr> {
|
||||
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)),*]}; }
|
||||
fn binop(self, ty: ty::Id) -> Option<fn(u8, u8, u8) -> EncodedInstr> {
|
||||
let size = ty.simple_size().unwrap();
|
||||
if ty.is_integer() || ty == ty::Id::BOOL || ty.is_pointer() {
|
||||
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 signed = ty.is_signed();
|
||||
|
||||
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,
|
||||
};
|
||||
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])
|
||||
Some(ops[size.ilog2() as usize])
|
||||
} else {
|
||||
debug_assert!(ty.is_float(), "{self} {ty:?}");
|
||||
let ops = match self {
|
||||
Self::Add => [fadd32, fadd64],
|
||||
Self::Sub => [fsub32, fsub64],
|
||||
Self::Mul => [fmul32, fmul64],
|
||||
Self::Div => [fdiv32, fdiv64],
|
||||
_ => return None,
|
||||
};
|
||||
Some(ops[size.ilog2() as usize - 2])
|
||||
}
|
||||
}
|
||||
|
||||
fn imm_binop(self, signed: bool, size: u32) -> Option<fn(u8, u8, u64) -> EncodedInstr> {
|
||||
fn imm_binop(self, ty: ty::Id) -> Option<fn(u8, u8, u64) -> EncodedInstr> {
|
||||
macro_rules! def_op {
|
||||
($name:ident |$a:ident, $b:ident, $c:ident| $($tt:tt)*) => {
|
||||
macro_rules! $name {
|
||||
|
@ -1240,9 +1307,14 @@ impl TokenKind {
|
|||
};
|
||||
}
|
||||
|
||||
if ty.is_float() {
|
||||
return None;
|
||||
}
|
||||
|
||||
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 signed = ty.is_signed();
|
||||
let ops = match self {
|
||||
Self::Add => basic_op!(addi8, addi16, addi32, addi64),
|
||||
Self::Sub => sub_op!(addi8, addi16, addi32, addi64),
|
||||
|
@ -1256,6 +1328,7 @@ impl TokenKind {
|
|||
_ => return None,
|
||||
};
|
||||
|
||||
let size = ty.simple_size().unwrap();
|
||||
Some(ops[size.ilog2() as usize])
|
||||
}
|
||||
|
||||
|
|
6
lang/tests/son_tests_floating_point_arithmetic.txt
Normal file
6
lang/tests/son_tests_floating_point_arithmetic.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
main:
|
||||
LI32 r1, 3212836864w
|
||||
JALA r0, r31, 0a
|
||||
code size: 25
|
||||
ret: 3212836864
|
||||
status: Ok(())
|
Loading…
Reference in a new issue