Vc  1.3.2-dev
SIMD Vector Classes for C++
operators.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2012-2016 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright
7  notice, this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright
9  notice, this list of conditions and the following disclaimer in the
10  documentation and/or other materials provided with the distribution.
11  * Neither the names of contributing organizations nor the
12  names of its contributors may be used to endorse or promote products
13  derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef COMMON_OPERATORS_H_
29 #define COMMON_OPERATORS_H_
30 #include "macros.h"
31 
32 namespace Vc_VERSIONED_NAMESPACE
33 {
34 namespace Detail
35 {
36 template <typename T, typename Abi, typename U>
37 enable_if<!std::is_same<T, U>::value, U> is_convertible_to_any_vector(Vector<U, Abi>);
38 template <typename T, typename Abi> T is_convertible_to_any_vector(Vector<T, Abi>);
39 template <typename T, typename Abi> void is_convertible_to_any_vector(...);
40 
41 template <typename T, typename U, bool = std::is_integral<T>::value,
42  bool = std::is_integral<U>::value>
43 struct FundamentalReturnType;
44 template <typename T, typename U> struct FundamentalReturnType<T, U, false, false> {
45  using type = typename std::conditional<
46  std::is_arithmetic<U>::value,
47  typename std::conditional<(sizeof(T) < sizeof(U)), U, T>::type,
48  // U is not arithmetic, e.g. an enum or a type with e.g. operator int()
49  T>::type;
50 };
51 template <typename T, typename U> struct FundamentalReturnType<T, U, true, false> {
52  using type = typename std::conditional<
53  std::is_arithmetic<U>::value, U,
54  // U is not arithmetic, e.g. an enum or a type with e.g. operator int()
55  T>::type;
56 };
57 template <typename T, typename U> struct FundamentalReturnType<T, U, false, true> {
58  using type = T;
59 };
60 
61 template <typename T> struct my_make_signed : public std::make_signed<T> {
62 };
63 template <> struct my_make_signed<bool> {
64  using type = bool;
65 };
66 
67 template <typename TT, typename UU>
68 struct higher_conversion_rank {
69  template <typename A>
70  using fix_sign =
71  typename std::conditional<(std::is_unsigned<TT>::value ||
72  std::is_unsigned<UU>::value),
73  typename std::make_unsigned<A>::type, A>::type;
74  using T = typename my_make_signed<TT>::type;
75  using U = typename my_make_signed<UU>::type;
76  template <typename Test, typename Otherwise>
77  using c = typename std::conditional<std::is_same<T, Test>::value ||
78  std::is_same<U, Test>::value,
79  Test, Otherwise>::type;
80 
81  using type = fix_sign<c<long long, c<long, c<int, c<short, c<signed char, void>>>>>>;
82 };
83 
84 template <typename T, typename U> struct FundamentalReturnType<T, U, true, true> {
85  template <bool B, class Then, class E>
86  using c = typename std::conditional<B, Then, E>::type;
87  using type =
88  c<(sizeof(T) > sizeof(U)), T,
89  c<(sizeof(T) < sizeof(U)), U, typename higher_conversion_rank<T, U>::type>>;
90 };
91 static_assert(std::is_same<long, typename FundamentalReturnType<int, long>::type>::value, "");
92 
93 template <typename V, typename T, bool, typename, bool> struct ReturnTypeImpl {
94  // no type => SFINAE
95 };
96 template <typename T, typename U, typename Abi, typename Deduced>
97 struct ReturnTypeImpl<Vector<T, Abi>, Vector<U, Abi>, false, Deduced, false> {
99 };
100 template <typename T, typename Abi>
101 struct ReturnTypeImpl<Vector<T, Abi>, int, true, T, true> {
102  using type = Vc::Vector<T, Abi>;
103 };
104 template <typename T, typename Abi>
105 struct ReturnTypeImpl<Vector<T, Abi>, unsigned int, true, T, true> {
107 };
108 template <typename T, typename U, typename Abi, bool Integral>
109 struct ReturnTypeImpl<Vector<T, Abi>, U, true, T, Integral> {
111 };
112 template <typename T, typename U, typename Abi, bool Integral>
113 struct ReturnTypeImpl<Vector<T, Abi>, U, false, void, Integral> {
114  // no type => SFINAE
115 };
116 template <typename T, typename U, typename Abi, typename V, bool Integral>
117 struct ReturnTypeImpl<Vector<T, Abi>, U, false, V, Integral> {
119 };
120 template <typename V, typename T>
121 using ReturnType = ReturnTypeImpl<
122  V, T, std::is_arithmetic<T>::value || std::is_convertible<T, int>::value,
123  decltype(is_convertible_to_any_vector<typename V::value_type, typename V::abi>(
124  std::declval<const T &>())),
125  std::is_integral<typename V::value_type>::value>;
126 
127 template <typename T> struct is_a_type : public std::true_type {
128 };
129 
130 #ifdef Vc_ENABLE_FLOAT_BIT_OPERATORS
131 #define Vc_TEST_FOR_BUILTIN_OPERATOR(op_) true
132 #else
133 #define Vc_TEST_FOR_BUILTIN_OPERATOR(op_) \
134  Detail::is_a_type<decltype( \
135  std::declval<typename Detail::ReturnType<Vector<T, Abi>, U>::type::EntryType>() \
136  op_ std::declval<typename Detail::ReturnType<Vector<T, Abi>, \
137  U>::type::EntryType>())>::value
138 #endif
139 } // namespace Detail
140 
141 #define Vc_GENERIC_OPERATOR(op_) \
142  template <typename T, typename Abi, typename U> \
143  Vc_ALWAYS_INLINE enable_if< \
144  Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
145  std::is_convertible<Vector<T, Abi>, typename Detail::ReturnType< \
146  Vector<T, Abi>, U>::type>::value && \
147  std::is_convertible< \
148  U, typename Detail::ReturnType<Vector<T, Abi>, U>::type>::value, \
149  typename Detail::ReturnType<Vector<T, Abi>, U>::type> \
150  operator op_(Vector<T, Abi> x, const U &y) \
151  { \
152  using V = typename Detail::ReturnType<Vector<T, Abi>, U>::type; \
153  return Detail::operator op_(V(x), V(y)); \
154  } \
155  template <typename T, typename Abi, typename U> \
156  Vc_ALWAYS_INLINE enable_if< \
157  Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
158  !Traits::is_simd_vector_internal<U>::value && \
159  std::is_convertible<Vector<T, Abi>, typename Detail::ReturnType< \
160  Vector<T, Abi>, U>::type>::value && \
161  std::is_convertible< \
162  U, typename Detail::ReturnType<Vector<T, Abi>, U>::type>::value, \
163  typename Detail::ReturnType<Vector<T, Abi>, U>::type> \
164  operator op_(const U &x, Vector<T, Abi> y) \
165  { \
166  using V = typename Detail::ReturnType<Vector<T, Abi>, U>::type; \
167  return Detail::operator op_(V(x), V(y)); \
168  } \
169  template <typename T, typename Abi, typename U> \
170  Vc_ALWAYS_INLINE enable_if< \
171  Vc_TEST_FOR_BUILTIN_OPERATOR(op_) && \
172  std::is_convertible<Vector<T, Abi>, typename Detail::ReturnType< \
173  Vector<T, Abi>, U>::type>::value && \
174  std::is_convertible< \
175  U, typename Detail::ReturnType<Vector<T, Abi>, U>::type>::value, \
176  Vector<T, Abi> &> \
177  operator op_##=(Vector<T, Abi> &x, const U &y) \
178  { \
179  using V = typename Detail::ReturnType<Vector<T, Abi>, U>::type; \
180  x = Detail::operator op_(V(x), V(y)); \
181  return x; \
182  }
183 
184 #define Vc_LOGICAL_OPERATOR(op_) \
185  template <typename T, typename Abi> \
186  Vc_ALWAYS_INLINE typename Vector<T, Abi>::Mask operator op_(Vector<T, Abi> x, \
187  Vector<T, Abi> y) \
188  { \
189  return !!x op_ !!y; \
190  } \
191  template <typename T, typename Abi, typename U> \
192  Vc_ALWAYS_INLINE enable_if< \
193  std::is_convertible<Vector<T, Abi>, Vector<U, Abi>>::value && \
194  std::is_convertible<Vector<U, Abi>, Vector<T, Abi>>::value, \
195  typename Detail::ReturnType<Vector<T, Abi>, Vector<U, Abi>>::type::Mask> \
196  operator op_(Vector<T, Abi> x, Vector<U, Abi> y) \
197  { \
198  return !!x op_ !!y; \
199  } \
200  template <typename T, typename Abi, typename U> \
201  Vc_ALWAYS_INLINE \
202  enable_if<std::is_same<bool, decltype(!std::declval<const U &>())>::value, \
203  typename Vector<T, Abi>::Mask> \
204  operator op_(Vector<T, Abi> x, const U &y) \
205  { \
206  using M = typename Vector<T, Abi>::Mask; \
207  return !!x op_ M(!!y); \
208  } \
209  template <typename T, typename Abi, typename U> \
210  Vc_ALWAYS_INLINE \
211  enable_if<std::is_same<bool, decltype(!std::declval<const U &>())>::value, \
212  typename Vector<T, Abi>::Mask> \
213  operator op_(const U &x, Vector<T, Abi> y) \
214  { \
215  using M = typename Vector<T, Abi>::Mask; \
216  return M(!!x) op_ !!y; \
217  }
218 
219 #define Vc_COMPARE_OPERATOR(op_) \
220  template <typename T, typename Abi, typename U> \
221  Vc_ALWAYS_INLINE enable_if< \
222  std::is_convertible<Vector<T, Abi>, typename Detail::ReturnType< \
223  Vector<T, Abi>, U>::type>::value && \
224  std::is_convertible< \
225  U, typename Detail::ReturnType<Vector<T, Abi>, U>::type>::value, \
226  typename Detail::ReturnType<Vector<T, Abi>, U>::type::Mask> \
227  operator op_(Vector<T, Abi> x, const U &y) \
228  { \
229  using V = typename Detail::ReturnType<Vector<T, Abi>, U>::type; \
230  return Detail::operator op_(V(x), V(y)); \
231  } \
232  template <typename T, typename Abi, typename U> \
233  Vc_ALWAYS_INLINE enable_if< \
234  !Traits::is_simd_vector_internal<U>::value && \
235  std::is_convertible<Vector<T, Abi>, typename Detail::ReturnType< \
236  Vector<T, Abi>, U>::type>::value && \
237  std::is_convertible< \
238  U, typename Detail::ReturnType<Vector<T, Abi>, U>::type>::value, \
239  typename Detail::ReturnType<Vector<T, Abi>, U>::type::Mask> \
240  operator op_(const U &x, Vector<T, Abi> y) \
241  { \
242  using V = typename Detail::ReturnType<Vector<T, Abi>, U>::type; \
243  return Detail::operator op_(V(x), V(y)); \
244  }
245 
246 Vc_ALL_LOGICAL (Vc_LOGICAL_OPERATOR);
247 Vc_ALL_BINARY (Vc_GENERIC_OPERATOR);
248 Vc_ALL_ARITHMETICS(Vc_GENERIC_OPERATOR);
249 Vc_ALL_COMPARES (Vc_COMPARE_OPERATOR);
250 
251 #undef Vc_LOGICAL_OPERATOR
252 #undef Vc_GENERIC_OPERATOR
253 #undef Vc_COMPARE_OPERATOR
254 #undef Vc_INVALID_OPERATOR
255 
256 } // namespace Vc
257 #endif // COMMON_OPERATORS_H_
The main vector class for expressing data parallelism.
Definition: types.h:44