1 /* 2 * Copyright 2013, 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 #include <portability.h> 18 #include <sys/types.h> 19 #include <fenv.h> 20 #include <fenv_portable.h> 21 22 static inline int mips_change_except(int flags) 23 { 24 int mipsflags = 0; 25 int exception = flags & FE_ALL_EXCEPT_PORTABLE; 26 27 // exception flags 28 if (exception & FE_INVALID_PORTABLE) 29 mipsflags |= FE_INVALID; 30 if (exception & FE_DIVBYZERO_PORTABLE) 31 mipsflags |= FE_DIVBYZERO; 32 if (exception & FE_OVERFLOW_PORTABLE) 33 mipsflags |= FE_OVERFLOW; 34 if (exception & FE_UNDERFLOW_PORTABLE) 35 mipsflags |= FE_UNDERFLOW; 36 if (exception & FE_INEXACT_PORTABLE) 37 mipsflags |= FE_INEXACT; 38 39 return mipsflags; 40 } 41 42 static inline int mips_change_rounding(int flags) 43 { 44 int mipsflags = 0; 45 int rounding = flags & 0x03; 46 47 // rounding flags 48 switch(rounding) 49 { 50 case FE_TONEAREST_PORTABLE: 51 mipsflags = FE_TONEAREST; 52 break; 53 case FE_DOWNWARD_PORTABLE: 54 mipsflags = FE_DOWNWARD; 55 break; 56 case FE_UPWARD_PORTABLE: 57 mipsflags = FE_UPWARD; 58 break; 59 case FE_TOWARDZERO_PORTABLE: 60 mipsflags = FE_TOWARDZERO; 61 break; 62 } 63 return mipsflags; 64 } 65 66 static inline int mips_get_except(int mipsflags) 67 { 68 int flags = 0; 69 int exception = mipsflags & FE_ALL_EXCEPT; 70 71 // exception flags 72 if (exception & FE_INVALID) 73 flags |= FE_INVALID_PORTABLE; 74 if (exception & FE_DIVBYZERO) 75 flags |= FE_DIVBYZERO_PORTABLE; 76 if (exception & FE_OVERFLOW) 77 flags |= FE_OVERFLOW_PORTABLE; 78 if (exception & FE_UNDERFLOW) 79 flags |= FE_UNDERFLOW_PORTABLE; 80 if (exception & FE_INEXACT) 81 flags |= FE_INEXACT_PORTABLE; 82 return flags; 83 } 84 85 static inline int mips_get_rounding(int mipsflags) 86 { 87 int flags = 0; 88 int rounding = mipsflags & _FCSR_RMASK; 89 90 // rounding flags 91 switch(rounding) 92 { 93 case FE_TONEAREST: 94 flags = FE_TONEAREST_PORTABLE; 95 break; 96 case FE_DOWNWARD: 97 flags = FE_DOWNWARD_PORTABLE; 98 break; 99 case FE_UPWARD: 100 flags = FE_UPWARD_PORTABLE; 101 break; 102 case FE_TOWARDZERO: 103 flags = FE_TOWARDZERO_PORTABLE; 104 break; 105 } 106 return flags; 107 } 108 109 int WRAP(fegetenv)(fenv_t* __envp) { 110 fenv_t _fcsr = 0; 111 #ifdef __mips_hard_float 112 __asm__ __volatile__("cfc1 %0,$31" : "=r" (_fcsr)); 113 #endif 114 *__envp = _fcsr; 115 return 0; 116 } 117 118 int WRAP(fesetenv)(const fenv_t* __envp) { 119 fenv_t _fcsr = *__envp; 120 #ifdef __mips_hard_float 121 __asm__ __volatile__("ctc1 %0,$31" : : "r" (_fcsr)); 122 #endif 123 return 0; 124 } 125 126 int WRAP(feclearexcept)(int __excepts) { 127 __excepts = mips_change_except(__excepts); 128 fexcept_t __fcsr; 129 WRAP(fegetenv)(&__fcsr); 130 __excepts &= FE_ALL_EXCEPT; 131 __fcsr &= ~(__excepts | (__excepts << _FCSR_CAUSE_SHIFT)); 132 WRAP(fesetenv)(&__fcsr); 133 return 0; 134 } 135 136 int WRAP(fegetexceptflag)(fexcept_t* __flagp, int __excepts) { 137 __excepts = mips_change_except(__excepts); 138 fexcept_t __fcsr; 139 WRAP(fegetenv)(&__fcsr); 140 *__flagp = mips_get_except(__fcsr & __excepts & FE_ALL_EXCEPT); 141 return 0; 142 } 143 144 int WRAP(fesetexceptflag)(const fexcept_t* __flagp, int __excepts) { 145 int __flagp_ = mips_change_except(*__flagp); 146 __excepts = mips_change_except(__excepts); 147 fexcept_t __fcsr; 148 WRAP(fegetenv)(&__fcsr); 149 /* Ensure that flags are all legal */ 150 __excepts &= FE_ALL_EXCEPT; 151 __fcsr &= ~__excepts; 152 __fcsr |= __flagp_ & __excepts; 153 WRAP(fesetenv)(&__fcsr); 154 return 0; 155 } 156 157 int WRAP(feraiseexcept)(int __excepts) { 158 __excepts = mips_change_except(__excepts); 159 fexcept_t __fcsr; 160 WRAP(fegetenv)(&__fcsr); 161 /* Ensure that flags are all legal */ 162 __excepts &= FE_ALL_EXCEPT; 163 /* Cause bit needs to be set as well for generating the exception*/ 164 __fcsr |= __excepts | (__excepts << _FCSR_CAUSE_SHIFT); 165 WRAP(fesetenv)(&__fcsr); 166 return 0; 167 } 168 169 int WRAP(fetestexcept)(int __excepts) { 170 __excepts = mips_change_except(__excepts); 171 fexcept_t __FCSR; 172 WRAP(fegetenv)(&__FCSR); 173 return mips_get_except(__FCSR & __excepts & FE_ALL_EXCEPT); 174 } 175 176 int WRAP(fegetround)(void) { 177 fenv_t _fcsr; 178 WRAP(fegetenv)(&_fcsr); 179 return mips_get_rounding(_fcsr & _FCSR_RMASK); 180 } 181 182 int WRAP(fesetround)(int __round) { 183 __round = mips_change_rounding(__round); 184 fenv_t _fcsr; 185 WRAP(fegetenv)(&_fcsr); 186 _fcsr &= ~_FCSR_RMASK; 187 _fcsr |= (__round & _FCSR_RMASK ); 188 WRAP(fesetenv)(&_fcsr); 189 return 0; 190 } 191 192 int WRAP(feholdexcept)(fenv_t* __envp) { 193 fenv_t __env; 194 WRAP(fegetenv)(&__env); 195 *__envp = __env; 196 __env &= ~(FE_ALL_EXCEPT | _FCSR_ENABLE_MASK); 197 WRAP(fesetenv)(&__env); 198 return 0; 199 } 200 201 int WRAP(feupdateenv)(const fenv_t* __envp) { 202 fexcept_t __fcsr; 203 WRAP(fegetenv)(&__fcsr); 204 WRAP(fesetenv)(__envp); 205 WRAP(feraiseexcept)(__fcsr & FE_ALL_EXCEPT); 206 return 0; 207 } 208 209