| Index: src/opts/SkNx_sse.h | 
| diff --git a/src/opts/SkNx_sse.h b/src/opts/SkNx_sse.h | 
| index f3952a976873ae4b15d994c4f6cb6901ab20587f..b3f509140626816367b4f34821299e44aeeb1eea 100644 | 
| --- a/src/opts/SkNx_sse.h | 
| +++ b/src/opts/SkNx_sse.h | 
| @@ -65,6 +65,52 @@ public: | 
| }; | 
|  | 
| template <> | 
| +class SkNx<2, double> { | 
| +public: | 
| +    SkNx(const __m128d& vec) : fVec(vec) {} | 
| + | 
| +    SkNx() {} | 
| +    SkNx(double val) : fVec(_mm_set1_pd(val)) {} | 
| +    static SkNx Load(const double vals[2]) { return _mm_loadu_pd(vals); } | 
| +    SkNx(double a, double b) : fVec(_mm_setr_pd(a,b)) {} | 
| + | 
| +    void store(double vals[2]) const { _mm_storeu_pd(vals, fVec); } | 
| + | 
| +    SkNx operator + (const SkNx& o) const { return _mm_add_pd(fVec, o.fVec); } | 
| +    SkNx operator - (const SkNx& o) const { return _mm_sub_pd(fVec, o.fVec); } | 
| +    SkNx operator * (const SkNx& o) const { return _mm_mul_pd(fVec, o.fVec); } | 
| +    SkNx operator / (const SkNx& o) const { return _mm_div_pd(fVec, o.fVec); } | 
| + | 
| +    SkNx operator == (const SkNx& o) const { return _mm_cmpeq_pd (fVec, o.fVec); } | 
| +    SkNx operator != (const SkNx& o) const { return _mm_cmpneq_pd(fVec, o.fVec); } | 
| +    SkNx operator  < (const SkNx& o) const { return _mm_cmplt_pd (fVec, o.fVec); } | 
| +    SkNx operator  > (const SkNx& o) const { return _mm_cmpgt_pd (fVec, o.fVec); } | 
| +    SkNx operator <= (const SkNx& o) const { return _mm_cmple_pd (fVec, o.fVec); } | 
| +    SkNx operator >= (const SkNx& o) const { return _mm_cmpge_pd (fVec, o.fVec); } | 
| + | 
| +    static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_pd(l.fVec, r.fVec); } | 
| +    static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_pd(l.fVec, r.fVec); } | 
| + | 
| +    SkNx sqrt() const { return _mm_sqrt_pd(fVec);  } | 
| + | 
| +    template <int k> double kth() const { | 
| +        SkASSERT(0 <= k && k < 2); | 
| +        union { __m128d v; double fs[2]; } pun = {fVec}; | 
| +        return pun.fs[k&1]; | 
| +    } | 
| + | 
| +    bool allTrue() const { return 0x3 == _mm_movemask_pd(fVec); } | 
| +    bool anyTrue() const { return 0x0 != _mm_movemask_pd(fVec); } | 
| + | 
| +    SkNx thenElse(const SkNx& t, const SkNx& e) const { | 
| +        return _mm_or_pd(_mm_and_pd   (fVec, t.fVec), | 
| +                         _mm_andnot_pd(fVec, e.fVec)); | 
| +    } | 
| + | 
| +    __m128d fVec; | 
| +}; | 
| + | 
| +template <> | 
| class SkNx<4, int> { | 
| public: | 
| SkNx(const __m128i& vec) : fVec(vec) {} | 
|  |