diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h --- a/libc/src/__support/FPUtil/FloatProperties.h +++ b/libc/src/__support/FPUtil/FloatProperties.h @@ -129,7 +129,7 @@ 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 @@ 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 --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -133,7 +133,8 @@ } uint32_t trim_size = MantissaWidth::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 --- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h +++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h @@ -28,10 +28,14 @@ template 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 { using UIntType = UInt128; @@ -45,8 +49,7 @@ static constexpr UIntType MIN_NORMAL = (UIntType(3) << MantissaWidth::VALUE); static constexpr UIntType MAX_NORMAL = - ((UIntType(MAX_EXPONENT) - 1) - << (MantissaWidth::VALUE + 1)) | + (UIntType(MAX_EXPONENT - 1) << (MantissaWidth::VALUE + 1)) | (UIntType(1) << MantissaWidth::VALUE) | MAX_SUBNORMAL; using FloatProp = FloatProperties; @@ -86,8 +89,8 @@ } 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 @@ } 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 --- a/libc/src/__support/UInt.h +++ b/libc/src/__support/UInt.h @@ -83,10 +83,16 @@ 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 &operator=(const UInt &other) = default; constexpr bool is_zero() const { @@ -108,7 +114,7 @@ return s.carry; } - constexpr UInt operator+(const UInt &other) const { + UInt operator+(const UInt &other) const { UInt result; SumCarry s{0, 0}; for (size_t i = 0; i < WORDCOUNT; ++i) { @@ -118,6 +124,18 @@ 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 operator+(UInt &&other) const { + UInt result; + SumCarry 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 &operator+=(const UInt &other) { add(other); // Returned carry value is ignored. return *this; @@ -134,7 +152,7 @@ return d.borrow; } - constexpr UInt operator-(const UInt &other) const { + UInt operator-(const UInt &other) const { UInt result; DiffBorrow d{0, 0}; for (size_t i = 0; i < WORDCOUNT; ++i) { @@ -144,6 +162,16 @@ return result; } + constexpr UInt operator-(UInt &&other) const { + UInt result; + DiffBorrow 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 &operator-=(const UInt &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 --- 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 @@ // Add with carry DEFINE_NAMED_PAIR_TEMPLATE(SumCarry, sum, carry); +// This version is always valid for constexpr. template LIBC_INLINE constexpr cpp::enable_if_t< cpp::is_integral_v && cpp::is_unsigned_v, SumCarry> -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 +LIBC_INLINE cpp::enable_if_t && cpp::is_unsigned_v, + SumCarry> +add_with_carry(T a, T b, T carry_in) { + return add_with_carry_const(a, b, carry_in); +} + #if LIBC_HAS_BUILTIN(__builtin_addc) // https://clang.llvm.org/docs/LanguageExtensions.html#multiprecision-arithmetic-builtins @@ -137,16 +147,26 @@ // Subtract with borrow DEFINE_NAMED_PAIR_TEMPLATE(DiffBorrow, diff, borrow); +// This version is always valid for constexpr. template LIBC_INLINE constexpr cpp::enable_if_t< cpp::is_integral_v && cpp::is_unsigned_v, DiffBorrow> -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 +LIBC_INLINE cpp::enable_if_t && cpp::is_unsigned_v, + DiffBorrow> +sub_with_borrow(T a, T b, T borrow_in) { + return sub_with_borrow_const(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 --- a/libc/test/src/__support/uint_test.cpp +++ b/libc/test/src/__support/uint_test.cpp @@ -526,3 +526,10 @@ 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)); +}