diff options
24 files changed, 301 insertions, 227 deletions
diff --git a/libc/src/math/ceil.cpp b/libc/src/math/ceil.cpp index c9af520..06ef903 100644 --- a/libc/src/math/ceil.cpp +++ b/libc/src/math/ceil.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/ceilf.cpp b/libc/src/math/ceilf.cpp index 2d2fb90..d44e273 100644 --- a/libc/src/math/ceilf.cpp +++ b/libc/src/math/ceilf.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/fabs.cpp b/libc/src/math/fabs.cpp index 15c60e8..ff78f1b 100644 --- a/libc/src/math/fabs.cpp +++ b/libc/src/math/fabs.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/BasicOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/fabsf.cpp b/libc/src/math/fabsf.cpp index dd2b055..9aa1419 100644 --- a/libc/src/math/fabsf.cpp +++ b/libc/src/math/fabsf.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/BasicOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/floor.cpp b/libc/src/math/floor.cpp index b2d5f87..cc2fde5 100644 --- a/libc/src/math/floor.cpp +++ b/libc/src/math/floor.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/floorf.cpp b/libc/src/math/floorf.cpp index 397602e..e220ab4 100644 --- a/libc/src/math/floorf.cpp +++ b/libc/src/math/floorf.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/round.cpp b/libc/src/math/round.cpp index 0a6e548..44a1119 100644 --- a/libc/src/math/round.cpp +++ b/libc/src/math/round.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/roundf.cpp b/libc/src/math/roundf.cpp index bdfcd0a..8cbb315 100644 --- a/libc/src/math/roundf.cpp +++ b/libc/src/math/roundf.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/trunc.cpp b/libc/src/math/trunc.cpp index 7e42fe4..0749e11 100644 --- a/libc/src/math/trunc.cpp +++ b/libc/src/math/trunc.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/src/math/truncf.cpp b/libc/src/math/truncf.cpp index c567865..0372571 100644 --- a/libc/src/math/truncf.cpp +++ b/libc/src/math/truncf.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/common.h" -#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/NearestIntegerOperations.h" namespace __llvm_libc { diff --git a/libc/test/src/math/cosf_test.cpp b/libc/test/src/math/cosf_test.cpp index 3ba0fcd..ac6020e 100644 --- a/libc/test/src/math/cosf_test.cpp +++ b/libc/test/src/math/cosf_test.cpp @@ -13,6 +13,7 @@ #include "test/src/math/sdcomp26094.h" #include "utils/CPP/Array.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/test/src/math/exp2f_test.cpp b/libc/test/src/math/exp2f_test.cpp index c900ec6..fe9955f 100644 --- a/libc/test/src/math/exp2f_test.cpp +++ b/libc/test/src/math/exp2f_test.cpp @@ -11,6 +11,7 @@ #include "src/errno/llvmlibc_errno.h" #include "src/math/exp2f.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/test/src/math/expf_test.cpp b/libc/test/src/math/expf_test.cpp index c99058d..577f5e4 100644 --- a/libc/test/src/math/expf_test.cpp +++ b/libc/test/src/math/expf_test.cpp @@ -11,6 +11,7 @@ #include "src/errno/llvmlibc_errno.h" #include "src/math/expf.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/test/src/math/frexp_test.cpp b/libc/test/src/math/frexp_test.cpp index a7fb953..f828d51 100644 --- a/libc/test/src/math/frexp_test.cpp +++ b/libc/test/src/math/frexp_test.cpp @@ -8,7 +8,9 @@ #include "include/math.h" #include "src/math/frexp.h" +#include "utils/FPUtil/BasicOperations.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/UnitTest/Test.h" diff --git a/libc/test/src/math/frexpf_test.cpp b/libc/test/src/math/frexpf_test.cpp index d90532b..e15f384 100644 --- a/libc/test/src/math/frexpf_test.cpp +++ b/libc/test/src/math/frexpf_test.cpp @@ -9,7 +9,9 @@ #include "include/math.h" #include "src/math/frexpf.h" +#include "utils/FPUtil/BasicOperations.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/test/src/math/modf_test.cpp b/libc/test/src/math/modf_test.cpp index fa4436d6..774ad8b6 100644 --- a/libc/test/src/math/modf_test.cpp +++ b/libc/test/src/math/modf_test.cpp @@ -8,9 +8,11 @@ #include "include/math.h" #include "src/math/modf.h" +#include "utils/FPUtil/BasicOperations.h" #include "utils/FPUtil/BitPatterns.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" +#include "utils/FPUtil/NearestIntegerOperations.h" #include "utils/UnitTest/Test.h" using __llvm_libc::fputil::valueAsBits; diff --git a/libc/test/src/math/modff_test.cpp b/libc/test/src/math/modff_test.cpp index db3b7c8..fbd3b86 100644 --- a/libc/test/src/math/modff_test.cpp +++ b/libc/test/src/math/modff_test.cpp @@ -9,9 +9,11 @@ #include "include/math.h" #include "src/math/modff.h" +#include "utils/FPUtil/BasicOperations.h" #include "utils/FPUtil/BitPatterns.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" +#include "utils/FPUtil/NearestIntegerOperations.h" #include "utils/UnitTest/Test.h" using __llvm_libc::fputil::valueAsBits; diff --git a/libc/test/src/math/sincosf_test.cpp b/libc/test/src/math/sincosf_test.cpp index 66b247a..2211ef1 100644 --- a/libc/test/src/math/sincosf_test.cpp +++ b/libc/test/src/math/sincosf_test.cpp @@ -13,6 +13,7 @@ #include "test/src/math/sdcomp26094.h" #include "utils/CPP/Array.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/test/src/math/sinf_test.cpp b/libc/test/src/math/sinf_test.cpp index 115359b..17c6671 100644 --- a/libc/test/src/math/sinf_test.cpp +++ b/libc/test/src/math/sinf_test.cpp @@ -13,6 +13,7 @@ #include "test/src/math/sdcomp26094.h" #include "utils/CPP/Array.h" #include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/ClassificationFunctions.h" #include "utils/FPUtil/FloatOperations.h" #include "utils/FPUtil/FloatProperties.h" #include "utils/MPFRWrapper/MPFRUtils.h" diff --git a/libc/utils/FPUtil/BasicOperations.h b/libc/utils/FPUtil/BasicOperations.h new file mode 100644 index 0000000..d5c7004 --- /dev/null +++ b/libc/utils/FPUtil/BasicOperations.h @@ -0,0 +1,21 @@ +//===-- Basic operations on floating point numbers --------------*- 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 "FloatOperations.h" + +namespace __llvm_libc { +namespace fputil { + +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline T abs(T x) { + return valueFromBits(absBits(x)); +} + +} // namespace fputil +} // namespace __llvm_libc diff --git a/libc/utils/FPUtil/ClassificationFunctions.h b/libc/utils/FPUtil/ClassificationFunctions.h new file mode 100644 index 0000000..a80e349 --- /dev/null +++ b/libc/utils/FPUtil/ClassificationFunctions.h @@ -0,0 +1,90 @@ +//===-- Floating point classification functions -----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UTILS_FPUTIL_CLASSIFICATION_FUNCTIONS_H +#define LLVM_LIBC_UTILS_FPUTIL_CLASSIFICATION_FUNCTIONS_H + +#include "BitPatterns.h" +#include "FloatOperations.h" +#include "FloatProperties.h" + +#include "utils/CPP/TypeTraits.h" + +namespace __llvm_libc { +namespace fputil { + +template <typename BitsType> static inline bool bitsAreInf(BitsType bits) { + using FPType = typename FloatType<BitsType>::Type; + return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) && + ((bits & FloatProperties<FPType>::mantissaMask) == 0); +} + +// Return true if x is infinity (positive or negative.) +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline bool isInf(T x) { + return bitsAreInf(valueAsBits(x)); +} + +template <typename BitsType> static inline bool bitsAreNaN(BitsType bits) { + using FPType = typename FloatType<BitsType>::Type; + return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) && + ((bits & FloatProperties<FPType>::mantissaMask) != 0); +} + +// Return true if x is a NAN (quiet or signalling.) +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline bool isNaN(T x) { + return bitsAreNaN(valueAsBits(x)); +} + +template <typename BitsType> static inline bool bitsAreInfOrNaN(BitsType bits) { + using FPType = typename FloatType<BitsType>::Type; + return (bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf; +} + +template <typename BitsType> static inline bool bitsAreZero(BitsType bits) { + using FPType = typename FloatType<BitsType>::Type; + return (bits == BitPatterns<FPType>::zero) || + (bits == BitPatterns<FPType>::negZero); +} + +// Return true if x is any kind of NaN or infinity. +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline bool isInfOrNaN(T x) { + return bitsAreInfOrNaN(valueAsBits(x)); +} + +// Return true if x is a quiet NAN. +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline bool isQuietNaN(T x) { + using Properties = FloatProperties<T>; + using BitsType = typename FloatProperties<T>::BitsType; + BitsType bits = valueAsBits(x); + return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) && + ((bits & Properties::quietNaNMask) != 0); +} + +// Return true if x is a quiet NAN with sign bit set. +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline bool isNegativeQuietNaN(T x) { + using Properties = FloatProperties<T>; + using BitsType = typename FloatProperties<T>::BitsType; + BitsType bits = valueAsBits(x); + return ((bits & BitPatterns<T>::negInf) == BitPatterns<T>::negInf) && + ((bits & Properties::quietNaNMask) != 0); +} + +} // namespace fputil +} // namespace __llvm_libc + +#endif // LLVM_LIBC_UTILS_FPUTIL_CLASSIFICATION_FUNCTIONS_H diff --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h index b599aad..0739548f 100644 --- a/libc/utils/FPUtil/FloatOperations.h +++ b/libc/utils/FPUtil/FloatOperations.h @@ -57,222 +57,6 @@ static inline int getExponent(T x) { return getExponentFromBits(valueAsBits(x)); } -template <typename BitsType> static inline bool bitsAreInf(BitsType bits) { - using FPType = typename FloatType<BitsType>::Type; - return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) && - ((bits & FloatProperties<FPType>::mantissaMask) == 0); -} - -// Return true if x is infinity (positive or negative.) -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline bool isInf(T x) { - return bitsAreInf(valueAsBits(x)); -} - -template <typename BitsType> static inline bool bitsAreNaN(BitsType bits) { - using FPType = typename FloatType<BitsType>::Type; - return ((bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf) && - ((bits & FloatProperties<FPType>::mantissaMask) != 0); -} - -// Return true if x is a NAN (quiet or signalling.) -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline bool isNaN(T x) { - return bitsAreNaN(valueAsBits(x)); -} - -template <typename BitsType> static inline bool bitsAreInfOrNaN(BitsType bits) { - using FPType = typename FloatType<BitsType>::Type; - return (bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf; -} - -template <typename BitsType> static inline bool bitsAreZero(BitsType bits) { - using FPType = typename FloatType<BitsType>::Type; - return (bits == BitPatterns<FPType>::zero) || - (bits == BitPatterns<FPType>::negZero); -} - -// Return true if x is any kind of NaN or infinity. -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline bool isInfOrNaN(T x) { - return bitsAreInfOrNaN(valueAsBits(x)); -} - -// Return true if x is a quiet NAN. -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline bool isQuietNaN(T x) { - using Properties = FloatProperties<T>; - using BitsType = typename FloatProperties<T>::BitsType; - BitsType bits = valueAsBits(x); - return ((bits & BitPatterns<T>::inf) == BitPatterns<T>::inf) && - ((bits & Properties::quietNaNMask) != 0); -} - -// Return true if x is a quiet NAN with sign bit set. -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline bool isNegativeQuietNaN(T x) { - using Properties = FloatProperties<T>; - using BitsType = typename FloatProperties<T>::BitsType; - BitsType bits = valueAsBits(x); - return ((bits & BitPatterns<T>::negInf) == BitPatterns<T>::negInf) && - ((bits & Properties::quietNaNMask) != 0); -} - -// Return the absolute value of x. -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline T abs(T x) { - return valueFromBits(absBits(x)); -} - -// Return the trucated value of x. If x is non-negative, then the return value -// is greatest integer less than or equal to x. Otherwise, return the smallest -// integer greater than or equal to x. That is, return the integer value rounded -// toward zero. -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline T trunc(T x) { - using Properties = FloatProperties<T>; - using BitsType = typename FloatProperties<T>::BitsType; - - BitsType bits = valueAsBits(x); - - // If x is infinity, NaN or zero, return it. - if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) - return x; - - int exponent = getExponentFromBits(bits); - - // If the exponent is greater than the most negative mantissa - // exponent, then x is already an integer. - if (exponent >= static_cast<int>(Properties::mantissaWidth)) - return x; - - // If the exponent is such that abs(x) is less than 1, then return 0. - if (exponent <= -1) { - if (Properties::signMask & bits) - return T(-0.0); - else - return T(0.0); - } - - uint32_t trimSize = Properties::mantissaWidth - exponent; - return valueFromBits((bits >> trimSize) << trimSize); -} - -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline T ceil(T x) { - using Properties = FloatProperties<T>; - using BitsType = typename FloatProperties<T>::BitsType; - - BitsType bits = valueAsBits(x); - - // If x is infinity NaN or zero, return it. - if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) - return x; - - bool isNeg = bits & Properties::signMask; - int exponent = getExponentFromBits(bits); - - // If the exponent is greater than the most negative mantissa - // exponent, then x is already an integer. - if (exponent >= static_cast<int>(Properties::mantissaWidth)) - return x; - - if (exponent <= -1) { - if (isNeg) - return T(-0.0); - else - return T(1.0); - } - - uint32_t trimSize = Properties::mantissaWidth - exponent; - // If x is already an integer, return it. - if ((bits << (Properties::bitWidth - trimSize)) == 0) - return x; - - BitsType truncBits = (bits >> trimSize) << trimSize; - T truncValue = valueFromBits(truncBits); - - // If x is negative, the ceil operation is equivalent to the trunc operation. - if (isNeg) - return truncValue; - - return truncValue + T(1.0); -} - -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline T floor(T x) { - auto bits = valueAsBits(x); - if (FloatProperties<T>::signMask & bits) { - return -ceil(-x); - } else { - return trunc(x); - } -} - -template <typename T, - cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> -static inline T round(T x) { - using Properties = FloatProperties<T>; - using BitsType = typename FloatProperties<T>::BitsType; - - BitsType bits = valueAsBits(x); - - // If x is infinity, NaN or zero, return it. - if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) - return x; - - bool isNeg = bits & Properties::signMask; - int exponent = getExponentFromBits(bits); - - // If the exponent is greater than the most negative mantissa - // exponent, then x is already an integer. - if (exponent >= static_cast<int>(Properties::mantissaWidth)) - return x; - - if (exponent == -1) { - // Absolute value of x is greater than equal to 0.5 but less than 1. - if (isNeg) - return T(-1.0); - else - return T(1.0); - } - - if (exponent <= -2) { - // Absolute value of x is less than 0.5. - if (isNeg) - return T(-0.0); - else - return T(0.0); - } - - uint32_t trimSize = Properties::mantissaWidth - exponent; - // If x is already an integer, return it. - if ((bits << (Properties::bitWidth - trimSize)) == 0) - return x; - - BitsType truncBits = (bits >> trimSize) << trimSize; - T truncValue = valueFromBits(truncBits); - - if ((bits & (BitsType(1) << (trimSize - 1))) == 0) { - // Franctional part is less than 0.5 so round value is the - // same as the trunc value. - return truncValue; - } - - if (isNeg) - return truncValue - T(1.0); - else - return truncValue + T(1.0); -} } // namespace fputil } // namespace __llvm_libc diff --git a/libc/utils/FPUtil/ManipulationFunctions.h b/libc/utils/FPUtil/ManipulationFunctions.h index a59c0a7..b1e06f7 100644 --- a/libc/utils/FPUtil/ManipulationFunctions.h +++ b/libc/utils/FPUtil/ManipulationFunctions.h @@ -1,4 +1,4 @@ -//===-- Common operations on floating point numbers -------------*- C++ -*-===// +//===-- Floating-point manipulation functions -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,10 @@ //===----------------------------------------------------------------------===// #include "BitPatterns.h" +#include "ClassificationFunctions.h" #include "FloatOperations.h" #include "FloatProperties.h" +#include "NearestIntegerOperations.h" #include "utils/CPP/TypeTraits.h" diff --git a/libc/utils/FPUtil/NearestIntegerOperations.h b/libc/utils/FPUtil/NearestIntegerOperations.h new file mode 100644 index 0000000..7f93de6 --- /dev/null +++ b/libc/utils/FPUtil/NearestIntegerOperations.h @@ -0,0 +1,164 @@ +//===-- Nearest integer floating-point operations ---------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H +#define LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H + +#include "ClassificationFunctions.h" +#include "FloatOperations.h" +#include "FloatProperties.h" + +#include "utils/CPP/TypeTraits.h" + +namespace __llvm_libc { +namespace fputil { + +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline T trunc(T x) { + using Properties = FloatProperties<T>; + using BitsType = typename FloatProperties<T>::BitsType; + + BitsType bits = valueAsBits(x); + + // If x is infinity, NaN or zero, return it. + if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + return x; + + int exponent = getExponentFromBits(bits); + + // If the exponent is greater than the most negative mantissa + // exponent, then x is already an integer. + if (exponent >= static_cast<int>(Properties::mantissaWidth)) + return x; + + // If the exponent is such that abs(x) is less than 1, then return 0. + if (exponent <= -1) { + if (Properties::signMask & bits) + return T(-0.0); + else + return T(0.0); + } + + uint32_t trimSize = Properties::mantissaWidth - exponent; + return valueFromBits((bits >> trimSize) << trimSize); +} + +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline T ceil(T x) { + using Properties = FloatProperties<T>; + using BitsType = typename FloatProperties<T>::BitsType; + + BitsType bits = valueAsBits(x); + + // If x is infinity NaN or zero, return it. + if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + return x; + + bool isNeg = bits & Properties::signMask; + int exponent = getExponentFromBits(bits); + + // If the exponent is greater than the most negative mantissa + // exponent, then x is already an integer. + if (exponent >= static_cast<int>(Properties::mantissaWidth)) + return x; + + if (exponent <= -1) { + if (isNeg) + return T(-0.0); + else + return T(1.0); + } + + uint32_t trimSize = Properties::mantissaWidth - exponent; + // If x is already an integer, return it. + if ((bits << (Properties::bitWidth - trimSize)) == 0) + return x; + + BitsType truncBits = (bits >> trimSize) << trimSize; + T truncValue = valueFromBits(truncBits); + + // If x is negative, the ceil operation is equivalent to the trunc operation. + if (isNeg) + return truncValue; + + return truncValue + T(1.0); +} + +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline T floor(T x) { + auto bits = valueAsBits(x); + if (FloatProperties<T>::signMask & bits) { + return -ceil(-x); + } else { + return trunc(x); + } +} + +template <typename T, + cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0> +static inline T round(T x) { + using Properties = FloatProperties<T>; + using BitsType = typename FloatProperties<T>::BitsType; + + BitsType bits = valueAsBits(x); + + // If x is infinity, NaN or zero, return it. + if (bitsAreInfOrNaN(bits) || bitsAreZero(bits)) + return x; + + bool isNeg = bits & Properties::signMask; + int exponent = getExponentFromBits(bits); + + // If the exponent is greater than the most negative mantissa + // exponent, then x is already an integer. + if (exponent >= static_cast<int>(Properties::mantissaWidth)) + return x; + + if (exponent == -1) { + // Absolute value of x is greater than equal to 0.5 but less than 1. + if (isNeg) + return T(-1.0); + else + return T(1.0); + } + + if (exponent <= -2) { + // Absolute value of x is less than 0.5. + if (isNeg) + return T(-0.0); + else + return T(0.0); + } + + uint32_t trimSize = Properties::mantissaWidth - exponent; + // If x is already an integer, return it. + if ((bits << (Properties::bitWidth - trimSize)) == 0) + return x; + + BitsType truncBits = (bits >> trimSize) << trimSize; + T truncValue = valueFromBits(truncBits); + + if ((bits & (BitsType(1) << (trimSize - 1))) == 0) { + // Franctional part is less than 0.5 so round value is the + // same as the trunc value. + return truncValue; + } + + if (isNeg) + return truncValue - T(1.0); + else + return truncValue + T(1.0); +} + +} // namespace fputil +} // namespace __llvm_libc + +#endif // LLVM_LIBC_UTILS_FPUTIL_NEAREST_INTEGER_OPERATIONS_H |