LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkNx.h (source / functions) Hit Total Coverage
Test: output.info Lines: 10 43 23.3 %
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_DEFINED
       9             : #define SkNx_DEFINED
      10             : 
      11             : #include "SkSafe_math.h"
      12             : #include "SkScalar.h"
      13             : #include "SkTypes.h"
      14             : #include <limits>
      15             : #include <type_traits>
      16             : 
      17             : // Every single SkNx method wants to be fully inlined.  (We know better than MSVC).
      18             : #define AI SK_ALWAYS_INLINE
      19             : 
      20             : namespace {
      21             : 
      22             : // The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>.
      23             : template <int N, typename T>
      24             : struct SkNx {
      25             :     typedef SkNx<N/2, T> Half;
      26             : 
      27             :     Half fLo, fHi;
      28             : 
      29           0 :     AI SkNx() = default;
      30       43968 :     AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {}
      31             : 
      32             :     AI SkNx(T v) : fLo(v), fHi(v) {}
      33             : 
      34             :     AI SkNx(T a, T b)           : fLo(a)  , fHi(b)   { static_assert(N==2, ""); }
      35             :     AI SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); }
      36             :     AI SkNx(T a, T b, T c, T d,  T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) {
      37             :         static_assert(N==8, "");
      38             :     }
      39             :     AI SkNx(T a, T b, T c, T d,  T e, T f, T g, T h,
      40             :             T i, T j, T k, T l,  T m, T n, T o, T p)
      41             :         : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) {
      42             :         static_assert(N==16, "");
      43             :     }
      44             : 
      45             :     AI T operator[](int k) const {
      46           0 :         SkASSERT(0 <= k && k < N);
      47           0 :         return k < N/2 ? fLo[k] : fHi[k-N/2];
      48             :     }
      49             : 
      50             :     AI static SkNx Load(const void* vptr) {
      51           0 :         auto ptr = (const char*)vptr;
      52           0 :         return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) };
      53             :     }
      54             :     AI void store(void* vptr) const {
      55           0 :         auto ptr = (char*)vptr;
      56           0 :         fLo.store(ptr);
      57           0 :         fHi.store(ptr + N/2*sizeof(T));
      58             :     }
      59             : 
      60             :     AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
      61             :         auto ptr = (const char*)vptr;
      62             :         Half al, bl, cl, dl,
      63             :              ah, bh, ch, dh;
      64             :         Half::Load4(ptr                  , &al, &bl, &cl, &dl);
      65             :         Half::Load4(ptr + 4*N/2*sizeof(T), &ah, &bh, &ch, &dh);
      66             :         *a = SkNx{al, ah};
      67             :         *b = SkNx{bl, bh};
      68             :         *c = SkNx{cl, ch};
      69             :         *d = SkNx{dl, dh};
      70             :     }
      71             :     AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
      72             :         auto ptr = (const char*)vptr;
      73             :         Half al, bl, cl,
      74             :              ah, bh, ch;
      75             :         Half::Load3(ptr                  , &al, &bl, &cl);
      76             :         Half::Load3(ptr + 3*N/2*sizeof(T), &ah, &bh, &ch);
      77             :         *a = SkNx{al, ah};
      78             :         *b = SkNx{bl, bh};
      79             :         *c = SkNx{cl, ch};
      80             :     }
      81             :     AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
      82             :         auto ptr = (char*)vptr;
      83             :         Half::Store4(ptr,                   a.fLo, b.fLo, c.fLo, d.fLo);
      84             :         Half::Store4(ptr + 4*N/2*sizeof(T), a.fHi, b.fHi, c.fHi, d.fHi);
      85             :     }
      86             : 
      87             :     AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
      88             :     AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
      89             : 
      90             :     AI SkNx    abs() const { return { fLo.   abs(), fHi.   abs() }; }
      91             :     AI SkNx   sqrt() const { return { fLo.  sqrt(), fHi.  sqrt() }; }
      92             :     AI SkNx  rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; }
      93             :     AI SkNx  floor() const { return { fLo. floor(), fHi. floor() }; }
      94             :     AI SkNx invert() const { return { fLo.invert(), fHi.invert() }; }
      95             : 
      96             :     AI SkNx operator!() const { return { !fLo, !fHi }; }
      97             :     AI SkNx operator-() const { return { -fLo, -fHi }; }
      98             :     AI SkNx operator~() const { return { ~fLo, ~fHi }; }
      99             : 
     100           0 :     AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; }
     101       29312 :     AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; }
     102             : 
     103       29312 :     AI SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; }
     104           0 :     AI SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; }
     105       29312 :     AI SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; }
     106             :     AI SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; }
     107             : 
     108             :     AI SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; }
     109             :     AI SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; }
     110             :     AI SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; }
     111             : 
     112             :     AI SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; }
     113             :     AI SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; }
     114             :     AI SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; }
     115             :     AI SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; }
     116             :     AI SkNx operator< (const SkNx& y) const { return { fLo <  y.fLo, fHi <  y.fHi }; }
     117             :     AI SkNx operator> (const SkNx& y) const { return { fLo >  y.fLo, fHi >  y.fHi }; }
     118             : 
     119             :     AI SkNx saturatedAdd(const SkNx& y) const {
     120             :         return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) };
     121             :     }
     122             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
     123           0 :         return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) };
     124             :     }
     125             : 
     126             :     AI static SkNx Min(const SkNx& x, const SkNx& y) {
     127           0 :         return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) };
     128             :     }
     129             :     AI static SkNx Max(const SkNx& x, const SkNx& y) {
     130             :         return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) };
     131             :     }
     132             : };
     133             : 
     134             : // The N -> N/2 recursion bottoms out at N == 1, a scalar value.
     135             : template <typename T>
     136             : struct SkNx<1,T> {
     137             :     T fVal;
     138             : 
     139             :     AI SkNx() = default;
     140             :     AI SkNx(T v) : fVal(v) {}
     141             : 
     142             :     // Android complains against unused parameters, so we guard it
     143             :     AI T operator[](int SkDEBUGCODE(k)) const {
     144           0 :         SkASSERT(k == 0);
     145           0 :         return fVal;
     146             :     }
     147             : 
     148             :     AI static SkNx Load(const void* ptr) {
     149             :         SkNx v;
     150           0 :         memcpy(&v, ptr, sizeof(T));
     151           0 :         return v;
     152             :     }
     153           0 :     AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); }
     154             : 
     155             :     AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
     156             :         auto ptr = (const char*)vptr;
     157             :         *a = Load(ptr + 0*sizeof(T));
     158             :         *b = Load(ptr + 1*sizeof(T));
     159             :         *c = Load(ptr + 2*sizeof(T));
     160             :         *d = Load(ptr + 3*sizeof(T));
     161             :     }
     162             :     AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
     163             :         auto ptr = (const char*)vptr;
     164             :         *a = Load(ptr + 0*sizeof(T));
     165             :         *b = Load(ptr + 1*sizeof(T));
     166             :         *c = Load(ptr + 2*sizeof(T));
     167             :     }
     168             :     AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
     169             :         auto ptr = (char*)vptr;
     170             :         a.store(ptr + 0*sizeof(T));
     171             :         b.store(ptr + 1*sizeof(T));
     172             :         c.store(ptr + 2*sizeof(T));
     173             :         d.store(ptr + 3*sizeof(T));
     174             :     }
     175             : 
     176             :     AI bool anyTrue() const { return fVal != 0; }
     177             :     AI bool allTrue() const { return fVal != 0; }
     178             : 
     179             :     AI SkNx    abs() const { return Abs(fVal); }
     180             :     AI SkNx   sqrt() const { return Sqrt(fVal); }
     181             :     AI SkNx  rsqrt() const { return T(1) / this->sqrt(); }
     182             :     AI SkNx  floor() const { return Floor(fVal); }
     183             :     AI SkNx invert() const { return T(1) / *this; }
     184             : 
     185             :     AI SkNx operator!() const { return !fVal; }
     186             :     AI SkNx operator-() const { return -fVal; }
     187             :     AI SkNx operator~() const { return FromBits(~ToBits(fVal)); }
     188             : 
     189             :     AI SkNx operator<<(int bits) const { return fVal << bits; }
     190             :     AI SkNx operator>>(int bits) const { return fVal >> bits; }
     191             : 
     192             :     AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; }
     193             :     AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; }
     194             :     AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; }
     195             :     AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; }
     196             : 
     197             :     AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); }
     198             :     AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); }
     199             :     AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); }
     200             : 
     201             :     AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); }
     202             :     AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); }
     203             :     AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); }
     204             :     AI SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); }
     205             :     AI SkNx operator< (const SkNx& y) const { return FromBits(fVal <  y.fVal ? ~0 : 0); }
     206             :     AI SkNx operator> (const SkNx& y) const { return FromBits(fVal >  y.fVal ? ~0 : 0); }
     207             : 
     208             :     AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; }
     209             :     AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; }
     210             : 
     211             :     AI SkNx saturatedAdd(const SkNx& y) const {
     212             :         static_assert(std::is_unsigned<T>::value, "");
     213             :         T sum = fVal + y.fVal;
     214             :         return sum < fVal ? std::numeric_limits<T>::max() : sum;
     215             :     }
     216             : 
     217             :     AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; }
     218             : 
     219             : private:
     220             :     // Helper functions to choose the right float/double methods.  (In <cmath> madness lies...)
     221             :     AI static float   Abs(float val) { return  ::fabsf(val); }
     222             :     AI static float  Sqrt(float val) { return  ::sqrtf(val); }
     223             :     AI static float Floor(float val) { return ::floorf(val); }
     224             : 
     225             :     AI static double   Abs(double val) { return  ::fabs(val); }
     226             :     AI static double  Sqrt(double val) { return  ::sqrt(val); }
     227             :     AI static double Floor(double val) { return ::floor(val); }
     228             : 
     229             :     // Helper functions for working with floats/doubles as bit patterns.
     230             :     template <typename U>
     231             :     AI static U ToBits(U v) { return v; }
     232             :     AI static int32_t ToBits(float  v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
     233             :     AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
     234             : 
     235             :     template <typename Bits>
     236             :     AI static T FromBits(Bits bits) {
     237             :         static_assert(std::is_pod<T   >::value &&
     238             :                       std::is_pod<Bits>::value &&
     239             :                       sizeof(T) <= sizeof(Bits), "");
     240             :         T val;
     241             :         memcpy(&val, &bits, sizeof(T));
     242             :         return val;
     243             :     }
     244             : };
     245             : 
     246             : // Allow scalars on the left or right of binary operators, and things like +=, &=, etc.
     247             : #define V template <int N, typename T> AI static SkNx<N,T>
     248           0 :     V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) +  y; }
     249           0 :     V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) -  y; }
     250          81 :     V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) *  y; }
     251           0 :     V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) /  y; }
     252             :     V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) &  y; }
     253           0 :     V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) |  y; }
     254             :     V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^  y; }
     255             :     V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; }
     256             :     V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; }
     257             :     V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; }
     258             :     V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; }
     259           0 :     V operator< (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <  y; }
     260             :     V operator> (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >  y; }
     261             : 
     262           0 :     V operator+ (const SkNx<N,T>& x, T y) { return x +  SkNx<N,T>(y); }
     263           0 :     V operator- (const SkNx<N,T>& x, T y) { return x -  SkNx<N,T>(y); }
     264         312 :     V operator* (const SkNx<N,T>& x, T y) { return x *  SkNx<N,T>(y); }
     265           0 :     V operator/ (const SkNx<N,T>& x, T y) { return x /  SkNx<N,T>(y); }
     266           0 :     V operator& (const SkNx<N,T>& x, T y) { return x &  SkNx<N,T>(y); }
     267             :     V operator| (const SkNx<N,T>& x, T y) { return x |  SkNx<N,T>(y); }
     268             :     V operator^ (const SkNx<N,T>& x, T y) { return x ^  SkNx<N,T>(y); }
     269           0 :     V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); }
     270             :     V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); }
     271             :     V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); }
     272             :     V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); }
     273          81 :     V operator< (const SkNx<N,T>& x, T y) { return x <  SkNx<N,T>(y); }
     274           0 :     V operator> (const SkNx<N,T>& x, T y) { return x >  SkNx<N,T>(y); }
     275             : 
     276             :     V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); }
     277             :     V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); }
     278             : 
     279           0 :     V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); }
     280             :     V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); }
     281       20294 :     V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); }
     282             :     V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); }
     283             :     V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); }
     284             :     V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); }
     285             :     V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); }
     286             : 
     287             :     V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); }
     288             :     V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); }
     289           0 :     V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); }
     290             :     V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); }
     291             :     V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); }
     292             :     V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); }
     293             :     V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); }
     294             : #undef V
     295             : 
     296             : // SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T>
     297             : template <int N, typename T>
     298             : AI static void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) {
     299           0 :     *lo = v.fLo;
     300           0 :     *hi = v.fHi;
     301             : }
     302             : 
     303             : // SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T>
     304             : template <int N, typename T>
     305             : AI static SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) {
     306             :     return { lo, hi };
     307             : }
     308             : 
     309             : // A very generic shuffle.  Can reorder, duplicate, contract, expand...
     310             : //    Sk4f v = { R,G,B,A };
     311             : //    SkNx_shuffle<2,1,0,3>(v)         ~~> {B,G,R,A}
     312             : //    SkNx_shuffle<2,1>(v)             ~~> {B,G}
     313             : //    SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G}
     314             : //    SkNx_shuffle<3,3,3,3>(v)         ~~> {A,A,A,A}
     315             : template <int... Ix, int N, typename T>
     316             : AI static SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) {
     317        2370 :     return { v[Ix]... };
     318             : }
     319             : 
     320             : // Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src).
     321             : template <typename Dst, typename Src, int N>
     322             : AI static SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) {
     323             :     return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) };
     324             : }
     325             : template <typename Dst, typename Src>
     326             : AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) {
     327             :     return static_cast<Dst>(v.fVal);
     328             : }
     329             : 
     330             : template <int N, typename T>
     331             : AI static SkNx<N,T> SkNx_fma(const SkNx<N,T>& f, const SkNx<N,T>& m, const SkNx<N,T>& a) {
     332         324 :     return f*m+a;
     333             : }
     334             : 
     335             : }  // namespace
     336             : 
     337             : typedef SkNx<2,     float> Sk2f;
     338             : typedef SkNx<4,     float> Sk4f;
     339             : typedef SkNx<8,     float> Sk8f;
     340             : typedef SkNx<16,    float> Sk16f;
     341             : 
     342             : typedef SkNx<2,  SkScalar> Sk2s;
     343             : typedef SkNx<4,  SkScalar> Sk4s;
     344             : typedef SkNx<8,  SkScalar> Sk8s;
     345             : typedef SkNx<16, SkScalar> Sk16s;
     346             : 
     347             : typedef SkNx<4,   uint8_t> Sk4b;
     348             : typedef SkNx<8,   uint8_t> Sk8b;
     349             : typedef SkNx<16,  uint8_t> Sk16b;
     350             : 
     351             : typedef SkNx<4,  uint16_t> Sk4h;
     352             : typedef SkNx<8,  uint16_t> Sk8h;
     353             : typedef SkNx<16, uint16_t> Sk16h;
     354             : 
     355             : typedef SkNx<4,  int32_t> Sk4i;
     356             : typedef SkNx<8,  int32_t> Sk8i;
     357             : typedef SkNx<4, uint32_t> Sk4u;
     358             : 
     359             : // Include platform specific specializations if available.
     360             : #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
     361             :     #include "../opts/SkNx_sse.h"
     362             : #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
     363             :     #include "../opts/SkNx_neon.h"
     364             : #else
     365             : 
     366             : AI static Sk4i Sk4f_round(const Sk4f& x) {
     367             :     return { (int) lrintf (x[0]),
     368             :              (int) lrintf (x[1]),
     369             :              (int) lrintf (x[2]),
     370             :              (int) lrintf (x[3]), };
     371             : }
     372             : 
     373             : #endif
     374             : 
     375             : AI static void Sk4f_ToBytes(uint8_t p[16],
     376             :                             const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) {
     377           0 :     SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p);
     378             : }
     379             : 
     380             : #undef AI
     381             : 
     382             : #endif//SkNx_DEFINED

Generated by: LCOV version 1.13