1 | /* Copyright (C) 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_DETAIL_GET_EXPR_BITWISE_H |
9 | #define LIBSIMDPP_SIMDPP_CORE_DETAIL_GET_EXPR_BITWISE_H |
10 | |
11 | #include <simdpp/detail/get_expr.h> |
12 | |
13 | namespace simdpp { |
14 | namespace SIMDPP_ARCH_NAMESPACE { |
15 | namespace detail { |
16 | |
17 | |
18 | /* We want to reduce the number of overloads that need to be created in order |
19 | to match a specific case of an expression tree containing 'bit_and', |
20 | or 'bit_andnot'. nodes. The following "optimizations" |
21 | are performed: |
22 | |
23 | * If the parameters are types have different element sizes then both |
24 | expression arguments have the same type as the expression itself, except |
25 | that signed vectors are converted to unsigned vectors. |
26 | * Otherwise if the expression is of a mask type then both types are the |
27 | same as the expression itself. |
28 | * Otherwise both types have the same type as the expression itself, except |
29 | that signed vectors are converted to unsigned vectors and if the second |
30 | type is a mask type then it is converted to floating-point mask if the |
31 | expression is floating-point expression and to integer mask otherwise. |
32 | |
33 | So, as a result, the following tuples of types will appear as the arguments |
34 | of the returned expression: |
35 | |
36 | * mask_int8, mask_int8 |
37 | * uint8, mask_int8 |
38 | * uint8, uint8 |
39 | * mask_int16, mask_int16 |
40 | * uint16, mask_int16 |
41 | * uint16, uint16 |
42 | * mask_int32, mask_int32 |
43 | * uint32, mask_int32 |
44 | * uint32, uint32 |
45 | * mask_int64, mask_int64 |
46 | * uint64, mask_int64 |
47 | * uint64, uint64 |
48 | * mask_float32, mask_float32 |
49 | * float32, mask_float32 |
50 | * float32, float32 |
51 | * mask_float64, mask_float64 |
52 | * float64, mask_float64 |
53 | * float64, float64 |
54 | |
55 | The type of the returned expression is governed by the usual rules |
56 | (see simdpp/types/tag.h) |
57 | */ |
58 | |
59 | template<class V1, class V2> |
60 | struct get_expr_bitwise2_and_impl { |
61 | using tags = expr2_maybe_scalar_tags<V1, V2>; |
62 | |
63 | // (size_tag) get the size tag of the resulting expression |
64 | static const unsigned size_tag = tags::v1_size_tag > tags::v2_size_tag |
65 | ? tags::v1_size_tag : tags::v2_size_tag; |
66 | |
67 | // (type_tag) get the type tag of the expression. We compute it in the same |
68 | // way get_expr2 computes them, i.e. |
69 | // type_tag == get_expr2<V1,V2>::type::type_tag |
70 | static const unsigned type_tag_t1 = tags::v1_type_tag > tags::v2_type_tag |
71 | ? tags::v1_type_tag : tags::v2_type_tag; |
72 | static const bool is_mask_op1 = type_tag_t1 == SIMDPP_TAG_MASK_INT || |
73 | type_tag_t1 == SIMDPP_TAG_MASK_FLOAT; |
74 | static const unsigned type_tag = (is_mask_op1 && tags::v1_size_tag != tags::v2_size_tag) |
75 | ? SIMDPP_TAG_UINT : type_tag_t1; |
76 | |
77 | // strip signed integer types |
78 | static const unsigned v1_type_tag = type_tag == SIMDPP_TAG_INT ? SIMDPP_TAG_UINT : type_tag; |
79 | |
80 | |
81 | static const bool is_v2_mask = tags::v2_type_tag == SIMDPP_TAG_MASK_INT || |
82 | tags::v2_type_tag == SIMDPP_TAG_MASK_FLOAT; |
83 | static const bool is_v1_float = type_tag == SIMDPP_TAG_FLOAT || |
84 | type_tag == SIMDPP_TAG_MASK_FLOAT; |
85 | |
86 | // if second parameter is a mask, then: |
87 | // - convert the mask to float mask if the expression is float |
88 | // - convert the mask to integer mask otherwise |
89 | static const unsigned v2_type_tag = (!is_v2_mask) ? v1_type_tag : |
90 | is_v1_float ? SIMDPP_TAG_MASK_FLOAT : |
91 | SIMDPP_TAG_MASK_INT; |
92 | |
93 | using v1_final_type = typename type_of_tag<v1_type_tag + size_tag, |
94 | tags::length_bytes, void>::type; |
95 | using v2_final_type = typename type_of_tag<v2_type_tag + size_tag, |
96 | tags::length_bytes, void>::type; |
97 | }; |
98 | |
99 | template<template<class, class> class E, class V1, class V2> |
100 | struct get_expr_bitwise2_and { |
101 | using impl = get_expr_bitwise2_and_impl<V1, V2>; |
102 | using type = typename type_of_tag<impl::type_tag + impl::size_tag, |
103 | impl::tags::length_bytes, |
104 | E<V1, V2>>::type; |
105 | }; |
106 | |
107 | |
108 | /* The case with bit_or is similar to bit_and and bit_andnot except that the |
109 | expression types are either leave two masks or none. |
110 | |
111 | * Both expression arguments have the same type as the expression itself, |
112 | except that signed vectors are converted to unsigned vectors. |
113 | |
114 | So, as a result, the following tuples of types will appear as the arguments |
115 | of the returned expression: |
116 | |
117 | * mask_int8, mask_int8 |
118 | * uint8, uint8 |
119 | * mask_int16, mask_int16 |
120 | * uint16, uint16 |
121 | * mask_int32, mask_int32 |
122 | * uint32, uint32 |
123 | * mask_int64, mask_int64 |
124 | * uint64, uint64 |
125 | * mask_float32, mask_float32 |
126 | * float32, float32 |
127 | * mask_float64, mask_float64 |
128 | * float64, float64 |
129 | |
130 | The type of the returned expression is governed by the usual rules |
131 | (see simdpp/types/tag.h) |
132 | */ |
133 | |
134 | template<class V1, class V2> |
135 | class get_expr_bit_or { |
136 | |
137 | // (size_tag) get the size tag of the resulting expression |
138 | static const unsigned size_tag = V1::size_tag > V2::size_tag ? V1::size_tag : V2::size_tag; |
139 | |
140 | // (type_tag) get the type tag of the expression. We compute it in the same |
141 | // way get_expr2 computes them, i.e. |
142 | // type_tag == get_expr2<V1,V2>::type::type_tag |
143 | static const unsigned type_tag_t1 = V1::type_tag > V2::type_tag ? V1::type_tag : V2::type_tag; |
144 | static const bool is_mask_op1 = type_tag_t1 == SIMDPP_TAG_MASK_INT || |
145 | type_tag_t1 == SIMDPP_TAG_MASK_FLOAT; |
146 | static const unsigned type_tag = (is_mask_op1 && V1::size_tag != V2::size_tag) |
147 | ? SIMDPP_TAG_UINT : type_tag_t1; |
148 | |
149 | // strip signed integer types |
150 | static const unsigned v12_type_tag = type_tag == SIMDPP_TAG_INT ? SIMDPP_TAG_UINT : type_tag; |
151 | |
152 | |
153 | public: |
154 | using v1_final_type = typename type_of_tag<v12_type_tag + size_tag, |
155 | V1::length_bytes, void>::type; |
156 | using v2_final_type = typename type_of_tag<v12_type_tag + size_tag, |
157 | V1::length_bytes, void>::type; |
158 | |
159 | using type = typename type_of_tag<type_tag + size_tag, V1::length_bytes, |
160 | expr_bit_or<V1, V2>>::type; |
161 | }; |
162 | |
163 | |
164 | |
165 | } // namespace detail |
166 | } // namespace SIMDPP_ARCH_NAMESPACE |
167 | } // namespace simdpp |
168 | |
169 | #endif |
170 | |