1b1fb3d75SLouis Dionne //===----------------------------------------------------------------------===// 2b1fb3d75SLouis Dionne // 3b1fb3d75SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b1fb3d75SLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5b1fb3d75SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b1fb3d75SLouis Dionne // 7b1fb3d75SLouis Dionne //===----------------------------------------------------------------------===// 8b1fb3d75SLouis Dionne 9b1fb3d75SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14, c++17 10b1fb3d75SLouis Dionne 11b1fb3d75SLouis Dionne // <bit> 12b1fb3d75SLouis Dionne // 13b1fb3d75SLouis Dionne // template<class To, class From> 14b1fb3d75SLouis Dionne // constexpr To bit_cast(const From& from) noexcept; // C++20 15b1fb3d75SLouis Dionne 16b1fb3d75SLouis Dionne #include <array> 17b1fb3d75SLouis Dionne #include <bit> 18b1fb3d75SLouis Dionne #include <cassert> 19b1fb3d75SLouis Dionne #include <cmath> 20b1fb3d75SLouis Dionne #include <cstdint> 21b1fb3d75SLouis Dionne #include <cstring> 22b1fb3d75SLouis Dionne #include <limits> 23b1fb3d75SLouis Dionne 24bf0d6136SVitaly Buka #include "test_macros.h" 25bf0d6136SVitaly Buka 26b1fb3d75SLouis Dionne // std::bit_cast does not preserve padding bits, so if T has padding bits, 27b1fb3d75SLouis Dionne // the results might not memcmp cleanly. 28b1fb3d75SLouis Dionne template<bool HasUniqueObjectRepresentations = true, typename T> 29b1fb3d75SLouis Dionne void test_roundtrip_through_buffer(T from) { 30b1fb3d75SLouis Dionne struct Buffer { char buffer[sizeof(T)]; }; 31b1fb3d75SLouis Dionne Buffer middle = std::bit_cast<Buffer>(from); 32b1fb3d75SLouis Dionne T to = std::bit_cast<T>(middle); 33b1fb3d75SLouis Dionne Buffer middle2 = std::bit_cast<Buffer>(to); 34b1fb3d75SLouis Dionne 35b1fb3d75SLouis Dionne assert((from == to) == (from == from)); // because NaN 36b1fb3d75SLouis Dionne 37b1fb3d75SLouis Dionne if constexpr (HasUniqueObjectRepresentations) { 38b1fb3d75SLouis Dionne assert(std::memcmp(&from, &middle, sizeof(T)) == 0); 39b1fb3d75SLouis Dionne assert(std::memcmp(&to, &middle, sizeof(T)) == 0); 40b1fb3d75SLouis Dionne assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0); 41b1fb3d75SLouis Dionne } 42b1fb3d75SLouis Dionne } 43b1fb3d75SLouis Dionne 44b1fb3d75SLouis Dionne template<bool HasUniqueObjectRepresentations = true, typename T> 45b1fb3d75SLouis Dionne void test_roundtrip_through_nested_T(T from) { 46b1fb3d75SLouis Dionne struct Nested { T x; }; 47b1fb3d75SLouis Dionne static_assert(sizeof(Nested) == sizeof(T)); 48b1fb3d75SLouis Dionne 49b1fb3d75SLouis Dionne Nested middle = std::bit_cast<Nested>(from); 50b1fb3d75SLouis Dionne T to = std::bit_cast<T>(middle); 51b1fb3d75SLouis Dionne Nested middle2 = std::bit_cast<Nested>(to); 52b1fb3d75SLouis Dionne 53b1fb3d75SLouis Dionne assert((from == to) == (from == from)); // because NaN 54b1fb3d75SLouis Dionne 55b1fb3d75SLouis Dionne if constexpr (HasUniqueObjectRepresentations) { 56b1fb3d75SLouis Dionne assert(std::memcmp(&from, &middle, sizeof(T)) == 0); 57b1fb3d75SLouis Dionne assert(std::memcmp(&to, &middle, sizeof(T)) == 0); 58b1fb3d75SLouis Dionne assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0); 59b1fb3d75SLouis Dionne } 60b1fb3d75SLouis Dionne } 61b1fb3d75SLouis Dionne 62b1fb3d75SLouis Dionne template <typename Intermediate, bool HasUniqueObjectRepresentations = true, typename T> 63b1fb3d75SLouis Dionne void test_roundtrip_through(T from) { 64b1fb3d75SLouis Dionne static_assert(sizeof(Intermediate) == sizeof(T)); 65b1fb3d75SLouis Dionne 66b1fb3d75SLouis Dionne Intermediate middle = std::bit_cast<Intermediate>(from); 67b1fb3d75SLouis Dionne T to = std::bit_cast<T>(middle); 68b1fb3d75SLouis Dionne Intermediate middle2 = std::bit_cast<Intermediate>(to); 69b1fb3d75SLouis Dionne 70b1fb3d75SLouis Dionne assert((from == to) == (from == from)); // because NaN 71b1fb3d75SLouis Dionne 72b1fb3d75SLouis Dionne if constexpr (HasUniqueObjectRepresentations) { 73b1fb3d75SLouis Dionne assert(std::memcmp(&from, &middle, sizeof(T)) == 0); 74b1fb3d75SLouis Dionne assert(std::memcmp(&to, &middle, sizeof(T)) == 0); 75b1fb3d75SLouis Dionne assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0); 76b1fb3d75SLouis Dionne } 77b1fb3d75SLouis Dionne } 78b1fb3d75SLouis Dionne 79b1fb3d75SLouis Dionne template <typename T> 80b1fb3d75SLouis Dionne constexpr std::array<T, 10> generate_signed_integral_values() { 81b1fb3d75SLouis Dionne return {std::numeric_limits<T>::min(), 82b1fb3d75SLouis Dionne std::numeric_limits<T>::min() + 1, 83b1fb3d75SLouis Dionne static_cast<T>(-2), static_cast<T>(-1), 84b1fb3d75SLouis Dionne static_cast<T>(0), static_cast<T>(1), 85b1fb3d75SLouis Dionne static_cast<T>(2), static_cast<T>(3), 86b1fb3d75SLouis Dionne std::numeric_limits<T>::max() - 1, 87b1fb3d75SLouis Dionne std::numeric_limits<T>::max()}; 88b1fb3d75SLouis Dionne } 89b1fb3d75SLouis Dionne 90b1fb3d75SLouis Dionne template <typename T> 91b1fb3d75SLouis Dionne constexpr std::array<T, 6> generate_unsigned_integral_values() { 92b1fb3d75SLouis Dionne return {static_cast<T>(0), static_cast<T>(1), 93b1fb3d75SLouis Dionne static_cast<T>(2), static_cast<T>(3), 94b1fb3d75SLouis Dionne std::numeric_limits<T>::max() - 1, 95b1fb3d75SLouis Dionne std::numeric_limits<T>::max()}; 96b1fb3d75SLouis Dionne } 97b1fb3d75SLouis Dionne 98b1fb3d75SLouis Dionne bool tests() { 99b1fb3d75SLouis Dionne for (bool b : {false, true}) { 100b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(b); 101b1fb3d75SLouis Dionne test_roundtrip_through_buffer(b); 102b1fb3d75SLouis Dionne test_roundtrip_through<char>(b); 103b1fb3d75SLouis Dionne } 104b1fb3d75SLouis Dionne 105b1fb3d75SLouis Dionne for (char c : {'\0', 'a', 'b', 'c', 'd'}) { 106b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(c); 107b1fb3d75SLouis Dionne test_roundtrip_through_buffer(c); 108b1fb3d75SLouis Dionne } 109b1fb3d75SLouis Dionne 110b1fb3d75SLouis Dionne // Fundamental signed integer types 111b1fb3d75SLouis Dionne for (signed char i : generate_signed_integral_values<signed char>()) { 112b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 113b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 114b1fb3d75SLouis Dionne } 115b1fb3d75SLouis Dionne 116b1fb3d75SLouis Dionne for (short i : generate_signed_integral_values<short>()) { 117b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 118b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 119b1fb3d75SLouis Dionne } 120b1fb3d75SLouis Dionne 121b1fb3d75SLouis Dionne for (int i : generate_signed_integral_values<int>()) { 122b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 123b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 124b1fb3d75SLouis Dionne test_roundtrip_through<float>(i); 125b1fb3d75SLouis Dionne } 126b1fb3d75SLouis Dionne 127b1fb3d75SLouis Dionne for (long i : generate_signed_integral_values<long>()) { 128b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 129b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 130b1fb3d75SLouis Dionne } 131b1fb3d75SLouis Dionne 132b1fb3d75SLouis Dionne for (long long i : generate_signed_integral_values<long long>()) { 133b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 134b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 135b1fb3d75SLouis Dionne test_roundtrip_through<double>(i); 136b1fb3d75SLouis Dionne } 137b1fb3d75SLouis Dionne 138b1fb3d75SLouis Dionne // Fundamental unsigned integer types 139b1fb3d75SLouis Dionne for (unsigned char i : generate_unsigned_integral_values<unsigned char>()) { 140b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 141b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 142b1fb3d75SLouis Dionne } 143b1fb3d75SLouis Dionne 144b1fb3d75SLouis Dionne for (unsigned short i : generate_unsigned_integral_values<unsigned short>()) { 145b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 146b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 147b1fb3d75SLouis Dionne } 148b1fb3d75SLouis Dionne 149b1fb3d75SLouis Dionne for (unsigned int i : generate_unsigned_integral_values<unsigned int>()) { 150b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 151b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 152b1fb3d75SLouis Dionne test_roundtrip_through<float>(i); 153b1fb3d75SLouis Dionne } 154b1fb3d75SLouis Dionne 155b1fb3d75SLouis Dionne for (unsigned long i : generate_unsigned_integral_values<unsigned long>()) { 156b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 157b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 158b1fb3d75SLouis Dionne } 159b1fb3d75SLouis Dionne 160b1fb3d75SLouis Dionne for (unsigned long long i : generate_unsigned_integral_values<unsigned long long>()) { 161b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 162b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 163b1fb3d75SLouis Dionne test_roundtrip_through<double>(i); 164b1fb3d75SLouis Dionne } 165b1fb3d75SLouis Dionne 166b1fb3d75SLouis Dionne // Fixed width signed integer types 167b1fb3d75SLouis Dionne for (std::int32_t i : generate_signed_integral_values<std::int32_t>()) { 168b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 169b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 170b1fb3d75SLouis Dionne test_roundtrip_through<int>(i); 171b1fb3d75SLouis Dionne test_roundtrip_through<std::uint32_t>(i); 172b1fb3d75SLouis Dionne test_roundtrip_through<float>(i); 173b1fb3d75SLouis Dionne } 174b1fb3d75SLouis Dionne 175b1fb3d75SLouis Dionne for (std::int64_t i : generate_signed_integral_values<std::int64_t>()) { 176b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 177b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 178b1fb3d75SLouis Dionne test_roundtrip_through<long long>(i); 179b1fb3d75SLouis Dionne test_roundtrip_through<std::uint64_t>(i); 180b1fb3d75SLouis Dionne test_roundtrip_through<double>(i); 181b1fb3d75SLouis Dionne } 182b1fb3d75SLouis Dionne 183b1fb3d75SLouis Dionne // Fixed width unsigned integer types 184b1fb3d75SLouis Dionne for (std::uint32_t i : generate_unsigned_integral_values<std::uint32_t>()) { 185b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 186b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 187b1fb3d75SLouis Dionne test_roundtrip_through<int>(i); 188b1fb3d75SLouis Dionne test_roundtrip_through<std::int32_t>(i); 189b1fb3d75SLouis Dionne test_roundtrip_through<float>(i); 190b1fb3d75SLouis Dionne } 191b1fb3d75SLouis Dionne 192b1fb3d75SLouis Dionne for (std::uint64_t i : generate_unsigned_integral_values<std::uint64_t>()) { 193b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 194b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 195b1fb3d75SLouis Dionne test_roundtrip_through<long long>(i); 196b1fb3d75SLouis Dionne test_roundtrip_through<std::int64_t>(i); 197b1fb3d75SLouis Dionne test_roundtrip_through<double>(i); 198b1fb3d75SLouis Dionne } 199b1fb3d75SLouis Dionne 200b1fb3d75SLouis Dionne // Floating point types 201b1fb3d75SLouis Dionne for (float i : {0.0f, 1.0f, -1.0f, 10.0f, -10.0f, 1e10f, 1e-10f, 1e20f, 1e-20f, 2.71828f, 3.14159f, 202b1fb3d75SLouis Dionne std::nanf(""), 203b1fb3d75SLouis Dionne __builtin_nanf("0x55550001"), // NaN with a payload 204b1fb3d75SLouis Dionne std::numeric_limits<float>::signaling_NaN(), 205b1fb3d75SLouis Dionne std::numeric_limits<float>::quiet_NaN()}) { 206b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 207b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 208b1fb3d75SLouis Dionne test_roundtrip_through<int>(i); 209b1fb3d75SLouis Dionne } 210b1fb3d75SLouis Dionne 211b1fb3d75SLouis Dionne for (double i : {0.0, 1.0, -1.0, 10.0, -10.0, 1e10, 1e-10, 1e100, 1e-100, 212b1fb3d75SLouis Dionne 2.718281828459045, 213b1fb3d75SLouis Dionne 3.141592653589793238462643383279502884197169399375105820974944, 214b1fb3d75SLouis Dionne std::nan(""), 215b1fb3d75SLouis Dionne std::numeric_limits<double>::signaling_NaN(), 216b1fb3d75SLouis Dionne std::numeric_limits<double>::quiet_NaN()}) { 217b1fb3d75SLouis Dionne test_roundtrip_through_nested_T(i); 218b1fb3d75SLouis Dionne test_roundtrip_through_buffer(i); 219b1fb3d75SLouis Dionne test_roundtrip_through<long long>(i); 220b1fb3d75SLouis Dionne } 221b1fb3d75SLouis Dionne 222b1fb3d75SLouis Dionne for (long double i : {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l, 1e-10l, 1e100l, 1e-100l, 223b1fb3d75SLouis Dionne 2.718281828459045l, 224b1fb3d75SLouis Dionne 3.141592653589793238462643383279502884197169399375105820974944l, 225b1fb3d75SLouis Dionne std::nanl(""), 226b1fb3d75SLouis Dionne std::numeric_limits<long double>::signaling_NaN(), 227b1fb3d75SLouis Dionne std::numeric_limits<long double>::quiet_NaN()}) { 228b1fb3d75SLouis Dionne // Note that x86's `long double` has 80 value bits and 48 padding bits. 229b1fb3d75SLouis Dionne test_roundtrip_through_nested_T<false>(i); 230b1fb3d75SLouis Dionne test_roundtrip_through_buffer<false>(i); 231b1fb3d75SLouis Dionne 232*c792de28SDavid Spickett #ifdef TEST_LONG_DOUBLE_IS_DOUBLE 233b1fb3d75SLouis Dionne test_roundtrip_through<double, false>(i); 234a03e17d4SMartin Storsjö #endif 235bf0d6136SVitaly Buka #if defined(__SIZEOF_INT128__) && __SIZEOF_LONG_DOUBLE__ == __SIZEOF_INT128__ && \ 236bf0d6136SVitaly Buka !TEST_HAS_FEATURE(memory_sanitizer) // Some bits are just padding. 237b1fb3d75SLouis Dionne test_roundtrip_through<__int128_t, false>(i); 238b1fb3d75SLouis Dionne test_roundtrip_through<__uint128_t, false>(i); 239b1fb3d75SLouis Dionne #endif 240b1fb3d75SLouis Dionne } 241b1fb3d75SLouis Dionne 2421c834112SLouis Dionne // Test pointers 2431c834112SLouis Dionne { 2441c834112SLouis Dionne { 2451c834112SLouis Dionne int obj = 3; 2461c834112SLouis Dionne void* p = &obj; 2471c834112SLouis Dionne test_roundtrip_through_nested_T(p); 2481c834112SLouis Dionne test_roundtrip_through_buffer(p); 2491c834112SLouis Dionne test_roundtrip_through<void*>(p); 2501c834112SLouis Dionne test_roundtrip_through<char*>(p); 2511c834112SLouis Dionne test_roundtrip_through<int*>(p); 2521c834112SLouis Dionne } 2531c834112SLouis Dionne { 2541c834112SLouis Dionne int obj = 3; 2551c834112SLouis Dionne int* p = &obj; 2561c834112SLouis Dionne test_roundtrip_through_nested_T(p); 2571c834112SLouis Dionne test_roundtrip_through_buffer(p); 2581c834112SLouis Dionne test_roundtrip_through<int*>(p); 2591c834112SLouis Dionne test_roundtrip_through<char*>(p); 2601c834112SLouis Dionne test_roundtrip_through<void*>(p); 2611c834112SLouis Dionne } 2621c834112SLouis Dionne } 2631c834112SLouis Dionne 264b1fb3d75SLouis Dionne return true; 265b1fb3d75SLouis Dionne } 266b1fb3d75SLouis Dionne 267b1fb3d75SLouis Dionne // TODO: There doesn't seem to be a way to perform non-trivial correctness 268b1fb3d75SLouis Dionne // tests inside constexpr. 269b1fb3d75SLouis Dionne constexpr bool basic_constexpr_test() { 270b1fb3d75SLouis Dionne struct Nested { char buffer[sizeof(int)]; }; 271b1fb3d75SLouis Dionne int from = 3; 272b1fb3d75SLouis Dionne Nested middle = std::bit_cast<Nested>(from); 273b1fb3d75SLouis Dionne int to = std::bit_cast<int>(middle); 274b1fb3d75SLouis Dionne assert(from == to); 275b1fb3d75SLouis Dionne return true; 276b1fb3d75SLouis Dionne } 277b1fb3d75SLouis Dionne 278b1fb3d75SLouis Dionne int main(int, char**) { 279b1fb3d75SLouis Dionne tests(); 280b1fb3d75SLouis Dionne static_assert(basic_constexpr_test()); 281b1fb3d75SLouis Dionne return 0; 282b1fb3d75SLouis Dionne } 283