cmath: Skip Libc for integral types in isinf, etc.

For std::isinf, the standard requires effectively calling isinf as
double from Libc for integral types. But integral types are never
infinite; we don't need to call Libc to return false.

Also short-circuit other functions where Libc won't have interesting
answers: signbit, fpclassify, isfinite, isnan, and isnormal.

I added correctness tests for integral types since we're no longer
deferring to Libc.

In review it was pointed out that in future revisions of the C++
standard we may add more types to std::is_arithmetic (e.g.,
std::is_fixed_point).  I'll leave it to a future commit to hack this to
allow using math functions on those.  We'll need to change things like
__libcpp_fpclassify anyway, so I'm not sure anything here would really
be future-proof.

https://reviews.llvm.org/D31561
rdar://problem/31361223

llvm-svn: 301060
This commit is contained in:
Duncan P. N. Exon Smith 2017-04-21 23:14:55 +00:00
parent e1bd7cceca
commit 42f8eee150
2 changed files with 114 additions and 8 deletions

View File

@ -307,6 +307,7 @@ long double truncl(long double x);
extern "C++" {
#include <type_traits>
#include <limits>
// signbit
@ -324,22 +325,50 @@ __libcpp_signbit(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_signbit((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{ return __lcpp_x < 0; }
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type
signbit(_A1) _NOEXCEPT
{ return false; }
#elif defined(_LIBCPP_MSVCRT)
template <typename _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{
return ::signbit(static_cast<typename std::__promote<_A1>::type>(__lcpp_x));
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_integral<_A1>::value && std::is_signed<_A1>::value, bool>::type
signbit(_A1 __lcpp_x) _NOEXCEPT
{ return __lcpp_x < 0; }
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_integral<_A1>::value && !std::is_signed<_A1>::value, bool>::type
signbit(_A1) _NOEXCEPT
{ return false; }
#endif // signbit
// fpclassify
@ -358,22 +387,34 @@ __libcpp_fpclassify(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, int>::type
typename std::enable_if<std::is_floating_point<_A1>::value, int>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_fpclassify((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_integral<_A1>::value, int>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; }
#elif defined(_LIBCPP_MSVCRT)
template <typename _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, int>::type
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{
return ::fpclassify(static_cast<typename std::__promote<_A1>::type>(__lcpp_x));
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_integral<_A1>::value, int>::type
fpclassify(_A1 __lcpp_x) _NOEXCEPT
{ return __lcpp_x == 0 ? FP_ZERO : FP_NORMAL; }
#endif // fpclassify
// isfinite
@ -392,12 +433,22 @@ __libcpp_isfinite(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<
std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity,
bool>::type
isfinite(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isfinite((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity,
bool>::type
isfinite(_A1) _NOEXCEPT
{ return true; }
#endif // isfinite
// isinf
@ -416,12 +467,22 @@ __libcpp_isinf(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<
std::is_arithmetic<_A1>::value && std::numeric_limits<_A1>::has_infinity,
bool>::type
isinf(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isinf((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<
std::is_arithmetic<_A1>::value && !std::numeric_limits<_A1>::has_infinity,
bool>::type
isinf(_A1) _NOEXCEPT
{ return false; }
#endif // isinf
// isnan
@ -440,12 +501,18 @@ __libcpp_isnan(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
isnan(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnan((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_integral<_A1>::value, bool>::type
isnan(_A1) _NOEXCEPT
{ return false; }
#endif // isnan
// isnormal
@ -464,12 +531,18 @@ __libcpp_isnormal(_A1 __lcpp_x) _NOEXCEPT
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_arithmetic<_A1>::value, bool>::type
typename std::enable_if<std::is_floating_point<_A1>::value, bool>::type
isnormal(_A1 __lcpp_x) _NOEXCEPT
{
return __libcpp_isnormal((typename std::__promote<_A1>::type)__lcpp_x);
}
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_integral<_A1>::value, bool>::type
isnormal(_A1 __lcpp_x) _NOEXCEPT
{ return __lcpp_x != 0; }
#endif // isnormal
// isgreater

View File

@ -10,6 +10,7 @@
// <cmath>
#include <cmath>
#include <limits>
#include <type_traits>
#include <cassert>
@ -551,6 +552,13 @@ void test_signbit()
static_assert((std::is_same<decltype(std::signbit((long double)0)), bool>::value), "");
static_assert((std::is_same<decltype(signbit(Ambiguous())), Ambiguous>::value), "");
assert(std::signbit(-1.0) == true);
assert(std::signbit(0u) == false);
assert(std::signbit(std::numeric_limits<unsigned>::max()) == false);
assert(std::signbit(0) == false);
assert(std::signbit(1) == false);
assert(std::signbit(-1) == true);
assert(std::signbit(std::numeric_limits<int>::max()) == false);
assert(std::signbit(std::numeric_limits<int>::min()) == true);
}
void test_fpclassify()
@ -564,6 +572,11 @@ void test_fpclassify()
static_assert((std::is_same<decltype(std::fpclassify((long double)0)), int>::value), "");
static_assert((std::is_same<decltype(fpclassify(Ambiguous())), Ambiguous>::value), "");
assert(std::fpclassify(-1.0) == FP_NORMAL);
assert(std::fpclassify(0) == FP_ZERO);
assert(std::fpclassify(1) == FP_NORMAL);
assert(std::fpclassify(-1) == FP_NORMAL);
assert(std::fpclassify(std::numeric_limits<int>::max()) == FP_NORMAL);
assert(std::fpclassify(std::numeric_limits<int>::min()) == FP_NORMAL);
}
void test_isfinite()
@ -577,6 +590,11 @@ void test_isfinite()
static_assert((std::is_same<decltype(std::isfinite((long double)0)), bool>::value), "");
static_assert((std::is_same<decltype(isfinite(Ambiguous())), Ambiguous>::value), "");
assert(std::isfinite(-1.0) == true);
assert(std::isfinite(0) == true);
assert(std::isfinite(1) == true);
assert(std::isfinite(-1) == true);
assert(std::isfinite(std::numeric_limits<int>::max()) == true);
assert(std::isfinite(std::numeric_limits<int>::min()) == true);
}
void test_isnormal()
@ -590,6 +608,11 @@ void test_isnormal()
static_assert((std::is_same<decltype(std::isnormal((long double)0)), bool>::value), "");
static_assert((std::is_same<decltype(isnormal(Ambiguous())), Ambiguous>::value), "");
assert(std::isnormal(-1.0) == true);
assert(std::isnormal(0) == false);
assert(std::isnormal(1) == true);
assert(std::isnormal(-1) == true);
assert(std::isnormal(std::numeric_limits<int>::max()) == true);
assert(std::isnormal(std::numeric_limits<int>::min()) == true);
}
void test_isgreater()
@ -651,6 +674,11 @@ void test_isinf()
static_assert((std::is_same<decltype(std::isinf(0)), bool>::value), "");
static_assert((std::is_same<decltype(std::isinf((long double)0)), bool>::value), "");
assert(std::isinf(-1.0) == false);
assert(std::isinf(0) == false);
assert(std::isinf(1) == false);
assert(std::isinf(-1) == false);
assert(std::isinf(std::numeric_limits<int>::max()) == false);
assert(std::isinf(std::numeric_limits<int>::min()) == false);
}
void test_isless()
@ -731,6 +759,11 @@ void test_isnan()
static_assert((std::is_same<decltype(std::isnan(0)), bool>::value), "");
static_assert((std::is_same<decltype(std::isnan((long double)0)), bool>::value), "");
assert(std::isnan(-1.0) == false);
assert(std::isnan(0) == false);
assert(std::isnan(1) == false);
assert(std::isnan(-1) == false);
assert(std::isnan(std::numeric_limits<int>::max()) == false);
assert(std::isnan(std::numeric_limits<int>::min()) == false);
}
void test_isunordered()