Import Upstream version 20180207
[hcoop/debian/mlton.git] / runtime / basis / Real / IEEEReal.c
1 #include "platform.h"
2
3 #if !HAS_FEROUND
4
5 #if (defined __i386__) || (defined __x86_64__)
6
7 /* Macros for accessing the hardware control word. */
8 #define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw))
9 #define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw))
10 #define _SSE_GETCSR(csr) __asm__ ("stmxcsr %0" : "=m" (*&csr))
11 #define _SSE_SETCSR(csr) __asm__ ("ldmxcsr %0" : : "m" (*&csr))
12
13 #define FPU_ROUNDING_CONTROL_MASK 0x0C00
14 #define FPU_ROUNDING_CONTROL_SHIFT 10
15 #define SSE_ROUNDING_CONTROL_MASK 0x00006000
16 #define SSE_ROUNDING_CONTROL_SHIFT 13
17
18 static inline C_Int_t fegetround (void) {
19 uint16_t fpuControl;
20
21 _FPU_GETCW (fpuControl);
22 return (fpuControl & FPU_ROUNDING_CONTROL_MASK)
23 >> FPU_ROUNDING_CONTROL_SHIFT;
24 }
25
26 static inline C_Int_t fesetround (C_Int_t mode) {
27 uint16_t fpuControl;
28 #ifdef __x86_64__
29 uint32_t sseControl;
30 #endif
31
32 _FPU_GETCW (fpuControl);
33 fpuControl &= ~FPU_ROUNDING_CONTROL_MASK;
34 fpuControl |= mode << FPU_ROUNDING_CONTROL_SHIFT;
35 _FPU_SETCW (fpuControl);
36
37 #ifdef __x86_64__
38 _SSE_GETCSR (sseControl);
39 sseControl &= ~SSE_ROUNDING_CONTROL_MASK;
40 sseControl |= mode << SSE_ROUNDING_CONTROL_SHIFT;
41 _SSE_SETCSR (sseControl);
42 #endif
43 return 0;
44 }
45
46 #elif (defined __UCLIBC__)
47
48 /* Use whatever we got from fpu_control.h for this CPU model */
49 #define FE_MASK (FE_DOWNWARD|FE_TONEAREST|FE_TOWARDZERO|FE_UPWARD)
50
51 static inline int fegetround () {
52 fpu_control_t controlWord;
53 _FPU_GETCW(controlWord);
54 return controlWord & FE_MASK;
55 }
56
57 static inline int fesetround (int mode) {
58 fpu_control_t controlWord;
59
60 _FPU_GETCW (controlWord);
61 controlWord = (controlWord & ~FE_MASK) | mode;
62 _FPU_SETCW (controlWord);
63 return 0;
64 }
65
66
67 #else
68
69 #error fe{get,set}round not implemented
70
71 #endif
72
73 #endif /* !HAS_FEROUND */
74
75 C_Int_t IEEEReal_getRoundingMode (void) {
76 return fegetround ();
77 }
78
79 C_Int_t IEEEReal_setRoundingMode (C_Int_t m) {
80 assert (m != IEEEReal_RoundingMode_FE_NOSUPPORT);
81 return fesetround (m);
82 }