Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:25:52

0001 /*  This file is part of the Vc library. {{{
0002 Copyright © 2013-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_COMMON_WHERE_H_
0029 #define VC_COMMON_WHERE_H_
0030 
0031 #include "types.h"
0032 #include "macros.h"
0033 
0034 namespace Vc_VERSIONED_NAMESPACE
0035 {
0036 
0037 namespace WhereImpl
0038 {
0039 
0040     /** \internal
0041      * The default implementation covers Vc::Mask types and any \p _LValue type that implements an
0042      * overload for the Vc::conditional_assign function.
0043      */
0044     template<typename _Mask, typename _LValue> struct MaskedLValue
0045     {
0046         typedef _Mask Mask;
0047         typedef _LValue LValue;
0048 
0049         const Mask &mask;
0050         LValue &lhs;
0051 
0052         // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
0053         constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
0054         MaskedLValue(const MaskedLValue &) = delete;
0055 #ifndef __cpp_guaranteed_copy_elision
0056         constexpr MaskedLValue(MaskedLValue &&) = default;
0057 #endif
0058 
0059         /* It is intentional that the assignment operators return void: When a bool is used for the
0060          * mask the code might get skipped completely, thus nothing can be returned. This would be
0061          * like requiring an if statement to return a value.
0062          */
0063         template<typename T> Vc_ALWAYS_INLINE void operator  =(T &&rhs) { conditional_assign<Operator::          Assign>(lhs, mask, std::forward<T>(rhs)); }
0064         template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { conditional_assign<Operator::      PlusAssign>(lhs, mask, std::forward<T>(rhs)); }
0065         template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { conditional_assign<Operator::     MinusAssign>(lhs, mask, std::forward<T>(rhs)); }
0066         template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { conditional_assign<Operator::  MultiplyAssign>(lhs, mask, std::forward<T>(rhs)); }
0067         template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { conditional_assign<Operator::    DivideAssign>(lhs, mask, std::forward<T>(rhs)); }
0068         template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { conditional_assign<Operator:: RemainderAssign>(lhs, mask, std::forward<T>(rhs)); }
0069         template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { conditional_assign<Operator::       XorAssign>(lhs, mask, std::forward<T>(rhs)); }
0070         template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { conditional_assign<Operator::       AndAssign>(lhs, mask, std::forward<T>(rhs)); }
0071         template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { conditional_assign<Operator::        OrAssign>(lhs, mask, std::forward<T>(rhs)); }
0072         template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { conditional_assign<Operator:: LeftShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
0073         template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { conditional_assign<Operator::RightShiftAssign>(lhs, mask, std::forward<T>(rhs)); }
0074         Vc_ALWAYS_INLINE void operator++()    { conditional_assign<Operator:: PreIncrement>(lhs, mask); }
0075         Vc_ALWAYS_INLINE void operator++(int) { conditional_assign<Operator::PostIncrement>(lhs, mask); }
0076         Vc_ALWAYS_INLINE void operator--()    { conditional_assign<Operator:: PreDecrement>(lhs, mask); }
0077         Vc_ALWAYS_INLINE void operator--(int) { conditional_assign<Operator::PostDecrement>(lhs, mask); }
0078 
0079         // masked gathers
0080         template <class T, class IV, class S>
0081         Vc_INTRINSIC void operator=(Common::SubscriptOperation<T, IV, S, true> &&rhs)
0082         {
0083             lhs.gather(std::move(rhs).gatherArguments(), mask);
0084         }
0085         template <class T, class IV, class S>
0086         void operator+=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0087         template <class T, class IV, class S>
0088         void operator-=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0089         template <class T, class IV, class S>
0090         void operator*=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0091         template <class T, class IV, class S>
0092         void operator/=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0093         template <class T, class IV, class S>
0094         void operator%=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0095         template <class T, class IV, class S>
0096         void operator^=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0097         template <class T, class IV, class S>
0098         void operator&=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0099         template <class T, class IV, class S>
0100         void operator|=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0101         template <class T, class IV, class S>
0102         void operator<<=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0103         template <class T, class IV, class S>
0104         void operator>>=(Common::SubscriptOperation<T, IV, S, true> &&rhs) = delete;
0105     };
0106 
0107     template <typename _Mask, typename T_, typename I_, typename S_>
0108     struct MaskedLValue<_Mask, Common::SubscriptOperation<T_, I_, S_, true>>
0109     {
0110         typedef _Mask Mask;
0111         typedef Common::SubscriptOperation<T_, I_, S_, true> SO;
0112 
0113         const Mask &mask;
0114         SO &lhs;
0115 
0116         template <typename T> using Decay = typename std::decay<T>::type;
0117 
0118         // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
0119         constexpr MaskedLValue(const Mask &m, SO &&l) : mask(m), lhs(l) {}
0120         MaskedLValue(const MaskedLValue &) = delete;
0121 #ifndef __cpp_guaranteed_copy_elision
0122         constexpr MaskedLValue(MaskedLValue &&) = default;
0123 #endif
0124 
0125         /* It is intentional that the assignment operators return void: When a bool is used for the
0126          * mask the code might get skipped completely, thus nothing can be returned. This would be
0127          * like requiring an if statement to return a value.
0128          */
0129         template <class T> Vc_ALWAYS_INLINE void operator=(T &&rhs) &&
0130         {
0131             std::forward<T>(rhs).scatter(std::move(lhs).scatterArguments(), mask);
0132         }
0133         /*
0134          * The following operators maybe make some sense. But only if implemented directly on the
0135          * scalar objects in memory. Thus, the user is probably better of with a manual loop.
0136          *
0137          * If implemented the operators would need to do a masked gather, one operation, and a
0138          * masked scatter. There is no way this is going to be efficient.
0139          *
0140         template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  + std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0141         template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  - std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0142         template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  * std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0143         template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  / std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0144         template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  % std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0145         template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  ^ std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0146         template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  & std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0147         template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask)  | std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0148         template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) << std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0149         template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { (Decay<T>(lhs.gatherArguments(), mask) >> std::forward<T>(rhs)).scatter(lhs.scatterArguments(), mask); }
0150         Vc_ALWAYS_INLINE void operator++()    { ++lhs(mask); }
0151         Vc_ALWAYS_INLINE void operator++(int) { lhs(mask)++; }
0152         Vc_ALWAYS_INLINE void operator--()    { --lhs(mask); }
0153         Vc_ALWAYS_INLINE void operator--(int) { lhs(mask)--; }
0154         */
0155     };
0156 
0157     template<typename _LValue> struct MaskedLValue<bool, _LValue>
0158     {
0159         typedef bool Mask;
0160         typedef _LValue LValue;
0161 
0162         const Mask &mask;
0163         LValue &lhs;
0164 
0165         // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
0166         constexpr MaskedLValue(const Mask &m, LValue &l) : mask(m), lhs(l) {}
0167         MaskedLValue(const MaskedLValue &) = delete;
0168         constexpr MaskedLValue(MaskedLValue &&) = default;
0169 
0170         template<typename T> Vc_ALWAYS_INLINE void operator  =(T &&rhs) { if (mask) lhs   = std::forward<T>(rhs); }
0171         template<typename T> Vc_ALWAYS_INLINE void operator +=(T &&rhs) { if (mask) lhs  += std::forward<T>(rhs); }
0172         template<typename T> Vc_ALWAYS_INLINE void operator -=(T &&rhs) { if (mask) lhs  -= std::forward<T>(rhs); }
0173         template<typename T> Vc_ALWAYS_INLINE void operator *=(T &&rhs) { if (mask) lhs  *= std::forward<T>(rhs); }
0174         template<typename T> Vc_ALWAYS_INLINE void operator /=(T &&rhs) { if (mask) lhs  /= std::forward<T>(rhs); }
0175         template<typename T> Vc_ALWAYS_INLINE void operator %=(T &&rhs) { if (mask) lhs  %= std::forward<T>(rhs); }
0176         template<typename T> Vc_ALWAYS_INLINE void operator ^=(T &&rhs) { if (mask) lhs  ^= std::forward<T>(rhs); }
0177         template<typename T> Vc_ALWAYS_INLINE void operator &=(T &&rhs) { if (mask) lhs  &= std::forward<T>(rhs); }
0178         template<typename T> Vc_ALWAYS_INLINE void operator |=(T &&rhs) { if (mask) lhs  |= std::forward<T>(rhs); }
0179         template<typename T> Vc_ALWAYS_INLINE void operator<<=(T &&rhs) { if (mask) lhs <<= std::forward<T>(rhs); }
0180         template<typename T> Vc_ALWAYS_INLINE void operator>>=(T &&rhs) { if (mask) lhs >>= std::forward<T>(rhs); }
0181         Vc_ALWAYS_INLINE void operator++()    { if (mask) ++lhs; }
0182         Vc_ALWAYS_INLINE void operator++(int) { if (mask) lhs++; }
0183         Vc_ALWAYS_INLINE void operator--()    { if (mask) --lhs; }
0184         Vc_ALWAYS_INLINE void operator--(int) { if (mask) lhs--; }
0185     };
0186 
0187     template<typename _Mask> struct WhereMask
0188     {
0189         typedef _Mask Mask;
0190         const Mask &mask;
0191 
0192         // the ctors must be present, otherwise GCC fails to warn for Vc_WARN_UNUSED_RESULT
0193         constexpr WhereMask(const Mask &m) : mask(m) {}
0194         WhereMask(const WhereMask &) = delete;
0195 
0196         template <typename T, typename I, typename S>
0197         constexpr Vc_WARN_UNUSED_RESULT
0198             MaskedLValue<Mask, Common::SubscriptOperation<T, I, S, true>>
0199             operator|(Common::SubscriptOperation<T, I, S, true> &&lhs) const
0200         {
0201             static_assert(!std::is_const<T>::value,
0202                           "masked scatter to constant memory not possible.");
0203             return {mask, std::move(lhs)};
0204         }
0205 
0206         template<typename T> constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator|(T &&lhs) const
0207         {
0208             static_assert(std::is_lvalue_reference<T>::value, "Syntax error: Incorrect use of Vc::where. Maybe operator precedence got you by surprise. Examples of correct usage:\n"
0209                     "  Vc::where(x < 2) | x += 1;\n"
0210                     "  (Vc::where(x < 2) | x)++;\n"
0211                     "  Vc::where(x < 2)(x) += 1;\n"
0212                     "  Vc::where(x < 2)(x)++;\n"
0213                     );
0214             return { mask, lhs };
0215         }
0216 
0217         template <class T,
0218                   class = decltype(std::declval<T>() = std::declval<const T &>())>
0219         constexpr Vc_WARN_UNUSED_RESULT MaskedLValue<Mask, T> operator()(T &&lhs) const
0220         {
0221             return operator|(std::forward<T>(lhs));
0222         }
0223     };
0224 }  // namespace WhereImpl
0225 
0226 /**
0227  * \ingroup Utilities
0228  *
0229  * Conditional assignment.
0230  *
0231  * Since compares between SIMD vectors do not return a single boolean, but rather a vector of
0232  * booleans (mask), one often cannot use if / else statements. Instead, one needs to state
0233  * that only a subset of entries of a given SIMD vector should be modified. The \c where function
0234  * can be prepended to any assignment operation to execute a masked assignment.
0235  *
0236  * \param mask The mask that selects the entries in the target vector that will be modified.
0237  *
0238  * \return This function returns an opaque object that binds to the left operand of an assignment
0239  * via the binary-or operator or the functor operator. (i.e. either <code>where(mask) | x = y</code>
0240  * or <code>where(mask)(x) = y</code>)
0241  *
0242  * Example:
0243  * \code
0244  * template<typename T> void f1(T &x, T &y)
0245  * {
0246  *   if (x < 2) {
0247  *     x *= y;
0248  *     y += 2;
0249  *   }
0250  * }
0251  * template<typename T> void f2(T &x, T &y)
0252  * {
0253  *   where(x < 2) | x *= y;
0254  *   where(x < 2) | y += 2;
0255  * }
0256  * \endcode
0257  * The block following the if statement in \c f1 will be executed if <code>x &lt; 2</code> evaluates
0258  * to \c true. If \c T is a scalar type you normally get what you expect. But if \c T is a SIMD
0259  * vector type, the comparison will use the implicit conversion from a mask to bool, meaning
0260  * <code>all_of(x &lt; 2)</code>.
0261  *
0262  * Most of the time the required operation is a masked assignment as stated in \c f2.
0263  *
0264  */
0265 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> where(const M &mask)
0266 {
0267     return { mask };
0268 }
0269 
0270 template <class M, class V>
0271 constexpr Vc_WARN_UNUSED_RESULT WhereImpl::MaskedLValue<M, V> where(const M &mask,
0272                                                                     V &value)
0273 {
0274     return {mask, value};
0275 }
0276 
0277 // `where` overload for masked scatters. It's necessary because SubscriptOperation doesn't
0278 // want to become an lvalue.
0279 template <class M, class T, class IT, class Scale>
0280 constexpr Vc_WARN_UNUSED_RESULT
0281     WhereImpl::MaskedLValue<M, Common::SubscriptOperation<T, IT, Scale, true>>
0282     where(const M &mask, Common::SubscriptOperation<T, IT, Scale, true> &&value)
0283 {
0284     return {mask, std::move(value)};
0285 }
0286 
0287 template<typename M> constexpr Vc_WARN_UNUSED_RESULT WhereImpl::WhereMask<M> _if(const M &m)
0288 {
0289     return { m };
0290 }
0291 
0292 }  // namespace Vc
0293 
0294 #endif // VC_COMMON_WHERE_H_