Skip to content

[libc] Added support for fixed-points in is_signed and is_unsigned. #133371

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

Merged
merged 9 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion libc/src/__support/CPP/type_traits/is_signed.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,43 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits/bool_constant.h"
#include "src/__support/CPP/type_traits/is_arithmetic.h"
#include "src/__support/CPP/type_traits/is_same.h"
#include "src/__support/CPP/type_traits/remove_cv.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {
namespace cpp {

// is_signed
#ifndef LIBC_COMPILER_HAS_FIXED_POINT
template <typename T>
struct is_signed : bool_constant<(is_arithmetic_v<T> && (T(-1) < T(0)))> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
Comment on lines 23 to 27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I just tested locally, and the following seems to work without all the specializations:

struct is_signed : bool_constant<
    (is_fixed_point_v<T> && T(-0.5) < T(0)) ||
    (is_arithmetic_v<T> && (T(-1) < T(0)))> {
    ...
};

Copy link
Contributor Author

@kr-2003 kr-2003 Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really? i think i am missing out on something, because this is what i get when i try this on my machine:

/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:23:34: error: non-type template argument is not a constant expression
   23 | struct is_signed : bool_constant<(is_fixed_point_v<T> && T(-0.5) < T(0)) ||
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   24 |                                  (is_arithmetic_v<T> && (T(-1) < T(0)))> {
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:105:46: note: in instantiation of template class '__llvm_libc_21_0_0_git::cpp::is_signed<unsigned _Fract>' requested here
  105 | LIBC_INLINE_VAR constexpr bool is_signed_v = is_signed<T>::value;
      |                                              ^
/Users/llvm-project/libc/test/src/__support/CPP/type_traits_test.cpp:427:17: note: in instantiation of variable template specialization '__llvm_libc_21_0_0_git::cpp::is_signed_v<unsigned _Fract>' requested here
  427 |   EXPECT_FALSE((is_signed_v<unsigned fract>));
/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:23:60: note: value 0.0 is outside the range of representable values of type 'unsigned _Fract'
   23 | struct is_signed : bool_constant<(is_fixed_point_v<T> && T(-0.5) < T(0)) ||

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it looks like static_assert with that works fine, but not with EXPECT_EQ in the tests that you added. Probably something is missing for fixed point support in constexpr context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it looks like static_assert with that works fine, but not with EXPECT_EQ in the tests that you added. Probably something is missing for fixed point support in constexpr context.

opened issue at #133680

#else
template <typename T> struct is_signed {
private:
template <typename Head, typename... Args>
LIBC_INLINE static constexpr bool __is_unqualified_any_of() {
return (... || is_same_v<remove_cv_t<Head>, Args>);
}

public:
LIBC_INLINE_VAR static constexpr bool value =
(is_arithmetic_v<T> && (T(-1) < T(0))) ||
__is_unqualified_any_of<T, short fract, fract, long fract, short accum,
accum, long accum, short sat fract, sat fract,
long sat fract, short sat accum, sat accum,
long sat accum>();
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
#endif // LIBC_COMPILER_HAS_FIXED_POINT

template <typename T>
LIBC_INLINE_VAR constexpr bool is_signed_v = is_signed<T>::value;

Expand Down
27 changes: 26 additions & 1 deletion libc/src/__support/CPP/type_traits/is_unsigned.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,45 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits/bool_constant.h"
#include "src/__support/CPP/type_traits/is_arithmetic.h"
#include "src/__support/CPP/type_traits/is_same.h"
#include "src/__support/CPP/type_traits/remove_cv.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {
namespace cpp {

// is_unsigned
#ifndef LIBC_COMPILER_HAS_FIXED_POINT
template <typename T>
struct is_unsigned : bool_constant<(is_arithmetic_v<T> && (T(-1) > T(0)))> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
#else
template <typename T> struct is_unsigned {
private:
template <typename Head, typename... Args>
LIBC_INLINE static constexpr bool __is_unqualified_any_of() {
return (... || is_same_v<remove_cv_t<Head>, Args>);
}

public:
LIBC_INLINE_VAR static constexpr bool value =
(is_arithmetic_v<T> && (T(-1) > T(0))) ||
__is_unqualified_any_of<T, unsigned short fract, unsigned fract,
unsigned long fract, unsigned short accum,
unsigned accum, unsigned long accum,
unsigned short sat fract, unsigned sat fract,
unsigned long sat fract, unsigned short sat accum,
unsigned sat accum, unsigned long sat accum>();
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
#endif // LIBC_COMPILER_HAS_FIXED_POINT

template <typename T>
LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value;

Expand Down
65 changes: 63 additions & 2 deletions libc/test/src/__support/CPP/type_traits_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/config.h"
#include "test/UnitTest/Test.h"
Expand Down Expand Up @@ -409,7 +410,37 @@ TEST(LlvmLibcTypeTraitsTest, is_object) {

// TODO is_scalar

// TODO is_signed
TEST(LlvmLibcTypeTraitsTest, is_signed) {
EXPECT_TRUE((is_signed_v<int>));
EXPECT_TRUE((is_signed_v<long>));
EXPECT_TRUE((is_signed_v<long long>));
EXPECT_FALSE((is_signed_v<unsigned int>));
EXPECT_FALSE((is_signed_v<unsigned long>));
EXPECT_FALSE((is_signed_v<unsigned long long>));
EXPECT_TRUE((is_signed_v<float>));
EXPECT_TRUE((is_signed_v<double>));
EXPECT_TRUE((is_signed_v<long double>));

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// for fixed point types
EXPECT_TRUE((is_signed_v<fract>));
EXPECT_FALSE((is_signed_v<unsigned fract>));
EXPECT_TRUE((is_signed_v<accum>));
EXPECT_FALSE((is_signed_v<unsigned accum>));
EXPECT_TRUE((is_signed_v<sat fract>));
EXPECT_FALSE((is_signed_v<unsigned sat fract>));
EXPECT_TRUE((is_signed_v<sat accum>));
EXPECT_FALSE((is_signed_v<unsigned sat accum>));
EXPECT_TRUE((is_signed_v<short fract>));
EXPECT_FALSE((is_signed_v<unsigned short fract>));
EXPECT_TRUE((is_signed_v<short accum>));
EXPECT_FALSE((is_signed_v<unsigned short accum>));
EXPECT_TRUE((is_signed_v<long fract>));
EXPECT_FALSE((is_signed_v<unsigned long fract>));
EXPECT_TRUE((is_signed_v<long accum>));
EXPECT_FALSE((is_signed_v<unsigned long accum>));
#endif
}

// TODO is_trivially_constructible

Expand All @@ -419,7 +450,37 @@ TEST(LlvmLibcTypeTraitsTest, is_object) {

// TODO is_union

// TODO is_unsigned
TEST(LlvmLibcTypeTraitsTest, is_unsigned) {
EXPECT_FALSE((is_unsigned_v<int>));
EXPECT_FALSE((is_unsigned_v<long>));
EXPECT_FALSE((is_unsigned_v<long long>));
EXPECT_TRUE((is_unsigned_v<unsigned int>));
EXPECT_TRUE((is_unsigned_v<unsigned long>));
EXPECT_TRUE((is_unsigned_v<unsigned long long>));
EXPECT_FALSE((is_unsigned_v<float>));
EXPECT_FALSE((is_unsigned_v<double>));
EXPECT_FALSE((is_unsigned_v<long double>));

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// for fixed point types
EXPECT_FALSE((is_unsigned_v<fract>));
EXPECT_TRUE((is_unsigned_v<unsigned fract>));
EXPECT_FALSE((is_unsigned_v<accum>));
EXPECT_TRUE((is_unsigned_v<unsigned accum>));
EXPECT_FALSE((is_unsigned_v<sat fract>));
EXPECT_TRUE((is_unsigned_v<unsigned sat fract>));
EXPECT_FALSE((is_unsigned_v<sat accum>));
EXPECT_TRUE((is_unsigned_v<unsigned sat accum>));
EXPECT_FALSE((is_unsigned_v<short fract>));
EXPECT_TRUE((is_unsigned_v<unsigned short fract>));
EXPECT_FALSE((is_unsigned_v<short accum>));
EXPECT_TRUE((is_unsigned_v<unsigned short accum>));
EXPECT_FALSE((is_unsigned_v<long fract>));
EXPECT_TRUE((is_unsigned_v<unsigned long fract>));
EXPECT_FALSE((is_unsigned_v<long accum>));
EXPECT_TRUE((is_unsigned_v<unsigned long accum>));
#endif
}

// TODO is_void

Expand Down
Loading