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 18 #include <portability.h> 19 20 #include <sys/cdefs.h> 21 #include <sys/types.h> 22 #include <fenv.h> 23 #include <fenv_portable.h> 24 25 #ifndef _ROUND_MASK 26 #define FE_TONEAREST 0x0000 27 #define FE_DOWNWARD 0x0400 28 #define FE_UPWARD 0x0800 29 #define FE_TOWARDZERO 0x0c00 30 #define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 31 FE_UPWARD | FE_TOWARDZERO) 32 #endif 33 34 static inline int x86_64_change_except(int flag) { 35 int x86_64flag = 0; 36 int exception = flag & FE_ALL_EXCEPT_PORTABLE; 37 38 if (exception & FE_INVALID_PORTABLE) 39 x86_64flag |= FE_INVALID; 40 if (exception & FE_DIVBYZERO_PORTABLE) 41 x86_64flag |= FE_DIVBYZERO; 42 if (exception & FE_OVERFLOW_PORTABLE) 43 x86_64flag |= FE_OVERFLOW; 44 if (exception & FE_UNDERFLOW_PORTABLE) 45 x86_64flag |= FE_UNDERFLOW; 46 if (exception & FE_INEXACT_PORTABLE) 47 x86_64flag |= FE_INEXACT; 48 49 return x86_64flag; 50 } 51 52 static inline int x86_64_change_rounding(int flag) { 53 int x86_64flag = 0; 54 int rounding = flag & 0x03; 55 56 switch(rounding) { 57 case FE_TONEAREST_PORTABLE: { 58 x86_64flag = FE_TONEAREST; 59 break; 60 } 61 case FE_DOWNWARD_PORTABLE: { 62 x86_64flag = FE_DOWNWARD; 63 break; 64 } 65 case FE_UPWARD_PORTABLE: { 66 x86_64flag = FE_UPWARD; 67 break; 68 } 69 case FE_TOWARDZERO_PORTABLE: { 70 x86_64flag = FE_TOWARDZERO; 71 break; 72 } 73 } 74 75 return x86_64flag; 76 } 77 78 static inline int x86_64_get_except(int x86_64flag) { 79 int flag = 0; 80 int exception = x86_64flag & FE_ALL_EXCEPT; 81 82 if (exception & FE_INVALID) 83 flag |= FE_INVALID_PORTABLE; 84 if (exception & FE_DIVBYZERO) 85 flag |= FE_DIVBYZERO_PORTABLE; 86 if (exception & FE_OVERFLOW) 87 flag |= FE_OVERFLOW_PORTABLE; 88 if (exception & FE_UNDERFLOW) 89 flag |= FE_UNDERFLOW_PORTABLE; 90 if (exception & FE_INEXACT) 91 flag |= FE_INEXACT_PORTABLE; 92 93 return flag; 94 } 95 96 static inline int x86_64_get_rounding(int x86_64flag) { 97 int flag = 0; 98 int rounding = x86_64flag & _ROUND_MASK; 99 100 switch(rounding) { 101 case FE_TONEAREST: { 102 flag = FE_TONEAREST_PORTABLE; 103 break; 104 } 105 case FE_DOWNWARD: { 106 flag = FE_DOWNWARD_PORTABLE; 107 break; 108 } 109 case FE_UPWARD: { 110 flag = FE_UPWARD_PORTABLE; 111 break; 112 } 113 case FE_TOWARDZERO: { 114 flag = FE_TOWARDZERO_PORTABLE; 115 break; 116 } 117 } 118 119 return flag; 120 } 121 122 123 int WRAP(feclearexcept)(int flag) { 124 return REAL(feclearexcept)(x86_64_change_except(flag)); 125 } 126 127 #ifdef __LP64__ 128 int WRAP(fegetexceptflag)(fexcept_t_portable *obj, int flag) { 129 int ret = REAL(fegetexceptflag)((fexcept_t*)obj, x86_64_change_except(flag)); 130 *obj = (fexcept_t_portable) x86_64_get_except(*obj); 131 return ret; 132 } 133 134 int WRAP(fesetexceptflag)(const fexcept_t_portable *obj, int flag) { 135 const fexcept_t x86_64obj = x86_64_change_except(*obj); 136 int x86_64flag = x86_64_change_except(flag); 137 return REAL(fesetexceptflag)(&x86_64obj, x86_64flag); 138 } 139 #endif 140 141 int WRAP(feraiseexcept)(int flag) { 142 return REAL(feraiseexcept)(x86_64_change_except(flag)); 143 } 144 145 146 int WRAP(fetestexcept)(int flag) { 147 int ret = REAL(fetestexcept)(x86_64_change_except(flag)); 148 return x86_64_get_except(ret); 149 } 150 151 int WRAP(fegetround)(void) { 152 int round = REAL(fegetround)(); 153 return x86_64_get_rounding(round); 154 } 155 156 int WRAP(fesetround)(int round) { 157 return REAL(fesetround)(x86_64_change_rounding(round)); 158 } 159 160 #ifdef __LP64__ 161 int WRAP(fegetenv)(fenv_t_portable *obj) { 162 return REAL(fegetenv)((fenv_t*)obj); 163 } 164 165 int WRAP(feholdexcept)(fenv_t_portable *obj) { 166 return REAL(feholdexcept)((fenv_t*)obj); 167 } 168 169 int WRAP(fesetenv)(const fenv_t_portable *obj) { 170 return REAL(fesetenv)((const fenv_t*)obj); 171 } 172 173 int WRAP(feupdateenv)(const fenv_t_portable *obj) { 174 return REAL(feupdateenv)((const fenv_t*)obj); 175 } 176 #endif 177 178 int WRAP(fegetexcept)(void) { 179 int flag = REAL(fegetexcept)(); 180 return x86_64_get_except(flag); 181 } 182 183