Skip to content

Commit

Permalink
[libc] Add support for 128 bit ints in limits.h
Browse files Browse the repository at this point in the history
Also, this adds unit tests to check that limits.h complies with the C
standard.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D110643
  • Loading branch information
michaelrj-google committed Sep 28, 2021
1 parent 5cf0606 commit b62d72f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 2 deletions.
10 changes: 10 additions & 0 deletions libc/test/utils/CPP/CMakeLists.txt
Expand Up @@ -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
Expand Down
49 changes: 49 additions & 0 deletions 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<int>::max(), INT_MAX);
ASSERT_EQ(__llvm_libc::cpp::NumericLimits<int>::min(), INT_MIN);

ASSERT_EQ(__llvm_libc::cpp::NumericLimits<unsigned int>::max(), UINT_MAX);

ASSERT_EQ(__llvm_libc::cpp::NumericLimits<long>::max(), LONG_MAX);
ASSERT_EQ(__llvm_libc::cpp::NumericLimits<long>::min(), LONG_MIN);

ASSERT_EQ(__llvm_libc::cpp::NumericLimits<unsigned long>::max(), ULONG_MAX);

ASSERT_EQ(__llvm_libc::cpp::NumericLimits<long long>::max(), LLONG_MAX);
ASSERT_EQ(__llvm_libc::cpp::NumericLimits<long long>::min(), LLONG_MIN);

ASSERT_EQ(__llvm_libc::cpp::NumericLimits<unsigned long long>::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<long long>::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<long long>::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<unsigned long long>::max()));
ASSERT_EQ(__llvm_libc::cpp::NumericLimits<__uint128_t>::max(), umax128);
}
10 changes: 10 additions & 0 deletions libc/utils/CPP/Limits.h
Expand Up @@ -52,6 +52,16 @@ template <> class NumericLimits<unsigned long long> {
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
Expand Down
2 changes: 1 addition & 1 deletion libc/utils/CPP/TypeTraits.h
Expand Up @@ -50,7 +50,7 @@ template <typename Type> struct IsIntegral {
IsSameV<unsigned int, TypeNoCV> || IsSameV<long, TypeNoCV> ||
IsSameV<unsigned long, TypeNoCV> || IsSameV<long long, TypeNoCV> ||
IsSameV<unsigned long long, TypeNoCV> || IsSameV<bool, TypeNoCV> ||
IsSameV<__uint128_t, TypeNoCV>;
IsSameV<__uint128_t, TypeNoCV> || IsSameV<__int128_t, TypeNoCV>;
};

template <typename T> struct IsPointerTypeNoCV : public FalseValue {};
Expand Down
14 changes: 13 additions & 1 deletion libc/utils/UnitTest/LibcTest.cpp
Expand Up @@ -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) {
Expand All @@ -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 <typename ValType>
void explainDifference(ValType LHS, ValType RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line,
Expand Down Expand Up @@ -209,6 +216,11 @@ template bool Test::test<long long, 0>(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<unsigned char, 0>(TestCondition Cond,
unsigned char LHS, unsigned char RHS,
const char *LHSStr,
Expand Down

0 comments on commit b62d72f

Please sign in to comment.