The big-endian vbpermq permute constant in _mm_movemask_ps lists the
four sign-bit indices as 0x00 0x20 0x40 0x60, which puts element 0 in
the most significant of the four result bits, while x86 (and the
little-endian branch) put element 0 in bit 0. Reverse the order so
big-endian returns the same mask as x86. _mm_movemask_pd and
_mm_movemask_epi8 are already correct on both endians.
The existing sse-movmskps-1.c test cannot catch this: its input has
negative values in elements 0 and 3 only, and that mask reads the same
in either bit order. Add a variant with an asymmetric input.
Tested with GCC 14 on powerpc64-unknown-freebsd15.1 (POWER9,
-mcpu=power8): {-1, 2, -3, 4} returned 10 instead of 5 before the fix.
Assisted-by: Claude Fable 5.1
gcc/ChangeLog:
* config/rs6000/xmmintrin.h (_mm_movemask_ps): Fix big-endian
permute constant.
gcc/testsuite/ChangeLog:
* gcc.target/powerpc/sse-movmskps-2.c: New test.
Signed-off-by: Piotr Kubaj <[email protected]>
---
gcc/config/rs6000/xmmintrin.h | 2 +-
.../gcc.target/powerpc/sse-movmskps-2.c | 45 +++++++++++++++++++
2 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.target/powerpc/sse-movmskps-2.c
diff --git a/gcc/config/rs6000/xmmintrin.h b/gcc/config/rs6000/xmmintrin.h
index bd5be19..79a2a4a 100644
--- a/gcc/config/rs6000/xmmintrin.h
+++ b/gcc/config/rs6000/xmmintrin.h
@@ -1361,7 +1361,7 @@ _mm_movemask_ps (__m128 __A)
#ifdef __LITTLE_ENDIAN__
0x00204060, 0x80808080, 0x80808080, 0x80808080
#else
- 0x80808080, 0x80808080, 0x80808080, 0x00204060
+ 0x80808080, 0x80808080, 0x80808080, 0x60402000
#endif
};
diff --git a/gcc/testsuite/gcc.target/powerpc/sse-movmskps-2.c
b/gcc/testsuite/gcc.target/powerpc/sse-movmskps-2.c
new file mode 100644
index 0000000..77a4d96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/sse-movmskps-2.c
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -mvsx" } */
+/* { dg-additional-options "-mdejagnu-cpu=power8" { target { ! has_arch_pwr8 }
} } */
+/* { dg-require-effective-target p8vector_hw } */
+
+#define NO_WARN_X86_INTRINSICS 1
+
+#ifndef CHECK_H
+#define CHECK_H "sse-check.h"
+#endif
+
+#include CHECK_H
+
+#ifndef TEST
+#define TEST sse_test_movmskps_2
+#endif
+
+#include <xmmintrin.h>
+
+static int
+__attribute__((noinline, unused))
+test (__m128 a)
+{
+ return _mm_movemask_ps (a);
+}
+
+static void
+TEST (void)
+{
+ union128 u;
+ float s[4] = {-1.0, 2.0, -3.0, 4.0};
+ int d;
+ int e = 0;
+ int i;
+
+ u.x = _mm_loadu_ps (s);
+ d = test (u.x);
+
+ for (i = 0; i < 4; i++)
+ if (s[i] < 0)
+ e |= (1 << i);
+
+ if (checkVi (&d, &e, 1))
+ abort ();
+}
--
2.55.0