diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -4,6 +4,8 @@ common HDRS architectures.h + builtin_bit_cast.h + builtin_memcpy.h common.h endian.h sanitizer.h diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -12,6 +12,7 @@ #include "PlatformDefs.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/builtin_bit_cast.h" #include "FloatProperties.h" #include @@ -35,7 +36,7 @@ // 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. // It is handled as an explicit specialization of this class. -template union FPBits { +template struct FPBits { static_assert(cpp::IsFloatingPointType::Value, "FPBits instantiated with invalid type."); @@ -76,7 +77,6 @@ bool get_sign() const { return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1)); } - T val; static_assert(sizeof(T) == sizeof(UIntType), "Data type and integral representation have different sizes."); @@ -96,7 +96,7 @@ // type match. template ::Value, int> = 0> - explicit FPBits(XType x) : val(x) {} + explicit FPBits(XType x) : bits(llvmlibc_builtin_bit_cast(x)) {} template ::Value, int> = 0> @@ -104,7 +104,11 @@ FPBits() : bits(0) {} - explicit operator T() { return val; } + T val() const { return llvmlibc_builtin_bit_cast(bits); } + + void set_val(T value) { bits = llvmlibc_builtin_bit_cast(value); } + + explicit operator T() const { return val(); } UIntType uintval() const { return bits; } diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -13,6 +13,7 @@ #include "FEnvImpl.h" #include "FPBits.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/builtin_bit_cast.h" namespace __llvm_libc { namespace fputil { @@ -285,7 +286,7 @@ } y_new |= static_cast(out_exp) << MantissaWidth::VALUE; - return *reinterpret_cast(&y_new); + return llvmlibc_builtin_bit_cast(y_new); } } // namespace fputil diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -15,6 +15,7 @@ #include "PlatformDefs.h" #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/builtin_bit_cast.h" #include #include @@ -171,7 +172,7 @@ int_val = (to_bits.uintval() & sign_mask) + UIntType(1); } - return *reinterpret_cast(&int_val); + return llvmlibc_builtin_bit_cast(int_val); // TODO: Raise floating point exceptions as required by the standard. } diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -14,6 +14,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PlatformDefs.h" +#include "src/__support/builtin_bit_cast.h" namespace __llvm_libc { namespace fputil { @@ -203,7 +204,7 @@ break; } - return *reinterpret_cast(&y); + return llvmlibc_builtin_bit_cast(y); } } } 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 @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H #include "src/__support/architectures.h" +#include "src/__support/builtin_bit_cast.h" #if !defined(LLVM_LIBC_ARCH_X86) #error "Invalid include" @@ -30,7 +31,7 @@ // x86_64 padding. template <> struct Padding<8> { static constexpr unsigned VALUE = 48; }; -template <> union FPBits { +template <> struct FPBits { using UIntType = __uint128_t; static constexpr int EXPONENT_BIAS = 0x3FFF; @@ -91,13 +92,11 @@ return ((bits & FloatProp::SIGN_MASK) >> (FloatProp::BIT_WIDTH - 1)); } - long double val; - FPBits() : bits(0) {} template ::Value, int> = 0> - explicit FPBits(XType x) : val(x) { + explicit FPBits(XType x) : bits(llvmlibc_builtin_bit_cast(x)) { // bits starts uninitialized, and setting it to a long double only // overwrites the first 80 bits. This clears those upper bits. bits = bits & ((UIntType(1) << 80) - 1); @@ -107,7 +106,9 @@ cpp::EnableIfType::Value, int> = 0> explicit FPBits(XType x) : bits(x) {} - operator long double() { return val; } + operator long double() { + return llvmlibc_builtin_bit_cast(bits); + } UIntType uintval() { // We zero the padding bits as they can contain garbage. diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h --- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h +++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h @@ -16,6 +16,7 @@ #endif #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtin_bit_cast.h" #include @@ -111,7 +112,7 @@ } } - return *reinterpret_cast(&int_val); + return llvmlibc_builtin_bit_cast(int_val); // TODO: Raise floating point exceptions as required by the standard. } diff --git a/libc/src/__support/builtin_bit_cast.h b/libc/src/__support/builtin_bit_cast.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/builtin_bit_cast.h @@ -0,0 +1,33 @@ +//===-- 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_BUILTIN_BIT_CAST_H +#define LLVM_LIBC_SUPPORT_BUILTIN_BIT_CAST_H + +#include "src/__support/builtin_memcpy.h" + +#if defined __has_builtin +#if __has_builtin(__builtin_bit_cast) +#define LLVM_LIBC_HAS_BUILTIN_BIT_CAST +#endif +#endif + +// This function guarantees the bitcast to be optimized by the compiler. +template +static To llvmlibc_builtin_bit_cast(const From &from) { + static_assert(sizeof(To) == sizeof(From), "To and From must be of same size"); +#ifdef LLVM_LIBC_HAS_BUILTIN_BIT_CAST + return __builtin_bit_cast(To, from); +#endif + To to; + llvmlibc_builtin_memcpy(reinterpret_cast(&to), + reinterpret_cast(&from)); + return to; +} + +#endif // LLVM_LIBC_SUPPORT_BUILTIN_BIT_CAST_H diff --git a/libc/src/__support/builtin_memcpy.h b/libc/src/__support/builtin_memcpy.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/builtin_memcpy.h @@ -0,0 +1,31 @@ +//===-- Freestanding version of memcpy --------------------------*- 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_BUILTIN_MEMCPY_H +#define LLVM_LIBC_SUPPORT_BUILTIN_MEMCPY_H + +#if defined __has_builtin +#if __has_builtin(__builtin_memcpy_inline) +#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE +#endif +#endif + +// This function guarantees the copy to be inlined by the compiler. +// We cannot use `__builtin_memcpy` that may call libc's memcpy. +template +static void llvmlibc_builtin_memcpy(char *__restrict dst, + const char *__restrict src) { +#if defined(LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE) + __builtin_memcpy_inline(dst, src, SIZE); +#else + for (unsigned i = 0; i < SIZE; ++i) + dst[i] = src[i]; +#endif +} + +#endif // LLVM_LIBC_SUPPORT_BUILTIN_MEMCPY_H diff --git a/libc/src/fenv/fesetexceptflag.cpp b/libc/src/fenv/fesetexceptflag.cpp --- a/libc/src/fenv/fesetexceptflag.cpp +++ b/libc/src/fenv/fesetexceptflag.cpp @@ -8,19 +8,26 @@ #include "src/fenv/fesetexceptflag.h" #include "src/__support/FPUtil/FEnvUtils.h" +#include "src/__support/builtin_bit_cast.h" #include "src/__support/common.h" #include namespace __llvm_libc { +template struct TypeSelector {}; +template <> struct TypeSelector<2> { using type = int16_t; }; +template <> struct TypeSelector<4> { using type = int32_t; }; + LLVM_LIBC_FUNCTION(int, fesetexceptflag, (const fexcept_t *flagp, int excepts)) { // Since the return type of fetestexcept is int, we ensure that fexcept_t // can fit in int type. static_assert(sizeof(int) >= sizeof(fexcept_t), "fexcept_t value cannot fit in an int value."); - int excepts_to_set = static_cast(*flagp) & excepts; + using IntType = TypeSelector::type; + const int excepts_as_int = llvmlibc_builtin_bit_cast(*flagp); + const int excepts_to_set = excepts_as_int & excepts; fputil::clear_except(FE_ALL_EXCEPT); return fputil::set_except(excepts_to_set); } diff --git a/libc/src/math/generic/log10f.cpp b/libc/src/math/generic/log10f.cpp --- a/libc/src/math/generic/log10f.cpp +++ b/libc/src/math/generic/log10f.cpp @@ -155,7 +155,7 @@ return x; } // Normalize denormal inputs. - xbits.val *= 0x1.0p23f; + xbits.set_val(xbits.val() * 0x1.0p23f); m -= 23.0; } @@ -164,7 +164,7 @@ xbits.set_unbiased_exponent(0x7F); int f_index = xbits.get_mantissa() >> 16; - FPBits f(xbits.val); + FPBits f(xbits.val()); f.bits &= ~0x0000'FFFF; double d = static_cast(xbits) - static_cast(f); diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp --- a/libc/src/math/generic/log2f.cpp +++ b/libc/src/math/generic/log2f.cpp @@ -138,7 +138,7 @@ return x; } // Normalize denormal inputs. - xbits.val *= 0x1.0p23f; + xbits.set_val(xbits.val() * 0x1.0p23f); m = -23; } @@ -149,7 +149,7 @@ // lookup tables. int f_index = xbits.get_mantissa() >> 16; - FPBits f(xbits.val); + FPBits f(xbits.val()); // Clear the lowest 16 bits. f.bits &= ~0x0000'FFFF; diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp --- a/libc/src/math/generic/logf.cpp +++ b/libc/src/math/generic/logf.cpp @@ -150,7 +150,7 @@ return x; } // Normalize denormal inputs. - xbits.val *= 0x1.0p23f; + xbits.set_val(xbits.val() * 0x1.0p23f); m = -23; } @@ -159,7 +159,7 @@ xbits.set_unbiased_exponent(0x7F); int f_index = xbits.get_mantissa() >> 16; - FPBits f(xbits.val); + FPBits f(xbits.val()); f.bits &= ~0x0000'FFFF; double d = static_cast(xbits) - static_cast(f); diff --git a/libc/src/math/generic/math_utils.h b/libc/src/math/generic/math_utils.h --- a/libc/src/math/generic/math_utils.h +++ b/libc/src/math/generic/math_utils.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_MATH_MATH_UTILS_H #include "src/__support/CPP/TypeTraits.h" +#include "src/__support/builtin_bit_cast.h" #include "src/__support/common.h" #include #include @@ -19,19 +20,19 @@ namespace __llvm_libc { static inline uint32_t as_uint32_bits(float x) { - return *reinterpret_cast(&x); + return llvmlibc_builtin_bit_cast(x); } static inline uint64_t as_uint64_bits(double x) { - return *reinterpret_cast(&x); + return llvmlibc_builtin_bit_cast(x); } static inline float as_float(uint32_t x) { - return *reinterpret_cast(&x); + return llvmlibc_builtin_bit_cast(x); } static inline double as_double(uint64_t x) { - return *reinterpret_cast(&x); + return llvmlibc_builtin_bit_cast(x); } static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; } diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -251,14 +251,23 @@ "ADD_IMPL" "" # Optional arguments "" # Single value arguments - "REQUIRE;SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi value arguments + "REQUIRE;SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;MLLVM_COMPILE_OPTIONS" # Multi value arguments ${ARGN}) + + if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + list(APPEND ADD_IMPL_MLLVM_COMPILE_OPTIONS "-combiner-global-alias-analysis") + # Note that '-mllvm' needs to be prefixed with 'SHELL:' to prevent CMake flag deduplication. + foreach(opt IN LISTS ADD_IMPL_MLLVM_COMPILE_OPTIONS) + list(APPEND ADD_IMPL_COMPILE_OPTIONS "SHELL:-mllvm ${opt}") + endforeach() + endif() + add_entrypoint_object(${impl_name} NAME ${name} SRCS ${ADD_IMPL_SRCS} HDRS ${ADD_IMPL_HDRS} DEPENDS ${ADD_IMPL_DEPENDS} - COMPILE_OPTIONS ${ADD_IMPL_COMPILE_OPTIONS} "SHELL:-mllvm -combiner-global-alias-analysis" + COMPILE_OPTIONS ${ADD_IMPL_COMPILE_OPTIONS} ) get_fq_target_name(${impl_name} fq_target_name) set_target_properties(${fq_target_name} PROPERTIES REQUIRE_CPU_FEATURES "${ADD_IMPL_REQUIRE}") @@ -382,10 +391,9 @@ add_memcpy(memcpy) elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) # Disable tail merging as it leads to lower performance. - # Note that '-mllvm' needs to be prefixed with 'SHELL:' to prevent CMake flag deduplication. add_memcpy(memcpy_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} - COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") - add_memcpy(memcpy COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") + MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") + add_memcpy(memcpy MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") else() add_memcpy(memcpy_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memcpy(memcpy) @@ -418,10 +426,9 @@ add_memmove(memmove) elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) # Disable tail merging as it leads to lower performance. - # Note that '-mllvm' needs to be prefixed with 'SHELL:' to prevent CMake flag deduplication. add_memmove(memmove_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} - COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") - add_memmove(memmove COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") + MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") + add_memmove(memmove MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") else() add_memmove(memmove_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memmove(memmove) @@ -452,9 +459,10 @@ add_memset(memset_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memset(memset) elseif(${LIBC_TARGET_ARCHITECTURE_IS_AARCH64}) + # Disable tail merging as it leads to lower performance. add_memset(memset_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE} - COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") - add_memset(memset COMPILE_OPTIONS "SHELL:-mllvm --tail-merge-threshold=0") + MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") + add_memset(memset MLLVM_COMPILE_OPTIONS "-tail-merge-threshold=0") else() add_memset(memset_opt_host COMPILE_OPTIONS ${LIBC_COMPILE_OPTIONS_NATIVE}) add_memset(memset) diff --git a/libc/src/string/memory_utils/elements_x86.h b/libc/src/string/memory_utils/elements_x86.h --- a/libc/src/string/memory_utils/elements_x86.h +++ b/libc/src/string/memory_utils/elements_x86.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_ELEMENTS_X86_H #include "src/__support/architectures.h" +#include "src/__support/builtin_bit_cast.h" #if defined(LLVM_LIBC_ARCH_X86) @@ -66,16 +67,18 @@ using T = char __attribute__((__vector_size__(SIZE))); static uint16_t mask(T value) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm_movemask_epi8(value); + return _mm_movemask_epi8(llvmlibc_builtin_bit_cast<__m128i>(value)); } static uint16_t not_equal_mask(T a, T b) { return mask(a != b); } static T load(const char *ptr) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm_loadu_si128(reinterpret_cast<__m128i_u const *>(ptr)); + return llvmlibc_builtin_bit_cast( + _mm_loadu_si128(reinterpret_cast<__m128i_u const *>(ptr))); } static void store(char *ptr, T value) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm_storeu_si128(reinterpret_cast<__m128i_u *>(ptr), value); + return _mm_storeu_si128(reinterpret_cast<__m128i_u *>(ptr), + llvmlibc_builtin_bit_cast<__m128i>(value)); } 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}; @@ -91,16 +94,18 @@ using T = char __attribute__((__vector_size__(SIZE))); static uint32_t mask(T value) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm256_movemask_epi8(value); + return _mm256_movemask_epi8(llvmlibc_builtin_bit_cast<__m256i>(value)); } static uint32_t not_equal_mask(T a, T b) { return mask(a != b); } static T load(const char *ptr) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm256_loadu_si256(reinterpret_cast<__m256i const *>(ptr)); + return llvmlibc_builtin_bit_cast( + _mm256_loadu_si256(reinterpret_cast<__m256i const *>(ptr))); } static void store(char *ptr, T value) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr), value); + return _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr), + llvmlibc_builtin_bit_cast<__m256i>(value)); } 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, @@ -117,15 +122,16 @@ using T = char __attribute__((__vector_size__(SIZE))); static uint64_t not_equal_mask(T a, T b) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm512_cmpneq_epi8_mask(a, b); + return _mm512_cmpneq_epi8_mask(llvmlibc_builtin_bit_cast<__m512i>(a), + llvmlibc_builtin_bit_cast<__m512i>(b)); } static T load(const char *ptr) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm512_loadu_epi8(ptr); + return llvmlibc_builtin_bit_cast(_mm512_loadu_epi8(ptr)); } static void store(char *ptr, T value) { // NOLINTNEXTLINE(llvmlibc-callee-namespace) - return _mm512_storeu_epi8(ptr, value); + return _mm512_storeu_epi8(ptr, llvmlibc_builtin_bit_cast<__m512i>(value)); } 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, diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h --- a/libc/test/src/math/NextAfterTest.h +++ b/libc/test/src/math/NextAfterTest.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/TypeTraits.h" #include "src/__support/FPUtil/BasicOperations.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtin_bit_cast.h" #include "utils/UnitTest/FPMatcher.h" #include "utils/UnitTest/Test.h" #include @@ -51,54 +52,54 @@ T x = zero; T result = func(x, T(1)); UIntType expected_bits = 1; - T expected = *reinterpret_cast(&expected_bits); + T expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); result = func(x, T(-1)); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); x = neg_zero; result = func(x, 1); expected_bits = 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); result = func(x, -1); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); // 'from' is max subnormal value. - x = *reinterpret_cast(&max_subnormal); + x = llvmlibc_builtin_bit_cast(max_subnormal); result = func(x, 1); - expected = *reinterpret_cast(&min_normal); + expected = llvmlibc_builtin_bit_cast(min_normal); ASSERT_FP_EQ(result, expected); result = func(x, 0); expected_bits = max_subnormal - 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); x = -x; result = func(x, -1); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); result = func(x, 0); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal - 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); // 'from' is min subnormal value. - x = *reinterpret_cast(&min_subnormal); + x = llvmlibc_builtin_bit_cast(min_subnormal); result = func(x, 1); expected_bits = min_subnormal + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); ASSERT_FP_EQ(func(x, 0), 0); @@ -106,35 +107,35 @@ result = func(x, -1); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_subnormal + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); ASSERT_FP_EQ(func(x, 0), T(-0.0)); // 'from' is min normal. - x = *reinterpret_cast(&min_normal); + x = llvmlibc_builtin_bit_cast(min_normal); result = func(x, 0); expected_bits = max_subnormal; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); result = func(x, inf); expected_bits = min_normal + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); x = -x; result = func(x, 0); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_subnormal; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); result = func(x, -inf); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + min_normal + 1; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); // 'from' is max normal and 'to' is infinity. - x = *reinterpret_cast(&max_normal); + x = llvmlibc_builtin_bit_cast(max_normal); result = func(x, inf); ASSERT_FP_EQ(result, inf); @@ -145,14 +146,14 @@ x = inf; result = func(x, 0); expected_bits = max_normal; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); ASSERT_FP_EQ(func(x, inf), inf); x = neg_inf; result = func(x, 0); expected_bits = (UIntType(1) << (BIT_WIDTH_OF_TYPE - 1)) + max_normal; - expected = *reinterpret_cast(&expected_bits); + expected = llvmlibc_builtin_bit_cast(expected_bits); ASSERT_FP_EQ(result, expected); ASSERT_FP_EQ(func(x, neg_inf), neg_inf); diff --git a/libc/test/src/math/SqrtTest.h b/libc/test/src/math/SqrtTest.h --- a/libc/test/src/math/SqrtTest.h +++ b/libc/test/src/math/SqrtTest.h @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/builtin_bit_cast.h" #include "utils/MPFRWrapper/MPFRUtils.h" #include "utils/UnitTest/FPMatcher.h" #include "utils/UnitTest/Test.h" @@ -47,7 +48,7 @@ constexpr UIntType COUNT = 1'000'001; constexpr UIntType STEP = HIDDEN_BIT / COUNT; for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - T x = *reinterpret_cast(&v); + T x = llvmlibc_builtin_bit_cast(v); test_all_rounding_modes(func, x); } } @@ -56,7 +57,7 @@ constexpr UIntType COUNT = 10'000'001; constexpr UIntType STEP = UIntType(-1) / COUNT; for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - T x = *reinterpret_cast(&v); + T x = llvmlibc_builtin_bit_cast(v); if (isnan(x) || (x < 0)) { continue; } diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -386,16 +386,6 @@ // These functions are useful for debugging. template T as() const; - template <> float as() const { - return mpfr_get_flt(value, mpfr_rounding); - } - template <> double as() const { - return mpfr_get_d(value, mpfr_rounding); - } - template <> long double as() const { - return mpfr_get_ld(value, mpfr_rounding); - } - void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); } // Return the ULP (units-in-the-last-place) difference between the @@ -482,6 +472,18 @@ } }; +template <> float MPFRNumber::as() const { + return mpfr_get_flt(value, mpfr_rounding); +} + +template <> double MPFRNumber::as() const { + return mpfr_get_d(value, mpfr_rounding); +} + +template <> long double MPFRNumber::as() const { + return mpfr_get_ld(value, mpfr_rounding); +} + namespace internal { template