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