]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ifcvt: Do not overwrite results in noce_convert_multiple_sets [PR116372, PR116405]
authorManolis Tsamis <manolis.tsamis@vrull.eu>
Tue, 20 Aug 2024 07:16:29 +0000 (09:16 +0200)
committerPhilipp Tomsich <philipp.tomsich@vrull.eu>
Fri, 23 Aug 2024 18:19:55 +0000 (20:19 +0200)
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.

gcc/ifcvt.cc
gcc/testsuite/gcc.dg/pr116372.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr116405.c [new file with mode: 0644]

index b136d7dbbba3cf15a976a2d3c454150e10cebca5..6487574c5149412e98ff49f286385ab2726fbc91 100644 (file)
@@ -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 (file)
index 0000000..e9878ac
--- /dev/null
@@ -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 (file)
index 0000000..9223f15
--- /dev/null
@@ -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;
+}