tree-cfg.c (verify_stmt): Add last_in_block parameter.
authorRichard Henderson <rth@redhat.com>
Tue, 29 Jun 2004 06:59:35 +0000 (23:59 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 29 Jun 2004 06:59:35 +0000 (23:59 -0700)
        * tree-cfg.c (verify_stmt): Add last_in_block parameter.  Verify
        that eh stmts can throw.
        (verify_stmts): Update verify_stmt call.
        (tree_purge_dead_eh_edges, tree_purge_all_dead_eh_edges): New.
        * tree-eh.c (remove_stmt_from_eh_region): New.
        (lower_eh_constructs): Fix throw_stmt_table delete routine.
        (tree_could_trap_p): Match may_trap_p.
        (maybe_clean_eh_stmt): New.
        * tree-flow.h: Update decls.
        * tree-ssa-ccp.c (pass_ccp): Add TODO_verify_stmts.
        (substitute_and_fold): Clean eh edges.
        * tree-ssa-dce.c (mark_control_dependent_edges_necessary): Handle
        empty basic blocks.
        * tree-ssa-dom.c (need_eh_cleanup): New.
        (tree_ssa_dominator_optimize): Allocate it.  Cleanup eh edges.
        (optimize_stmt): Cleanup eh stmts; set need_eh_cleanup.

From-SVN: r83843

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-eh.c
gcc/tree-flow.h
gcc/tree-ssa-ccp.c
gcc/tree-ssa-dce.c
gcc/tree-ssa-dom.c

index 7403553b1710fff0eb11a85063e9799fb81e071e..854141fed44731a34259ea586f2cbaf01ad0611b 100644 (file)
@@ -1,3 +1,22 @@
+2004-06-28  Richard Henderson  <rth@redhat.com>
+
+       * tree-cfg.c (verify_stmt): Add last_in_block parameter.  Verify
+       that eh stmts can throw.
+       (verify_stmts): Update verify_stmt call.
+       (tree_purge_dead_eh_edges, tree_purge_all_dead_eh_edges): New.
+       * tree-eh.c (remove_stmt_from_eh_region): New.
+       (lower_eh_constructs): Fix throw_stmt_table delete routine.
+       (tree_could_trap_p): Match may_trap_p.
+       (maybe_clean_eh_stmt): New.
+       * tree-flow.h: Update decls.
+       * tree-ssa-ccp.c (pass_ccp): Add TODO_verify_stmts.
+       (substitute_and_fold): Clean eh edges.
+       * tree-ssa-dce.c (mark_control_dependent_edges_necessary): Handle
+       empty basic blocks.
+       * tree-ssa-dom.c (need_eh_cleanup): New.
+       (tree_ssa_dominator_optimize): Allocate it.  Cleanup eh edges.
+       (optimize_stmt): Cleanup eh stmts; set need_eh_cleanup.
+       
 2004-06-29  Alan Modra  <amodra@bigpond.net.au>
 
        * function.c (assign_parms): Don't abort with zero size stack
index 6855d712833a9b77d9440bcd4dfbb7cb1928699d..88e66f7badce6c3fb4e0688d0bf1f81fb3ccce9a 100644 (file)
@@ -3316,15 +3316,14 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
    TODO: Implement type checking.  */
 
 static bool
-verify_stmt (tree stmt)
+verify_stmt (tree stmt, bool last_in_block)
 {
   tree addr;
 
   if (!is_gimple_stmt (stmt))
     {
       error ("Is not a valid GIMPLE statement.");
-      debug_generic_stmt (stmt);
-      return true;
+      goto fail;
     }
 
   addr = walk_tree (&stmt, verify_expr, NULL, NULL);
@@ -3334,7 +3333,30 @@ verify_stmt (tree stmt)
       return true;
     }
 
+  /* If the statement is marked as part of an EH region, then it is
+     expected that the statement could throw.  Verify that when we
+     have optimizations that simplify statements such that we prove
+     that they cannot throw, that we update other data structures
+     to match.  */
+  if (lookup_stmt_eh_region (stmt) >= 0)
+    {
+      if (!tree_could_throw_p (stmt))
+       {
+         error ("Statement marked for throw, but doesn't.");
+         goto fail;
+       }
+      if (!last_in_block && tree_can_throw_internal (stmt))
+       {
+         error ("Statement marked for throw in middle of block.");
+         goto fail;
+       }
+    }
+
   return false;
+
+ fail:
+  debug_generic_stmt (stmt);
+  return true;
 }
 
 
@@ -3449,10 +3471,11 @@ verify_stmts (void)
            }
        }
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
        {
          tree stmt = bsi_stmt (bsi);
-         err |= verify_stmt (stmt);
+         bsi_next (&bsi);
+         err |= verify_stmt (stmt, bsi_end_p (bsi));
          addr = walk_tree (&stmt, verify_node_sharing, htab, NULL);
          if (addr)
            {
@@ -4637,6 +4660,40 @@ tree_flow_call_edges_add (sbitmap blocks)
   return blocks_split;
 }
 
+bool
+tree_purge_dead_eh_edges (basic_block bb)
+{
+  bool changed = false;
+  edge e, next;
+  tree stmt = last_stmt (bb);
+
+  if (stmt && tree_can_throw_internal (stmt))
+    return false;
+
+  for (e = bb->succ; e ; e = next)
+    {
+      next = e->succ_next;
+      if (e->flags & EDGE_EH)
+       {
+         ssa_remove_edge (e);
+         changed = true;
+       }
+    }
+
+  return changed;
+}
+
+bool
+tree_purge_all_dead_eh_edges (bitmap blocks)
+{
+  bool changed = false;
+  size_t i;
+
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i,
+    { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); });
+
+  return changed;
+}
 
 struct cfg_hooks tree_cfg_hooks = {
   "tree",
index f15fe0991420f33b779ab0d04ab43f0001d5b9c0..c0ddf3e7c3c6c8a6e089bc0cdd88166268be49e0 100644 (file)
@@ -119,7 +119,27 @@ add_stmt_to_eh_region (tree t, int num)
     abort ();
   *slot = n;
 }
-  
+
+bool
+remove_stmt_from_eh_region (tree t)
+{
+  struct throw_stmt_node dummy;
+  void **slot;
+
+  if (!throw_stmt_table)
+    return false;
+
+  dummy.stmt = t;
+  slot = htab_find_slot (throw_stmt_table, &dummy, NO_INSERT);
+  if (slot)
+    {
+      htab_clear_slot (throw_stmt_table, slot);
+      return true;
+    }
+  else
+    return false;
+}
+
 int
 lookup_stmt_eh_region (tree t)
 {
@@ -1600,7 +1620,8 @@ lower_eh_constructs (void)
   tree *tp = &DECL_SAVED_TREE (current_function_decl);
 
   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
-  throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq, free);
+  throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq,
+                                     ggc_free);
 
   collect_finally_tree (*tp, NULL);
 
@@ -1670,15 +1691,32 @@ make_eh_edges (tree stmt)
 
 
 \f
-/* Return true if the expr can trap, as in dereferencing an
-   invalid pointer location.  */
+/* Return true if the expr can trap, as in dereferencing an invalid pointer
+   location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
+   This routine expects only GIMPLE lhs or rhs input.  */
 
 bool
 tree_could_trap_p (tree expr)
 {
   enum tree_code code = TREE_CODE (expr);
+  bool honor_nans = false;
+  bool honor_snans = false;
+  bool fp_operation = false;
   tree t;
 
+  if (TREE_CODE_CLASS (code) == '<'
+      || TREE_CODE_CLASS (code) == '1'
+      || TREE_CODE_CLASS (code) == '2')
+    {
+      t = TREE_TYPE (expr);
+      fp_operation = FLOAT_TYPE_P (t);
+      if (fp_operation)
+       {
+         honor_nans = flag_trapping_math && !flag_finite_math_only;
+         honor_snans = flag_signaling_nans != 0;
+       }
+    }
+
   switch (code)
     {
     case ARRAY_REF:
@@ -1691,7 +1729,10 @@ tree_could_trap_p (tree expr)
       return !t || tree_could_trap_p (t);
 
     case INDIRECT_REF:
-      return (TREE_THIS_NOTRAP (expr) == false);
+      return !TREE_THIS_NOTRAP (expr);
+
+    case ASM_EXPR:
+      return TREE_THIS_VOLATILE (expr);
 
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
@@ -1702,16 +1743,57 @@ tree_could_trap_p (tree expr)
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case TRUNC_MOD_EXPR:
-      return true;
+    case RDIV_EXPR:
+      if (honor_snans)
+       return true;
+      if (fp_operation && flag_trapping_math)
+       return true;
+      t = TREE_OPERAND (expr, 1);
+      if (!TREE_CONSTANT (t) || integer_zerop (t))
+        return true;
+      return false;
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case LTGT_EXPR:
+      /* Some floating point comparisons may trap.  */
+      return honor_nans;
+
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+      return honor_snans;
+
+    case CONVERT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIX_CEIL_EXPR:
+    case FIX_FLOOR_EXPR:
+    case FIX_ROUND_EXPR:
+      /* Conversion of floating point might trap.  */
+      return honor_nans;
+
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case CONJ_EXPR:
+      /* These operations don't trap even with floating point.  */
+      return false;
 
     default:
-      break;
+      /* Any floating arithmetic may trap.  */
+      if (fp_operation && flag_trapping_math)
+       return true;
+      return false;
     }
-
-  return false;
 }
 
-
 bool
 tree_could_throw_p (tree t)
 {
@@ -1750,4 +1832,13 @@ tree_can_throw_external (tree stmt)
   return can_throw_external_1 (region_nr);
 }
 
+bool
+maybe_clean_eh_stmt (tree stmt)
+{
+  if (!tree_could_throw_p (stmt))
+    if (remove_stmt_from_eh_region (stmt))
+      return true;
+  return false;
+}
+
 #include "gt-tree-eh.h"
index 0f97a5b9cf1a533efd4a71f4ca6ed33ae035c2ff..8b6690b21e7b4af1d5c39c248e5582ade976fbe4 100644 (file)
@@ -497,6 +497,8 @@ extern void compute_dominance_frontiers (bitmap *);
 extern void verify_stmts (void);
 extern tree tree_block_label (basic_block bb);
 extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
+extern bool tree_purge_dead_eh_edges (basic_block);
+extern bool tree_purge_all_dead_eh_edges (bitmap);
 
 /* In tree-pretty-print.c.  */
 extern void dump_generic_bb (FILE *, basic_block, int, int);
@@ -600,7 +602,10 @@ extern bool tree_could_trap_p (tree);
 extern bool tree_could_throw_p (tree);
 extern bool tree_can_throw_internal (tree);
 extern bool tree_can_throw_external (tree);
+extern int lookup_stmt_eh_region (tree);
 extern void add_stmt_to_eh_region (tree, int);
+extern bool remove_stmt_from_eh_region (tree);
+extern bool maybe_clean_eh_stmt (tree);
 
 /* In tree-ssa-pre.c  */
 void add_to_value (tree, tree);
index ef0c12be3783b9e55b03b733d6532e256549d50e..559f19b0765218540e8eedffc1e95ef30e542048 100644 (file)
@@ -248,7 +248,8 @@ struct tree_opt_pass pass_ccp =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_rename_vars
-    | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */
+    | TODO_ggc_collect | TODO_verify_ssa
+    | TODO_verify_stmts                        /* todo_flags_finish */
 };
 
 
@@ -427,7 +428,11 @@ substitute_and_fold (void)
              /* If we folded a builtin function, we'll likely
                 need to rename VDEFs.  */
              if (replaced_address || changed)
-               mark_new_vars_to_rename (stmt, vars_to_rename);
+               {
+                 mark_new_vars_to_rename (stmt, vars_to_rename);
+                 if (maybe_clean_eh_stmt (stmt))
+                   tree_purge_dead_eh_edges (bb);
+               }
            }
 
          if (dump_file && (dump_flags & TDF_DETAILS))
index 344f2249ada2d17126b608e65262a2900561bbf9..e9ead5c0dfbc4b08a735024e766eb845f5955775 100644 (file)
@@ -500,7 +500,7 @@ mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el)
       SET_BIT (last_stmt_necessary, cd_bb->index);
 
       t = last_stmt (cd_bb);
-      if (is_ctrl_stmt (t))
+      if (t && is_ctrl_stmt (t))
        mark_stmt_necessary (t, true);
     });
 }
index 287807477366bea6da3198c267fb0f865236dd13..ddd803bc4ba250de3cdbfdbac4a37274fec3cffa 100644 (file)
@@ -95,6 +95,10 @@ static bitmap nonzero_vars;
 /* Track whether or not we have changed the control flow graph.  */
 static bool cfg_altered;
 
+/* Bitmap of blocks that have had EH statements cleaned.  We should
+   remove thier dead edges eventually.  */
+static bitmap need_eh_cleanup;
+
 /* Statistics for dominator optimizations.  */
 struct opt_stats_d
 {
@@ -554,6 +558,7 @@ tree_ssa_dominator_optimize (void)
   nonzero_vars = BITMAP_XMALLOC ();
   VARRAY_EDGE_INIT (redirection_edges, 20, "redirection_edges");
   VARRAY_GENERIC_PTR_INIT (vrp_data, num_ssa_names, "vrp_data");
+  need_eh_cleanup = BITMAP_XMALLOC ();
 
   /* Setup callbacks for the generic dominator tree walker.  */
   walk_data.walk_stmts_backward = false;
@@ -599,15 +604,24 @@ tree_ssa_dominator_optimize (void)
       if (VARRAY_ACTIVE_SIZE (redirection_edges) > 0)
        redirect_edges_and_update_ssa_graph (redirection_edges);
 
+      if (bitmap_first_set_bit (need_eh_cleanup) >= 0)
+       {
+         cfg_altered = tree_purge_all_dead_eh_edges (need_eh_cleanup);
+         bitmap_zero (need_eh_cleanup);
+       }
+
       /* We may have made some basic blocks unreachable, remove them.  */
       cfg_altered |= delete_unreachable_blocks ();
 
       /* If the CFG was altered, then recompute the dominator tree.  This
         is not strictly needed if we only removed unreachable blocks, but
         may produce better results.  If we threaded jumps, then rebuilding
-        the dominator tree is strictly necessary.  */
+        the dominator tree is strictly necessary.  Likewise with EH cleanup.
+        Free the dominance info first so that cleanup_tree_cfg doesn't try
+        to verify it.  */
       if (cfg_altered)
        {
+          free_dominance_info (CDI_DOMINATORS);
          cleanup_tree_cfg ();
          calculate_dominance_info (CDI_DOMINATORS);
        }
@@ -656,6 +670,7 @@ tree_ssa_dominator_optimize (void)
 
   /* Free nonzero_vars.   */
   BITMAP_XFREE (nonzero_vars);
+  BITMAP_XFREE (need_eh_cleanup);
 }
 
 static bool
@@ -2985,8 +3000,7 @@ cprop_into_stmt (tree stmt, varray_type const_and_copies)
       the variable in the LHS in the CONST_AND_COPIES table.  */
 
 static void
-optimize_stmt (struct dom_walk_data *walk_data,
-              basic_block bb ATTRIBUTE_UNUSED,
+optimize_stmt (struct dom_walk_data *walk_data, basic_block bb,
               block_stmt_iterator si)
 {
   stmt_ann_t ann;
@@ -3100,11 +3114,19 @@ optimize_stmt (struct dom_walk_data *walk_data,
       else if (TREE_CODE (stmt) == SWITCH_EXPR)
        val = SWITCH_COND (stmt);
 
-      if (val && TREE_CODE (val) == INTEGER_CST
-         && find_taken_edge (bb_for_stmt (stmt), val))
+      if (val && TREE_CODE (val) == INTEGER_CST && find_taken_edge (bb, val))
        cfg_altered = true;
+
+      /* If we simplified a statement in such a way as to be shown that it
+        cannot trap, update the eh information and the cfg to match.  */
+      if (maybe_clean_eh_stmt (stmt))
+       {
+         bitmap_set_bit (need_eh_cleanup, bb->index);
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file, "  Flagged to clear EH edges.\n");
+       }
     }
-                                                                                
+
   if (may_have_exposed_new_symbols)
     {
       if (! bd->stmts_to_rescan)