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}