The following delays all edge pruning until inlining into a function
is complete.  This avoids crashes with stmt folding walking the
SSA use->def chain and arriving at PHIs without arguments.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2019-11-26  Richard Biener  <rguent...@suse.de>

        PR middle-end/92674
        * tree-inline.c (expand_call_inline): Delay purging EH/abnormal
        edges and instead record blocks in bitmap.
        (gimple_expand_calls_inline): Adjust.
        (fold_marked_statements): Delay EH cleanup until all folding is
        done.
        (optimize_inline_calls): Do EH/abnormal cleanup for calls after
        inlining finished.

Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c   (revision 278722)
+++ gcc/tree-inline.c   (working copy)
@@ -4623,7 +4623,8 @@ reset_debug_bindings (copy_body_data *id
 /* If STMT is a GIMPLE_CALL, replace it with its inline expansion.  */
 
 static bool
-expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
+expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
+                   bitmap to_purge)
 {
   tree use_retvar;
   tree fn;
@@ -4768,7 +4769,7 @@ expand_call_inline (basic_block bb, gimp
       gimple_call_set_fndecl (stmt, edge->callee->decl);
       update_stmt (stmt);
       id->src_node->remove ();
-      expand_call_inline (bb, stmt, id);
+      expand_call_inline (bb, stmt, id, to_purge);
       maybe_remove_unused_call_args (cfun, stmt);
       return true;
     }
@@ -5156,10 +5157,7 @@ expand_call_inline (basic_block bb, gimp
     }
 
   if (purge_dead_abnormal_edges)
-    {
-      gimple_purge_dead_eh_edges (return_block);
-      gimple_purge_dead_abnormal_call_edges (return_block);
-    }
+    bitmap_set_bit (to_purge, return_block->index);
 
   /* If the value of the new expression is ignored, that's OK.  We
      don't warn about this for CALL_EXPRs, so we shouldn't warn about
@@ -5197,7 +5195,8 @@ expand_call_inline (basic_block bb, gimp
    in a MODIFY_EXPR.  */
 
 static bool
-gimple_expand_calls_inline (basic_block bb, copy_body_data *id)
+gimple_expand_calls_inline (basic_block bb, copy_body_data *id,
+                           bitmap to_purge)
 {
   gimple_stmt_iterator gsi;
   bool inlined = false;
@@ -5209,7 +5208,7 @@ gimple_expand_calls_inline (basic_block
 
       if (is_gimple_call (stmt)
          && !gimple_call_internal_p (stmt))
-       inlined |= expand_call_inline (bb, stmt, id);
+       inlined |= expand_call_inline (bb, stmt, id, to_purge);
     }
 
   return inlined;
@@ -5222,6 +5221,7 @@ gimple_expand_calls_inline (basic_block
 static void
 fold_marked_statements (int first, hash_set<gimple *> *statements)
 {
+  auto_bitmap to_purge;
   for (; first < last_basic_block_for_fn (cfun); first++)
     if (BASIC_BLOCK_FOR_FN (cfun, first))
       {
@@ -5233,7 +5233,8 @@ fold_marked_statements (int first, hash_
          if (statements->contains (gsi_stmt (gsi)))
            {
              gimple *old_stmt = gsi_stmt (gsi);
-             tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl 
(old_stmt) : 0;
+             tree old_decl
+               = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
 
              if (old_decl && fndecl_built_in_p (old_decl))
                {
@@ -5277,8 +5278,7 @@ fold_marked_statements (int first, hash_
                                 is mood anyway.  */
                              if (maybe_clean_or_replace_eh_stmt (old_stmt,
                                                                  new_stmt))
-                               gimple_purge_dead_eh_edges (
-                                 BASIC_BLOCK_FOR_FN (cfun, first));
+                               bitmap_set_bit (to_purge, first);
                              break;
                            }
                          gsi_next (&i2);
@@ -5298,11 +5298,11 @@ fold_marked_statements (int first, hash_
                                                       new_stmt);
 
                  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
-                   gimple_purge_dead_eh_edges (BASIC_BLOCK_FOR_FN (cfun,
-                                                                   first));
+                   bitmap_set_bit (to_purge, first);
                }
            }
       }
+  gimple_purge_all_dead_eh_edges (to_purge);
 }
 
 /* Expand calls to inline functions in the body of FN.  */
@@ -5348,8 +5348,9 @@ optimize_inline_calls (tree fn)
      will split id->current_basic_block, and the new blocks will
      follow it; we'll trudge through them, processing their CALL_EXPRs
      along the way.  */
+  auto_bitmap to_purge;
   FOR_EACH_BB_FN (bb, cfun)
-    inlined_p |= gimple_expand_calls_inline (bb, &id);
+    inlined_p |= gimple_expand_calls_inline (bb, &id, to_purge);
 
   pop_gimplify_context (NULL);
 
@@ -5369,6 +5370,21 @@ optimize_inline_calls (tree fn)
   fold_marked_statements (last, id.statements_to_fold);
   delete id.statements_to_fold;
 
+  /* Finally purge EH and abnormal edges from the call stmts we inlined.
+     We need to do this after fold_marked_statements since that may walk
+     the SSA use-def chain.  */
+  unsigned i;
+  bitmap_iterator bi;
+  EXECUTE_IF_SET_IN_BITMAP (to_purge, 0, i, bi)
+    {
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
+      if (bb)
+       {
+         gimple_purge_dead_eh_edges (bb);
+         gimple_purge_dead_abnormal_call_edges (bb);
+       }
+    }
+
   gcc_assert (!id.debug_stmts.exists ());
 
   /* If we didn't inline into the function there is nothing to do.  */

Reply via email to