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