diff options
author | peter klausler <pklausler@nvidia.com> | 2021-04-01 12:59:59 -0700 |
---|---|---|
committer | peter klausler <pklausler@nvidia.com> | 2021-04-01 15:39:32 -0700 |
commit | 5f6c5c63c7c21cc9cf1c2b21759e40aa4854d496 (patch) | |
tree | 771a70304a16e3f66e05d3b79d621b1747722538 /flang | |
parent | llvm-shlib: Create object libraries for each component and link against them (diff) | |
download | llvm-project-5f6c5c63c7c21cc9cf1c2b21759e40aa4854d496.tar.gz llvm-project-5f6c5c63c7c21cc9cf1c2b21759e40aa4854d496.tar.bz2 llvm-project-5f6c5c63c7c21cc9cf1c2b21759e40aa4854d496.zip |
[flang] Implement numeric intrinsic functions in runtime
Adds APIs, implementations, and unit tests for AINT, ANINT,
CEILING, EXPONENT, FLOOR, FRACTION, MOD, MODULO, NEAREST, NINT,
RRSPACING, SCALE, SET_EXPONENT, & SPACING.
Differential Revision: https://reviews.llvm.org/D99764
Diffstat (limited to 'flang')
-rw-r--r-- | flang/runtime/CMakeLists.txt | 1 | ||||
-rw-r--r-- | flang/runtime/numeric.cpp | 773 | ||||
-rw-r--r-- | flang/runtime/numeric.h | 329 | ||||
-rw-r--r-- | flang/unittests/RuntimeGTest/CMakeLists.txt | 1 | ||||
-rw-r--r-- | flang/unittests/RuntimeGTest/Numeric.cpp | 168 |
5 files changed, 1272 insertions, 0 deletions
diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index fc9043218193..49ac98d01f1d 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -51,6 +51,7 @@ add_flang_library(FortranRuntime io-stmt.cpp main.cpp memory.cpp + numeric.cpp reduction.cpp stat.cpp stop.cpp diff --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp new file mode 100644 index 000000000000..a2d32d86b49c --- /dev/null +++ b/flang/runtime/numeric.cpp @@ -0,0 +1,773 @@ +//===-- runtime/numeric.cpp -------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "numeric.h" +#include "flang/Common/long-double.h" +#include <climits> +#include <cmath> +#include <limits> + +namespace Fortran::runtime { + +// AINT +template <typename RESULT, typename ARG> inline RESULT Aint(ARG x) { + return std::trunc(x); +} + +// ANINT & NINT +template <typename RESULT, typename ARG> inline RESULT Anint(ARG x) { + if (x >= 0) { + return std::trunc(x + ARG{0.5}); + } else { + return std::trunc(x - ARG{0.5}); + } +} + +// CEILING & FLOOR (16.9.43, .79) +template <typename RESULT, typename ARG> inline RESULT Ceiling(ARG x) { + return std::ceil(x); +} +template <typename RESULT, typename ARG> inline RESULT Floor(ARG x) { + return std::floor(x); +} + +// EXPONENT (16.9.75) +template <typename RESULT, typename ARG> inline RESULT Exponent(ARG x) { + if (std::isinf(x) || std::isnan(x)) { + return std::numeric_limits<RESULT>::max(); // +/-Inf, NaN -> HUGE(0) + } else if (x == 0) { + return 0; // 0 -> 0 + } else { + return std::ilogb(x) + 1; + } +} + +// FRACTION (16.9.80) +template <typename T> inline T Fraction(T x) { + if (std::isnan(x)) { + return x; // NaN -> same NaN + } else if (std::isinf(x)) { + return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN + } else if (x == 0) { + return 0; // 0 -> 0 + } else { + int ignoredExp; + return std::frexp(x, &ignoredExp); + } +} + +// MOD & MODULO (16.9.135, .136) +template <bool IS_MODULO, typename T> inline T IntMod(T x, T p) { + auto mod{x - (x / p) * p}; + if (IS_MODULO && (x > 0) != (p > 0)) { + mod += p; + } + return mod; +} +template <bool IS_MODULO, typename T> inline T RealMod(T x, T p) { + if constexpr (IS_MODULO) { + return x - std::floor(x / p) * p; + } else { + return x - std::trunc(x / p) * p; + } +} + +// RRSPACING (16.9.164) +template <int PREC, typename T> inline T RRSpacing(T x) { + if (std::isnan(x)) { + return x; // NaN -> same NaN + } else if (std::isinf(x)) { + return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN + } else if (x == 0) { + return 0; // 0 -> 0 + } else { + return std::ldexp(std::abs(x), PREC - (std::ilogb(x) + 1)); + } +} + +// SCALE (16.9.166) +template <typename T> inline T Scale(T x, std::int64_t p) { + auto ip{static_cast<int>(p)}; + if (ip != p) { + ip = p < 0 ? std::numeric_limits<int>::min() + : std::numeric_limits<int>::max(); + } + return std::ldexp(x, p); // x*2**p +} + +// SET_EXPONENT (16.9.171) +template <typename T> inline T SetExponent(T x, std::int64_t p) { + if (std::isnan(x)) { + return x; // NaN -> same NaN + } else if (std::isinf(x)) { + return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN + } else if (x == 0) { + return 0; // 0 -> 0 + } else { + int expo{std::ilogb(x)}; + auto ip{static_cast<int>(p - expo)}; + if (ip != p - expo) { + ip = p < 0 ? std::numeric_limits<int>::min() + : std::numeric_limits<int>::max(); + } + return std::ldexp(x, ip); // x*2**(p-e) + } +} + +// SPACING (16.9.180) +template <int PREC, typename T> inline T Spacing(T x) { + if (std::isnan(x)) { + return x; // NaN -> same NaN + } else if (std::isinf(x)) { + return std::numeric_limits<T>::quiet_NaN(); // +/-Inf -> NaN + } else if (x == 0) { + // The standard-mandated behavior seems broken, since TINY() can't be + // subnormal. + return std::numeric_limits<T>::min(); // 0 -> TINY(x) + } else { + return std::ldexp( + static_cast<T>(1.0), std::ilogb(x) + 1 - PREC); // 2**(e-p) + } +} + +// NEAREST (16.9.139) +template <int PREC, typename T> inline T Nearest(T x, bool positive) { + auto spacing{Spacing<PREC>(x)}; + if (x == 0) { + auto least{std::numeric_limits<T>::denorm_min()}; + return positive ? least : -least; + } else { + return positive ? x + spacing : x - spacing; + } +} + +extern "C" { + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Aint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Aint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Aint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Aint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint4_10)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Aint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint8_10)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Aint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Aint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Aint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint10_10)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Aint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint4_16)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Aint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint8_16)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Aint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Aint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Aint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint16_16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Aint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint4_10)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint8_10)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint10_10)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Real, 10>>(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint4_16)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint8_16)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Real, 4>>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Real, 8>>(x); +} +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint16_16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Real, 16>>(x); +} +#endif + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling4_1)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling4_2)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling4_16)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling8_1)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling8_2)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling8_16)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling10_1)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling10_2)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling10_16)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#else +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling16_1)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling16_2)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling16_16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Ceiling<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#endif + +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Exponent<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +#endif + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor4_1)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor4_2)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor4_16)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor8_1)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor8_2)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor8_16)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor10_1)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor10_2)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor10_16)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#else +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor16_1)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor16_2)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor16_16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Floor<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Fraction4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Fraction(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Fraction8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Fraction(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Fraction10)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Fraction(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Fraction16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Fraction(x); +} +#endif + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModInteger1)( + CppTypeFor<TypeCategory::Integer, 1> x, + CppTypeFor<TypeCategory::Integer, 1> p) { + return IntMod<false>(x, p); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModInteger2)( + CppTypeFor<TypeCategory::Integer, 2> x, + CppTypeFor<TypeCategory::Integer, 2> p) { + return IntMod<false>(x, p); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModInteger4)( + CppTypeFor<TypeCategory::Integer, 4> x, + CppTypeFor<TypeCategory::Integer, 4> p) { + return IntMod<false>(x, p); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModInteger8)( + CppTypeFor<TypeCategory::Integer, 8> x, + CppTypeFor<TypeCategory::Integer, 8> p) { + return IntMod<false>(x, p); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModInteger16)( + CppTypeFor<TypeCategory::Integer, 16> x, + CppTypeFor<TypeCategory::Integer, 16> p) { + return IntMod<false>(x, p); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(ModReal4)( + CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p) { + return RealMod<false>(x, p); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(ModReal8)( + CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p) { + return RealMod<false>(x, p); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(ModReal10)( + CppTypeFor<TypeCategory::Real, 10> x, + CppTypeFor<TypeCategory::Real, 10> p) { + return RealMod<false>(x, p); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(ModReal16)( + CppTypeFor<TypeCategory::Real, 16> x, + CppTypeFor<TypeCategory::Real, 16> p) { + return RealMod<false>(x, p); +} +#endif + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModuloInteger1)( + CppTypeFor<TypeCategory::Integer, 1> x, + CppTypeFor<TypeCategory::Integer, 1> p) { + return IntMod<true>(x, p); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModuloInteger2)( + CppTypeFor<TypeCategory::Integer, 2> x, + CppTypeFor<TypeCategory::Integer, 2> p) { + return IntMod<true>(x, p); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModuloInteger4)( + CppTypeFor<TypeCategory::Integer, 4> x, + CppTypeFor<TypeCategory::Integer, 4> p) { + return IntMod<true>(x, p); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModuloInteger8)( + CppTypeFor<TypeCategory::Integer, 8> x, + CppTypeFor<TypeCategory::Integer, 8> p) { + return IntMod<true>(x, p); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModuloInteger16)( + CppTypeFor<TypeCategory::Integer, 16> x, + CppTypeFor<TypeCategory::Integer, 16> p) { + return IntMod<true>(x, p); +} +CppTypeFor<TypeCategory::Real, 4> RTNAME(ModuloReal4)( + CppTypeFor<TypeCategory::Real, 4> x, CppTypeFor<TypeCategory::Real, 4> p) { + return RealMod<true>(x, p); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(ModuloReal8)( + CppTypeFor<TypeCategory::Real, 8> x, CppTypeFor<TypeCategory::Real, 8> p) { + return RealMod<true>(x, p); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(ModuloReal10)( + CppTypeFor<TypeCategory::Real, 10> x, + CppTypeFor<TypeCategory::Real, 10> p) { + return RealMod<true>(x, p); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(ModuloReal16)( + CppTypeFor<TypeCategory::Real, 16> x, + CppTypeFor<TypeCategory::Real, 16> p) { + return RealMod<true>(x, p); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Nearest4)( + CppTypeFor<TypeCategory::Real, 4> x, bool positive) { + return Nearest<24>(x, positive); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Nearest8)( + CppTypeFor<TypeCategory::Real, 8> x, bool positive) { + return Nearest<53>(x, positive); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Nearest10)( + CppTypeFor<TypeCategory::Real, 10> x, bool positive) { + return Nearest<64>(x, positive); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Nearest16)( + CppTypeFor<TypeCategory::Real, 16> x, bool positive) { + return Nearest<113>(x, positive); +} +#endif + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint4_1)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint4_2)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint4_4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint4_8)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint4_16)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint8_1)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint8_2)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint8_4)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint8_8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint8_16)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint10_1)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint10_2)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint10_4)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint10_8)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint10_16)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#else +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint16_1)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 1>>(x); +} +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint16_2)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 2>>(x); +} +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint16_4)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 4>>(x); +} +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint16_8)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 8>>(x); +} +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint16_16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Anint<CppTypeFor<TypeCategory::Integer, 16>>(x); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(RRSpacing4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return RRSpacing<24>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(RRSpacing8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return RRSpacing<53>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(RRSpacing10)( + CppTypeFor<TypeCategory::Real, 10> x) { + return RRSpacing<64>(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(RRSpacing16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return RRSpacing<113>(x); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(SetExponent4)( + CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) { + return SetExponent(x, p); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(SetExponent8)( + CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) { + return SetExponent(x, p); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(SetExponent10)( + CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) { + return SetExponent(x, p); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(SetExponent16)( + CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) { + return SetExponent(x, p); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Scale4)( + CppTypeFor<TypeCategory::Real, 4> x, std::int64_t p) { + return Scale(x, p); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Scale8)( + CppTypeFor<TypeCategory::Real, 8> x, std::int64_t p) { + return Scale(x, p); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Scale10)( + CppTypeFor<TypeCategory::Real, 10> x, std::int64_t p) { + return Scale(x, p); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Scale16)( + CppTypeFor<TypeCategory::Real, 16> x, std::int64_t p) { + return Scale(x, p); +} +#endif + +CppTypeFor<TypeCategory::Real, 4> RTNAME(Spacing4)( + CppTypeFor<TypeCategory::Real, 4> x) { + return Spacing<24>(x); +} +CppTypeFor<TypeCategory::Real, 8> RTNAME(Spacing8)( + CppTypeFor<TypeCategory::Real, 8> x) { + return Spacing<53>(x); +} +#if LONG_DOUBLE == 80 +CppTypeFor<TypeCategory::Real, 10> RTNAME(Spacing10)( + CppTypeFor<TypeCategory::Real, 10> x) { + return Spacing<64>(x); +} +#elif LONG_DOUBLE == 128 +CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)( + CppTypeFor<TypeCategory::Real, 16> x) { + return Spacing<113>(x); +} +#endif +} // extern "C" +} // namespace Fortran::runtime diff --git a/flang/runtime/numeric.h b/flang/runtime/numeric.h new file mode 100644 index 000000000000..d9c9e9e87424 --- /dev/null +++ b/flang/runtime/numeric.h @@ -0,0 +1,329 @@ +//===-- runtime/numeric.h ---------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Defines API between compiled code and the implementations of various numeric +// intrinsic functions in the runtime library. + +#ifndef FORTRAN_RUNTIME_NUMERIC_H_ +#define FORTRAN_RUNTIME_NUMERIC_H_ + +#include "cpp-type.h" +#include "entry-names.h" + +namespace Fortran::runtime { +extern "C" { + +// AINT +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint4_10)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint4_16)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint8_10)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint8_16)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Aint10_10)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Aint16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Aint16_8)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Aint16_16)( + CppTypeFor<TypeCategory::Real, 16>); + +// ANINT +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint4_10)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint4_16)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint8_10)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint8_16)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Anint10_10)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(Anint16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Anint16_8)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Anint16_16)( + CppTypeFor<TypeCategory::Real, 16>); + +// CEILING +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling4_1)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling4_2)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling4_16)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling8_1)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling8_2)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling8_16)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling10_1)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling10_2)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling10_16)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling16_1)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Ceiling16_2)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Ceiling16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Ceiling16_8)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Ceiling16_16)( + CppTypeFor<TypeCategory::Real, 16>); + +// EXPONENT is defined to return default INTEGER; support INTEGER(4 & 8) +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Exponent16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Exponent16_8)( + CppTypeFor<TypeCategory::Real, 16>); + +// FLOOR +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor4_1)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor4_2)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor4_16)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor8_1)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor8_2)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor8_16)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor10_1)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor10_2)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor10_16)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Floor16_1)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Floor16_2)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Floor16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Floor16_8)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Floor16_16)( + CppTypeFor<TypeCategory::Real, 16>); + +// FRACTION +CppTypeFor<TypeCategory::Real, 4> RTNAME(Fraction4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Fraction8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Fraction10)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Fraction16)( + CppTypeFor<TypeCategory::Real, 16>); + +// MOD & MODULO +CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModInteger1)( + CppTypeFor<TypeCategory::Integer, 1>, CppTypeFor<TypeCategory::Integer, 1>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModInteger2)( + CppTypeFor<TypeCategory::Integer, 2>, CppTypeFor<TypeCategory::Integer, 2>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModInteger4)( + CppTypeFor<TypeCategory::Integer, 4>, CppTypeFor<TypeCategory::Integer, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModInteger8)( + CppTypeFor<TypeCategory::Integer, 8>, CppTypeFor<TypeCategory::Integer, 8>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModInteger16)( + CppTypeFor<TypeCategory::Integer, 16>, + CppTypeFor<TypeCategory::Integer, 16>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(ModReal4)( + CppTypeFor<TypeCategory::Real, 4>, CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(ModReal8)( + CppTypeFor<TypeCategory::Real, 8>, CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(ModReal10)( + CppTypeFor<TypeCategory::Real, 10>, CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(ModReal16)( + CppTypeFor<TypeCategory::Real, 16>, CppTypeFor<TypeCategory::Real, 16>); + +CppTypeFor<TypeCategory::Integer, 1> RTNAME(ModuloInteger1)( + CppTypeFor<TypeCategory::Integer, 1>, CppTypeFor<TypeCategory::Integer, 1>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(ModuloInteger2)( + CppTypeFor<TypeCategory::Integer, 2>, CppTypeFor<TypeCategory::Integer, 2>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(ModuloInteger4)( + CppTypeFor<TypeCategory::Integer, 4>, CppTypeFor<TypeCategory::Integer, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(ModuloInteger8)( + CppTypeFor<TypeCategory::Integer, 8>, CppTypeFor<TypeCategory::Integer, 8>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(ModuloInteger16)( + CppTypeFor<TypeCategory::Integer, 16>, + CppTypeFor<TypeCategory::Integer, 16>); +CppTypeFor<TypeCategory::Real, 4> RTNAME(ModuloReal4)( + CppTypeFor<TypeCategory::Real, 4>, CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(ModuloReal8)( + CppTypeFor<TypeCategory::Real, 8>, CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(ModuloReal10)( + CppTypeFor<TypeCategory::Real, 10>, CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(ModuloReal16)( + CppTypeFor<TypeCategory::Real, 16>, CppTypeFor<TypeCategory::Real, 16>); + +// NINT +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint4_1)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint4_2)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint4_4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint4_8)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint4_16)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint8_1)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint8_2)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint8_4)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint8_8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint8_16)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint10_1)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint10_2)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint10_4)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint10_8)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint10_16)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Integer, 1> RTNAME(Nint16_1)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 2> RTNAME(Nint16_2)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 4> RTNAME(Nint16_4)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 8> RTNAME(Nint16_8)( + CppTypeFor<TypeCategory::Real, 16>); +CppTypeFor<TypeCategory::Integer, 16> RTNAME(Nint16_16)( + CppTypeFor<TypeCategory::Real, 16>); + +// NEAREST +// The second argument to NEAREST is the result of a comparison +// to zero (i.e., S > 0) +CppTypeFor<TypeCategory::Real, 4> RTNAME(Nearest4)( + CppTypeFor<TypeCategory::Real, 4>, bool positive); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Nearest8)( + CppTypeFor<TypeCategory::Real, 8>, bool positive); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Nearest10)( + CppTypeFor<TypeCategory::Real, 10>, bool positive); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Nearest16)( + CppTypeFor<TypeCategory::Real, 16>, bool positive); + +// RRSPACING +CppTypeFor<TypeCategory::Real, 4> RTNAME(RRSpacing4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(RRSpacing8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(RRSpacing10)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(RRSpacing16)( + CppTypeFor<TypeCategory::Real, 16>); + +// SET_EXPONENT's I= argument can be any INTEGER kind; upcast it to 64-bit +CppTypeFor<TypeCategory::Real, 4> RTNAME(SetExponent4)( + CppTypeFor<TypeCategory::Real, 4>, std::int64_t); +CppTypeFor<TypeCategory::Real, 8> RTNAME(SetExponent8)( + CppTypeFor<TypeCategory::Real, 8>, std::int64_t); +CppTypeFor<TypeCategory::Real, 10> RTNAME(SetExponent10)( + CppTypeFor<TypeCategory::Real, 10>, std::int64_t); +CppTypeFor<TypeCategory::Real, 16> RTNAME(SetExponent16)( + CppTypeFor<TypeCategory::Real, 16>, std::int64_t); + +// SCALE +CppTypeFor<TypeCategory::Real, 4> RTNAME(Scale4)( + CppTypeFor<TypeCategory::Real, 4>, std::int64_t); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Scale8)( + CppTypeFor<TypeCategory::Real, 8>, std::int64_t); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Scale10)( + CppTypeFor<TypeCategory::Real, 10>, std::int64_t); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Scale16)( + CppTypeFor<TypeCategory::Real, 16>, std::int64_t); + +// SPACING +CppTypeFor<TypeCategory::Real, 4> RTNAME(Spacing4)( + CppTypeFor<TypeCategory::Real, 4>); +CppTypeFor<TypeCategory::Real, 8> RTNAME(Spacing8)( + CppTypeFor<TypeCategory::Real, 8>); +CppTypeFor<TypeCategory::Real, 10> RTNAME(Spacing10)( + CppTypeFor<TypeCategory::Real, 10>); +CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)( + CppTypeFor<TypeCategory::Real, 16>); +} // extern "C" +} // namespace Fortran::runtime +#endif // FORTRAN_RUNTIME_NUMERIC_H_ diff --git a/flang/unittests/RuntimeGTest/CMakeLists.txt b/flang/unittests/RuntimeGTest/CMakeLists.txt index ad6377e0babd..1d4e2d01508e 100644 --- a/flang/unittests/RuntimeGTest/CMakeLists.txt +++ b/flang/unittests/RuntimeGTest/CMakeLists.txt @@ -1,6 +1,7 @@ add_flang_unittest(FlangRuntimeTests CharacterTest.cpp CrashHandlerFixture.cpp + Numeric.cpp NumericalFormatTest.cpp Reduction.cpp RuntimeCrashTest.cpp diff --git a/flang/unittests/RuntimeGTest/Numeric.cpp b/flang/unittests/RuntimeGTest/Numeric.cpp new file mode 100644 index 000000000000..60a878dbd280 --- /dev/null +++ b/flang/unittests/RuntimeGTest/Numeric.cpp @@ -0,0 +1,168 @@ +//===-- flang/unittests/RuntimeGTest/Numeric.cpp ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "../../runtime/numeric.h" +#include "gtest/gtest.h" +#include <cmath> +#include <limits> + +using namespace Fortran::runtime; +using Fortran::common::TypeCategory; +template <int KIND> using Int = CppTypeFor<TypeCategory::Integer, KIND>; +template <int KIND> using Real = CppTypeFor<TypeCategory::Real, KIND>; + +// Simple tests of numeric intrinsic functions using examples from Fortran 2018 + +TEST(Numeric, Aint) { + EXPECT_EQ(RTNAME(Aint4_4)(Real<4>{3.7}), 3.0); + EXPECT_EQ(RTNAME(Aint8_4)(Real<8>{-3.7}), -3.0); + EXPECT_EQ(RTNAME(Aint8_8)(Real<8>{0}), 0.0); + EXPECT_EQ(RTNAME(Aint4_4)(std::numeric_limits<Real<4>>::infinity()), + std::numeric_limits<Real<4>>::infinity()); + EXPECT_TRUE( + std::isnan(RTNAME(Aint8_8)(std::numeric_limits<Real<8>>::quiet_NaN()))); +} + +TEST(Numeric, Anint) { + EXPECT_EQ(RTNAME(Anint4_4)(Real<4>{2.783}), 3.0); + EXPECT_EQ(RTNAME(Anint8_4)(Real<8>{-2.783}), -3.0); + EXPECT_EQ(RTNAME(Anint4_4)(Real<4>{2.5}), 3.0); + EXPECT_EQ(RTNAME(Anint8_4)(Real<8>{-2.5}), -3.0); + EXPECT_EQ(RTNAME(Anint8_8)(Real<8>{0}), 0.0); + EXPECT_EQ(RTNAME(Anint4_4)(std::numeric_limits<Real<4>>::infinity()), + std::numeric_limits<Real<4>>::infinity()); + EXPECT_TRUE( + std::isnan(RTNAME(Aint8_8)(std::numeric_limits<Real<8>>::quiet_NaN()))); +} + +TEST(Numeric, Ceiling) { + EXPECT_EQ(RTNAME(Ceiling4_4)(Real<4>{3.7}), 4); + EXPECT_EQ(RTNAME(Ceiling8_8)(Real<8>{-3.7}), -3); + EXPECT_EQ(RTNAME(Ceiling4_1)(Real<4>{0}), 0); + EXPECT_EQ(RTNAME(Ceiling4_4)(std::numeric_limits<Real<4>>::infinity()), + std::numeric_limits<Int<4>>::min()); + EXPECT_EQ(RTNAME(Ceiling4_4)(std::numeric_limits<Real<4>>::quiet_NaN()), + std::numeric_limits<Int<4>>::min()); +} + +TEST(Numeric, Floor) { + EXPECT_EQ(RTNAME(Floor4_4)(Real<4>{3.7}), 3); + EXPECT_EQ(RTNAME(Floor8_8)(Real<8>{-3.7}), -4); + EXPECT_EQ(RTNAME(Floor4_1)(Real<4>{0}), 0); + EXPECT_EQ(RTNAME(Floor4_4)(std::numeric_limits<Real<4>>::infinity()), + std::numeric_limits<Int<4>>::min()); + EXPECT_EQ(RTNAME(Floor4_4)(std::numeric_limits<Real<4>>::quiet_NaN()), + std::numeric_limits<Int<4>>::min()); +} + +TEST(Numeric, Exponent) { + EXPECT_EQ(RTNAME(Exponent4_4)(Real<4>{0}), 0); + EXPECT_EQ(RTNAME(Exponent4_8)(Real<4>{1.0}), 1); + EXPECT_EQ(RTNAME(Exponent8_4)(Real<8>{4.1}), 3); + EXPECT_EQ(RTNAME(Exponent8_8)(std::numeric_limits<Real<8>>::infinity()), + std::numeric_limits<Int<8>>::max()); + EXPECT_EQ(RTNAME(Exponent8_8)(std::numeric_limits<Real<8>>::quiet_NaN()), + std::numeric_limits<Int<8>>::max()); +} + +TEST(Numeric, Fraction) { + EXPECT_EQ(RTNAME(Fraction4)(Real<4>{0}), 0); + EXPECT_EQ(RTNAME(Fraction8)(Real<8>{3.0}), 0.75); + EXPECT_TRUE( + std::isnan(RTNAME(Fraction4)(std::numeric_limits<Real<4>>::infinity()))); + EXPECT_TRUE( + std::isnan(RTNAME(Fraction8)(std::numeric_limits<Real<8>>::quiet_NaN()))); +} + +TEST(Numeric, Mod) { + EXPECT_EQ(RTNAME(ModInteger1)(Int<1>{8}, Int<1>(5)), 3); + EXPECT_EQ(RTNAME(ModInteger4)(Int<4>{-8}, Int<4>(5)), -3); + EXPECT_EQ(RTNAME(ModInteger2)(Int<2>{8}, Int<2>(-5)), 3); + EXPECT_EQ(RTNAME(ModInteger8)(Int<8>{-8}, Int<8>(-5)), -3); + EXPECT_EQ(RTNAME(ModReal4)(Real<4>{8.0}, Real<4>(5.0)), 3.0); + EXPECT_EQ(RTNAME(ModReal4)(Real<4>{-8.0}, Real<4>(5.0)), -3.0); + EXPECT_EQ(RTNAME(ModReal8)(Real<8>{8.0}, Real<8>(-5.0)), 3.0); + EXPECT_EQ(RTNAME(ModReal8)(Real<8>{-8.0}, Real<8>(-5.0)), -3.0); +} + +TEST(Numeric, Modulo) { + EXPECT_EQ(RTNAME(ModuloInteger1)(Int<1>{8}, Int<1>(5)), 3); + EXPECT_EQ(RTNAME(ModuloInteger4)(Int<4>{-8}, Int<4>(5)), 2); + EXPECT_EQ(RTNAME(ModuloInteger2)(Int<2>{8}, Int<2>(-5)), -2); + EXPECT_EQ(RTNAME(ModuloInteger8)(Int<8>{-8}, Int<8>(-5)), -3); + EXPECT_EQ(RTNAME(ModuloReal4)(Real<4>{8.0}, Real<4>(5.0)), 3.0); + EXPECT_EQ(RTNAME(ModuloReal4)(Real<4>{-8.0}, Real<4>(5.0)), 2.0); + EXPECT_EQ(RTNAME(ModuloReal8)(Real<8>{8.0}, Real<8>(-5.0)), -2.0); + EXPECT_EQ(RTNAME(ModuloReal8)(Real<8>{-8.0}, Real<8>(-5.0)), -3.0); +} + +TEST(Numeric, Nearest) { + EXPECT_EQ(RTNAME(Nearest4)(Real<4>{0}, true), + std::numeric_limits<Real<4>>::denorm_min()); + EXPECT_EQ(RTNAME(Nearest4)(Real<4>{3.0}, true), + Real<4>{3.0} + std::ldexp(Real<4>{1.0}, -22)); + EXPECT_EQ(RTNAME(Nearest8)(Real<8>{1.0}, true), + Real<8>{1.0} + std::ldexp(Real<8>{1.0}, -52)); + EXPECT_EQ(RTNAME(Nearest8)(Real<8>{1.0}, false), + Real<8>{1.0} - std::ldexp(Real<8>{1.0}, -52)); +} + +TEST(Numeric, Nint) { + EXPECT_EQ(RTNAME(Nint4_4)(Real<4>{2.783}), 3); + EXPECT_EQ(RTNAME(Nint8_4)(Real<8>{-2.783}), -3); + EXPECT_EQ(RTNAME(Nint4_4)(Real<4>{2.5}), 3); + EXPECT_EQ(RTNAME(Nint8_4)(Real<8>{-2.5}), -3); + EXPECT_EQ(RTNAME(Nint8_8)(Real<8>{0}), 0); + EXPECT_EQ(RTNAME(Nint4_4)(std::numeric_limits<Real<4>>::infinity()), + std::numeric_limits<Int<4>>::min()); + EXPECT_EQ(RTNAME(Nint4_4)(std::numeric_limits<Real<4>>::quiet_NaN()), + std::numeric_limits<Int<4>>::min()); +} + +TEST(Numeric, RRSpacing) { + EXPECT_EQ(RTNAME(RRSpacing8)(Real<8>{0}), 0); + EXPECT_EQ(RTNAME(RRSpacing4)(Real<4>{-3.0}), 0.75 * (1 << 24)); + EXPECT_EQ(RTNAME(RRSpacing8)(Real<8>{-3.0}), 0.75 * (std::int64_t{1} << 53)); + EXPECT_TRUE( + std::isnan(RTNAME(RRSpacing4)(std::numeric_limits<Real<4>>::infinity()))); + EXPECT_TRUE(std::isnan( + RTNAME(RRSpacing8)(std::numeric_limits<Real<8>>::quiet_NaN()))); +} + +TEST(Numeric, Scale) { + EXPECT_EQ(RTNAME(Scale4)(Real<4>{0}, 0), 0); + EXPECT_EQ(RTNAME(Scale4)(Real<4>{1.0}, 0), 1.0); + EXPECT_EQ(RTNAME(Scale4)(Real<4>{1.0}, 1), 2.0); + EXPECT_EQ(RTNAME(Scale4)(Real<4>{1.0}, -1), 0.5); + EXPECT_TRUE( + std::isinf(RTNAME(Scale4)(std::numeric_limits<Real<4>>::infinity(), 1))); + EXPECT_TRUE( + std::isnan(RTNAME(Scale8)(std::numeric_limits<Real<8>>::quiet_NaN(), 1))); +} + +TEST(Numeric, SetExponent) { + EXPECT_EQ(RTNAME(SetExponent4)(Real<4>{0}, 0), 0); + EXPECT_EQ(RTNAME(SetExponent8)(Real<8>{0}, 666), 0); + EXPECT_EQ(RTNAME(SetExponent8)(Real<8>{3.0}, 0), 1.5); + EXPECT_EQ(RTNAME(SetExponent4)(Real<4>{1.0}, 0), 1.0); + EXPECT_EQ(RTNAME(SetExponent4)(Real<4>{1.0}, 1), 2.0); + EXPECT_EQ(RTNAME(SetExponent4)(Real<4>{1.0}, -1), 0.5); + EXPECT_TRUE(std::isnan( + RTNAME(SetExponent4)(std::numeric_limits<Real<4>>::infinity(), 1))); + EXPECT_TRUE(std::isnan( + RTNAME(SetExponent8)(std::numeric_limits<Real<8>>::quiet_NaN(), 1))); +} + +TEST(Numeric, Spacing) { + EXPECT_EQ(RTNAME(Spacing8)(Real<8>{0}), std::numeric_limits<Real<8>>::min()); + EXPECT_EQ(RTNAME(Spacing4)(Real<4>{3.0}), std::ldexp(Real<4>{1.0}, -22)); + EXPECT_TRUE( + std::isnan(RTNAME(Spacing4)(std::numeric_limits<Real<4>>::infinity()))); + EXPECT_TRUE( + std::isnan(RTNAME(Spacing8)(std::numeric_limits<Real<8>>::quiet_NaN()))); +} |