//===-- runtime/exceptions.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Map Fortran ieee_arithmetic module exceptions to fenv.h exceptions. #include "flang/Runtime/exceptions.h" #include "terminator.h" #include "flang/Runtime/magic-numbers.h" #include #ifndef __FE_DENORM #define __FE_DENORM 0 // denorm is nonstandard #endif namespace Fortran::runtime { extern "C" { std::int32_t RTNAME(MapException)(int32_t except) { Terminator terminator{__FILE__, __LINE__}; static constexpr int32_t mask{_FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DENORM | _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO | _FORTRAN_RUNTIME_IEEE_OVERFLOW | _FORTRAN_RUNTIME_IEEE_UNDERFLOW | _FORTRAN_RUNTIME_IEEE_INEXACT}; if (except == 0 || except != (except & mask)) { terminator.Crash("Invalid exception value: %d", except); } // Fortran and fenv.h values are identical; return the value. if constexpr (_FORTRAN_RUNTIME_IEEE_INVALID == FE_INVALID && _FORTRAN_RUNTIME_IEEE_DENORM == __FE_DENORM && _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO == FE_DIVBYZERO && _FORTRAN_RUNTIME_IEEE_OVERFLOW == FE_OVERFLOW && _FORTRAN_RUNTIME_IEEE_UNDERFLOW == FE_UNDERFLOW && _FORTRAN_RUNTIME_IEEE_INEXACT == FE_INEXACT) { return except; } // fenv.h calls that take exception arguments are able to process multiple // exceptions in one call, such as FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID. // And intrinsic module procedures that manage exceptions are elemental // procedures that may specify multiple exceptions, such as ieee_all. // However, general elemental call processing places single scalar arguments // in a loop. As a consequence, argument 'except' here will be a power of // two, corresponding to a single exception. If code generation were // modified to bypass normal elemental call processing for calls with // ieee_usual, ieee_all, or user-specified array arguments, this switch // could be extended to support that. // Fortran and fenv.h values differ. switch (except) { case _FORTRAN_RUNTIME_IEEE_INVALID: return FE_INVALID; case _FORTRAN_RUNTIME_IEEE_DENORM: if (__FE_DENORM) { return __FE_DENORM; } break; case _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO: return FE_DIVBYZERO; case _FORTRAN_RUNTIME_IEEE_OVERFLOW: return FE_OVERFLOW; case _FORTRAN_RUNTIME_IEEE_UNDERFLOW: return FE_UNDERFLOW; case _FORTRAN_RUNTIME_IEEE_INEXACT: return FE_INEXACT; } terminator.Crash("Invalid exception set: %d", except); } // Verify that the size of ieee_modes_type and ieee_status_type objects from // intrinsic module file __fortran_ieee_exceptions.f90 are large enough to // hold fenv_t object. // TODO: fenv_t can be way larger than // sizeof(int) * _FORTRAN_RUNTIME_IEEE_FENV_T_EXTENT // on some systems, e.g. Solaris, so omit object size comparison for now. // TODO: consider femode_t object size comparison once its more mature. } // extern "C" } // namespace Fortran::runtime