Skip to content

Commit 2a29337

Browse files
committed
core: Add ARM64 FJCVTZS instruction optimization for f64 to i32
1 parent 7ab3548 commit 2a29337

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

core/src/ecma_conversions.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,57 @@ pub fn f64_to_wrapping_u32(n: f64) -> u32 {
4040
/// Converts an `f64` to an `i32` with ECMAScript `ToInt32` wrapping behavior.
4141
/// The value will be wrapped in the range [-2^31, 2^31).
4242
pub fn f64_to_wrapping_i32(n: f64) -> i32 {
43+
// TODO: use core intrinsic when https://github.com/rust-lang/rust/issues/147555 is stabilized.
44+
#[cfg(target_arch = "aarch64")]
45+
{
46+
#[cfg(target_feature = "jsconv")]
47+
// SAFETY: `jsconv` feature is checked in compile time to be existed, so it's safe to call.
48+
unsafe {
49+
f64_to_wrapping_int32_aarch64(n)
50+
}
51+
#[cfg(not(target_feature = "jsconv"))]
52+
if std::arch::is_aarch64_feature_detected!("jsconv") {
53+
// SAFETY: `jsconv` feature is checked in runtime to be existed, so it's safe to call.
54+
unsafe { f64_to_wrapping_int32_aarch64(n) }
55+
} else {
56+
f64_to_wrapping_i32_generic(n)
57+
}
58+
}
59+
#[cfg(not(target_arch = "aarch64"))]
60+
f64_to_wrapping_i32_generic(n)
61+
}
62+
63+
#[allow(unused)]
64+
fn f64_to_wrapping_i32_generic(n: f64) -> i32 {
4365
f64_to_wrapping_u32(n) as i32
4466
}
4567

68+
/// Converts an `f64` to an `i32` with ECMAScript `ToInt32` wrapping behavior.
69+
/// The value will be wrapped in the range [-2^31, 2^31).
70+
/// Optimized for aarch64 cpu with the fjcvtzs instruction.
71+
///
72+
/// # Safety
73+
///
74+
/// The caller must ensure either:
75+
/// - The target platform is aarch64 with `jsconv` feature enabled, or
76+
/// - Runtime feature detection has been performed to verify `jsconv` support
77+
#[allow(unused)]
78+
#[cfg(target_arch = "aarch64")]
79+
#[target_feature(enable = "jsconv")]
80+
unsafe fn f64_to_wrapping_int32_aarch64(number: f64) -> i32 {
81+
let ret: i32;
82+
// SAFETY: fjcvtzs instruction is available under jsconv feature.
83+
unsafe {
84+
std::arch::asm!(
85+
"fjcvtzs {dst:w}, {src:d}",
86+
src = in(vreg) number,
87+
dst = out(reg) ret,
88+
options(nostack, nomem, pure)
89+
);
90+
}
91+
ret
92+
}
93+
4694
/// Implements the IEEE-754 "Round to nearest, ties to even" rounding rule.
4795
/// (e.g., both 1.5 and 2.5 will round to 2).
4896
/// This also clamps out-of-range values and NaN to `i32::MIN`.

0 commit comments

Comments
 (0)