[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
This commit is contained in:
peter klausler 2021-04-01 12:59:59 -07:00
parent 43ceb74eb1
commit 5f6c5c63c7
5 changed files with 1272 additions and 0 deletions

View file

@ -51,6 +51,7 @@ add_flang_library(FortranRuntime
io-stmt.cpp
main.cpp
memory.cpp
numeric.cpp
reduction.cpp
stat.cpp
stop.cpp

773
flang/runtime/numeric.cpp Normal file
View file

@ -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

329
flang/runtime/numeric.h Normal file
View file

@ -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_

View file

@ -1,6 +1,7 @@
add_flang_unittest(FlangRuntimeTests
CharacterTest.cpp
CrashHandlerFixture.cpp
Numeric.cpp
NumericalFormatTest.cpp
Reduction.cpp
RuntimeCrashTest.cpp

View file

@ -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())));
}