[libc-commits] [libc] [llvm] [libc] Add user defined literals to initialize `BigInt` and `__uint128_t` constants (PR #81267)
Guillaume Chatelet via libc-commits
libc-commits at lists.llvm.org
Wed Feb 14 02:12:13 PST 2024
https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/81267
>From 6a88fb1145db944fde48908574cf013f8c40638b Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 9 Feb 2024 16:27:51 +0000
Subject: [PATCH 1/6] [libc] Add user defined literals to ease testing
---
libc/src/__support/integer_literals.h | 166 ++++++++
.../test/src/__support/FPUtil/fpbits_test.cpp | 390 ++++++++----------
.../src/__support/integer_literals_test.cpp | 134 ++++++
.../llvm-project-overlay/libc/BUILD.bazel | 8 +
.../libc/test/src/__support/BUILD.bazel | 8 +
.../test/src/__support/FPUtil/BUILD.bazel | 1 +
6 files changed, 494 insertions(+), 213 deletions(-)
create mode 100644 libc/src/__support/integer_literals.h
create mode 100644 libc/test/src/__support/integer_literals_test.cpp
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
new file mode 100644
index 00000000000000..c588cf9a63986d
--- /dev/null
+++ b/libc/src/__support/integer_literals.h
@@ -0,0 +1,166 @@
+//===-- User literal for unsigned integers ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// This set of user defined literals allows uniform constructions of constants
+// up to 256 bits and also help with unit tests (EXPECT_EQ requires the same
+// type for LHS and RHS).
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
+#define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
+
+#include "src/__support/UInt128.h" // UInt128
+#include "src/__support/macros/attributes.h" // LIBC_INLINE
+#include <limits.h> // CHAR_BIT
+#include <stddef.h> // size_t
+#include <stdint.h> // __uintxx_t
+
+namespace LIBC_NAMESPACE {
+
+LIBC_INLINE constexpr __uint8_t operator""_u8(unsigned long long value) {
+ return value;
+}
+
+LIBC_INLINE constexpr __uint16_t operator""_u16(unsigned long long value) {
+ return value;
+}
+
+LIBC_INLINE constexpr __uint32_t operator""_u32(unsigned long long value) {
+ return value;
+}
+
+LIBC_INLINE constexpr __uint64_t operator""_u64(unsigned long long value) {
+ return value;
+}
+
+namespace internal {
+
+// Creates a T by reading digits from an array.
+template <typename T>
+LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits,
+ size_t size) {
+ T value{};
+ for (; size; ++digits, --size) {
+ value *= base;
+ value += *digits;
+ }
+ return value;
+}
+
+// A static buffer to hold the digits for a T.
+template <typename T, int base> struct DigitBuffer {
+ static_assert(base == 2 || base == 10 || base == 16);
+ // Base 2: one char provides exactly one bit.
+ // Base 10: one char provides between three and four bits.
+ // Base 16: one char provides exactly four bits.
+ LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 1
+ : base == 10 ? 3
+ : base == 16 ? 4
+ : 0;
+ LIBC_INLINE_VAR static constexpr size_t MAX_DIGITS =
+ sizeof(T) * CHAR_BIT / BITS_PER_DIGIT;
+
+ uint8_t digits[MAX_DIGITS] = {};
+ size_t size = 0;
+
+ constexpr DigitBuffer(const char *str) {
+ for (; *str != '\0'; ++str)
+ push(*str);
+ }
+
+ // Returns the digit for a particular character.
+ // Returns 255 if the character is invalid.
+ LIBC_INLINE static constexpr uint8_t get_digit_value(const char c) {
+ const auto to_lower = [](char c) { return c | 32; };
+ const auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
+ const auto is_lower = [](char c) { return 'a' <= c && c <= 'z'; };
+ const auto is_upper = [](char c) { return 'A' <= c && c <= 'Z'; };
+ const auto is_alpha = [&](char c) { return is_lower(c) || is_upper(c); };
+ if (is_digit(c))
+ return c - '0';
+ if (base > 10 && is_alpha(c))
+ return to_lower(c) - 'a' + 10;
+ return 255;
+ }
+
+ // Adds a single character to this buffer.
+ LIBC_INLINE constexpr void push(char c) {
+ if (c == '\'')
+ return; // ' is valid but not taken into account.
+ const uint8_t value = get_digit_value(c);
+ if (value == 255 || size >= MAX_DIGITS)
+ __builtin_unreachable(); // invalid or too many characters.
+ digits[size] = value;
+ ++size;
+ }
+};
+
+// Generic implementation for native types (including __uint128_t or ExtInt
+// where available).
+template <typename T> struct Parser {
+ template <int base> LIBC_INLINE static constexpr T parse(const char *str) {
+ const DigitBuffer<T, base> buffer(str);
+ return accumulate<T>(base, buffer.digits, buffer.size);
+ }
+};
+
+// Specialization for cpp::UInt<N>.
+// Because this code runs at compile time we try to make it as efficient as
+// possible. For binary and hexadecimal formats we read digits by chunks of 64
+// bits and produce the BigInt internal representation direcly. For decimal
+// numbers we go the slow path and use BigInt arithmetic.
+template <size_t N> struct Parser<LIBC_NAMESPACE::cpp::UInt<N>> {
+ using UIntT = cpp::UInt<N>;
+ template <int base> static constexpr UIntT parse(const char *str) {
+ const DigitBuffer<UIntT, base> buffer(str);
+ if constexpr (base == 10) {
+ // Slow path, we sum and multiply BigInt for each digit.
+ return accumulate<UIntT>(base, buffer.digits, buffer.size);
+ } else {
+ // Fast path, we consume blocks of uint64_t and creates the BigInt's
+ // internal representation directly.
+ using U64ArrayT = cpp::array<uint64_t, UIntT::WORDCOUNT>;
+ U64ArrayT array;
+ size_t size = buffer.size;
+ const uint8_t *digit_ptr = buffer.digits + size;
+ for (size_t i = 0; i < array.size(); ++i) {
+ constexpr size_t U64_DIGITS = DigitBuffer<uint64_t, base>::MAX_DIGITS;
+ const size_t chunk = size > U64_DIGITS ? U64_DIGITS : size;
+ digit_ptr -= chunk;
+ size -= chunk;
+ array[i] = accumulate<uint64_t>(base, digit_ptr, chunk);
+ }
+ return UIntT(array);
+ }
+ }
+};
+
+// Detects the base of the number and dispatches to the right implementation.
+template <typename T>
+LIBC_INLINE constexpr T parse_with_prefix(const char *ptr) {
+ using P = Parser<T>;
+ if (ptr[0] == '0' && ptr[1] == 'x')
+ return P::template parse<16>(ptr + 2);
+ else if (ptr[0] == '0' && ptr[1] == 'b')
+ return P::template parse<2>(ptr + 2);
+ else
+ return P::template parse<10>(ptr);
+}
+
+} // namespace internal
+
+LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) {
+ return internal::parse_with_prefix<UInt128>(x);
+}
+
+LIBC_INLINE constexpr auto operator""_u256(const char *x) {
+ return internal::parse_with_prefix<cpp::UInt<256>>(x);
+}
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index 4504a4f0cfcc7d..312ef276442e95 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -8,6 +8,7 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/fpbits_str.h"
+#include "src/__support/integer_literals.h"
#include "test/UnitTest/Test.h"
using LIBC_NAMESPACE::fputil::FPBits;
@@ -15,37 +16,42 @@ using LIBC_NAMESPACE::fputil::FPType;
using LIBC_NAMESPACE::fputil::Sign;
using LIBC_NAMESPACE::fputil::internal::FPRep;
+using LIBC_NAMESPACE::operator""_u16;
+using LIBC_NAMESPACE::operator""_u32;
+using LIBC_NAMESPACE::operator""_u64;
+using LIBC_NAMESPACE::operator""_u128;
+
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary16) {
using Rep = FPRep<FPType::IEEE754_Binary16>;
using u16 = typename Rep::StorageType;
- EXPECT_EQ(u16(0b0'00000'0000000000), u16(Rep::zero()));
- EXPECT_EQ(u16(0b0'01111'0000000000), u16(Rep::one()));
- EXPECT_EQ(u16(0b0'00000'0000000001), u16(Rep::min_subnormal()));
- EXPECT_EQ(u16(0b0'00000'1111111111), u16(Rep::max_subnormal()));
- EXPECT_EQ(u16(0b0'00001'0000000000), u16(Rep::min_normal()));
- EXPECT_EQ(u16(0b0'11110'1111111111), u16(Rep::max_normal()));
- EXPECT_EQ(u16(0b0'11111'0000000000), u16(Rep::inf()));
- EXPECT_EQ(u16(0b0'11111'0100000000), u16(Rep::signaling_nan()));
- EXPECT_EQ(u16(0b0'11111'1000000000), u16(Rep::quiet_nan()));
+ EXPECT_EQ(0b0'00000'0000000000_u16, u16(Rep::zero()));
+ EXPECT_EQ(0b0'01111'0000000000_u16, u16(Rep::one()));
+ EXPECT_EQ(0b0'00000'0000000001_u16, u16(Rep::min_subnormal()));
+ EXPECT_EQ(0b0'00000'1111111111_u16, u16(Rep::max_subnormal()));
+ EXPECT_EQ(0b0'00001'0000000000_u16, u16(Rep::min_normal()));
+ EXPECT_EQ(0b0'11110'1111111111_u16, u16(Rep::max_normal()));
+ EXPECT_EQ(0b0'11111'0000000000_u16, u16(Rep::inf()));
+ EXPECT_EQ(0b0'11111'0100000000_u16, u16(Rep::signaling_nan()));
+ EXPECT_EQ(0b0'11111'1000000000_u16, u16(Rep::quiet_nan()));
}
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary32) {
using Rep = FPRep<FPType::IEEE754_Binary32>;
using u32 = typename Rep::StorageType;
- EXPECT_EQ(u32(0b0'00000000'00000000000000000000000), u32(Rep::zero()));
- EXPECT_EQ(u32(0b0'01111111'00000000000000000000000), u32(Rep::one()));
- EXPECT_EQ(u32(0b0'00000000'00000000000000000000001),
+ EXPECT_EQ(0b0'00000000'00000000000000000000000_u32, u32(Rep::zero()));
+ EXPECT_EQ(0b0'01111111'00000000000000000000000_u32, u32(Rep::one()));
+ EXPECT_EQ(0b0'00000000'00000000000000000000001_u32,
u32(Rep::min_subnormal()));
- EXPECT_EQ(u32(0b0'00000000'11111111111111111111111),
+ EXPECT_EQ(0b0'00000000'11111111111111111111111_u32,
u32(Rep::max_subnormal()));
- EXPECT_EQ(u32(0b0'00000001'00000000000000000000000), u32(Rep::min_normal()));
- EXPECT_EQ(u32(0b0'11111110'11111111111111111111111), u32(Rep::max_normal()));
- EXPECT_EQ(u32(0b0'11111111'00000000000000000000000), u32(Rep::inf()));
- EXPECT_EQ(u32(0b0'11111111'01000000000000000000000),
+ EXPECT_EQ(0b0'00000001'00000000000000000000000_u32, u32(Rep::min_normal()));
+ EXPECT_EQ(0b0'11111110'11111111111111111111111_u32, u32(Rep::max_normal()));
+ EXPECT_EQ(0b0'11111111'00000000000000000000000_u32, u32(Rep::inf()));
+ EXPECT_EQ(0b0'11111111'01000000000000000000000_u32,
u32(Rep::signaling_nan()));
- EXPECT_EQ(u32(0b0'11111111'10000000000000000000000), u32(Rep::quiet_nan()));
+ EXPECT_EQ(0b0'11111111'10000000000000000000000_u32, u32(Rep::quiet_nan()));
}
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary64) {
@@ -53,80 +59,63 @@ TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary64) {
using u64 = typename Rep::StorageType;
EXPECT_EQ(
- u64(0b0'00000000000'0000000000000000000000000000000000000000000000000000),
+ 0b0'00000000000'0000000000000000000000000000000000000000000000000000_u64,
u64(Rep::zero()));
EXPECT_EQ(
- u64(0b0'01111111111'0000000000000000000000000000000000000000000000000000),
+ 0b0'01111111111'0000000000000000000000000000000000000000000000000000_u64,
u64(Rep::one()));
EXPECT_EQ(
- u64(0b0'00000000000'0000000000000000000000000000000000000000000000000001),
+ 0b0'00000000000'0000000000000000000000000000000000000000000000000001_u64,
u64(Rep::min_subnormal()));
EXPECT_EQ(
- u64(0b0'00000000000'1111111111111111111111111111111111111111111111111111),
+ 0b0'00000000000'1111111111111111111111111111111111111111111111111111_u64,
u64(Rep::max_subnormal()));
EXPECT_EQ(
- u64(0b0'00000000001'0000000000000000000000000000000000000000000000000000),
+ 0b0'00000000001'0000000000000000000000000000000000000000000000000000_u64,
u64(Rep::min_normal()));
EXPECT_EQ(
- u64(0b0'11111111110'1111111111111111111111111111111111111111111111111111),
+ 0b0'11111111110'1111111111111111111111111111111111111111111111111111_u64,
u64(Rep::max_normal()));
EXPECT_EQ(
- u64(0b0'11111111111'0000000000000000000000000000000000000000000000000000),
+ 0b0'11111111111'0000000000000000000000000000000000000000000000000000_u64,
u64(Rep::inf()));
EXPECT_EQ(
- u64(0b0'11111111111'0100000000000000000000000000000000000000000000000000),
+ 0b0'11111111111'0100000000000000000000000000000000000000000000000000_u64,
u64(Rep::signaling_nan()));
EXPECT_EQ(
- u64(0b0'11111111111'1000000000000000000000000000000000000000000000000000),
+ 0b0'11111111111'1000000000000000000000000000000000000000000000000000_u64,
u64(Rep::quiet_nan()));
}
-static constexpr UInt128 u128(uint64_t hi, uint64_t lo) {
-#if defined(__SIZEOF_INT128__)
- return __uint128_t(hi) << 64 | __uint128_t(lo);
-#else
- return UInt128({lo, hi});
-#endif
-}
-
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary128) {
using Rep = FPRep<FPType::IEEE754_Binary128>;
EXPECT_EQ(
- u128(0b0'000000000000000'000000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::zero()));
EXPECT_EQ(
- u128(0b0'011111111111111'000000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'011111111111111'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::one()));
EXPECT_EQ(
- u128(0b0'000000000000000'000000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000001),
+ 0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001_u128,
UInt128(Rep::min_subnormal()));
EXPECT_EQ(
- u128(0b0'000000000000000'111111111111111111111111111111111111111111111111,
- 0b1111111111111111111111111111111111111111111111111111111111111111),
+ 0b0'000000000000000'1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_u128,
UInt128(Rep::max_subnormal()));
EXPECT_EQ(
- u128(0b0'000000000000001'000000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'000000000000001'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::min_normal()));
EXPECT_EQ(
- u128(0b0'111111111111110'111111111111111111111111111111111111111111111111,
- 0b1111111111111111111111111111111111111111111111111111111111111111),
+ 0b0'111111111111110'1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111_u128,
UInt128(Rep::max_normal()));
EXPECT_EQ(
- u128(0b0'111111111111111'000000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::inf()));
EXPECT_EQ(
- u128(0b0'111111111111111'010000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'111111111111111'0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::signaling_nan()));
EXPECT_EQ(
- u128(0b0'111111111111111'100000000000000000000000000000000000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'111111111111111'1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::quiet_nan()));
}
@@ -134,89 +123,73 @@ TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80) {
using Rep = FPRep<FPType::X86_Binary80>;
EXPECT_EQ(
- u128(0b0'000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'0000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::zero()));
EXPECT_EQ(
- u128(0b0'011111111111111,
- 0b1000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'0111111111111111000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::one()));
EXPECT_EQ(
- u128(0b0'000000000000000,
- 0b0000000000000000000000000000000000000000000000000000000000000001),
+ 0b0'0000000000000000000000000000000000000000000000000000000000000000000000000000001_u128,
UInt128(Rep::min_subnormal()));
EXPECT_EQ(
- u128(0b0'000000000000000,
- 0b0111111111111111111111111111111111111111111111111111111111111111),
+ 0b0'0000000000000000111111111111111111111111111111111111111111111111111111111111111_u128,
UInt128(Rep::max_subnormal()));
EXPECT_EQ(
- u128(0b0'000000000000001,
- 0b1000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'0000000000000011000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::min_normal()));
EXPECT_EQ(
- u128(0b0'111111111111110,
- 0b1111111111111111111111111111111111111111111111111111111111111111),
+ 0b0'1111111111111101111111111111111111111111111111111111111111111111111111111111111_u128,
UInt128(Rep::max_normal()));
EXPECT_EQ(
- u128(0b0'111111111111111,
- 0b1000000000000000000000000000000000000000000000000000000000000000),
+ 0b0'1111111111111111000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::inf()));
EXPECT_EQ(
- u128(0b0'111111111111111,
- 0b1010000000000000000000000000000000000000000000000000000000000000),
+ 0b0'1111111111111111010000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::signaling_nan()));
EXPECT_EQ(
- u128(0b0'111111111111111,
- 0b1100000000000000000000000000000000000000000000000000000000000000),
+ 0b0'1111111111111111100000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::quiet_nan()));
}
TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80_IsNan) {
using Rep = FPRep<FPType::X86_Binary80>;
- const auto is_nan = [](uint64_t hi, uint64_t lo) {
- Rep rep;
- rep.set_uintval(u128(hi, lo));
- return rep.is_nan();
- };
-
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Pseudo-Infinity
- 0b0000000000000000000000000000000000000000000000000000000000000000));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Pseudo Not a Number
- 0b0000000000000000000000000000000000000000000000000000000000000001));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Pseudo Not a Number
- 0b0100000000000000000000000000000000000000000000000000000000000000));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Signalling Not a Number
- 0b1000000000000000000000000000000000000000000000000000000000000001));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Floating-point Indefinite
- 0b1100000000000000000000000000000000000000000000000000000000000000));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111111, // NAN : Quiet Not a Number
- 0b1100000000000000000000000000000000000000000000000000000000000001));
- EXPECT_TRUE(is_nan(
- 0b0'111111111111110, // NAN : Unnormal
- 0b0000000000000000000000000000000000000000000000000000000000000000));
-
- EXPECT_FALSE(is_nan(
- 0b0'000000000000000, // Zero
- 0b0000000000000000000000000000000000000000000000000000000000000000));
- EXPECT_FALSE(is_nan(
- 0b0'000000000000000, // Subnormal
- 0b0000000000000000000000000000000000000000000000000000000000000001));
- EXPECT_FALSE(is_nan(
- 0b0'000000000000000, // Pseudo Denormal
- 0b1000000000000000000000000000000000000000000000000000000000000001));
- EXPECT_FALSE(is_nan(
- 0b0'111111111111111, // Infinity
- 0b1000000000000000000000000000000000000000000000000000000000000000));
- EXPECT_FALSE(is_nan(
- 0b0'111111111111110, // Normalized
- 0b1000000000000000000000000000000000000000000000000000000000000000));
+ EXPECT_TRUE( // NAN : Pseudo-Infinity
+ Rep(0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Pseudo Not a Number
+ Rep(0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000001_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Pseudo Not a Number
+ Rep(0b0'111111111111111'0100000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Signalling Not a Number
+ Rep(0b0'111111111111111'1000000000000000000000000000000000000000000000000000000000000001_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Floating-point Indefinite
+ Rep(0b0'111111111111111'1100000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Quiet Not a Number
+ Rep(0b0'111111111111111'1100000000000000000000000000000000000000000000000000000000000001_u128)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Unnormal
+ Rep(0b0'111111111111110'0000000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_FALSE( // Zero
+ Rep(0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_FALSE( // Subnormal
+ Rep(0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000001_u128)
+ .is_nan());
+ EXPECT_FALSE( // Pseudo Denormal
+ Rep(0b0'000000000000000'1000000000000000000000000000000000000000000000000000000000000001_u128)
+ .is_nan());
+ EXPECT_FALSE( // Infinity
+ Rep(0b0'111111111111111'1000000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
+ EXPECT_FALSE( // Normalized
+ Rep(0b0'111111111111110'1000000000000000000000000000000000000000000000000000000000000000_u128)
+ .is_nan());
}
enum class FP {
@@ -339,49 +312,49 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
FloatBits zero(0.0f);
EXPECT_TRUE(zero.is_pos());
- EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0));
- EXPECT_EQ(zero.get_mantissa(), static_cast<uint32_t>(0));
- EXPECT_EQ(zero.uintval(), static_cast<uint32_t>(0x00000000));
+ EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(zero.get_mantissa(), 0_u32);
+ EXPECT_EQ(zero.uintval(), 0_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(zero).c_str(),
"0x00000000 = (S: 0, E: 0x0000, M: 0x00000000)");
FloatBits negzero(-0.0f);
EXPECT_TRUE(negzero.is_neg());
- EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0));
- EXPECT_EQ(negzero.get_mantissa(), static_cast<uint32_t>(0));
- EXPECT_EQ(negzero.uintval(), static_cast<uint32_t>(0x80000000));
+ EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(negzero.get_mantissa(), 0_u32);
+ EXPECT_EQ(negzero.uintval(), 0x80000000_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(negzero).c_str(),
"0x80000000 = (S: 1, E: 0x0000, M: 0x00000000)");
FloatBits one(1.0f);
EXPECT_TRUE(one.is_pos());
- EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x7F));
- EXPECT_EQ(one.get_mantissa(), static_cast<uint32_t>(0));
- EXPECT_EQ(one.uintval(), static_cast<uint32_t>(0x3F800000));
+ EXPECT_EQ(one.get_biased_exponent(), 0x7F_u16);
+ EXPECT_EQ(one.get_mantissa(), 0_u32);
+ EXPECT_EQ(one.uintval(), 0x3F800000_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(one).c_str(),
"0x3F800000 = (S: 0, E: 0x007F, M: 0x00000000)");
FloatBits negone(-1.0f);
EXPECT_TRUE(negone.is_neg());
- EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x7F));
- EXPECT_EQ(negone.get_mantissa(), static_cast<uint32_t>(0));
- EXPECT_EQ(negone.uintval(), static_cast<uint32_t>(0xBF800000));
+ EXPECT_EQ(negone.get_biased_exponent(), 0x7F_u16);
+ EXPECT_EQ(negone.get_mantissa(), 0_u32);
+ EXPECT_EQ(negone.uintval(), 0xBF800000_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(negone).c_str(),
"0xBF800000 = (S: 1, E: 0x007F, M: 0x00000000)");
FloatBits num(1.125f);
EXPECT_TRUE(num.is_pos());
- EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x7F));
- EXPECT_EQ(num.get_mantissa(), static_cast<uint32_t>(0x00100000));
- EXPECT_EQ(num.uintval(), static_cast<uint32_t>(0x3F900000));
+ EXPECT_EQ(num.get_biased_exponent(), 0x7F_u16);
+ EXPECT_EQ(num.get_mantissa(), 0x00100000_u32);
+ EXPECT_EQ(num.uintval(), 0x3F900000_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(num).c_str(),
"0x3F900000 = (S: 0, E: 0x007F, M: 0x00100000)");
FloatBits negnum(-1.125f);
EXPECT_TRUE(negnum.is_neg());
- EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x7F));
- EXPECT_EQ(negnum.get_mantissa(), static_cast<uint32_t>(0x00100000));
- EXPECT_EQ(negnum.uintval(), static_cast<uint32_t>(0xBF900000));
+ EXPECT_EQ(negnum.get_biased_exponent(), 0x7F_u16);
+ EXPECT_EQ(negnum.get_mantissa(), 0x00100000_u32);
+ EXPECT_EQ(negnum.uintval(), 0xBF900000_u32);
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
"0xBF900000 = (S: 1, E: 0x007F, M: 0x00100000)");
@@ -401,49 +374,49 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
DoubleBits zero(0.0);
EXPECT_TRUE(zero.is_pos());
- EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(zero.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
- EXPECT_EQ(zero.uintval(), static_cast<uint64_t>(0x0000000000000000));
+ EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(zero.get_mantissa(), 0_u64);
+ EXPECT_EQ(zero.uintval(), 0_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(zero).c_str(),
"0x0000000000000000 = (S: 0, E: 0x0000, M: 0x0000000000000000)");
DoubleBits negzero(-0.0);
EXPECT_TRUE(negzero.is_neg());
- EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(negzero.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
- EXPECT_EQ(negzero.uintval(), static_cast<uint64_t>(0x8000000000000000));
+ EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(negzero.get_mantissa(), 0_u64);
+ EXPECT_EQ(negzero.uintval(), 0x8000000000000000_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(negzero).c_str(),
"0x8000000000000000 = (S: 1, E: 0x0000, M: 0x0000000000000000)");
DoubleBits one(1.0);
EXPECT_TRUE(one.is_pos());
- EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
- EXPECT_EQ(one.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
- EXPECT_EQ(one.uintval(), static_cast<uint64_t>(0x3FF0000000000000));
+ EXPECT_EQ(one.get_biased_exponent(), 0x03FF_u16);
+ EXPECT_EQ(one.get_mantissa(), 0_u64);
+ EXPECT_EQ(one.uintval(), 0x3FF0000000000000_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(one).c_str(),
"0x3FF0000000000000 = (S: 0, E: 0x03FF, M: 0x0000000000000000)");
DoubleBits negone(-1.0);
EXPECT_TRUE(negone.is_neg());
- EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
- EXPECT_EQ(negone.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
- EXPECT_EQ(negone.uintval(), static_cast<uint64_t>(0xBFF0000000000000));
+ EXPECT_EQ(negone.get_biased_exponent(), 0x03FF_u16);
+ EXPECT_EQ(negone.get_mantissa(), 0_u64);
+ EXPECT_EQ(negone.uintval(), 0xBFF0000000000000_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(negone).c_str(),
"0xBFF0000000000000 = (S: 1, E: 0x03FF, M: 0x0000000000000000)");
DoubleBits num(1.125);
EXPECT_TRUE(num.is_pos());
- EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
- EXPECT_EQ(num.get_mantissa(), static_cast<uint64_t>(0x0002000000000000));
- EXPECT_EQ(num.uintval(), static_cast<uint64_t>(0x3FF2000000000000));
+ EXPECT_EQ(num.get_biased_exponent(), 0x03FF_u16);
+ EXPECT_EQ(num.get_mantissa(), 0x0002000000000000_u64);
+ EXPECT_EQ(num.uintval(), 0x3FF2000000000000_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(num).c_str(),
"0x3FF2000000000000 = (S: 0, E: 0x03FF, M: 0x0002000000000000)");
DoubleBits negnum(-1.125);
EXPECT_TRUE(negnum.is_neg());
- EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
- EXPECT_EQ(negnum.get_mantissa(), static_cast<uint64_t>(0x0002000000000000));
- EXPECT_EQ(negnum.uintval(), static_cast<uint64_t>(0xBFF2000000000000));
+ EXPECT_EQ(negnum.get_biased_exponent(), 0x03FF_u16);
+ EXPECT_EQ(negnum.get_mantissa(), 0x0002000000000000_u64);
+ EXPECT_EQ(negnum.uintval(), 0xBFF2000000000000_u64);
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
"0xBFF2000000000000 = (S: 1, E: 0x03FF, M: 0x0002000000000000)");
@@ -467,10 +440,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits zero(0.0l);
EXPECT_TRUE(zero.is_pos());
- EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(zero.uintval(), static_cast<UInt128>(0x0000000000000000) << 64);
+ EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(zero.get_mantissa(), 0_u128);
+ EXPECT_EQ(zero.uintval(), 0_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(zero).c_str(),
"0x00000000000000000000000000000000 = "
@@ -478,10 +450,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits negzero(-0.0l);
EXPECT_TRUE(negzero.is_neg());
- EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negzero.uintval(), static_cast<UInt128>(0x1) << 79);
+ EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(negzero.get_mantissa(), 0_u128);
+ EXPECT_EQ(negzero.uintval(), 0x80000000000000000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negzero).c_str(),
"0x00000000000080000000000000000000 = "
@@ -489,9 +460,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits one(1.0l);
EXPECT_TRUE(one.is_pos());
- EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
- EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF8) << 60);
+ EXPECT_EQ(one.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(one.get_mantissa(), 0_u128);
+ EXPECT_EQ(one.uintval(), 0x3FFF8000000000000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(one).c_str(),
"0x0000000000003FFF8000000000000000 = "
@@ -499,10 +470,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits negone(-1.0l);
EXPECT_TRUE(negone.is_neg());
- EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negone.uintval(), static_cast<UInt128>(0xBFFF8) << 60);
+ EXPECT_EQ(negone.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negone.get_mantissa(), 0_u128);
+ EXPECT_EQ(negone.uintval(), 0xBFFF8000000000000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negone).c_str(),
"0x000000000000BFFF8000000000000000 = "
@@ -510,9 +480,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits num(1.125l);
EXPECT_TRUE(num.is_pos());
- EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x1) << 60);
- EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF9) << 60);
+ EXPECT_EQ(num.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(num.get_mantissa(), 0x1000000000000000_u128);
+ EXPECT_EQ(num.uintval(), 0x3FFF9000000000000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(num).c_str(),
"0x0000000000003FFF9000000000000000 = "
@@ -520,9 +490,9 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits negnum(-1.125l);
EXPECT_TRUE(negnum.is_neg());
- EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x1) << 60);
- EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF9) << 60);
+ EXPECT_EQ(negnum.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negnum.get_mantissa(), 0x1000000000000000_u128);
+ EXPECT_EQ(negnum.uintval(), 0xBFFF9000000000000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negnum).c_str(),
"0x000000000000BFFF9000000000000000 = "
@@ -547,57 +517,54 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
LongDoubleBits zero(0.0l);
EXPECT_TRUE(zero.is_pos());
- EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(zero.uintval(), static_cast<UInt128>(0x0000000000000000) << 64);
+ EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(zero.get_mantissa(), 0_u128);
+ EXPECT_EQ(zero.uintval(), 0_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(zero).c_str(),
"0x00000000000000000000000000000000 = "
"(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
LongDoubleBits negzero(-0.0l);
EXPECT_TRUE(negzero.is_neg());
- EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negzero.uintval(), static_cast<UInt128>(0x1) << 127);
+ EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(negzero.get_mantissa(), 0_u128);
+ EXPECT_EQ(negzero.uintval(), 0x80000000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negzero).c_str(),
"0x80000000000000000000000000000000 = "
"(S: 1, E: 0x0000, M: 0x00000000000000000000000000000000)");
LongDoubleBits one(1.0l);
EXPECT_TRUE(one.is_pos());
- EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
- EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF) << 112);
+ EXPECT_EQ(one.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(one.get_mantissa(), 0_u128);
+ EXPECT_EQ(one.uintval(), 0x3FFF0000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(one).c_str(),
"0x3FFF0000000000000000000000000000 = "
"(S: 0, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
LongDoubleBits negone(-1.0l);
EXPECT_TRUE(negone.is_neg());
- EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negone.uintval(), static_cast<UInt128>(0xBFFF) << 112);
+ EXPECT_EQ(negone.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negone.get_mantissa(), 0_u128);
+ EXPECT_EQ(negone.uintval(), 0xBFFF0000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negone).c_str(),
"0xBFFF0000000000000000000000000000 = "
"(S: 1, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
LongDoubleBits num(1.125l);
EXPECT_TRUE(num.is_pos());
- EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x2) << 108);
- EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF2) << 108);
+ EXPECT_EQ(num.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(num.get_mantissa(), 0x2000000000000000000000000000_u128);
+ EXPECT_EQ(num.uintval(), 0x3FFF2000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(num).c_str(),
"0x3FFF2000000000000000000000000000 = "
"(S: 0, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
LongDoubleBits negnum(-1.125l);
EXPECT_TRUE(negnum.is_neg());
- EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x2) << 108);
- EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF2) << 108);
+ EXPECT_EQ(negnum.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negnum.get_mantissa(), 0x2000000000000000000000000000_u128);
+ EXPECT_EQ(negnum.uintval(), 0xBFFF2000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
"0xBFFF2000000000000000000000000000 = "
"(S: 1, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
@@ -621,57 +588,54 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
Float128Bits zero = Float128Bits::zero(Sign::POS);
EXPECT_TRUE(zero.is_pos());
- EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(zero.uintval(), static_cast<UInt128>(0x0000000000000000) << 64);
+ EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(zero.get_mantissa(), 0_u128);
+ EXPECT_EQ(zero.uintval(), 0_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(zero).c_str(),
"0x00000000000000000000000000000000 = "
"(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
Float128Bits negzero = Float128Bits::zero(Sign::NEG);
EXPECT_TRUE(negzero.is_neg());
- EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
- EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negzero.uintval(), static_cast<UInt128>(0x1) << 127);
+ EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
+ EXPECT_EQ(negzero.get_mantissa(), 0_u128);
+ EXPECT_EQ(negzero.uintval(), 0x80000000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negzero).c_str(),
"0x80000000000000000000000000000000 = "
"(S: 1, E: 0x0000, M: 0x00000000000000000000000000000000)");
Float128Bits one(float128(1.0));
EXPECT_TRUE(one.is_pos());
- EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
- EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF) << 112);
+ EXPECT_EQ(one.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(one.get_mantissa(), 0_u128);
+ EXPECT_EQ(one.uintval(), 0x3FFF0000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(one).c_str(),
"0x3FFF0000000000000000000000000000 = "
"(S: 0, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
Float128Bits negone(float128(-1.0));
EXPECT_TRUE(negone.is_neg());
- EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
- << 64);
- EXPECT_EQ(negone.uintval(), static_cast<UInt128>(0xBFFF) << 112);
+ EXPECT_EQ(negone.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negone.get_mantissa(), 0_u128);
+ EXPECT_EQ(negone.uintval(), 0xBFFF0000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negone).c_str(),
"0xBFFF0000000000000000000000000000 = "
"(S: 1, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
Float128Bits num(float128(1.125));
EXPECT_TRUE(num.is_pos());
- EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x2) << 108);
- EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF2) << 108);
+ EXPECT_EQ(num.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(num.get_mantissa(), 0x2000000000000000000000000000_u128);
+ EXPECT_EQ(num.uintval(), 0x3FFF2000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(num).c_str(),
"0x3FFF2000000000000000000000000000 = "
"(S: 0, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
Float128Bits negnum(float128(-1.125));
EXPECT_TRUE(negnum.is_neg());
- EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
- EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x2) << 108);
- EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF2) << 108);
+ EXPECT_EQ(negnum.get_biased_exponent(), 0x3FFF_u16);
+ EXPECT_EQ(negnum.get_mantissa(), 0x2000000000000000000000000000_u128);
+ EXPECT_EQ(negnum.uintval(), 0xBFFF2000000000000000000000000000_u128);
EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
"0xBFFF2000000000000000000000000000 = "
"(S: 1, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
diff --git a/libc/test/src/__support/integer_literals_test.cpp b/libc/test/src/__support/integer_literals_test.cpp
new file mode 100644
index 00000000000000..10c3625a0e5a49
--- /dev/null
+++ b/libc/test/src/__support/integer_literals_test.cpp
@@ -0,0 +1,134 @@
+
+//===-- Unittests for user defined integer literals -----------------------===//
+//
+// 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 "src/__support/integer_literals.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::operator""_u8;
+using LIBC_NAMESPACE::operator""_u16;
+using LIBC_NAMESPACE::operator""_u32;
+using LIBC_NAMESPACE::operator""_u64;
+using LIBC_NAMESPACE::operator""_u128;
+using LIBC_NAMESPACE::operator""_u256;
+
+TEST(LlvmLibcIntegerLiteralTest, u8) {
+ EXPECT_EQ(uint8_t(0), 0_u8);
+ EXPECT_EQ(uint8_t(UINT8_MAX), 255_u8);
+ EXPECT_EQ(uint8_t(UINT8_MAX), 0xFF_u8);
+ EXPECT_EQ(uint8_t(UINT8_MAX), 0b11111111_u8);
+}
+
+TEST(LlvmLibcIntegerLiteralTest, u16) {
+ EXPECT_EQ(uint16_t(0), 0_u16);
+ EXPECT_EQ(uint16_t(UINT8_MAX), 255_u16);
+ EXPECT_EQ(uint16_t(UINT8_MAX), 0xFF_u16);
+ EXPECT_EQ(uint16_t(UINT8_MAX), 0b11111111_u16);
+ EXPECT_EQ(uint16_t(UINT16_MAX), 65535_u16);
+ EXPECT_EQ(uint16_t(UINT16_MAX), 0xFFFF_u16);
+ EXPECT_EQ(uint16_t(UINT16_MAX), 0b11111111'11111111_u16);
+}
+
+TEST(LlvmLibcIntegerLiteralTest, u32) {
+ EXPECT_EQ(uint32_t(0), 0_u32);
+ EXPECT_EQ(uint32_t(UINT8_MAX), 255_u32);
+ EXPECT_EQ(uint32_t(UINT8_MAX), 0xFF_u32);
+ EXPECT_EQ(uint32_t(UINT8_MAX), 0b11111111_u32);
+ EXPECT_EQ(uint32_t(UINT16_MAX), 65535_u32);
+ EXPECT_EQ(uint32_t(UINT16_MAX), 0xFFFF_u32);
+ EXPECT_EQ(uint32_t(UINT16_MAX), 0b11111111'11111111_u32);
+ EXPECT_EQ(uint32_t(UINT32_MAX), 4294967295_u32);
+ EXPECT_EQ(uint32_t(UINT32_MAX), 0xFFFFFFFF_u32);
+ EXPECT_EQ(uint32_t(UINT32_MAX), 0b1111111111111111'1111111111111111_u32);
+}
+
+TEST(LlvmLibcIntegerLiteralTest, u64) {
+ EXPECT_EQ(uint64_t(0), 0_u64);
+ EXPECT_EQ(uint64_t(UINT8_MAX), 255_u64);
+ EXPECT_EQ(uint64_t(UINT8_MAX), 0xFF_u64);
+ EXPECT_EQ(uint64_t(UINT8_MAX), 0b11111111_u64);
+ EXPECT_EQ(uint64_t(UINT16_MAX), 65535_u64);
+ EXPECT_EQ(uint64_t(UINT16_MAX), 0xFFFF_u64);
+ EXPECT_EQ(uint64_t(UINT16_MAX), 0b11111111'11111111_u64);
+ EXPECT_EQ(uint64_t(UINT32_MAX), 4294967295_u64);
+ EXPECT_EQ(uint64_t(UINT32_MAX), 0xFFFFFFFF_u64);
+ EXPECT_EQ(uint64_t(UINT32_MAX), 0b1111111111111111'1111111111111111_u64);
+ EXPECT_EQ(uint64_t(UINT64_MAX), 18446744073709551615_u64);
+ EXPECT_EQ(uint64_t(UINT64_MAX), 0xFFFFFFFF'FFFFFFFF_u64);
+ EXPECT_EQ(
+ uint64_t(UINT64_MAX),
+ 0b1111111111111111'1111111111111111'1111111111111111'1111111111111111_u64);
+}
+
+TEST(LlvmLibcIntegerLiteralTest, u128) {
+#if defined(__SIZEOF_INT128__)
+ const __uint128_t ZERO = 0;
+ const __uint128_t U8_MAX = UINT8_MAX;
+ const __uint128_t U16_MAX = UINT16_MAX;
+ const __uint128_t U32_MAX = UINT32_MAX;
+ const __uint128_t U64_MAX = UINT64_MAX;
+ const __uint128_t U128_MAX = (U64_MAX << 64) | U64_MAX;
+#else
+ const UInt128 ZERO = 0;
+ const UInt128 U8_MAX = UINT8_MAX;
+ const UInt128 U16_MAX = UINT16_MAX;
+ const UInt128 U32_MAX = UINT32_MAX;
+ const UInt128 U64_MAX = UINT64_MAX;
+ const UInt128 U128_MAX = (U64_MAX << 64) | U64_MAX;
+#endif
+ EXPECT_EQ(ZERO, 0_u128);
+ EXPECT_EQ(U8_MAX, 255_u128);
+ EXPECT_EQ(U8_MAX, 0xFF_u128);
+ EXPECT_EQ(U8_MAX, 0b11111111_u128);
+ EXPECT_EQ(U16_MAX, 65535_u128);
+ EXPECT_EQ(U16_MAX, 0xFFFF_u128);
+ EXPECT_EQ(U16_MAX, 0b11111111'11111111_u128);
+ EXPECT_EQ(U32_MAX, 4294967295_u128);
+ EXPECT_EQ(U32_MAX, 0xFFFFFFFF_u128);
+ EXPECT_EQ(U32_MAX, 0b1111111111111111'1111111111111111_u128);
+ EXPECT_EQ(U64_MAX, 18446744073709551615_u128);
+ EXPECT_EQ(U64_MAX, 0xFFFFFFFF'FFFFFFFF_u128);
+ EXPECT_EQ(
+ U64_MAX,
+ 0b1111111111111111'1111111111111111'1111111111111111'1111111111111111_u128);
+ EXPECT_EQ(U128_MAX, 340282366920938463463374607431768211455_u128);
+ EXPECT_EQ(U128_MAX, 0xFFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF_u128);
+ EXPECT_EQ(
+ U128_MAX,
+ 0b1111111111111111'1111111111111111'1111111111111111'1111111111111111'1111111111111111'1111111111111111'1111111111111111'1111111111111111_u128);
+}
+
+TEST(LlvmLibcIntegerLiteralTest, u256) {
+ using UInt256 = LIBC_NAMESPACE::cpp::UInt<256>;
+ const UInt256 ZERO = 0;
+ const UInt256 U8_MAX = UINT8_MAX;
+ const UInt256 U16_MAX = UINT16_MAX;
+ const UInt256 U32_MAX = UINT32_MAX;
+ const UInt256 U64_MAX = UINT64_MAX;
+ const UInt256 U128_MAX = (U64_MAX << 64) | U64_MAX;
+ const UInt256 U256_MAX = (U128_MAX << 128) | U128_MAX;
+ EXPECT_EQ(ZERO, 0_u256);
+ EXPECT_EQ(U8_MAX, 255_u256);
+ EXPECT_EQ(U8_MAX, 0xFF_u256);
+ EXPECT_EQ(U8_MAX, 0b11111111_u256);
+ EXPECT_EQ(U16_MAX, 65535_u256);
+ EXPECT_EQ(U16_MAX, 0xFFFF_u256);
+ EXPECT_EQ(U16_MAX, 0b11111111'11111111_u256);
+ EXPECT_EQ(U32_MAX, 4294967295_u256);
+ EXPECT_EQ(U32_MAX, 0xFFFFFFFF_u256);
+ EXPECT_EQ(U32_MAX, 0b1111111111111111'1111111111111111_u256);
+ EXPECT_EQ(U64_MAX, 18446744073709551615_u256);
+ EXPECT_EQ(U64_MAX, 0xFFFFFFFF'FFFFFFFF_u256);
+ EXPECT_EQ(
+ U64_MAX,
+ 0b1111111111111111'1111111111111111'1111111111111111'1111111111111111_u256);
+ EXPECT_EQ(U128_MAX, 0xFFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF_u256);
+ EXPECT_EQ(
+ U256_MAX,
+ 0xFFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF'FFFFFFFF_u256);
+}
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index fd6d1dc047f428..f99305974fd3bc 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -472,6 +472,14 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_integer_literals",
+ hdrs = ["src/__support/integer_literals.h"],
+ deps = [
+ ":__support_uint128",
+ ],
+)
+
libc_support_library(
name = "__support_str_to_num_result",
hdrs = ["src/__support/str_to_num_result.h"],
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
index 22f4d03ee900b6..e691d3c3d2ebdd 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
@@ -99,3 +99,11 @@ libc_test(
"//libc:__support_char_vector",
],
)
+
+libc_test(
+ name = "integer_literals_test",
+ srcs = ["integer_literals_test.cpp"],
+ deps = [
+ "//libc:__support_integer_literals",
+ ],
+)
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
index 461d5127a42a74..76443fc5d9f85b 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/FPUtil/BUILD.bazel
@@ -16,6 +16,7 @@ libc_test(
deps = [
"//libc:__support_fputil_fp_bits",
"//libc:__support_fputil_fpbits_str",
+ "//libc:__support_integer_literals",
],
)
>From 3eadb081a807b2e90cf12cab1750be1bc57657bc Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 9 Feb 2024 17:04:56 +0000
Subject: [PATCH 2/6] Add CMake support, simplify code, add documentation
---
libc/src/__support/CMakeLists.txt | 6 ++++++
libc/src/__support/integer_literals.h | 24 ++++++++++++------------
libc/test/src/__support/CMakeLists.txt | 11 +++++++++++
3 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index bd814a080c4f87..d95519938cc472 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -146,6 +146,12 @@ add_header_library(
libc.src.errno.errno
)
+add_header_library(
+ integer_literals
+ HDRS
+ integer_literals.h
+)
+
add_header_library(
integer_operations
HDRS
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
index c588cf9a63986d..48f297d8f1a75f 100644
--- a/libc/src/__support/integer_literals.h
+++ b/libc/src/__support/integer_literals.h
@@ -17,23 +17,23 @@
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include <limits.h> // CHAR_BIT
#include <stddef.h> // size_t
-#include <stdint.h> // __uintxx_t
+#include <stdint.h> // uintxx_t
namespace LIBC_NAMESPACE {
-LIBC_INLINE constexpr __uint8_t operator""_u8(unsigned long long value) {
+LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) {
return value;
}
-LIBC_INLINE constexpr __uint16_t operator""_u16(unsigned long long value) {
+LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) {
return value;
}
-LIBC_INLINE constexpr __uint32_t operator""_u32(unsigned long long value) {
+LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) {
return value;
}
-LIBC_INLINE constexpr __uint64_t operator""_u64(unsigned long long value) {
+LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) {
return value;
}
@@ -77,9 +77,9 @@ template <typename T, int base> struct DigitBuffer {
LIBC_INLINE static constexpr uint8_t get_digit_value(const char c) {
const auto to_lower = [](char c) { return c | 32; };
const auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
- const auto is_lower = [](char c) { return 'a' <= c && c <= 'z'; };
- const auto is_upper = [](char c) { return 'A' <= c && c <= 'Z'; };
- const auto is_alpha = [&](char c) { return is_lower(c) || is_upper(c); };
+ const auto is_alpha = [](char c) {
+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+ };
if (is_digit(c))
return c - '0';
if (base > 10 && is_alpha(c))
@@ -109,10 +109,10 @@ template <typename T> struct Parser {
};
// Specialization for cpp::UInt<N>.
-// Because this code runs at compile time we try to make it as efficient as
-// possible. For binary and hexadecimal formats we read digits by chunks of 64
-// bits and produce the BigInt internal representation direcly. For decimal
-// numbers we go the slow path and use BigInt arithmetic.
+// Because this code runs at compile time we try to make it efficient. For
+// binary and hexadecimal formats we read digits by chunks of 64 bits and
+// produce the BigInt internal representation direcly. For decimal numbers we go
+// the slow path and use slower BigInt arithmetic.
template <size_t N> struct Parser<LIBC_NAMESPACE::cpp::UInt<N>> {
using UIntT = cpp::UInt<N>;
template <int base> static constexpr UIntT parse(const char *str) {
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
index a92e6da56096a1..231b01e0ee50a7 100644
--- a/libc/test/src/__support/CMakeLists.txt
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -97,6 +97,17 @@ add_libc_test(
libc.src.__support.CPP.optional
)
+add_libc_test(
+ integer_literals_test
+ SUITE
+ libc-support-tests
+ SRCS
+ integer_literals_test.cpp
+ DEPENDS
+ libc.src.__support.integer_literals
+ libc.src.__support.CPP.optional
+)
+
add_libc_test(
fixedvector_test
SUITE
>From 41df455f7703dde4528794a14ee5f0130393ffbd Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 12 Feb 2024 10:19:42 +0000
Subject: [PATCH 3/6] Use `src/__support/CPP/limits.h` instead of `limits.h`
---
libc/src/__support/CMakeLists.txt | 3 +++
libc/src/__support/integer_literals.h | 2 +-
utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index d95519938cc472..013627788940d8 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -150,6 +150,9 @@ add_header_library(
integer_literals
HDRS
integer_literals.h
+ DEPENDS
+ .uint128
+ libc.src.__support.CPP.limits
)
add_header_library(
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
index 48f297d8f1a75f..5f09bb18f7fa3f 100644
--- a/libc/src/__support/integer_literals.h
+++ b/libc/src/__support/integer_literals.h
@@ -13,9 +13,9 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
#define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
+#include "src/__support/CPP/limits.h" // CHAR_BIT
#include "src/__support/UInt128.h" // UInt128
#include "src/__support/macros/attributes.h" // LIBC_INLINE
-#include <limits.h> // CHAR_BIT
#include <stddef.h> // size_t
#include <stdint.h> // uintxx_t
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index f99305974fd3bc..d4c62db2b0bfd2 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -476,6 +476,7 @@ libc_support_library(
name = "__support_integer_literals",
hdrs = ["src/__support/integer_literals.h"],
deps = [
+ ":__support_cpp_limits",
":__support_uint128",
],
)
>From 035cf51c53640d8039be45a23429b3789cd80e90 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 12 Feb 2024 10:45:45 +0000
Subject: [PATCH 4/6] Add missing CMake dependency
---
libc/test/src/__support/FPUtil/CMakeLists.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 897434ceff6007..f1a027a514ba23 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -23,6 +23,7 @@ add_libc_test(
DEPENDS
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
+ libc.src.__support.integer_literals
)
add_fp_unittest(
>From f21277051cafc5c9c705c12a739f5374b453de09 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 14 Feb 2024 10:03:04 +0000
Subject: [PATCH 5/6] Documentation of builtin_unreachable usage
---
libc/src/__support/integer_literals.h | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
index 5f09bb18f7fa3f..50ae7a2ce3ab5b 100644
--- a/libc/src/__support/integer_literals.h
+++ b/libc/src/__support/integer_literals.h
@@ -92,8 +92,13 @@ template <typename T, int base> struct DigitBuffer {
if (c == '\'')
return; // ' is valid but not taken into account.
const uint8_t value = get_digit_value(c);
- if (value == 255 || size >= MAX_DIGITS)
+ if (value == 255 || size >= MAX_DIGITS) {
+ // During constant evaluation `__builtin_unreachable` will halt the
+ // compiler as it is not executable. This is preferable over `assert` that
+ // will only trigger in debug mode. Also we can't use `static_assert`
+ // because `value` and `size` are not constant.
__builtin_unreachable(); // invalid or too many characters.
+ }
digits[size] = value;
++size;
}
@@ -111,8 +116,8 @@ template <typename T> struct Parser {
// Specialization for cpp::UInt<N>.
// Because this code runs at compile time we try to make it efficient. For
// binary and hexadecimal formats we read digits by chunks of 64 bits and
-// produce the BigInt internal representation direcly. For decimal numbers we go
-// the slow path and use slower BigInt arithmetic.
+// produce the BigInt internal representation direcly. For decimal numbers we
+// go the slow path and use slower BigInt arithmetic.
template <size_t N> struct Parser<LIBC_NAMESPACE::cpp::UInt<N>> {
using UIntT = cpp::UInt<N>;
template <int base> static constexpr UIntT parse(const char *str) {
>From 909eea1ad24362776e6eaa7fc76e74c81219d33c Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 14 Feb 2024 10:10:24 +0000
Subject: [PATCH 6/6] Better document the bits per character rationale
---
libc/src/__support/integer_literals.h | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
index 50ae7a2ce3ab5b..74c873cb976af2 100644
--- a/libc/src/__support/integer_literals.h
+++ b/libc/src/__support/integer_literals.h
@@ -54,9 +54,10 @@ LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits,
// A static buffer to hold the digits for a T.
template <typename T, int base> struct DigitBuffer {
static_assert(base == 2 || base == 10 || base == 16);
- // Base 2: one char provides exactly one bit.
- // Base 10: one char provides between three and four bits.
- // Base 16: one char provides exactly four bits.
+ // One character provides log2(base) bits.
+ // Base 2 and 16 provide exactly one and four bits per character respectively.
+ // For base 10, a character provides log2(10) ≈ 3.32... which we round to 3
+ // for the purpose of buffer allocation.
LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 1
: base == 10 ? 3
: base == 16 ? 4
More information about the libc-commits
mailing list