compiler_builtins\libm\src\math\arch/
aarch64.rs

1//! Architecture-specific support for aarch64 with neon.
2
3use core::arch::asm;
4
5pub fn fma(mut x: f64, y: f64, z: f64) -> f64 {
6    // SAFETY: `fmadd` is available with neon and has no side effects.
7    unsafe {
8        asm!(
9            "fmadd {x:d}, {x:d}, {y:d}, {z:d}",
10            x = inout(vreg) x,
11            y = in(vreg) y,
12            z = in(vreg) z,
13            options(nomem, nostack, pure)
14        );
15    }
16    x
17}
18
19pub fn fmaf(mut x: f32, y: f32, z: f32) -> f32 {
20    // SAFETY: `fmadd` is available with neon and has no side effects.
21    unsafe {
22        asm!(
23            "fmadd {x:s}, {x:s}, {y:s}, {z:s}",
24            x = inout(vreg) x,
25            y = in(vreg) y,
26            z = in(vreg) z,
27            options(nomem, nostack, pure)
28        );
29    }
30    x
31}
32
33// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM
34// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the
35// side-effect-free `frintn`.
36//
37// In general, C code that calls Rust's libm should assume that fpenv is ignored.
38
39pub fn rint(mut x: f64) -> f64 {
40    // SAFETY: `frintn` is available with neon and has no side effects.
41    //
42    // `frintn` is always round-to-nearest which does not match the C specification, but Rust does
43    // not support rounding modes.
44    unsafe {
45        asm!(
46            "frintn {x:d}, {x:d}",
47            x = inout(vreg) x,
48            options(nomem, nostack, pure)
49        );
50    }
51    x
52}
53
54pub fn rintf(mut x: f32) -> f32 {
55    // SAFETY: `frintn` is available with neon and has no side effects.
56    //
57    // `frintn` is always round-to-nearest which does not match the C specification, but Rust does
58    // not support rounding modes.
59    unsafe {
60        asm!(
61            "frintn {x:s}, {x:s}",
62            x = inout(vreg) x,
63            options(nomem, nostack, pure)
64        );
65    }
66    x
67}
68
69#[cfg(all(f16_enabled, target_feature = "fp16"))]
70pub fn rintf16(mut x: f16) -> f16 {
71    // SAFETY: `frintn` is available for `f16` with `fp16` (implies `neon`) and has no side effects.
72    //
73    // `frintn` is always round-to-nearest which does not match the C specification, but Rust does
74    // not support rounding modes.
75    unsafe {
76        asm!(
77            "frintn {x:h}, {x:h}",
78            x = inout(vreg) x,
79            options(nomem, nostack, pure)
80        );
81    }
82    x
83}
84
85pub fn sqrt(mut x: f64) -> f64 {
86    // SAFETY: `fsqrt` is available with neon and has no side effects.
87    unsafe {
88        asm!(
89            "fsqrt {x:d}, {x:d}",
90            x = inout(vreg) x,
91            options(nomem, nostack, pure)
92        );
93    }
94    x
95}
96
97pub fn sqrtf(mut x: f32) -> f32 {
98    // SAFETY: `fsqrt` is available with neon and has no side effects.
99    unsafe {
100        asm!(
101            "fsqrt {x:s}, {x:s}",
102            x = inout(vreg) x,
103            options(nomem, nostack, pure)
104        );
105    }
106    x
107}
108
109#[cfg(all(f16_enabled, target_feature = "fp16"))]
110pub fn sqrtf16(mut x: f16) -> f16 {
111    // SAFETY: `fsqrt` is available for `f16` with `fp16` (implies `neon`) and has no
112    // side effects.
113    unsafe {
114        asm!(
115            "fsqrt {x:h}, {x:h}",
116            x = inout(vreg) x,
117            options(nomem, nostack, pure)
118        );
119    }
120    x
121}