Home | History | Annotate | Download | only in arch-x86
      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 
     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 static inline int x86_change_except(int flags)
     26 {
     27     int x86flags = 0;
     28     int exception = flags & FE_ALL_EXCEPT_PORTABLE;
     29 
     30     // exception flags
     31     if (exception & FE_INVALID_PORTABLE)
     32         x86flags |= FE_INVALID;
     33     if (exception & FE_DIVBYZERO_PORTABLE)
     34         x86flags |= FE_DIVBYZERO;
     35     if (exception & FE_OVERFLOW_PORTABLE)
     36         x86flags |= FE_OVERFLOW;
     37     if (exception & FE_UNDERFLOW_PORTABLE)
     38         x86flags |= FE_UNDERFLOW;
     39     if (exception & FE_INEXACT_PORTABLE)
     40         x86flags |= FE_INEXACT;
     41 
     42     return x86flags;
     43 }
     44 
     45 static inline int x86_change_rounding(int flags)
     46 {
     47     int x86flags = 0;
     48     int rounding = flags & 0x03;
     49 
     50     // rounding flags
     51     switch(rounding)
     52     {
     53         case FE_TONEAREST_PORTABLE:
     54             x86flags = FE_TONEAREST;
     55             break;
     56         case FE_DOWNWARD_PORTABLE:
     57             x86flags = FE_DOWNWARD;
     58             break;
     59         case FE_UPWARD_PORTABLE:
     60             x86flags = FE_UPWARD;
     61             break;
     62         case FE_TOWARDZERO_PORTABLE:
     63             x86flags = FE_TOWARDZERO;
     64             break;
     65     }
     66     return x86flags;
     67 }
     68 
     69 static inline int x86_get_except(int x86flags)
     70 {
     71     int flags = 0;
     72     int exception = x86flags & FE_ALL_EXCEPT;
     73 
     74     // exception flags
     75     if (exception & FE_INVALID)
     76         flags |= FE_INVALID_PORTABLE;
     77     if (exception & FE_DIVBYZERO)
     78         flags |= FE_DIVBYZERO_PORTABLE;
     79     if (exception & FE_OVERFLOW)
     80         flags |= FE_OVERFLOW_PORTABLE;
     81     if (exception & FE_UNDERFLOW)
     82         flags |= FE_UNDERFLOW_PORTABLE;
     83     if (exception & FE_INEXACT)
     84         flags |= FE_INEXACT_PORTABLE;
     85 
     86     return flags;
     87 }
     88 static inline int x86_get_rounding(int x86flags)
     89 {
     90     int flags = 0;
     91     int rounding = x86flags & _ROUND_MASK;
     92 
     93     // rounding flags
     94     switch(rounding)
     95     {
     96         case FE_TONEAREST:
     97             flags = FE_TONEAREST_PORTABLE;
     98             break;
     99         case FE_DOWNWARD:
    100             flags = FE_DOWNWARD_PORTABLE;
    101             break;
    102         case FE_UPWARD:
    103             flags = FE_UPWARD_PORTABLE;
    104             break;
    105         case FE_TOWARDZERO:
    106             flags = FE_TOWARDZERO_PORTABLE;
    107             break;
    108     }
    109 
    110     return flags;
    111 }
    112 
    113 int
    114 WRAP(fesetexceptflag)(const fexcept_t *flagp, int excepts)
    115 {
    116     const fexcept_t flagp_ = x86_change_except(*flagp);
    117     int excepts_ = x86_change_except(excepts);
    118     return REAL(fesetexceptflag)(&flagp_, excepts_);
    119 }
    120 
    121 int
    122 WRAP(fegetexceptflag)(fexcept_t *flagp, int excepts)
    123 {
    124     REAL(fegetexceptflag)(flagp, x86_change_except(excepts));
    125     *flagp = x86_get_except(*flagp);
    126     return 0;
    127 }
    128 
    129 int
    130 WRAP(feraiseexcept)(int excepts)
    131 {
    132     return REAL(feraiseexcept)(x86_change_except(excepts));
    133 }
    134 
    135 int
    136 WRAP(feclearexcept)(int excepts)
    137 {
    138     return REAL(feclearexcept)(x86_change_except(excepts));
    139 }
    140 
    141 int
    142 WRAP(fetestexcept)(int excepts)
    143 {
    144     return REAL(fetestexcept)(x86_change_except(excepts));
    145 }
    146 
    147 int
    148 WRAP(fegetround)(void)
    149 {
    150     int round = REAL(fegetround)();
    151     return x86_get_rounding(round);
    152 }
    153 
    154 int
    155 WRAP(fesetround)(int round)
    156 {
    157     return REAL(fesetround)(x86_change_rounding(round));
    158 }
    159 
    160 int
    161 WRAP(fegetexcept)(void)
    162 {
    163     int flags = REAL(fegetexcept)();
    164     return x86_get_except(flags);
    165 }
    166 
    167