1 1.1 mrg /* SysV FPU-related code (for systems not otherwise supported). 2 1.1.1.4 mrg Copyright (C) 2005-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Francois-Xavier Coudert <coudert (at) clipper.ens.fr> 4 1.1 mrg 5 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 6 1.1 mrg 7 1.1 mrg Libgfortran is free software; you can redistribute it and/or 8 1.1 mrg modify it under the terms of the GNU General Public 9 1.1 mrg License as published by the Free Software Foundation; either 10 1.1 mrg version 3 of the License, or (at your option) any later version. 11 1.1 mrg 12 1.1 mrg Libgfortran is distributed in the hope that it will be useful, 13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 mrg GNU General Public License for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* FPU-related code for SysV platforms with fpsetmask(). */ 27 1.1 mrg 28 1.1 mrg /* BSD and Solaris systems have slightly different types and functions 29 1.1 mrg naming. We deal with these here, to simplify the code below. */ 30 1.1 mrg 31 1.1 mrg #if HAVE_FP_EXCEPT 32 1.1 mrg # define FP_EXCEPT_TYPE fp_except 33 1.1 mrg #elif HAVE_FP_EXCEPT_T 34 1.1 mrg # define FP_EXCEPT_TYPE fp_except_t 35 1.1 mrg #else 36 1.1 mrg choke me 37 1.1 mrg #endif 38 1.1 mrg 39 1.1 mrg #if HAVE_FP_RND 40 1.1 mrg # define FP_RND_TYPE fp_rnd 41 1.1 mrg #elif HAVE_FP_RND_T 42 1.1 mrg # define FP_RND_TYPE fp_rnd_t 43 1.1 mrg #else 44 1.1 mrg choke me 45 1.1 mrg #endif 46 1.1 mrg 47 1.1 mrg #if HAVE_FPSETSTICKY 48 1.1 mrg # define FPSETSTICKY fpsetsticky 49 1.1 mrg #elif HAVE_FPRESETSTICKY 50 1.1 mrg # define FPSETSTICKY fpresetsticky 51 1.1 mrg #else 52 1.1 mrg choke me 53 1.1 mrg #endif 54 1.1 mrg 55 1.1 mrg 56 1.1 mrg void 57 1.1 mrg set_fpu_trap_exceptions (int trap, int notrap) 58 1.1 mrg { 59 1.1 mrg FP_EXCEPT_TYPE cw = fpgetmask(); 60 1.1 mrg 61 1.1 mrg #ifdef FP_X_INV 62 1.1 mrg if (trap & GFC_FPE_INVALID) 63 1.1 mrg cw |= FP_X_INV; 64 1.1 mrg if (notrap & GFC_FPE_INVALID) 65 1.1 mrg cw &= ~FP_X_INV; 66 1.1 mrg #endif 67 1.1 mrg 68 1.1 mrg #ifdef FP_X_DNML 69 1.1 mrg if (trap & GFC_FPE_DENORMAL) 70 1.1 mrg cw |= FP_X_DNML; 71 1.1 mrg if (notrap & GFC_FPE_DENORMAL) 72 1.1 mrg cw &= ~FP_X_DNML; 73 1.1 mrg #endif 74 1.1 mrg 75 1.1 mrg #ifdef FP_X_DZ 76 1.1 mrg if (trap & GFC_FPE_ZERO) 77 1.1 mrg cw |= FP_X_DZ; 78 1.1 mrg if (notrap & GFC_FPE_ZERO) 79 1.1 mrg cw &= ~FP_X_DZ; 80 1.1 mrg #endif 81 1.1 mrg 82 1.1 mrg #ifdef FP_X_OFL 83 1.1 mrg if (trap & GFC_FPE_OVERFLOW) 84 1.1 mrg cw |= FP_X_OFL; 85 1.1 mrg if (notrap & GFC_FPE_OVERFLOW) 86 1.1 mrg cw &= ~FP_X_OFL; 87 1.1 mrg #endif 88 1.1 mrg 89 1.1 mrg #ifdef FP_X_UFL 90 1.1 mrg if (trap & GFC_FPE_UNDERFLOW) 91 1.1 mrg cw |= FP_X_UFL; 92 1.1 mrg if (notrap & GFC_FPE_UNDERFLOW) 93 1.1 mrg cw &= ~FP_X_UFL; 94 1.1 mrg #endif 95 1.1 mrg 96 1.1 mrg #ifdef FP_X_IMP 97 1.1 mrg if (trap & GFC_FPE_INEXACT) 98 1.1 mrg cw |= FP_X_IMP; 99 1.1 mrg if (notrap & GFC_FPE_INEXACT) 100 1.1 mrg cw &= ~FP_X_IMP; 101 1.1 mrg #endif 102 1.1 mrg 103 1.1 mrg fpsetmask(cw); 104 1.1 mrg } 105 1.1 mrg 106 1.1 mrg 107 1.1 mrg int 108 1.1 mrg get_fpu_trap_exceptions (void) 109 1.1 mrg { 110 1.1 mrg int res = 0; 111 1.1 mrg FP_EXCEPT_TYPE cw = fpgetmask(); 112 1.1 mrg 113 1.1 mrg #ifdef FP_X_INV 114 1.1 mrg if (cw & FP_X_INV) res |= GFC_FPE_INVALID; 115 1.1 mrg #endif 116 1.1 mrg 117 1.1 mrg #ifdef FP_X_DNML 118 1.1 mrg if (cw & FP_X_DNML) res |= GFC_FPE_DENORMAL; 119 1.1 mrg #endif 120 1.1 mrg 121 1.1 mrg #ifdef FP_X_DZ 122 1.1 mrg if (cw & FP_X_DZ) res |= GFC_FPE_ZERO; 123 1.1 mrg #endif 124 1.1 mrg 125 1.1 mrg #ifdef FP_X_OFL 126 1.1 mrg if (cw & FP_X_OFL) res |= GFC_FPE_OVERFLOW; 127 1.1 mrg #endif 128 1.1 mrg 129 1.1 mrg #ifdef FP_X_UFL 130 1.1 mrg if (cw & FP_X_UFL) res |= GFC_FPE_UNDERFLOW; 131 1.1 mrg #endif 132 1.1 mrg 133 1.1 mrg #ifdef FP_X_IMP 134 1.1 mrg if (cw & FP_X_IMP) res |= GFC_FPE_INEXACT; 135 1.1 mrg #endif 136 1.1 mrg 137 1.1 mrg return res; 138 1.1 mrg } 139 1.1 mrg 140 1.1 mrg 141 1.1 mrg int 142 1.1 mrg support_fpu_trap (int flag) 143 1.1 mrg { 144 1.1 mrg return support_fpu_flag (flag); 145 1.1 mrg } 146 1.1 mrg 147 1.1 mrg 148 1.1 mrg void 149 1.1 mrg set_fpu (void) 150 1.1 mrg { 151 1.1 mrg #ifndef FP_X_INV 152 1.1 mrg if (options.fpe & GFC_FPE_INVALID) 153 1.1 mrg estr_write ("Fortran runtime warning: IEEE 'invalid operation' " 154 1.1 mrg "exception not supported.\n"); 155 1.1 mrg #endif 156 1.1 mrg 157 1.1 mrg #ifndef FP_X_DNML 158 1.1 mrg if (options.fpe & GFC_FPE_DENORMAL) 159 1.1 mrg estr_write ("Fortran runtime warning: Floating point 'denormal operand' " 160 1.1 mrg "exception not supported.\n"); 161 1.1 mrg #endif 162 1.1 mrg 163 1.1 mrg #ifndef FP_X_DZ 164 1.1 mrg if (options.fpe & GFC_FPE_ZERO) 165 1.1 mrg estr_write ("Fortran runtime warning: IEEE 'division by zero' " 166 1.1 mrg "exception not supported.\n"); 167 1.1 mrg #endif 168 1.1 mrg 169 1.1 mrg #ifndef FP_X_OFL 170 1.1 mrg if (options.fpe & GFC_FPE_OVERFLOW) 171 1.1 mrg estr_write ("Fortran runtime warning: IEEE 'overflow' " 172 1.1 mrg "exception not supported.\n"); 173 1.1 mrg #endif 174 1.1 mrg 175 1.1 mrg #ifndef FP_X_UFL 176 1.1 mrg if (options.fpe & GFC_FPE_UNDERFLOW) 177 1.1 mrg estr_write ("Fortran runtime warning: IEEE 'underflow' " 178 1.1 mrg "exception not supported.\n"); 179 1.1 mrg #endif 180 1.1 mrg 181 1.1 mrg #ifndef FP_X_IMP 182 1.1 mrg if (options.fpe & GFC_FPE_INEXACT) 183 1.1 mrg estr_write ("Fortran runtime warning: IEEE 'inexact' " 184 1.1 mrg "exception not supported.\n"); 185 1.1 mrg #endif 186 1.1 mrg 187 1.1 mrg set_fpu_trap_exceptions (options.fpe, 0); 188 1.1 mrg } 189 1.1 mrg 190 1.1 mrg 191 1.1 mrg int 192 1.1 mrg get_fpu_except_flags (void) 193 1.1 mrg { 194 1.1 mrg int result; 195 1.1 mrg FP_EXCEPT_TYPE set_excepts; 196 1.1 mrg 197 1.1 mrg result = 0; 198 1.1 mrg set_excepts = fpgetsticky (); 199 1.1 mrg 200 1.1 mrg #ifdef FP_X_INV 201 1.1 mrg if (set_excepts & FP_X_INV) 202 1.1 mrg result |= GFC_FPE_INVALID; 203 1.1 mrg #endif 204 1.1 mrg 205 1.1 mrg #ifdef FP_X_DZ 206 1.1 mrg if (set_excepts & FP_X_DZ) 207 1.1 mrg result |= GFC_FPE_ZERO; 208 1.1 mrg #endif 209 1.1 mrg 210 1.1 mrg #ifdef FP_X_OFL 211 1.1 mrg if (set_excepts & FP_X_OFL) 212 1.1 mrg result |= GFC_FPE_OVERFLOW; 213 1.1 mrg #endif 214 1.1 mrg 215 1.1 mrg #ifdef FP_X_UFL 216 1.1 mrg if (set_excepts & FP_X_UFL) 217 1.1 mrg result |= GFC_FPE_UNDERFLOW; 218 1.1 mrg #endif 219 1.1 mrg 220 1.1 mrg #ifdef FP_X_DNML 221 1.1 mrg if (set_excepts & FP_X_DNML) 222 1.1 mrg result |= GFC_FPE_DENORMAL; 223 1.1 mrg #endif 224 1.1 mrg 225 1.1 mrg #ifdef FP_X_IMP 226 1.1 mrg if (set_excepts & FP_X_IMP) 227 1.1 mrg result |= GFC_FPE_INEXACT; 228 1.1 mrg #endif 229 1.1 mrg 230 1.1 mrg return result; 231 1.1 mrg } 232 1.1 mrg 233 1.1 mrg 234 1.1 mrg void 235 1.1 mrg set_fpu_except_flags (int set, int clear) 236 1.1 mrg { 237 1.1 mrg FP_EXCEPT_TYPE flags; 238 1.1 mrg 239 1.1 mrg flags = fpgetsticky (); 240 1.1 mrg 241 1.1 mrg #ifdef FP_X_INV 242 1.1 mrg if (set & GFC_FPE_INVALID) 243 1.1 mrg flags |= FP_X_INV; 244 1.1 mrg if (clear & GFC_FPE_INVALID) 245 1.1 mrg flags &= ~FP_X_INV; 246 1.1 mrg #endif 247 1.1 mrg 248 1.1 mrg #ifdef FP_X_DZ 249 1.1 mrg if (set & GFC_FPE_ZERO) 250 1.1 mrg flags |= FP_X_DZ; 251 1.1 mrg if (clear & GFC_FPE_ZERO) 252 1.1 mrg flags &= ~FP_X_DZ; 253 1.1 mrg #endif 254 1.1 mrg 255 1.1 mrg #ifdef FP_X_OFL 256 1.1 mrg if (set & GFC_FPE_OVERFLOW) 257 1.1 mrg flags |= FP_X_OFL; 258 1.1 mrg if (clear & GFC_FPE_OVERFLOW) 259 1.1 mrg flags &= ~FP_X_OFL; 260 1.1 mrg #endif 261 1.1 mrg 262 1.1 mrg #ifdef FP_X_UFL 263 1.1 mrg if (set & GFC_FPE_UNDERFLOW) 264 1.1 mrg flags |= FP_X_UFL; 265 1.1 mrg if (clear & GFC_FPE_UNDERFLOW) 266 1.1 mrg flags &= ~FP_X_UFL; 267 1.1 mrg #endif 268 1.1 mrg 269 1.1 mrg #ifdef FP_X_DNML 270 1.1 mrg if (set & GFC_FPE_DENORMAL) 271 1.1 mrg flags |= FP_X_DNML; 272 1.1 mrg if (clear & GFC_FPE_DENORMAL) 273 1.1 mrg flags &= ~FP_X_DNML; 274 1.1 mrg #endif 275 1.1 mrg 276 1.1 mrg #ifdef FP_X_IMP 277 1.1 mrg if (set & GFC_FPE_INEXACT) 278 1.1 mrg flags |= FP_X_IMP; 279 1.1 mrg if (clear & GFC_FPE_INEXACT) 280 1.1 mrg flags &= ~FP_X_IMP; 281 1.1 mrg #endif 282 1.1 mrg 283 1.1 mrg FPSETSTICKY (flags); 284 1.1 mrg } 285 1.1 mrg 286 1.1 mrg 287 1.1 mrg int 288 1.1 mrg support_fpu_flag (int flag) 289 1.1 mrg { 290 1.1 mrg if (flag & GFC_FPE_INVALID) 291 1.1 mrg { 292 1.1 mrg #ifndef FP_X_INV 293 1.1 mrg return 0; 294 1.1 mrg #endif 295 1.1 mrg } 296 1.1 mrg else if (flag & GFC_FPE_ZERO) 297 1.1 mrg { 298 1.1 mrg #ifndef FP_X_DZ 299 1.1 mrg return 0; 300 1.1 mrg #endif 301 1.1 mrg } 302 1.1 mrg else if (flag & GFC_FPE_OVERFLOW) 303 1.1 mrg { 304 1.1 mrg #ifndef FP_X_OFL 305 1.1 mrg return 0; 306 1.1 mrg #endif 307 1.1 mrg } 308 1.1 mrg else if (flag & GFC_FPE_UNDERFLOW) 309 1.1 mrg { 310 1.1 mrg #ifndef FP_X_UFL 311 1.1 mrg return 0; 312 1.1 mrg #endif 313 1.1 mrg } 314 1.1 mrg else if (flag & GFC_FPE_DENORMAL) 315 1.1 mrg { 316 1.1 mrg #ifndef FP_X_DNML 317 1.1 mrg return 0; 318 1.1 mrg #endif 319 1.1 mrg } 320 1.1 mrg else if (flag & GFC_FPE_INEXACT) 321 1.1 mrg { 322 1.1 mrg #ifndef FP_X_IMP 323 1.1 mrg return 0; 324 1.1 mrg #endif 325 1.1 mrg } 326 1.1 mrg 327 1.1 mrg return 1; 328 1.1 mrg } 329 1.1 mrg 330 1.1 mrg 331 1.1 mrg int 332 1.1 mrg get_fpu_rounding_mode (void) 333 1.1 mrg { 334 1.1 mrg switch (fpgetround ()) 335 1.1 mrg { 336 1.1 mrg case FP_RN: 337 1.1 mrg return GFC_FPE_TONEAREST; 338 1.1 mrg case FP_RP: 339 1.1 mrg return GFC_FPE_UPWARD; 340 1.1 mrg case FP_RM: 341 1.1 mrg return GFC_FPE_DOWNWARD; 342 1.1 mrg case FP_RZ: 343 1.1 mrg return GFC_FPE_TOWARDZERO; 344 1.1 mrg default: 345 1.1 mrg return 0; /* Should be unreachable. */ 346 1.1 mrg } 347 1.1 mrg } 348 1.1 mrg 349 1.1 mrg 350 1.1 mrg void 351 1.1 mrg set_fpu_rounding_mode (int mode) 352 1.1 mrg { 353 1.1 mrg FP_RND_TYPE rnd_mode; 354 1.1 mrg 355 1.1 mrg switch (mode) 356 1.1 mrg { 357 1.1 mrg case GFC_FPE_TONEAREST: 358 1.1 mrg rnd_mode = FP_RN; 359 1.1 mrg break; 360 1.1 mrg case GFC_FPE_UPWARD: 361 1.1 mrg rnd_mode = FP_RP; 362 1.1 mrg break; 363 1.1 mrg case GFC_FPE_DOWNWARD: 364 1.1 mrg rnd_mode = FP_RM; 365 1.1 mrg break; 366 1.1 mrg case GFC_FPE_TOWARDZERO: 367 1.1 mrg rnd_mode = FP_RZ; 368 1.1 mrg break; 369 1.1 mrg default: 370 1.1 mrg return; /* Should be unreachable. */ 371 1.1 mrg } 372 1.1 mrg fpsetround (rnd_mode); 373 1.1 mrg } 374 1.1 mrg 375 1.1 mrg 376 1.1 mrg int 377 1.1.1.4 mrg support_fpu_rounding_mode (int mode) 378 1.1 mrg { 379 1.1.1.4 mrg if (mode == GFC_FPE_AWAY) 380 1.1.1.4 mrg return 0; 381 1.1.1.4 mrg else 382 1.1.1.4 mrg return 1; 383 1.1 mrg } 384 1.1 mrg 385 1.1 mrg 386 1.1 mrg typedef struct 387 1.1 mrg { 388 1.1 mrg FP_EXCEPT_TYPE mask; 389 1.1 mrg FP_EXCEPT_TYPE sticky; 390 1.1 mrg FP_RND_TYPE round; 391 1.1 mrg } fpu_state_t; 392 1.1 mrg 393 1.1 mrg 394 1.1 mrg /* Check we can actually store the FPU state in the allocated size. */ 395 1.1 mrg _Static_assert (sizeof(fpu_state_t) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE, 396 1.1 mrg "GFC_FPE_STATE_BUFFER_SIZE is too small"); 397 1.1 mrg 398 1.1 mrg 399 1.1 mrg void 400 1.1 mrg get_fpu_state (void *s) 401 1.1 mrg { 402 1.1 mrg fpu_state_t *state = s; 403 1.1 mrg 404 1.1 mrg state->mask = fpgetmask (); 405 1.1 mrg state->sticky = fpgetsticky (); 406 1.1 mrg state->round = fpgetround (); 407 1.1 mrg } 408 1.1 mrg 409 1.1 mrg void 410 1.1 mrg set_fpu_state (void *s) 411 1.1 mrg { 412 1.1 mrg fpu_state_t *state = s; 413 1.1 mrg 414 1.1 mrg fpsetmask (state->mask); 415 1.1 mrg FPSETSTICKY (state->sticky); 416 1.1 mrg fpsetround (state->round); 417 1.1 mrg } 418 1.1 mrg 419 1.1 mrg 420 1.1 mrg int 421 1.1 mrg support_fpu_underflow_control (int kind __attribute__((unused))) 422 1.1 mrg { 423 1.1 mrg return 0; 424 1.1 mrg } 425 1.1 mrg 426 1.1 mrg 427 1.1 mrg int 428 1.1 mrg get_fpu_underflow_mode (void) 429 1.1 mrg { 430 1.1 mrg return 0; 431 1.1 mrg } 432 1.1 mrg 433 1.1 mrg 434 1.1 mrg void 435 1.1 mrg set_fpu_underflow_mode (int gradual __attribute__((unused))) 436 1.1 mrg { 437 1.1 mrg } 438 1.1 mrg 439