summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorRafael CF Sousa <rafaelcfsousa@ibm.com>2022-05-23 16:20:47 -0300
committerRafael CF Sousa <rafaelcfsousa@ibm.com>2022-05-23 18:53:43 -0300
commit09b22a118466ff85fe365f451139cc3da2e8bc43 (patch)
tree056ab9df3393f7f0be505bb656c80bc23f975529 /numpy
parentff03e72646ee0e4727a1cc333d5ea4945724d44b (diff)
downloadnumpy-09b22a118466ff85fe365f451139cc3da2e8bc43.tar.gz
SIMD, ENH: Use logical bitwise to implement comparison functions (bool_)
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/_simd/_simd.dispatch.c.src6
-rw-r--r--numpy/core/src/common/simd/avx2/operators.h5
-rw-r--r--numpy/core/src/common/simd/avx512/operators.h12
-rw-r--r--numpy/core/src/common/simd/neon/operators.h5
-rw-r--r--numpy/core/src/common/simd/sse/operators.h5
-rw-r--r--numpy/core/src/common/simd/vsx/operators.h5
-rw-r--r--numpy/core/src/umath/loops_comparison.dispatch.c.src25
-rw-r--r--numpy/core/tests/test_simd.py45
8 files changed, 99 insertions, 9 deletions
diff --git a/numpy/core/src/_simd/_simd.dispatch.c.src b/numpy/core/src/_simd/_simd.dispatch.c.src
index ad8c538e4..f8a0a3196 100644
--- a/numpy/core/src/_simd/_simd.dispatch.c.src
+++ b/numpy/core/src/_simd/_simd.dispatch.c.src
@@ -462,6 +462,9 @@ SIMD_IMPL_INTRIN_2(or_@bsfx@, v@bsfx@, v@bsfx@, v@bsfx@)
SIMD_IMPL_INTRIN_2(xor_@bsfx@, v@bsfx@, v@bsfx@, v@bsfx@)
SIMD_IMPL_INTRIN_1(not_@bsfx@, v@bsfx@, v@bsfx@)
/**end repeat**/
+SIMD_IMPL_INTRIN_2(andc_b8, vb8, vb8, vb8)
+SIMD_IMPL_INTRIN_2(orc_b8, vb8, vb8, vb8)
+SIMD_IMPL_INTRIN_2(xnor_b8, vb8, vb8, vb8)
/***************************
* Conversions
***************************/
@@ -710,6 +713,9 @@ SIMD_INTRIN_DEF(or_@bsfx@)
SIMD_INTRIN_DEF(xor_@bsfx@)
SIMD_INTRIN_DEF(not_@bsfx@)
/**end repeat**/
+SIMD_INTRIN_DEF(andc_b8)
+SIMD_INTRIN_DEF(orc_b8)
+SIMD_INTRIN_DEF(xnor_b8)
/***************************
* Conversions
***************************/
diff --git a/numpy/core/src/common/simd/avx2/operators.h b/numpy/core/src/common/simd/avx2/operators.h
index 5fc7719e9..0e77fc6be 100644
--- a/numpy/core/src/common/simd/avx2/operators.h
+++ b/numpy/core/src/common/simd/avx2/operators.h
@@ -114,6 +114,11 @@ NPY_FINLINE __m256i npyv_shr_s64(__m256i a, int c)
#define npyv_not_b32 npyv_not_u8
#define npyv_not_b64 npyv_not_u8
+// ANDC, ORC and XNOR
+#define npyv_andc_b8(A, B) _mm256_andnot_si256(A, B)
+#define npyv_orc_b8(A, B) npyv_or_b8(npyv_not_b8(A), B)
+#define npyv_xnor_b8(A, B) npyv_not_b8(npyv_xor_b8(A, B))
+
/***************************
* Comparison
***************************/
diff --git a/numpy/core/src/common/simd/avx512/operators.h b/numpy/core/src/common/simd/avx512/operators.h
index d53932fa8..8c98b72dd 100644
--- a/numpy/core/src/common/simd/avx512/operators.h
+++ b/numpy/core/src/common/simd/avx512/operators.h
@@ -152,6 +152,9 @@
#define npyv_xor_b16 _kxor_mask32
#define npyv_not_b8 _knot_mask64
#define npyv_not_b16 _knot_mask32
+ #define npyv_andc_b8 _kandn_mask64
+ #define npyv_orc_b8(A, B) npyv_or_b8(npyv_not_b8(A), B)
+ #define npyv_xnor_b8 _kxnor_mask64
#elif defined(NPY_HAVE_AVX512BW)
NPY_FINLINE npyv_b8 npyv_and_b8(npyv_b8 a, npyv_b8 b)
{ return a & b; }
@@ -169,6 +172,12 @@
{ return ~a; }
NPY_FINLINE npyv_b16 npyv_not_b16(npyv_b16 a)
{ return ~a; }
+ NPY_FINLINE npyv_b8 npyv_andc_b8(npyv_b8 a, npyv_b8 b)
+ { return (~a) & b; }
+ NPY_FINLINE npyv_b8 npyv_orc_b8(npyv_b8 a, npyv_b8 b)
+ { return (~a) | b; }
+ NPY_FINLINE npyv_b8 npyv_xnor_b8(npyv_b8 a, npyv_b8 b)
+ { return ~(a ^ b); }
#else
#define npyv_and_b8 _mm512_and_si512
#define npyv_and_b16 _mm512_and_si512
@@ -178,6 +187,9 @@
#define npyv_xor_b16 _mm512_xor_si512
#define npyv_not_b8 npyv_not_u8
#define npyv_not_b16 npyv_not_u8
+ #define npyv_andc_b8 _mm512_andnot_si512
+ #define npyv_orc_b8(A, B) npyv_or_b8(npyv_not_b8(A), B)
+ #define npyv_xnor_b8(A, B) npyv_not_b8(npyv_xor_b8(A, B))
#endif
#define npyv_and_b32 _mm512_kand
diff --git a/numpy/core/src/common/simd/neon/operators.h b/numpy/core/src/common/simd/neon/operators.h
index b43ba3653..6c155fc67 100644
--- a/numpy/core/src/common/simd/neon/operators.h
+++ b/numpy/core/src/common/simd/neon/operators.h
@@ -116,6 +116,11 @@
#define npyv_not_b32 vmvnq_u32
#define npyv_not_b64 npyv_not_u64
+// ANDC, ORC and XNOR
+#define npyv_andc_b8(A, B) vbicq_u8(B, A)
+#define npyv_orc_b8(A, B) vornq_u8(B, A)
+#define npyv_xnor_b8 vceqq_u8
+
/***************************
* Comparison
***************************/
diff --git a/numpy/core/src/common/simd/sse/operators.h b/numpy/core/src/common/simd/sse/operators.h
index 51c84fb4e..51bdca356 100644
--- a/numpy/core/src/common/simd/sse/operators.h
+++ b/numpy/core/src/common/simd/sse/operators.h
@@ -115,6 +115,11 @@ NPY_FINLINE __m128i npyv_shr_s64(__m128i a, int c)
#define npyv_not_b32 npyv_not_u8
#define npyv_not_b64 npyv_not_u8
+// ANDC, ORC and XNOR
+#define npyv_andc_b8(A, B) _mm_andnot_si128(A, B)
+#define npyv_orc_b8(A, B) npyv_or_b8(npyv_not_b8(A), B)
+#define npyv_xnor_b8(A, B) npyv_not_b8(npyv_xor_b8(A, B))
+
/***************************
* Comparison
***************************/
diff --git a/numpy/core/src/common/simd/vsx/operators.h b/numpy/core/src/common/simd/vsx/operators.h
index d34057ff3..fc29ba920 100644
--- a/numpy/core/src/common/simd/vsx/operators.h
+++ b/numpy/core/src/common/simd/vsx/operators.h
@@ -133,6 +133,11 @@ NPY_FINLINE npyv_f32 npyv_not_f32(npyv_f32 a)
NPY_FINLINE npyv_f64 npyv_not_f64(npyv_f64 a)
{ return vec_nor(a, a); }
+// ANDC, ORC and XNOR
+#define npyv_andc_b8(A, B) vec_andc(B, A)
+#define npyv_orc_b8(A, B) vec_orc(B, A)
+#define npyv_xnor_b8 vec_eqv
+
/***************************
* Comparison
***************************/
diff --git a/numpy/core/src/umath/loops_comparison.dispatch.c.src b/numpy/core/src/umath/loops_comparison.dispatch.c.src
index e5518afb3..07bbf0354 100644
--- a/numpy/core/src/umath/loops_comparison.dispatch.c.src
+++ b/numpy/core/src/umath/loops_comparison.dispatch.c.src
@@ -207,7 +207,8 @@ static void simd_binary_scalar2_@kind@_@sfx@(char **args, npy_intp len)
/**begin repeat
* #kind = equal, not_equal, less, less_equal, greater, greater_equal#
* #OP = ==, !=, <, <=, >, >=#
- * #VOP = cmpeq, cmpneq, cmplt, cmple, cmpgt, cmpge#
+ * #VOP = xnor, xor, andc, orc, andc, orc#
+ * #rev = 0, 0, 0, 0, 1, 1#
*/
#if NPY_SIMD
@@ -225,7 +226,11 @@ static void simd_binary_@kind@_b8(char **args, npy_intp len)
// Whatever element in src != 0x0 is converted to 0xFF
npyv_b8 a = npyv_cmpneq_u8(npyv_load_u8(src1), vzero);
npyv_b8 b = npyv_cmpneq_u8(npyv_load_u8(src2), vzero);
- npyv_b8 c = npyv_@VOP@_u8(npyv_cvt_u8_b8(a), npyv_cvt_u8_b8(b));
+#if !@rev@
+ npyv_b8 c = npyv_@VOP@_b8(a, b);
+#else
+ npyv_b8 c = npyv_@VOP@_b8(b, a);
+#endif
npyv_store_u8(dst, npyv_and_u8(npyv_cvt_u8_b8(c), truemask));
}
@@ -243,13 +248,17 @@ static void simd_binary_scalar1_@kind@_b8(char **args, npy_intp len)
npyv_lanetype_u8 *dst = (npyv_lanetype_u8 *) args[2];
const npyv_u8 vzero = npyv_setall_u8(0x0);
const npyv_u8 vscalar = npyv_setall_u8(scalar);
- const npyv_u8 a = npyv_cvt_u8_b8(npyv_cmpneq_u8(vscalar, vzero));
+ const npyv_b8 a = npyv_cmpneq_u8(vscalar, vzero);
const npyv_u8 truemask = npyv_setall_u8(0x1);
const int vstep = npyv_nlanes_u8;
for (; len >= vstep; len -= vstep, src += vstep, dst += vstep) {
npyv_b8 b = npyv_cmpneq_u8(npyv_load_u8(src), vzero);
- npyv_b8 c = npyv_@VOP@_u8(a, npyv_cvt_u8_b8(b));
+#if !@rev@
+ npyv_b8 c = npyv_@VOP@_b8(a, b);
+#else
+ npyv_b8 c = npyv_@VOP@_b8(b, a);
+#endif
npyv_store_u8(dst, npyv_and_u8(npyv_cvt_u8_b8(c), truemask));
}
@@ -266,13 +275,17 @@ static void simd_binary_scalar2_@kind@_b8(char **args, npy_intp len)
npyv_lanetype_u8 *dst = (npyv_lanetype_u8 *) args[2];
const npyv_u8 vzero = npyv_setall_u8(0x0);
const npyv_u8 vscalar = npyv_setall_u8(scalar);
- const npyv_u8 b = npyv_cvt_u8_b8(npyv_cmpneq_u8(vscalar, vzero));
+ const npyv_b8 b = npyv_cmpneq_u8(vscalar, vzero);
const npyv_u8 truemask = npyv_setall_u8(0x1);
const int vstep = npyv_nlanes_u8;
for (; len >= vstep; len -= vstep, src += vstep, dst += vstep) {
npyv_b8 a = npyv_cmpneq_u8(npyv_load_u8(src), vzero);
- npyv_b8 c = npyv_@VOP@_u8(npyv_cvt_u8_b8(a), b);
+#if !@rev@
+ npyv_b8 c = npyv_@VOP@_b8(a, b);
+#else
+ npyv_b8 c = npyv_@VOP@_b8(b, a);
+#endif
npyv_store_u8(dst, npyv_and_u8(npyv_cvt_u8_b8(c), truemask));
}
diff --git a/numpy/core/tests/test_simd.py b/numpy/core/tests/test_simd.py
index b0b62b4a2..81d759ad4 100644
--- a/numpy/core/tests/test_simd.py
+++ b/numpy/core/tests/test_simd.py
@@ -156,6 +156,48 @@ class _SIMD_BOOL(_Test_Utility):
tobits = bin(self.tobits(vdata))
assert tobits == bin(data_bits)
+ def test_andc(self):
+ if self.sfx not in ("b8"):
+ return
+ andc_simd = getattr(self.npyv, f"andc_b8")
+ # create the vectors
+ data = self._data()
+ rdata = self._data(reverse=True)
+ vdata = self._load_b(data)
+ vrdata = self._load_b(rdata)
+ # check andc
+ sandc = [(~x & y) & 0xFF for x, y in zip(rdata, data)]
+ vandc = andc_simd(vrdata, vdata)
+ assert sandc == vandc
+
+ def test_orc(self):
+ if self.sfx not in ("b8"):
+ return
+ orc_simd = getattr(self.npyv, f"orc_b8")
+ # create the vectors
+ data = self._data()
+ rdata = self._data(reverse=True)
+ vdata = self._load_b(data)
+ vrdata = self._load_b(rdata)
+ # check orc
+ sorc = [(~x | y) & 0xFF for x, y in zip(rdata, data)]
+ vorc = orc_simd(vrdata, vdata)
+ assert sorc == vorc
+
+ def test_xnor(self):
+ if self.sfx not in ("b8"):
+ return
+ xnor_simd = getattr(self.npyv, f"xnor_b8")
+ # create the vectors
+ data = self._data()
+ rdata = self._data(reverse=True)
+ vdata = self._load_b(data)
+ vrdata = self._load_b(rdata)
+ # check orc
+ sxnor = [~(x ^ y) & 0xFF for x, y in zip(rdata, data)]
+ vxnor = xnor_simd(vrdata, vdata)
+ assert sxnor == vxnor
+
def test_pack(self):
"""
Pack multiple vectors into one
@@ -166,15 +208,12 @@ class _SIMD_BOOL(_Test_Utility):
"""
if self.sfx not in ("b16", "b32", "b64"):
return
-
# create the vectors
data = self._data()
rdata = self._data(reverse=True)
vdata = self._load_b(data)
vrdata = self._load_b(rdata)
-
pack_simd = getattr(self.npyv, f"pack_b8_{self.sfx}")
-
# for scalar execution, concatenate the elements of the multiple lists
# into a single list (spack) and then iterate over the elements of
# the created list applying a mask to capture the first byte of them.