mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge branch 'main' into int_overflow
This commit is contained in:
commit
7866331f67
4 changed files with 88 additions and 43 deletions
|
@ -437,16 +437,16 @@ pub const RocDec = extern struct {
|
|||
const numerator_i128 = self.num;
|
||||
const denominator_i128 = other.num;
|
||||
|
||||
// (0 / n) is always 0
|
||||
if (numerator_i128 == 0) {
|
||||
return RocDec{ .num = 0 };
|
||||
}
|
||||
|
||||
// (n / 0) is an error
|
||||
if (denominator_i128 == 0) {
|
||||
roc_panic("Decimal division by 0!", 0);
|
||||
}
|
||||
|
||||
// (0 / n) is always 0
|
||||
if (numerator_i128 == 0) {
|
||||
return RocDec{ .num = 0 };
|
||||
}
|
||||
|
||||
// If they're both negative, or if neither is negative, the final answer
|
||||
// is positive or zero. If one is negative and the denominator isn't, the
|
||||
// final answer is negative (or zero, in which case final sign won't matter).
|
||||
|
|
|
@ -2116,27 +2116,34 @@ 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,
|
||||
match *arg_layout {
|
||||
Layout::F32 => {
|
||||
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, FloatWidth::F32);
|
||||
}
|
||||
Layout::F64 => {
|
||||
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, FloatWidth::F64);
|
||||
}
|
||||
Layout::DEC => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
// boolean "false"
|
||||
ASM::mov_reg64_imm64(&mut self.buf, dst_reg, 0);
|
||||
}
|
||||
_ => 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 => {
|
||||
match *arg_layout {
|
||||
Layout::F32 => {
|
||||
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| {
|
||||
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);
|
||||
|
@ -2144,46 +2151,69 @@ impl<
|
|||
|
||||
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 => {
|
||||
},
|
||||
)
|
||||
}
|
||||
Layout::F64 => {
|
||||
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| {
|
||||
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!(),
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
Layout::DEC => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
// boolean "false"
|
||||
ASM::mov_reg64_imm64(&mut self.buf, dst_reg, 0);
|
||||
}
|
||||
_ => 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 => {
|
||||
match *arg_layout {
|
||||
Layout::F32 => {
|
||||
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| {
|
||||
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_reg_reg_reg(buf, RegisterWidth::W32, dst_reg, dst_reg, mask_reg);
|
||||
}
|
||||
Layout::F64 => {
|
||||
},
|
||||
)
|
||||
}
|
||||
Layout::F64 => {
|
||||
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| {
|
||||
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_reg_reg_reg(buf, RegisterWidth::W64, dst_reg, dst_reg, mask_reg);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
Layout::DEC => {
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||
// boolean "true"
|
||||
ASM::mov_reg64_imm64(&mut self.buf, dst_reg, 1);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_int_to_float_cast(
|
||||
|
|
|
@ -2253,6 +2253,11 @@ fn build_dec_unary_op<'a, 'ctx>(
|
|||
NumFloor => dec_unary_op(env, &bitcode::DEC_FLOOR[int_width()], arg),
|
||||
NumCeiling => dec_unary_op(env, &bitcode::DEC_CEILING[int_width()], arg),
|
||||
|
||||
// return constant value bools
|
||||
NumIsFinite => env.context.bool_type().const_int(1, false).into(),
|
||||
NumIsInfinite => env.context.bool_type().const_int(0, false).into(),
|
||||
NumIsNan => env.context.bool_type().const_int(0, false).into(),
|
||||
|
||||
_ => {
|
||||
unreachable!("Unrecognized dec unary operation: {:?}", op);
|
||||
}
|
||||
|
|
|
@ -790,6 +790,13 @@ fn gen_div_checked_by_zero_dec() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic(expected = r#"Roc failed with message: "Decimal division by 0!"#)]
|
||||
fn gen_div_dec_zero_by_zero() {
|
||||
assert_evals_to!("0dec / 0", RocDec::from_str("-1").unwrap(), RocDec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
#[should_panic(expected = r#"Roc failed with message: "Decimal division by 0!"#)]
|
||||
|
@ -1809,6 +1816,7 @@ fn frac_is_nan() {
|
|||
assert_evals_to!("Num.isNaN (0 / 0f64)", true, bool);
|
||||
assert_evals_to!("Num.isNaN (1 / 0f64)", false, bool);
|
||||
assert_evals_to!("Num.isNaN 42f64", false, bool);
|
||||
assert_evals_to!("Num.isNaN 42dec", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1818,6 +1826,7 @@ fn frac_is_infinite() {
|
|||
assert_evals_to!("Num.isInfinite (-1 / 0f64)", true, bool);
|
||||
assert_evals_to!("Num.isInfinite (0 / 0f64)", false, bool);
|
||||
assert_evals_to!("Num.isInfinite 42f64", false, bool);
|
||||
assert_evals_to!("Num.isInfinite 42dec", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1826,6 +1835,7 @@ fn frac_is_finite() {
|
|||
assert_evals_to!("Num.isFinite 42f64", true, bool);
|
||||
assert_evals_to!("Num.isFinite (1 / 0f64)", false, bool);
|
||||
assert_evals_to!("Num.isFinite (0 / 0f64)", false, bool);
|
||||
assert_evals_to!("Num.isFinite 42dec", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue