source: trunk/lib/sse_simd_t.h @ 179

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

Templated SIMD Library - initial version

File size: 14.9 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
32#define simd_or(b1, b2) _mm_or_si128(b1, b2)
33#define simd_and(b1, b2) _mm_and_si128(b1, b2)
34#define simd_xor(b1, b2) _mm_xor_si128(b1, b2)
35
36static inline SIMD_type simd_andc(SIMD_type b1, SIMD_type b2) {
37        return _mm_andnot_si128(b2, b1);
38}
39#define simd_if(cond, then_val, else_val) \
40  simd_or(simd_and(then_val, cond), simd_andc(else_val, cond))
41#define simd_not(b) (simd_xor(b, _mm_set1_epi32(0xFFFFFFFF)))
42#define simd_nor(a,b) (simd_not(simd_or(a,b)))
43
44/* Idealized operations with direct implementation by built-in
45   operations for various target architectures. */
46
47#define simd_mult_16(a, b) _mm_mullo_epi16(a, b)
48#define simd_sll_64(r, shft_reg) _mm_sll_epi64(r, shft_reg)
49#define simd_srl_64(r, shft_reg) _mm_srl_epi64(r, shft_reg)
50
51#define simd_max_8(a, b) _mm_max_epu8(a, b)
52
53//#define sisd_add(a, b) simd_add_128(a, b)
54//#define sisd_sub(a, b) simd_sub_128(a, b)
55
56#define sisd_store_aligned(r, addr) _mm_store_si128(addr, r)
57#define sisd_store_unaligned(r, addr) _mm_storeu_si128(addr, r)
58#define sisd_load_aligned(addr) _mm_load_si128(addr)
59#ifndef USE_LDDQU
60#define sisd_load_unaligned(addr) _mm_loadu_si128(addr)
61#endif
62#ifdef USE_LDDQU
63#define sisd_load_unaligned(addr) _mm_lddqu_si128(addr)
64#endif
65
66#define sisd_to_int(x) _mm_cvtsi128_si32(x)
67
68#define sisd_from_int(n) _mm_cvtsi32_si128(n)
69
70
71#define simd_all_eq_8(v1, v2) simd_all_true_8(_mm_cmpeq_epi8(v1, v2))
72#define simd_all_le_8(v1, v2) simd_all_eq_8(simd_max_8(v1, v2), v2)
73
74#define simd_all_signed_gt_8(v1, v2) simd_all_true_8(_mm_cmpgt_epi8(v1, v2))
75
76#define simd_cmpgt_8(v1,v2) _mm_cmpgt_epi8(v1, v2)
77
78#define simd_himask_16 _mm_set1_epi16(0xFF00)
79#define simd_slli_16(r, shft) _mm_slli_epi16(r, shft)
80#define simd_srli_16(r, shft) _mm_srli_epi16(r, shft)
81#define simd_pack_16(a, b) \
82  _mm_packus_epi16(simd_andc(b, simd_himask_16), simd_andc(a, simd_himask_16))
83#define simd_pack_16_ll(a, b) simd_pack_16(a, b)
84#define simd_pack_16_hh(a, b) \
85  simd_pack_16(simd_srli_16(a, 8), simd_srli_16(b, 8))
86
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>
138inline SIMD_type simd_himask();
139
140template<>
141inline SIMD_type simd_himask<2>() {
142        return _mm_set1_epi8(0xAA);
143}
144template<>
145inline SIMD_type simd_himask<4>() {
146        return _mm_set1_epi8(0xCC);
147}
148template<>
149inline SIMD_type simd_himask<8>() {
150        return _mm_set1_epi8(0xF0);
151}
152template<>
153inline SIMD_type simd_himask<16>() {
154        return _mm_set1_epi16(0xFF00);
155}
156template<>
157inline SIMD_type simd_himask<32>() {
158        return _mm_set1_epi32(0xFFFF0000);
159}
160template<>
161inline SIMD_type simd_himask<64>() {
162        return _mm_set_epi32(-1,0,-1,0);
163}
164template<>
165inline 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>
172inline SIMD_type simd_const(int n);
173template<>
174inline SIMD_type simd_const<4>(int n) {
175        return _mm_set1_epi8((n)<<4|(n));
176}
177template<>
178inline SIMD_type simd_const<8>(int n) {
179        return _mm_set1_epi8(n);
180}
181template<>
182inline SIMD_type simd_const<16>(int n) {
183        return _mm_set1_epi16(n);
184}
185template<>
186inline SIMD_type simd_const<32>(int n) {
187        return _mm_set1_epi32(n);
188}
189template<>
190inline 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<>
195inline SIMD_type simd_const<2>(int n) {
196        return simd_const<4>(n<<2|n);
197}
198
199template<int fw, int val>
200inline SIMD_type simd_const();
201
202template<>
203inline SIMD_type simd_const<1, 0>() {
204        return simd_const<8>(0);
205}
206
207template<>
208inline 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>
216inline SIMD_type simd_srli(SIMD_type r, int sh);
217template<>
218inline SIMD_type simd_srli<16>(SIMD_type r, int sh) {
219        return _mm_srli_epi16(r, sh);
220}
221template<>
222inline SIMD_type simd_srli<32>(SIMD_type r, int sh) {
223        return _mm_srli_epi32(r, sh);
224}
225template<>
226inline SIMD_type simd_srli<64>(SIMD_type r, int sh) {
227        return _mm_srli_epi64(r, sh);
228}
229template<>
230inline 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<>
234inline 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<>
238inline 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>
245inline SIMD_type simd_slli(SIMD_type r, int sh);
246template<>
247inline SIMD_type simd_slli<16>(SIMD_type r, int sh) {
248        return _mm_slli_epi16(r, sh);
249}
250template<>
251inline SIMD_type simd_slli<32>(SIMD_type r, int sh) {
252        return _mm_slli_epi32(r, sh);
253}
254template<>
255inline SIMD_type simd_slli<64>(SIMD_type r, int sh) {
256        return _mm_slli_epi64(r, sh);
257}
258template<>
259inline 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<>
263inline 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<>
267inline 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>
300inline SIMD_type simd_srai(SIMD_type r, int sh);
301template<>
302inline SIMD_type simd_srai<16>(SIMD_type r, int sh) {
303        return _mm_srai_epi16(r, sh);
304}
305template<>
306inline 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>
313inline SIMD_type simd_add(SIMD_type r1, SIMD_type r2);
314template<>
315inline 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<>
322inline SIMD_type simd_add<8>(SIMD_type r1, SIMD_type r2) {
323        return _mm_add_epi8(r1, r2);
324}
325template<>
326inline 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<>
331inline SIMD_type simd_add<16>(SIMD_type r1, SIMD_type r2) {
332        return _mm_add_epi16(r1, r2);
333}
334template<>
335inline SIMD_type simd_add<32>(SIMD_type r1, SIMD_type r2) {
336        return _mm_add_epi32(r1, r2);
337}
338template<>
339inline SIMD_type simd_add<64>(SIMD_type r1, SIMD_type r2) {
340        return _mm_add_epi64(r1, r2);
341}
342/* simd_sub
343 * fw: 8,16,32,64*/
344template<int fw>
345inline SIMD_type simd_sub(SIMD_type r1, SIMD_type r2);
346
347template<>
348inline SIMD_type simd_sub<8>(SIMD_type r1, SIMD_type r2) {
349        return _mm_sub_epi8(r1, r2);
350}
351template<>
352inline SIMD_type simd_sub<16>(SIMD_type r1, SIMD_type r2) {
353        return _mm_sub_epi16(r1, r2);
354}
355template<>
356inline SIMD_type simd_sub<32>(SIMD_type r1, SIMD_type r2) {
357        return _mm_sub_epi32(r1, r2);
358}
359template<>
360inline SIMD_type simd_sub<64>(SIMD_type r1, SIMD_type r2) {
361        return _mm_sub_epi64(r1, r2);
362}
363/* simd_eq
364 * fw: 8,16,32*/
365template<int fw>
366inline SIMD_type simd_eq(SIMD_type r1, SIMD_type r2);
367
368template<>
369inline SIMD_type simd_eq<8>(SIMD_type r1, SIMD_type r2) {
370        return _mm_cmpeq_epi8(r1, r2);
371}
372template<>
373inline SIMD_type simd_eq<16>(SIMD_type r1, SIMD_type r2) {
374        return _mm_cmpeq_epi16(r1, r2);
375}
376template<>
377inline SIMD_type simd_eq<32>(SIMD_type r1, SIMD_type r2) {
378        return _mm_cmpeq_epi32(r1, r2);
379}
380
381enum HOM {x,h,l};
382
383
384/*simd_pack
385 * fw: 2,4,8,16*/
386template<int fw>
387static inline SIMD_type simd_pack(SIMD_type r1, SIMD_type r2){
388        /*fw:2,4,8*/
389        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));
390}
391template<>
392static inline SIMD_type simd_pack<16>(SIMD_type r1, SIMD_type r2) {
393        return _mm_packus_epi16(simd_andc(r2, simd_himask<16>()), simd_andc(r1, simd_himask<16>()));
394}
395
396/* simd_mergeh
397 * fw: 1,2,4,8,16,32,64*/
398template<int fw>
399inline SIMD_type simd_mergeh(SIMD_type r1, SIMD_type r2){
400        /*fw: 1,2,4*/
401        return simd_mergeh<fw*2>(simd_if(simd_himask<fw*2>(),r1,simd_srli<fw*2>(r2,fw)),
402        simd_if(simd_himask<fw*2>(),simd_slli<fw*2>(r1,fw),r2));
403}
404
405template<>
406inline SIMD_type simd_mergeh<8>(SIMD_type r1, SIMD_type r2) {
407        return _mm_unpackhi_epi8(r2, r1);
408}
409template<>
410inline SIMD_type simd_mergeh<16>(SIMD_type r1, SIMD_type r2) {
411        return _mm_unpackhi_epi16(r2, r1);
412}
413template<>
414inline SIMD_type simd_mergeh<32>(SIMD_type r1, SIMD_type r2) {
415        return _mm_unpackhi_epi32(r2, r1);
416}
417template<>
418inline SIMD_type simd_mergeh<64>(SIMD_type r1, SIMD_type r2) {
419        return _mm_unpackhi_epi64(r2, r1);
420}
421
422/* simd_mergel
423 * fw: 1,2,4,8,16,32,64*/
424template<int fw>
425inline SIMD_type simd_mergel(SIMD_type r1, SIMD_type r2){
426        /*fw: 1,2,4*/
427        return simd_mergel<fw*2>(simd_if(simd_himask<fw*2>(),r1,simd_srli<fw*2>(r2,fw)),
428        simd_if(simd_himask<fw*2>(),simd_slli<fw*2>(r1,fw),r2));
429}
430template<>
431inline SIMD_type simd_mergel<8>(SIMD_type r1, SIMD_type r2) {
432        return _mm_unpacklo_epi8(r2, r1);
433}
434template<>
435inline SIMD_type simd_mergel<16>(SIMD_type r1, SIMD_type r2) {
436        return _mm_unpacklo_epi16(r2, r1);
437}
438template<>
439inline SIMD_type simd_mergel<32>(SIMD_type r1, SIMD_type r2) {
440        return _mm_unpacklo_epi32(r2, r1);
441}
442template<>
443inline SIMD_type simd_mergel<64>(SIMD_type r1, SIMD_type r2) {
444        return _mm_unpacklo_epi64(r2, r1);
445}
446
447
448/* simd_all_true
449 * fw: 8*/
450template<int fw>
451inline int simd_all_true(SIMD_type r);
452template<>
453inline int simd_all_true<8>(SIMD_type r) {
454        return _mm_movemask_epi8(r) == 0xFFFF;
455}
456
457/* simd_any_true
458 * fw: 8*/
459template<int fw>
460inline int simd_any_true(SIMD_type r);
461template<>
462inline int simd_any_true<8>(SIMD_type r) {
463        return _mm_movemask_epi8(r) != 0;
464}
465
466/* simd_any_sign_bit
467 * fw: 8*/
468template<int fw>
469inline int simd_any_sign_bit(SIMD_type r);
470template<>
471inline int simd_any_sign_bit<8>(SIMD_type r) {
472        return _mm_movemask_epi8(r) != 0;
473}
474
475/* Half operand modifier*/
476template <int fw, HOM m>
477struct SIMD {
478        static inline SIMD_type hom(SIMD_type r) {}
479};
480
481template <int fw>
482struct SIMD<fw, x> {
483        static inline SIMD_type hom(SIMD_type r) {return r;}
484        static inline SIMD_type hx(SIMD_type r) {return r;}
485};
486
487template <int fw>
488struct SIMD<fw, l> {
489        static inline SIMD_type hom(SIMD_type r) {return simd_andc(r, simd_himask<fw>());}
490        static inline SIMD_type hx(SIMD_type r) {return r;}
491};
492
493template <int fw>
494struct SIMD<fw, h> {
495        static inline SIMD_type hom(SIMD_type r) {return simd_srli<fw>(r, fw/2);}
496        static inline SIMD_type hx(SIMD_type r) {return simd_srli<fw>(r, fw/2);}
497};
498
499
500/* SIMD operations extended with HOM*/
501template<int fw, HOM m1, HOM m2>
502inline SIMD_type simd_add(SIMD_type r1, SIMD_type r2){
503        return simd_add<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m1>::hom(r2));
504}
505
506template<int fw, HOM m1, HOM m2>
507inline SIMD_type simd_sub(SIMD_type r1, SIMD_type r2){
508        return simd_sub<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
509}
510
511template<int fw, HOM m1, HOM m2>
512inline SIMD_type simd_eq(SIMD_type r1, SIMD_type r2){
513        return simd_eq<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
514}
515
516template<int fw, HOM m1, HOM m2>
517static inline SIMD_type simd_pack(SIMD_type r1, SIMD_type r2){
518        return simd_pack<fw>(SIMD<fw,m1>::hx(r1),SIMD<fw,m2>::hx(r2));
519}
520
521template<int fw, HOM m1, HOM m2>
522inline SIMD_type simd_mergeh(SIMD_type r1, SIMD_type r2){
523        return simd_mergeh<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
524}
525
526template<int fw, HOM m1, HOM m2>
527inline SIMD_type simd_mergel(SIMD_type r1, SIMD_type r2){
528        return simd_mergel<fw>(SIMD<fw,m1>::hom(r1),SIMD<fw,m2>::hom(r2));
529} 
530                 
531static inline int bitblock_has_bit(SIMD_type v) {
532  return !simd_all_true<8>(simd_eq<8>(v, simd_const<8>(0)));
533}
534
535static inline int bitblock_bit_count(SIMD_type v) {
536  int bit_count = 0;
537  SIMD_type cts_2 = simd_add<2,l,h>(v, v);
538  SIMD_type cts_4 = simd_add<4,l,h>(cts_2, cts_2);
539  SIMD_type cts_8 = simd_add<8,l,h>(cts_4, cts_4);
540  SIMD_type cts_64 = _mm_sad_epu8(cts_8, simd_const<8>(0));
541  /* SIMD_type cts_128 = simd_add_128_lh(cts_64, cts_64) */;
542  SIMD_type cts_128 = simd_add<64>(cts_64, sisd_srli(cts_64,64));
543  return (int) sisd_to_int(cts_128);
544}
545#endif
546
Note: See TracBrowser for help on using the repository browser.