1.1 --- a/templates/native/float.c Fri Jan 25 14:17:30 2019 +0100
1.2 +++ b/templates/native/float.c Fri Jan 25 23:12:44 2019 +0100
1.3 @@ -16,7 +16,8 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 */
1.6
1.7 -#include <fenv.h> /* feclearexcept, fetestexcept */
1.8 +#include <setjmp.h>
1.9 +#include <signal.h>
1.10 #include <math.h> /* pow */
1.11 #include <stdio.h> /* snprintf */
1.12 #include <errno.h> /* errno */
1.13 @@ -66,32 +67,7 @@
1.14
1.15 /* Floating point exception handling. */
1.16
1.17 -static void init_env(fenv_t *envp, int excepts)
1.18 -{
1.19 - fegetenv(envp);
1.20 - feclearexcept(excepts);
1.21 -}
1.22 -
1.23 -static int test_env(fenv_t *envp, int excepts)
1.24 -{
1.25 - if (fetestexcept(excepts))
1.26 - {
1.27 - fesetenv(envp);
1.28 - return 1;
1.29 - }
1.30 - return 0;
1.31 -}
1.32 -
1.33 -static int have_result(fenv_t *envp, int excepts)
1.34 -{
1.35 - return !fetestexcept(excepts);
1.36 -}
1.37 -
1.38 -static __attr make_result(fenv_t *envp, double result)
1.39 -{
1.40 - fesetenv(envp);
1.41 - return __new_float(result);
1.42 -}
1.43 +extern jmp_buf __fpe_env;
1.44
1.45 /* Floating point operations. */
1.46
1.47 @@ -100,21 +76,17 @@
1.48 /* self and other interpreted as float */
1.49 double i = __TOFLOAT(self);
1.50 double j = __TOFLOAT(other);
1.51 - double result;
1.52 -
1.53 - /* Preserve environment, clear exception state. */
1.54 - fenv_t env;
1.55 - init_env(&env, FE_OVERFLOW);
1.56 -
1.57 - result = i + j;
1.58 + int signum;
1.59
1.60 - /* Test for result, restore state, return the new float. */
1.61 - if (have_result(&env, FE_OVERFLOW))
1.62 - return make_result(&env, result);
1.63 + /* Perform the operation while handling exceptions. */
1.64 + signum = setjmp(__fpe_env);
1.65 + if (!signum)
1.66 + return __new_float(i + j);
1.67
1.68 - /* Restore state, raise exception. */
1.69 - if (test_env(&env, FE_OVERFLOW))
1.70 + /* Exception occurred. */
1.71 + if (signum == FPE_FLTOVF)
1.72 __raise_overflow_error();
1.73 +
1.74 return __NULL;
1.75 }
1.76
1.77 @@ -123,21 +95,17 @@
1.78 /* self and other interpreted as float */
1.79 double i = __TOFLOAT(self);
1.80 double j = __TOFLOAT(other);
1.81 - double result;
1.82 -
1.83 - /* Preserve environment, clear exception state. */
1.84 - fenv_t env;
1.85 - init_env(&env, FE_OVERFLOW);
1.86 -
1.87 - result = i - j;
1.88 + int signum;
1.89
1.90 - /* Test for result, restore state, return the new float. */
1.91 - if (have_result(&env, FE_OVERFLOW))
1.92 - return make_result(&env, result);
1.93 + /* Perform the operation while handling exceptions. */
1.94 + signum = setjmp(__fpe_env);
1.95 + if (!signum)
1.96 + return __new_float(i - j);
1.97
1.98 - /* Restore state, raise exception. */
1.99 - if (test_env(&env, FE_OVERFLOW))
1.100 + /* Exception occurred. */
1.101 + if (signum == FPE_FLTOVF)
1.102 __raise_overflow_error();
1.103 +
1.104 return __NULL;
1.105 }
1.106
1.107 @@ -146,23 +114,19 @@
1.108 /* self and other interpreted as float */
1.109 double i = __TOFLOAT(self);
1.110 double j = __TOFLOAT(other);
1.111 - double result;
1.112 + int signum;
1.113
1.114 - /* Preserve environment, clear exception state. */
1.115 - fenv_t env;
1.116 - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW);
1.117 -
1.118 - result = i * j;
1.119 + /* Perform the operation while handling exceptions. */
1.120 + signum = setjmp(__fpe_env);
1.121 + if (!signum)
1.122 + return __new_float(i * j);
1.123
1.124 - /* Test for result, restore state, return the new float. */
1.125 - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW))
1.126 - return make_result(&env, result);
1.127 + /* Exception occurred. */
1.128 + if (signum == FPE_FLTOVF)
1.129 + __raise_overflow_error();
1.130 + else if (signum == FPE_FLTUND)
1.131 + __raise_underflow_error();
1.132
1.133 - /* Restore state, raise exception. */
1.134 - if (test_env(&env, FE_OVERFLOW))
1.135 - __raise_overflow_error();
1.136 - if (test_env(&env, FE_UNDERFLOW))
1.137 - __raise_underflow_error();
1.138 return __NULL;
1.139 }
1.140
1.141 @@ -171,25 +135,21 @@
1.142 /* self and other interpreted as float */
1.143 double i = __TOFLOAT(self);
1.144 double j = __TOFLOAT(other);
1.145 - double result;
1.146 + int signum;
1.147
1.148 - /* Preserve environment, clear exception state. */
1.149 - fenv_t env;
1.150 - init_env(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO);
1.151 -
1.152 - result = i / j;
1.153 + /* Perform the operation while handling exceptions. */
1.154 + signum = setjmp(__fpe_env);
1.155 + if (!signum)
1.156 + return __new_float(i / j);
1.157
1.158 - /* Test for result, restore state, return the new float. */
1.159 - if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO))
1.160 - return make_result(&env, result);
1.161 + /* Exception occurred. */
1.162 + if (signum == FPE_FLTOVF)
1.163 + __raise_overflow_error();
1.164 + else if (signum == FPE_FLTUND)
1.165 + __raise_underflow_error();
1.166 + else if (signum == FPE_FLTDIV)
1.167 + __raise_zero_division_error();
1.168
1.169 - /* Restore state, raise exception. */
1.170 - if (test_env(&env, FE_OVERFLOW))
1.171 - __raise_overflow_error();
1.172 - if (test_env(&env, FE_UNDERFLOW))
1.173 - __raise_underflow_error();
1.174 - if (test_env(&env, FE_DIVBYZERO))
1.175 - __raise_zero_division_error();
1.176 return __NULL;
1.177 }
1.178
1.179 @@ -198,23 +158,19 @@
1.180 /* self and other interpreted as float */
1.181 double i = __TOFLOAT(self);
1.182 double j = __TOFLOAT(other);
1.183 - double result;
1.184 + int signum;
1.185
1.186 - /* Preserve environment, clear exception state. */
1.187 - fenv_t env;
1.188 - init_env(&env, FE_OVERFLOW | FE_DIVBYZERO);
1.189 -
1.190 - result = fmod(i, j);
1.191 + /* Perform the operation while handling exceptions. */
1.192 + signum = setjmp(__fpe_env);
1.193 + if (!signum)
1.194 + return __new_float(fmod(i, j));
1.195
1.196 - /* Test for result, restore state, return the new float. */
1.197 - if (have_result(&env, FE_OVERFLOW | FE_DIVBYZERO))
1.198 - return make_result(&env, result);
1.199 + /* Exception occurred. */
1.200 + if (signum == FPE_FLTOVF)
1.201 + __raise_overflow_error();
1.202 + else if (signum == FPE_FLTDIV)
1.203 + __raise_zero_division_error();
1.204
1.205 - /* Restore state, raise exception. */
1.206 - if (test_env(&env, FE_OVERFLOW))
1.207 - __raise_overflow_error();
1.208 - if (test_env(&env, FE_DIVBYZERO))
1.209 - __raise_zero_division_error();
1.210 return __NULL;
1.211 }
1.212
1.213 @@ -222,21 +178,17 @@
1.214 {
1.215 /* self interpreted as float */
1.216 double i = __TOFLOAT(self);
1.217 - double result;
1.218 -
1.219 - /* Preserve environment, clear exception state. */
1.220 - fenv_t env;
1.221 - init_env(&env, FE_OVERFLOW);
1.222 -
1.223 - result = -i;
1.224 + int signum;
1.225
1.226 - /* Test for result, restore state, return the new float. */
1.227 - if (have_result(&env, FE_OVERFLOW))
1.228 - return make_result(&env, result);
1.229 + /* Perform the operation while handling exceptions. */
1.230 + signum = setjmp(__fpe_env);
1.231 + if (!signum)
1.232 + return __new_float(-i);
1.233
1.234 - /* Restore state, raise exception. */
1.235 - if (test_env(&env, FE_OVERFLOW))
1.236 + /* Exception occurred. */
1.237 + if (signum == FPE_FLTOVF)
1.238 __raise_overflow_error();
1.239 +
1.240 return __NULL;
1.241 }
1.242