https://gcc.gnu.org/g:a9f5e23aba1a6f4ec32f1147b340a8145d827da9

commit r15-3138-ga9f5e23aba1a6f4ec32f1147b340a8145d827da9
Author: Manolis Tsamis <manolis.tsa...@vrull.eu>
Date:   Tue Aug 20 09:16:29 2024 +0200

    ifcvt: Do not overwrite results in noce_convert_multiple_sets [PR116372, 
PR116405]
    
    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.
    
            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.

Diff:
---
 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(-)

diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
index b136d7dbbba3..6487574c5149 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 000000000000..e9878ac5042b
--- /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 000000000000..9223f15a2987
--- /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;
+}

Reply via email to