forked from OSchip/llvm-project
[libc] Replace type punning with bit_cast
Although type punning is defined for union in C, it is UB in C++. This patch introduces a bit_cast function to convert between types in a safe way. This is necessary to get llvm-libc compile with GCC. This patch is extracted from D119002. Differential Revision: https://reviews.llvm.org/D119145
This commit is contained in:
parent
9be6e40d1a
commit
7e7ecef980
|
@ -0,0 +1,48 @@
|
||||||
|
//===-- Freestanding version of bit_cast -----------------------*- 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_SUPPORT_CPP_BIT_H
|
||||||
|
#define LLVM_LIBC_SUPPORT_CPP_BIT_H
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
#if defined __has_builtin
|
||||||
|
#if __has_builtin(__builtin_bit_cast)
|
||||||
|
#define LLVM_LIBC_HAS_BUILTIN_BIT_CAST
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined __has_builtin
|
||||||
|
#if __has_builtin(__builtin_memcpy_inline)
|
||||||
|
#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This function guarantees the bitcast to be optimized away by the compiler for
|
||||||
|
// GCC >= 8 and Clang >= 6.
|
||||||
|
template <class To, class From> constexpr To bit_cast(const From &from) {
|
||||||
|
static_assert(sizeof(To) == sizeof(From), "To and From must be of same size");
|
||||||
|
#if defined(LLVM_LIBC_HAS_BUILTIN_BIT_CAST)
|
||||||
|
return __builtin_bit_cast(To, from);
|
||||||
|
#else
|
||||||
|
To to;
|
||||||
|
char *dst = reinterpret_cast<char *>(&to);
|
||||||
|
const char *src = reinterpret_cast<const char *>(&from);
|
||||||
|
#if defined(LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE)
|
||||||
|
__builtin_memcpy_inline(dst, src, sizeof(To));
|
||||||
|
#else
|
||||||
|
for (unsigned i = 0; i < sizeof(To); ++i)
|
||||||
|
dst[i] = src[i];
|
||||||
|
#endif // defined(LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE)
|
||||||
|
return to;
|
||||||
|
#endif // defined(LLVM_LIBC_HAS_BUILTIN_BIT_CAST)
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SUPPORT_CPP_BIT_H
|
|
@ -3,9 +3,10 @@ add_header_library(
|
||||||
HDRS
|
HDRS
|
||||||
Array.h
|
Array.h
|
||||||
ArrayRef.h
|
ArrayRef.h
|
||||||
|
Bit.h
|
||||||
Bitset.h
|
Bitset.h
|
||||||
Functional.h
|
Functional.h
|
||||||
|
Limits.h
|
||||||
StringView.h
|
StringView.h
|
||||||
TypeTraits.h
|
TypeTraits.h
|
||||||
Limits.h
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "PlatformDefs.h"
|
#include "PlatformDefs.h"
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
|
|
||||||
#include "FloatProperties.h"
|
#include "FloatProperties.h"
|
||||||
|
@ -35,7 +36,7 @@ template <typename T> struct ExponentWidth {
|
||||||
// floating numbers. On x86 platforms however, the 'long double' type maps to
|
// floating numbers. On x86 platforms however, the 'long double' type maps to
|
||||||
// an x87 floating point format. This format is an IEEE 754 extension format.
|
// an x87 floating point format. This format is an IEEE 754 extension format.
|
||||||
// It is handled as an explicit specialization of this class.
|
// It is handled as an explicit specialization of this class.
|
||||||
template <typename T> union FPBits {
|
template <typename T> struct FPBits {
|
||||||
static_assert(cpp::IsFloatingPointType<T>::Value,
|
static_assert(cpp::IsFloatingPointType<T>::Value,
|
||||||
"FPBits instantiated with invalid type.");
|
"FPBits instantiated with invalid type.");
|
||||||
|
|
||||||
|
@ -76,7 +77,6 @@ template <typename T> union FPBits {
|
||||||
bool get_sign() const {
|
bool get_sign() const {
|
||||||
return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
|
return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
|
||||||
}
|
}
|
||||||
T val;
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == sizeof(UIntType),
|
static_assert(sizeof(T) == sizeof(UIntType),
|
||||||
"Data type and integral representation have different sizes.");
|
"Data type and integral representation have different sizes.");
|
||||||
|
@ -96,15 +96,20 @@ template <typename T> union FPBits {
|
||||||
// type match.
|
// type match.
|
||||||
template <typename XType,
|
template <typename XType,
|
||||||
cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
|
cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
|
||||||
explicit FPBits(XType x) : val(x) {}
|
constexpr explicit FPBits(XType x)
|
||||||
|
: bits(__llvm_libc::bit_cast<UIntType>(x)) {}
|
||||||
|
|
||||||
template <typename XType,
|
template <typename XType,
|
||||||
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
|
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
|
||||||
explicit FPBits(XType x) : bits(x) {}
|
constexpr explicit FPBits(XType x) : bits(x) {}
|
||||||
|
|
||||||
FPBits() : bits(0) {}
|
FPBits() : bits(0) {}
|
||||||
|
|
||||||
explicit operator T() { return val; }
|
T get_val() const { return __llvm_libc::bit_cast<T>(bits); }
|
||||||
|
|
||||||
|
void set_val(T value) { bits = __llvm_libc::bit_cast<UIntType>(value); }
|
||||||
|
|
||||||
|
explicit operator T() const { return get_val(); }
|
||||||
|
|
||||||
UIntType uintval() const { return bits; }
|
UIntType uintval() const { return bits; }
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "BasicOperations.h"
|
#include "BasicOperations.h"
|
||||||
#include "FEnvImpl.h"
|
#include "FEnvImpl.h"
|
||||||
#include "FPBits.h"
|
#include "FPBits.h"
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
|
|
||||||
namespace __llvm_libc {
|
namespace __llvm_libc {
|
||||||
|
@ -285,7 +286,7 @@ static inline T hypot(T x, T y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
y_new |= static_cast<UIntType>(out_exp) << MantissaWidth<T>::VALUE;
|
y_new |= static_cast<UIntType>(out_exp) << MantissaWidth<T>::VALUE;
|
||||||
return *reinterpret_cast<T *>(&y_new);
|
return __llvm_libc::bit_cast<T>(y_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fputil
|
} // namespace fputil
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "NormalFloat.h"
|
#include "NormalFloat.h"
|
||||||
#include "PlatformDefs.h"
|
#include "PlatformDefs.h"
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -171,7 +172,7 @@ static inline T nextafter(T from, T to) {
|
||||||
int_val = (to_bits.uintval() & sign_mask) + UIntType(1);
|
int_val = (to_bits.uintval() & sign_mask) + UIntType(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *reinterpret_cast<T *>(&int_val);
|
return __llvm_libc::bit_cast<T>(int_val);
|
||||||
// TODO: Raise floating point exceptions as required by the standard.
|
// TODO: Raise floating point exceptions as required by the standard.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_H
|
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_GENERIC_SQRT_H
|
||||||
|
|
||||||
#include "sqrt_80_bit_long_double.h"
|
#include "sqrt_80_bit_long_double.h"
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
#include "src/__support/FPUtil/FEnvImpl.h"
|
#include "src/__support/FPUtil/FEnvImpl.h"
|
||||||
#include "src/__support/FPUtil/FPBits.h"
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
@ -203,7 +204,7 @@ sqrt(T x) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *reinterpret_cast<T *>(&y);
|
return __llvm_libc::bit_cast<T>(y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H
|
#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H
|
||||||
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H
|
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/architectures.h"
|
#include "src/__support/architectures.h"
|
||||||
|
|
||||||
#if !defined(LLVM_LIBC_ARCH_X86)
|
#if !defined(LLVM_LIBC_ARCH_X86)
|
||||||
|
@ -30,7 +31,7 @@ template <> struct Padding<4> { static constexpr unsigned VALUE = 16; };
|
||||||
// x86_64 padding.
|
// x86_64 padding.
|
||||||
template <> struct Padding<8> { static constexpr unsigned VALUE = 48; };
|
template <> struct Padding<8> { static constexpr unsigned VALUE = 48; };
|
||||||
|
|
||||||
template <> union FPBits<long double> {
|
template <> struct FPBits<long double> {
|
||||||
using UIntType = __uint128_t;
|
using UIntType = __uint128_t;
|
||||||
|
|
||||||
static constexpr int EXPONENT_BIAS = 0x3FFF;
|
static constexpr int EXPONENT_BIAS = 0x3FFF;
|
||||||
|
@ -91,13 +92,11 @@ template <> union FPBits<long double> {
|
||||||
return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
|
return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
long double val;
|
|
||||||
|
|
||||||
FPBits() : bits(0) {}
|
FPBits() : bits(0) {}
|
||||||
|
|
||||||
template <typename XType,
|
template <typename XType,
|
||||||
cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
|
cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
|
||||||
explicit FPBits(XType x) : val(x) {
|
explicit FPBits(XType x) : bits(__llvm_libc::bit_cast<UIntType>(x)) {
|
||||||
// bits starts uninitialized, and setting it to a long double only
|
// bits starts uninitialized, and setting it to a long double only
|
||||||
// overwrites the first 80 bits. This clears those upper bits.
|
// overwrites the first 80 bits. This clears those upper bits.
|
||||||
bits = bits & ((UIntType(1) << 80) - 1);
|
bits = bits & ((UIntType(1) << 80) - 1);
|
||||||
|
@ -107,7 +106,7 @@ template <> union FPBits<long double> {
|
||||||
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
|
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
|
||||||
explicit FPBits(XType x) : bits(x) {}
|
explicit FPBits(XType x) : bits(x) {}
|
||||||
|
|
||||||
operator long double() { return val; }
|
operator long double() { return __llvm_libc::bit_cast<long double>(bits); }
|
||||||
|
|
||||||
UIntType uintval() {
|
UIntType uintval() {
|
||||||
// We zero the padding bits as they can contain garbage.
|
// We zero the padding bits as they can contain garbage.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#error "Invalid include"
|
#error "Invalid include"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/FPUtil/FPBits.h"
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -111,7 +112,7 @@ static inline long double nextafter(long double from, long double to) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *reinterpret_cast<long double *>(&int_val);
|
return __llvm_libc::bit_cast<long double>(int_val);
|
||||||
// TODO: Raise floating point exceptions as required by the standard.
|
// TODO: Raise floating point exceptions as required by the standard.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,8 @@ template <> inline double sqrt<double>(double x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline long double sqrt<long double>(long double x) {
|
template <> inline long double sqrt<long double>(long double x) {
|
||||||
long double result;
|
__asm__ __volatile__("fsqrt" : "+t"(x));
|
||||||
__asm__ __volatile__("fsqrt" : "=t"(result) : "t"(x));
|
return x;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fputil
|
} // namespace fputil
|
||||||
|
|
|
@ -155,7 +155,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
// Normalize denormal inputs.
|
// Normalize denormal inputs.
|
||||||
xbits.val *= 0x1.0p23f;
|
xbits.set_val(xbits.get_val() * 0x1.0p23f);
|
||||||
m -= 23.0;
|
m -= 23.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
|
||||||
xbits.set_unbiased_exponent(0x7F);
|
xbits.set_unbiased_exponent(0x7F);
|
||||||
int f_index = xbits.get_mantissa() >> 16;
|
int f_index = xbits.get_mantissa() >> 16;
|
||||||
|
|
||||||
FPBits f(xbits.val);
|
FPBits f = xbits;
|
||||||
f.bits &= ~0x0000'FFFF;
|
f.bits &= ~0x0000'FFFF;
|
||||||
|
|
||||||
double d = static_cast<float>(xbits) - static_cast<float>(f);
|
double d = static_cast<float>(xbits) - static_cast<float>(f);
|
||||||
|
|
|
@ -59,7 +59,7 @@ INLINE_FMA static inline float log(double x) {
|
||||||
int f_index =
|
int f_index =
|
||||||
xbits.get_mantissa() >> 45; // fputil::MantissaWidth<double>::VALUE - 7
|
xbits.get_mantissa() >> 45; // fputil::MantissaWidth<double>::VALUE - 7
|
||||||
|
|
||||||
FPBits f(xbits.val);
|
FPBits f = xbits;
|
||||||
// Clear the lowest 45 bits.
|
// Clear the lowest 45 bits.
|
||||||
f.bits &= ~0x0000'1FFF'FFFF'FFFFULL;
|
f.bits &= ~0x0000'1FFF'FFFF'FFFFULL;
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
// Normalize denormal inputs.
|
// Normalize denormal inputs.
|
||||||
xbits.val *= 0x1.0p23f;
|
xbits.set_val(xbits.get_val() * 0x1.0p23f);
|
||||||
m = -23;
|
m = -23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
|
||||||
// lookup tables.
|
// lookup tables.
|
||||||
int f_index = xbits.get_mantissa() >> 16;
|
int f_index = xbits.get_mantissa() >> 16;
|
||||||
|
|
||||||
FPBits f(xbits.val);
|
FPBits f = xbits;
|
||||||
// Clear the lowest 16 bits.
|
// Clear the lowest 16 bits.
|
||||||
f.bits &= ~0x0000'FFFF;
|
f.bits &= ~0x0000'FFFF;
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
// Normalize denormal inputs.
|
// Normalize denormal inputs.
|
||||||
xbits.val *= 0x1.0p23f;
|
xbits.set_val(xbits.get_val() * 0x1.0p23f);
|
||||||
m = -23;
|
m = -23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
|
||||||
xbits.set_unbiased_exponent(0x7F);
|
xbits.set_unbiased_exponent(0x7F);
|
||||||
int f_index = xbits.get_mantissa() >> 16;
|
int f_index = xbits.get_mantissa() >> 16;
|
||||||
|
|
||||||
FPBits f(xbits.val);
|
FPBits f = xbits;
|
||||||
f.bits &= ~0x0000'FFFF;
|
f.bits &= ~0x0000'FFFF;
|
||||||
|
|
||||||
double d = static_cast<float>(xbits) - static_cast<float>(f);
|
double d = static_cast<float>(xbits) - static_cast<float>(f);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef LLVM_LIBC_SRC_MATH_MATH_UTILS_H
|
#ifndef LLVM_LIBC_SRC_MATH_MATH_UTILS_H
|
||||||
#define LLVM_LIBC_SRC_MATH_MATH_UTILS_H
|
#define LLVM_LIBC_SRC_MATH_MATH_UTILS_H
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
#include "src/__support/common.h"
|
#include "src/__support/common.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -19,19 +20,19 @@
|
||||||
namespace __llvm_libc {
|
namespace __llvm_libc {
|
||||||
|
|
||||||
static inline uint32_t as_uint32_bits(float x) {
|
static inline uint32_t as_uint32_bits(float x) {
|
||||||
return *reinterpret_cast<uint32_t *>(&x);
|
return __llvm_libc::bit_cast<uint32_t>(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t as_uint64_bits(double x) {
|
static inline uint64_t as_uint64_bits(double x) {
|
||||||
return *reinterpret_cast<uint64_t *>(&x);
|
return __llvm_libc::bit_cast<uint64_t>(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float as_float(uint32_t x) {
|
static inline float as_float(uint32_t x) {
|
||||||
return *reinterpret_cast<float *>(&x);
|
return __llvm_libc::bit_cast<float>(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double as_double(uint64_t x) {
|
static inline double as_double(uint64_t x) {
|
||||||
return *reinterpret_cast<double *>(&x);
|
return __llvm_libc::bit_cast<double>(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; }
|
static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; }
|
||||||
|
|
|
@ -7,6 +7,8 @@ add_header_library(
|
||||||
memcmp_implementations.h
|
memcmp_implementations.h
|
||||||
memcpy_implementations.h
|
memcpy_implementations.h
|
||||||
memset_implementations.h
|
memset_implementations.h
|
||||||
|
DEPS
|
||||||
|
standalone_cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_header_library(
|
add_header_library(
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ELEMENTS_X86_H
|
#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ELEMENTS_X86_H
|
||||||
#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ELEMENTS_X86_H
|
#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ELEMENTS_X86_H
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/architectures.h"
|
#include "src/__support/architectures.h"
|
||||||
|
|
||||||
#if defined(LLVM_LIBC_ARCH_X86)
|
#if defined(LLVM_LIBC_ARCH_X86)
|
||||||
|
@ -66,16 +67,18 @@ struct M128 {
|
||||||
using T = char __attribute__((__vector_size__(SIZE)));
|
using T = char __attribute__((__vector_size__(SIZE)));
|
||||||
static uint16_t mask(T value) {
|
static uint16_t mask(T value) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm_movemask_epi8(value);
|
return _mm_movemask_epi8(__llvm_libc::bit_cast<__m128i>(value));
|
||||||
}
|
}
|
||||||
static uint16_t not_equal_mask(T a, T b) { return mask(a != b); }
|
static uint16_t not_equal_mask(T a, T b) { return mask(a != b); }
|
||||||
static T load(const char *ptr) {
|
static T load(const char *ptr) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm_loadu_si128(reinterpret_cast<__m128i_u const *>(ptr));
|
return __llvm_libc::bit_cast<T>(
|
||||||
|
_mm_loadu_si128(reinterpret_cast<__m128i_u const *>(ptr)));
|
||||||
}
|
}
|
||||||
static void store(char *ptr, T value) {
|
static void store(char *ptr, T value) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm_storeu_si128(reinterpret_cast<__m128i_u *>(ptr), value);
|
return _mm_storeu_si128(reinterpret_cast<__m128i_u *>(ptr),
|
||||||
|
__llvm_libc::bit_cast<__m128i>(value));
|
||||||
}
|
}
|
||||||
static T get_splatted_value(const char v) {
|
static T get_splatted_value(const char v) {
|
||||||
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v};
|
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v};
|
||||||
|
@ -91,16 +94,18 @@ struct M256 {
|
||||||
using T = char __attribute__((__vector_size__(SIZE)));
|
using T = char __attribute__((__vector_size__(SIZE)));
|
||||||
static uint32_t mask(T value) {
|
static uint32_t mask(T value) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm256_movemask_epi8(value);
|
return _mm256_movemask_epi8(__llvm_libc::bit_cast<__m256i>(value));
|
||||||
}
|
}
|
||||||
static uint32_t not_equal_mask(T a, T b) { return mask(a != b); }
|
static uint32_t not_equal_mask(T a, T b) { return mask(a != b); }
|
||||||
static T load(const char *ptr) {
|
static T load(const char *ptr) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm256_loadu_si256(reinterpret_cast<__m256i const *>(ptr));
|
return __llvm_libc::bit_cast<T>(
|
||||||
|
_mm256_loadu_si256(reinterpret_cast<__m256i const *>(ptr)));
|
||||||
}
|
}
|
||||||
static void store(char *ptr, T value) {
|
static void store(char *ptr, T value) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr), value);
|
return _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr),
|
||||||
|
__llvm_libc::bit_cast<__m256i>(value));
|
||||||
}
|
}
|
||||||
static T get_splatted_value(const char v) {
|
static T get_splatted_value(const char v) {
|
||||||
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v,
|
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v,
|
||||||
|
@ -117,15 +122,16 @@ struct M512 {
|
||||||
using T = char __attribute__((__vector_size__(SIZE)));
|
using T = char __attribute__((__vector_size__(SIZE)));
|
||||||
static uint64_t not_equal_mask(T a, T b) {
|
static uint64_t not_equal_mask(T a, T b) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm512_cmpneq_epi8_mask(a, b);
|
return _mm512_cmpneq_epi8_mask(__llvm_libc::bit_cast<__m512i>(a),
|
||||||
|
__llvm_libc::bit_cast<__m512i>(b));
|
||||||
}
|
}
|
||||||
static T load(const char *ptr) {
|
static T load(const char *ptr) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm512_loadu_epi8(ptr);
|
return __llvm_libc::bit_cast<T>(_mm512_loadu_epi8(ptr));
|
||||||
}
|
}
|
||||||
static void store(char *ptr, T value) {
|
static void store(char *ptr, T value) {
|
||||||
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
// NOLINTNEXTLINE(llvmlibc-callee-namespace)
|
||||||
return _mm512_storeu_epi8(ptr, value);
|
return _mm512_storeu_epi8(ptr, __llvm_libc::bit_cast<__m512i>(value));
|
||||||
}
|
}
|
||||||
static T get_splatted_value(const char v) {
|
static T get_splatted_value(const char v) {
|
||||||
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v,
|
const T splatted = {v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef LLVM_LIBC_TEST_SRC_MATH_NEXTAFTERTEST_H
|
#ifndef LLVM_LIBC_TEST_SRC_MATH_NEXTAFTERTEST_H
|
||||||
#define LLVM_LIBC_TEST_SRC_MATH_NEXTAFTERTEST_H
|
#define LLVM_LIBC_TEST_SRC_MATH_NEXTAFTERTEST_H
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "src/__support/CPP/TypeTraits.h"
|
#include "src/__support/CPP/TypeTraits.h"
|
||||||
#include "src/__support/FPUtil/BasicOperations.h"
|
#include "src/__support/FPUtil/BasicOperations.h"
|
||||||
#include "src/__support/FPUtil/FPBits.h"
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
@ -51,54 +52,54 @@ public:
|
||||||
T x = zero;
|
T x = zero;
|
||||||
T result = func(x, T(1));
|
T result = func(x, T(1));
|
||||||
UIntType expected_bits = 1;
|
UIntType expected_bits = 1;
|
||||||
T expected = *reinterpret_cast<T *>(&expected_bits);
|
T expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, T(-1));
|
result = func(x, T(-1));
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
x = neg_zero;
|
x = neg_zero;
|
||||||
result = func(x, 1);
|
result = func(x, 1);
|
||||||
expected_bits = 1;
|
expected_bits = 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, -1);
|
result = func(x, -1);
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
// 'from' is max subnormal value.
|
// 'from' is max subnormal value.
|
||||||
x = *reinterpret_cast<const T *>(&max_subnormal);
|
x = __llvm_libc::bit_cast<T>(max_subnormal);
|
||||||
result = func(x, 1);
|
result = func(x, 1);
|
||||||
expected = *reinterpret_cast<const T *>(&min_normal);
|
expected = __llvm_libc::bit_cast<T>(min_normal);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits = max_subnormal - 1;
|
expected_bits = max_subnormal - 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
x = -x;
|
x = -x;
|
||||||
|
|
||||||
result = func(x, -1);
|
result = func(x, -1);
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits =
|
expected_bits =
|
||||||
(UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal - 1;
|
(UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal - 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
// 'from' is min subnormal value.
|
// 'from' is min subnormal value.
|
||||||
x = *reinterpret_cast<const T *>(&min_subnormal);
|
x = __llvm_libc::bit_cast<T>(min_subnormal);
|
||||||
result = func(x, 1);
|
result = func(x, 1);
|
||||||
expected_bits = min_subnormal + 1;
|
expected_bits = min_subnormal + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
ASSERT_FP_EQ(func(x, 0), 0);
|
ASSERT_FP_EQ(func(x, 0), 0);
|
||||||
|
|
||||||
|
@ -106,35 +107,35 @@ public:
|
||||||
result = func(x, -1);
|
result = func(x, -1);
|
||||||
expected_bits =
|
expected_bits =
|
||||||
(UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_subnormal + 1;
|
(UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_subnormal + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
ASSERT_FP_EQ(func(x, 0), T(-0.0));
|
ASSERT_FP_EQ(func(x, 0), T(-0.0));
|
||||||
|
|
||||||
// 'from' is min normal.
|
// 'from' is min normal.
|
||||||
x = *reinterpret_cast<const T *>(&min_normal);
|
x = __llvm_libc::bit_cast<T>(min_normal);
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits = max_subnormal;
|
expected_bits = max_subnormal;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, inf);
|
result = func(x, inf);
|
||||||
expected_bits = min_normal + 1;
|
expected_bits = min_normal + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
x = -x;
|
x = -x;
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
result = func(x, -inf);
|
result = func(x, -inf);
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal + 1;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal + 1;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
|
|
||||||
// 'from' is max normal and 'to' is infinity.
|
// 'from' is max normal and 'to' is infinity.
|
||||||
x = *reinterpret_cast<const T *>(&max_normal);
|
x = __llvm_libc::bit_cast<T>(max_normal);
|
||||||
result = func(x, inf);
|
result = func(x, inf);
|
||||||
ASSERT_FP_EQ(result, inf);
|
ASSERT_FP_EQ(result, inf);
|
||||||
|
|
||||||
|
@ -145,14 +146,14 @@ public:
|
||||||
x = inf;
|
x = inf;
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits = max_normal;
|
expected_bits = max_normal;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
ASSERT_FP_EQ(func(x, inf), inf);
|
ASSERT_FP_EQ(func(x, inf), inf);
|
||||||
|
|
||||||
x = neg_inf;
|
x = neg_inf;
|
||||||
result = func(x, 0);
|
result = func(x, 0);
|
||||||
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_normal;
|
expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_normal;
|
||||||
expected = *reinterpret_cast<T *>(&expected_bits);
|
expected = __llvm_libc::bit_cast<T>(expected_bits);
|
||||||
ASSERT_FP_EQ(result, expected);
|
ASSERT_FP_EQ(result, expected);
|
||||||
ASSERT_FP_EQ(func(x, neg_inf), neg_inf);
|
ASSERT_FP_EQ(func(x, neg_inf), neg_inf);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "src/__support/CPP/Bit.h"
|
||||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
#include "utils/UnitTest/FPMatcher.h"
|
#include "utils/UnitTest/FPMatcher.h"
|
||||||
#include "utils/UnitTest/Test.h"
|
#include "utils/UnitTest/Test.h"
|
||||||
|
@ -47,7 +48,7 @@ public:
|
||||||
constexpr UIntType COUNT = 1'000'001;
|
constexpr UIntType COUNT = 1'000'001;
|
||||||
constexpr UIntType STEP = HIDDEN_BIT / COUNT;
|
constexpr UIntType STEP = HIDDEN_BIT / COUNT;
|
||||||
for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
||||||
T x = *reinterpret_cast<T *>(&v);
|
T x = __llvm_libc::bit_cast<T>(v);
|
||||||
test_all_rounding_modes(func, x);
|
test_all_rounding_modes(func, x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,7 @@ public:
|
||||||
constexpr UIntType COUNT = 10'000'001;
|
constexpr UIntType COUNT = 10'000'001;
|
||||||
constexpr UIntType STEP = UIntType(-1) / COUNT;
|
constexpr UIntType STEP = UIntType(-1) / COUNT;
|
||||||
for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
||||||
T x = *reinterpret_cast<T *>(&v);
|
T x = __llvm_libc::bit_cast<T>(v);
|
||||||
if (isnan(x) || (x < 0)) {
|
if (isnan(x) || (x < 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ cc_library(
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"src/__support/CPP/Array.h",
|
"src/__support/CPP/Array.h",
|
||||||
"src/__support/CPP/ArrayRef.h",
|
"src/__support/CPP/ArrayRef.h",
|
||||||
|
"src/__support/CPP/Bit.h",
|
||||||
"src/__support/CPP/Bitset.h",
|
"src/__support/CPP/Bitset.h",
|
||||||
"src/__support/CPP/Functional.h",
|
"src/__support/CPP/Functional.h",
|
||||||
"src/__support/CPP/Limits.h",
|
"src/__support/CPP/Limits.h",
|
||||||
|
@ -661,6 +662,7 @@ cc_library(
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
":__support_common",
|
":__support_common",
|
||||||
|
":__support_standalone_cpp",
|
||||||
":libc_root",
|
":libc_root",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue