mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
gen_dev: Implement builtins Num.isNan, Num.isFinite, Num.isInfinite
This commit is contained in:
parent
d8b658da5d
commit
9a2afbb09b
3 changed files with 137 additions and 3 deletions
|
@ -1590,6 +1590,89 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_num_is_nan(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>) {
|
||||||
|
let float_width = match *arg_layout {
|
||||||
|
Layout::F32 => FloatWidth::F32,
|
||||||
|
Layout::F64 => FloatWidth::F64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
let src_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src);
|
||||||
|
|
||||||
|
ASM::is_nan_freg_reg64(&mut self.buf, dst_reg, src_reg, float_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_num_is_infinite(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>) {
|
||||||
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
let src_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src);
|
||||||
|
|
||||||
|
self.storage_manager.with_tmp_general_reg(
|
||||||
|
&mut self.buf,
|
||||||
|
|_storage_manager, buf, mask_reg| {
|
||||||
|
match *arg_layout {
|
||||||
|
Layout::F32 => {
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7fff_ffff);
|
||||||
|
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg); // zero out dst reg
|
||||||
|
ASM::mov_reg32_freg32(buf, dst_reg, src_reg);
|
||||||
|
ASM::and_reg64_reg64_reg64(buf, dst_reg, dst_reg, mask_reg);
|
||||||
|
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7f80_0000);
|
||||||
|
ASM::eq_reg_reg_reg(buf, RegisterWidth::W32, dst_reg, dst_reg, mask_reg);
|
||||||
|
}
|
||||||
|
Layout::F64 => {
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7fff_ffff_ffff_ffff);
|
||||||
|
ASM::mov_reg64_freg64(buf, dst_reg, src_reg);
|
||||||
|
ASM::and_reg64_reg64_reg64(buf, dst_reg, dst_reg, mask_reg);
|
||||||
|
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7ff0_0000_0000_0000);
|
||||||
|
ASM::eq_reg_reg_reg(buf, RegisterWidth::W64, dst_reg, dst_reg, mask_reg);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_num_is_finite(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>) {
|
||||||
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
let src_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src);
|
||||||
|
|
||||||
|
self.storage_manager.with_tmp_general_reg(
|
||||||
|
&mut self.buf,
|
||||||
|
|_storage_manager, buf, mask_reg| {
|
||||||
|
match *arg_layout {
|
||||||
|
Layout::F32 => {
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7f80_0000);
|
||||||
|
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg); // zero out dst reg
|
||||||
|
ASM::mov_reg32_freg32(buf, dst_reg, src_reg);
|
||||||
|
ASM::and_reg64_reg64_reg64(buf, dst_reg, dst_reg, mask_reg);
|
||||||
|
ASM::neq_reg64_reg64_reg64(
|
||||||
|
buf,
|
||||||
|
RegisterWidth::W32,
|
||||||
|
dst_reg,
|
||||||
|
dst_reg,
|
||||||
|
mask_reg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Layout::F64 => {
|
||||||
|
ASM::mov_reg64_imm64(buf, mask_reg, 0x7ff0_0000_0000_0000);
|
||||||
|
ASM::mov_reg64_freg64(buf, dst_reg, src_reg);
|
||||||
|
ASM::and_reg64_reg64_reg64(buf, dst_reg, dst_reg, mask_reg);
|
||||||
|
ASM::neq_reg64_reg64_reg64(
|
||||||
|
buf,
|
||||||
|
RegisterWidth::W64,
|
||||||
|
dst_reg,
|
||||||
|
dst_reg,
|
||||||
|
mask_reg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn build_num_lt(
|
fn build_num_lt(
|
||||||
&mut self,
|
&mut self,
|
||||||
dst: &Symbol,
|
dst: &Symbol,
|
||||||
|
|
|
@ -830,6 +830,48 @@ trait Backend<'a> {
|
||||||
);
|
);
|
||||||
self.build_num_to_frac(sym, &args[0], &arg_layouts[0], ret_layout)
|
self.build_num_to_frac(sym, &args[0], &arg_layouts[0], ret_layout)
|
||||||
}
|
}
|
||||||
|
LowLevel::NumIsNan => {
|
||||||
|
debug_assert_eq!(
|
||||||
|
1,
|
||||||
|
args.len(),
|
||||||
|
"NumIsNan: expected to have exactly one argument"
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
Layout::BOOL,
|
||||||
|
*ret_layout,
|
||||||
|
"NumIsNan: expected to have return layout of type Bool"
|
||||||
|
);
|
||||||
|
self.build_num_is_nan(sym, &args[0], &arg_layouts[0])
|
||||||
|
}
|
||||||
|
LowLevel::NumIsInfinite => {
|
||||||
|
debug_assert_eq!(
|
||||||
|
1,
|
||||||
|
args.len(),
|
||||||
|
"NumIsInfinite: expected to have exactly one argument"
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
Layout::BOOL,
|
||||||
|
*ret_layout,
|
||||||
|
"NumIsInfinite: expected to have return layout of type Bool"
|
||||||
|
);
|
||||||
|
self.build_num_is_infinite(sym, &args[0], &arg_layouts[0])
|
||||||
|
}
|
||||||
|
LowLevel::NumIsFinite => {
|
||||||
|
debug_assert_eq!(
|
||||||
|
1,
|
||||||
|
args.len(),
|
||||||
|
"NumIsFinite: expected to have exactly one argument"
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
Layout::BOOL,
|
||||||
|
*ret_layout,
|
||||||
|
"NumIsFinite: expected to have return layout of type Bool"
|
||||||
|
);
|
||||||
|
self.build_num_is_finite(sym, &args[0], &arg_layouts[0])
|
||||||
|
}
|
||||||
LowLevel::NumLte => {
|
LowLevel::NumLte => {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
2,
|
2,
|
||||||
|
@ -1477,6 +1519,15 @@ trait Backend<'a> {
|
||||||
ret_layout: &InLayout<'a>,
|
ret_layout: &InLayout<'a>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// build_num_is_nan check is a Frac is NaN
|
||||||
|
fn build_num_is_nan(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>);
|
||||||
|
|
||||||
|
/// build_num_is_infinite check is a Frac is infinite
|
||||||
|
fn build_num_is_infinite(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>);
|
||||||
|
|
||||||
|
/// build_num_is_finite check is a Frac is finite
|
||||||
|
fn build_num_is_finite(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>);
|
||||||
|
|
||||||
/// build_num_lte stores the result of `src1 <= src2` into dst.
|
/// build_num_lte stores the result of `src1 <= src2` into dst.
|
||||||
fn build_num_lte(
|
fn build_num_lte(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -1706,7 +1706,7 @@ fn float_to_float() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
fn frac_is_nan() {
|
fn frac_is_nan() {
|
||||||
assert_evals_to!("Num.isNaN (0 / 0)", true, bool);
|
assert_evals_to!("Num.isNaN (0 / 0)", true, bool);
|
||||||
assert_evals_to!("Num.isNaN (1 / 0)", false, bool);
|
assert_evals_to!("Num.isNaN (1 / 0)", false, bool);
|
||||||
|
@ -1714,7 +1714,7 @@ fn frac_is_nan() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
fn frac_is_infinite() {
|
fn frac_is_infinite() {
|
||||||
assert_evals_to!("Num.isInfinite (1 / 0)", true, bool);
|
assert_evals_to!("Num.isInfinite (1 / 0)", true, bool);
|
||||||
assert_evals_to!("Num.isInfinite (-1 / 0)", true, bool);
|
assert_evals_to!("Num.isInfinite (-1 / 0)", true, bool);
|
||||||
|
@ -1723,7 +1723,7 @@ fn frac_is_infinite() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
fn frac_is_finite() {
|
fn frac_is_finite() {
|
||||||
assert_evals_to!("Num.isFinite 42", true, bool);
|
assert_evals_to!("Num.isFinite 42", true, bool);
|
||||||
assert_evals_to!("Num.isFinite (1 / 0)", false, bool);
|
assert_evals_to!("Num.isFinite (1 / 0)", false, bool);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue