adding floating point conversions
This commit is contained in:
parent
80558ea7e6
commit
24b9f9e78b
|
@ -277,6 +277,9 @@ main := fn(): uint {
|
|||
same_type_as_byte := @as(@TypeOf(byte), 30)
|
||||
wide_uint := @as(u32, 40)
|
||||
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)
|
||||
align_of_Type_in_bytes := @alignof(foo.Type)
|
||||
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||
|
|
|
@ -257,9 +257,16 @@ impl TokenKind {
|
|||
&& 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 {
|
||||
Self::Sub if float => (-f64::from_bits(value as _)).to_bits() as _,
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -792,10 +792,14 @@ impl Nodes {
|
|||
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
||||
let ty = self[target].ty;
|
||||
|
||||
let is_float = self[oper].ty.is_float();
|
||||
|
||||
if let K::CInt { value } = self[oper].kind {
|
||||
return Some(
|
||||
self.new_node(ty, K::CInt { value: op.apply_unop(value) }, [ctrl]),
|
||||
);
|
||||
return Some(self.new_node(
|
||||
ty,
|
||||
K::CInt { value: op.apply_unop(value, is_float) },
|
||||
[ctrl],
|
||||
));
|
||||
}
|
||||
}
|
||||
K::If => {
|
||||
|
@ -2649,6 +2653,79 @@ impl<'a> Codegen<'a> {
|
|||
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], .. } => {
|
||||
let ty = self.ty(ty);
|
||||
let ctx = Ctx::default().with_ty(ty);
|
||||
|
|
|
@ -323,7 +323,9 @@ impl ItemCtx {
|
|||
_ => instrs::li64(atr(allocs[0]), value as _),
|
||||
}),
|
||||
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!() };
|
||||
self.emit(op(atr(dst), atr(oper)));
|
||||
}
|
||||
|
@ -1332,9 +1334,19 @@ impl TokenKind {
|
|||
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 {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue