source: trunk/lib/sse_simd_t.h @ 1073

Last change on this file since 1073 was 736, checked in by ksherdy, 9 years ago

Add parallel prefix parity method, high bit mask, low bit mask, sisd_add/simd_add_128.

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