Our power8 swap optimization pass has some special handling for optimizing
swaps of TImode variables.  The test case reported in bugzilla uses a call
to  __atomic_compare_exchange, which introduces a variable of PTImode and
that does not get the same treatment as TImode leading to wrong code
generation.  The simple fix is to treat PTImode identically to TImode.

This passed bootstrap and regtesting on powerpc64le-linux with no regressions.
I also confirmed the testcase is correctly not run on -m32 BE and passes
on -m64 BE.

Ok for trunk?


This is broken back to GCC 12, so ok for the releases branches after some
bake-in time on trunk?

Peter


gcc/
        PR target/116415
        * config/rs6000/rs6000-p8swap.cc (rs6000_analyze_swaps): Handle PTImode
        identically to TImode.

gcc/testsuite/
        PR target/116415
        * gcc.target/powerpc/pr116415.c: New test.


diff --git a/gcc/config/rs6000/rs6000-p8swap.cc 
b/gcc/config/rs6000/rs6000-p8swap.cc
index 639f477d782..15e44bb63a6 100644
--- a/gcc/config/rs6000/rs6000-p8swap.cc
+++ b/gcc/config/rs6000/rs6000-p8swap.cc
@@ -2469,10 +2469,11 @@ rs6000_analyze_swaps (function *fun)
                    mode = V4SImode;
                }
 
-             if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode)
+             if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode
+                 || mode == PTImode)
                {
                  insn_entry[uid].is_relevant = 1;
-                 if (mode == TImode || mode == V1TImode
+                 if (mode == TImode || mode == PTImode || mode == V1TImode
                      || FLOAT128_VECTOR_P (mode))
                    insn_entry[uid].is_128_int = 1;
                  if (DF_REF_INSN_INFO (mention))
@@ -2497,10 +2498,11 @@ rs6000_analyze_swaps (function *fun)
                  && ALTIVEC_OR_VSX_VECTOR_MODE (GET_MODE (SET_DEST (insn))))
                mode = GET_MODE (SET_DEST (insn));
 
-             if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode)
+             if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode
+                 || mode == PTImode)
                {
                  insn_entry[uid].is_relevant = 1;
-                 if (mode == TImode || mode == V1TImode
+                 if (mode == TImode || mode == PTImode || mode == V1TImode
                      || FLOAT128_VECTOR_P (mode))
                    insn_entry[uid].is_128_int = 1;
                  if (DF_REF_INSN_INFO (mention))
diff --git a/gcc/testsuite/gcc.target/powerpc/pr116415.c 
b/gcc/testsuite/gcc.target/powerpc/pr116415.c
new file mode 100644
index 00000000000..5fad810ceb0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr116415.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -mdejagnu-cpu=power8" } */
+
+/* PR 116415: Verify our Power8 swap optimization pass doesn't incorrectly swap
+   PTImode values.  They should be handled identically to TImode values.  */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef union {
+  struct {
+    uint64_t a;
+    uint64_t b;
+  } t;
+  __uint128_t data;
+} Value;
+Value value, next;
+
+void
+bug (Value *val, Value *nxt)
+{
+  for (;;) {
+    nxt->t.a = val->t.a + 1;
+    nxt->t.b = val->t.b + 2;
+    if (__atomic_compare_exchange (&val->data, &val->data, &nxt->data,
+                                  0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))
+      break;
+  }
+}
+
+int
+main (void)
+{
+  bug (&value, &next);
+  printf ("%lu %lu\n", value.t.a, value.t.b);
+  if (value.t.a != 1 || value.t.b != 2)
+    abort ();
+  return 0;
+}

Reply via email to