Skip to content

Commit 243ac89

Browse files
<cmath>: Enable Clang FP comparison intrinsics for heterogeneous FP comparison function overloads (#4648)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 0be5257 commit 243ac89

File tree

5 files changed

+1154
-4
lines changed

5 files changed

+1154
-4
lines changed

stl/inc/cmath

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,53 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo
611611
return __builtin_##NAME(_Xx, _Yx); \
612612
}
613613

614+
#define _CLANG_BUILTIN2_ARG_TEMPLATED(NAME, ARG) \
615+
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
616+
_NODISCARD _Check_return_ inline bool NAME(_In_ ARG _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
617+
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
618+
}
619+
620+
#ifdef __cpp_char8_t
621+
#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \
622+
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
623+
_NODISCARD _Check_return_ inline bool NAME(_In_ char8_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
624+
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
625+
}
626+
#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv
627+
#define _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME)
628+
#endif // ^^^ !defined(__cpp_char8_t) ^^^
629+
630+
#ifdef _NATIVE_WCHAR_T_DEFINED
631+
#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME) \
632+
template <class _Ty, _STD enable_if_t<_STD is_arithmetic_v<_Ty>, int> = 0> \
633+
_NODISCARD _Check_return_ inline bool NAME(_In_ wchar_t _Xx, _In_ _Ty _Yx) noexcept /* strengthened */ { \
634+
return __builtin_##NAME(static_cast<double>(_Xx), static_cast<double>(_Yx)); \
635+
}
636+
#else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv
637+
#define _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME)
638+
#endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^
639+
640+
#define _CLANG_BUILTIN2_TEMPLATED(NAME) \
641+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, float) \
642+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, double) \
643+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long double) \
644+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, signed char) \
645+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, short) \
646+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, int) \
647+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long) \
648+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, long long) \
649+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned char) \
650+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned short) \
651+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned int) \
652+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long) \
653+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, unsigned long long) \
654+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, bool) \
655+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char) \
656+
_CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T(NAME) \
657+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char16_t) \
658+
_CLANG_BUILTIN2_ARG_TEMPLATED(NAME, char32_t) \
659+
_CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T(NAME)
660+
614661
#define _CLANG_BUILTIN1(NAME) \
615662
_CLANG_BUILTIN1_ARG(NAME, float) \
616663
_CLANG_BUILTIN1_ARG(NAME, double) \
@@ -633,19 +680,30 @@ _CLANG_BUILTIN2(islessequal)
633680
_CLANG_BUILTIN2(islessgreater)
634681
_CLANG_BUILTIN2(isunordered)
635682

683+
_CLANG_BUILTIN2_TEMPLATED(isgreater)
684+
_CLANG_BUILTIN2_TEMPLATED(isgreaterequal)
685+
_CLANG_BUILTIN2_TEMPLATED(isless)
686+
_CLANG_BUILTIN2_TEMPLATED(islessequal)
687+
_CLANG_BUILTIN2_TEMPLATED(islessgreater)
688+
_CLANG_BUILTIN2_TEMPLATED(isunordered)
689+
636690
#undef _CLANG_BUILTIN1_ARG
637691
#undef _CLANG_BUILTIN2_ARG
638692
#undef _CLANG_BUILTIN1
639693
#undef _CLANG_BUILTIN2
694+
#undef _CLANG_BUILTIN2_ARG_TEMPLATED
695+
#undef _CLANG_BUILTIN2_ARG_TEMPLATED_CHAR8_T
696+
#undef _CLANG_BUILTIN2_ARG_TEMPLATED_WCHAR_T
697+
#undef _CLANG_BUILTIN2_TEMPLATED
640698
#endif // ^^^ defined(__clang__) ^^^
641699

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

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

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

732-
// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT
790+
// TRANSITION, DevCom-10294165, additional overloads are not templated to avoid ambiguity with the overload in UCRT
733791
#define _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, TYPE) \
734792
_NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \
735793
return RETV; \

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ tests\GH_004275_seeking_fancy_iterators
244244
tests\GH_004388_unordered_meow_operator_equal
245245
tests\GH_004477_mdspan_warning_5246
246246
tests\GH_004597_self_swap
247+
tests\GH_004609_heterogeneous_cmp_overloads
247248
tests\GH_004618_mixed_operator_usage_keeps_statistical_properties
248249
tests\GH_004618_normal_distribution_avoids_resets
249250
tests\GH_004657_expected_constraints_permissive

tests/std/tests/GH_000519_cmath_overloads/test.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ CONSTEXPR23 void test_bool_overloads() {
8282

8383
template <class I>
8484
CONSTEXPR23 void test_other_integral_overloads() {
85+
constexpr I imax = std::numeric_limits<I>::max();
86+
constexpr I imaxm1 = static_cast<I>(imax - 1);
87+
constexpr bool narrower_than_double = std::numeric_limits<I>::digits < std::numeric_limits<double>::digits;
88+
8589
// test overloads in std
8690

8791
assert(std::fpclassify(I{}) == FP_ZERO);
@@ -118,6 +122,14 @@ CONSTEXPR23 void test_other_integral_overloads() {
118122
assert(std::islessequal(static_cast<I>(17), static_cast<I>(29)));
119123
assert(std::islessgreater(static_cast<I>(17), static_cast<I>(29)));
120124
assert(!std::isunordered(static_cast<I>(17), static_cast<I>(29)));
125+
126+
// test that integers are converted to double
127+
assert(std::isgreater(imax, imaxm1) == narrower_than_double);
128+
assert(std::isgreaterequal(imaxm1, imax) == !narrower_than_double);
129+
assert(std::isless(imaxm1, imax) == narrower_than_double);
130+
assert(std::islessequal(imax, imaxm1) == !narrower_than_double);
131+
assert(std::islessgreater(imax, imaxm1) == narrower_than_double);
132+
assert(!std::isunordered(imax, imaxm1));
121133
}
122134

123135
// test overloads in the global namespace
@@ -156,6 +168,14 @@ CONSTEXPR23 void test_other_integral_overloads() {
156168
assert(::islessequal(static_cast<I>(17), static_cast<I>(29)));
157169
assert(::islessgreater(static_cast<I>(17), static_cast<I>(29)));
158170
assert(!::isunordered(static_cast<I>(17), static_cast<I>(29)));
171+
172+
// test that integers are converted to double
173+
assert(::isgreater(imax, imaxm1) == narrower_than_double);
174+
assert(::isgreaterequal(imaxm1, imax) == !narrower_than_double);
175+
assert(::isless(imaxm1, imax) == narrower_than_double);
176+
assert(::islessequal(imax, imaxm1) == !narrower_than_double);
177+
assert(::islessgreater(imax, imaxm1) == narrower_than_double);
178+
assert(!::isunordered(imax, imaxm1));
159179
}
160180
}
161181

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_matrix.lst

0 commit comments

Comments
 (0)