aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2018-03-26 13:04:14 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-26 18:48:23 +0000
commit68ff92f78addb3c862cc28bcee2b97ff4679c290 (patch)
treef214fbde644e1e7a778a207f6bc070c44ac24e0f
parent376a96aa07b5d88fdb77693642586192cd17101b (diff)
specialize arm64 allTrue()/anyTrue()
aarch64 added vector-wise add/mul/min/max instructions. We can use min and max to implement allTrue() and anyTrue(), respectively. (This CL is mostly so I don't forget these intrinsics exist.) In assembly, these actually compile to two instructions, the folding operation into a vector register, then a move from the vector register to a general purpose register. Change-Id: Ia6a999ac250740de765e871094e911979a8711c7 Reviewed-on: https://skia-review.googlesource.com/116482 Reviewed-by: Chris Dalton <csmartdalton@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
-rw-r--r--src/opts/SkNx_neon.h16
-rw-r--r--tests/SkNxTest.cpp14
2 files changed, 30 insertions, 0 deletions
diff --git a/src/opts/SkNx_neon.h b/src/opts/SkNx_neon.h
index f8170ef962..52247c8f66 100644
--- a/src/opts/SkNx_neon.h
+++ b/src/opts/SkNx_neon.h
@@ -112,12 +112,20 @@ public:
}
AI bool allTrue() const {
+ #if defined(__aarch64__)
+ return 0 != vminv_u32(vreinterpret_u32_f32(fVec));
+ #else
auto v = vreinterpret_u32_f32(fVec);
return vget_lane_u32(v,0) && vget_lane_u32(v,1);
+ #endif
}
AI bool anyTrue() const {
+ #if defined(__aarch64__)
+ return 0 != vmaxv_u32(vreinterpret_u32_f32(fVec));
+ #else
auto v = vreinterpret_u32_f32(fVec);
return vget_lane_u32(v,0) || vget_lane_u32(v,1);
+ #endif
}
AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
@@ -229,14 +237,22 @@ public:
}
AI bool allTrue() const {
+ #if defined(__aarch64__)
+ return 0 != vminvq_u32(vreinterpretq_u32_f32(fVec));
+ #else
auto v = vreinterpretq_u32_f32(fVec);
return vgetq_lane_u32(v,0) && vgetq_lane_u32(v,1)
&& vgetq_lane_u32(v,2) && vgetq_lane_u32(v,3);
+ #endif
}
AI bool anyTrue() const {
+ #if defined(__aarch64__)
+ return 0 != vmaxvq_u32(vreinterpretq_u32_f32(fVec));
+ #else
auto v = vreinterpretq_u32_f32(fVec);
return vgetq_lane_u32(v,0) || vgetq_lane_u32(v,1)
|| vgetq_lane_u32(v,2) || vgetq_lane_u32(v,3);
+ #endif
}
AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
diff --git a/tests/SkNxTest.cpp b/tests/SkNxTest.cpp
index 9e2c27e79c..9901f7a41d 100644
--- a/tests/SkNxTest.cpp
+++ b/tests/SkNxTest.cpp
@@ -454,3 +454,17 @@ DEF_TEST(Sk2f_Store4, r) {
REPORTER_ASSERT(r, dst[6] == 6);
REPORTER_ASSERT(r, dst[7] == 7);
}
+
+DEF_TEST(SkNf_anyTrue_allTrue, r) {
+ REPORTER_ASSERT(r, (Sk2f{1,2} < Sk2f{3,4}).anyTrue());
+ REPORTER_ASSERT(r, (Sk2f{1,2} < Sk2f{3,4}).allTrue());
+ REPORTER_ASSERT(r, (Sk2f{3,2} < Sk2f{1,4}).anyTrue());
+ REPORTER_ASSERT(r, !(Sk2f{3,2} < Sk2f{1,4}).allTrue());
+ REPORTER_ASSERT(r, !(Sk2f{3,4} < Sk2f{1,2}).anyTrue());
+
+ REPORTER_ASSERT(r, (Sk4f{1,2,3,4} < Sk4f{3,4,5,6}).anyTrue());
+ REPORTER_ASSERT(r, (Sk4f{1,2,3,4} < Sk4f{3,4,5,6}).allTrue());
+ REPORTER_ASSERT(r, (Sk4f{1,2,3,4} < Sk4f{1,4,1,1}).anyTrue());
+ REPORTER_ASSERT(r, !(Sk4f{1,2,3,4} < Sk4f{1,4,1,1}).allTrue());
+ REPORTER_ASSERT(r, !(Sk4f{3,4,5,6} < Sk4f{1,2,3,4}).anyTrue());
+}