| 1 | /* Idealized SIMD Operations with SSE versions |
|---|
| 2 | Copyright (C) 2006, 2007, 2008, 2009, Robert D. Cameron and Dan Lin |
|---|
| 3 | Licensed to the public under the Open Software License 3.0. |
|---|
| 4 | Licensed to International Characters Inc. |
|---|
| 5 | under the Academic Free License version 3.0. |
|---|
| 6 | */ |
|---|
| 7 | #ifndef SSE_SIMD_H |
|---|
| 8 | #define SSE_SIMD_H |
|---|
| 9 | |
|---|
| 10 | /* |
|---|
| 11 | Replace the following SSE version specific include directives with the x86intrin.h meta intrinsic header. This header is available with GCC 4.4.X |
|---|
| 12 | */ |
|---|
| 13 | #ifdef __MMX__ |
|---|
| 14 | #include <mmintrin.h> |
|---|
| 15 | #endif |
|---|
| 16 | |
|---|
| 17 | #ifdef __SSE__ |
|---|
| 18 | #include <xmmintrin.h> |
|---|
| 19 | #endif |
|---|
| 20 | |
|---|
| 21 | #ifdef __SSE2__ |
|---|
| 22 | #include <emmintrin.h> |
|---|
| 23 | #endif |
|---|
| 24 | |
|---|
| 25 | #ifdef __SSE3__ |
|---|
| 26 | #include <pmmintrin.h> |
|---|
| 27 | #endif |
|---|
| 28 | |
|---|
| 29 | #ifdef __SSSE3__ |
|---|
| 30 | #include <tmmintrin.h> |
|---|
| 31 | #endif |
|---|
| 32 | |
|---|
| 33 | #ifdef __SSE4a__ |
|---|
| 34 | #include <ammintrin.h> |
|---|
| 35 | #endif |
|---|
| 36 | |
|---|
| 37 | #if defined (__SSE4_2__) || defined (__SSE4_1__) |
|---|
| 38 | |
|---|
| 39 | #include <smmintrin.h> |
|---|
| 40 | #endif |
|---|
| 41 | |
|---|
| 42 | /*------------------------------------------------------------*/ |
|---|
| 43 | #ifndef _MSC_VER |
|---|
| 44 | #include <stdint.h> |
|---|
| 45 | #endif |
|---|
| 46 | #ifdef _MSC_VER |
|---|
| 47 | #include "stdint.h" |
|---|
| 48 | #define LITTLE_ENDIAN 1234 |
|---|
| 49 | #define BIG_ENDIAN 4321 |
|---|
| 50 | #define BYTE_ORDER LITTLE_ENDIAN |
|---|
| 51 | #endif |
|---|
| 52 | #include <limits.h> |
|---|
| 53 | #ifndef LONG_BIT |
|---|
| 54 | #define LONG_BIT (8* sizeof(unsigned long)) |
|---|
| 55 | #endif |
|---|
| 56 | #include <emmintrin.h> |
|---|
| 57 | #ifdef USE_LDDQU |
|---|
| 58 | #include <pmmintrin.h> |
|---|
| 59 | #endif |
|---|
| 60 | |
|---|
| 61 | #include <stdio.h> |
|---|
| 62 | |
|---|
| 63 | typedef __m128i SIMD_type; |
|---|
| 64 | |
|---|
| 65 | static inline void print_bit_block(const char * var_name, SIMD_type v); |
|---|
| 66 | |
|---|
| 67 | /*------------------------------------------------------------*/ |
|---|
| 68 | /* I. SIMD bitwise logical operations */ |
|---|
| 69 | |
|---|
| 70 | static inline SIMD_type simd_and(SIMD_type b1, SIMD_type b2) { |
|---|
| 71 | return _mm_and_si128(b1, b2); |
|---|
| 72 | } |
|---|
| 73 | static inline SIMD_type simd_andc(SIMD_type b1, SIMD_type b2) { |
|---|
| 74 | return _mm_andnot_si128(b2, b1); |
|---|
| 75 | } |
|---|
| 76 | static inline SIMD_type simd_or(SIMD_type b1, SIMD_type b2) { |
|---|
| 77 | return _mm_or_si128(b1, b2); |
|---|
| 78 | } |
|---|
| 79 | static inline SIMD_type simd_xor(SIMD_type b1, SIMD_type b2) { |
|---|
| 80 | return _mm_xor_si128(b1, b2); |
|---|
| 81 | } |
|---|
| 82 | static inline SIMD_type simd_not(SIMD_type b) { |
|---|
| 83 | return simd_xor(b, _mm_set1_epi32(0xFFFFFFFF)); |
|---|
| 84 | } |
|---|
| 85 | static inline SIMD_type simd_nor(SIMD_type b1, SIMD_type b2) { |
|---|
| 86 | return simd_not(simd_or(b1,b2)); |
|---|
| 87 | } |
|---|
| 88 | static inline SIMD_type simd_if(SIMD_type cond, SIMD_type then_val, SIMD_type else_val) { |
|---|
| 89 | return simd_or(simd_and(then_val, cond), simd_andc(else_val, cond)); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | |
|---|
| 93 | /*------------------------------------------------------------*/ |
|---|
| 94 | /* II. Declarations of field-width based operations. */ |
|---|
| 95 | |
|---|
| 96 | /* Half-operand modifier specifications use "x", "h" or "l", |
|---|
| 97 | * "x" - no modification of the corresponding operand value |
|---|
| 98 | * "h" - each n-bit field is modified by taking the high n/2 bits. |
|---|
| 99 | * "l" - each n-bit field is modified by taking the low n/2 bits. */ |
|---|
| 100 | |
|---|
| 101 | enum HOM_t {x,h,l}; |
|---|
| 102 | |
|---|
| 103 | /* simd<fw> is a template struct providing all the simd operations |
|---|
| 104 | * for a given field width. */ |
|---|
| 105 | template <int fw> |
|---|
| 106 | struct simd { |
|---|
| 107 | /* The himask selector in which each field is fw/2 1 bits, |
|---|
| 108 | * followed by fw/2 0 bits. */ |
|---|
| 109 | static inline SIMD_type himask(); |
|---|
| 110 | |
|---|
| 111 | /* Splat constant generator with compile-time constant. */ |
|---|
| 112 | template <int v> static inline SIMD_type constant(); |
|---|
| 113 | /* Splat generator using the first field of a register. */ |
|---|
| 114 | static inline SIMD_type splat(SIMD_type r); |
|---|
| 115 | /* Move mask */ |
|---|
| 116 | static inline int movemask(SIMD_type r); |
|---|
| 117 | /* Shuffle */ |
|---|
| 118 | static inline SIMD_type shuffle(SIMD_type r, SIMD_type s); |
|---|
| 119 | |
|---|
| 120 | |
|---|
| 121 | /* Shift immediate with the shift constant as a template parameter. */ |
|---|
| 122 | template <int shft> static inline SIMD_type srli(SIMD_type r); |
|---|
| 123 | template <int shft> static inline SIMD_type slli(SIMD_type r); |
|---|
| 124 | template <int shft> static inline SIMD_type srai(SIMD_type r); |
|---|
| 125 | |
|---|
| 126 | /* Shift operations with register-specified shift values. */ |
|---|
| 127 | static inline SIMD_type srl(SIMD_type r, SIMD_type shft); |
|---|
| 128 | static inline SIMD_type sll(SIMD_type r, SIMD_type shft); |
|---|
| 129 | |
|---|
| 130 | /* Binary operations. */ |
|---|
| 131 | static inline SIMD_type add(SIMD_type r1, SIMD_type r2); |
|---|
| 132 | static inline SIMD_type sub(SIMD_type r1, SIMD_type r2); |
|---|
| 133 | static inline SIMD_type mult(SIMD_type r1, SIMD_type r2); |
|---|
| 134 | static inline SIMD_type max(SIMD_type r1, SIMD_type r2); |
|---|
| 135 | static inline SIMD_type eq(SIMD_type r1, SIMD_type r2); |
|---|
| 136 | static inline SIMD_type gt(SIMD_type r1, SIMD_type r2); |
|---|
| 137 | static inline SIMD_type pack(SIMD_type r1, SIMD_type r2); |
|---|
| 138 | static inline SIMD_type mergeh(SIMD_type r1, SIMD_type r2); |
|---|
| 139 | static inline SIMD_type mergel(SIMD_type r1, SIMD_type r2); |
|---|
| 140 | |
|---|
| 141 | // /* Functions for half-operand modification. */ |
|---|
| 142 | // |
|---|
| 143 | // template <HOM_t m> static inline SIMD_type hom(SIMD_type r); |
|---|
| 144 | // template <HOM_t m> static inline SIMD_type hx(SIMD_type r); |
|---|
| 145 | |
|---|
| 146 | /* Binary operations with half-operand modifiers */ |
|---|
| 147 | |
|---|
| 148 | template <HOM_t m1, HOM_t m2> static inline SIMD_type add(SIMD_type r1, SIMD_type r2); |
|---|
| 149 | template <HOM_t m1, HOM_t m2> static inline SIMD_type sub(SIMD_type r1, SIMD_type r2); |
|---|
| 150 | template <HOM_t m1, HOM_t m2> static inline SIMD_type mult(SIMD_type r1, SIMD_type r2); |
|---|
| 151 | template <HOM_t m1, HOM_t m2> static inline SIMD_type pack(SIMD_type r1, SIMD_type r2); |
|---|
| 152 | template <HOM_t m1, HOM_t m2> static inline SIMD_type mergeh(SIMD_type r1, SIMD_type r2); |
|---|
| 153 | template <HOM_t m1, HOM_t m2> static inline SIMD_type mergel(SIMD_type r1, SIMD_type r2); |
|---|
| 154 | |
|---|
| 155 | }; |
|---|
| 156 | |
|---|
| 157 | #define sisd_to_int(x) _mm_cvtsi128_si32(x) |
|---|
| 158 | |
|---|
| 159 | #define sisd_from_int(n) _mm_cvtsi32_si128(n) |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | /* III. Implementations of simd<fw> operations. */ |
|---|
| 165 | |
|---|
| 166 | /* Constant generator functions for various field widths. */ |
|---|
| 167 | |
|---|
| 168 | template<> inline SIMD_type simd<2>::himask() {return _mm_set1_epi8(0xAA);} |
|---|
| 169 | |
|---|
| 170 | template<> inline SIMD_type simd<4>::himask() {return _mm_set1_epi8(0xCC);} |
|---|
| 171 | |
|---|
| 172 | template<> inline SIMD_type simd<8>::himask() {return _mm_set1_epi8(0xF0);} |
|---|
| 173 | |
|---|
| 174 | template<> inline SIMD_type simd<16>::himask() {return _mm_set1_epi16(0xFF00);} |
|---|
| 175 | |
|---|
| 176 | template<> inline SIMD_type simd<32>::himask() {return _mm_set1_epi32(0xFFFF0000);} |
|---|
| 177 | |
|---|
| 178 | template<> inline SIMD_type simd<64>::himask() {return _mm_set_epi32(-1,0,-1,0);} |
|---|
| 179 | |
|---|
| 180 | template<> inline SIMD_type simd<128>::himask() {return _mm_set_epi32(-1,-1,0,0);} |
|---|
| 181 | |
|---|
| 182 | template<> template <int n> inline SIMD_type simd<4>::constant() {return _mm_set1_epi8((n)<<4|(n));} |
|---|
| 183 | |
|---|
| 184 | template<> template <int n> inline SIMD_type simd<8>::constant() {return _mm_set1_epi8(n);} |
|---|
| 185 | |
|---|
| 186 | template<> template <int n> inline SIMD_type simd<16>::constant() {return _mm_set1_epi16(n);} |
|---|
| 187 | |
|---|
| 188 | template<> template <int n> inline SIMD_type simd<32>::constant() {return _mm_set1_epi32(n);} |
|---|
| 189 | |
|---|
| 190 | template<> template <> inline SIMD_type simd<1>::constant<0>() {return simd<8>::constant<0>();} |
|---|
| 191 | template<> template <> inline SIMD_type simd<1>::constant<1>() {return simd<8>::constant<-1>();} |
|---|
| 192 | |
|---|
| 193 | template<> template <int n> inline SIMD_type simd<2>::constant() {return simd<4>::constant<(n<<2|n)>();} |
|---|
| 194 | |
|---|
| 195 | // Splat the first 8-bit int into all positions. |
|---|
| 196 | template <> inline SIMD_type simd<8>::splat(SIMD_type x) { |
|---|
| 197 | return _mm_set1_epi8(*(uint8_t *)(&x)); |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | // Splat the first 16-bit int into all positions. |
|---|
| 201 | template <> inline SIMD_type simd<16>::splat(SIMD_type x) { |
|---|
| 202 | SIMD_type t = _mm_shufflelo_epi16(x,0); |
|---|
| 203 | return _mm_shuffle_epi32(t,0); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | // Splat the first 32-bit int into all positions. |
|---|
| 207 | template <> inline SIMD_type simd<32>::splat(SIMD_type x) { |
|---|
| 208 | return _mm_shuffle_epi32(x,0); |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | // Splat the first 64-bit int into all positions. |
|---|
| 212 | template <> inline SIMD_type simd<64>::splat(SIMD_type x) { |
|---|
| 213 | return _mm_shuffle_epi32(x,_MM_SHUFFLE(1,0,1,0)); |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | // Move mask 8-bit |
|---|
| 217 | template <> inline int simd<8>::movemask(SIMD_type r) { |
|---|
| 218 | return _mm_movemask_epi8(r); |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | // Shuffle 8-bit |
|---|
| 222 | template <> inline SIMD_type simd<8>::shuffle(SIMD_type r, SIMD_type s) { |
|---|
| 223 | return _mm_shuffle_epi8(r,s); |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | /* Shift immediate operations with direct implementation by built-ins. */ |
|---|
| 227 | |
|---|
| 228 | template<> template<int sh> inline SIMD_type simd<16>::slli(SIMD_type r) {return _mm_slli_epi16(r, sh);} |
|---|
| 229 | |
|---|
| 230 | template<> template<int sh> inline SIMD_type simd<32>::slli(SIMD_type r) {return _mm_slli_epi32(r, sh);} |
|---|
| 231 | |
|---|
| 232 | template<> template<int sh> inline SIMD_type simd<64>::slli(SIMD_type r) {return _mm_slli_epi64(r, sh);} |
|---|
| 233 | |
|---|
| 234 | template<> template<int sh> inline SIMD_type simd<16>::srli(SIMD_type r) {return _mm_srli_epi16(r, sh);} |
|---|
| 235 | |
|---|
| 236 | template<> template<int sh> inline SIMD_type simd<32>::srli(SIMD_type r) {return _mm_srli_epi32(r, sh);} |
|---|
| 237 | |
|---|
| 238 | template<> template<int sh> inline SIMD_type simd<64>::srli(SIMD_type r) {return _mm_srli_epi64(r, sh);} |
|---|
| 239 | |
|---|
| 240 | /* simd_srai |
|---|
| 241 | * fw: 16,32*/ |
|---|
| 242 | template<> template<int sh> inline SIMD_type simd<16>::srai(SIMD_type r) {return _mm_srai_epi16(r, sh);} |
|---|
| 243 | |
|---|
| 244 | template<> template<int sh> inline SIMD_type simd<32>::srai(SIMD_type r) {return _mm_srai_epi32(r, sh);} |
|---|
| 245 | |
|---|
| 246 | |
|---|
| 247 | |
|---|
| 248 | /* General rules for slli/srli for field widths 2, 4, 8 in terms of 32-bit shifts. */ |
|---|
| 249 | |
|---|
| 250 | |
|---|
| 251 | // Doesn't work: |
|---|
| 252 | //template<int fw> template<int sh> |
|---|
| 253 | //inline SIMD_type simd<fw>::slli(SIMD_type r) { |
|---|
| 254 | // return simd_and(simd<32>::slli<sh>(r), simd<fw>::constant<6>()); |
|---|
| 255 | //} |
|---|
| 256 | // |
|---|
| 257 | |
|---|
| 258 | |
|---|
| 259 | template<> template<int sh> |
|---|
| 260 | inline SIMD_type simd<2>::slli(SIMD_type r) { |
|---|
| 261 | return simd_and(simd<32>::slli<sh>(r),simd<2>::constant<((3<<sh)&3)>()); |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | template<> template<int sh> |
|---|
| 265 | inline SIMD_type simd<4>::slli(SIMD_type r) { |
|---|
| 266 | return simd_and(simd<32>::slli<sh>(r),simd<4>::constant<((15<<sh)&15)>()); |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | template<> template<int sh> |
|---|
| 270 | inline SIMD_type simd<8>::slli(SIMD_type r) { |
|---|
| 271 | return simd_and(simd<32>::slli<sh>(r),simd<8>::constant<((255<<sh)&255)>()); |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | //template<int fw> template<int sh> |
|---|
| 276 | //inline SIMD_type simd<fw>::srli(SIMD_type r) { |
|---|
| 277 | // return simd_and(simd<32>::srli<sh>(r),simd<fw>::constant<((1<<(fw-sh))-1)>()); |
|---|
| 278 | //} |
|---|
| 279 | // |
|---|
| 280 | |
|---|
| 281 | |
|---|
| 282 | template<> template<int sh> |
|---|
| 283 | inline SIMD_type simd<2>::srli(SIMD_type r) { |
|---|
| 284 | return simd_and(simd<32>::srli<sh>(r),simd<2>::constant<(3>>sh)>()); |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | template<> template<int sh> |
|---|
| 288 | inline SIMD_type simd<4>::srli(SIMD_type r) { |
|---|
| 289 | return simd_and(simd<32>::srli<sh>(r),simd<4>::constant<(15>>sh)>()); |
|---|
| 290 | } |
|---|
| 291 | |
|---|
| 292 | template<> template<int sh> |
|---|
| 293 | inline SIMD_type simd<8>::srli(SIMD_type r) { |
|---|
| 294 | return simd_and(simd<32>::srli<sh>(r),simd<8>::constant<(255>>sh)>()); |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | |
|---|
| 298 | |
|---|
| 299 | |
|---|
| 300 | /* Shift immediate for 128-bit fields */ |
|---|
| 301 | |
|---|
| 302 | template<> template<int shft> |
|---|
| 303 | inline SIMD_type simd<128>::slli(SIMD_type r) { |
|---|
| 304 | return (shft % 8 == 0 ? _mm_slli_si128(r, shft/8) : |
|---|
| 305 | shft >= 64 ? simd<64>::slli<shft-64>(_mm_slli_si128(r, 8)) : |
|---|
| 306 | simd_or(simd<64>::slli<shft>(r), _mm_slli_si128(simd<64>::srli<64-shft>(r), 8))); |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | template<> template<int shft> |
|---|
| 310 | inline SIMD_type simd<128>::srli(SIMD_type r) { |
|---|
| 311 | return (shft % 8 == 0 ? _mm_srli_si128(r, shft/8) : |
|---|
| 312 | shft >= 64 ? simd<64>::srli<shft-64>(_mm_srli_si128(r, 8)) : |
|---|
| 313 | simd_or(simd<64>::srli<shft>(r), _mm_srli_si128(simd<64>::slli<64-shft>(r), 8))); |
|---|
| 314 | } |
|---|
| 315 | |
|---|
| 316 | |
|---|
| 317 | /* Shifts with shift values specified in an operand register. */ |
|---|
| 318 | |
|---|
| 319 | template<> |
|---|
| 320 | inline SIMD_type simd<128>::srl(SIMD_type r, SIMD_type shft) { |
|---|
| 321 | return simd_or(_mm_srl_epi64(r, shft), |
|---|
| 322 | simd_or(_mm_srli_si128(_mm_srl_epi64(r, _mm_sub_epi32(shft, sisd_from_int(64))), 8), |
|---|
| 323 | _mm_srli_si128(_mm_sll_epi64(r, _mm_sub_epi32(sisd_from_int(64), shft)), 8))); |
|---|
| 324 | } |
|---|
| 325 | |
|---|
| 326 | template<> |
|---|
| 327 | inline SIMD_type simd<128>::sll(SIMD_type r, SIMD_type shft) { |
|---|
| 328 | return simd_or(_mm_sll_epi64(r, shft), |
|---|
| 329 | simd_or(_mm_slli_si128(_mm_sll_epi64(r, _mm_sub_epi32(shft, sisd_from_int(64))), 8), |
|---|
| 330 | _mm_slli_si128(_mm_srl_epi64(r, _mm_sub_epi32(sisd_from_int(64), shft)), 8))); |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | template<> |
|---|
| 334 | inline SIMD_type simd<64>::srl(SIMD_type r, SIMD_type shft) { |
|---|
| 335 | return simd_if(simd<128>::himask(), |
|---|
| 336 | _mm_srl_epi64(r, _mm_srli_si128(shft, 8)), |
|---|
| 337 | _mm_srl_epi64(r, simd_andc(shft, simd<128>::himask()))); |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | template<> |
|---|
| 341 | inline SIMD_type simd<64>::sll(SIMD_type r, SIMD_type shft) { |
|---|
| 342 | return simd_if(simd<128>::himask(), |
|---|
| 343 | _mm_sll_epi64(r, _mm_srli_si128(shft, 8)), |
|---|
| 344 | _mm_sll_epi64(r, simd_andc(shft, simd<128>::himask()))); |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | |
|---|
| 348 | /* simd_add |
|---|
| 349 | * fw: 2,4,8,16,32,64 |
|---|
| 350 | |
|---|
| 351 | Use built-ins for 8, 16, 32, 64, simulations for 2, 4. */ |
|---|
| 352 | |
|---|
| 353 | template<> inline SIMD_type simd<8>::add(SIMD_type r1, SIMD_type r2) {return _mm_add_epi8(r1, r2);} |
|---|
| 354 | |
|---|
| 355 | template<> inline SIMD_type simd<16>::add(SIMD_type r1, SIMD_type r2) {return _mm_add_epi16(r1, r2);} |
|---|
| 356 | |
|---|
| 357 | template<> inline SIMD_type simd<32>::add(SIMD_type r1, SIMD_type r2) {return _mm_add_epi32(r1, r2);} |
|---|
| 358 | |
|---|
| 359 | template<> inline SIMD_type simd<64>::add(SIMD_type r1, SIMD_type r2) {return _mm_add_epi64(r1, r2);} |
|---|
| 360 | |
|---|
| 361 | template<> |
|---|
| 362 | inline SIMD_type simd<2>::add(SIMD_type r1, SIMD_type r2) { |
|---|
| 363 | SIMD_type c1 = simd_xor(r1,r2); |
|---|
| 364 | SIMD_type borrow = simd_and(r1,r2); |
|---|
| 365 | SIMD_type c2 = simd_xor(c1,(simd<128>::slli<1>(borrow))); |
|---|
| 366 | return simd_if(simd<2>::himask(),c2,c1); |
|---|
| 367 | } |
|---|
| 368 | |
|---|
| 369 | template<> |
|---|
| 370 | inline SIMD_type simd<4>::add(SIMD_type r1, SIMD_type r2) { |
|---|
| 371 | return simd_if(simd<8>::himask(), |
|---|
| 372 | simd<8>::add(r1,simd_and(r2,simd<8>::himask())), |
|---|
| 373 | simd<8>::add(r1, r2)); |
|---|
| 374 | } |
|---|
| 375 | |
|---|
| 376 | /* simd_sub |
|---|
| 377 | * fw: 2,4,8,16,32,64 |
|---|
| 378 | |
|---|
| 379 | Use built-ins for 8, 16, 32, 64, simulations for 2, 4. */ |
|---|
| 380 | |
|---|
| 381 | template<> inline SIMD_type simd<8>::sub(SIMD_type r1, SIMD_type r2) {return _mm_sub_epi8(r1, r2);} |
|---|
| 382 | |
|---|
| 383 | template<> inline SIMD_type simd<16>::sub(SIMD_type r1, SIMD_type r2) {return _mm_sub_epi16(r1, r2);} |
|---|
| 384 | |
|---|
| 385 | template<> inline SIMD_type simd<32>::sub(SIMD_type r1, SIMD_type r2) {return _mm_sub_epi32(r1, r2);} |
|---|
| 386 | |
|---|
| 387 | template<> inline SIMD_type simd<64>::sub(SIMD_type r1, SIMD_type r2) {return _mm_sub_epi64(r1, r2);} |
|---|
| 388 | |
|---|
| 389 | |
|---|
| 390 | template<> |
|---|
| 391 | inline SIMD_type simd<2>::sub(SIMD_type r1, SIMD_type r2) |
|---|
| 392 | { |
|---|
| 393 | SIMD_type c1 = simd_xor(r1,r2); |
|---|
| 394 | SIMD_type borrow = simd_andc(r2,r1); |
|---|
| 395 | SIMD_type c2 = simd_xor(c1,(simd<128>::slli<1>(borrow))); |
|---|
| 396 | return simd_if(simd<2>::himask(),c2,c1); |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | template<> |
|---|
| 400 | inline SIMD_type simd<4>::sub(SIMD_type r1, SIMD_type r2){ |
|---|
| 401 | return simd_if(simd<8>::himask(), |
|---|
| 402 | simd<8>::sub(r1, simd_and(r2,simd<8>::himask())), |
|---|
| 403 | simd<8>::sub(r1, r2)); |
|---|
| 404 | } |
|---|
| 405 | |
|---|
| 406 | /* simd_mult built-in for 16 bits only. */ |
|---|
| 407 | |
|---|
| 408 | template<> inline SIMD_type simd<16>::mult(SIMD_type r1, SIMD_type r2) {return _mm_mullo_epi16(r1, r2);} |
|---|
| 409 | |
|---|
| 410 | |
|---|
| 411 | /* _mm_mul_epu2 is equivalent of simd<64>::mult<l,l>*/ |
|---|
| 412 | template<> inline SIMD_type simd<32>::mult(SIMD_type r1, SIMD_type r2) { |
|---|
| 413 | return simd_or(_mm_mul_epu32(r1, r2), |
|---|
| 414 | simd::slli<32>(_mm_mul_epu32(simd::srli<32>(r1), simd::srli<32>(r2)))); |
|---|
| 415 | } |
|---|
| 416 | |
|---|
| 417 | |
|---|
| 418 | template<> |
|---|
| 419 | inline SIMD_type simd<8>::mult(SIMD_type r1, SIMD_type r2){ |
|---|
| 420 | return simd_or(simd<16>::mult<h,x>(r1, simd_and(simd<16>::himask(), r2)), |
|---|
| 421 | simd<16>::mult<l,l>(r1, r2)); |
|---|
| 422 | } |
|---|
| 423 | |
|---|
| 424 | |
|---|
| 425 | |
|---|
| 426 | |
|---|
| 427 | |
|---|
| 428 | /* simd_max for 8 bits only. */ |
|---|
| 429 | |
|---|
| 430 | template<> inline SIMD_type simd<8>::max(SIMD_type r1, SIMD_type r2) {return _mm_max_epu8(r1, r2);} |
|---|
| 431 | |
|---|
| 432 | |
|---|
| 433 | /* simd_eq |
|---|
| 434 | * fw: 8,16,32*/ |
|---|
| 435 | |
|---|
| 436 | template<> inline SIMD_type simd<8>::eq(SIMD_type r1, SIMD_type r2) {return _mm_cmpeq_epi8(r1, r2);} |
|---|
| 437 | |
|---|
| 438 | template<> inline SIMD_type simd<16>::eq(SIMD_type r1, SIMD_type r2) {return _mm_cmpeq_epi16(r1, r2);} |
|---|
| 439 | |
|---|
| 440 | template<> inline SIMD_type simd<32>::eq(SIMD_type r1, SIMD_type r2) {return _mm_cmpeq_epi32(r1, r2);} |
|---|
| 441 | |
|---|
| 442 | template<> inline SIMD_type simd<64>::eq(SIMD_type r1, SIMD_type r2) { |
|---|
| 443 | |
|---|
| 444 | #ifdef __SSE4_1__ |
|---|
| 445 | return _mm_cmpeq_epi64(r1, r2); |
|---|
| 446 | #endif |
|---|
| 447 | |
|---|
| 448 | // Fall back |
|---|
| 449 | SIMD_type t = _mm_cmpeq_epi32(r1, r2); |
|---|
| 450 | return simd_and(t, _mm_shuffle_epi32(t,_MM_SHUFFLE(2,3,0,1))); |
|---|
| 451 | |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | /*simd_pack |
|---|
| 455 | * fw: 2,4,8,16*/ |
|---|
| 456 | |
|---|
| 457 | /* Built-in operation for fw = 16. */ |
|---|
| 458 | template<> |
|---|
| 459 | inline SIMD_type simd<16>::pack(SIMD_type r1, SIMD_type r2) { |
|---|
| 460 | return _mm_packus_epi16(simd_andc(r2, simd<16>::himask()), simd_andc(r1, simd<16>::himask())); |
|---|
| 461 | } |
|---|
| 462 | |
|---|
| 463 | template<> |
|---|
| 464 | inline SIMD_type simd<32>::pack(SIMD_type r1, SIMD_type r2) { |
|---|
| 465 | |
|---|
| 466 | #ifdef __SSE4_1__ |
|---|
| 467 | return _mm_packus_epi32(simd_andc(r2, simd<32>::himask()), simd_andc(r1, simd<32>::himask())); |
|---|
| 468 | #endif |
|---|
| 469 | |
|---|
| 470 | // Fall back |
|---|
| 471 | return simd_or (_mm_shuffle_epi8(simd_andc(r1, simd<32>::himask()), _mm_set_epi8(0,1,4,5,8,9,12,13,2,3,6,7,10,11,14,15)), |
|---|
| 472 | _mm_shuffle_epi8(simd_andc(r2, simd<32>::himask()), _mm_set_epi8(2,3,6,7,10,11,14,15,0,1,4,5,8,9,12,13))); |
|---|
| 473 | |
|---|
| 474 | } |
|---|
| 475 | |
|---|
| 476 | template<> |
|---|
| 477 | inline SIMD_type simd<64>::pack(SIMD_type r1, SIMD_type r2) { |
|---|
| 478 | |
|---|
| 479 | |
|---|
| 480 | return simd_or(_mm_shuffle_epi32(simd_andc(r1, simd<64>::himask()), _MM_SHUFFLE(2,0,3,1)), |
|---|
| 481 | _mm_shuffle_epi32(simd_andc(r2, simd<64>::himask()), _MM_SHUFFLE(3,1,2,0))); // 1,3 contain 0 |
|---|
| 482 | |
|---|
| 483 | } |
|---|
| 484 | |
|---|
| 485 | /* fw: 2, 4, 8 */ |
|---|
| 486 | template<int fw> |
|---|
| 487 | inline SIMD_type simd<fw>::pack(SIMD_type r1, SIMD_type r2){ |
|---|
| 488 | return simd<fw*2>::pack(simd_if(simd<fw>::himask(),simd<128>::srli<fw/2>(r1),r1), |
|---|
| 489 | simd_if(simd<fw>::himask(),simd<128>::srli<fw/2>(r2),r2)); |
|---|
| 490 | } |
|---|
| 491 | |
|---|
| 492 | /* simd_mergeh |
|---|
| 493 | * fw: 1,2,4,8,16,32,64*/ |
|---|
| 494 | template<int fw> |
|---|
| 495 | inline SIMD_type simd<fw>::mergeh(SIMD_type r1, SIMD_type r2){ |
|---|
| 496 | /*fw: 1,2,4*/ |
|---|
| 497 | return simd<fw*2>::mergeh(simd_if(simd<fw*2>::himask(),r1,simd<fw*2>::srli<fw>(r2)), |
|---|
| 498 | simd_if(simd<fw*2>::himask(),simd<fw*2>::slli<fw>(r1),r2)); |
|---|
| 499 | } |
|---|
| 500 | |
|---|
| 501 | template<> inline SIMD_type simd<8>::mergeh(SIMD_type r1, SIMD_type r2) {return _mm_unpackhi_epi8(r2, r1);} |
|---|
| 502 | template<> inline SIMD_type simd<16>::mergeh(SIMD_type r1, SIMD_type r2) {return _mm_unpackhi_epi16(r2, r1);} |
|---|
| 503 | template<> inline SIMD_type simd<32>::mergeh(SIMD_type r1, SIMD_type r2) {return _mm_unpackhi_epi32(r2, r1);} |
|---|
| 504 | template<> inline SIMD_type simd<64>::mergeh(SIMD_type r1, SIMD_type r2) {return _mm_unpackhi_epi64(r2, r1);} |
|---|
| 505 | |
|---|
| 506 | |
|---|
| 507 | /* simd_mergel |
|---|
| 508 | * fw: 1,2,4,8,16,32,64*/ |
|---|
| 509 | template<int fw> |
|---|
| 510 | inline SIMD_type simd<fw>::mergel(SIMD_type r1, SIMD_type r2){ |
|---|
| 511 | /*fw: 1,2,4*/ |
|---|
| 512 | return simd<fw*2>::mergel(simd_if(simd<fw*2>::himask(),r1,simd<fw*2>::srli<fw>(r2)), |
|---|
| 513 | simd_if(simd<fw*2>::himask(),simd<fw*2>::slli<fw>(r1),r2)); |
|---|
| 514 | } |
|---|
| 515 | |
|---|
| 516 | template<> inline SIMD_type simd<8>::mergel(SIMD_type r1, SIMD_type r2) {return _mm_unpacklo_epi8(r2, r1);} |
|---|
| 517 | template<> inline SIMD_type simd<16>::mergel(SIMD_type r1, SIMD_type r2) {return _mm_unpacklo_epi16(r2, r1);} |
|---|
| 518 | template<> inline SIMD_type simd<32>::mergel(SIMD_type r1, SIMD_type r2) {return _mm_unpacklo_epi32(r2, r1);} |
|---|
| 519 | template<> inline SIMD_type simd<64>::mergel(SIMD_type r1, SIMD_type r2) {return _mm_unpacklo_epi64(r2, r1);} |
|---|
| 520 | |
|---|
| 521 | |
|---|
| 522 | #define simd_all_eq_8(v1, v2) simd_all_true<8>(_mm_cmpeq_epi8(v1, v2)) |
|---|
| 523 | #define simd_mask_eq_8(v1, v2, hex_mask) simd_mask_true<8>(_mm_cmpeq_epi8(v1, v2), hex_mask) |
|---|
| 524 | #define simd_all_le_8(v1, v2) simd_all_eq_8(simd_max_8(v1, v2), v2) |
|---|
| 525 | |
|---|
| 526 | #define simd_all_signed_gt_8(v1, v2) simd_all_true_8(_mm_cmpgt_epi8(v1, v2)) |
|---|
| 527 | |
|---|
| 528 | #define simd_cmpgt_8(v1,v2) _mm_cmpgt_epi8(v1, v2) |
|---|
| 529 | |
|---|
| 530 | |
|---|
| 531 | |
|---|
| 532 | /* simd_all_true |
|---|
| 533 | * fw: 8*/ |
|---|
| 534 | template<int fw> |
|---|
| 535 | static inline int simd_all_true(SIMD_type r); |
|---|
| 536 | template<> |
|---|
| 537 | inline int simd_all_true<8>(SIMD_type r) { |
|---|
| 538 | return _mm_movemask_epi8(r) == 0xFFFF; |
|---|
| 539 | } |
|---|
| 540 | |
|---|
| 541 | /* simd_any_true |
|---|
| 542 | * fw: 8*/ |
|---|
| 543 | template<int fw> |
|---|
| 544 | static inline int simd_any_true(SIMD_type r); |
|---|
| 545 | template<> |
|---|
| 546 | inline int simd_any_true<8>(SIMD_type r) { |
|---|
| 547 | return _mm_movemask_epi8(r) != 0; |
|---|
| 548 | } |
|---|
| 549 | |
|---|
| 550 | /* simd_mask_true |
|---|
| 551 | * fw: 8*/ |
|---|
| 552 | template<int fw> |
|---|
| 553 | static inline int simd_mask_true(SIMD_type v, int mask_16_bit) { |
|---|
| 554 | return (_mm_movemask_epi8(v) & mask_16_bit) == mask_16_bit; |
|---|
| 555 | } |
|---|
| 556 | |
|---|
| 557 | /* simd_any_sign_bit |
|---|
| 558 | * fw: 8*/ |
|---|
| 559 | template<int fw> |
|---|
| 560 | static inline int simd_any_sign_bit(SIMD_type r); |
|---|
| 561 | template<> |
|---|
| 562 | inline int simd_any_sign_bit<8>(SIMD_type r) { |
|---|
| 563 | return _mm_movemask_epi8(r) != 0; |
|---|
| 564 | } |
|---|
| 565 | |
|---|
| 566 | |
|---|
| 567 | |
|---|
| 568 | /* IV. Half operand modifiers - implementations. */ |
|---|
| 569 | /* Half operand modifier functions.*/ |
|---|
| 570 | |
|---|
| 571 | template <int fw, HOM_t m> |
|---|
| 572 | struct SIMD { |
|---|
| 573 | static inline SIMD_type hom(SIMD_type r) {} |
|---|
| 574 | }; |
|---|
| 575 | |
|---|
| 576 | template <int fw> |
|---|
| 577 | struct SIMD<fw, x> { |
|---|
| 578 | static inline SIMD_type hom(SIMD_type r) {return r;} |
|---|
| 579 | static inline SIMD_type l2x(SIMD_type r) {return r;} |
|---|
| 580 | }; |
|---|
| 581 | |
|---|
| 582 | template <int fw> |
|---|
| 583 | struct SIMD<fw, l> { |
|---|
| 584 | static inline SIMD_type hom(SIMD_type r) {return simd_andc(r, simd<fw>::himask());} |
|---|
| 585 | static inline SIMD_type l2x(SIMD_type r) {return r;} |
|---|
| 586 | }; |
|---|
| 587 | |
|---|
| 588 | // Wish we could make this generic. |
|---|
| 589 | //template <int fw> |
|---|
| 590 | //struct SIMD<fw, h> { |
|---|
| 591 | // static inline SIMD_type hom(SIMD_type r) {return simd<fw>::srli<fw/2>(r);} |
|---|
| 592 | // static inline SIMD_type l2x(SIMD_type r) {return simd<fw>::srli<fw/2>(r);} |
|---|
| 593 | //}; |
|---|
| 594 | // |
|---|
| 595 | template <> |
|---|
| 596 | struct SIMD<2, h> { |
|---|
| 597 | static inline SIMD_type hom(SIMD_type r) {return simd<2>::srli<1>(r);} |
|---|
| 598 | static inline SIMD_type l2x(SIMD_type r) {return simd<2>::srli<1>(r);} |
|---|
| 599 | }; |
|---|
| 600 | |
|---|
| 601 | template <> |
|---|
| 602 | struct SIMD<4, h> { |
|---|
| 603 | static inline SIMD_type hom(SIMD_type r) {return simd<4>::srli<2>(r);} |
|---|
| 604 | static inline SIMD_type l2x(SIMD_type r) {return simd<4>::srli<2>(r);} |
|---|
| 605 | }; |
|---|
| 606 | |
|---|
| 607 | template <> |
|---|
| 608 | struct SIMD<8, h> { |
|---|
| 609 | static inline SIMD_type hom(SIMD_type r) {return simd<8>::srli<4>(r);} |
|---|
| 610 | static inline SIMD_type l2x(SIMD_type r) {return simd<8>::srli<4>(r);} |
|---|
| 611 | }; |
|---|
| 612 | |
|---|
| 613 | template <> |
|---|
| 614 | struct SIMD<16, h> { |
|---|
| 615 | static inline SIMD_type hom(SIMD_type r) {return simd<16>::srli<8>(r);} |
|---|
| 616 | static inline SIMD_type l2x(SIMD_type r) {return simd<16>::srli<8>(r);} |
|---|
| 617 | }; |
|---|
| 618 | |
|---|
| 619 | template <> |
|---|
| 620 | struct SIMD<32, h> { |
|---|
| 621 | static inline SIMD_type hom(SIMD_type r) {return simd<32>::srli<16>(r);} |
|---|
| 622 | static inline SIMD_type l2x(SIMD_type r) {return simd<32>::srli<16>(r);} |
|---|
| 623 | }; |
|---|
| 624 | |
|---|
| 625 | |
|---|
| 626 | /* SIMD operations extended with HOM*/ |
|---|
| 627 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 628 | inline SIMD_type simd<fw>::add(SIMD_type r1, SIMD_type r2){ |
|---|
| 629 | return simd<fw>::add(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2)); |
|---|
| 630 | } |
|---|
| 631 | |
|---|
| 632 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 633 | inline SIMD_type simd<fw>::sub(SIMD_type r1, SIMD_type r2){ |
|---|
| 634 | return simd<fw>::sub(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2)); |
|---|
| 635 | } |
|---|
| 636 | |
|---|
| 637 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 638 | inline SIMD_type simd<fw>::pack(SIMD_type r1, SIMD_type r2){ |
|---|
| 639 | return simd<fw>::pack(SIMD<fw,m1>::l2x(r1),SIMD<fw,m2>::l2x(r2)); |
|---|
| 640 | } |
|---|
| 641 | |
|---|
| 642 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 643 | inline SIMD_type simd<fw>::mergeh(SIMD_type r1, SIMD_type r2){ |
|---|
| 644 | return simd<fw>::mergeh(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2)); |
|---|
| 645 | } |
|---|
| 646 | |
|---|
| 647 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 648 | inline SIMD_type simd<fw>::mergel(SIMD_type r1, SIMD_type r2){ |
|---|
| 649 | return simd<fw>::mergel(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2)); |
|---|
| 650 | } |
|---|
| 651 | |
|---|
| 652 | template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 653 | inline SIMD_type simd<fw>::mult(SIMD_type r1, SIMD_type r2){ |
|---|
| 654 | return simd<fw>::mult(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2)); |
|---|
| 655 | } |
|---|
| 656 | |
|---|
| 657 | |
|---|
| 658 | // |
|---|
| 659 | //template <HOM_t m> |
|---|
| 660 | //struct HOM { |
|---|
| 661 | //template<int fw> SIMD_type hom(SIMD_type r) {return r;} |
|---|
| 662 | //template<int fw> SIMD_type l2x(SIMD_type r) {return r;} |
|---|
| 663 | //}; |
|---|
| 664 | // |
|---|
| 665 | //template <> |
|---|
| 666 | //template <int fw> |
|---|
| 667 | //SIMD_type HOM<l>::hom(SIMD_type r) {return simd_andc(r, simd<fw>::himask());} |
|---|
| 668 | // |
|---|
| 669 | //template <> |
|---|
| 670 | //template <int fw> |
|---|
| 671 | //SIMD_type HOM<h>::hom(SIMD_type r) {return simd<fw>::srli<fw/2>(r);} |
|---|
| 672 | // |
|---|
| 673 | //template <> |
|---|
| 674 | //template <int fw> |
|---|
| 675 | //SIMD_type HOM<h>::l2x(SIMD_type r) {return simd<fw>::srli<fw/2>(r);} |
|---|
| 676 | // |
|---|
| 677 | // |
|---|
| 678 | ///* SIMD operations extended with Half-Operand Modifiers */ |
|---|
| 679 | // |
|---|
| 680 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 681 | //inline SIMD_type simd<fw>::add(SIMD_type r1, SIMD_type r2){ |
|---|
| 682 | // return simd<fw>::add(HOM<m1>::hom<fw>, HOM<m2>::hom<fw>(r2)); |
|---|
| 683 | //} |
|---|
| 684 | // |
|---|
| 685 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 686 | //inline SIMD_type simd<fw>::sub(SIMD_type r1, SIMD_type r2){ |
|---|
| 687 | // return simd<fw>::sub(HOM<m1>::hom<fw>, HOM<m2>::hom<fw>(r2)); |
|---|
| 688 | //} |
|---|
| 689 | // |
|---|
| 690 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 691 | //inline SIMD_type simd<fw>::mult(SIMD_type r1, SIMD_type r2){ |
|---|
| 692 | // return simd<fw>::mult(HOM<m1>::hom<fw>, HOM<m2>::hom<fw>(r2)); |
|---|
| 693 | //} |
|---|
| 694 | // |
|---|
| 695 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 696 | //inline SIMD_type simd<fw>::pack(SIMD_type r1, SIMD_type r2){ |
|---|
| 697 | // return simd<fw>::pack(HOM<m1>::l2x<fw>, HOM<m2>::hom<fw>::hom(r2)); |
|---|
| 698 | //} |
|---|
| 699 | // |
|---|
| 700 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 701 | //inline SIMD_type simd<fw>::mergeh(SIMD_type r1, SIMD_type r2){ |
|---|
| 702 | // return simd<fw>::mergeh(HOM<m1>::hom<fw>, HOM<m2>::hom<fw>::hom(r2)); |
|---|
| 703 | //} |
|---|
| 704 | // |
|---|
| 705 | //template<int fw> template <HOM_t m1, HOM_t m2> |
|---|
| 706 | //inline SIMD_type simd<fw>::mergel(SIMD_type r1, SIMD_type r2){ |
|---|
| 707 | // return simd<fw>::mergel(HOM<m1>::hom<fw>, HOM<m2>::hom<fw>::hom(r2)); |
|---|
| 708 | //} |
|---|
| 709 | |
|---|
| 710 | /* V. sisd operations on full 128-bit register width. */ |
|---|
| 711 | |
|---|
| 712 | //struct sisd { |
|---|
| 713 | // template <int shft> inline SIMD_type slli(SIMD_type r) {return simd<128>::slli<shft>(r);} |
|---|
| 714 | // template <int shft> inline SIMD_type srli(SIMD_type r) {return simd<128>::srli<shft>(r);} |
|---|
| 715 | // inline SIMD_type sll(SIMD_type r, SIMD_type shft) {return simd<128>::sll<shft>(r, shft);} |
|---|
| 716 | // inline SIMD_type srl(SIMD_type r, SIMD_type shft) {return simd<128>::srl<shft>(r, shft);} |
|---|
| 717 | //}; |
|---|
| 718 | |
|---|
| 719 | |
|---|
| 720 | #define sisd_store_aligned(r, addr) _mm_store_si128(addr, r) |
|---|
| 721 | #define sisd_store_unaligned(r, addr) _mm_storeu_si128(addr, r) |
|---|
| 722 | #define sisd_load_aligned(addr) _mm_load_si128(addr) |
|---|
| 723 | #ifndef USE_LDDQU |
|---|
| 724 | #define sisd_load_unaligned(addr) _mm_loadu_si128(addr) |
|---|
| 725 | #endif |
|---|
| 726 | #ifdef USE_LDDQU |
|---|
| 727 | #define sisd_load_unaligned(addr) _mm_lddqu_si128(addr) |
|---|
| 728 | #endif |
|---|
| 729 | |
|---|
| 730 | |
|---|
| 731 | #define bitblock_test_bit(blk, n) \ |
|---|
| 732 | sisd_to_int(sisd_srli(sisd_slli(blk, ((BLOCKSIZE-1)-(n))), BLOCKSIZE-1)) |
|---|
| 733 | |
|---|
| 734 | |
|---|
| 735 | #if (BYTE_ORDER == BIG_ENDIAN) |
|---|
| 736 | void print_bit_block(const char * var_name, SIMD_type v) { |
|---|
| 737 | union {SIMD_type vec; unsigned char elems[8];} x; |
|---|
| 738 | x.vec = v; |
|---|
| 739 | unsigned char c, bit_reversed; |
|---|
| 740 | int i; |
|---|
| 741 | printf("%30s = ", var_name); |
|---|
| 742 | for (i = 0; i < sizeof(SIMD_type); i++) { |
|---|
| 743 | c = x.elems[i]; |
|---|
| 744 | printf("%02X ", c); |
|---|
| 745 | } |
|---|
| 746 | printf("\n"); |
|---|
| 747 | } |
|---|
| 748 | #endif |
|---|
| 749 | |
|---|
| 750 | #if (BYTE_ORDER == LITTLE_ENDIAN) |
|---|
| 751 | void print_bit_block(const char * var_name, SIMD_type v) { |
|---|
| 752 | union {SIMD_type vec; unsigned char elems[8];} x; |
|---|
| 753 | x.vec = v; |
|---|
| 754 | unsigned char c, bit_reversed; |
|---|
| 755 | int i; |
|---|
| 756 | printf("%30s = ", var_name); |
|---|
| 757 | for (i = sizeof(SIMD_type)-1; i >= 0; i--) { |
|---|
| 758 | c = x.elems[i]; |
|---|
| 759 | printf("%02X ", c); |
|---|
| 760 | } |
|---|
| 761 | printf("\n"); |
|---|
| 762 | } |
|---|
| 763 | #endif |
|---|
| 764 | |
|---|
| 765 | |
|---|
| 766 | static inline int bitblock_has_bit(SIMD_type v) { |
|---|
| 767 | return !simd_all_true<8>(simd<8>::eq(v, simd<8>::constant<0>())); |
|---|
| 768 | } |
|---|
| 769 | |
|---|
| 770 | static inline int bitblock_bit_count(SIMD_type v) { |
|---|
| 771 | int bit_count = 0; |
|---|
| 772 | SIMD_type cts_2 = simd<2>::add<l,h>(v, v); |
|---|
| 773 | SIMD_type cts_4 = simd<4>::add<l,h>(cts_2, cts_2); |
|---|
| 774 | SIMD_type cts_8 = simd<8>::add<l,h>(cts_4, cts_4); |
|---|
| 775 | SIMD_type cts_64 = _mm_sad_epu8(cts_8, simd<8>::constant<0>()); |
|---|
| 776 | /* SIMD_type cts_128 = simd<a28>::add<l,h>(cts_64, cts_64) */; |
|---|
| 777 | SIMD_type cts_128 = simd<64>::add(cts_64, simd<128>::srli<64>(cts_64)); |
|---|
| 778 | return (int) sisd_to_int(cts_128); |
|---|
| 779 | } |
|---|
| 780 | #endif |
|---|
| 781 | |
|---|