1#[cfg(target_arch = "x86_64")]
5pub type fexcept_t = u16;
6
7#[cfg(target_arch = "aarch64")]
8pub type fexcept_t = u32;
9
10#[cfg(target_arch = "riscv64")]
11pub type fexcept_t = u32;
12
13#[cfg(target_arch = "x86_64")]
15#[repr(C)]
16pub struct fenv_t {
17 __x87_env: [u8; 28],
18 __mxcsr: u32,
19}
20
21#[cfg(target_arch = "aarch64")]
22#[repr(C)]
23pub struct fenv_t {
24 __fpcr: u32,
25 __fpsr: u32,
26}
27
28#[cfg(target_arch = "riscv64")]
29pub type fenv_t = u32;
30
31#[cfg(target_arch = "x86_64")]
32const FE_DFL_ENV: *const fenv_t = -1isize as *const fenv_t;
33#[cfg(target_arch = "aarch64")]
34const FE_DFL_ENV: *const fenv_t = -1isize as *const fenv_t;
35#[cfg(target_arch = "riscv64")]
36const FE_DFL_ENV: *const fenv_t = -1isize as *const fenv_t;
37
38#[cfg(target_arch = "x86_64")]
39mod feconst {
40 use super::*;
41 pub const FE_INVALID: c_int = 1;
42 pub const FE_DIVBYZERO: c_int = 4;
43 pub const FE_OVERFLOW: c_int = 8;
44 pub const FE_UNDERFLOW: c_int = 16;
45 pub const FE_INEXACT: c_int = 32;
46 pub const FE_ALL_EXCEPT: c_int = 63;
47
48 pub const FE_TONEAREST: c_int = 0;
49 pub const FE_DOWNWARD: c_int = 0x400;
50 pub const FE_UPWARD: c_int = 0x800;
51 pub const FE_TOWARDZERO: c_int = 0xc00;
52}
53
54#[cfg(target_arch = "aarch64")]
55mod feconst {
56 use super::*;
57 pub const FE_INVALID: c_int = 1;
58 pub const FE_DIVBYZERO: c_int = 2;
59 pub const FE_OVERFLOW: c_int = 4;
60 pub const FE_UNDERFLOW: c_int = 8;
61 pub const FE_INEXACT: c_int = 16;
62 pub const FE_ALL_EXCEPT: c_int = 31;
63
64 pub const FE_TONEAREST: c_int = 0;
65 pub const FE_DOWNWARD: c_int = 0x800000;
66 pub const FE_UPWARD: c_int = 0x400000;
67 pub const FE_TOWARDZERO: c_int = 0xc00000;
68}
69
70#[cfg(target_arch = "riscv64")]
71mod feconst {
72 use super::*;
73 pub const FE_INVALID: c_int = 16;
74 pub const FE_DIVBYZERO: c_int = 8;
75 pub const FE_OVERFLOW: c_int = 4;
76 pub const FE_UNDERFLOW: c_int = 2;
77 pub const FE_INEXACT: c_int = 1;
78 pub const FE_ALL_EXCEPT: c_int = 31;
79
80 pub const FE_TONEAREST: c_int = 0;
81 pub const FE_DOWNWARD: c_int = 2;
82 pub const FE_UPWARD: c_int = 3;
83 pub const FE_TOWARDZERO: c_int = 1;
84}
85
86use feconst::*;
87
88#[cfg(target_arch = "x86_64")]
90mod x86_64_imp {
91 use super::*;
92
93 const DEFAULT_X87_ENV: [u8; 28] = {
95 let mut env = [0u8; 28];
96 env[0] = 0x7f;
97 env[1] = 0x03;
98 env[8] = 0xff;
99 env[9] = 0xff;
100 env
101 };
102 const DEFAULT_MXCSR: u32 = 0x1f80;
103
104 #[no_mangle]
106 pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int {
107 let mask = excepts & 0x3f;
108 let sw: u16;
109 core::arch::asm!("fnstsw ax", out("ax") sw);
110 if (sw as c_int) & mask != 0 {
111 core::arch::asm!("fnclex");
112 }
113 let mut mxcsr: u32 = 0;
114 let p = &mut mxcsr as *mut u32;
115 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
116 let mxcsr_val = core::ptr::read(p) | ((sw as u32) & 0x3f);
117 if mxcsr_val & (mask as u32) != 0 {
118 core::ptr::write(p, mxcsr_val & !(mask as u32));
119 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
120 }
121 0
122 }
123
124 #[no_mangle]
125 pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int {
126 let mask = (excepts & 0x3f) as u32;
127 let mut mxcsr: u32 = 0;
128 let p = &mut mxcsr as *mut u32;
129 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
130 core::ptr::write(p, core::ptr::read(p) | mask);
131 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
132 0
133 }
134
135 #[no_mangle]
136 pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int {
137 let mask = excepts & 0x3f;
138 let mut mxcsr: u32 = 0;
139 let p = &mut mxcsr as *mut u32;
140 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
141 let sw: u16;
142 core::arch::asm!("fnstsw ax", out("ax") sw);
143 ((sw as c_int) | (core::ptr::read(p) as c_int)) & mask
144 }
145
146 #[no_mangle]
147 pub unsafe extern "C" fn fegetround() -> c_int {
148 let mut mxcsr: u32 = 0;
149 let p = &mut mxcsr as *mut u32;
150 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p);
151 ((core::ptr::read(p) >> 3) & 0xc00) as c_int
153 }
154
155 #[no_mangle]
156 pub unsafe extern "C" fn fesetround(r: c_int) -> c_int {
157 if r != FE_TONEAREST && r != FE_DOWNWARD && r != FE_UPWARD && r != FE_TOWARDZERO {
158 return -1;
159 }
160 let mut cw: u16 = 0;
161 let p_cw = &mut cw as *mut u16;
162 core::arch::asm!("fnstcw [{p}]", p = in(reg) p_cw);
163 core::ptr::write(p_cw, (core::ptr::read(p_cw) & 0xf3ff) | (r as u16 & 0x0c00));
164 core::arch::asm!("fldcw [{p}]", p = in(reg) p_cw);
165
166 let mut mxcsr: u32 = 0;
167 let p_mx = &mut mxcsr as *mut u32;
168 core::arch::asm!("stmxcsr [{p}]", p = in(reg) p_mx);
169 core::ptr::write(p_mx, (core::ptr::read(p_mx) & 0xffff9fff) | ((r as u32 & 0xc00) << 3));
170 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p_mx);
171 0
172 }
173
174 #[no_mangle]
175 pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int {
176 core::arch::asm!("fnstenv [{p}]", p = in(reg) envp);
177 let mxcsr_p = (envp as *mut u8).add(28) as *mut u32;
178 core::arch::asm!("stmxcsr [{p}]", p = in(reg) mxcsr_p);
179 0
180 }
181
182 #[no_mangle]
183 pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int {
184 if envp == FE_DFL_ENV {
185 core::arch::asm!("fldenv [{p}]", p = in(reg) DEFAULT_X87_ENV.as_ptr());
186 let p = &DEFAULT_MXCSR as *const u32;
187 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) p);
188 } else {
189 core::arch::asm!("fldenv [{p}]", p = in(reg) envp);
190 let mxcsr_p = (envp as *const u8).add(28) as *const u32;
191 core::arch::asm!("ldmxcsr [{p}]", p = in(reg) mxcsr_p);
192 }
193 0
194 }
195}
196
197#[cfg(target_arch = "x86_64")]
198use x86_64_imp::*;
199
200#[cfg(target_arch = "aarch64")]
202mod aarch64_imp {
203 use super::*;
204
205 #[no_mangle]
206 pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int {
207 let mask = (excepts & 0x1f) as u64;
208 let mut fpsr: u64;
209 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
210 let new_fpsr = fpsr & !mask;
211 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) new_fpsr);
212 0
213 }
214
215 #[no_mangle]
216 pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int {
217 let mask = (excepts & 0x1f) as u64;
218 let mut fpsr: u64;
219 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
220 let new_fpsr = fpsr | mask;
221 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) new_fpsr);
222 0
223 }
224
225 #[no_mangle]
226 pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int {
227 let mask = (excepts & 0x1f) as u64;
228 let mut fpsr: u64;
229 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
230 (fpsr & mask) as c_int
231 }
232
233 #[no_mangle]
234 pub unsafe extern "C" fn fegetround() -> c_int {
235 let mut fpcr: u64;
236 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
237 (fpcr as c_int) & 0xc00000
238 }
239
240 #[no_mangle]
241 pub unsafe extern "C" fn fesetround(r: c_int) -> c_int {
242 if r != FE_TONEAREST && r != FE_DOWNWARD && r != FE_UPWARD && r != FE_TOWARDZERO {
243 return -1;
244 }
245 let mut fpcr: u64;
246 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
247 let new_fpcr = (fpcr & !0xc00000u64) | ((r as u64) & 0xc00000);
248 core::arch::asm!("msr fpcr, {fpcr}", fpcr = in(reg) new_fpcr);
249 0
250 }
251
252 #[no_mangle]
253 pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int {
254 let mut fpcr: u64;
255 let mut fpsr: u64;
256 core::arch::asm!("mrs {fpcr}, fpcr", fpcr = out(reg) fpcr);
257 core::arch::asm!("mrs {fpsr}, fpsr", fpsr = out(reg) fpsr);
258 (*envp).__fpcr = fpcr as u32;
259 (*envp).__fpsr = fpsr as u32;
260 0
261 }
262
263 #[no_mangle]
264 pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int {
265 let (fpcr, fpsr) = if envp == FE_DFL_ENV {
266 (0u64, 0u64)
267 } else {
268 ((*envp).__fpcr as u64, (*envp).__fpsr as u64)
269 };
270 core::arch::asm!("msr fpcr, {fpcr}", fpcr = in(reg) fpcr);
271 core::arch::asm!("msr fpsr, {fpsr}", fpsr = in(reg) fpsr);
272 0
273 }
274}
275
276#[cfg(target_arch = "aarch64")]
277use aarch64_imp::*;
278
279#[cfg(target_arch = "riscv64")]
281mod riscv64_imp {
282 use super::*;
283
284 #[no_mangle]
285 pub unsafe extern "C" fn feclearexcept(excepts: c_int) -> c_int {
286 let mask = (excepts & 0x1f) as u64;
287 core::arch::asm!(
289 "csrc fflags, {mask}",
290 mask = in(reg) mask,
291 options(nostack),
292 );
293 0
294 }
295
296 #[no_mangle]
297 pub unsafe extern "C" fn feraiseexcept(excepts: c_int) -> c_int {
298 let mask = (excepts & 0x1f) as u64;
299 core::arch::asm!(
301 "csrs fflags, {mask}",
302 mask = in(reg) mask,
303 options(nostack),
304 );
305 0
306 }
307
308 #[no_mangle]
309 pub unsafe extern "C" fn fetestexcept(excepts: c_int) -> c_int {
310 let fflags: u64;
311 core::arch::asm!(
313 "frflags {fflags}",
314 fflags = out(reg) fflags,
315 options(nostack),
316 );
317 (fflags as c_int) & (excepts & 0x1f)
318 }
319
320 #[no_mangle]
321 pub unsafe extern "C" fn fegetround() -> c_int {
322 let frm: u64;
323 core::arch::asm!(
325 "frrm {frm}",
326 frm = out(reg) frm,
327 options(nostack),
328 );
329 frm as c_int
330 }
331
332 #[no_mangle]
333 pub unsafe extern "C" fn fesetround(r: c_int) -> c_int {
334 if r != FE_TONEAREST && r != FE_DOWNWARD && r != FE_UPWARD && r != FE_TOWARDZERO {
335 return -1;
336 }
337 core::arch::asm!(
339 "fsrm zero, {r}",
340 r = in(reg) r as u64,
341 options(nostack),
342 );
343 0
344 }
345
346 #[no_mangle]
347 pub unsafe extern "C" fn fegetenv(envp: *mut fenv_t) -> c_int {
348 let fcsr: u64;
349 core::arch::asm!(
351 "frcsr {fcsr}",
352 fcsr = out(reg) fcsr,
353 options(nostack),
354 );
355 *envp = fcsr as u32;
356 0
357 }
358
359 #[no_mangle]
360 pub unsafe extern "C" fn fesetenv(envp: *const fenv_t) -> c_int {
361 let val = if envp == FE_DFL_ENV {
362 0u64
363 } else {
364 *envp as u64
365 };
366 core::arch::asm!(
368 "fscsr zero, {val}",
369 val = in(reg) val,
370 options(nostack),
371 );
372 0
373 }
374}
375
376#[cfg(target_arch = "riscv64")]
377use riscv64_imp::*;
378
379#[no_mangle]
380pub unsafe extern "C" fn fegetexceptflag(fp: *mut fexcept_t, mask: c_int) -> c_int {
381 *fp = fetestexcept(mask) as fexcept_t;
382 0
383}
384
385#[no_mangle]
386pub unsafe extern "C" fn fesetexceptflag(fp: *const fexcept_t, mask: c_int) -> c_int {
387 let flags = *fp as c_int;
388 feclearexcept((!flags) & mask);
389 feraiseexcept(flags & mask);
390 0
391}
392
393#[no_mangle]
394pub unsafe extern "C" fn feholdexcept(envp: *mut fenv_t) -> c_int {
395 fegetenv(envp);
396 feclearexcept(FE_ALL_EXCEPT);
397 0
398}
399
400#[no_mangle]
401pub unsafe extern "C" fn feupdateenv(envp: *const fenv_t) -> c_int {
402 let ex = fetestexcept(FE_ALL_EXCEPT);
403 fesetenv(envp);
404 feraiseexcept(ex);
405 0
406}
407
408#[no_mangle]
410pub extern "C" fn __flt_rounds() -> c_int {
411 match unsafe { fegetround() } {
412 FE_TOWARDZERO => 0,
413 FE_TONEAREST => 1,
414 FE_UPWARD => 2,
415 FE_DOWNWARD => 3,
416 _ => -1,
417 }
418}