Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][math] Add constexpr for std::signbit() #105946

Merged
merged 10 commits into from
Sep 5, 2024
13 changes: 10 additions & 3 deletions libcxx/include/__math/traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,25 @@ namespace __math {

// signbit

// TODO(LLVM 22): Remove conditional once support for Clang 19 is dropped.
#if defined(_LIBCPP_COMPILER_GCC) || __has_constexpr_builtin(__builtin_signbit)
# define _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_CONSTEXPR_SINCE_CXX23
#else
# define _LIBCPP_SIGNBIT_CONSTEXPR
#endif

template <class _A1, __enable_if_t<is_floating_point<_A1>::value, int> = 0>
_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT {
_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT {
return __builtin_signbit(__x);
}

template <class _A1, __enable_if_t<is_integral<_A1>::value && is_signed<_A1>::value, int> = 0>
_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT {
_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT {
return __x < 0;
}

template <class _A1, __enable_if_t<is_integral<_A1>::value && !is_signed<_A1>::value, int> = 0>
_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1) _NOEXCEPT {
_LIBCPP_NODISCARD inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1) _NOEXCEPT {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,16 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0) == 1);
ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0L) == 1);

// TODO(LLVM 22): Remove `__has_constexpr_builtin` conditional once support for Clang 19 is dropped.
#if !__has_constexpr_builtin(__builtin_signbit)
ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1);
ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);
#else
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1);
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);
#endif

ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,9 @@ int main(int, char**) {
ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0) == 1);
ASSERT_CONSTEXPR_CXX23(std::isnormal(-1.0L) == 1);

ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1);
ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
ASSERT_NOT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0f) == 1);
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0) == 1);
ASSERT_CONSTEXPR_CXX23(std::signbit(-1.0L) == 1);

ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0f, 0.0f) == 0);
ASSERT_NOT_CONSTEXPR_CXX23(std::isgreater(-1.0, 0.0) == 0);
Expand Down
78 changes: 78 additions & 0 deletions libcxx/test/std/numerics/c.math/signbit.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// bool signbit(floating-point-type x); // constexpr since C++23

// We don't control the implementation on windows
// UNSUPPORTED: windows

// These compilers don't support constexpr `__builtin_signbit` yet.
// UNSUPPORTED: clang-17, clang-18, clang-19, apple-clang-15, apple-clang-16

#include <cassert>
#include <cmath>
#include <limits>

#include "test_macros.h"
#include "type_algorithms.h"

struct TestFloat {
template <class T>
static TEST_CONSTEXPR_CXX23 bool test() {
assert(!std::signbit(T(0)));
assert(!std::signbit(std::numeric_limits<T>::min()));
assert(!std::signbit(std::numeric_limits<T>::denorm_min()));
assert(!std::signbit(std::numeric_limits<T>::max()));
assert(!std::signbit(std::numeric_limits<T>::infinity()));
assert(!std::signbit(std::numeric_limits<T>::quiet_NaN()));
assert(!std::signbit(std::numeric_limits<T>::signaling_NaN()));
assert(std::signbit(-T(0)));
assert(std::signbit(-std::numeric_limits<T>::infinity()));
assert(std::signbit(std::numeric_limits<T>::lowest()));

return true;
}

template <class T>
TEST_CONSTEXPR_CXX23 void operator()() {
test<T>();
#if TEST_STD_VER >= 23
static_assert(test<T>());
#endif
}
};

struct TestInt {
template <class T>
static TEST_CONSTEXPR_CXX23 bool test() {
assert(!std::signbit(std::numeric_limits<T>::max()));
assert(!std::signbit(T(0)));
if (std::is_unsigned<T>::value) {
assert(!std::signbit(std::numeric_limits<T>::lowest()));
} else {
assert(std::signbit(std::numeric_limits<T>::lowest()));
}
robincaloudis marked this conversation as resolved.
Show resolved Hide resolved

return true;
}

template <class T>
TEST_CONSTEXPR_CXX23 void operator()() {
test<T>();
#if TEST_STD_VER >= 23
static_assert(test<T>());
#endif
}
};

int main(int, char**) {
types::for_each(types::floating_point_types(), TestFloat());
types::for_each(types::integral_types(), TestInt());

return 0;
}
Loading