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