Hi!

RTL DCE is called in different modes, sometimes it is allowed to alter cfg,
in other cases it is not.  The following testcase ICEs because when it is
not allowed to alter cfg (combiner's df_analyze) we remove a noop move that
was considered to potentially throw and that made a bb unreachable (which
the pass didn't like), but even removing those unreachable bbs would ICE
anyway, as the algorithm is for !can_alter_cfg not really prepared to see
bbs and edges being removed.

So, the following patch does 3 things:
1) doesn't delete noop moves if they can
   throw and we can't alter cfg or delete dead exceptions
2) instead of setting must_clean blindly for any CALL_INSNs, it instead
   sets it accurately from delete_insn_and_edges return value
3) it asserts that if !can_alter_cfg we don't actually have must_clean set

Bootstrapped/regtested on powerpc64{,le}-linux, ok for trunk?

2019-02-05  Jakub Jelinek  <ja...@redhat.com>

        PR target/89188
        * dce.c (delete_unmarked_insns): Don't remove no-op moves if they
        can throw, non-call exceptions are enabled and we can't delete
        dead exceptions or alter cfg.  Set must_clean if
        delete_insn_and_edges returns true, don't set it blindly for calls.
        Assert that delete_unreachable_blocks is called only if can_alter_cfg.

        * g++.dg/opt/pr89188.C: New test.

--- gcc/dce.c.jj        2019-02-05 10:04:16.984062429 +0100
+++ gcc/dce.c   2019-02-05 10:53:47.655584503 +0100
@@ -584,7 +584,12 @@ delete_unmarked_insns (void)
          rtx turn_into_use = NULL_RTX;
 
          /* Always delete no-op moves.  */
-         if (noop_move_p (insn))
+         if (noop_move_p (insn)
+             /* Unless the no-op move can throw and we are not allowed
+                to alter cfg.  */
+             && (!cfun->can_throw_non_call_exceptions
+                 || (cfun->can_delete_dead_exceptions && can_alter_cfg)
+                 || insn_nothrow_p (insn)))
            {
              if (RTX_FRAME_RELATED_P (insn))
                turn_into_use
@@ -627,12 +632,6 @@ delete_unmarked_insns (void)
             for the destination regs in order to avoid dangling notes.  */
          remove_reg_equal_equiv_notes_for_defs (insn);
 
-         /* If a pure or const call is deleted, this may make the cfg
-            have unreachable blocks.  We rememeber this and call
-            delete_unreachable_blocks at the end.  */
-         if (CALL_P (insn))
-           must_clean = true;
-
          if (turn_into_use)
            {
              /* Don't remove frame related noop moves if they cary
@@ -645,12 +644,15 @@ delete_unmarked_insns (void)
            }
          else
            /* Now delete the insn.  */
-           delete_insn_and_edges (insn);
+           must_clean |= delete_insn_and_edges (insn);
        }
 
   /* Deleted a pure or const call.  */
   if (must_clean)
-    delete_unreachable_blocks ();
+    {
+      gcc_assert (can_alter_cfg);
+      delete_unreachable_blocks ();
+    }
 }
 
 
--- gcc/testsuite/g++.dg/opt/pr89188.C.jj       2019-02-04 14:20:57.714851393 
+0100
+++ gcc/testsuite/g++.dg/opt/pr89188.C  2019-02-04 14:52:09.988782531 +0100
@@ -0,0 +1,5 @@
+// PR target/89188
+// { dg-do compile { target c++11 } }
+// { dg-options "-Og -flive-range-shrinkage -fnon-call-exceptions" }
+
+#include "../torture/pr88861.C"

        Jakub

Reply via email to