Skip to content

Commit

Permalink
[libc] Add Uint128 type as a fallback when __uint128_t is not available.
Browse files Browse the repository at this point in the history
Also, the unused specializations of __int128_t have been removed.

Differential Revision: https://reviews.llvm.org/D128304
  • Loading branch information
Siva Chandra Reddy committed Jun 24, 2022
1 parent 056d639 commit 300f8da
Show file tree
Hide file tree
Showing 27 changed files with 365 additions and 309 deletions.
1 change: 1 addition & 0 deletions libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ add_header_library(
libc.include.errno
libc.src.errno.errno
libc.src.__support.CPP.limits
libc.src.__support.CPP.uint128
libc.src.__support.FPUtil.fputil
)

Expand Down
28 changes: 20 additions & 8 deletions libc/src/__support/CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ add_header_library(
Array.h
)

add_header_library(
uint
HDRS
UInt.h
DEPENDS
.array
)

add_header_library(
uint128
HDRS
UInt128.h
DEPENDS
.uint
)

add_header_library(
array_ref
HDRS
Expand Down Expand Up @@ -32,6 +48,8 @@ add_header_library(
limits
HDRS
Limits.h
DEPENDS
.uint
)

add_header_library(
Expand All @@ -44,6 +62,8 @@ add_header_library(
type_traits
HDRS
TypeTraits.h
DEPENDS
.uint
)

add_header_library(
Expand Down Expand Up @@ -77,11 +97,3 @@ add_header_library(
HDRS
error.h
)

add_header_library(
uint
HDRS
UInt.h
DEPENDS
libc.src.__support.CPP.array
)
20 changes: 15 additions & 5 deletions libc/src/__support/CPP/Limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_LIMITS_H
#define LLVM_LIBC_SRC_SUPPORT_CPP_LIMITS_H

#include "UInt.h"

#include <limits.h>

namespace __llvm_libc {
Expand Down Expand Up @@ -72,18 +74,26 @@ template <> class NumericLimits<unsigned char> {
static constexpr unsigned char max() { return UCHAR_MAX; }
static constexpr unsigned char min() { return 0; }
};
// This specialization enables two things:
// 1. On platforms where UInt128 resolves to UInt<128>, this specialization
// provides limits of UInt128.
// 2. On platforms where UInt128 resolves to __uint128_t, this specialization
// allows us to unittest UInt<128>.
template <> class NumericLimits<UInt<128>> {
public:
static constexpr UInt<128> max() { return ~UInt<128>(0); }
static constexpr UInt<128> min() { return 0; }
};
#ifdef __SIZEOF_INT128__
// On platform where UInt128 resolves to __uint128_t, this specialization
// provides the limits of UInt128.
template <> class NumericLimits<__uint128_t> {
public:
static constexpr __uint128_t max() { return ~__uint128_t(0); }
static constexpr __uint128_t min() { return 0; }
};
template <> class NumericLimits<__int128_t> {
public:
static constexpr __int128_t max() { return ~__uint128_t(0) >> 1; }
static constexpr __int128_t min() { return __int128_t(1) << 127; }
};
#endif

} // namespace cpp
} // namespace __llvm_libc

Expand Down
8 changes: 6 additions & 2 deletions libc/src/__support/CPP/TypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,13 @@ template <typename Type> struct IsIntegral {
IsSameV<unsigned int, TypeNoCV> || IsSameV<long, TypeNoCV> ||
IsSameV<unsigned long, TypeNoCV> || IsSameV<long long, TypeNoCV> ||
IsSameV<unsigned long long, TypeNoCV> || IsSameV<bool, TypeNoCV> ||
IsSameV<UInt<128>, TypeNoCV>
// We need to include UInt<128> and __uint128_t when available because
// we want to unittest UInt<128>. If we include only UInt128, then on
// platform where it resolves to __uint128_t, we cannot unittest
// UInt<128>.
IsSameV<__llvm_libc::cpp::UInt<128>, TypeNoCV>
#ifdef __SIZEOF_INT128__
|| IsSameV<__uint128_t, TypeNoCV> || IsSameV<__int128_t, TypeNoCV>
|| IsSameV<__uint128_t, TypeNoCV>
#endif
;
};
Expand Down
23 changes: 17 additions & 6 deletions libc/src/__support/CPP/UInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ template <size_t Bits> class UInt {
return result;
}

constexpr UInt<Bits> &operator<<=(size_t s) {
shift_left(s);
return *this;
}

constexpr void shift_right(size_t s) {
const size_t drop = s / 64; // Number of words to drop
const size_t shift = s % 64; // Bit shift in the remaining words.
Expand All @@ -208,6 +213,11 @@ template <size_t Bits> class UInt {
return result;
}

constexpr UInt<Bits> &operator>>=(size_t s) {
shift_right(s);
return *this;
}

constexpr UInt<Bits> operator&(const UInt<Bits> &other) const {
UInt<Bits> result;
for (size_t i = 0; i < WordCount; ++i)
Expand All @@ -229,6 +239,13 @@ template <size_t Bits> class UInt {
return result;
}

constexpr UInt<Bits> operator~() const {
UInt<Bits> result;
for (size_t i = 0; i < WordCount; ++i)
result.val[i] = ~val[i];
return result;
}

constexpr bool operator==(const UInt<Bits> &other) const {
for (size_t i = 0; i < WordCount; ++i) {
if (val[i] != other.val[i])
Expand Down Expand Up @@ -345,10 +362,4 @@ constexpr UInt<128> UInt<128>::operator*(const UInt<128> &other) const {
} // namespace cpp
} // namespace __llvm_libc

/* TODO: determine the best way to support uint128 using this class.
#if !defined(__SIZEOF_INT128__)
using __uint128_t = __llvm_libc::internal::UInt<128>;
#endif // uint128 is not defined, define it with this class.
*/

#endif // LLVM_LIBC_UTILS_CPP_UINT_H
20 changes: 20 additions & 0 deletions libc/src/__support/CPP/UInt128.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- A 128 bit unsigned int type -----------------------------*- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H
#define LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H

#include "UInt.h"

#if !defined(__SIZEOF_INT128__)
using UInt128 = __llvm_libc::internal::UInt<128>;
#else
using UInt128 = __uint128_t;
#endif

#endif // LLVM_LIBC_SRC_SUPPORT_CPP_UINT128_H
4 changes: 2 additions & 2 deletions libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ add_header_library(
NearestIntegerOperations.h
NormalFloat.h
PlatformDefs.h
UInt.h
builtin_wrappers.h
DEPENDS
libc.include.math
libc.include.errno
libc.include.fenv
libc.src.__support.common
libc.src.__support.CPP.type_traits
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
libc.src.__support.CPP.uint128
libc.src.errno.errno
)

Expand Down
7 changes: 5 additions & 2 deletions libc/src/__support/FPUtil/FloatProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H

#include "PlatformDefs.h"

#include "src/__support/CPP/UInt128.h"

#include <stdint.h>

namespace __llvm_libc {
Expand Down Expand Up @@ -104,7 +107,7 @@ template <> struct FloatProperties<long double> {
// Properties for numbers represented in 80 bits long double on non-Windows x86
// platforms.
template <> struct FloatProperties<long double> {
typedef __uint128_t BitsType;
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");

Expand Down Expand Up @@ -140,7 +143,7 @@ template <> struct FloatProperties<long double> {
// Properties for numbers represented in 128 bits long double on non x86
// platform.
template <> struct FloatProperties<long double> {
typedef __uint128_t BitsType;
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");

Expand Down
5 changes: 4 additions & 1 deletion libc/src/__support/FPUtil/Hypot.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "builtin_wrappers.h"
#include "src/__support/CPP/Bit.h"
#include "src/__support/CPP/TypeTraits.h"
#include "src/__support/CPP/UInt128.h"

namespace __llvm_libc {
namespace fputil {
Expand All @@ -38,7 +39,9 @@ template <> struct DoubleLength<uint16_t> { using Type = uint32_t; };

template <> struct DoubleLength<uint32_t> { using Type = uint64_t; };

template <> struct DoubleLength<uint64_t> { using Type = __uint128_t; };
template <> struct DoubleLength<uint64_t> {
using Type = UInt128;
};

// Correctly rounded IEEE 754 HYPOT(x, y) with round to nearest, ties to even.
//
Expand Down
4 changes: 4 additions & 0 deletions libc/src/__support/FPUtil/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ add_header_library(
HDRS
sqrt.h
sqrt_80_bit_long_double.h
DEPENDS
libc.src.__support.CPP.uint128
)

add_header_library(
fma
HDRS
FMA.h
DEPENDS
libc.src.__support.CPP.uint128
)
13 changes: 7 additions & 6 deletions libc/src/__support/FPUtil/generic/FMA.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "src/__support/CPP/Bit.h"
#include "src/__support/CPP/TypeTraits.h"
#include "src/__support/CPP/UInt128.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/FloatProperties.h"
Expand Down Expand Up @@ -78,12 +79,12 @@ namespace internal {

// Extract the sticky bits and shift the `mantissa` to the right by
// `shift_length`.
static inline bool shift_mantissa(int shift_length, __uint128_t &mant) {
static inline bool shift_mantissa(int shift_length, UInt128 &mant) {
if (shift_length >= 128) {
mant = 0;
return true; // prod_mant is non-zero.
}
__uint128_t mask = (__uint128_t(1) << shift_length) - 1;
UInt128 mask = (UInt128(1) << shift_length) - 1;
bool sticky_bits = (mant & mask) != 0;
mant >>= shift_length;
return sticky_bits;
Expand Down Expand Up @@ -131,9 +132,9 @@ template <> inline double fma<double>(double x, double y, double z) {
return x * y + z;

// Extract mantissa and append hidden leading bits.
__uint128_t x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL;
__uint128_t y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL;
__uint128_t z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL;
UInt128 x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL;
UInt128 y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL;
UInt128 z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL;

// If the exponent of the product x*y > the exponent of z, then no extra
// precision beside the entire product x*y is needed. On the other hand, when
Expand All @@ -154,7 +155,7 @@ template <> inline double fma<double>(double x, double y, double z) {
// the original mantissa as high part when constructing 128-bit z_mant. So the
// mantissa of prod will be left-shifted by 64 - 54 = 10 initially.

__uint128_t prod_mant = x_mant * y_mant << 10;
UInt128 prod_mant = x_mant * y_mant << 10;
int prod_lsb_exp =
x_exp + y_exp -
(FPBits::EXPONENT_BIAS + 2 * MantissaWidth<double>::VALUE + 10);
Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/generic/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "sqrt_80_bit_long_double.h"
#include "src/__support/CPP/Bit.h"
#include "src/__support/CPP/TypeTraits.h"
#include "src/__support/CPP/UInt128.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PlatformDefs.h"
Expand Down Expand Up @@ -48,7 +49,7 @@ inline void normalize<long double>(int &exponent, uint64_t &mantissa) {
}
#elif !defined(SPECIAL_X86_LONG_DOUBLE)
template <>
inline void normalize<long double>(int &exponent, __uint128_t &mantissa) {
inline void normalize<long double>(int &exponent, UInt128 &mantissa) {
const uint64_t hi_bits = static_cast<uint64_t>(mantissa >> 64);
const int shift = hi_bits ? (clz(hi_bits) - 15)
: (clz(static_cast<uint64_t>(mantissa)) + 49);
Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_80_BIT_LONG_DOUBLE_H
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_80_BIT_LONG_DOUBLE_H

#include "src/__support/CPP/UInt128.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PlatformDefs.h"
Expand All @@ -18,7 +19,7 @@ namespace __llvm_libc {
namespace fputil {
namespace x86 {

inline void normalize(int &exponent, __uint128_t &mantissa) {
inline void normalize(int &exponent, UInt128 &mantissa) {
const int shift =
clz(static_cast<uint64_t>(mantissa)) -
(8 * sizeof(uint64_t) - 1 - MantissaWidth<long double>::VALUE);
Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H

#include "src/__support/CPP/Bit.h"
#include "src/__support/CPP/UInt128.h"
#include "src/__support/architectures.h"

#if !defined(LLVM_LIBC_ARCH_X86)
Expand All @@ -32,7 +33,7 @@ template <> struct Padding<4> { static constexpr unsigned VALUE = 16; };
template <> struct Padding<8> { static constexpr unsigned VALUE = 48; };

template <> struct FPBits<long double> {
using UIntType = __uint128_t;
using UIntType = UInt128;

static constexpr int EXPONENT_BIAS = 0x3FFF;
static constexpr int MAX_EXPONENT = 0x7FFF;
Expand Down
Loading

0 comments on commit 300f8da

Please sign in to comment.