Now that more operations are allowed for noce_convert_multiple_sets, it is
possible that the same register appears multiple times as target in a
basic block.  After noce_convert_multiple_sets_1 is called we potentially
also emit register moves from temporaries back to the original targets.
In some cases where the target registers overlap with the block's condition,
these register moves may overwrite intermediate variables because they're
emitted after the if-converted code.  To address this issue we now iterate
backwards and keep track of seen registers when emitting these final register
moves.

Fix-up for the recent ifcvt commit 72c9b5f4

        PR rtl-optimization/116372
        PR rtl-optimization/116405

gcc/ChangeLog:

        * ifcvt.cc (noce_convert_multiple_sets): Iterate backwards and track
        target registers.

gcc/testsuite/ChangeLog:

        * gcc.dg/pr116372.c: New test.
        * gcc.dg/pr116405.c: New test.

Signed-off-by: Manolis Tsamis <manolis.tsa...@vrull.eu>
---

 gcc/ifcvt.cc                    | 22 ++++++++++++++++++----
 gcc/testsuite/gcc.dg/pr116372.c | 13 +++++++++++++
 gcc/testsuite/gcc.dg/pr116405.c | 17 +++++++++++++++++
 3 files changed, 48 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr116372.c
 create mode 100644 gcc/testsuite/gcc.dg/pr116405.c

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index da59c907891..36de036661b 100644
--- a/gcc/ifcvt.cc
+++ b/gcc/ifcvt.cc
@@ -3515,10 +3515,24 @@ noce_convert_multiple_sets (struct noce_if_info 
*if_info)
      given an empty BB to convert, and we can't handle that.  */
   gcc_assert (!insn_info.is_empty ());
 
-  /* Now fixup the assignments.  */
-  for (unsigned i = 0; i < insn_info.length (); i++)
-    if (insn_info[i]->target != insn_info[i]->temporary)
-      noce_emit_move_insn (insn_info[i]->target, insn_info[i]->temporary);
+  /* Now fixup the assignments.
+     PR116405: Iterate in reverse order and keep track of the targets so that
+     a move does not overwrite a subsequent value when multiple instructions
+     have the same target.  */
+  unsigned i;
+  noce_multiple_sets_info *info;
+  bitmap set_targets = BITMAP_ALLOC (&reg_obstack);
+  FOR_EACH_VEC_ELT_REVERSE (insn_info, i, info)
+    {
+      gcc_checking_assert (REG_P (info->target));
+
+      if (info->target != info->temporary
+         && !bitmap_bit_p (set_targets, REGNO (info->target)))
+       noce_emit_move_insn (info->target, info->temporary);
+
+      bitmap_set_bit (set_targets, REGNO (info->target));
+    }
+  BITMAP_FREE (set_targets);
 
   /* Actually emit the sequence if it isn't too expensive.  */
   rtx_insn *seq = get_insns ();
diff --git a/gcc/testsuite/gcc.dg/pr116372.c b/gcc/testsuite/gcc.dg/pr116372.c
new file mode 100644
index 00000000000..e9878ac5042
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr116372.c
@@ -0,0 +1,13 @@
+/* PR rtl-optimization/116372 */
+/* { dg-do run } */
+/* { dg-options "-O1" } */ 
+/* { dg-additional-options "-march=z13" { target s390x-*-* } } */
+
+long x = -0x7fffffff - 1;
+int main (void)
+{
+  long y = x % (-0xf - 1);
+  if (-0x7fffffff - 1 + y == x == 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr116405.c b/gcc/testsuite/gcc.dg/pr116405.c
new file mode 100644
index 00000000000..9223f15a298
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr116405.c
@@ -0,0 +1,17 @@
+/* PR rtl-optimization/116405 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-ssa-phiopt -fno-tree-dce" } */ 
+
+int printf(const char *, ...);
+int a, b = 2, c = 1;
+unsigned d, e;
+int main() {
+ L:
+  a = -1 / c;
+  d = ~(b && (c && ~e) & b);
+  printf("0\n");
+  c = 0;
+  if (d != -1)
+    goto L;
+  return 0;
+}
-- 
2.34.1

Reply via email to