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_DETAIL_GET_EXPR_H
9#define LIBSIMDPP_SIMDPP_DETAIL_GET_EXPR_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/expr.h>
17#include <simdpp/types/fwd.h>
18#include <simdpp/types/any.h>
19#include <simdpp/types/tag.h>
20#include <simdpp/expr.h>
21
22namespace simdpp {
23namespace SIMDPP_ARCH_NAMESPACE {
24namespace detail {
25
26/* The tag values are selected specifically to make this class template
27 simpler.
28
29 See simdpp/types/tag.h
30
31 Note that B refers to the number of elements in the resulting vector. Since
32 get_expr2 always selects elements with smaller number of (wider) elements,
33 one only needs to ensure that B refers to the function argument with widest
34 elements among the function arguments.
35*/
36
37template<unsigned Tag, unsigned B, class E> struct type_of_tag;
38template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_INT + SIMDPP_TAG_SIZE8, B, E> { using type = int8<B,E>; using empty = int8<B,expr_empty>; };
39template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_INT + SIMDPP_TAG_SIZE16, B, E> { using type = int16<B/2,E>; using empty = int16<B/2,expr_empty>; };
40template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_INT + SIMDPP_TAG_SIZE32, B, E> { using type = int32<B/4,E>; using empty = int32<B/4,expr_empty>; };
41template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_INT + SIMDPP_TAG_SIZE64, B, E> { using type = int64<B/8,E>; using empty = int64<B/8,expr_empty>; };
42template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_UINT + SIMDPP_TAG_SIZE8, B, E> { using type = uint8<B,E>; using empty = uint8<B,expr_empty>; };
43template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_UINT + SIMDPP_TAG_SIZE16, B, E> { using type = uint16<B/2,E>; using empty = uint16<B/2,expr_empty>; };
44template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_UINT + SIMDPP_TAG_SIZE32, B, E> { using type = uint32<B/4,E>; using empty = uint32<B/4,expr_empty>; };
45template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_UINT + SIMDPP_TAG_SIZE64, B, E> { using type = uint64<B/8,E>; using empty = uint64<B/8,expr_empty>; };
46template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_INT + SIMDPP_TAG_SIZE8, B, E> { using type = mask_int8<B,E>; using empty = mask_int8<B,expr_empty>; };
47template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_INT + SIMDPP_TAG_SIZE16, B, E> { using type = mask_int16<B/2,E>; using empty = mask_int16<B/2,expr_empty>; };
48template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_INT + SIMDPP_TAG_SIZE32, B, E> { using type = mask_int32<B/4,E>; using empty = mask_int32<B/4,expr_empty>; };
49template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_INT + SIMDPP_TAG_SIZE64, B, E> { using type = mask_int64<B/8,E>; using empty = mask_int64<B/8,expr_empty>; };
50template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_FLOAT + SIMDPP_TAG_SIZE32, B, E> { using type = float32<B/4,E>; using empty = float32<B/4,expr_empty>; };
51template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_FLOAT + SIMDPP_TAG_SIZE64, B, E> { using type = float64<B/8,E>; using empty = float64<B/8,expr_empty>; };
52template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_FLOAT + SIMDPP_TAG_SIZE32, B, E> { using type = mask_float32<B/4,E>; using empty = mask_float32<B/4,expr_empty>; };
53template<unsigned B, class E> struct type_of_tag<SIMDPP_TAG_MASK_FLOAT + SIMDPP_TAG_SIZE64, B, E> { using type = mask_float64<B/8,E>; using empty = mask_float64<B/8,expr_empty>; };
54
55template<class V1, class V2>
56struct expr2_maybe_scalar_tags {
57 static const unsigned v1_type_tag = V1::type_tag;
58 static const unsigned v1_size_tag = V1::size_tag;
59 static const unsigned v2_type_tag = V2::type_tag;
60 static const unsigned v2_size_tag = V2::size_tag;
61 static const unsigned length_bytes = V1::length_bytes;
62};
63
64template<class V2>
65struct expr2_maybe_scalar_tags<int, V2> {
66 static const unsigned v1_type_tag = V2::type_tag;
67 static const unsigned v1_size_tag = V2::size_tag;
68 static const unsigned v2_type_tag = V2::type_tag;
69 static const unsigned v2_size_tag = V2::size_tag;
70 static const unsigned length_bytes = V2::length_bytes;
71};
72
73template<class V2>
74struct expr2_maybe_scalar_tags<long, V2> {
75 static const unsigned v1_type_tag = V2::type_tag;
76 static const unsigned v1_size_tag = V2::size_tag;
77 static const unsigned v2_type_tag = V2::type_tag;
78 static const unsigned v2_size_tag = V2::size_tag;
79 static const unsigned length_bytes = V2::length_bytes;
80};
81
82template<class V2>
83struct expr2_maybe_scalar_tags<long long, V2> {
84 static const unsigned v1_type_tag = V2::type_tag;
85 static const unsigned v1_size_tag = V2::size_tag;
86 static const unsigned v2_type_tag = V2::type_tag;
87 static const unsigned v2_size_tag = V2::size_tag;
88 static const unsigned length_bytes = V2::length_bytes;
89};
90
91template<class V2>
92struct expr2_maybe_scalar_tags<unsigned, V2> {
93 static const unsigned v1_type_tag = V2::type_tag;
94 static const unsigned v1_size_tag = V2::size_tag;
95 static const unsigned v2_type_tag = V2::type_tag;
96 static const unsigned v2_size_tag = V2::size_tag;
97 static const unsigned length_bytes = V2::length_bytes;
98};
99
100template<class V2>
101struct expr2_maybe_scalar_tags<unsigned long, V2> {
102 static const unsigned v1_type_tag = V2::type_tag;
103 static const unsigned v1_size_tag = V2::size_tag;
104 static const unsigned v2_type_tag = V2::type_tag;
105 static const unsigned v2_size_tag = V2::size_tag;
106 static const unsigned length_bytes = V2::length_bytes;
107};
108
109template<class V2>
110struct expr2_maybe_scalar_tags<unsigned long long, V2> {
111 static const unsigned v1_type_tag = V2::type_tag;
112 static const unsigned v1_size_tag = V2::size_tag;
113 static const unsigned v2_type_tag = V2::type_tag;
114 static const unsigned v2_size_tag = V2::size_tag;
115 static const unsigned length_bytes = V2::length_bytes;
116};
117
118template<class V2>
119struct expr2_maybe_scalar_tags<float, V2> {
120 static const unsigned v1_type_tag = V2::type_tag;
121 static const unsigned v1_size_tag = V2::size_tag;
122 static const unsigned v2_type_tag = V2::type_tag;
123 static const unsigned v2_size_tag = V2::size_tag;
124 static const unsigned length_bytes = V2::length_bytes;
125};
126
127template<class V2>
128struct expr2_maybe_scalar_tags<double, V2> {
129 static const unsigned v1_type_tag = V2::type_tag;
130 static const unsigned v1_size_tag = V2::size_tag;
131 static const unsigned v2_type_tag = V2::type_tag;
132 static const unsigned v2_size_tag = V2::size_tag;
133 static const unsigned length_bytes = V2::length_bytes;
134};
135
136template<class V1>
137struct expr2_maybe_scalar_tags<V1, int> {
138 static const unsigned v1_type_tag = V1::type_tag;
139 static const unsigned v1_size_tag = V1::size_tag;
140 static const unsigned v2_type_tag = V1::type_tag;
141 static const unsigned v2_size_tag = V1::size_tag;
142 static const unsigned length_bytes = V1::length_bytes;
143};
144
145template<class V1>
146struct expr2_maybe_scalar_tags<V1, long> {
147 static const unsigned v1_type_tag = V1::type_tag;
148 static const unsigned v1_size_tag = V1::size_tag;
149 static const unsigned v2_type_tag = V1::type_tag;
150 static const unsigned v2_size_tag = V1::size_tag;
151 static const unsigned length_bytes = V1::length_bytes;
152};
153
154template<class V1>
155struct expr2_maybe_scalar_tags<V1, long long> {
156 static const unsigned v1_type_tag = V1::type_tag;
157 static const unsigned v1_size_tag = V1::size_tag;
158 static const unsigned v2_type_tag = V1::type_tag;
159 static const unsigned v2_size_tag = V1::size_tag;
160 static const unsigned length_bytes = V1::length_bytes;
161};
162
163template<class V1>
164struct expr2_maybe_scalar_tags<V1, unsigned> {
165 static const unsigned v1_type_tag = V1::type_tag;
166 static const unsigned v1_size_tag = V1::size_tag;
167 static const unsigned v2_type_tag = V1::type_tag;
168 static const unsigned v2_size_tag = V1::size_tag;
169 static const unsigned length_bytes = V1::length_bytes;
170};
171
172template<class V1>
173struct expr2_maybe_scalar_tags<V1, unsigned long> {
174 static const unsigned v1_type_tag = V1::type_tag;
175 static const unsigned v1_size_tag = V1::size_tag;
176 static const unsigned v2_type_tag = V1::type_tag;
177 static const unsigned v2_size_tag = V1::size_tag;
178 static const unsigned length_bytes = V1::length_bytes;
179};
180
181template<class V1>
182struct expr2_maybe_scalar_tags<V1, unsigned long long> {
183 static const unsigned v1_type_tag = V1::type_tag;
184 static const unsigned v1_size_tag = V1::size_tag;
185 static const unsigned v2_type_tag = V1::type_tag;
186 static const unsigned v2_size_tag = V1::size_tag;
187 static const unsigned length_bytes = V1::length_bytes;
188};
189
190template<class V1>
191struct expr2_maybe_scalar_tags<V1, float> {
192 static const unsigned v1_type_tag = V1::type_tag;
193 static const unsigned v1_size_tag = V1::size_tag;
194 static const unsigned v2_type_tag = V1::type_tag;
195 static const unsigned v2_size_tag = V1::size_tag;
196 static const unsigned length_bytes = V1::length_bytes;
197};
198
199template<class V1>
200struct expr2_maybe_scalar_tags<V1, double> {
201 static const unsigned v1_type_tag = V1::type_tag;
202 static const unsigned v1_size_tag = V1::size_tag;
203 static const unsigned v2_type_tag = V1::type_tag;
204 static const unsigned v2_size_tag = V1::size_tag;
205 static const unsigned length_bytes = V1::length_bytes;
206};
207
208template<class V, class E = void>
209class get_expr {
210public:
211 using type = typename type_of_tag<V::type_tag + V::size_tag, V::length_bytes, E>::type;
212 using empty = typename type_of_tag<V::type_tag + V::size_tag, V::length_bytes, E>::empty;
213};
214
215template<class V, class E = void>
216class get_expr_nomask {
217 static const unsigned type_tag = (V::type_tag == SIMDPP_TAG_MASK_FLOAT) ? SIMDPP_TAG_FLOAT :
218 (V::type_tag == SIMDPP_TAG_MASK_INT) ? SIMDPP_TAG_UINT : V::type_tag;
219public:
220 using type = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::type;
221 using empty = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::empty;
222};
223
224template<class V, class E = void>
225class get_expr_nosign {
226 static const unsigned type_tag = (V::type_tag == SIMDPP_TAG_INT) ? SIMDPP_TAG_UINT : V::type_tag;
227public:
228 using type = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::type;
229 using empty = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::empty;
230};
231
232template<class V, class E = void>
233class get_expr_nomask_nosign {
234 static const unsigned type_tag = (V::type_tag == SIMDPP_TAG_MASK_FLOAT) ? SIMDPP_TAG_FLOAT :
235 (V::type_tag == SIMDPP_TAG_INT) ? SIMDPP_TAG_UINT :
236 (V::type_tag == SIMDPP_TAG_MASK_INT) ? SIMDPP_TAG_UINT : V::type_tag;
237public:
238 using type = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::type;
239 using empty = typename type_of_tag<type_tag + V::size_tag, V::length_bytes, E>::empty;
240};
241
242template<class V1, class V2>
243class get_expr2_same {
244 using tags = expr2_maybe_scalar_tags<V1, V2>;
245public:
246 using v1_final_type = typename type_of_tag<tags::v1_type_tag + tags::v1_size_tag,
247 tags::length_bytes, void>::type;
248 using v2_final_type = typename type_of_tag<tags::v2_type_tag + tags::v2_size_tag,
249 tags::length_bytes, void>::type;
250};
251
252template<class V1, class V2, class E = void>
253class get_expr2 {
254 static const bool is_mask_op = (V1::type_tag == SIMDPP_TAG_MASK_FLOAT || V1::type_tag == SIMDPP_TAG_MASK_INT) &&
255 (V2::type_tag == SIMDPP_TAG_MASK_FLOAT || V2::type_tag == SIMDPP_TAG_MASK_INT);
256 static const unsigned size_tag = V1::size_tag > V2::size_tag ? V1::size_tag : V2::size_tag;
257 static const unsigned type_tag = (is_mask_op && V1::size_tag != V2::size_tag) ? SIMDPP_TAG_UINT :
258 (V1::type_tag > V2::type_tag ? V1::type_tag : V2::type_tag);
259
260public:
261 using type = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::type;
262 using empty = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::empty;
263};
264
265
266
267template<class V1, class V2, class E = void>
268class get_expr2_nomask {
269 static const unsigned type_tag_t1 = V1::type_tag > V2::type_tag ? V1::type_tag : V2::type_tag;
270
271 static const unsigned size_tag = V1::size_tag > V2::size_tag ? V1::size_tag : V2::size_tag;
272 static const unsigned type_tag = (type_tag_t1 == SIMDPP_TAG_MASK_FLOAT) ? SIMDPP_TAG_FLOAT :
273 (type_tag_t1 == SIMDPP_TAG_MASK_INT) ? SIMDPP_TAG_UINT : type_tag_t1;
274
275public:
276 using type = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::type;
277 using empty = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::empty;
278};
279
280template<class V1, class V2, class E = void>
281class get_expr2_nosign {
282 static const unsigned type_tag_t1 = V1::type_tag > V2::type_tag ? V1::type_tag : V2::type_tag;
283
284public:
285 static const unsigned size_tag = V1::size_tag > V2::size_tag ? V1::size_tag : V2::size_tag;
286 static const unsigned type_tag = (type_tag_t1 == SIMDPP_TAG_INT) ? SIMDPP_TAG_UINT : type_tag_t1;
287
288 using type = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::type;
289 using empty = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::empty;
290};
291
292
293template<class V1, class V2, class E = void>
294class get_expr2_nomask_nosign {
295 static const unsigned type_tag_t1 = V1::type_tag > V2::type_tag ? V1::type_tag : V2::type_tag;
296 static const bool is_mask_op = type_tag_t1 == SIMDPP_TAG_MASK_FLOAT || type_tag_t1 == SIMDPP_TAG_MASK_INT;
297
298 static const unsigned size_tag = V1::size_tag > V2::size_tag ? V1::size_tag : V2::size_tag;
299 static const unsigned type_tag = (is_mask_op && V1::size_tag != V2::size_tag) ? SIMDPP_TAG_UINT :
300 (type_tag_t1 == SIMDPP_TAG_INT) ? SIMDPP_TAG_UINT : type_tag_t1;
301
302public:
303 using type = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::type;
304 using empty = typename type_of_tag<type_tag + size_tag, V1::length_bytes, E>::empty;
305};
306
307
308} // namespace detail
309} // namespace SIMDPP_ARCH_NAMESPACE
310} // namespace simdpp
311
312#endif
313