source: trunk/lib/sse_simd_t.h @ 182

Last change on this file since 182 was 182, checked in by lindanl, 11 years ago

Templated SIMD Library modifications

File size: 15.8 KB
Line 
1/*  Idealized SIMD Operations with SSE versions
2    Copyright (C) 2006, 2007, 2008, Robert D. Cameron
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#ifndef _MSC_VER
12#include <stdint.h>
13#endif
14#ifdef _MSC_VER
15#include "stdint.h"
16#define LITTLE_ENDIAN 1234
17#define BIG_ENDIAN 4321
18#define BYTE_ORDER LITTLE_ENDIAN
19#endif
20#include <limits.h>
21#ifndef LONG_BIT
22#define LONG_BIT (8* sizeof(unsigned long))
23#endif
24#include <emmintrin.h>
25#ifdef USE_LDDQU
26#include <pmmintrin.h>
27#endif
28typedef __m128i SIMD_type;
29/*------------------------------------------------------------*/
30/* I. SIMD bitwise logical operations */
31
32static inline SIMD_type simd_and(SIMD_type b1, SIMD_type b2) {
33        return _mm_and_si128(b1, b2);
34}
35static inline SIMD_type simd_andc(SIMD_type b1, SIMD_type b2) {
36        return _mm_andnot_si128(b2, b1);
37}
38static inline SIMD_type simd_or(SIMD_type b1, SIMD_type b2) {
39        return  _mm_or_si128(b1, b2);
40}
41static inline SIMD_type simd_xor(SIMD_type b1, SIMD_type b2) {
42        return  _mm_xor_si128(b1, b2);
43}
44static inline SIMD_type simd_not(SIMD_type b) {
45        return  simd_xor(b, _mm_set1_epi32(0xFFFFFFFF));
46}
47static inline SIMD_type simd_nor(SIMD_type b1, SIMD_type b2) {
48        return  simd_not(simd_or(b1,b2));
49}
50static inline SIMD_type simd_if(SIMD_type cond, SIMD_type then_val, SIMD_type else_val) {       
51        return  simd_or(simd_and(then_val, cond), simd_andc(else_val, cond));
52}
53
54/* Idealized operations with direct implementation by built-in
55   operations for various target architectures. */
56
57#define simd_mult_16(a, b) _mm_mullo_epi16(a, b)
58#define simd_sll_64(r, shft_reg) _mm_sll_epi64(r, shft_reg)
59#define simd_srl_64(r, shft_reg) _mm_srl_epi64(r, shft_reg)
60
61#define simd_max_8(a, b) _mm_max_epu8(a, b)
62
63//#define sisd_add(a, b) simd_add_128(a, b)
64//#define sisd_sub(a, b) simd_sub_128(a, b)
65
66#define sisd_store_aligned(r, addr) _mm_store_si128(addr, r)
67#define sisd_store_unaligned(r, addr) _mm_storeu_si128(addr, r)
68#define sisd_load_aligned(addr) _mm_load_si128(addr)
69#ifndef USE_LDDQU
70#define sisd_load_unaligned(addr) _mm_loadu_si128(addr)
71#endif
72#ifdef USE_LDDQU
73#define sisd_load_unaligned(addr) _mm_lddqu_si128(addr)
74#endif
75
76#define sisd_to_int(x) _mm_cvtsi128_si32(x)
77
78#define sisd_from_int(n) _mm_cvtsi32_si128(n)
79
80
81#define simd_all_eq_8(v1, v2) simd_all_true_8(_mm_cmpeq_epi8(v1, v2))
82#define simd_all_le_8(v1, v2) simd_all_eq_8(simd_max_8(v1, v2), v2)
83
84#define simd_all_signed_gt_8(v1, v2) simd_all_true_8(_mm_cmpgt_epi8(v1, v2))
85
86#define simd_cmpgt_8(v1,v2) _mm_cmpgt_epi8(v1, v2)
87
88#define bitblock_test_bit(blk, n) \
89   sisd_to_int(sisd_srli(sisd_slli(blk, ((BLOCKSIZE-1)-(n))), BLOCKSIZE-1))
90
91// Splat the first 16-bit int into all positions.
92static inline SIMD_type simd_splat_16(SIMD_type x) {
93  SIMD_type t = _mm_shufflelo_epi16(x,0);
94  return _mm_shuffle_epi32(t,0);
95}
96
97// Splat the first 32-bit int into all positions.
98static inline SIMD_type simd_splat_32(SIMD_type x) {
99  return _mm_shuffle_epi32(x,0);
100}
101
102
103void print_bit_block(char * var_name, SIMD_type v) {
104  union {SIMD_type vec; unsigned char elems[8];} x;
105  x.vec = v;
106  unsigned char c, bit_reversed;
107  int i;
108  printf("%20s = ", var_name);
109  for (i = 0; i < sizeof(SIMD_type); i++) {
110    c = x.elems[i];
111     printf("%02X ", c); 
112  }
113  printf("\n");
114}
115
116
117// Linda says that this is way too complex!
118//
119//#define SIMD_DEFINE(op, intrinsic, fw) \
120//template <int w> \
121//SIMD_type simd_ ## op (SIMD_type r1, SIMD_type r2); \
122//template <> \
123//SIMD_type simd_ ## op < fw > (SIMD_type r1, SIMD_type r2) {\
124//      return intrinsic ## fw(r1, r2);\
125//}
126//
127//#define SIMD_DEFINE_8_16_32(op, intrinsic)\
128//SIMD_DEFINE(op, intrinsic, 8) \
129//SIMD_DEFINE(op, intrinsic, 16)\
130//SIMD_DEFINE(op, intrinsic, 32)
131//
132//SIMD_DEFINE_8_16_32(sub, _mm_sub_epi)
133//SIMD_DEFINE_8_16_32(eq, _mm_cmpeq_epi)
134
135/* simd_himask
136 * fw: 2,4,8,16,32,64,128*/
137template<int fw>
138static inline SIMD_type simd_himask();
139
140template<>
141static inline SIMD_type simd_himask<2>() {
142        return _mm_set1_epi8(0xAA);
143}
144template<>
145static inline SIMD_type simd_himask<4>() {
146        return _mm_set1_epi8(0xCC);
147}
148template<>
149static inline SIMD_type simd_himask<8>() {
150        return _mm_set1_epi8(0xF0);
151}
152template<>
153static inline SIMD_type simd_himask<16>() {
154        return _mm_set1_epi16(0xFF00);
155}
156template<>
157static inline SIMD_type simd_himask<32>() {
158        return _mm_set1_epi32(0xFFFF0000);
159}
160template<>
161static inline SIMD_type simd_himask<64>() {
162        return _mm_set_epi32(-1,0,-1,0);
163}
164template<>
165static inline SIMD_type simd_himask<128>() {
166        return _mm_set_epi32(-1,-1,0,0);
167}
168
169/* simd_const
170 * fw: 2,4,8,16,32*/
171template<int fw>
172static inline SIMD_type simd_const(int n);
173template<>
174static inline SIMD_type simd_const<4>(int n) {
175        return _mm_set1_epi8((n)<<4|(n));
176}
177template<>
178static inline SIMD_type simd_const<8>(int n) {
179        return _mm_set1_epi8(n);
180}
181template<>
182static inline SIMD_type simd_const<16>(int n) {
183        return _mm_set1_epi16(n);
184}
185template<>
186static inline SIMD_type simd_const<32>(int n) {
187        return _mm_set1_epi32(n);
188}
189template<>
190static inline SIMD_type simd_const<1>(int n) {
191        if(n==0) return simd_const<8>(0);
192        else return simd_const<8>(-1);
193}
194template<>
195static inline SIMD_type simd_const<2>(int n) {
196        return simd_const<4>(n<<2|n);
197}
198
199template<int fw, int val>
200static inline SIMD_type simd_const();
201
202template<>
203static inline SIMD_type simd_const<1, 0>() {
204        return simd_const<8>(0);
205}
206
207template<>
208static inline SIMD_type simd_const<1, 1>() {
209        return simd_const<8>(-1);
210}
211
212
213/* simd_srli
214 * fw: 2,4,8,16,32,64*/
215template<int fw>
216static inline SIMD_type simd_srli(SIMD_type r, int sh);
217template<>
218static inline SIMD_type simd_srli<16>(SIMD_type r, int sh) {
219        return _mm_srli_epi16(r, sh);
220}
221template<>
222static inline SIMD_type simd_srli<32>(SIMD_type r, int sh) {
223        return _mm_srli_epi32(r, sh);
224}
225template<>
226static inline SIMD_type simd_srli<64>(SIMD_type r, int sh) {
227        return _mm_srli_epi64(r, sh);
228}
229template<>
230static inline SIMD_type simd_srli<2>(SIMD_type r, int sh) {
231        return simd_and(simd_srli<32>(r,sh),simd_const<2>(3>>sh));
232}
233template<>
234static inline SIMD_type simd_srli<4>(SIMD_type r, int sh) {
235        return simd_and(simd_srli<32>(r,sh),simd_const<4>(15>>sh));
236}
237template<>
238static inline SIMD_type simd_srli<8>(SIMD_type r, int sh) {
239        return simd_and(simd_srli<32>(r,sh),simd_const<8>(255>>sh));
240}
241
242/* simd_slli
243 * fw: 2,4,8,16,32,64*/
244template<int fw>
245static inline SIMD_type simd_slli(SIMD_type r, int sh);
246template<>
247static inline SIMD_type simd_slli<16>(SIMD_type r, int sh) {
248        return _mm_slli_epi16(r, sh);
249}
250template<>
251static inline SIMD_type simd_slli<32>(SIMD_type r, int sh) {
252        return _mm_slli_epi32(r, sh);
253}
254template<>
255static inline SIMD_type simd_slli<64>(SIMD_type r, int sh) {
256        return _mm_slli_epi64(r, sh);
257}
258template<>
259static inline SIMD_type simd_slli<2>(SIMD_type r, int sh) {
260        return simd_and(simd_slli<32>(r,sh),simd_const<2>((3<<sh)&3));
261}
262template<>
263static inline SIMD_type simd_slli<4>(SIMD_type r, int sh) {
264        return simd_and(simd_slli<32>(r,sh),simd_const<4>((15<<sh)&15));
265}
266template<>
267static inline SIMD_type simd_slli<8>(SIMD_type r, int sh) {
268        return simd_and(simd_slli<32>(r,sh),simd_const<8>((255<<sh) &255));
269}
270
271#define simd_slli_128(r, shft) \
272  ((shft) % 8 == 0 ? _mm_slli_si128(r, (shft)/8) : \
273   (shft) >= 64 ? simd_slli<64>(_mm_slli_si128(r, 8), (shft) - 64) : \
274   simd_or(simd_slli<64>(r, shft), _mm_slli_si128(simd_srli<64>(r, 64-(shft)), 8)))
275
276#define simd_srli_128(r, shft) \
277  ((shft) % 8 == 0 ? _mm_srli_si128(r, (shft)/8) : \
278   (shft) >= 64 ? simd_srli<64>(_mm_srli_si128(r, 8), (shft) - 64) : \
279   simd_or(simd_srli<64>(r, shft), _mm_srli_si128(simd_slli<64>(r, 64-(shft)), 8)))
280
281#define simd_sll_128(r, shft) \
282   simd_or(simd_sll_64(r, shft), \
283           simd_or(_mm_slli_si128(simd_sll_64(r, simd_sub<32>(shft, sisd_from_int(64))), 8), \
284                   _mm_slli_si128(simd_srl_64(r, simd_sub<32>(sisd_from_int(64), shft)), 8)))
285
286#define simd_srl_128(r, shft) \
287   simd_or(simd_srl_64(r, shft), \
288           simd_or(_mm_srli_si128(simd_srl_64(r, simd_sub<32>(shft, sisd_from_int(64))), 8), \
289                   _mm_srli_si128(simd_sll_64(r, simd_sub<32>(sisd_from_int(64), shft)), 8)))
290
291#define sisd_sll(r, shft) simd_sll_128(r, shft)
292#define sisd_srl(r, shft) simd_srl_128(r, shft)
293#define sisd_slli(r, shft) simd_slli_128(r, shft)
294#define sisd_srli(r, shft) simd_srli_128(r, shft)
295
296
297/* simd_srai
298 * fw: 16,32*/
299template<int fw>
300static inline SIMD_type simd_srai(SIMD_type r, int sh);
301template<>
302static inline SIMD_type simd_srai<16>(SIMD_type r, int sh) {
303        return _mm_srai_epi16(r, sh);
304}
305template<>
306static inline SIMD_type simd_srai<32>(SIMD_type r, int sh) {
307        return _mm_srai_epi32(r, sh);
308}
309                 
310/* simd_add
311 * fw: 2,4,8,16,32,64*/
312template<int fw>
313static inline SIMD_type simd_add(SIMD_type r1, SIMD_type r2);
314template<>
315static inline SIMD_type simd_add<2>(SIMD_type r1, SIMD_type r2) {
316         SIMD_type c1 = simd_xor(r1,r2);
317         SIMD_type borrow = simd_and(r1,r2);
318         SIMD_type c2 = simd_xor(c1,(sisd_slli(borrow,1)));
319         return simd_if(simd_himask<2>(),c2,c1);
320}
321template<>
322static inline SIMD_type simd_add<8>(SIMD_type r1, SIMD_type r2) {
323        return _mm_add_epi8(r1, r2);
324}
325template<>
326static inline SIMD_type simd_add<4>(SIMD_type r1, SIMD_type r2) {
327        return simd_if(simd_himask<8>(), simd_add<8>(simd_and(r1,simd_himask<8>()),simd_and(r2,simd_himask<8>()))
328        ,simd_add<8>(simd_andc(r1,simd_himask<8>()),simd_andc(r2,simd_himask<8>())));
329}
330template<>
331static inline SIMD_type simd_add<16>(SIMD_type r1, SIMD_type r2) {
332        return _mm_add_epi16(r1, r2);
333}
334template<>
335static inline SIMD_type simd_add<32>(SIMD_type r1, SIMD_type r2) {
336        return _mm_add_epi32(r1, r2);
337}
338template<>
339static inline SIMD_type simd_add<64>(SIMD_type r1, SIMD_type r2) {
340        return _mm_add_epi64(r1, r2);
341}
342/* simd_sub
343 * fw: 2,4,8,16,32,64*/
344template<int fw>
345static inline SIMD_type simd_sub(SIMD_type r1, SIMD_type r2);
346
347template<>
348static inline SIMD_type simd_sub<2>(SIMD_type r1, SIMD_type r2)
349{
350         SIMD_type c1 = simd_xor(r1,r2);
351         SIMD_type borrow = simd_andc(r2,r1);
352         SIMD_type c2 = simd_xor(c1,(sisd_slli(borrow,1)));
353         return simd_if(simd_himask<2>(),c2,c1);
354}
355template<>
356static inline SIMD_type simd_sub<8>(SIMD_type r1, SIMD_type r2) {
357        return _mm_sub_epi8(r1, r2);
358}
359template<>
360static inline SIMD_type simd_sub<4>(SIMD_type r1,SIMD_type r2){
361        return simd_if(simd_himask<8>(), simd_sub<8>(simd_and(r1,simd_himask<8>()),simd_and(r2,simd_himask<8>()))
362        ,simd_sub<8>(simd_andc(r1,simd_himask<8>()),simd_andc(r2,simd_himask<8>())));
363}
364template<>
365static inline SIMD_type simd_sub<16>(SIMD_type r1, SIMD_type r2) {
366        return _mm_sub_epi16(r1, r2);
367}
368template<>
369static inline SIMD_type simd_sub<32>(SIMD_type r1, SIMD_type r2) {
370        return _mm_sub_epi32(r1, r2);
371}
372template<>
373static inline SIMD_type simd_sub<64>(SIMD_type r1, SIMD_type r2) {
374        return _mm_sub_epi64(r1, r2);
375}
376/* simd_eq
377 * fw: 8,16,32*/
378template<int fw>
379static inline SIMD_type simd_eq(SIMD_type r1, SIMD_type r2);
380
381template<>
382static inline SIMD_type simd_eq<8>(SIMD_type r1, SIMD_type r2) {
383        return _mm_cmpeq_epi8(r1, r2);
384}
385template<>
386static inline SIMD_type simd_eq<16>(SIMD_type r1, SIMD_type r2) {
387        return _mm_cmpeq_epi16(r1, r2);
388}
389template<>
390static inline SIMD_type simd_eq<32>(SIMD_type r1, SIMD_type r2) {
391        return _mm_cmpeq_epi32(r1, r2);
392}
393
394enum HOM {x,h,l};
395
396
397/*simd_pack
398 * fw: 2,4,8,16*/
399template<int fw>
400static inline SIMD_type simd_pack(SIMD_type r1, SIMD_type r2){
401        /*fw:2,4,8*/
402        return simd_pack<fw*2>(simd_if(simd_himask<fw>(),sisd_srli(r1,fw/2),r1),simd_if(simd_himask<fw>(),sisd_srli(r2,fw/2),r2));
403}
404template<>
405static inline SIMD_type simd_pack<16>(SIMD_type r1, SIMD_type r2) {
406        return _mm_packus_epi16(simd_andc(r2, simd_himask<16>()), simd_andc(r1, simd_himask<16>()));
407}
408
409/* simd_mergeh
410 * fw: 1,2,4,8,16,32,64*/
411template<int fw>
412static inline SIMD_type simd_mergeh(SIMD_type r1, SIMD_type r2){
413        /*fw: 1,2,4*/
414        return simd_mergeh<fw*2>(simd_if(simd_himask<fw*2>(),r1,simd_srli<fw*2>(r2,fw)),
415        simd_if(simd_himask<fw*2>(),simd_slli<fw*2>(r1,fw),r2));
416}
417
418template<>
419static inline SIMD_type simd_mergeh<8>(SIMD_type r1, SIMD_type r2) {
420        return _mm_unpackhi_epi8(r2, r1);
421}
422template<>
423static inline SIMD_type simd_mergeh<16>(SIMD_type r1, SIMD_type r2) {
424        return _mm_unpackhi_epi16(r2, r1);
425}
426template<>
427static inline SIMD_type simd_mergeh<32>(SIMD_type r1, SIMD_type r2) {
428        return _mm_unpackhi_epi32(r2, r1);
429}
430template<>
431static inline SIMD_type simd_mergeh<64>(SIMD_type r1, SIMD_type r2) {
432        return _mm_unpackhi_epi64(r2, r1);
433}
434
435/* simd_mergel
436 * fw: 1,2,4,8,16,32,64*/
437template<int fw>
438static inline SIMD_type simd_mergel(SIMD_type r1, SIMD_type r2){
439        /*fw: 1,2,4*/
440        return simd_mergel<fw*2>(simd_if(simd_himask<fw*2>(),r1,simd_srli<fw*2>(r2,fw)),
441        simd_if(simd_himask<fw*2>(),simd_slli<fw*2>(r1,fw),r2));
442}
443template<>
444static inline SIMD_type simd_mergel<8>(SIMD_type r1, SIMD_type r2) {
445        return _mm_unpacklo_epi8(r2, r1);
446}
447template<>
448static inline SIMD_type simd_mergel<16>(SIMD_type r1, SIMD_type r2) {
449        return _mm_unpacklo_epi16(r2, r1);
450}
451template<>
452static inline SIMD_type simd_mergel<32>(SIMD_type r1, SIMD_type r2) {
453        return _mm_unpacklo_epi32(r2, r1);
454}
455template<>
456static inline SIMD_type simd_mergel<64>(SIMD_type r1, SIMD_type r2) {
457        return _mm_unpacklo_epi64(r2, r1);
458}
459
460
461/* simd_all_true
462 * fw: 8*/
463template<int fw>
464static inline int simd_all_true(SIMD_type r);
465template<>
466static inline int simd_all_true<8>(SIMD_type r) {
467        return _mm_movemask_epi8(r) == 0xFFFF;
468}
469
470/* simd_any_true
471 * fw: 8*/
472template<int fw>
473static inline int simd_any_true(SIMD_type r);
474template<>
475static inline int simd_any_true<8>(SIMD_type r) {
476        return _mm_movemask_epi8(r) != 0;
477}
478
479/* simd_any_sign_bit
480 * fw: 8*/
481template<int fw>
482static inline int simd_any_sign_bit(SIMD_type r);
483template<>
484static inline int simd_any_sign_bit<8>(SIMD_type r) {
485        return _mm_movemask_epi8(r) != 0;
486}
487
488/* Half operand modifier*/
489template <int fw, HOM m>
490struct SIMD {
491        static inline SIMD_type hom(SIMD_type r) {}
492};
493
494template <int fw>
495struct SIMD<fw, x> {
496        static inline SIMD_type hom(SIMD_type r) {return r;}
497        static inline SIMD_type hx(SIMD_type r) {return r;}
498};
499
500template <int fw>
501struct SIMD<fw, l> {
502        static inline SIMD_type hom(SIMD_type r) {return simd_andc(r, simd_himask<fw>());}
503        static inline SIMD_type hx(SIMD_type r) {return r;}
504};
505
506template <int fw>
507struct SIMD<fw, h> {
508        static inline SIMD_type hom(SIMD_type r) {return simd_srli<fw>(r, fw/2);}
509        static inline SIMD_type hx(SIMD_type r) {return simd_srli<fw>(r, fw/2);}
510};
511
512
513/* SIMD operations extended with HOM*/
514template<int fw, HOM m1, HOM m2>
515static inline SIMD_type simd_add(SIMD_type r1, SIMD_type r2){
516        return simd_add<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m1>::hom(r2));
517}
518
519template<int fw, HOM m1, HOM m2>
520static inline SIMD_type simd_sub(SIMD_type r1, SIMD_type r2){
521        return simd_sub<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
522}
523
524template<int fw, HOM m1, HOM m2>
525static inline SIMD_type simd_eq(SIMD_type r1, SIMD_type r2){
526        return simd_eq<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
527}
528
529template<int fw, HOM m1, HOM m2>
530static inline SIMD_type simd_pack(SIMD_type r1, SIMD_type r2){
531        return simd_pack<fw>(SIMD<fw,m1>::hx(r1),SIMD<fw,m2>::hx(r2));
532}
533
534template<int fw, HOM m1, HOM m2>
535static inline SIMD_type simd_mergeh(SIMD_type r1, SIMD_type r2){
536        return simd_mergeh<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
537}
538
539template<int fw, HOM m1, HOM m2>
540static inline SIMD_type simd_mergel(SIMD_type r1, SIMD_type r2){
541        return simd_mergel<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
542} 
543                 
544static inline int bitblock_has_bit(SIMD_type v) {
545  return !simd_all_true<8>(simd_eq<8>(v, simd_const<8>(0)));
546}
547
548static inline int bitblock_bit_count(SIMD_type v) {
549  int bit_count = 0;
550  SIMD_type cts_2 = simd_add<2,l,h>(v, v);
551  SIMD_type cts_4 = simd_add<4,l,h>(cts_2, cts_2);
552  SIMD_type cts_8 = simd_add<8,l,h>(cts_4, cts_4);
553  SIMD_type cts_64 = _mm_sad_epu8(cts_8, simd_const<8>(0));
554  /* SIMD_type cts_128 = simd_add_128_lh(cts_64, cts_64) */;
555  SIMD_type cts_128 = simd_add<64>(cts_64, sisd_srli(cts_64,64));
556  return (int) sisd_to_int(cts_128);
557}
558#endif
559
Note: See TracBrowser for help on using the repository browser.