Author: dexonsmith Date: Fri Apr 21 18:14:55 2017 New Revision: 301060 URL: http://llvm.org/viewvc/llvm-project?rev=301060&view=rev Log: 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 Modified: libcxx/trunk/include/math.h libcxx/trunk/test/std/numerics/c.math/cmath.pass.cpp Modified: libcxx/trunk/include/math.h URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/math.h?rev=301060&r1=301059&r2=301060&view=diff ============================================================================== --- libcxx/trunk/include/math.h (original) +++ libcxx/trunk/include/math.h Fri Apr 21 18:14:55 2017 @@ -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) _NOEXC 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) _NOEXCEP 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) _NOEXCEP 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 Modified: libcxx/trunk/test/std/numerics/c.math/cmath.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/c.math/cmath.pass.cpp?rev=301060&r1=301059&r2=301060&view=diff ============================================================================== --- libcxx/trunk/test/std/numerics/c.math/cmath.pass.cpp (original) +++ libcxx/trunk/test/std/numerics/c.math/cmath.pass.cpp Fri Apr 21 18:14:55 2017 @@ -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() _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits