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