-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathferoundingmode.h
66 lines (49 loc) · 1.52 KB
/
feroundingmode.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#ifndef FE_ROUNDING_MODE
#define FE_ROUNDING_MODE
// include this as a header instead of using glibc so that the compiler can
// inline these methods.
//
// Considering that interval arithmetic is required to /guarantee/ that there
// aren't issues due to floating point rounding, this gets called a lot when it
// is trying to construct a proof. The overhead of indirecting through a shared
// library function was noticeable
#if __x86_64__
// copied (and modified) from glibc source version 2.19
static inline int
inlined_fesetround (int round)
{
unsigned short int cw;
int mxcsr;
if ((round & ~0xc00) != 0)
/* ROUND is no valid rounding mode. */
return 1;
/* First set the x87 FPU. */
asm ("fnstcw %0" : "=m" (*&cw));
cw &= ~0xc00;
cw |= round;
asm ("fldcw %0" : : "m" (*&cw));
/* And now the MSCSR register for SSE, the precision is at different bit
positions in the different units, we need to shift it 3 bits. */
asm ("stmxcsr %0" : "=m" (*&mxcsr));
mxcsr &= ~ 0x6000;
mxcsr |= round << 3;
asm ("ldmxcsr %0" : : "m" (*&mxcsr));
return 0;
}
static inline int
inlined_fegetround (void)
{
int cw;
/* We only check the x87 FPU unit. The SSE unit should be the same
- and if it's not the same there's no way to signal it. */
__asm__ ("fnstcw %0" : "=m" (*&cw));
return cw & 0xc00;
}
// ensure that we don't conflict with the builtin definition
#include <fenv.h>
#define fesetround inlined_fesetround
#define fegetround inlined_fegetround
#else
#include <fenv.h>
#endif
#endif