source: trunk/lib/sse_simd_t.h @ 1516

Last change on this file since 1516 was 1228, checked in by vla24, 8 years ago

Integrated symbol table with xmlwf. There are various implementations for the symbol table, please read /proto/SymbolTable/README_SymbolTable for more information.

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