Skip to content

Commit d72276f

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

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

core/src/ecma_conversions.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,53 @@ 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+
#[cfg(target_arch = "aarch64")]
44+
#[cfg(target_feature = "jsconv")]
45+
{
46+
// macOS aarch64 always has jsconv feature
47+
// SAFETY: macOS aarch64 always supports jsconv
48+
unsafe { f64_to_wrapping_int32_arm64(n) }
49+
}
50+
#[cfg(target_arch = "aarch64")]
51+
#[cfg(not(target_feature = "jsconv"))]
52+
{
53+
if std::arch::is_aarch64_feature_detected!("jsconv") {
54+
// SAFETY: Feature detection confirmed jsconv is available
55+
unsafe { f64_to_wrapping_int32_arm64(n) }
56+
} else {
57+
f64_to_wrapping_i32_generic(n)
58+
}
59+
}
60+
#[cfg(not(target_arch = "aarch64"))]
61+
{
62+
f64_to_wrapping_i32_generic(n)
63+
}
64+
}
65+
66+
#[allow(unused)]
67+
fn f64_to_wrapping_i32_generic(n: f64) -> i32 {
4368
f64_to_wrapping_u32(n) as i32
4469
}
4570

71+
#[allow(unused)]
72+
#[cfg(target_arch = "aarch64")]
73+
#[target_feature(enable = "jsconv")]
74+
/// Converts an `f64` to an `i32` with ECMAScript `ToInt32` wrapping behavior.
75+
/// The value will be wrapped in the range [-2^31, 2^31).
76+
/// Optimized for macOS aarch64 with the fjcvtzs instruction.
77+
unsafe fn f64_to_wrapping_int32_arm64(number: f64) -> i32 {
78+
let ret: i32;
79+
// SAFETY: fjcvtzs instruction is available on macOS aarch64.
80+
unsafe {
81+
std::arch::asm!(
82+
"fjcvtzs {dst:w}, {src:d}",
83+
src = in(vreg) number,
84+
dst = out(reg) ret,
85+
);
86+
}
87+
ret
88+
}
89+
4690
/// Implements the IEEE-754 "Round to nearest, ties to even" rounding rule.
4791
/// (e.g., both 1.5 and 2.5 will round to 2).
4892
/// This also clamps out-of-range values and NaN to `i32::MIN`.

0 commit comments

Comments
 (0)