[libc] Add support for 128 bit ints in limits.h

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
This commit is contained in:
Michael Jones 2021-09-28 18:25:43 +00:00
parent 5cf0606140
commit b62d72f3c5
5 changed files with 83 additions and 2 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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 {};

View File

@ -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 <typename ValType>
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<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,