[libcxx-commits] [libcxx] 1a12647 - [libc++][math] Add `constexpr` for `std::signbit()` (#105946)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Sep 5 06:44:20 PDT 2024


Author: Robin Caloudis
Date: 2024-09-05T15:44:16+02:00
New Revision: 1a1264726db275d4b207c5bc640e2779dd484478

URL: https://github.com/llvm/llvm-project/commit/1a1264726db275d4b207c5bc640e2779dd484478
DIFF: https://github.com/llvm/llvm-project/commit/1a1264726db275d4b207c5bc640e2779dd484478.diff

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

## Why
Since 18th of August, the floating point comparison builtin
``__builtin_signbit`` is available in Clang as constant expression
(https://github.com/llvm/llvm-project/pull/94118).

## What
* Implement `constexpr` for `std::signbit()` as defined by
[P0533R9](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0533r9.pdf)
(new C++23 feature)
* Restrict execution of tests to tip-of-trunk Clang as builtin is not
yet available (note that builtin is available in GCC)

Added: 
    libcxx/test/std/numerics/c.math/signbit.pass.cpp

Modified: 
    libcxx/include/__math/traits.h
    libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
    libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__math/traits.h b/libcxx/include/__math/traits.h
index 0638a6949580eb..3d4f14fc9cd552 100644
--- a/libcxx/include/__math/traits.h
+++ b/libcxx/include/__math/traits.h
@@ -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;
 }
 

diff  --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
index a07260a34516f1..3f17f21e8c1087 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-clang.pass.cpp
@@ -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);

diff  --git a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
index 8c481f41a945ed..d8779706bcee22 100644
--- a/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
+++ b/libcxx/test/libcxx/numerics/c.math/constexpr-cxx23-gcc.pass.cpp
@@ -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);

diff  --git a/libcxx/test/std/numerics/c.math/signbit.pass.cpp b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
new file mode 100644
index 00000000000000..c85033e363ce55
--- /dev/null
+++ b/libcxx/test/std/numerics/c.math/signbit.pass.cpp
@@ -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()));
+    }
+
+    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;
+}


        


More information about the libcxx-commits mailing list