brintos

brintos / llvm-project-archived public Read only

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