File indexing completed on 2025-01-31 10:25:45
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #ifndef VC_SSE_VECTOR_H_
0029 #define VC_SSE_VECTOR_H_
0030
0031 #include "../scalar/vector.h"
0032 #include "intrinsics.h"
0033 #include "types.h"
0034 #include "vectorhelper.h"
0035 #include "mask.h"
0036 #include "../common/writemaskedvector.h"
0037 #include "../common/aliasingentryhelper.h"
0038 #include "../common/memoryfwd.h"
0039 #include "../common/loadstoreflags.h"
0040 #include <algorithm>
0041 #include <cmath>
0042 #include "detail.h"
0043
0044 #include "macros.h"
0045
0046 #ifdef isfinite
0047 #undef isfinite
0048 #endif
0049 #ifdef isnan
0050 #undef isnan
0051 #endif
0052
0053 namespace Vc_VERSIONED_NAMESPACE
0054 {
0055
0056 #define Vc_CURRENT_CLASS_NAME Vector
0057 template <typename T> class Vector<T, VectorAbi::Sse>
0058 {
0059 static_assert(std::is_arithmetic<T>::value,
0060 "Vector<T> only accepts arithmetic builtin types as template parameter T.");
0061
0062 protected:
0063 #ifdef Vc_COMPILE_BENCHMARKS
0064 public:
0065 #endif
0066 typedef typename SSE::VectorTraits<T>::StorageType StorageType;
0067 StorageType d;
0068 typedef typename SSE::VectorTraits<T>::GatherMaskType GatherMask;
0069 typedef SSE::VectorHelper<typename SSE::VectorTraits<T>::VectorType> HV;
0070 typedef SSE::VectorHelper<T> HT;
0071 public:
0072 Vc_FREE_STORE_OPERATORS_ALIGNED(16);
0073
0074 typedef typename SSE::VectorTraits<T>::VectorType VectorType;
0075 using vector_type = VectorType;
0076 static constexpr size_t Size = SSE::VectorTraits<T>::Size;
0077 static constexpr size_t MemoryAlignment = alignof(VectorType);
0078 typedef typename SSE::VectorTraits<T>::EntryType EntryType;
0079 using value_type = EntryType;
0080 using VectorEntryType = EntryType;
0081 using IndexType = fixed_size_simd<int, Size>;
0082 using index_type = IndexType;
0083 typedef typename SSE::VectorTraits<T>::MaskType Mask;
0084 using MaskType = Mask;
0085 using mask_type = Mask;
0086 typedef typename Mask::Argument MaskArg;
0087 typedef typename Mask::Argument MaskArgument;
0088 typedef const Vector AsArg;
0089 using abi = VectorAbi::Sse;
0090 using WriteMaskedVector = Common::WriteMaskedVector<Vector, Mask>;
0091 template <typename U> using V = Vector<U, abi>;
0092
0093 using reference = Detail::ElementReference<Vector>;
0094
0095 #include "../common/generalinterface.h"
0096
0097 static Vc_INTRINSIC_L Vector Random() Vc_INTRINSIC_R;
0098
0099
0100
0101 Vc_ALWAYS_INLINE Vector(VectorType x) : d(x) {}
0102
0103
0104 template <typename U>
0105 Vc_INTRINSIC Vector(
0106 V<U> x, typename std::enable_if<Traits::is_implicit_cast_allowed<U, T>::value,
0107 void *>::type = nullptr)
0108 : d(SSE::convert<U, T>(x.data()))
0109 {
0110 }
0111
0112 #if Vc_IS_VERSION_1
0113
0114 template <typename U>
0115 Vc_DEPRECATED("use simd_cast instead of explicit type casting to convert between "
0116 "vector types") Vc_INTRINSIC
0117 explicit Vector(
0118 V<U> x,
0119 typename std::enable_if<!Traits::is_implicit_cast_allowed<U, T>::value,
0120 void *>::type = nullptr)
0121 : d(SSE::convert<U, T>(x.data()))
0122 {
0123 }
0124 #endif
0125
0126
0127
0128 Vc_INTRINSIC Vector(EntryType a) : d(HT::set(a)) {}
0129 template <typename U>
0130 Vc_INTRINSIC Vector(U a,
0131 typename std::enable_if<std::is_same<U, int>::value &&
0132 !std::is_same<U, EntryType>::value,
0133 void *>::type = nullptr)
0134 : Vector(static_cast<EntryType>(a))
0135 {
0136 }
0137
0138 Vc_INTRINSIC explicit Vector(reference a) : Vector(static_cast<EntryType>(a)) {}
0139
0140 #include "../common/loadinterface.h"
0141 #include "../common/storeinterface.h"
0142
0143
0144
0145 Vc_INTRINSIC_L void setZero() Vc_INTRINSIC_R;
0146 Vc_INTRINSIC_L void setZero(const Mask &k) Vc_INTRINSIC_R;
0147 Vc_INTRINSIC_L void setZeroInverted(const Mask &k) Vc_INTRINSIC_R;
0148
0149 Vc_INTRINSIC_L void setQnan() Vc_INTRINSIC_R;
0150 Vc_INTRINSIC_L void setQnan(const Mask &k) Vc_INTRINSIC_R;
0151
0152 #include "../common/gatherinterface.h"
0153 #include "../common/scatterinterface.h"
0154 #if defined Vc_IMPL_AVX2 && !defined Vc_MSVC
0155
0156
0157
0158
0159 template <class U, class A, int Scale, int N = Vector<U, A>::size(),
0160 class = enable_if<(Vector<U, A>::size() >= size() && sizeof(T) >= 4)>>
0161 Vc_INTRINSIC void gatherImplementation(
0162 const Common::GatherArguments<T, Vector<U, A>, Scale> &args)
0163 {
0164 d.v() = SSE::gather<sizeof(T) * Scale>(
0165 args.address, simd_cast<SSE::int_v>(args.indexes).data());
0166 }
0167
0168
0169 template <class U, class A, int Scale, int N = Vector<U, A>::size(),
0170 class = enable_if<(Vector<U, A>::size() >= size() && sizeof(T) >= 4)>>
0171 Vc_INTRINSIC void gatherImplementation(
0172 const Common::GatherArguments<T, Vector<U, A>, Scale> &args, MaskArgument k)
0173 {
0174 d.v() = SSE::gather<sizeof(T) * Scale>(
0175 d.v(), k.data(), args.address,
0176 simd_cast<SSE::int_v>(args.indexes).data());
0177 }
0178
0179
0180
0181
0182 template <
0183 class MT, class U, class A, int Scale,
0184 class = enable_if<(sizeof(T) == 2 && std::is_integral<MT>::value &&
0185 (sizeof(MT) <= 2) && Vector<U, A>::size() >= size())>>
0186 Vc_INTRINSIC void gatherImplementation(
0187 const Common::GatherArguments<MT, Vector<U, A>, Scale> &args)
0188 {
0189 using AVX2::int_v;
0190 const auto idx = simd_cast<int_v>(args.indexes).data();
0191 *this = simd_cast<Vector>(int_v(
0192 AVX::gather<sizeof(MT) * Scale>(aliasing_cast<int>(args.address), idx)));
0193 if (sizeof(MT) == 1) {
0194 if (std::is_signed<MT>::value) {
0195 d.v() = _mm_srai_epi16(_mm_slli_epi16(d.v(), 8), 8);
0196 } else {
0197 *this &= 0xff;
0198 }
0199 }
0200 }
0201
0202
0203 template <
0204 class MT, class U, class A, int Scale,
0205 class = enable_if<(sizeof(T) == 2 && std::is_integral<MT>::value &&
0206 (sizeof(MT) <= 2) && Vector<U, A>::size() >= size())>>
0207 Vc_INTRINSIC void gatherImplementation(
0208 const Common::GatherArguments<MT, Vector<U, A>, Scale> &args, MaskArgument k)
0209 {
0210 using AVX2::int_v;
0211 auto v = simd_cast<Vector>(int_v(AVX::gather<sizeof(MT) * Scale>(
0212 _mm256_setzero_si256(), simd_cast<AVX2::int_m>(k).data(),
0213 aliasing_cast<int>(args.address),
0214 simd_cast<int_v>(args.indexes).data())));
0215 if (sizeof(MT) == 1) {
0216 if (std::is_signed<MT>::value) {
0217 v.data() = _mm_srai_epi16(_mm_slli_epi16(v.data(), 8), 8);
0218 } else {
0219 v &= 0xff;
0220 }
0221 }
0222 assign(v, k);
0223 }
0224
0225
0226
0227 template <class MT, class U, class A, int Scale>
0228 Vc_INTRINSIC enable_if<((sizeof(T) != 2 || sizeof(MT) > 2) &&
0229 Traits::is_valid_vector_argument<MT>::value &&
0230 !std::is_same<MT, T>::value &&
0231 Vector<U, A>::size() >= size()),
0232 void>
0233 gatherImplementation(const Common::GatherArguments<MT, Vector<U, A>, Scale> &args)
0234 {
0235 *this = simd_cast<Vector>(fixed_size_simd<MT, Size>(args));
0236 }
0237
0238
0239 template <class MT, class U, class A, int Scale>
0240 Vc_INTRINSIC enable_if<((sizeof(T) != 2 || sizeof(MT) > 2) &&
0241 Traits::is_valid_vector_argument<MT>::value &&
0242 !std::is_same<MT, T>::value &&
0243 Vector<U, A>::size() >= size()),
0244 void>
0245 gatherImplementation(const Common::GatherArguments<MT, Vector<U, A>, Scale> &args,
0246 MaskArgument k)
0247 {
0248 assign(simd_cast<Vector>(fixed_size_simd<MT, Size>(args, k)), k);
0249 }
0250 #endif
0251
0252
0253 Vc_INTRINSIC Vector &operator++() { data() = HT::add(data(), HT::one()); return *this; }
0254 Vc_INTRINSIC Vector &operator--() { data() = HT::sub(data(), HT::one()); return *this; }
0255
0256 Vc_INTRINSIC Vector operator++(int) { const Vector r = *this; data() = HT::add(data(), HT::one()); return r; }
0257 Vc_INTRINSIC Vector operator--(int) { const Vector r = *this; data() = HT::sub(data(), HT::one()); return r; }
0258
0259 private:
0260 friend reference;
0261 Vc_INTRINSIC static value_type get(const Vector &o, int i) noexcept
0262 {
0263 return o.d.m(i);
0264 }
0265 template <typename U>
0266 Vc_INTRINSIC static void set(Vector &o, int i, U &&v) noexcept(
0267 noexcept(std::declval<value_type &>() = v))
0268 {
0269 o.d.set(i, v);
0270 }
0271
0272 public:
0273
0274
0275
0276
0277
0278
0279 Vc_ALWAYS_INLINE reference operator[](size_t index) noexcept
0280 {
0281 static_assert(noexcept(reference{std::declval<Vector &>(), int()}), "");
0282 return {*this, int(index)};
0283 }
0284 Vc_ALWAYS_INLINE value_type operator[](size_t index) const noexcept
0285 {
0286 return d.m(index);
0287 }
0288
0289 Vc_INTRINSIC_L Vector Vc_VDECL operator[](const SSE::int_v &perm) const Vc_INTRINSIC_R;
0290
0291 Vc_INTRINSIC Vc_PURE Mask operator!() const
0292 {
0293 return *this == Zero();
0294 }
0295 Vc_INTRINSIC Vc_PURE Vector operator~() const
0296 {
0297 #ifndef Vc_ENABLE_FLOAT_BIT_OPERATORS
0298 static_assert(std::is_integral<T>::value,
0299 "bit-complement can only be used with Vectors of integral type");
0300 #endif
0301 return Detail::andnot_(data(), HV::allone());
0302 }
0303 Vc_ALWAYS_INLINE_L Vc_PURE_L Vector operator-() const Vc_ALWAYS_INLINE_R Vc_PURE_R;
0304 Vc_INTRINSIC Vc_PURE Vector operator+() const { return *this; }
0305
0306 Vc_ALWAYS_INLINE Vector Vc_VDECL operator<< (AsArg shift) const { return generate([&](int i) { return get(*this, i) << get(shift, i); }); }
0307 Vc_ALWAYS_INLINE Vector Vc_VDECL operator>> (AsArg shift) const { return generate([&](int i) { return get(*this, i) >> get(shift, i); }); }
0308 Vc_ALWAYS_INLINE Vector &Vc_VDECL operator<<=(AsArg shift) { return *this = *this << shift; }
0309 Vc_ALWAYS_INLINE Vector &Vc_VDECL operator>>=(AsArg shift) { return *this = *this >> shift; }
0310
0311 Vc_INTRINSIC_L Vector &Vc_VDECL operator<<=( int shift) Vc_INTRINSIC_R;
0312 Vc_INTRINSIC_L Vector Vc_VDECL operator<< ( int shift) const Vc_INTRINSIC_R;
0313 Vc_INTRINSIC_L Vector &Vc_VDECL operator>>=( int shift) Vc_INTRINSIC_R;
0314 Vc_INTRINSIC_L Vector Vc_VDECL operator>> ( int shift) const Vc_INTRINSIC_R;
0315
0316 Vc_DEPRECATED("use isnegative(x) instead") Vc_INTRINSIC Vc_PURE Mask
0317 isNegative() const
0318 {
0319 return Vc::isnegative(*this);
0320 }
0321
0322 Vc_ALWAYS_INLINE void assign(const Vector &v, const Mask &mask)
0323 {
0324 data() = HV::blend(data(), v.data(), mask.data());
0325 }
0326
0327 template <typename V2>
0328 Vc_DEPRECATED("Use simd_cast instead of Vector::staticCast")
0329 Vc_ALWAYS_INLINE Vc_PURE V2 staticCast() const
0330 {
0331 return SSE::convert<T, typename V2::EntryType>(data());
0332 }
0333 template <typename V2>
0334 Vc_DEPRECATED("use reinterpret_components_cast instead")
0335 Vc_ALWAYS_INLINE Vc_PURE V2 reinterpretCast() const
0336 {
0337 return SSE::sse_cast<typename V2::VectorType>(data());
0338 }
0339
0340 Vc_INTRINSIC WriteMaskedVector operator()(const Mask &k) { return {*this, k}; }
0341
0342 Vc_ALWAYS_INLINE Vc_PURE VectorType &data() { return d.v(); }
0343 Vc_ALWAYS_INLINE Vc_PURE const VectorType &data() const { return d.v(); }
0344
0345 template<int Index>
0346 Vc_INTRINSIC_L Vector broadcast() const Vc_INTRINSIC_R;
0347
0348 Vc_INTRINSIC EntryType min() const { return HT::min(data()); }
0349 Vc_INTRINSIC EntryType max() const { return HT::max(data()); }
0350 Vc_INTRINSIC EntryType product() const { return HT::mul(data()); }
0351 Vc_INTRINSIC EntryType sum() const { return HT::add(data()); }
0352 Vc_INTRINSIC_L Vector partialSum() const Vc_INTRINSIC_R;
0353 Vc_INTRINSIC_L EntryType min(MaskArg m) const Vc_INTRINSIC_R;
0354 Vc_INTRINSIC_L EntryType max(MaskArg m) const Vc_INTRINSIC_R;
0355 Vc_INTRINSIC_L EntryType product(MaskArg m) const Vc_INTRINSIC_R;
0356 Vc_INTRINSIC_L EntryType sum(MaskArg m) const Vc_INTRINSIC_R;
0357
0358 Vc_INTRINSIC_L Vector shifted(int amount, Vector shiftIn) const Vc_INTRINSIC_R;
0359 Vc_INTRINSIC_L Vector shifted(int amount) const Vc_INTRINSIC_R;
0360 Vc_INTRINSIC_L Vector rotated(int amount) const Vc_INTRINSIC_R;
0361 Vc_INTRINSIC_L Vc_PURE_L Vector reversed() const Vc_INTRINSIC_R Vc_PURE_R;
0362 Vc_ALWAYS_INLINE_L Vc_PURE_L Vector sorted() const Vc_ALWAYS_INLINE_R Vc_PURE_R;
0363
0364 template <typename F> void callWithValuesSorted(F &&f)
0365 {
0366 EntryType value = d.m(0);
0367 f(value);
0368 for (std::size_t i = 1; i < Size; ++i) {
0369 if (d.m(i) != value) {
0370 value = d.m(i);
0371 f(value);
0372 }
0373 }
0374 }
0375
0376 template <typename F> Vc_INTRINSIC void call(F &&f) const
0377 {
0378 Common::for_all_vector_entries<Size>([&](size_t i) { f(EntryType(d.m(i))); });
0379 }
0380
0381 template <typename F> Vc_INTRINSIC void call(F &&f, const Mask &mask) const
0382 {
0383 for(size_t i : where(mask)) {
0384 f(EntryType(d.m(i)));
0385 }
0386 }
0387
0388 template <typename F> Vc_INTRINSIC Vector apply(F &&f) const
0389 {
0390 Vector r;
0391 Common::for_all_vector_entries<Size>(
0392 [&](size_t i) { r.d.set(i, f(EntryType(d.m(i)))); });
0393 return r;
0394 }
0395 template <typename F> Vc_INTRINSIC Vector apply(F &&f, const Mask &mask) const
0396 {
0397 Vector r(*this);
0398 for (size_t i : where(mask)) {
0399 r.d.set(i, f(EntryType(r.d.m(i))));
0400 }
0401 return r;
0402 }
0403
0404 template<typename IndexT> Vc_INTRINSIC void fill(EntryType (&f)(IndexT)) {
0405 Common::for_all_vector_entries<Size>([&](size_t i) { d.set(i, f(i)); });
0406 }
0407 Vc_INTRINSIC void fill(EntryType (&f)()) {
0408 Common::for_all_vector_entries<Size>([&](size_t i) { d.set(i, f()); });
0409 }
0410
0411 template <typename G> static Vc_INTRINSIC_L Vector generate(G gen) Vc_INTRINSIC_R;
0412
0413 Vc_DEPRECATED("use copysign(x, y) instead") Vc_INTRINSIC Vector
0414 copySign(AsArg x) const
0415 {
0416 return Vc::copysign(*this, x);
0417 }
0418
0419 Vc_DEPRECATED("use exponent(x) instead") Vc_INTRINSIC Vector exponent() const
0420 {
0421 return Vc::exponent(*this);
0422 }
0423
0424 Vc_INTRINSIC_L Vector interleaveLow(Vector x) const Vc_INTRINSIC_R;
0425 Vc_INTRINSIC_L Vector interleaveHigh(Vector x) const Vc_INTRINSIC_R;
0426 };
0427 #undef Vc_CURRENT_CLASS_NAME
0428 template <typename T> constexpr size_t Vector<T, VectorAbi::Sse>::Size;
0429 template <typename T> constexpr size_t Vector<T, VectorAbi::Sse>::MemoryAlignment;
0430
0431 static Vc_ALWAYS_INLINE Vc_PURE SSE::int_v min(const SSE::int_v &x, const SSE::int_v &y) { return SSE::min_epi32(x.data(), y.data()); }
0432 static Vc_ALWAYS_INLINE Vc_PURE SSE::uint_v min(const SSE::uint_v &x, const SSE::uint_v &y) { return SSE::min_epu32(x.data(), y.data()); }
0433 static Vc_ALWAYS_INLINE Vc_PURE SSE::short_v min(const SSE::short_v &x, const SSE::short_v &y) { return _mm_min_epi16(x.data(), y.data()); }
0434 static Vc_ALWAYS_INLINE Vc_PURE SSE::ushort_v min(const SSE::ushort_v &x, const SSE::ushort_v &y) { return SSE::min_epu16(x.data(), y.data()); }
0435 static Vc_ALWAYS_INLINE Vc_PURE SSE::float_v min(const SSE::float_v &x, const SSE::float_v &y) { return _mm_min_ps(x.data(), y.data()); }
0436 static Vc_ALWAYS_INLINE Vc_PURE SSE::double_v min(const SSE::double_v &x, const SSE::double_v &y) { return _mm_min_pd(x.data(), y.data()); }
0437 static Vc_ALWAYS_INLINE Vc_PURE SSE::int_v max(const SSE::int_v &x, const SSE::int_v &y) { return SSE::max_epi32(x.data(), y.data()); }
0438 static Vc_ALWAYS_INLINE Vc_PURE SSE::uint_v max(const SSE::uint_v &x, const SSE::uint_v &y) { return SSE::max_epu32(x.data(), y.data()); }
0439 static Vc_ALWAYS_INLINE Vc_PURE SSE::short_v max(const SSE::short_v &x, const SSE::short_v &y) { return _mm_max_epi16(x.data(), y.data()); }
0440 static Vc_ALWAYS_INLINE Vc_PURE SSE::ushort_v max(const SSE::ushort_v &x, const SSE::ushort_v &y) { return SSE::max_epu16(x.data(), y.data()); }
0441 static Vc_ALWAYS_INLINE Vc_PURE SSE::float_v max(const SSE::float_v &x, const SSE::float_v &y) { return _mm_max_ps(x.data(), y.data()); }
0442 static Vc_ALWAYS_INLINE Vc_PURE SSE::double_v max(const SSE::double_v &x, const SSE::double_v &y) { return _mm_max_pd(x.data(), y.data()); }
0443
0444 template <typename T,
0445 typename = enable_if<std::is_same<T, double>::value || std::is_same<T, float>::value ||
0446 std::is_same<T, short>::value ||
0447 std::is_same<T, int>::value>>
0448 Vc_ALWAYS_INLINE Vc_PURE Vector<T, VectorAbi::Sse> abs(Vector<T, VectorAbi::Sse> x)
0449 {
0450 return SSE::VectorHelper<T>::abs(x.data());
0451 }
0452
0453 template<typename T> Vc_ALWAYS_INLINE Vc_PURE Vector<T, VectorAbi::Sse> sqrt (const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::sqrt(x.data()); }
0454 template<typename T> Vc_ALWAYS_INLINE Vc_PURE Vector<T, VectorAbi::Sse> rsqrt(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::rsqrt(x.data()); }
0455 template<typename T> Vc_ALWAYS_INLINE Vc_PURE Vector<T, VectorAbi::Sse> reciprocal(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::reciprocal(x.data()); }
0456 template<typename T> Vc_ALWAYS_INLINE Vc_PURE Vector<T, VectorAbi::Sse> round(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::round(x.data()); }
0457
0458 template<typename T> Vc_ALWAYS_INLINE Vc_PURE typename Vector<T, VectorAbi::Sse>::Mask isfinite(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::isFinite(x.data()); }
0459 template<typename T> Vc_ALWAYS_INLINE Vc_PURE typename Vector<T, VectorAbi::Sse>::Mask isinf(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::isInfinite(x.data()); }
0460 template<typename T> Vc_ALWAYS_INLINE Vc_PURE typename Vector<T, VectorAbi::Sse>::Mask isnan(const Vector<T, VectorAbi::Sse> &x) { return SSE::VectorHelper<T>::isNaN(x.data()); }
0461
0462 #define Vc_CONDITIONAL_ASSIGN(name_, op_) \
0463 template <Operator O, typename T, typename M, typename U> \
0464 Vc_INTRINSIC enable_if<O == Operator::name_, void> conditional_assign( \
0465 Vector<T, VectorAbi::Sse> &lhs, M &&mask, U &&rhs) \
0466 { \
0467 lhs(mask) op_ rhs; \
0468 } \
0469 Vc_NOTHING_EXPECTING_SEMICOLON
0470 Vc_CONDITIONAL_ASSIGN( Assign, =);
0471 Vc_CONDITIONAL_ASSIGN( PlusAssign, +=);
0472 Vc_CONDITIONAL_ASSIGN( MinusAssign, -=);
0473 Vc_CONDITIONAL_ASSIGN( MultiplyAssign, *=);
0474 Vc_CONDITIONAL_ASSIGN( DivideAssign, /=);
0475 Vc_CONDITIONAL_ASSIGN( RemainderAssign, %=);
0476 Vc_CONDITIONAL_ASSIGN( XorAssign, ^=);
0477 Vc_CONDITIONAL_ASSIGN( AndAssign, &=);
0478 Vc_CONDITIONAL_ASSIGN( OrAssign, |=);
0479 Vc_CONDITIONAL_ASSIGN( LeftShiftAssign,<<=);
0480 Vc_CONDITIONAL_ASSIGN(RightShiftAssign,>>=);
0481 #undef Vc_CONDITIONAL_ASSIGN
0482
0483 #define Vc_CONDITIONAL_ASSIGN(name_, expr_) \
0484 template <Operator O, typename T, typename M> \
0485 Vc_INTRINSIC enable_if<O == Operator::name_, Vector<T, VectorAbi::Sse>> \
0486 conditional_assign(Vector<T, VectorAbi::Sse> &lhs, M &&mask) \
0487 { \
0488 return expr_; \
0489 } \
0490 Vc_NOTHING_EXPECTING_SEMICOLON
0491 Vc_CONDITIONAL_ASSIGN(PostIncrement, lhs(mask)++);
0492 Vc_CONDITIONAL_ASSIGN( PreIncrement, ++lhs(mask));
0493 Vc_CONDITIONAL_ASSIGN(PostDecrement, lhs(mask)--);
0494 Vc_CONDITIONAL_ASSIGN( PreDecrement, --lhs(mask));
0495 #undef Vc_CONDITIONAL_ASSIGN
0496
0497 }
0498
0499 #include "vector.tcc"
0500 #include "simd_cast.h"
0501
0502 #endif