[libc-commits] [libc] [llvm] [libc] Add user defined literals to ease testing (PR #81267)
Guillaume Chatelet via libc-commits
libc-commits at lists.llvm.org
Mon Feb 12 02:33:49 PST 2024
================
@@ -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.
----------------
gchatelet wrote:
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.
https://github.com/llvm/llvm-project/pull/81267
More information about the libc-commits
mailing list