@@ -59,11 +59,39 @@ struct UnaryPlus {
5959 }
6060};
6161
62- struct VecOperators {
62+ // Tag to map/templatize the mixin for prefix/postfix inc/dec operators.
63+ struct IncDec {};
64+
65+ template <typename SelfOperandTy> struct IncDecImpl {
66+ using element_type = typename from_incomplete<SelfOperandTy>::element_type;
67+ using vec_t = simplify_if_swizzle_t <std::remove_const_t <SelfOperandTy>>;
68+
69+ public:
70+ friend SelfOperandTy &operator ++(SelfOperandTy &x) {
71+ x += element_type{1 };
72+ return x;
73+ }
74+ friend SelfOperandTy &operator --(SelfOperandTy &x) {
75+ x -= element_type{1 };
76+ return x;
77+ }
78+ friend auto operator ++(SelfOperandTy &x, int ) {
79+ vec_t tmp{x};
80+ x += element_type{1 };
81+ return tmp;
82+ }
83+ friend auto operator --(SelfOperandTy &x, int ) {
84+ vec_t tmp{x};
85+ x -= element_type{1 };
86+ return tmp;
87+ }
88+ };
89+
90+ template <typename Self> struct VecOperators {
91+ static_assert (is_vec_v<Self>);
92+
6393 template <typename OpTy, typename ... ArgTys>
6494 static constexpr auto apply (const ArgTys &...Args) {
65- using Self = nth_type_t <0 , ArgTys...>;
66- static_assert (is_vec_v<Self>);
6795 static_assert (((std::is_same_v<Self, ArgTys> && ...)));
6896
6997 using element_type = typename Self::element_type;
@@ -163,6 +191,41 @@ struct VecOperators {
163191 res[i] = Op (Args[i]...);
164192 return res;
165193 }
194+
195+ // Uglier than possible due to
196+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282.
197+ template <typename Op, typename = void > struct OpMixin ;
198+
199+ template <typename Op>
200+ struct OpMixin <Op, std::enable_if_t <std::is_same_v<Op, IncDec>>>
201+ : public IncDecImpl<Self> {};
202+
203+ #define __SYCL_VEC_UOP_MIXIN (OP, OPERATOR ) \
204+ template <typename Op> \
205+ struct OpMixin <Op, std::enable_if_t <std::is_same_v<Op, OP>>> { \
206+ friend auto operator OPERATOR (const Self &v) { return apply<OP>(v); } \
207+ };
208+
209+ __SYCL_VEC_UOP_MIXIN (std::negate<void >, -)
210+ __SYCL_VEC_UOP_MIXIN (std::logical_not<void >, !)
211+ __SYCL_VEC_UOP_MIXIN (UnaryPlus, +)
212+
213+ template <typename Op>
214+ struct OpMixin <Op, std::enable_if_t <std::is_same_v<Op, std::bit_not<void >>>> {
215+ template <typename T = typename from_incomplete<Self>::element_type>
216+ friend std::enable_if_t <!is_vgenfloat_v<T>, Self> operator ~(const Self &v) {
217+ return apply<std::bit_not<void >>(v);
218+ }
219+ };
220+
221+ #undef __SYCL_VEC_UOP_MIXIN
222+
223+ template <typename ... Op>
224+ struct __SYCL_EBO CombineImpl : public OpMixin<Op>... {};
225+
226+ struct Combined
227+ : public CombineImpl<std::negate<void >, std::logical_not<void >,
228+ std::bit_not<void >, UnaryPlus, IncDec> {};
166229};
167230
168231// Macros to populate binary operation on sycl::vec.
@@ -174,7 +237,7 @@ struct VecOperators {
174237 template <typename T = DataT> \
175238 friend std::enable_if_t <(COND), vec_t > operator BINOP (const vec_t & Lhs, \
176239 const vec_t & Rhs) { \
177- return VecOperators:: apply<FUNCTOR>(Lhs, Rhs); \
240+ return VecOperators< vec_t >:: template apply<FUNCTOR>(Lhs, Rhs); \
178241 } \
179242 \
180243 template <typename T = DataT> \
@@ -200,65 +263,11 @@ struct VecOperators {
200263 return Lhs; \
201264 }
202265
203- /* ***************************************************************
204- * vec_arith_common
205- * / | \
206- * / | \
207- * vec_arith<int> vec_arith<float> ... vec_arith<byte>
208- * \ | /
209- * \ | /
210- * sycl::vec<T>
211- *
212- * vec_arith_common is the base class for vec_arith. It contains
213- * the common math operators of sycl::vec for all types.
214- * vec_arith is the derived class that contains the math operators
215- * specialized for certain types. sycl::vec inherits from vec_arith.
216- * *************************************************************/
217- template <typename DataT, int NumElements> class vec_arith_common ;
218- template <typename DataT> struct vec_helper ;
219-
220266template <typename DataT, int NumElements>
221- class vec_arith : public vec_arith_common < DataT, NumElements> {
267+ class vec_arith : public VecOperators <vec< DataT, NumElements>>::Combined {
222268protected:
223269 using vec_t = vec<DataT, NumElements>;
224270 using ocl_t = detail::fixed_width_signed<sizeof (DataT)>;
225- template <typename T> using vec_data = vec_helper<T>;
226-
227- // operator!.
228- friend vec<ocl_t , NumElements> operator !(const vec_t &Rhs) {
229- return VecOperators::apply<std::logical_not<void >>(Rhs);
230- }
231-
232- // operator +.
233- friend vec_t operator +(const vec_t &Lhs) {
234- return VecOperators::apply<UnaryPlus>(Lhs);
235- }
236-
237- // operator -.
238- friend vec_t operator -(const vec_t &Lhs) {
239- return VecOperators::apply<std::negate<void >>(Lhs);
240- }
241-
242- // Unary operations on sycl::vec
243- // FIXME: Don't allow Unary operators on vec<bool> after
244- // https://github.com/KhronosGroup/SYCL-CTS/issues/896 gets fixed.
245- #ifdef __SYCL_UOP
246- #error "Undefine __SYCL_UOP macro"
247- #endif
248- #define __SYCL_UOP (UOP, OPASSIGN ) \
249- friend vec_t &operator UOP (vec_t & Rhs) { \
250- Rhs OPASSIGN DataT{1 }; \
251- return Rhs; \
252- } \
253- friend vec_t operator UOP (vec_t &Lhs, int ) { \
254- vec_t Ret (Lhs); \
255- Lhs OPASSIGN DataT{1 }; \
256- return Ret; \
257- }
258-
259- __SYCL_UOP (++, +=)
260- __SYCL_UOP (--, -=)
261- #undef __SYCL_UOP
262271
263272 // The logical operations on scalar types results in 0/1, while for vec<>,
264273 // logical operations should result in 0 and -1 (similar to OpenCL vectors).
@@ -272,7 +281,7 @@ class vec_arith : public vec_arith_common<DataT, NumElements> {
272281 template <typename T = DataT> \
273282 friend std::enable_if_t <(COND), vec<ocl_t , NumElements>> operator RELLOGOP ( \
274283 const vec_t & Lhs, const vec_t & Rhs) { \
275- return VecOperators:: apply<FUNCTOR>(Lhs, Rhs); \
284+ return VecOperators< vec_t >:: template apply<FUNCTOR>(Lhs, Rhs); \
276285 } \
277286 \
278287 template <typename T = DataT> \
@@ -325,13 +334,13 @@ class vec_arith : public vec_arith_common<DataT, NumElements> {
325334#if (!defined(_HAS_STD_BYTE) || _HAS_STD_BYTE != 0)
326335template <int NumElements>
327336class vec_arith <std::byte, NumElements>
328- : public vec_arith_common<std::byte, NumElements> {
337+ : public VecOperators<vec<std::byte, NumElements>>::template OpMixin<
338+ std::bit_not<void >> {
329339protected:
330340 // NumElements can never be zero. Still using the redundant check to avoid
331341 // incomplete type errors.
332342 using DataT = typename std::conditional_t <NumElements == 0 , int , std::byte>;
333343 using vec_t = vec<DataT, NumElements>;
334- template <typename T> using vec_data = vec_helper<T>;
335344
336345 // Special <<, >> operators for std::byte.
337346 // std::byte is not an arithmetic type and it only supports the following
@@ -376,25 +385,6 @@ class vec_arith<std::byte, NumElements>
376385};
377386#endif // (!defined(_HAS_STD_BYTE) || _HAS_STD_BYTE != 0)
378387
379- template <typename DataT, int NumElements> class vec_arith_common {
380- protected:
381- using vec_t = vec<DataT, NumElements>;
382-
383- static constexpr bool IsBfloat16 =
384- std::is_same_v<DataT, sycl::ext::oneapi::bfloat16>;
385-
386- // operator~() available only when: dataT != float && dataT != double
387- // && dataT != half
388- template <typename T = DataT>
389- friend std::enable_if_t <!detail::is_vgenfloat_v<T>, vec_t >
390- operator ~(const vec_t &Rhs) {
391- return VecOperators::apply<std::bit_not<void >>(Rhs);
392- }
393-
394- // friends
395- template <typename T1, int T2> friend class __SYCL_EBO vec;
396- };
397-
398388#undef __SYCL_BINOP
399389
400390} // namespace detail
0 commit comments