diff --git a/libc/test/utils/CPP/CMakeLists.txt b/libc/test/utils/CPP/CMakeLists.txt index 580fed5923e8..09c43d64ce93 100644 --- a/libc/test/utils/CPP/CMakeLists.txt +++ b/libc/test/utils/CPP/CMakeLists.txt @@ -20,6 +20,16 @@ add_libc_unittest( libc.utils.CPP.standalone_cpp ) +add_libc_unittest( + limits_test + SUITE + libc_cpp_utils_unittests + SRCS + limits_test.cpp + DEPENDS + libc.utils.CPP.standalone_cpp +) + add_libc_unittest( arrayref_test SUITE diff --git a/libc/test/utils/CPP/limits_test.cpp b/libc/test/utils/CPP/limits_test.cpp new file mode 100644 index 000000000000..6904a728c4cb --- /dev/null +++ b/libc/test/utils/CPP/limits_test.cpp @@ -0,0 +1,49 @@ +//===-- Unittests for Limits ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "utils/CPP/Limits.h" +#include "utils/UnitTest/Test.h" + +// This just checks against the C spec, almost all implementations will surpass +// this. +TEST(LlvmLibcLimitsTest, LimitsFollowSpec) { + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), INT_MAX); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::min(), INT_MIN); + + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), UINT_MAX); + + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), LONG_MAX); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::min(), LONG_MIN); + + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), ULONG_MAX); + + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), LLONG_MAX); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::min(), LLONG_MIN); + + ASSERT_EQ(__llvm_libc::cpp::NumericLimits::max(), + ULLONG_MAX); +} + +// This checks that the current environment supports 128 bit integers. +TEST(LlvmLibcLimitsTest, Int128Works) { + __int128_t max128 = ~__uint128_t(0) >> 1; + __int128_t min128 = (__int128_t(1) << 127); + EXPECT_GT(__llvm_libc::cpp::NumericLimits<__int128_t>::max(), + __int128_t(__llvm_libc::cpp::NumericLimits::max())); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__int128_t>::max(), max128); + + EXPECT_LT(__llvm_libc::cpp::NumericLimits<__int128_t>::min(), + __int128_t(__llvm_libc::cpp::NumericLimits::min())); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__int128_t>::min(), min128); + + __uint128_t umax128 = ~__uint128_t(0); + EXPECT_GT( + __llvm_libc::cpp::NumericLimits<__uint128_t>::max(), + __uint128_t(__llvm_libc::cpp::NumericLimits::max())); + ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__uint128_t>::max(), umax128); +} diff --git a/libc/utils/CPP/Limits.h b/libc/utils/CPP/Limits.h index ac327b30ee71..393c3b6a031a 100644 --- a/libc/utils/CPP/Limits.h +++ b/libc/utils/CPP/Limits.h @@ -52,6 +52,16 @@ public: static constexpr unsigned long long max() { return ULLONG_MAX; } static constexpr unsigned long long min() { return 0; } }; +template <> class NumericLimits<__uint128_t> { +public: + static constexpr __uint128_t max() { return ~__uint128_t(0); } + static constexpr __uint128_t min() { return 0; } +}; +template <> class NumericLimits<__int128_t> { +public: + static constexpr __int128_t max() { return ~__uint128_t(0) >> 1; } + static constexpr __int128_t min() { return __int128_t(1) << 127; } +}; } // namespace cpp } // namespace __llvm_libc diff --git a/libc/utils/CPP/TypeTraits.h b/libc/utils/CPP/TypeTraits.h index 1f2c85af3a1c..060d36e4e00e 100644 --- a/libc/utils/CPP/TypeTraits.h +++ b/libc/utils/CPP/TypeTraits.h @@ -50,7 +50,7 @@ template struct IsIntegral { IsSameV || IsSameV || IsSameV || IsSameV || IsSameV || IsSameV || - IsSameV<__uint128_t, TypeNoCV>; + IsSameV<__uint128_t, TypeNoCV> || IsSameV<__int128_t, TypeNoCV>; }; template struct IsPointerTypeNoCV : public FalseValue {}; diff --git a/libc/utils/UnitTest/LibcTest.cpp b/libc/utils/UnitTest/LibcTest.cpp index dc5c0dd651ea..710ee15bba3f 100644 --- a/libc/utils/UnitTest/LibcTest.cpp +++ b/libc/utils/UnitTest/LibcTest.cpp @@ -44,7 +44,7 @@ std::string describeValue(std::string Value) { return std::string(Value); } // When the value is __uint128_t, also show its hexadecimal digits. // Using template to force exact match, prevent ambiguous promotion. -template <> std::string describeValue<__uint128_t>(__uint128_t Value) { +std::string describeValue128(__uint128_t Value) { std::string S(sizeof(__uint128_t) * 2, '0'); for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value >>= 4) { @@ -55,6 +55,13 @@ template <> std::string describeValue<__uint128_t>(__uint128_t Value) { return "0x" + S; } +template <> std::string describeValue<__int128_t>(__int128_t Value) { + return describeValue128(Value); +} +template <> std::string describeValue<__uint128_t>(__uint128_t Value) { + return describeValue128(Value); +} + template void explainDifference(ValType LHS, ValType RHS, const char *LHSStr, const char *RHSStr, const char *File, unsigned long Line, @@ -209,6 +216,11 @@ template bool Test::test(TestCondition Cond, long long LHS, const char *RHSStr, const char *File, unsigned long Line); +template bool Test::test<__int128_t, 0>(TestCondition Cond, __int128_t LHS, + __int128_t RHS, const char *LHSStr, + const char *RHSStr, const char *File, + unsigned long Line); + template bool Test::test(TestCondition Cond, unsigned char LHS, unsigned char RHS, const char *LHSStr,