diff options
author | mtklein <mtklein@chromium.org> | 2016-07-29 11:11:12 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-07-29 11:11:12 -0700 |
commit | 6ad22315eb6eacfcd35497cd118440a619d05b18 (patch) | |
tree | c1f797e4afd6747a9943424afdad3c48a0259053 | |
parent | 01f696e30f775e345d1e378b2c40dd24e3a037c3 (diff) |
Tidy up SkNx_neon.
This takes advantage of the fact that all the compilers we use that
support NEON implement it with their own vector extensions. This means
normal things like c = a + b work on the underlying vector types already.
Odd instructions like min or saturated add need to stay intrinsics.
Also, rearrange functions to a more consistent order.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2196773002
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
Review-Url: https://codereview.chromium.org/2196773002
-rw-r--r-- | src/opts/SkNx_neon.h | 280 |
1 files changed, 98 insertions, 182 deletions
diff --git a/src/opts/SkNx_neon.h b/src/opts/SkNx_neon.h index eea68007a6..ebc3c97c4e 100644 --- a/src/opts/SkNx_neon.h +++ b/src/opts/SkNx_neon.h @@ -17,9 +17,9 @@ // - subtract 1 if that's too big (possible for negative values). // This restricts the domain of our inputs to a maximum somehwere around 2^31. Seems plenty big. static inline float32x4_t armv7_vrndmq_f32(float32x4_t v) { - auto roundtrip = vcvtq_f32_s32(vcvtq_s32_f32(v)); - auto too_big = vcgtq_f32(roundtrip, v); - return vsubq_f32(roundtrip, (float32x4_t)vandq_u32(too_big, (uint32x4_t)vdupq_n_f32(1))); + float32x4_t roundtrip = vcvtq_f32_s32(vcvtq_s32_f32(v)); + uint32x4_t too_big = roundtrip > v; + return roundtrip - (float32x4_t)vandq_u32(too_big, (uint32x4_t)vdupq_n_f32(1)); } // Well, this is absurd. The shifts require compile-time constant arguments. @@ -50,40 +50,23 @@ public: SkNx(float32x2_t vec) : fVec(vec) {} SkNx() {} - SkNx(float val) : fVec(vdup_n_f32(val)) {} - static SkNx Load(const void* ptr) { return vld1_f32((const float*)ptr); } - SkNx(float a, float b) { fVec = (float32x2_t) { a, b }; } + SkNx(float a, float b) : fVec{a,b} {} + SkNx(float v) : fVec{v,v} {} + static SkNx Load(const void* ptr) { return vld1_f32((const float*)ptr); } void store(void* ptr) const { vst1_f32((float*)ptr, fVec); } - SkNx invert() const { - float32x2_t est0 = vrecpe_f32(fVec), - est1 = vmul_f32(vrecps_f32(est0, fVec), est0); - return est1; - } - - SkNx operator + (const SkNx& o) const { return vadd_f32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsub_f32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmul_f32(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { - #if defined(SK_CPU_ARM64) - return vdiv_f32(fVec, o.fVec); - #else - float32x2_t est0 = vrecpe_f32(o.fVec), - est1 = vmul_f32(vrecps_f32(est0, o.fVec), est0), - est2 = vmul_f32(vrecps_f32(est1, o.fVec), est1); - return vmul_f32(fVec, est2); - #endif - } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } + SkNx operator / (const SkNx& o) const { return fVec / o.fVec; } - SkNx operator == (const SkNx& o) const { return vreinterpret_f32_u32(vceq_f32(fVec, o.fVec)); } - SkNx operator < (const SkNx& o) const { return vreinterpret_f32_u32(vclt_f32(fVec, o.fVec)); } - SkNx operator > (const SkNx& o) const { return vreinterpret_f32_u32(vcgt_f32(fVec, o.fVec)); } - SkNx operator <= (const SkNx& o) const { return vreinterpret_f32_u32(vcle_f32(fVec, o.fVec)); } - SkNx operator >= (const SkNx& o) const { return vreinterpret_f32_u32(vcge_f32(fVec, o.fVec)); } - SkNx operator != (const SkNx& o) const { - return vreinterpret_f32_u32(vmvn_u32(vceq_f32(fVec, o.fVec))); - } + SkNx operator == (const SkNx& o) const { return fVec == o.fVec; } + SkNx operator < (const SkNx& o) const { return fVec < o.fVec; } + SkNx operator > (const SkNx& o) const { return fVec > o.fVec; } + SkNx operator <= (const SkNx& o) const { return fVec <= o.fVec; } + SkNx operator >= (const SkNx& o) const { return fVec >= o.fVec; } + SkNx operator != (const SkNx& o) const { return fVec != o.fVec; } static SkNx Min(const SkNx& l, const SkNx& r) { return vmin_f32(l.fVec, r.fVec); } static SkNx Max(const SkNx& l, const SkNx& r) { return vmax_f32(l.fVec, r.fVec); } @@ -104,12 +87,14 @@ public: #endif } - float operator[](int k) const { - SkASSERT(0 <= k && k < 2); - union { float32x2_t v; float fs[2]; } pun = {fVec}; - return pun.fs[k&1]; + SkNx invert() const { + float32x2_t est0 = vrecpe_f32(fVec), + est1 = vmul_f32(vrecps_f32(est0, fVec), est0); + return est1; } + float operator[](int k) const { return fVec[k&1]; } + bool allTrue() const { auto v = vreinterpret_u32_f32(fVec); return vget_lane_u32(v,0) && vget_lane_u32(v,1); @@ -128,39 +113,23 @@ public: SkNx(float32x4_t vec) : fVec(vec) {} SkNx() {} - SkNx(float val) : fVec(vdupq_n_f32(val)) {} - static SkNx Load(const void* ptr) { return vld1q_f32((const float*)ptr); } - SkNx(float a, float b, float c, float d) { fVec = (float32x4_t) { a, b, c, d }; } + SkNx(float a, float b, float c, float d) : fVec{a,b,c,d} {} + SkNx(float v) : fVec{v,v,v,v} {} + static SkNx Load(const void* ptr) { return vld1q_f32((const float*)ptr); } void store(void* ptr) const { vst1q_f32((float*)ptr, fVec); } - SkNx invert() const { - float32x4_t est0 = vrecpeq_f32(fVec), - est1 = vmulq_f32(vrecpsq_f32(est0, fVec), est0); - return est1; - } - SkNx operator + (const SkNx& o) const { return vaddq_f32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_f32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_f32(fVec, o.fVec); } - SkNx operator / (const SkNx& o) const { - #if defined(SK_CPU_ARM64) - return vdivq_f32(fVec, o.fVec); - #else - float32x4_t est0 = vrecpeq_f32(o.fVec), - est1 = vmulq_f32(vrecpsq_f32(est0, o.fVec), est0), - est2 = vmulq_f32(vrecpsq_f32(est1, o.fVec), est1); - return vmulq_f32(fVec, est2); - #endif - } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } + SkNx operator / (const SkNx& o) const { return fVec / o.fVec; } - SkNx operator==(const SkNx& o) const { return vreinterpretq_f32_u32(vceqq_f32(fVec, o.fVec)); } - SkNx operator <(const SkNx& o) const { return vreinterpretq_f32_u32(vcltq_f32(fVec, o.fVec)); } - SkNx operator >(const SkNx& o) const { return vreinterpretq_f32_u32(vcgtq_f32(fVec, o.fVec)); } - SkNx operator<=(const SkNx& o) const { return vreinterpretq_f32_u32(vcleq_f32(fVec, o.fVec)); } - SkNx operator>=(const SkNx& o) const { return vreinterpretq_f32_u32(vcgeq_f32(fVec, o.fVec)); } - SkNx operator!=(const SkNx& o) const { - return vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(fVec, o.fVec))); - } + SkNx operator==(const SkNx& o) const { return fVec == o.fVec; } + SkNx operator <(const SkNx& o) const { return fVec < o.fVec; } + SkNx operator >(const SkNx& o) const { return fVec > o.fVec; } + SkNx operator<=(const SkNx& o) const { return fVec <= o.fVec; } + SkNx operator>=(const SkNx& o) const { return fVec >= o.fVec; } + SkNx operator!=(const SkNx& o) const { return fVec != o.fVec; } static SkNx Min(const SkNx& l, const SkNx& r) { return vminq_f32(l.fVec, r.fVec); } static SkNx Max(const SkNx& l, const SkNx& r) { return vmaxq_f32(l.fVec, r.fVec); } @@ -174,7 +143,6 @@ public: #endif } - SkNx rsqrt() const { float32x4_t est0 = vrsqrteq_f32(fVec); return vmulq_f32(vrsqrtsq_f32(fVec, vmulq_f32(est0, est0)), est0); @@ -191,12 +159,14 @@ public: #endif } - float operator[](int k) const { - SkASSERT(0 <= k && k < 4); - union { float32x4_t v; float fs[4]; } pun = {fVec}; - return pun.fs[k&3]; + SkNx invert() const { + float32x4_t est0 = vrecpeq_f32(fVec), + est1 = vmulq_f32(vrecpsq_f32(est0, fVec), est0); + return est1; } + float operator[](int k) const { return fVec[k&3]; } + bool allTrue() const { auto v = vreinterpretq_u32_f32(fVec); return vgetq_lane_u32(v,0) && vgetq_lane_u32(v,1) @@ -224,29 +194,22 @@ public: SkNx(const uint16x4_t& vec) : fVec(vec) {} SkNx() {} - SkNx(uint16_t val) : fVec(vdup_n_u16(val)) {} - static SkNx Load(const void* ptr) { return vld1_u16((const uint16_t*)ptr); } - - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) { - fVec = (uint16x4_t) { a,b,c,d }; - } + SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) : fVec{a,b,c,d} {} + SkNx(uint16_t v) : fVec{v,v,v,v} {} + static SkNx Load(const void* ptr) { return vld1_u16((const uint16_t*)ptr); } void store(void* ptr) const { vst1_u16((uint16_t*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return vadd_u16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsub_u16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmul_u16(fVec, o.fVec); } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } SkNx operator << (int bits) const { SHIFT16(vshl_n_u16, fVec, bits); } SkNx operator >> (int bits) const { SHIFT16(vshr_n_u16, fVec, bits); } static SkNx Min(const SkNx& a, const SkNx& b) { return vmin_u16(a.fVec, b.fVec); } - uint16_t operator[](int k) const { - SkASSERT(0 <= k && k < 4); - union { uint16x4_t v; uint16_t us[4]; } pun = {fVec}; - return pun.us[k&3]; - } + uint16_t operator[](int k) const { return fVec[k&3]; } SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbsl_u16(fVec, t.fVec, e.fVec); @@ -261,30 +224,23 @@ public: SkNx(const uint16x8_t& vec) : fVec(vec) {} SkNx() {} - SkNx(uint16_t val) : fVec(vdupq_n_u16(val)) {} - static SkNx Load(const void* ptr) { return vld1q_u16((const uint16_t*)ptr); } - SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, - uint16_t e, uint16_t f, uint16_t g, uint16_t h) { - fVec = (uint16x8_t) { a,b,c,d, e,f,g,h }; - } + uint16_t e, uint16_t f, uint16_t g, uint16_t h) : fVec{a,b,c,d,e,f,g,h} {} + SkNx(uint16_t v) : fVec{v,v,v,v,v,v,v,v} {} + static SkNx Load(const void* ptr) { return vld1q_u16((const uint16_t*)ptr); } void store(void* ptr) const { vst1q_u16((uint16_t*)ptr, fVec); } - SkNx operator + (const SkNx& o) const { return vaddq_u16(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u16(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_u16(fVec, o.fVec); } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } SkNx operator << (int bits) const { SHIFT16(vshlq_n_u16, fVec, bits); } SkNx operator >> (int bits) const { SHIFT16(vshrq_n_u16, fVec, bits); } static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u16(a.fVec, b.fVec); } - uint16_t operator[](int k) const { - SkASSERT(0 <= k && k < 8); - union { uint16x8_t v; uint16_t us[8]; } pun = {fVec}; - return pun.us[k&7]; - } + uint16_t operator[](int k) const { return fVec[k&7]; } SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u16(fVec, t.fVec, e.fVec); @@ -301,22 +257,17 @@ public: SkNx(const uint8x8_t& vec) : fVec(vec) {} SkNx() {} - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { - fVec = (uint8x8_t){a,b,c,d, 0,0,0,0}; - } + SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) : fVec{a,b,c,d,0,0,0,0} {} + SkNx(uint8_t v) : fVec{v,v,v,v,0,0,0,0} {} + static SkNx Load(const void* ptr) { return (uint8x8_t)vld1_dup_u32((const unaligned_uint32_t*)ptr); } void store(void* ptr) const { return vst1_lane_u32((unaligned_uint32_t*)ptr, (uint32x2_t)fVec, 0); } - uint8_t operator[](int k) const { - SkASSERT(0 <= k && k < 4); - union { uint8x8_t v; uint8_t us[8]; } pun = {fVec}; - return pun.us[k&3]; - } - // TODO as needed + uint8_t operator[](int k) const { return fVec[k&3]; } uint8x8_t fVec; }; @@ -327,31 +278,24 @@ public: SkNx(const uint8x16_t& vec) : fVec(vec) {} SkNx() {} - SkNx(uint8_t val) : fVec(vdupq_n_u8(val)) {} - static SkNx Load(const void* ptr) { return vld1q_u8((const uint8_t*)ptr); } - SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g, uint8_t h, uint8_t i, uint8_t j, uint8_t k, uint8_t l, - uint8_t m, uint8_t n, uint8_t o, uint8_t p) { - fVec = (uint8x16_t) { a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p }; - } + uint8_t m, uint8_t n, uint8_t o, uint8_t p) : fVec{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p} {} + SkNx(uint8_t v) : fVec{v,v,v,v,v,v,v,v,v,v,v,v,v,v,v,v} {} + static SkNx Load(const void* ptr) { return vld1q_u8((const uint8_t*)ptr); } void store(void* ptr) const { vst1q_u8((uint8_t*)ptr, fVec); } SkNx saturatedAdd(const SkNx& o) const { return vqaddq_u8(fVec, o.fVec); } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } - SkNx operator + (const SkNx& o) const { return vaddq_u8(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u8(fVec, o.fVec); } + SkNx operator < (const SkNx& o) const { return fVec < o.fVec; } static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u8(a.fVec, b.fVec); } - SkNx operator < (const SkNx& o) const { return vcltq_u8(fVec, o.fVec); } - uint8_t operator[](int k) const { - SkASSERT(0 <= k && k < 16); - union { uint8x16_t v; uint8_t us[16]; } pun = {fVec}; - return pun.us[k&15]; - } + uint8_t operator[](int k) const { return fVec[k&15]; } SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u8(fVec, t.fVec, e.fVec); @@ -366,47 +310,30 @@ public: SkNx(const int32x4_t& vec) : fVec(vec) {} SkNx() {} - SkNx(int32_t v) { - fVec = vdupq_n_s32(v); - } - SkNx(int32_t a, int32_t b, int32_t c, int32_t d) { - fVec = (int32x4_t){a,b,c,d}; - } - static SkNx Load(const void* ptr) { - return vld1q_s32((const int32_t*)ptr); - } - void store(void* ptr) const { - return vst1q_s32((int32_t*)ptr, fVec); - } - int32_t operator[](int k) const { - SkASSERT(0 <= k && k < 4); - union { int32x4_t v; int32_t is[4]; } pun = {fVec}; - return pun.is[k&3]; - } + SkNx(int32_t a, int32_t b, int32_t c, int32_t d) : fVec{a,b,c,d} {} + SkNx(int32_t v) : fVec{v,v,v,v} {} - SkNx operator + (const SkNx& o) const { return vaddq_s32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_s32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_s32(fVec, o.fVec); } + static SkNx Load(const void* ptr) { return vld1q_s32((const int32_t*)ptr); } + void store(void* ptr) const { return vst1q_s32((int32_t*)ptr, fVec); } - SkNx operator & (const SkNx& o) const { return vandq_s32(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return vorrq_s32(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return veorq_s32(fVec, o.fVec); } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } + + SkNx operator & (const SkNx& o) const { return fVec & o.fVec; } + SkNx operator | (const SkNx& o) const { return fVec | o.fVec; } + SkNx operator ^ (const SkNx& o) const { return fVec ^ o.fVec; } SkNx operator << (int bits) const { SHIFT32(vshlq_n_s32, fVec, bits); } SkNx operator >> (int bits) const { SHIFT32(vshrq_n_s32, fVec, bits); } - SkNx operator == (const SkNx& o) const { - return vreinterpretq_s32_u32(vceqq_s32(fVec, o.fVec)); - } - SkNx operator < (const SkNx& o) const { - return vreinterpretq_s32_u32(vcltq_s32(fVec, o.fVec)); - } - SkNx operator > (const SkNx& o) const { - return vreinterpretq_s32_u32(vcgtq_s32(fVec, o.fVec)); - } + SkNx operator == (const SkNx& o) const { return fVec == o.fVec; } + SkNx operator < (const SkNx& o) const { return fVec < o.fVec; } + SkNx operator > (const SkNx& o) const { return fVec > o.fVec; } static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_s32(a.fVec, b.fVec); } - // TODO as needed + + int32_t operator[](int k) const { return fVec[k&3]; } SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_s32(vreinterpretq_u32_s32(fVec), t.fVec, e.fVec); @@ -421,41 +348,30 @@ public: SkNx(const uint32x4_t& vec) : fVec(vec) {} SkNx() {} - SkNx(uint32_t v) { - fVec = vdupq_n_u32(v); - } - SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { - fVec = (uint32x4_t){a,b,c,d}; - } - static SkNx Load(const void* ptr) { - return vld1q_u32((const uint32_t*)ptr); - } - void store(void* ptr) const { - return vst1q_u32((uint32_t*)ptr, fVec); - } - uint32_t operator[](int k) const { - SkASSERT(0 <= k && k < 4); - union { uint32x4_t v; uint32_t us[4]; } pun = {fVec}; - return pun.us[k&3]; - } + SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : fVec{a,b,c,d} {} + SkNx(uint32_t v) : fVec{v,v,v,v} {} - SkNx operator + (const SkNx& o) const { return vaddq_u32(fVec, o.fVec); } - SkNx operator - (const SkNx& o) const { return vsubq_u32(fVec, o.fVec); } - SkNx operator * (const SkNx& o) const { return vmulq_u32(fVec, o.fVec); } + static SkNx Load(const void* ptr) { return vld1q_u32((const uint32_t*)ptr); } + void store(void* ptr) const { return vst1q_u32((uint32_t*)ptr, fVec); } - SkNx operator & (const SkNx& o) const { return vandq_u32(fVec, o.fVec); } - SkNx operator | (const SkNx& o) const { return vorrq_u32(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return veorq_u32(fVec, o.fVec); } + SkNx operator + (const SkNx& o) const { return fVec + o.fVec; } + SkNx operator - (const SkNx& o) const { return fVec - o.fVec; } + SkNx operator * (const SkNx& o) const { return fVec * o.fVec; } + + SkNx operator & (const SkNx& o) const { return fVec & o.fVec; } + SkNx operator | (const SkNx& o) const { return fVec | o.fVec; } + SkNx operator ^ (const SkNx& o) const { return fVec ^ o.fVec; } SkNx operator << (int bits) const { SHIFT32(vshlq_n_u32, fVec, bits); } SkNx operator >> (int bits) const { SHIFT32(vshrq_n_u32, fVec, bits); } - SkNx operator == (const SkNx& o) const { return vceqq_u32(fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return vcltq_u32(fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return vcgtq_u32(fVec, o.fVec); } + SkNx operator == (const SkNx& o) const { return fVec == o.fVec; } + SkNx operator < (const SkNx& o) const { return fVec < o.fVec; } + SkNx operator > (const SkNx& o) const { return fVec > o.fVec; } static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u32(a.fVec, b.fVec); } - // TODO as needed + + uint32_t operator[](int k) const { return fVec[k&3]; } SkNx thenElse(const SkNx& t, const SkNx& e) const { return vbslq_u32(fVec, t.fVec, e.fVec); |