IEEE_ARITHMETIC intrinsic module procedures IEEE_NEXT_AFTER, IEEE_NEXT_DOWN, and IEEE_NEXT_UP, and intrinsic NEAREST return larger or smaller values adjacent to their primary REAL argument. The four procedures vary in how the direction is chosen, in how special cases are treated, and in what exceptions are generated. Implement the three IEEE_ARITHMETIC procedures. Update the NEAREST implementation to support all six REAL kinds 2,3,4,8,10,16, and fix several bugs. IEEE_NEXT_AFTER(X,Y) returns a NaN when Y is a NaN as that seems to be the universal choice of other compilers. Change the front end compile time implementation of these procedures to return normal (HUGE) values for infinities when applicable, rather than always returning the input infinity.
61 lines
1.9 KiB
C++
61 lines
1.9 KiB
C++
//===-- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Runtime exception support.
|
|
|
|
#include "flang/Runtime/exceptions.h"
|
|
#include "terminator.h"
|
|
#include <cfenv>
|
|
|
|
#ifndef __FE_DENORM
|
|
#define __FE_DENORM 0 // denorm is nonstandard
|
|
#endif
|
|
|
|
namespace Fortran::runtime {
|
|
|
|
extern "C" {
|
|
|
|
// Map a set of Fortran ieee_arithmetic module exceptions to a libm fenv.h
|
|
// excepts value.
|
|
uint32_t RTNAME(MapException)(uint32_t excepts) {
|
|
Terminator terminator{__FILE__, __LINE__};
|
|
|
|
static constexpr uint32_t v{FE_INVALID};
|
|
static constexpr uint32_t s{__FE_DENORM}; // subnormal
|
|
static constexpr uint32_t z{FE_DIVBYZERO};
|
|
static constexpr uint32_t o{FE_OVERFLOW};
|
|
static constexpr uint32_t u{FE_UNDERFLOW};
|
|
static constexpr uint32_t x{FE_INEXACT};
|
|
|
|
#define vm(p) p, p | v
|
|
#define sm(p) vm(p), vm(p | s)
|
|
#define zm(p) sm(p), sm(p | z)
|
|
#define om(p) zm(p), zm(p | o)
|
|
#define um(p) om(p), om(p | u)
|
|
#define xm um(0), um(x)
|
|
|
|
static constexpr uint32_t map[]{xm};
|
|
static constexpr uint32_t mapSize{sizeof(map) / sizeof(uint32_t)};
|
|
static_assert(mapSize == 64);
|
|
if (excepts == 0 || excepts >= mapSize) {
|
|
terminator.Crash("Invalid excepts value: %d", excepts);
|
|
}
|
|
return map[excepts];
|
|
}
|
|
|
|
// 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
|