[libc-commits] [libc] 86fe88c - [libc] Support constexpr uint initialization
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Apr 20 13:09:21 PDT 2023
Author: Michael Jones
Date: 2023-04-20T13:09:15-07:00
New Revision: 86fe88c8d91bb30870007c48ca71672fda8d6492
URL: https://github.com/llvm/llvm-project/commit/86fe88c8d91bb30870007c48ca71672fda8d6492
DIFF: https://github.com/llvm/llvm-project/commit/86fe88c8d91bb30870007c48ca71672fda8d6492.diff
LOG: [libc] Support constexpr uint initialization
Uint addition and subtraction normally use builtins which aren't
constexpr. This patch adds an rvalue overload version of the addition
and subtraction operation that is always constexpr.
Reviewed By: sivachandra
Differential Revision: https://reviews.llvm.org/D148759
Added:
Modified:
libc/src/__support/FPUtil/FloatProperties.h
libc/src/__support/FPUtil/NearestIntegerOperations.h
libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
libc/src/__support/UInt.h
libc/src/__support/builtin_wrappers.h
libc/test/src/__support/uint_test.cpp
Removed:
################################################################################
diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h
index be87390118c4d..93e0c18ee940b 100644
--- a/libc/src/__support/FPUtil/FloatProperties.h
+++ b/libc/src/__support/FPUtil/FloatProperties.h
@@ -129,7 +129,7 @@ template <> struct FloatProperties<long double> {
static constexpr uint32_t EXPONENT_BIAS = 16383;
static constexpr BitsType EXP_MANT_MASK =
- MANTISSA_MASK + EXPLICIT_BIT_MASK + EXPONENT_MASK;
+ MANTISSA_MASK | EXPLICIT_BIT_MASK | EXPONENT_MASK;
static_assert(EXP_MANT_MASK == (~SIGN_MASK & FULL_WIDTH_MASK),
"Exponent and mantissa masks are not as expected.");
@@ -157,7 +157,7 @@ template <> struct FloatProperties<long double> {
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 16383;
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
+ static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h
index 06aa9484c3f70..7081fc59057cf 100644
--- a/libc/src/__support/FPUtil/NearestIntegerOperations.h
+++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h
@@ -133,7 +133,8 @@ LIBC_INLINE T round(T x) {
}
uint32_t trim_size = MantissaWidth<T>::VALUE - exponent;
- bool half_bit_set = bits.get_mantissa() & (UIntType(1) << (trim_size - 1));
+ bool half_bit_set =
+ bool(bits.get_mantissa() & (UIntType(1) << (trim_size - 1)));
bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
T trunc_value = T(bits);
diff --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
index 0ca9b125099af..ba2fddb2a6fed 100644
--- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
+++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
@@ -28,10 +28,14 @@ namespace fputil {
template <unsigned Width> struct Padding;
// i386 padding.
-template <> struct Padding<4> { static constexpr unsigned VALUE = 16; };
+template <> struct Padding<4> {
+ static constexpr unsigned VALUE = 16;
+};
// x86_64 padding.
-template <> struct Padding<8> { static constexpr unsigned VALUE = 48; };
+template <> struct Padding<8> {
+ static constexpr unsigned VALUE = 48;
+};
template <> struct FPBits<long double> {
using UIntType = UInt128;
@@ -45,8 +49,7 @@ template <> struct FPBits<long double> {
static constexpr UIntType MIN_NORMAL =
(UIntType(3) << MantissaWidth<long double>::VALUE);
static constexpr UIntType MAX_NORMAL =
- ((UIntType(MAX_EXPONENT) - 1)
- << (MantissaWidth<long double>::VALUE + 1)) |
+ (UIntType(MAX_EXPONENT - 1) << (MantissaWidth<long double>::VALUE + 1)) |
(UIntType(1) << MantissaWidth<long double>::VALUE) | MAX_SUBNORMAL;
using FloatProp = FloatProperties<long double>;
@@ -86,8 +89,8 @@ template <> struct FPBits<long double> {
}
LIBC_INLINE bool get_implicit_bit() const {
- return ((bits & (UIntType(1) << FloatProp::MANTISSA_WIDTH)) >>
- FloatProp::MANTISSA_WIDTH);
+ return bool((bits & (UIntType(1) << FloatProp::MANTISSA_WIDTH)) >>
+ FloatProp::MANTISSA_WIDTH);
}
LIBC_INLINE void set_sign(bool signVal) {
@@ -97,7 +100,7 @@ template <> struct FPBits<long double> {
}
LIBC_INLINE bool get_sign() const {
- return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
+ return bool((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
}
FPBits() : bits(0) {}
diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index da46d3b316d09..8b273e3689643 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -83,10 +83,16 @@ template <size_t Bits> struct UInt {
return uint32_t(uint64_t(*this));
}
+ constexpr explicit operator uint16_t() const {
+ return uint16_t(uint64_t(*this));
+ }
+
constexpr explicit operator uint8_t() const {
return uint8_t(uint64_t(*this));
}
+ constexpr explicit operator bool() const { return !is_zero(); }
+
UInt<Bits> &operator=(const UInt<Bits> &other) = default;
constexpr bool is_zero() const {
@@ -108,7 +114,7 @@ template <size_t Bits> struct UInt {
return s.carry;
}
- constexpr UInt<Bits> operator+(const UInt<Bits> &other) const {
+ UInt<Bits> operator+(const UInt<Bits> &other) const {
UInt<Bits> result;
SumCarry<uint64_t> s{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
@@ -118,6 +124,18 @@ template <size_t Bits> struct UInt {
return result;
}
+ // This will only apply when initializing a variable from constant values, so
+ // it will always use the constexpr version of add_with_carry.
+ constexpr UInt<Bits> operator+(UInt<Bits> &&other) const {
+ UInt<Bits> result;
+ SumCarry<uint64_t> s{0, 0};
+ for (size_t i = 0; i < WORDCOUNT; ++i) {
+ s = add_with_carry_const(val[i], other.val[i], s.carry);
+ result.val[i] = s.sum;
+ }
+ return result;
+ }
+
constexpr UInt<Bits> &operator+=(const UInt<Bits> &other) {
add(other); // Returned carry value is ignored.
return *this;
@@ -134,7 +152,7 @@ template <size_t Bits> struct UInt {
return d.borrow;
}
- constexpr UInt<Bits> operator-(const UInt<Bits> &other) const {
+ UInt<Bits> operator-(const UInt<Bits> &other) const {
UInt<Bits> result;
DiffBorrow<uint64_t> d{0, 0};
for (size_t i = 0; i < WORDCOUNT; ++i) {
@@ -144,6 +162,16 @@ template <size_t Bits> struct UInt {
return result;
}
+ constexpr UInt<Bits> operator-(UInt<Bits> &&other) const {
+ UInt<Bits> result;
+ DiffBorrow<uint64_t> d{0, 0};
+ for (size_t i = 0; i < WORDCOUNT; ++i) {
+ d = sub_with_borrow_const(val[i], other.val[i], d.borrow);
+ result.val[i] = d.
diff ;
+ }
+ return result;
+ }
+
constexpr UInt<Bits> &operator-=(const UInt<Bits> &other) {
// TODO(lntue): Set overflow flag / errno when carry is true.
sub(other);
diff --git a/libc/src/__support/builtin_wrappers.h b/libc/src/__support/builtin_wrappers.h
index 003d485885329..7681e01f16007 100644
--- a/libc/src/__support/builtin_wrappers.h
+++ b/libc/src/__support/builtin_wrappers.h
@@ -12,8 +12,8 @@
#include "named_pair.h"
#include "src/__support/CPP/type_traits.h"
-#include "src/__support/macros/attributes.h" // LIBC_INLINE
-#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN
+#include "src/__support/macros/attributes.h" // LIBC_INLINE
+#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN
namespace __llvm_libc {
@@ -74,16 +74,26 @@ template <typename T> LIBC_INLINE int unsafe_clz(T val) {
// Add with carry
DEFINE_NAMED_PAIR_TEMPLATE(SumCarry, sum, carry);
+// This version is always valid for constexpr.
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, SumCarry<T>>
-add_with_carry(T a, T b, T carry_in) {
+add_with_carry_const(T a, T b, T carry_in) {
T tmp = a + carry_in;
T sum = b + tmp;
- T carry_out = (sum < b) || (tmp < a);
+ T carry_out = (sum < b) + (tmp < a);
return {sum, carry_out};
}
+// This version is not always valid for constepxr because it's overriden below
+// if builtins are available.
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>,
+ SumCarry<T>>
+add_with_carry(T a, T b, T carry_in) {
+ return add_with_carry_const<T>(a, b, carry_in);
+}
+
#if LIBC_HAS_BUILTIN(__builtin_addc)
// https://clang.llvm.org/docs/LanguageExtensions.html#multiprecision-arithmetic-builtins
@@ -137,16 +147,26 @@ add_with_carry<unsigned long long>(unsigned long long a, unsigned long long b,
// Subtract with borrow
DEFINE_NAMED_PAIR_TEMPLATE(DiffBorrow,
diff , borrow);
+// This version is always valid for constexpr.
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<
cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, DiffBorrow<T>>
-sub_with_borrow(T a, T b, T borrow_in) {
+sub_with_borrow_const(T a, T b, T borrow_in) {
T tmp = a - b;
T
diff = tmp - borrow_in;
- T borrow_out = (
diff > tmp) || (tmp > a);
+ T borrow_out = (
diff > tmp) + (tmp > a);
return {
diff , borrow_out};
}
+// This version is not always valid for constepxr because it's overriden below
+// if builtins are available.
+template <typename T>
+LIBC_INLINE cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>,
+ DiffBorrow<T>>
+sub_with_borrow(T a, T b, T borrow_in) {
+ return sub_with_borrow_const<T>(a, b, borrow_in);
+}
+
#if LIBC_HAS_BUILTIN(__builtin_subc)
// https://clang.llvm.org/docs/LanguageExtensions.html#multiprecision-arithmetic-builtins
diff --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp
index 54b65f4421919..fb266c25da261 100644
--- a/libc/test/src/__support/uint_test.cpp
+++ b/libc/test/src/__support/uint_test.cpp
@@ -526,3 +526,10 @@ TEST(LlvmLibcUIntClassTest, QuickMulHiTests) {
TEST_QUICK_MUL_HI(256, 3);
TEST_QUICK_MUL_HI(512, 7);
}
+
+TEST(LlvmLibcUIntClassTest, ConstexprInitTests) {
+ constexpr LL_UInt128 add = LL_UInt128(1) + LL_UInt128(2);
+ ASSERT_EQ(add, LL_UInt128(3));
+ constexpr LL_UInt128 sub = LL_UInt128(5) - LL_UInt128(4);
+ ASSERT_EQ(sub, LL_UInt128(1));
+}
More information about the libc-commits
mailing list