Home | History | Annotate | Download | only in arch-mips
      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