adding floating point conversions

This commit is contained in:
Jakub Doka 2024-10-29 14:24:31 +01:00
parent 80558ea7e6
commit 24b9f9e78b
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
4 changed files with 105 additions and 6 deletions

View file

@ -277,6 +277,9 @@ main := fn(): uint {
same_type_as_byte := @as(@TypeOf(byte), 30) same_type_as_byte := @as(@TypeOf(byte), 30)
wide_uint := @as(u32, 40) wide_uint := @as(u32, 40)
truncated_uint := @as(u8, @intcast(wide_uint)) truncated_uint := @as(u8, @intcast(wide_uint))
widened_float := @as(f64, @floatcast(1.))
int_from_float := @as(int, @fti(1.))
float_from_int := @as(f64, @itf(@as(int, 1)))
size_of_Type_in_bytes := @sizeof(foo.Type) size_of_Type_in_bytes := @sizeof(foo.Type)
align_of_Type_in_bytes := @alignof(foo.Type) align_of_Type_in_bytes := @alignof(foo.Type)
hardcoded_pointer := @as(^u8, @bitcast(10)) hardcoded_pointer := @as(^u8, @bitcast(10))

View file

@ -257,9 +257,16 @@ impl TokenKind {
&& self.precedence() != Self::Eof.precedence() && self.precedence() != Self::Eof.precedence()
} }
pub fn apply_unop(&self, value: i64) -> i64 { pub fn apply_unop(&self, value: i64, float: bool) -> i64 {
match self { match self {
Self::Sub if float => (-f64::from_bits(value as _)).to_bits() as _,
Self::Sub => value.wrapping_neg(), Self::Sub => value.wrapping_neg(),
Self::Float if float => value,
Self::Float => (value as f64).to_bits() as _,
Self::Number => {
debug_assert!(float);
f64::from_bits(value as _).to_bits() as _
}
s => todo!("{s}"), s => todo!("{s}"),
} }
} }

View file

@ -792,10 +792,14 @@ impl Nodes {
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() }; let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
let ty = self[target].ty; let ty = self[target].ty;
let is_float = self[oper].ty.is_float();
if let K::CInt { value } = self[oper].kind { if let K::CInt { value } = self[oper].kind {
return Some( return Some(self.new_node(
self.new_node(ty, K::CInt { value: op.apply_unop(value) }, [ctrl]), ty,
); K::CInt { value: op.apply_unop(value, is_float) },
[ctrl],
));
} }
} }
K::If => { K::If => {
@ -2649,6 +2653,79 @@ impl<'a> Codegen<'a> {
Some(val.ty(ty)) Some(val.ty(ty))
} }
} }
Expr::Directive { pos, name: "floatcast", args: [expr] } => {
let val = self.expr(expr)?;
if !val.ty.is_float() {
self.report(
expr.pos(),
fa!(
"only floats can be truncated ('{}' is not a float)",
self.ty_display(val.ty)
),
);
return Value::NEVER;
}
inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))");
if !ty.is_float() {
self.report(
expr.pos(),
fa!(
"floatcast is inferred to output '{}', which is not a float",
self.ty_display(ty)
),
);
}
if self.tys.size_of(val.ty) < self.tys.size_of(ty) {
Some(
self.ci
.nodes
.new_node_lit(ty, Kind::UnOp { op: TokenKind::Float }, [VOID, val.id]),
)
} else {
Some(val.ty(ty))
}
}
Expr::Directive { name: "fti", args: [expr], .. } => {
let val = self.expr(expr)?;
let ret_ty = match val.ty {
ty::Id::F64 => ty::Id::INT,
ty::Id::F32 => ty::Id::I32,
_ => {
self.report(
expr.pos(),
fa!("expected float ('{}' is not a float)", self.ty_display(val.ty)),
);
return Value::NEVER;
}
};
Some(
self.ci
.nodes
.new_node_lit(ret_ty, Kind::UnOp { op: TokenKind::Number }, [VOID, val.id]),
)
}
Expr::Directive { name: "itf", args: [expr], .. } => {
let mut val = self.expr(expr)?;
let (ret_ty, expected) = match val.ty.simple_size().unwrap() {
8 => (ty::Id::F64, ty::Id::INT),
_ => (ty::Id::F32, ty::Id::I32),
};
self.assert_ty(expr.pos(), &mut val, expected, "converted integer");
Some(
self.ci
.nodes
.new_node_lit(ret_ty, Kind::UnOp { op: TokenKind::Float }, [VOID, val.id]),
)
}
Expr::Directive { name: "as", args: [ty, expr], .. } => { Expr::Directive { name: "as", args: [ty, expr], .. } => {
let ty = self.ty(ty); let ty = self.ty(ty);
let ctx = Ctx::default().with_ty(ty); let ctx = Ctx::default().with_ty(ty);

View file

@ -323,7 +323,9 @@ impl ItemCtx {
_ => instrs::li64(atr(allocs[0]), value as _), _ => instrs::li64(atr(allocs[0]), value as _),
}), }),
Kind::UnOp { op } => { Kind::UnOp { op } => {
let op = op.unop().expect("TODO: unary operator not supported"); let op = op
.unop(node.ty, fuc.nodes[node.inputs[1]].ty)
.expect("TODO: unary operator not supported");
let &[dst, oper] = allocs else { unreachable!() }; let &[dst, oper] = allocs else { unreachable!() };
self.emit(op(atr(dst), atr(oper))); self.emit(op(atr(dst), atr(oper)));
} }
@ -1332,9 +1334,19 @@ impl TokenKind {
Some(ops[size.ilog2() as usize]) Some(ops[size.ilog2() as usize])
} }
pub fn unop(&self) -> Option<fn(u8, u8) -> EncodedInstr> { pub fn unop(&self, dst: ty::Id, src: ty::Id) -> Option<fn(u8, u8) -> EncodedInstr> {
let src_idx = src.simple_size().unwrap().ilog2() as usize - 2;
Some(match self { Some(match self {
Self::Sub => instrs::neg, Self::Sub => instrs::neg,
Self::Float if dst.is_float() && src.is_integer() => {
[instrs::itf32, instrs::itf64][src_idx]
}
Self::Number if src.is_float() && dst.is_integer() => {
[|a, b| instrs::fti32(a, b, 1), |a, b| instrs::fti64(a, b, 1)][src_idx]
}
Self::Float if dst.is_float() && src.is_float() => {
[instrs::fc32t64, |a, b| instrs::fc64t32(a, b, 1)][src_idx]
}
_ => return None, _ => return None,
}) })
} }