LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/opts - SkNx_sse.h (source / functions) Hit Total Coverage
Test: output.info Lines: 62 194 32.0 %
Date: 2017-07-14 16:53:18 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #ifndef SkNx_sse_DEFINED
       9             : #define SkNx_sse_DEFINED
      10             : 
      11             : #include <immintrin.h>
      12             : 
      13             : // This file may assume <= SSE2, but must check SK_CPU_SSE_LEVEL for anything more recent.
      14             : // If you do, make sure this is in a static inline function... anywhere else risks violating ODR.
      15             : 
      16             : namespace {
      17             : 
      18             : template <>
      19             : class SkNx<2, float> {
      20             : public:
      21      214011 :     AI SkNx(const __m128& vec) : fVec(vec) {}
      22             : 
      23        1394 :     AI SkNx() {}
      24        1432 :     AI SkNx(float val) : fVec(_mm_set1_ps(val)) {}
      25             :     AI static SkNx Load(const void* ptr) {
      26        8139 :         return _mm_castsi128_ps(_mm_loadl_epi64((const __m128i*)ptr));
      27             :     }
      28      111850 :     AI SkNx(float a, float b) : fVec(_mm_setr_ps(a,b,0,0)) {}
      29             : 
      30         558 :     AI void store(void* ptr) const { _mm_storel_pi((__m64*)ptr, fVec); }
      31             : 
      32        6756 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); }
      33        4584 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); }
      34        6180 :     AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); }
      35           0 :     AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); }
      36             : 
      37             :     AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); }
      38             :     AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); }
      39      304662 :     AI SkNx operator  < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); }
      40      304662 :     AI SkNx operator  > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); }
      41             :     AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); }
      42             :     AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); }
      43             : 
      44        3525 :     AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); }
      45        3525 :     AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); }
      46             : 
      47           0 :     AI SkNx   sqrt() const { return _mm_sqrt_ps (fVec);  }
      48             :     AI SkNx  rsqrt() const { return _mm_rsqrt_ps(fVec); }
      49             :     AI SkNx invert() const { return _mm_rcp_ps(fVec); }
      50             : 
      51             :     AI float operator[](int k) const {
      52           0 :         SkASSERT(0 <= k && k < 2);
      53           0 :         union { __m128 v; float fs[4]; } pun = {fVec};
      54           0 :         return pun.fs[k&1];
      55             :     }
      56             : 
      57             :     AI bool allTrue() const { return 0xff == (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); }
      58      609324 :     AI bool anyTrue() const { return 0x00 != (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); }
      59             : 
      60             :     __m128 fVec;
      61             : };
      62             : 
      63             : template <>
      64             : class SkNx<4, float> {
      65             : public:
      66       86576 :     AI SkNx(const __m128& vec) : fVec(vec) {}
      67             : 
      68         286 :     AI SkNx() {}
      69        7888 :     AI SkNx(float val)           : fVec( _mm_set1_ps(val) ) {}
      70       55063 :     AI SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {}
      71             : 
      72       13218 :     AI static SkNx Load(const void* ptr) { return _mm_loadu_ps((const float*)ptr); }
      73        5551 :     AI void store(void* ptr) const { _mm_storeu_ps((float*)ptr, fVec); }
      74             : 
      75             :     AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) {
      76           0 :         __m128 v0 = _mm_loadu_ps(((float*)ptr) +  0),
      77           0 :                v1 = _mm_loadu_ps(((float*)ptr) +  4),
      78           0 :                v2 = _mm_loadu_ps(((float*)ptr) +  8),
      79           0 :                v3 = _mm_loadu_ps(((float*)ptr) + 12);
      80           0 :         _MM_TRANSPOSE4_PS(v0, v1, v2, v3);
      81           0 :         *r = v0;
      82           0 :         *g = v1;
      83           0 :         *b = v2;
      84           0 :         *a = v3;
      85             :     }
      86             :     AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) {
      87           0 :         __m128 v0 = r.fVec,
      88           0 :                v1 = g.fVec,
      89           0 :                v2 = b.fVec,
      90           0 :                v3 = a.fVec;
      91           0 :         _MM_TRANSPOSE4_PS(v0, v1, v2, v3);
      92             :         _mm_storeu_ps(((float*) dst) +  0, v0);
      93           0 :         _mm_storeu_ps(((float*) dst) +  4, v1);
      94           0 :         _mm_storeu_ps(((float*) dst) +  8, v2);
      95           0 :         _mm_storeu_ps(((float*) dst) + 12, v3);
      96             :     }
      97             : 
      98      129903 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); }
      99        1905 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); }
     100       76038 :     AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); }
     101           0 :     AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); }
     102             : 
     103         858 :     AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); }
     104           0 :     AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); }
     105         243 :     AI SkNx operator  < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); }
     106           0 :     AI SkNx operator  > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); }
     107           0 :     AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); }
     108           0 :     AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); }
     109             : 
     110       11880 :     AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); }
     111       11880 :     AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); }
     112             : 
     113           0 :     AI SkNx abs() const { return _mm_andnot_ps(_mm_set1_ps(-0.0f), fVec); }
     114             :     AI SkNx floor() const {
     115             :     #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
     116           0 :         return _mm_floor_ps(fVec);
     117             :     #else
     118             :         // Emulate _mm_floor_ps() with SSE2:
     119             :         //   - roundtrip through integers via truncation
     120             :         //   - subtract 1 if that's too big (possible for negative values).
     121             :         // This restricts the domain of our inputs to a maximum somehwere around 2^31.
     122             :         // Seems plenty big.
     123           0 :         __m128 roundtrip = _mm_cvtepi32_ps(_mm_cvttps_epi32(fVec));
     124           0 :         __m128 too_big = _mm_cmpgt_ps(roundtrip, fVec);
     125           0 :         return _mm_sub_ps(roundtrip, _mm_and_ps(too_big, _mm_set1_ps(1.0f)));
     126             :     #endif
     127             :     }
     128             : 
     129           0 :     AI SkNx   sqrt() const { return _mm_sqrt_ps (fVec);  }
     130         486 :     AI SkNx  rsqrt() const { return _mm_rsqrt_ps(fVec); }
     131         243 :     AI SkNx invert() const { return _mm_rcp_ps(fVec); }
     132             : 
     133             :     AI float operator[](int k) const {
     134       37247 :         SkASSERT(0 <= k && k < 4);
     135       37247 :         union { __m128 v; float fs[4]; } pun = {fVec};
     136       37247 :         return pun.fs[k&3];
     137             :     }
     138             : 
     139         858 :     AI bool allTrue() const { return 0xffff == _mm_movemask_epi8(_mm_castps_si128(fVec)); }
     140             :     AI bool anyTrue() const { return 0x0000 != _mm_movemask_epi8(_mm_castps_si128(fVec)); }
     141             : 
     142             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     143             :     #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
     144           0 :         return _mm_blendv_ps(e.fVec, t.fVec, fVec);
     145             :     #else
     146         324 :         return _mm_or_ps(_mm_and_ps   (fVec, t.fVec),
     147         162 :                          _mm_andnot_ps(fVec, e.fVec));
     148             :     #endif
     149             :     }
     150             : 
     151             :     __m128 fVec;
     152             : };
     153             : 
     154             : template <>
     155             : class SkNx<4, int32_t> {
     156             : public:
     157        3836 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     158             : 
     159           0 :     AI SkNx() {}
     160           0 :     AI SkNx(int32_t val) : fVec(_mm_set1_epi32(val)) {}
     161        3362 :     AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
     162        3524 :     AI SkNx(int32_t a, int32_t b, int32_t c, int32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {}
     163             : 
     164           0 :     AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); }
     165             : 
     166        5043 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); }
     167           0 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); }
     168             :     AI SkNx operator * (const SkNx& o) const {
     169           0 :         __m128i mul20 = _mm_mul_epu32(fVec, o.fVec),
     170           0 :                 mul31 = _mm_mul_epu32(_mm_srli_si128(fVec, 4), _mm_srli_si128(o.fVec, 4));
     171           0 :         return _mm_unpacklo_epi32(_mm_shuffle_epi32(mul20, _MM_SHUFFLE(0,0,2,0)),
     172           0 :                                   _mm_shuffle_epi32(mul31, _MM_SHUFFLE(0,0,2,0)));
     173             :     }
     174             : 
     175           0 :     AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); }
     176           0 :     AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); }
     177           0 :     AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); }
     178             : 
     179           0 :     AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); }
     180           0 :     AI SkNx operator >> (int bits) const { return _mm_srai_epi32(fVec, bits); }
     181             : 
     182             :     AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); }
     183           0 :     AI SkNx operator  < (const SkNx& o) const { return _mm_cmplt_epi32 (fVec, o.fVec); }
     184             :     AI SkNx operator  > (const SkNx& o) const { return _mm_cmpgt_epi32 (fVec, o.fVec); }
     185             : 
     186             :     AI int32_t operator[](int k) const {
     187         243 :         SkASSERT(0 <= k && k < 4);
     188         243 :         union { __m128i v; int32_t is[4]; } pun = {fVec};
     189         243 :         return pun.is[k&3];
     190             :     }
     191             : 
     192             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     193             :     #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
     194             :         return _mm_blendv_epi8(e.fVec, t.fVec, fVec);
     195             :     #else
     196             :         return _mm_or_si128(_mm_and_si128   (fVec, t.fVec),
     197             :                             _mm_andnot_si128(fVec, e.fVec));
     198             :     #endif
     199             :     }
     200             : 
     201             :     __m128i fVec;
     202             : };
     203             : 
     204             : template <>
     205             : class SkNx<4, uint32_t> {
     206             : public:
     207           0 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     208             : 
     209             :     AI SkNx() {}
     210           0 :     AI SkNx(uint32_t val) : fVec(_mm_set1_epi32(val)) {}
     211           0 :     AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
     212             :     AI SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {}
     213             : 
     214             :     AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); }
     215             : 
     216             :     AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); }
     217           0 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); }
     218             :     // Not quite sure how to best do operator * in SSE2.  We probably don't use it.
     219             : 
     220           0 :     AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); }
     221             :     AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); }
     222             :     AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); }
     223             : 
     224             :     AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); }
     225           0 :     AI SkNx operator >> (int bits) const { return _mm_srli_epi32(fVec, bits); }
     226             : 
     227             :     AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); }
     228             :     // operator < and > take a little extra fiddling to make work for unsigned ints.
     229             : 
     230             :     AI uint32_t operator[](int k) const {
     231             :         SkASSERT(0 <= k && k < 4);
     232             :         union { __m128i v; uint32_t us[4]; } pun = {fVec};
     233             :         return pun.us[k&3];
     234             :     }
     235             : 
     236             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     237             :     #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
     238             :         return _mm_blendv_epi8(e.fVec, t.fVec, fVec);
     239             :     #else
     240             :         return _mm_or_si128(_mm_and_si128   (fVec, t.fVec),
     241             :                             _mm_andnot_si128(fVec, e.fVec));
     242             :     #endif
     243             :     }
     244             : 
     245             :     __m128i fVec;
     246             : };
     247             : 
     248             : 
     249             : template <>
     250             : class SkNx<4, uint16_t> {
     251             : public:
     252           0 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     253             : 
     254           0 :     AI SkNx() {}
     255           0 :     AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {}
     256             :     AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
     257           0 :         : fVec(_mm_setr_epi16(a,b,c,d,0,0,0,0)) {}
     258             : 
     259           0 :     AI static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); }
     260           0 :     AI void store(void* ptr) const { _mm_storel_epi64((__m128i*)ptr, fVec); }
     261             : 
     262             :     AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) {
     263           0 :         __m128i lo = _mm_loadu_si128(((__m128i*)ptr) + 0),
     264           0 :                 hi = _mm_loadu_si128(((__m128i*)ptr) + 1);
     265           0 :         __m128i even = _mm_unpacklo_epi16(lo, hi),   // r0 r2 g0 g2 b0 b2 a0 a2
     266           0 :                  odd = _mm_unpackhi_epi16(lo, hi);   // r1 r3 ...
     267           0 :         __m128i rg = _mm_unpacklo_epi16(even, odd),  // r0 r1 r2 r3 g0 g1 g2 g3
     268           0 :                 ba = _mm_unpackhi_epi16(even, odd);  // b0 b1 ...   a0 a1 ...
     269           0 :         *r = rg;
     270           0 :         *g = _mm_srli_si128(rg, 8);
     271           0 :         *b = ba;
     272           0 :         *a = _mm_srli_si128(ba, 8);
     273             :     }
     274             :     AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) {
     275             :         // The idea here is to get 4 vectors that are R G B _ _ _ _ _.
     276             :         // The second load is at a funny location to make sure we don't read past
     277             :         // the bounds of memory.  This is fine, we just need to shift it a little bit.
     278           0 :         const uint8_t* ptr8 = (const uint8_t*) ptr;
     279           0 :         __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 + 0));
     280           0 :         __m128i rgb1 = _mm_srli_si128(rgb0, 3*2);
     281           0 :         __m128i rgb2 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 4*2)), 2*2);
     282           0 :         __m128i rgb3 = _mm_srli_si128(rgb2, 3*2);
     283             : 
     284           0 :         __m128i rrggbb01 = _mm_unpacklo_epi16(rgb0, rgb1);
     285           0 :         __m128i rrggbb23 = _mm_unpacklo_epi16(rgb2, rgb3);
     286           0 :         *r = _mm_unpacklo_epi32(rrggbb01, rrggbb23);
     287           0 :         *g = _mm_srli_si128(r->fVec, 4*2);
     288           0 :         *b = _mm_unpackhi_epi32(rrggbb01, rrggbb23);
     289             :     }
     290             :     AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) {
     291           0 :         __m128i rg = _mm_unpacklo_epi16(r.fVec, g.fVec);
     292           0 :         __m128i ba = _mm_unpacklo_epi16(b.fVec, a.fVec);
     293           0 :         __m128i lo = _mm_unpacklo_epi32(rg, ba);
     294           0 :         __m128i hi = _mm_unpackhi_epi32(rg, ba);
     295             :         _mm_storeu_si128(((__m128i*) dst) + 0, lo);
     296           0 :         _mm_storeu_si128(((__m128i*) dst) + 1, hi);
     297             :     }
     298             : 
     299           0 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); }
     300             :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); }
     301             :     AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); }
     302           0 :     AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); }
     303           0 :     AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); }
     304             : 
     305           0 :     AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); }
     306           0 :     AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); }
     307             : 
     308             :     AI uint16_t operator[](int k) const {
     309           0 :         SkASSERT(0 <= k && k < 4);
     310           0 :         union { __m128i v; uint16_t us[8]; } pun = {fVec};
     311           0 :         return pun.us[k&3];
     312             :     }
     313             : 
     314             :     __m128i fVec;
     315             : };
     316             : 
     317             : template <>
     318             : class SkNx<8, uint16_t> {
     319             : public:
     320       87936 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     321             : 
     322             :     AI SkNx() {}
     323             :     AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {}
     324             :     AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
     325             :             uint16_t e, uint16_t f, uint16_t g, uint16_t h)
     326           0 :         : fVec(_mm_setr_epi16(a,b,c,d,e,f,g,h)) {}
     327             : 
     328             :     AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
     329             :     AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); }
     330             : 
     331             :     AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) {
     332             :         __m128i _01 = _mm_loadu_si128(((__m128i*)ptr) + 0),
     333             :                 _23 = _mm_loadu_si128(((__m128i*)ptr) + 1),
     334             :                 _45 = _mm_loadu_si128(((__m128i*)ptr) + 2),
     335             :                 _67 = _mm_loadu_si128(((__m128i*)ptr) + 3);
     336             : 
     337             :         __m128i _02 = _mm_unpacklo_epi16(_01, _23),  // r0 r2 g0 g2 b0 b2 a0 a2
     338             :                 _13 = _mm_unpackhi_epi16(_01, _23),  // r1 r3 g1 g3 b1 b3 a1 a3
     339             :                 _46 = _mm_unpacklo_epi16(_45, _67),
     340             :                 _57 = _mm_unpackhi_epi16(_45, _67);
     341             : 
     342             :         __m128i rg0123 = _mm_unpacklo_epi16(_02, _13),  // r0 r1 r2 r3 g0 g1 g2 g3
     343             :                 ba0123 = _mm_unpackhi_epi16(_02, _13),  // b0 b1 b2 b3 a0 a1 a2 a3
     344             :                 rg4567 = _mm_unpacklo_epi16(_46, _57),
     345             :                 ba4567 = _mm_unpackhi_epi16(_46, _57);
     346             : 
     347             :         *r = _mm_unpacklo_epi64(rg0123, rg4567);
     348             :         *g = _mm_unpackhi_epi64(rg0123, rg4567);
     349             :         *b = _mm_unpacklo_epi64(ba0123, ba4567);
     350             :         *a = _mm_unpackhi_epi64(ba0123, ba4567);
     351             :     }
     352             :     AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) {
     353             :         const uint8_t* ptr8 = (const uint8_t*) ptr;
     354             :         __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 +  0*2));
     355             :         __m128i rgb1 = _mm_srli_si128(rgb0, 3*2);
     356             :         __m128i rgb2 = _mm_loadu_si128((const __m128i*) (ptr8 +  6*2));
     357             :         __m128i rgb3 = _mm_srli_si128(rgb2, 3*2);
     358             :         __m128i rgb4 = _mm_loadu_si128((const __m128i*) (ptr8 + 12*2));
     359             :         __m128i rgb5 = _mm_srli_si128(rgb4, 3*2);
     360             :         __m128i rgb6 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 16*2)), 2*2);
     361             :         __m128i rgb7 = _mm_srli_si128(rgb6, 3*2);
     362             : 
     363             :         __m128i rgb01 = _mm_unpacklo_epi16(rgb0, rgb1);
     364             :         __m128i rgb23 = _mm_unpacklo_epi16(rgb2, rgb3);
     365             :         __m128i rgb45 = _mm_unpacklo_epi16(rgb4, rgb5);
     366             :         __m128i rgb67 = _mm_unpacklo_epi16(rgb6, rgb7);
     367             : 
     368             :         __m128i rg03 = _mm_unpacklo_epi32(rgb01, rgb23);
     369             :         __m128i bx03 = _mm_unpackhi_epi32(rgb01, rgb23);
     370             :         __m128i rg47 = _mm_unpacklo_epi32(rgb45, rgb67);
     371             :         __m128i bx47 = _mm_unpackhi_epi32(rgb45, rgb67);
     372             : 
     373             :         *r = _mm_unpacklo_epi64(rg03, rg47);
     374             :         *g = _mm_unpackhi_epi64(rg03, rg47);
     375             :         *b = _mm_unpacklo_epi64(bx03, bx47);
     376             :     }
     377             :     AI static void Store4(void* ptr, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) {
     378             :         __m128i rg0123 = _mm_unpacklo_epi16(r.fVec, g.fVec),  // r0 g0 r1 g1 r2 g2 r3 g3
     379             :                 rg4567 = _mm_unpackhi_epi16(r.fVec, g.fVec),  // r4 g4 r5 g5 r6 g6 r7 g7
     380             :                 ba0123 = _mm_unpacklo_epi16(b.fVec, a.fVec),
     381             :                 ba4567 = _mm_unpackhi_epi16(b.fVec, a.fVec);
     382             : 
     383             :         _mm_storeu_si128((__m128i*)ptr + 0, _mm_unpacklo_epi32(rg0123, ba0123));
     384             :         _mm_storeu_si128((__m128i*)ptr + 1, _mm_unpackhi_epi32(rg0123, ba0123));
     385             :         _mm_storeu_si128((__m128i*)ptr + 2, _mm_unpacklo_epi32(rg4567, ba4567));
     386             :         _mm_storeu_si128((__m128i*)ptr + 3, _mm_unpackhi_epi32(rg4567, ba4567));
     387             :     }
     388             : 
     389       43968 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); }
     390           0 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); }
     391       43968 :     AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); }
     392             :     AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); }
     393             :     AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); }
     394             : 
     395           0 :     AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); }
     396       43968 :     AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); }
     397             : 
     398             :     AI static SkNx Min(const SkNx& a, const SkNx& b) {
     399             :         // No unsigned _mm_min_epu16, so we'll shift into a space where we can use the
     400             :         // signed version, _mm_min_epi16, then shift back.
     401           0 :         const uint16_t top = 0x8000; // Keep this separate from _mm_set1_epi16 or MSVC will whine.
     402           0 :         const __m128i top_8x = _mm_set1_epi16(top);
     403           0 :         return _mm_add_epi8(top_8x, _mm_min_epi16(_mm_sub_epi8(a.fVec, top_8x),
     404           0 :                                                   _mm_sub_epi8(b.fVec, top_8x)));
     405             :     }
     406             : 
     407             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     408           0 :         return _mm_or_si128(_mm_and_si128   (fVec, t.fVec),
     409           0 :                             _mm_andnot_si128(fVec, e.fVec));
     410             :     }
     411             : 
     412             :     AI uint16_t operator[](int k) const {
     413           0 :         SkASSERT(0 <= k && k < 8);
     414           0 :         union { __m128i v; uint16_t us[8]; } pun = {fVec};
     415           0 :         return pun.us[k&7];
     416             :     }
     417             : 
     418             :     __m128i fVec;
     419             : };
     420             : 
     421             : template <>
     422             : class SkNx<4, uint8_t> {
     423             : public:
     424             :     AI SkNx() {}
     425       20768 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     426             :     AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
     427             :         : fVec(_mm_setr_epi8(a,b,c,d, 0,0,0,0, 0,0,0,0, 0,0,0,0)) {}
     428             : 
     429             : 
     430        1179 :     AI static SkNx Load(const void* ptr) { return _mm_cvtsi32_si128(*(const int*)ptr); }
     431       40750 :     AI void store(void* ptr) const { *(int*)ptr = _mm_cvtsi128_si32(fVec); }
     432             : 
     433             :     AI uint8_t operator[](int k) const {
     434           0 :         SkASSERT(0 <= k && k < 4);
     435           0 :         union { __m128i v; uint8_t us[16]; } pun = {fVec};
     436           0 :         return pun.us[k&3];
     437             :     }
     438             : 
     439             :     // TODO as needed
     440             : 
     441             :     __m128i fVec;
     442             : };
     443             : 
     444             : template <>
     445             : class SkNx<16, uint8_t> {
     446             : public:
     447       22760 :     AI SkNx(const __m128i& vec) : fVec(vec) {}
     448             : 
     449             :     AI SkNx() {}
     450        7500 :     AI SkNx(uint8_t val) : fVec(_mm_set1_epi8(val)) {}
     451             :     AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
     452             :     AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
     453             :             uint8_t e, uint8_t f, uint8_t g, uint8_t h,
     454             :             uint8_t i, uint8_t j, uint8_t k, uint8_t l,
     455             :             uint8_t m, uint8_t n, uint8_t o, uint8_t p)
     456             :         : fVec(_mm_setr_epi8(a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p)) {}
     457             : 
     458           0 :     AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); }
     459             : 
     460           0 :     AI SkNx saturatedAdd(const SkNx& o) const { return _mm_adds_epu8(fVec, o.fVec); }
     461             : 
     462       10992 :     AI SkNx operator + (const SkNx& o) const { return _mm_add_epi8(fVec, o.fVec); }
     463       10992 :     AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi8(fVec, o.fVec); }
     464             : 
     465             :     AI static SkNx Min(const SkNx& a, const SkNx& b) { return _mm_min_epu8(a.fVec, b.fVec); }
     466             :     AI SkNx operator < (const SkNx& o) const {
     467             :         // There's no unsigned _mm_cmplt_epu8, so we flip the sign bits then use a signed compare.
     468           0 :         auto flip = _mm_set1_epi8(char(0x80));
     469           0 :         return _mm_cmplt_epi8(_mm_xor_si128(flip, fVec), _mm_xor_si128(flip, o.fVec));
     470             :     }
     471             : 
     472             :     AI uint8_t operator[](int k) const {
     473             :         SkASSERT(0 <= k && k < 16);
     474             :         union { __m128i v; uint8_t us[16]; } pun = {fVec};
     475             :         return pun.us[k&15];
     476             :     }
     477             : 
     478             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     479           0 :         return _mm_or_si128(_mm_and_si128   (fVec, t.fVec),
     480           0 :                             _mm_andnot_si128(fVec, e.fVec));
     481             :     }
     482             : 
     483             :     __m128i fVec;
     484             : };
     485             : 
     486             : template<> AI /*static*/ Sk4f SkNx_cast<float, int32_t>(const Sk4i& src) {
     487        5043 :     return _mm_cvtepi32_ps(src.fVec);
     488             : }
     489             : template<> AI /*static*/ Sk4f SkNx_cast<float, uint32_t>(const Sk4u& src) {
     490           0 :     return SkNx_cast<float>(Sk4i::Load(&src));
     491             : }
     492             : 
     493             : template <> AI /*static*/ Sk4i SkNx_cast<int32_t, float>(const Sk4f& src) {
     494         243 :     return _mm_cvttps_epi32(src.fVec);
     495             : }
     496             : 
     497             : template<> AI /*static*/ Sk4h SkNx_cast<uint16_t, int32_t>(const Sk4i& src) {
     498             : #if 0 && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
     499             :     // TODO: This seems to be causing code generation problems.   Investigate?
     500             :     return _mm_packus_epi32(src.fVec);
     501             : #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
     502             :     // With SSSE3, we can just shuffle the low 2 bytes from each lane right into place.
     503           0 :     const int _ = ~0;
     504           0 :     return _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,1, 4,5, 8,9, 12,13, _,_,_,_,_,_,_,_));
     505             : #else
     506             :     // With SSE2, we have to sign extend our input, making _mm_packs_epi32 do the pack we want.
     507           0 :     __m128i x = _mm_srai_epi32(_mm_slli_epi32(src.fVec, 16), 16);
     508           0 :     return _mm_packs_epi32(x,x);
     509             : #endif
     510             : }
     511             : 
     512             : template<> AI /*static*/ Sk4h SkNx_cast<uint16_t, float>(const Sk4f& src) {
     513           0 :     return SkNx_cast<uint16_t>(SkNx_cast<int32_t>(src));
     514             : }
     515             : 
     516             : template<> AI /*static*/ Sk4b SkNx_cast<uint8_t, float>(const Sk4f& src) {
     517       40588 :     auto _32 = _mm_cvttps_epi32(src.fVec);
     518             : #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
     519           0 :     const int _ = ~0;
     520           0 :     return _mm_shuffle_epi8(_32, _mm_setr_epi8(0,4,8,12, _,_,_,_, _,_,_,_, _,_,_,_));
     521             : #else
     522       20294 :     auto _16 = _mm_packus_epi16(_32, _32);
     523       40588 :     return     _mm_packus_epi16(_16, _16);
     524             : #endif
     525             : }
     526             : 
     527             : template<> AI /*static*/ Sk4i SkNx_cast<int32_t, uint8_t>(const Sk4b& src) {
     528             : #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
     529           0 :     const int _ = ~0;
     530           0 :     return _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_));
     531             : #else
     532         786 :     auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128());
     533        1179 :     return _mm_unpacklo_epi16(_16, _mm_setzero_si128());
     534             : #endif
     535             : }
     536             : 
     537             : template<> AI /*static*/ Sk4f SkNx_cast<float, uint8_t>(const Sk4b& src) {
     538        1179 :     return _mm_cvtepi32_ps(SkNx_cast<int32_t>(src).fVec);
     539             : }
     540             : 
     541             : template<> AI /*static*/ Sk4f SkNx_cast<float, uint16_t>(const Sk4h& src) {
     542           0 :     auto _32 = _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128());
     543           0 :     return _mm_cvtepi32_ps(_32);
     544             : }
     545             : 
     546             : template<> AI /*static*/ Sk16b SkNx_cast<uint8_t, float>(const Sk16f& src) {
     547             :     Sk8f ab, cd;
     548             :     SkNx_split(src, &ab, &cd);
     549             : 
     550             :     Sk4f a,b,c,d;
     551             :     SkNx_split(ab, &a, &b);
     552             :     SkNx_split(cd, &c, &d);
     553             : 
     554           0 :     return _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec),
     555             :                                              _mm_cvttps_epi32(b.fVec)),
     556             :                             _mm_packus_epi16(_mm_cvttps_epi32(c.fVec),
     557           0 :                                              _mm_cvttps_epi32(d.fVec)));
     558             : }
     559             : 
     560             : template<> AI /*static*/ Sk4h SkNx_cast<uint16_t, uint8_t>(const Sk4b& src) {
     561           0 :     return _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128());
     562             : }
     563             : 
     564             : template<> AI /*static*/ Sk4b SkNx_cast<uint8_t, uint16_t>(const Sk4h& src) {
     565           0 :     return _mm_packus_epi16(src.fVec, src.fVec);
     566             : }
     567             : 
     568             : template<> AI /*static*/ Sk4i SkNx_cast<int32_t, uint16_t>(const Sk4h& src) {
     569           0 :     return _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128());
     570             : }
     571             : 
     572             : template<> AI /*static*/ Sk4b SkNx_cast<uint8_t, int32_t>(const Sk4i& src) {
     573         324 :     return _mm_packus_epi16(_mm_packus_epi16(src.fVec, src.fVec), src.fVec);
     574             : }
     575             : 
     576             : template<> AI /*static*/ Sk4i SkNx_cast<int32_t, uint32_t>(const Sk4u& src) {
     577             :     return src.fVec;
     578             : }
     579             : 
     580             : AI static Sk4i Sk4f_round(const Sk4f& x) {
     581           0 :     return _mm_cvtps_epi32(x.fVec);
     582             : }
     583             : 
     584             : }  // namespace
     585             : 
     586             : #endif//SkNx_sse_DEFINED

Generated by: LCOV version 1.13