1 | /* Determine floating-point rounding mode within libc. Generic version. |
2 | Copyright (C) 2012-2021 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #ifndef _GET_ROUNDING_MODE_H |
20 | #define _GET_ROUNDING_MODE_H 1 |
21 | |
22 | #include <fpu_control.h> |
23 | #include <stdlib.h> |
24 | |
25 | /* Define values for FE_* modes not defined for this architecture. */ |
26 | #ifdef FE_DOWNWARD |
27 | # define ORIG_FE_DOWNWARD FE_DOWNWARD |
28 | #else |
29 | # define ORIG_FE_DOWNWARD 0 |
30 | #endif |
31 | #ifdef FE_TONEAREST |
32 | # define ORIG_FE_TONEAREST FE_TONEAREST |
33 | #else |
34 | # define ORIG_FE_TONEAREST 0 |
35 | #endif |
36 | #ifdef FE_TOWARDZERO |
37 | # define ORIG_FE_TOWARDZERO FE_TOWARDZERO |
38 | #else |
39 | # define ORIG_FE_TOWARDZERO 0 |
40 | #endif |
41 | #ifdef FE_UPWARD |
42 | # define ORIG_FE_UPWARD FE_UPWARD |
43 | #else |
44 | # define ORIG_FE_UPWARD 0 |
45 | #endif |
46 | #define FE_CONSTRUCT_DISTINCT_VALUE(X, Y, Z) \ |
47 | ((((X) & 1) | ((Y) & 2) | ((Z) & 4)) ^ 7) |
48 | #ifndef FE_DOWNWARD |
49 | # define FE_DOWNWARD FE_CONSTRUCT_DISTINCT_VALUE (ORIG_FE_TONEAREST, \ |
50 | ORIG_FE_TOWARDZERO, \ |
51 | ORIG_FE_UPWARD) |
52 | #endif |
53 | #ifndef FE_TONEAREST |
54 | # define FE_TONEAREST FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \ |
55 | ORIG_FE_TOWARDZERO, \ |
56 | ORIG_FE_UPWARD) |
57 | #endif |
58 | #ifndef FE_TOWARDZERO |
59 | # define FE_TOWARDZERO FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \ |
60 | FE_TONEAREST, \ |
61 | ORIG_FE_UPWARD) |
62 | #endif |
63 | #ifndef FE_UPWARD |
64 | # define FE_UPWARD FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \ |
65 | FE_TONEAREST, \ |
66 | FE_TOWARDZERO) |
67 | #endif |
68 | |
69 | /* Return the floating-point rounding mode. */ |
70 | |
71 | static inline int |
72 | get_rounding_mode (void) |
73 | { |
74 | #if (defined _FPU_RC_DOWN \ |
75 | || defined _FPU_RC_NEAREST \ |
76 | || defined _FPU_RC_ZERO \ |
77 | || defined _FPU_RC_UP) |
78 | fpu_control_t fc; |
79 | const fpu_control_t mask = (0 |
80 | # ifdef _FPU_RC_DOWN |
81 | | _FPU_RC_DOWN |
82 | # endif |
83 | # ifdef _FPU_RC_NEAREST |
84 | | _FPU_RC_NEAREST |
85 | # endif |
86 | # ifdef _FPU_RC_ZERO |
87 | | _FPU_RC_ZERO |
88 | # endif |
89 | # ifdef _FPU_RC_UP |
90 | | _FPU_RC_UP |
91 | # endif |
92 | ); |
93 | |
94 | _FPU_GETCW (fc); |
95 | switch (fc & mask) |
96 | { |
97 | # ifdef _FPU_RC_DOWN |
98 | case _FPU_RC_DOWN: |
99 | return FE_DOWNWARD; |
100 | # endif |
101 | |
102 | # ifdef _FPU_RC_NEAREST |
103 | case _FPU_RC_NEAREST: |
104 | return FE_TONEAREST; |
105 | # endif |
106 | |
107 | # ifdef _FPU_RC_ZERO |
108 | case _FPU_RC_ZERO: |
109 | return FE_TOWARDZERO; |
110 | # endif |
111 | |
112 | # ifdef _FPU_RC_UP |
113 | case _FPU_RC_UP: |
114 | return FE_UPWARD; |
115 | # endif |
116 | |
117 | default: |
118 | abort (); |
119 | } |
120 | #else |
121 | return FE_TONEAREST; |
122 | #endif |
123 | } |
124 | |
125 | #endif /* get-rounding-mode.h */ |
126 | |