Skip to content

Commit

Permalink
<cmath>: Enable Clang FP comparison intrinsics for heterogeneous FP…
Browse files Browse the repository at this point in the history
… comparison function overloads (#4648)

Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
  • Loading branch information
frederick-vs-ja and StephanTLavavej authored Jun 27, 2024
1 parent 0be5257 commit 243ac89
Show file tree
Hide file tree
Showing 5 changed files with 1,154 additions and 4 deletions.
66 changes: 62 additions & 4 deletions stl/inc/cmath
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,53 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo
return __builtin_##NAME(_Xx, _Yx); \
}

#define _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, ARG) \
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
_NODISCARD _Check_return_ inline bool NAME(_In_ ARG _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
}

#ifdef __cpp_char8_t
#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
_NODISCARD _Check_return_ inline bool NAME(_In_ char8_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
}
#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv
#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME)
#endif // ^^^ !defined(__cpp_char8_t) ^^^

#ifdef _NATIVE_WCHAR_T_DEFINED
#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) \
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
_NODISCARD _Check_return_ inline bool NAME(_In_ wchar_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
}
#else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv
#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME)
#endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^

#define _CLANG_BUILTIN2_TEMPLATED(NAME) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, float) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, double) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long double) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, signed char) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, short) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, int) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long long) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned char) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned short) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned int) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long long) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, bool) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char) \
_CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char16_t) \
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char32_t) \
_CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME)

#define _CLANG_BUILTIN1(NAME) \
_CLANG_BUILTIN1_ARG(NAME, float) \
_CLANG_BUILTIN1_ARG(NAME, double) \
Expand All @@ -633,19 +680,30 @@ _CLANG_BUILTIN2(islessequal)
_CLANG_BUILTIN2(islessgreater)
_CLANG_BUILTIN2(isunordered)

_CLANG_BUILTIN2_TEMPLATED(isgreater)
_CLANG_BUILTIN2_TEMPLATED(isgreaterequal)
_CLANG_BUILTIN2_TEMPLATED(isless)
_CLANG_BUILTIN2_TEMPLATED(islessequal)
_CLANG_BUILTIN2_TEMPLATED(islessgreater)
_CLANG_BUILTIN2_TEMPLATED(isunordered)

#undef _CLANG_BUILTIN1_ARG
#undef _CLANG_BUILTIN2_ARG
#undef _CLANG_BUILTIN1
#undef _CLANG_BUILTIN2
#undef _CLANG_BUILTIN2_ARG_TEMPLATED
#undef _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T
#undef _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T
#undef _CLANG_BUILTIN2_TEMPLATED
#endif // ^^^ defined(__clang__) ^^^

// TRANSITION, GH-519, should be provided by UCRT
// TRANSITION, DevCom-10294165, should be provided by UCRT
template <class _Ty, _STD enable_if_t<_STD is_integral_v<_Ty>, int> = 0>
_NODISCARD _Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ {
return _Ix == 0 ? FP_ZERO : FP_NORMAL;
}

// TRANSITION, GH-519, should be provided by UCRT
// TRANSITION, DevCom-10294165, should be provided by UCRT
template <class _Ty, _STD enable_if_t<_STD is_integral_v<_Ty>, int> = 0>
_NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ {
if constexpr (static_cast<_Ty>(-1) < _Ty{}) {
Expand All @@ -655,7 +713,7 @@ _NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept
}
}

// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT
// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT
#define _GENERIC_MATH_ISNORMAL(TYPE) \
_NODISCARD _Check_return_ _CONSTEXPR23 bool isnormal(_In_ const TYPE _Ix) noexcept /* strengthened */ { \
return _Ix != 0; \
Expand Down Expand Up @@ -729,7 +787,7 @@ _GENERIC_MATH_ISNORMAL(wchar_t)
#define _GENERIC_MATH2I(FUN, CLANG_INTRIN, MSVC_INTRIN) _GENERIC_MATH2_BASE(FUN, _CSTD FUN)
#endif // ^^^ intrinsics unavailable ^^^

// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT
// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT
#define _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, TYPE) \
_NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \
return RETV; \
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ tests\GH_004275_seeking_fancy_iterators
tests\GH_004388_unordered_meow_operator_equal
tests\GH_004477_mdspan_warning_5246
tests\GH_004597_self_swap
tests\GH_004609_heterogeneous_cmp_overloads
tests\GH_004618_mixed_operator_usage_keeps_statistical_properties
tests\GH_004618_normal_distribution_avoids_resets
tests\GH_004657_expected_constraints_permissive
Expand Down
20 changes: 20 additions & 0 deletions tests/std/tests/GH_000519_cmath_overloads/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ CONSTEXPR23 void test_bool_overloads() {

template <class I>
CONSTEXPR23 void test_other_integral_overloads() {
constexpr I imax = std::numeric_limits<I>::max();
constexpr I imaxm1 = static_cast<I>(imax - 1);
constexpr bool narrower_than_double = std::numeric_limits<I>::digits < std::numeric_limits<double>::digits;

// test overloads in std

assert(std::fpclassify(I{}) == FP_ZERO);
Expand Down Expand Up @@ -118,6 +122,14 @@ CONSTEXPR23 void test_other_integral_overloads() {
assert(std::islessequal(static_cast<I>(17), static_cast<I>(29)));
assert(std::islessgreater(static_cast<I>(17), static_cast<I>(29)));
assert(!std::isunordered(static_cast<I>(17), static_cast<I>(29)));

// test that integers are converted to double
assert(std::isgreater(imax, imaxm1) == narrower_than_double);
assert(std::isgreaterequal(imaxm1, imax) == !narrower_than_double);
assert(std::isless(imaxm1, imax) == narrower_than_double);
assert(std::islessequal(imax, imaxm1) == !narrower_than_double);
assert(std::islessgreater(imax, imaxm1) == narrower_than_double);
assert(!std::isunordered(imax, imaxm1));
}

// test overloads in the global namespace
Expand Down Expand Up @@ -156,6 +168,14 @@ CONSTEXPR23 void test_other_integral_overloads() {
assert(::islessequal(static_cast<I>(17), static_cast<I>(29)));
assert(::islessgreater(static_cast<I>(17), static_cast<I>(29)));
assert(!::isunordered(static_cast<I>(17), static_cast<I>(29)));

// test that integers are converted to double
assert(::isgreater(imax, imaxm1) == narrower_than_double);
assert(::isgreaterequal(imaxm1, imax) == !narrower_than_double);
assert(::isless(imaxm1, imax) == narrower_than_double);
assert(::islessequal(imax, imaxm1) == !narrower_than_double);
assert(::islessgreater(imax, imaxm1) == narrower_than_double);
assert(!::isunordered(imax, imaxm1));
}
}

Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_004609_heterogeneous_cmp_overloads/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
Loading

0 comments on commit 243ac89

Please sign in to comment.