-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc] Add user defined literals to initialize BigInt
and __uint128_t
constants
#81267
Conversation
@llvm/pr-subscribers-libc Author: Guillaume Chatelet (gchatelet) ChangesPatch is 47.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81267.diff 6 Files Affected:
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());
+...
[truncated]
|
@lntue @michaelrj-google I think this could be useful for testing purposes as we need to deal with the impedance mismatch between C++ types, extensions (i.e., Ideally the functions should be |
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we assert here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These user defined literals are used to build constants so they should run at compile time exclusively. Since LLVM libc is C++17 we don't have ways to enforce it through consteval
but that's the idea nonetheless. If the function is called in a constant context it will force the compile time evaluation of the function.
The nice property of __builtin_unreachable
is that it is not executable by the compiler and so the error is pretty clear : https://godbolt.org/z/PT3j1cKc7
If we go with assert
, we will only catch the issue when compiling in debug mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about static_assert
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So unfortunately static_assert
can only access constant expressions so that would fail as well
https://godbolt.org/z/ojWbvs3f4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I see what's going on; it's a neat trick. Consider adding a comment above for future travelers to better recognize the trick (and that this will result in an explicit failure in constexpr evaluation context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you forsee usage of these literals outside of libc/test/src/__support/FPUtil/fpbits_test.cpp? It seems like a fair amount of complexity added just to avoid typing out static_cast<>()
in libc/test/src/__support/FPUtil/fpbits_test.cpp. libc/test/src/__support/FPUtil/fpbits_test.cpp is already inconsistent of its use of static_cast vs constructor calls.
The literal syntax doesn't save us much typing over just using the constructors:
static_cast<uint16_t>(1)
u16(1)
1_u16
I do like the idea of these suffixes (they remind me of rust, which I think has these), but if the goal is just to simplify libc/test/src/__support/FPUtil/fpbits_test.cpp then I think we can just consistently use the constructor functions rather than static_cast
consistently throughout libc/test/src/__support/FPUtil/fpbits_test.cpp without adding support for custom literals.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about static_assert
?
Thx for challenging the usefulness of this patch. I think I missed quite a few important pieces of information as I presented it solely for testing purposes. I initially started working on this because @michaelrj-google rightfully mentioned in #80709 (comment) that I should merge Now there are a bunch of places where we rely on constants of type
These constants are initialized with Now, if So indeed there is a bit more to it than just simplifying a few test files (although it also helps in that regard). Please let me know what you think. |
this seems like a useful tool given the difficulties initializing uint128. Currently in the |
+1 on simplifying DyadicFloat and UInt initializations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, yeah sounds useful in multiple places then. Consider adding more context to the commit description.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I see what's going on; it's a neat trick. Consider adding a comment above for future travelers to better recognize the trick (and that this will result in an explicit failure in constexpr evaluation context.
BigInt
and __uint128_t
constants
Adds user defined literal to construct unsigned integer constants. This is useful when constructing constants for non native C++ types like
__uint128_t
or our customBigInt
type.