| 1 | /* Copyright (C) 2011-2014 Povilas Kanapickas <povilas@radix.lt> |
| 2 | |
| 3 | Distributed under the Boost Software License, Version 1.0. |
| 4 | (See accompanying file LICENSE_1_0.txt or copy at |
| 5 | http://www.boost.org/LICENSE_1_0.txt) |
| 6 | */ |
| 7 | |
| 8 | #ifndef LIBSIMDPP_SIMDPP_CORE_CAST_H |
| 9 | #define LIBSIMDPP_SIMDPP_CORE_CAST_H |
| 10 | |
| 11 | #ifndef LIBSIMDPP_SIMD_H |
| 12 | #error "This file must be included through simd.h" |
| 13 | #endif |
| 14 | |
| 15 | #include <simdpp/setup_arch.h> |
| 16 | #include <simdpp/detail/cast.h> |
| 17 | #include <simdpp/types/traits.h> |
| 18 | |
| 19 | namespace simdpp { |
| 20 | namespace SIMDPP_ARCH_NAMESPACE { |
| 21 | |
| 22 | namespace detail { |
| 23 | |
| 24 | // on certain architectures mask-mask conversions may need unmasking or remasking |
| 25 | template<class R, class T> struct cast_mask_override { static const unsigned value = CAST_MASK_MEMCPY; }; |
| 26 | #if SIMDPP_USE_NEON_NO_FLT_SP |
| 27 | template<unsigned N> |
| 28 | struct cast_mask_override<mask_float32<N>, mask_int32<N>> { static const unsigned value = CAST_MASK_UNMASK; }; |
| 29 | template<unsigned N> |
| 30 | struct cast_mask_override<mask_int32<N>, mask_float32<N>> { static const unsigned value = CAST_MASK_REMASK; }; |
| 31 | #endif |
| 32 | #if SIMDPP_USE_NEON && SIMDPP_32_BITS |
| 33 | template<unsigned N> |
| 34 | struct cast_mask_override<mask_int64<N>, mask_float64<N>> { static const unsigned value = CAST_MASK_UNMASK; }; |
| 35 | template<unsigned N> |
| 36 | struct cast_mask_override<mask_float64<N>, mask_int64<N>> { static const unsigned value = CAST_MASK_REMASK; }; |
| 37 | #endif |
| 38 | #if SIMDPP_USE_VSX_206 && !SIMDPP_USE_VSX_207 |
| 39 | template<unsigned N> |
| 40 | struct cast_mask_override<mask_int64<N>, mask_float64<N>> { static const unsigned value = CAST_MASK_REMASK; }; |
| 41 | template<unsigned N> |
| 42 | struct cast_mask_override<mask_float64<N>, mask_int64<N>> { static const unsigned value = CAST_MASK_UNMASK; }; |
| 43 | #endif |
| 44 | |
| 45 | template<class R, class T> SIMDPP_INL |
| 46 | void bit_cast_impl(const T& t, R& r) |
| 47 | { |
| 48 | const bool is_vector_r = is_vector<R>::value; |
| 49 | const bool is_vector_t = is_vector<T>::value; |
| 50 | const bool is_mask_r = is_mask<R>::value; |
| 51 | const bool is_mask_t = is_mask<T>::value; |
| 52 | const unsigned mask_mask_cast_override = detail::cast_mask_override<R,T>::value; |
| 53 | |
| 54 | const unsigned cast_type = |
| 55 | (!is_vector_t && !is_vector_r) ? CAST_TYPE_OTHER : |
| 56 | (!is_mask_t && !is_mask_r) ? CAST_TYPE_VECTOR_TO_VECTOR : |
| 57 | (is_mask_t && !is_mask_r) ? CAST_TYPE_MASK_TO_VECTOR : |
| 58 | (!is_mask_t && is_mask_r) ? CAST_TYPE_VECTOR_TO_MASK : |
| 59 | // remaining cases deal with is_mask_t && is_mask_r |
| 60 | (mask_mask_cast_override == CAST_MASK_REMASK) ? CAST_TYPE_MASK_TO_MASK_REMASK : |
| 61 | (mask_mask_cast_override == CAST_MASK_UNMASK) ? CAST_TYPE_MASK_TO_MASK_UNMASK : |
| 62 | CAST_TYPE_MASK_TO_MASK_BITWISE; |
| 63 | |
| 64 | static_assert(is_vector_r == is_vector_t, |
| 65 | "bit_cast can't convert between vector and non-vector types" ); |
| 66 | |
| 67 | detail::cast_wrapper<cast_type>::run(t, r); |
| 68 | } |
| 69 | |
| 70 | template<class T> SIMDPP_INL |
| 71 | void bit_cast_impl(const T& t, T& r) |
| 72 | { |
| 73 | // Simple implementation for the common case |
| 74 | r = t; |
| 75 | } |
| 76 | |
| 77 | } // namespace detail |
| 78 | |
| 79 | /** Casts between unrelated types. No changes to the stored values are |
| 80 | performed. |
| 81 | |
| 82 | Conversions between vector and non-vector types are not allowed. |
| 83 | |
| 84 | Conversion from non-mask type to mask type is not allowed. |
| 85 | |
| 86 | Conversion from mask type to a non-mask type is not a costless operation |
| 87 | because masks may have different logical and physical layout (e.g., in |
| 88 | some implementations one bit represents entire element in a vector). |
| 89 | |
| 90 | Conversions between mask types is only allowed if the element size is the |
| 91 | same. |
| 92 | */ |
| 93 | template<class R, class T> SIMDPP_INL |
| 94 | R bit_cast(const T& t) |
| 95 | { |
| 96 | R r; |
| 97 | detail::bit_cast_impl(t, r); |
| 98 | return r; |
| 99 | } |
| 100 | |
| 101 | } // namespace SIMDPP_ARCH_NAMESPACE |
| 102 | } // namespace simdpp |
| 103 | |
| 104 | #endif |
| 105 | |