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_UINT_H
9 #define LIBSIMDPP_SIMDPP_CORE_DETAIL_GET_EXPR_UINT_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 various integer
20     operation nodes, such as add(int), mul_lo(int), etc. For particular
21     vector size each of these operations are equivalent regardless of the
22     argument types. Thus we simply convert the arguments of the expression to
23     uint expressions of certain configuration.
24 
25     As a result, the following tuples of types will appear as the arguments
26      of the returned expression:
27 
28       * uint8, uint8
29       * uint16, uint16
30       * uint32, uint32
31       * uint64, uint64
32 */
33 
34 template<class V1, class V2>
35 struct expr2_uint_maybe_scalar_tags {
36     static const unsigned v1_type_tag = V1::type_tag;
37     static const unsigned v1_size_tag = V1::size_tag;
38     static const unsigned v2_type_tag = V2::type_tag;
39     static const unsigned v2_size_tag = V2::size_tag;
40     static const unsigned length_bytes = V1::length_bytes;
41 };
42 
43 template<class V2>
44 struct expr2_uint_maybe_scalar_tags<int, V2> {
45     static const unsigned v1_type_tag = SIMDPP_TAG_INT;
46     static const unsigned v1_size_tag = V2::size_tag;
47     static const unsigned v2_type_tag = V2::type_tag;
48     static const unsigned v2_size_tag = V2::size_tag;
49     static const unsigned length_bytes = V2::length_bytes;
50 };
51 
52 template<class V2>
53 struct expr2_uint_maybe_scalar_tags<long, V2> {
54     static const unsigned v1_type_tag = SIMDPP_TAG_INT;
55     static const unsigned v1_size_tag = V2::size_tag;
56     static const unsigned v2_type_tag = V2::type_tag;
57     static const unsigned v2_size_tag = V2::size_tag;
58     static const unsigned length_bytes = V2::length_bytes;
59 };
60 
61 template<class V2>
62 struct expr2_uint_maybe_scalar_tags<long long, V2> {
63     static const unsigned v1_type_tag = SIMDPP_TAG_INT;
64     static const unsigned v1_size_tag = V2::size_tag;
65     static const unsigned v2_type_tag = V2::type_tag;
66     static const unsigned v2_size_tag = V2::size_tag;
67     static const unsigned length_bytes = V2::length_bytes;
68 };
69 
70 template<class V2>
71 struct expr2_uint_maybe_scalar_tags<unsigned, V2> {
72     static const unsigned v1_type_tag = SIMDPP_TAG_UINT;
73     static const unsigned v1_size_tag = V2::size_tag;
74     static const unsigned v2_type_tag = V2::type_tag;
75     static const unsigned v2_size_tag = V2::size_tag;
76     static const unsigned length_bytes = V2::length_bytes;
77 };
78 
79 template<class V2>
80 struct expr2_uint_maybe_scalar_tags<unsigned long, V2> {
81     static const unsigned v1_type_tag = SIMDPP_TAG_UINT;
82     static const unsigned v1_size_tag = V2::size_tag;
83     static const unsigned v2_type_tag = V2::type_tag;
84     static const unsigned v2_size_tag = V2::size_tag;
85     static const unsigned length_bytes = V2::length_bytes;
86 };
87 
88 template<class V2>
89 struct expr2_uint_maybe_scalar_tags<unsigned long long, V2> {
90     static const unsigned v1_type_tag = SIMDPP_TAG_UINT;
91     static const unsigned v1_size_tag = V2::size_tag;
92     static const unsigned v2_type_tag = V2::type_tag;
93     static const unsigned v2_size_tag = V2::size_tag;
94     static const unsigned length_bytes = V2::length_bytes;
95 };
96 
97 template<class V2>
98 struct expr2_uint_maybe_scalar_tags<float, V2> {
99     static const unsigned v1_type_tag = SIMDPP_TAG_INT;
100     static const unsigned v1_size_tag = V2::size_tag;
101     static const unsigned v2_type_tag = V2::type_tag;
102     static const unsigned v2_size_tag = V2::size_tag;
103     static const unsigned length_bytes = V2::length_bytes;
104 };
105 
106 template<class V2>
107 struct expr2_uint_maybe_scalar_tags<double, V2> {
108     static const unsigned v1_type_tag = SIMDPP_TAG_INT;
109     static const unsigned v1_size_tag = V2::size_tag;
110     static const unsigned v2_type_tag = V2::type_tag;
111     static const unsigned v2_size_tag = V2::size_tag;
112     static const unsigned length_bytes = V2::length_bytes;
113 };
114 
115 
116 template<class V1>
117 struct expr2_uint_maybe_scalar_tags<V1, int> {
118     static const unsigned v1_type_tag = V1::type_tag;
119     static const unsigned v1_size_tag = V1::size_tag;
120     static const unsigned v2_type_tag = SIMDPP_TAG_INT;
121     static const unsigned v2_size_tag = V1::size_tag;
122     static const unsigned length_bytes = V1::length_bytes;
123 };
124 
125 template<class V1>
126 struct expr2_uint_maybe_scalar_tags<V1, long> {
127     static const unsigned v1_type_tag = V1::type_tag;
128     static const unsigned v1_size_tag = V1::size_tag;
129     static const unsigned v2_type_tag = SIMDPP_TAG_INT;
130     static const unsigned v2_size_tag = V1::size_tag;
131     static const unsigned length_bytes = V1::length_bytes;
132 };
133 
134 template<class V1>
135 struct expr2_uint_maybe_scalar_tags<V1, long long> {
136     static const unsigned v1_type_tag = V1::type_tag;
137     static const unsigned v1_size_tag = V1::size_tag;
138     static const unsigned v2_type_tag = SIMDPP_TAG_INT;
139     static const unsigned v2_size_tag = V1::size_tag;
140     static const unsigned length_bytes = V1::length_bytes;
141 };
142 
143 template<class V1>
144 struct expr2_uint_maybe_scalar_tags<V1, unsigned> {
145     static const unsigned v1_type_tag = V1::type_tag;
146     static const unsigned v1_size_tag = V1::size_tag;
147     static const unsigned v2_type_tag = SIMDPP_TAG_UINT;
148     static const unsigned v2_size_tag = V1::size_tag;
149     static const unsigned length_bytes = V1::length_bytes;
150 };
151 
152 template<class V1>
153 struct expr2_uint_maybe_scalar_tags<V1, unsigned long> {
154     static const unsigned v1_type_tag = V1::type_tag;
155     static const unsigned v1_size_tag = V1::size_tag;
156     static const unsigned v2_type_tag = SIMDPP_TAG_UINT;
157     static const unsigned v2_size_tag = V1::size_tag;
158     static const unsigned length_bytes = V1::length_bytes;
159 };
160 
161 template<class V1>
162 struct expr2_uint_maybe_scalar_tags<V1, unsigned long long> {
163     static const unsigned v1_type_tag = V1::type_tag;
164     static const unsigned v1_size_tag = V1::size_tag;
165     static const unsigned v2_type_tag = SIMDPP_TAG_UINT;
166     static const unsigned v2_size_tag = V1::size_tag;
167     static const unsigned length_bytes = V1::length_bytes;
168 };
169 
170 template<class V1>
171 struct expr2_uint_maybe_scalar_tags<V1, float> {
172     static const unsigned v1_type_tag = V1::type_tag;
173     static const unsigned v1_size_tag = V1::size_tag;
174     static const unsigned v2_type_tag = SIMDPP_TAG_INT;
175     static const unsigned v2_size_tag = V1::size_tag;
176     static const unsigned length_bytes = V1::length_bytes;
177 };
178 
179 template<class V1>
180 struct expr2_uint_maybe_scalar_tags<V1, double> {
181     static const unsigned v1_type_tag = V1::type_tag;
182     static const unsigned v1_size_tag = V1::size_tag;
183     static const unsigned v2_type_tag = SIMDPP_TAG_INT;
184     static const unsigned v2_size_tag = V1::size_tag;
185     static const unsigned length_bytes = V1::length_bytes;
186 };
187 
188 template<class V1, class V2>
189 struct get_expr_uint_impl {
190     using tags = expr2_uint_maybe_scalar_tags<V1, V2>;
191 
192 #if SIMDPP_EXPR_DEBUG
193     static_assert(tags::v1_size_tag == tags::v2_size_tag, "Mismatching vector sizes");
194     static_assert(tags::v1_type_tag == SIMDPP_TAG_MASK_INT ||
195                   tags::v1_type_tag == SIMDPP_TAG_UINT ||
196                   tags::v1_type_tag == SIMDPP_TAG_INT, "Incorrect type parameter");
197     static_assert(tags::v2_type_tag == SIMDPP_TAG_MASK_INT ||
198                   tags::v2_type_tag == SIMDPP_TAG_UINT ||
199                   tags::v2_type_tag == SIMDPP_TAG_INT, "Incorrect type parameter");
200 #endif
201 
202     // the size tag of the expression
203     static const unsigned size_tag = tags::v1_size_tag;
204 
205     // (type_tag) get the type tag of the expression. Pretty much the same as
206     // get_expr2_nomask does
207     static const unsigned type_tag_t1 = tags::v1_type_tag > tags::v2_type_tag ? tags::v1_type_tag : tags::v2_type_tag;
208     static const unsigned type_tag = (type_tag_t1 == SIMDPP_TAG_MASK_INT) ? SIMDPP_TAG_UINT : type_tag_t1;
209 
210     // strip signed integer types and masks
211     static const unsigned v1_type_tag = SIMDPP_TAG_UINT;
212     static const unsigned v2_type_tag = SIMDPP_TAG_UINT;
213 
214     using v1_final_type = typename type_of_tag<v1_type_tag + size_tag,
215                                                tags::length_bytes, void>::type;
216     using v2_final_type = typename type_of_tag<v2_type_tag + size_tag,
217                                                tags::length_bytes, void>::type;
218 };
219 
220 template<template<class, class> class E, class V1, class V2>
221 struct get_expr_uint {
222     using impl = get_expr_uint_impl<V1, V2>;
223 
224     using type = typename type_of_tag<impl::type_tag + impl::size_tag,
225                                       impl::tags::length_bytes,
226                                       E<V1, V2>>::type;
227 };
228 
229 } // namespace detail
230 } // namespace SIMDPP_ARCH_NAMESPACE
231 } // namespace simdpp
232 
233 #endif
234