Skip to content

Commit 9f57c21

Browse files
CrazyboyQCDkjarosh
authored andcommitted
core: Add ARM64 FJCVTZS instruction optimization for f64 to i32
1 parent b33e449 commit 9f57c21

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

core/src/ecma_conversions.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,51 @@ 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+
if std::arch::is_aarch64_feature_detected!("jsconv") {
47+
// SAFETY: `jsconv` feature is checked in both compile time and runtime to be existed, so it's safe to call.
48+
unsafe { f64_to_wrapping_int32_aarch64(n) }
49+
} else {
50+
f64_to_wrapping_i32_generic(n)
51+
}
52+
}
53+
#[cfg(not(target_arch = "aarch64"))]
54+
f64_to_wrapping_i32_generic(n)
55+
}
56+
57+
#[allow(unused)]
58+
fn f64_to_wrapping_i32_generic(n: f64) -> i32 {
4359
f64_to_wrapping_u32(n) as i32
4460
}
4561

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

0 commit comments

Comments
 (0)