1 /* Copyright (C) 2014 Povilas Kanapickas <povilas@radix.lt> 2 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 8 #ifndef LIBSIMDPP_SIMDPP_CORE_DETAIL_GET_EXPR_UINT_H 9 #define LIBSIMDPP_SIMDPP_CORE_DETAIL_GET_EXPR_UINT_H 10 11 #include <simdpp/detail/get_expr.h> 12 13 namespace simdpp { 14 namespace SIMDPP_ARCH_NAMESPACE { 15 namespace detail { 16 17 18 /* We want to reduce the number of overloads that need to be created in order 19 to match a specific case of an expression tree containing various integer 20 operation nodes, such as add(int), mul_lo(int), etc. For particular 21 vector size each of these operations are equivalent regardless of the 22 argument types. Thus we simply convert the arguments of the expression to 23 uint expressions of certain configuration. 24 25 As a result, the following tuples of types will appear as the arguments 26 of the returned expression: 27 28 * uint8, uint8 29 * uint16, uint16 30 * uint32, uint32 31 * uint64, uint64 32 */ 33 34 template<class V1, class V2> 35 struct expr2_uint_maybe_scalar_tags { 36 static const unsigned v1_type_tag = V1::type_tag; 37 static const unsigned v1_size_tag = V1::size_tag; 38 static const unsigned v2_type_tag = V2::type_tag; 39 static const unsigned v2_size_tag = V2::size_tag; 40 static const unsigned length_bytes = V1::length_bytes; 41 }; 42 43 template<class V2> 44 struct expr2_uint_maybe_scalar_tags<int, V2> { 45 static const unsigned v1_type_tag = SIMDPP_TAG_INT; 46 static const unsigned v1_size_tag = V2::size_tag; 47 static const unsigned v2_type_tag = V2::type_tag; 48 static const unsigned v2_size_tag = V2::size_tag; 49 static const unsigned length_bytes = V2::length_bytes; 50 }; 51 52 template<class V2> 53 struct expr2_uint_maybe_scalar_tags<long, V2> { 54 static const unsigned v1_type_tag = SIMDPP_TAG_INT; 55 static const unsigned v1_size_tag = V2::size_tag; 56 static const unsigned v2_type_tag = V2::type_tag; 57 static const unsigned v2_size_tag = V2::size_tag; 58 static const unsigned length_bytes = V2::length_bytes; 59 }; 60 61 template<class V2> 62 struct expr2_uint_maybe_scalar_tags<long long, V2> { 63 static const unsigned v1_type_tag = SIMDPP_TAG_INT; 64 static const unsigned v1_size_tag = V2::size_tag; 65 static const unsigned v2_type_tag = V2::type_tag; 66 static const unsigned v2_size_tag = V2::size_tag; 67 static const unsigned length_bytes = V2::length_bytes; 68 }; 69 70 template<class V2> 71 struct expr2_uint_maybe_scalar_tags<unsigned, V2> { 72 static const unsigned v1_type_tag = SIMDPP_TAG_UINT; 73 static const unsigned v1_size_tag = V2::size_tag; 74 static const unsigned v2_type_tag = V2::type_tag; 75 static const unsigned v2_size_tag = V2::size_tag; 76 static const unsigned length_bytes = V2::length_bytes; 77 }; 78 79 template<class V2> 80 struct expr2_uint_maybe_scalar_tags<unsigned long, V2> { 81 static const unsigned v1_type_tag = SIMDPP_TAG_UINT; 82 static const unsigned v1_size_tag = V2::size_tag; 83 static const unsigned v2_type_tag = V2::type_tag; 84 static const unsigned v2_size_tag = V2::size_tag; 85 static const unsigned length_bytes = V2::length_bytes; 86 }; 87 88 template<class V2> 89 struct expr2_uint_maybe_scalar_tags<unsigned long long, V2> { 90 static const unsigned v1_type_tag = SIMDPP_TAG_UINT; 91 static const unsigned v1_size_tag = V2::size_tag; 92 static const unsigned v2_type_tag = V2::type_tag; 93 static const unsigned v2_size_tag = V2::size_tag; 94 static const unsigned length_bytes = V2::length_bytes; 95 }; 96 97 template<class V2> 98 struct expr2_uint_maybe_scalar_tags<float, V2> { 99 static const unsigned v1_type_tag = SIMDPP_TAG_INT; 100 static const unsigned v1_size_tag = V2::size_tag; 101 static const unsigned v2_type_tag = V2::type_tag; 102 static const unsigned v2_size_tag = V2::size_tag; 103 static const unsigned length_bytes = V2::length_bytes; 104 }; 105 106 template<class V2> 107 struct expr2_uint_maybe_scalar_tags<double, V2> { 108 static const unsigned v1_type_tag = SIMDPP_TAG_INT; 109 static const unsigned v1_size_tag = V2::size_tag; 110 static const unsigned v2_type_tag = V2::type_tag; 111 static const unsigned v2_size_tag = V2::size_tag; 112 static const unsigned length_bytes = V2::length_bytes; 113 }; 114 115 116 template<class V1> 117 struct expr2_uint_maybe_scalar_tags<V1, int> { 118 static const unsigned v1_type_tag = V1::type_tag; 119 static const unsigned v1_size_tag = V1::size_tag; 120 static const unsigned v2_type_tag = SIMDPP_TAG_INT; 121 static const unsigned v2_size_tag = V1::size_tag; 122 static const unsigned length_bytes = V1::length_bytes; 123 }; 124 125 template<class V1> 126 struct expr2_uint_maybe_scalar_tags<V1, long> { 127 static const unsigned v1_type_tag = V1::type_tag; 128 static const unsigned v1_size_tag = V1::size_tag; 129 static const unsigned v2_type_tag = SIMDPP_TAG_INT; 130 static const unsigned v2_size_tag = V1::size_tag; 131 static const unsigned length_bytes = V1::length_bytes; 132 }; 133 134 template<class V1> 135 struct expr2_uint_maybe_scalar_tags<V1, long long> { 136 static const unsigned v1_type_tag = V1::type_tag; 137 static const unsigned v1_size_tag = V1::size_tag; 138 static const unsigned v2_type_tag = SIMDPP_TAG_INT; 139 static const unsigned v2_size_tag = V1::size_tag; 140 static const unsigned length_bytes = V1::length_bytes; 141 }; 142 143 template<class V1> 144 struct expr2_uint_maybe_scalar_tags<V1, unsigned> { 145 static const unsigned v1_type_tag = V1::type_tag; 146 static const unsigned v1_size_tag = V1::size_tag; 147 static const unsigned v2_type_tag = SIMDPP_TAG_UINT; 148 static const unsigned v2_size_tag = V1::size_tag; 149 static const unsigned length_bytes = V1::length_bytes; 150 }; 151 152 template<class V1> 153 struct expr2_uint_maybe_scalar_tags<V1, unsigned long> { 154 static const unsigned v1_type_tag = V1::type_tag; 155 static const unsigned v1_size_tag = V1::size_tag; 156 static const unsigned v2_type_tag = SIMDPP_TAG_UINT; 157 static const unsigned v2_size_tag = V1::size_tag; 158 static const unsigned length_bytes = V1::length_bytes; 159 }; 160 161 template<class V1> 162 struct expr2_uint_maybe_scalar_tags<V1, unsigned long long> { 163 static const unsigned v1_type_tag = V1::type_tag; 164 static const unsigned v1_size_tag = V1::size_tag; 165 static const unsigned v2_type_tag = SIMDPP_TAG_UINT; 166 static const unsigned v2_size_tag = V1::size_tag; 167 static const unsigned length_bytes = V1::length_bytes; 168 }; 169 170 template<class V1> 171 struct expr2_uint_maybe_scalar_tags<V1, float> { 172 static const unsigned v1_type_tag = V1::type_tag; 173 static const unsigned v1_size_tag = V1::size_tag; 174 static const unsigned v2_type_tag = SIMDPP_TAG_INT; 175 static const unsigned v2_size_tag = V1::size_tag; 176 static const unsigned length_bytes = V1::length_bytes; 177 }; 178 179 template<class V1> 180 struct expr2_uint_maybe_scalar_tags<V1, double> { 181 static const unsigned v1_type_tag = V1::type_tag; 182 static const unsigned v1_size_tag = V1::size_tag; 183 static const unsigned v2_type_tag = SIMDPP_TAG_INT; 184 static const unsigned v2_size_tag = V1::size_tag; 185 static const unsigned length_bytes = V1::length_bytes; 186 }; 187 188 template<class V1, class V2> 189 struct get_expr_uint_impl { 190 using tags = expr2_uint_maybe_scalar_tags<V1, V2>; 191 192 #if SIMDPP_EXPR_DEBUG 193 static_assert(tags::v1_size_tag == tags::v2_size_tag, "Mismatching vector sizes"); 194 static_assert(tags::v1_type_tag == SIMDPP_TAG_MASK_INT || 195 tags::v1_type_tag == SIMDPP_TAG_UINT || 196 tags::v1_type_tag == SIMDPP_TAG_INT, "Incorrect type parameter"); 197 static_assert(tags::v2_type_tag == SIMDPP_TAG_MASK_INT || 198 tags::v2_type_tag == SIMDPP_TAG_UINT || 199 tags::v2_type_tag == SIMDPP_TAG_INT, "Incorrect type parameter"); 200 #endif 201 202 // the size tag of the expression 203 static const unsigned size_tag = tags::v1_size_tag; 204 205 // (type_tag) get the type tag of the expression. Pretty much the same as 206 // get_expr2_nomask does 207 static const unsigned type_tag_t1 = tags::v1_type_tag > tags::v2_type_tag ? tags::v1_type_tag : tags::v2_type_tag; 208 static const unsigned type_tag = (type_tag_t1 == SIMDPP_TAG_MASK_INT) ? SIMDPP_TAG_UINT : type_tag_t1; 209 210 // strip signed integer types and masks 211 static const unsigned v1_type_tag = SIMDPP_TAG_UINT; 212 static const unsigned v2_type_tag = SIMDPP_TAG_UINT; 213 214 using v1_final_type = typename type_of_tag<v1_type_tag + size_tag, 215 tags::length_bytes, void>::type; 216 using v2_final_type = typename type_of_tag<v2_type_tag + size_tag, 217 tags::length_bytes, void>::type; 218 }; 219 220 template<template<class, class> class E, class V1, class V2> 221 struct get_expr_uint { 222 using impl = get_expr_uint_impl<V1, V2>; 223 224 using type = typename type_of_tag<impl::type_tag + impl::size_tag, 225 impl::tags::length_bytes, 226 E<V1, V2>>::type; 227 }; 228 229 } // namespace detail 230 } // namespace SIMDPP_ARCH_NAMESPACE 231 } // namespace simdpp 232 233 #endif 234