Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 10:25:45

0001 /*  This file is part of the Vc library. {{{
0002 Copyright © 2009-2015 Matthias Kretz <kretz@kde.org>
0003 
0004 Redistribution and use in source and binary forms, with or without
0005 modification, are permitted provided that the following conditions are met:
0006     * Redistributions of source code must retain the above copyright
0007       notice, this list of conditions and the following disclaimer.
0008     * Redistributions in binary form must reproduce the above copyright
0009       notice, this list of conditions and the following disclaimer in the
0010       documentation and/or other materials provided with the distribution.
0011     * Neither the names of contributing organizations nor the
0012       names of its contributors may be used to endorse or promote products
0013       derived from this software without specific prior written permission.
0014 
0015 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0016 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0017 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0018 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
0019 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0020 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0021 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0022 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0023 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0024 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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         // internal: required to enable returning objects of VectorType
0101         Vc_ALWAYS_INLINE Vector(VectorType x) : d(x) {}
0102 
0103         // implict conversion from compatible Vector<U>
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         // static_cast from the remaining Vector<U>
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         // broadcast
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         // zeroing
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         // skip this code for MSVC because it fails to do overload resolution correctly
0156 
0157         ////////////////////////////////////////////////////////////////////////////////
0158         // non-converting pd, ps, and epi32 gathers
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         // masked overload
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         // converting (from 8-bit and 16-bit integers only) epi16 gather emulation via
0181         // epi32 gathers
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         // masked overload
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         // all remaining converting gathers
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         // masked overload
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  // Vc_IMPL_AVX2 && !MSVC
0251 
0252         //prefix
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         //postfix
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          * \note the returned object models the concept of a reference and
0275          * as such it can exist longer than the data it is referencing.
0276          * \note to avoid lifetime issues, we strongly advice not to store
0277          * any reference objects.
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 }  // namespace Vc
0498 
0499 #include "vector.tcc"
0500 #include "simd_cast.h"
0501 
0502 #endif // VC_SSE_VECTOR_H_