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