[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:28 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