Skip to content

Commit

Permalink
Add fjcvtzs instruction for ARMv8.3 target (#4084)
Browse files Browse the repository at this point in the history
* feature: add fjcvtzs instruction for `ARMv8.3` target

* Add a test for various edge cases.

---------

Co-authored-by: Hans Larsen <[email protected]>
  • Loading branch information
CrazyboyQCD and hansl authored Dec 13, 2024
1 parent 4cc816f commit 6f2dca8
Showing 1 changed file with 46 additions and 0 deletions.
46 changes: 46 additions & 0 deletions core/engine/src/builtins/number/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
///
/// [ToInt32]: https://tc39.es/ecma262/#sec-toint32
#[allow(clippy::float_cmp)]
#[cfg(not(all(target_arch = "aarch64", target_feature = "jsconv")))]
pub(crate) fn f64_to_int32(number: f64) -> i32 {
const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
const EXPONENT_MASK: u64 = 0x7FF0_0000_0000_0000;
Expand Down Expand Up @@ -72,9 +73,54 @@ pub(crate) fn f64_to_int32(number: f64) -> i32 {
(sign(number) * (bits as i64)) as i32
}

/// Converts a 64-bit floating point number to an `i32` using [`FJCVTZS`][FJCVTZS] instruction on `ARMv8.3`.
///
/// [FJCVTZS]: https://developer.arm.com/documentation/dui0801/h/A64-Floating-point-Instructions/FJCVTZS
#[cfg(all(target_arch = "aarch64", target_feature = "jsconv"))]
pub(crate) fn f64_to_int32(number: f64) -> i32 {
if number.is_nan() {
return 0;
}
let ret: i32;
// SAFETY: Number is not nan so no floating-point exception should throw.
unsafe {
std::arch::asm!(
"fjcvtzs {dst:w}, {src:d}",
src = in(vreg) number,
dst = out(reg) ret,
)
}
ret
}

/// Converts a 64-bit floating point number to an `i32` using [`FJCVTZS`][FJCVTZS] instruction on `ARMv8.3`.
///
/// [FJCVTZS]: https://developer.arm.com/documentation/dui0801/h/A64-Floating-point-Instructions/FJCVTZS
#[cfg(all(target_arch = "aarch64", target_feature = "jsconv"))]
pub(crate) fn f64_to_uint32(number: f64) -> u32 {
f64_to_int32(number) as u32
}

/// Converts a 64-bit floating point number to an `u32` according to the [`ToUint32`][ToUint32] algorithm.
///
/// [ToUint32]: https://tc39.es/ecma262/#sec-touint32
#[cfg(not(all(target_arch = "aarch64", target_feature = "jsconv")))]
pub(crate) fn f64_to_uint32(number: f64) -> u32 {
f64_to_int32(number) as u32
}

#[test]
fn f64_to_int32_conversion() {
use crate::builtins::Number;

assert_eq!(f64_to_int32(0.0), 0);
assert_eq!(f64_to_int32(-0.0), 0);
assert_eq!(f64_to_int32(f64::NAN), 0);
assert_eq!(f64_to_int32(f64::INFINITY), 0);
assert_eq!(f64_to_int32(f64::NEG_INFINITY), 0);
assert_eq!(f64_to_int32((i64::from(i32::MAX) + 1) as f64), i32::MIN);
assert_eq!(f64_to_int32((i64::from(i32::MIN) - 1) as f64), i32::MAX);

assert_eq!(f64_to_int32(Number::MAX_SAFE_INTEGER + 1.0), 0);
assert_eq!(f64_to_int32(Number::MIN_SAFE_INTEGER - 1.0), 0);
}

0 comments on commit 6f2dca8

Please sign in to comment.