blob: 8896804b5040333d06b77daa16ea48dbd917aad1 [file] [log] [blame]
//! Architecture-specific support for aarch64 with neon.
use core::arch::asm;
pub fn fma(mut x: f64, y: f64, z: f64) -> f64 {
// SAFETY: `fmadd` is available with neon and has no side effects.
unsafe {
asm!(
"fmadd {x:d}, {x:d}, {y:d}, {z:d}",
x = inout(vreg) x,
y = in(vreg) y,
z = in(vreg) z,
options(nomem, nostack, pure)
);
}
x
}
pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 {
// SAFETY: `fmadd` is available with neon and has no side effects.
unsafe {
asm!(
"fmadd {x:s}, {x:s}, {y:s}, {z:s}",
x = inout(vreg) x,
y = in(vreg) y,
z = in(vreg) z,
options(nomem, nostack, pure)
);
}
x
}
// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM
// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the
// side-effect-free `frintn`.
//
// In general, C code that calls Rust's libm should assume that fpenv is ignored.
pub fn rint(mut x: f64) -> f64 {
// SAFETY: `frintn` is available with neon and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:d}, {x:d}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn rintf(mut x: f32) -> f32 {
// SAFETY: `frintn` is available with neon and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:s}, {x:s}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
#[cfg(all(f16_enabled, target_feature = "fp16"))]
pub fn rintf16(mut x: f16) -> f16 {
// SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects.
//
// `frintn` is always round-to-nearest which does not match the C specification, but Rust does
// not support rounding modes.
unsafe {
asm!(
"frintn {x:h}, {x:h}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn sqrt(mut x: f64) -> f64 {
// SAFETY: `fsqrt` is available with neon and has no side effects.
unsafe {
asm!(
"fsqrt {x:d}, {x:d}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
pub fn sqrtf(mut x: f32) -> f32 {
// SAFETY: `fsqrt` is available with neon and has no side effects.
unsafe {
asm!(
"fsqrt {x:s}, {x:s}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}
#[cfg(all(f16_enabled, target_feature = "fp16"))]
pub fn sqrtf16(mut x: f16) -> f16 {
// SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no
// side effects.
unsafe {
asm!(
"fsqrt {x:h}, {x:h}",
x = inout(vreg) x,
options(nomem, nostack, pure)
);
}
x
}