1 /*
2 * Copyright 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef _FENV_PORTABLE_H_
18 #define _FENV_PORTABLE_H_
19
20 #include <fenv.h>
21 #include <portability.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24
25 typedef struct {
26 unsigned char a[128];
27 } fenv_t_portable;
28 typedef uint32_t fexcept_t_portable;
29
30 /* Exception flags. */
31 #define FE_INVALID_PORTABLE 0x01
32 #define FE_DIVBYZERO_PORTABLE 0x02
33 #define FE_OVERFLOW_PORTABLE 0x04
34 #define FE_UNDERFLOW_PORTABLE 0x08
35 #define FE_INEXACT_PORTABLE 0x10
36 #define FE_ALL_EXCEPT_PORTABLE (FE_DIVBYZERO_PORTABLE | FE_INEXACT_PORTABLE | FE_INVALID_PORTABLE |\
37 FE_OVERFLOW_PORTABLE | FE_UNDERFLOW_PORTABLE)
38
39 /* Rounding modes. */
40 #define FE_TONEAREST_PORTABLE 0x0
41 #define FE_UPWARD_PORTABLE 0x1
42 #define FE_DOWNWARD_PORTABLE 0x2
43 #define FE_TOWARDZERO_PORTABLE 0x3
44
45
target_change_except(int flags)46 static inline int target_change_except(int flags)
47 {
48 int targetflags = 0;
49
50 if (flags & FE_INVALID_PORTABLE)
51 targetflags |= FE_INVALID;
52 if (flags & FE_DIVBYZERO_PORTABLE)
53 targetflags |= FE_DIVBYZERO;
54 if (flags & FE_OVERFLOW_PORTABLE)
55 targetflags |= FE_OVERFLOW;
56 if (flags & FE_UNDERFLOW_PORTABLE)
57 targetflags |= FE_UNDERFLOW;
58 if (flags & FE_INEXACT_PORTABLE)
59 targetflags |= FE_INEXACT;
60
61 return targetflags;
62 }
63
target_change_rounding(int flags)64 static inline int target_change_rounding(int flags)
65 {
66 int targetflags = 0;
67
68 switch(flags)
69 {
70 case FE_TONEAREST_PORTABLE:
71 targetflags = FE_TONEAREST;
72 break;
73 case FE_DOWNWARD_PORTABLE:
74 targetflags = FE_DOWNWARD;
75 break;
76 case FE_UPWARD_PORTABLE:
77 targetflags = FE_UPWARD;
78 break;
79 case FE_TOWARDZERO_PORTABLE:
80 targetflags = FE_TOWARDZERO;
81 break;
82 }
83 return targetflags;
84 }
85
target_get_except(int targetflags)86 static inline int target_get_except(int targetflags)
87 {
88 int flags = 0;
89
90 if (targetflags & FE_INVALID)
91 flags |= FE_INVALID_PORTABLE;
92 if (targetflags & FE_DIVBYZERO)
93 flags |= FE_DIVBYZERO_PORTABLE;
94 if (targetflags & FE_OVERFLOW)
95 flags |= FE_OVERFLOW_PORTABLE;
96 if (targetflags & FE_UNDERFLOW)
97 flags |= FE_UNDERFLOW_PORTABLE;
98 if (targetflags & FE_INEXACT)
99 flags |= FE_INEXACT_PORTABLE;
100 return flags;
101 }
102
target_get_rounding(int targetflags)103 static inline int target_get_rounding(int targetflags)
104 {
105 int flags = 0;
106
107 switch(targetflags)
108 {
109 case FE_TONEAREST:
110 flags = FE_TONEAREST_PORTABLE;
111 break;
112 case FE_DOWNWARD:
113 flags = FE_DOWNWARD_PORTABLE;
114 break;
115 case FE_UPWARD:
116 flags = FE_UPWARD_PORTABLE;
117 break;
118 case FE_TOWARDZERO:
119 flags = FE_TOWARDZERO_PORTABLE;
120 break;
121 }
122 return flags;
123 }
124
125
WRAP(fegetenv)126 int WRAP(fegetenv)(fenv_t_portable* __envp) {
127 return REAL(fegetenv)((fenv_t*) __envp);
128 }
129
WRAP(fesetenv)130 int WRAP(fesetenv)(const fenv_t_portable* __envp) {
131 return REAL(fesetenv)((fenv_t*) __envp);
132 }
133
WRAP(feclearexcept)134 int WRAP(feclearexcept)(int __excepts) {
135 __excepts = target_change_except(__excepts);
136 return REAL(feclearexcept)(__excepts);
137 }
138
WRAP(fegetexceptflag)139 int WRAP(fegetexceptflag)(fexcept_t_portable* __flagp, int __excepts) {
140 __excepts = target_change_except(__excepts);
141 int ret = REAL(fegetexceptflag)((fexcept_t*) __flagp, __excepts);
142 *__flagp = target_get_except(*__flagp);
143 return ret;
144 }
145
WRAP(fesetexceptflag)146 int WRAP(fesetexceptflag)(const fexcept_t_portable* __flagp, int __excepts) {
147 __excepts = target_change_except(__excepts);
148 return REAL(fesetexceptflag)((const fexcept_t*) __flagp, __excepts);
149 }
150
WRAP(feraiseexcept)151 int WRAP(feraiseexcept)(int __excepts) {
152 __excepts = target_change_except(__excepts);
153 return REAL(feraiseexcept)(__excepts);
154 }
155
WRAP(fetestexcept)156 int WRAP(fetestexcept)(int __excepts) {
157 __excepts = target_change_except(__excepts);
158 return target_get_except(REAL(fetestexcept)(__excepts));
159 }
160
WRAP(fegetround)161 int WRAP(fegetround)(void) {
162 int rounding = REAL(fegetround)();
163 return target_get_rounding(rounding);
164 }
165
WRAP(fesetround)166 int WRAP(fesetround)(int __round) {
167 __round = target_change_rounding(__round);
168 return REAL(fesetround)(__round);
169 }
170
WRAP(feholdexcept)171 int WRAP(feholdexcept)(fenv_t_portable* __envp) {
172 memset(__envp, '\0', sizeof(fenv_t_portable));
173 fenv_t env;
174 int ret = REAL(feholdexcept)(&env);
175 memcpy(__envp, &env, sizeof(env));
176 return ret;
177 }
178
WRAP(feupdateenv)179 int WRAP(feupdateenv)(const fenv_t_portable* __envp) {
180 fenv_t env;
181 memcpy(&env, __envp, sizeof(env));
182 return REAL(feupdateenv)(&env);
183 }
184
WRAP(feenableexcept)185 int WRAP(feenableexcept)(int __excepts) {
186 __excepts = target_change_except(__excepts);
187 return REAL(feenableexcept)(__excepts);
188 }
189
WRAP(fedisableexcept)190 int WRAP(fedisableexcept)(int __excepts) {
191 __excepts = target_change_except(__excepts);
192 return REAL(fedisableexcept)(__excepts);
193 }
194
195 #endif /* _FENV_PORTABLE_H_ */
196