aboutsummaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorpeter klausler <pklausler@nvidia.com>2021-04-01 12:59:59 -0700
committerpeter klausler <pklausler@nvidia.com>2021-04-01 15:39:32 -0700
commit5f6c5c63c7c21cc9cf1c2b21759e40aa4854d496 (patch)
tree771a70304a16e3f66e05d3b79d621b1747722538 /flang
parentllvm-shlib: Create object libraries for each component and link against them (diff)
downloadllvm-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.txt1
-rw-r--r--flang/runtime/numeric.cpp773
-rw-r--r--flang/runtime/numeric.h329
-rw-r--r--flang/unittests/RuntimeGTest/CMakeLists.txt1
-rw-r--r--flang/unittests/RuntimeGTest/Numeric.cpp168
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())));
+}