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
19namespace simdpp {
20namespace SIMDPP_ARCH_NAMESPACE {
21
22namespace detail {
23
24// on certain architectures mask-mask conversions may need unmasking or remasking
25template<class R, class T> struct cast_mask_override { static const unsigned value = CAST_MASK_MEMCPY; };
26#if SIMDPP_USE_NEON_NO_FLT_SP
27template<unsigned N>
28struct cast_mask_override<mask_float32<N>, mask_int32<N>> { static const unsigned value = CAST_MASK_UNMASK; };
29template<unsigned N>
30struct 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
33template<unsigned N>
34struct cast_mask_override<mask_int64<N>, mask_float64<N>> { static const unsigned value = CAST_MASK_UNMASK; };
35template<unsigned N>
36struct 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
39template<unsigned N>
40struct cast_mask_override<mask_int64<N>, mask_float64<N>> { static const unsigned value = CAST_MASK_REMASK; };
41template<unsigned N>
42struct cast_mask_override<mask_float64<N>, mask_int64<N>> { static const unsigned value = CAST_MASK_UNMASK; };
43#endif
44
45template<class R, class T> SIMDPP_INL
46void 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
70template<class T> SIMDPP_INL
71void 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*/
93template<class R, class T> SIMDPP_INL
94R 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