1#[cfg(target_arch = "x86_64")]
2pub type fexcept_t = u16;
3
4#[cfg(target_arch = "aarch64")]
5pub type fexcept_t = u32;
6
7#[cfg(target_arch = "x86_64")]
9#[repr(C)]
10pub struct fenv_t {
11 __x87_env: [u8; 28],
12 __mxcsr: u32,
13}
14
15#[cfg(target_arch = "aarch64")]
16#[repr(C)]
17pub struct fenv_t {
18 __fpcr: u32,
19 __fpsr: u32,
20}
21
22#[cfg(target_arch = "x86_64")]
23const FE_DFL_ENV: *const fenv_t = -1isize as *const fenv_t;
24#[cfg(target_arch = "aarch64")]
25const FE_DFL_ENV: *const fenv_t = -1isize as *const fenv_t;
26
27#[cfg(target_arch = "x86_64")]
28mod feconst {
29 use super::*;
30 pub const FE_INVALID: c_int = 1;
31 pub const FE_DIVBYZERO: c_int = 4;
32 pub const FE_OVERFLOW: c_int = 8;
33 pub const FE_UNDERFLOW: c_int = 16;
34 pub const FE_INEXACT: c_int = 32;
35 pub const FE_ALL_EXCEPT: c_int = 63;
36
37 pub const FE_TONEAREST: c_int = 0;
38 pub const FE_DOWNWARD: c_int = 0x400;
39 pub const FE_UPWARD: c_int = 0x800;
40 pub const FE_TOWARDZERO: c_int = 0xc00;
41}
42
43#[cfg(target_arch = "aarch64")]
44mod feconst {
45 use super::*;
46 pub const FE_INVALID: c_int = 1;
47 pub const FE_DIVBYZERO: c_int = 2;
48 pub const FE_OVERFLOW: c_int = 4;
49 pub const FE_UNDERFLOW: c_int = 8;
50 pub const FE_INEXACT: c_int = 16;
51 pub const FE_ALL_EXCEPT: c_int = 31;
52
53 pub const FE_TONEAREST: c_int = 0;
54 pub const FE_DOWNWARD: c_int = 0x800000;
55 pub const FE_UPWARD: c_int = 0x400000;
56 pub const FE_TOWARDZERO: c_int = 0xc00000;
57}
58
59use feconst::*;
60
61#[cfg(target_arch = "x86_64")]
63mod x86_64_imp {
64 use super::*;
65
66 const DEFAULT_X87_ENV: [u8; 28] = {
68 let mut env = [0u8; 28];
69 env[0] = 0x7f;
70 env[1] = 0x03;
71 env[8] = 0xff;
72 env[9] = 0xff;
73 env
74 };
75 const DEFAULT_MXCSR: u32 = 0x1f80;
76
77 #[no_mangle]
79 pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int {
80 let mask = excepts & 0x3f;
81 let sw: u16;
82 core::arch::asm!("fnstsw ax", out("ax") sw);
83 if (sw as c_int) & mask != 0 {
84 core::arch::asm!("fnclex");
85 }
86 let mut mxcsr: u32 = 0;
87 let p = &mut mxcsr as *mut u32;
88 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
89 let mxcsr_val = core::ptr::read(p) | ((sw as u32) & 0x3f);
90 if mxcsr_val & (mask as u32) != 0 {
91 core::ptr::write(p, mxcsr_val & !(mask as u32));
92 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
93 }
94 0
95 }
96
97 #[no_mangle]
98 pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int {
99 let mask = (excepts & 0x3f) as u32;
100 let mut mxcsr: u32 = 0;
101 let p = &mut mxcsr as *mut u32;
102 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
103 core::ptr::write(p, core::ptr::read(p) | mask);
104 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
105 0
106 }
107
108 #[no_mangle]
109 pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int {
110 let mask = excepts & 0x3f;
111 let mut mxcsr: u32 = 0;
112 let p = &mut mxcsr as *mut u32;
113 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
114 let sw: u16;
115 core::arch::asm!("fnstsw ax", out("ax") sw);
116 ((sw as c_int) | (core::ptr::read(p) as c_int)) & mask
117 }
118
119 #[no_mangle]
120 pub unsafe extern "C" fn fegetround() -> c_int {
121 let mut mxcsr: u32 = 0;
122 let p = &mut mxcsr as *mut u32;
123 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
124 ((core::ptr::read(p) >> 3) & 0xc00) as c_int
126 }
127
128 #[no_mangle]
129 pub unsafe extern "C" fn fesetround(r: c_int) -> c_int {
130 if r != FE_TONEAREST && r != FE_DOWNWARD && r != FE_UPWARD && r != FE_TOWARDZERO {
131 return -1;
132 }
133 let mut cw: u16 = 0;
134 let p_cw = &mut cw as *mut u16;
135 core::arch::asm!("fnstcw [{p}]", p = in(reg) p_cw);
136 core::ptr::write(p_cw, (core::ptr::read(p_cw) & 0xf3ff) | (r as u16 & 0x0c00));
137 core::arch::asm!("fldcw [{p}]", p = in(reg) p_cw);
138
139 let mut mxcsr: u32 = 0;
140 let p_mx = &mut mxcsr as *mut u32;
141 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p_mx);
142 core::ptr::write(p_mx, (core::ptr::read(p_mx) & 0xffff9fff) | ((r as u32 & 0xc00) << 3));
143 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p_mx);
144 0
145 }
146
147 #[no_mangle]
148 pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int {
149 core::arch::asm!("fnstenv [{p}]", p = in(reg) envp);
150 let mxcsr_p = (envp as *mut u8).add(28) as *mut u32;
151 core::arch::asm!("stmxcsr [{p}]", p = in(reg) mxcsr_p);
152 0
153 }
154
155 #[no_mangle]
156 pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int {
157 if envp == FE_DFL_ENV {
158 core::arch::asm!("fldenv [{p}]", p = in(reg) DEFAULT_X87_ENV.as_ptr());
159 let p = &DEFAULT_MXCSR as *const u32;
160 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
161 } else {
162 core::arch::asm!("fldenv [{p}]", p = in(reg) envp);
163 let mxcsr_p = (envp as *const u8).add(28) as *const u32;
164 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) mxcsr_p);
165 }
166 0
167 }
168}
169
170#[cfg(target_arch = "x86_64")]
171use x86_64_imp::*;
172
173#[cfg(target_arch = "aarch64")]
175mod aarch64_imp {
176 use super::*;
177
178 #[no_mangle]
179 pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int {
180 let mask = (excepts & 0x1f) as u64;
181 let mut fpsr: u64;
182 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
183 let new_fpsr = fpsr & !mask;
184 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) new_fpsr);
185 0
186 }
187
188 #[no_mangle]
189 pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int {
190 let mask = (excepts & 0x1f) as u64;
191 let mut fpsr: u64;
192 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
193 let new_fpsr = fpsr | mask;
194 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) new_fpsr);
195 0
196 }
197
198 #[no_mangle]
199 pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int {
200 let mask = (excepts & 0x1f) as u64;
201 let mut fpsr: u64;
202 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
203 (fpsr & mask) as c_int
204 }
205
206 #[no_mangle]
207 pub unsafe extern "C" fn fegetround() -> c_int {
208 let mut fpcr: u64;
209 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
210 (fpcr as c_int) & 0xc00000
211 }
212
213 #[no_mangle]
214 pub unsafe extern "C" fn fesetround(r: c_int) -> c_int {
215 if r != FE_TONEAREST && r != FE_DOWNWARD && r != FE_UPWARD && r != FE_TOWARDZERO {
216 return -1;
217 }
218 let mut fpcr: u64;
219 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
220 let new_fpcr = (fpcr & !0xc00000u64) | ((r as u64) & 0xc00000);
221 core::arch::asm!("msr fpcr, {fpcr}", fpcr = in(reg) new_fpcr);
222 0
223 }
224
225 #[no_mangle]
226 pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int {
227 let mut fpcr: u64;
228 let mut fpsr: u64;
229 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
230 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
231 (*envp).__fpcr = fpcr as u32;
232 (*envp).__fpsr = fpsr as u32;
233 0
234 }
235
236 #[no_mangle]
237 pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int {
238 let (fpcr, fpsr) = if envp == FE_DFL_ENV {
239 (0u64, 0u64)
240 } else {
241 ((*envp).__fpcr as u64, (*envp).__fpsr as u64)
242 };
243 core::arch::asm!("msr fpcr, {fpcr}", fpcr = in(reg) fpcr);
244 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) fpsr);
245 0
246 }
247}
248
249#[cfg(target_arch = "aarch64")]
250use aarch64_imp::*;
251
252#[no_mangle]
253pub unsafe extern "C" fn fegetexceptflag(fp: *mut fexcept_t, mask: c_int) -> c_int {
254 *fp = fetestexcept(mask) as fexcept_t;
255 0
256}
257
258#[no_mangle]
259pub unsafe extern "C" fn fesetexceptflag(fp: *const fexcept_t, mask: c_int) -> c_int {
260 let flags = *fp as c_int;
261 feclearexcept((!flags) & mask);
262 feraiseexcept(flags & mask);
263 0
264}
265
266#[no_mangle]
267pub unsafe extern "C" fn feholdexcept(envp: *mut fenv_t) -> c_int {
268 fegetenv(envp);
269 feclearexcept(FE_ALL_EXCEPT);
270 0
271}
272
273#[no_mangle]
274pub unsafe extern "C" fn feupdateenv(envp: *const fenv_t) -> c_int {
275 let ex = fetestexcept(FE_ALL_EXCEPT);
276 fesetenv(envp);
277 feraiseexcept(ex);
278 0
279}
280
281#[no_mangle]
283pub extern "C" fn __flt_rounds() -> c_int {
284 match unsafe { fegetround() } {
285 FE_TOWARDZERO => 0,
286 FE_TONEAREST => 1,
287 FE_UPWARD => 2,
288 FE_DOWNWARD => 3,
289 _ => -1,
290 }
291}