OSDN Git Service

* cgraph.c (cgraph_make_edge, dump_cgraph_node, cgraph_set_call_stmt):
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 18 Apr 2009 18:39:52 +0000 (18:39 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 18 Apr 2009 18:39:52 +0000 (18:39 +0000)
Set nothrow flag.
* cgraph.h (struct function): Reduce loop_nest to 30 bits; add
can_throw_external flag.
* ipa-reference.c (ipa_utils_reduced_inorder): Update call.
* ipa-pure-const.c (ignore_edge): New function.
(propagate): Compute order for NOTHROW computation; set NOTHROWs
only over can_throw_external edges.
(local_pure_const): Add nothrow flag.
* ipa-utils.c (searchc): Add ignore_edge callback.
(ipa_utils_reduced_inorder): Add ignore_edge callback.
* ipa-utils.h (ipa_utils_reduced_inorder): Update prototype.
(set_nothrow_function_flags): Update cgraph.
* tree-cfg.c (verify_stmt): Relax nothrow checking when in IPA mode.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@146322 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraph.h
gcc/except.c
gcc/ipa-pure-const.c
gcc/ipa-reference.c
gcc/ipa-utils.c
gcc/ipa-utils.h
gcc/tree-cfg.c

index 19806f5..33cea05 100644 (file)
@@ -1,3 +1,20 @@
+2009-04-18  Jan Hubicka  <jh@suse.cz>
+
+       * cgraph.c (cgraph_make_edge, dump_cgraph_node, cgraph_set_call_stmt):
+       Set nothrow flag.
+       * cgraph.h (struct function): Reduce loop_nest to 30 bits; add
+       can_throw_external flag.
+       * ipa-reference.c (ipa_utils_reduced_inorder): Update call.
+       * ipa-pure-const.c (ignore_edge): New function.
+       (propagate): Compute order for NOTHROW computation; set NOTHROWs
+       only over can_throw_external edges.
+       (local_pure_const): Add nothrow flag.
+       * ipa-utils.c (searchc): Add ignore_edge callback.
+       (ipa_utils_reduced_inorder): Add ignore_edge callback.
+       * ipa-utils.h (ipa_utils_reduced_inorder): Update prototype.
+       (set_nothrow_function_flags): Update cgraph.
+       * tree-cfg.c (verify_stmt): Relax nothrow checking when in IPA mode.
+
 2009-04-18  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/39804
index 86642ab..f7189b9 100644 (file)
@@ -640,6 +640,7 @@ cgraph_set_call_stmt (struct cgraph_edge *e, gimple new_stmt)
                                 htab_hash_pointer (e->call_stmt));
     }
   e->call_stmt = new_stmt;
+  e->can_throw_external = stmt_can_throw_external (new_stmt);
   if (e->caller->call_site_hash)
     {
       void **slot;
@@ -704,6 +705,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
   edge->caller = caller;
   edge->callee = callee;
   edge->call_stmt = call_stmt;
+  edge->can_throw_external = stmt_can_throw_external (call_stmt);
   edge->prev_caller = NULL;
   edge->next_caller = callee->callers;
   if (callee->callers)
@@ -1215,6 +1217,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
        fprintf(f, "(inlined) ");
       if (edge->indirect_call)
        fprintf(f, "(indirect) ");
+      if (edge->can_throw_external)
+       fprintf(f, "(can throw external) ");
     }
 
   fprintf (f, "\n  calls: ");
index aba0e59..347653f 100644 (file)
@@ -216,9 +216,11 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call
      per function call.  The range is 0 to CGRAPH_FREQ_MAX.  */
   int frequency;
   /* Depth of loop nest, 1 means no loop nest.  */
-  unsigned int loop_nest : 31;
+  unsigned int loop_nest : 30;
   /* Whether this edge describes a call that was originally indirect.  */
   unsigned int indirect_call : 1;
+  /* Can this call throw externally?  */
+  unsigned int can_throw_external : 1;
   /* Unique id of the edge.  */
   int uid;
 };
index 9874b59..bc3b8c4 100644 (file)
@@ -2846,6 +2846,10 @@ set_nothrow_function_flags (void)
                                             (current_function_decl))
           >= AVAIL_AVAILABLE))
     {
+      struct cgraph_node *node = cgraph_node (current_function_decl);
+      struct cgraph_edge *e;
+      for (e = node->callers; e; e = e->next_caller)
+        e->can_throw_external = false;
       TREE_NOTHROW (current_function_decl) = 1;
 
       if (dump_file)
index ca4da1c..1aef09f 100644 (file)
@@ -637,6 +637,12 @@ generate_summary (void)
   visited_nodes = NULL;
 }
 
+static bool
+ignore_edge (struct cgraph_edge *e)
+{
+  return (!e->can_throw_external);
+}
+
 /* Produce the global information by preforming a transitive closure
    on the local information that was produced by generate_summary.
    Note that there is no function_transform pass since this only
@@ -656,7 +662,7 @@ propagate (void)
   cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
   cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
   cgraph_remove_node_removal_hook (node_removal_hook_holder);
-  order_pos = ipa_utils_reduced_inorder (order, true, false);
+  order_pos = ipa_utils_reduced_inorder (order, true, false, NULL);
   if (dump_file)
     {
       dump_cgraph (dump_file);
@@ -671,7 +677,6 @@ propagate (void)
     {
       enum pure_const_state_e pure_const_state = IPA_CONST;
       bool looping = false;
-      bool can_throw = false;
       int count = 0;
       node = order[i];
 
@@ -684,13 +689,10 @@ propagate (void)
          if (pure_const_state < w_l->pure_const_state)
            pure_const_state = w_l->pure_const_state;
 
-         if (w_l->can_throw)
-           can_throw = true;
          if (w_l->looping)
            looping = true;
 
-         if (pure_const_state == IPA_NEITHER
-             && can_throw)
+         if (pure_const_state == IPA_NEITHER)
            break;
 
          count++;
@@ -707,16 +709,10 @@ propagate (void)
                  funct_state y_l = get_function_state (y);
                  if (pure_const_state < y_l->pure_const_state)
                    pure_const_state = y_l->pure_const_state;
-                 if (pure_const_state == IPA_NEITHER
-                     && can_throw) 
+                 if (pure_const_state == IPA_NEITHER)
                    break;
                  if (y_l->looping)
                    looping = true;
-                 if (y_l->can_throw && !TREE_NOTHROW (w->decl)
-                     /* FIXME: We should check that the throw can get external.
-                        We also should handle only loops formed by can throw external
-                        edges.  */)
-                   can_throw = true;
                }
            }
          w_info = (struct ipa_dfs_info *) w->aux;
@@ -766,12 +762,80 @@ propagate (void)
            default:
              break;
            }
+         w_info = (struct ipa_dfs_info *) w->aux;
+         w = w_info->next_cycle;
+       }
+    }
+
+  /* Cleanup. */
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+      /* Get rid of the aux information.  */
+      if (node->aux)
+       {
+         w_info = (struct ipa_dfs_info *) node->aux;
+         free (node->aux);
+         node->aux = NULL;
+       }
+    }
+  order_pos = ipa_utils_reduced_inorder (order, true, false, ignore_edge);
+  if (dump_file)
+    {
+      dump_cgraph (dump_file);
+      ipa_utils_print_order(dump_file, "reduced for nothrow", order, order_pos);
+    }
+  /* Propagate the local information thru the call graph to produce
+     the global information.  All the nodes within a cycle will have
+     the same info so we collapse cycles first.  Then we can do the
+     propagation in one pass from the leaves to the roots.  */
+  for (i = 0; i < order_pos; i++ )
+    {
+      bool can_throw = false;
+      node = order[i];
+
+      /* Find the worst state for any node in the cycle.  */
+      w = node;
+      while (w)
+       {
+         struct cgraph_edge *e;
+         funct_state w_l = get_function_state (w);
+
+         if (w_l->can_throw)
+           can_throw = true;
+
+         if (can_throw)
+           break;
+               
+         for (e = w->callees; e; e = e->next_callee) 
+           {
+             struct cgraph_node *y = e->callee;
+
+             if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE)
+               {
+                 funct_state y_l = get_function_state (y);
+
+                 if (can_throw) 
+                   break;
+                 if (y_l->can_throw && !TREE_NOTHROW (w->decl)
+                     && e->can_throw_external)
+                   can_throw = true;
+               }
+           }
+         w_info = (struct ipa_dfs_info *) w->aux;
+         w = w_info->next_cycle;
+       }
+
+      /* Copy back the region's pure_const_state which is shared by
+        all nodes in the region.  */
+      w = node;
+      while (w)
+       {
          if (!can_throw && !TREE_NOTHROW (w->decl))
            {
-             /* FIXME: TREE_NOTHROW is not set because passmanager will execute
-                verify_ssa and verify_cfg on every function.  Before fixup_cfg is done,
-                those functions are going to have NOTHROW calls in EH regions reulting
-                in ICE.  */
+             struct cgraph_edge *e;
+             TREE_NOTHROW (w->decl) = true;
+             for (e = w->callers; e; e = e->next_caller)
+               e->can_throw_external = false;
              if (dump_file)
                fprintf (dump_file, "Function found to be nothrow: %s\n",  
                         cgraph_node_name (w));
@@ -918,7 +982,12 @@ local_pure_const (void)
     }
   if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
     {
-      TREE_NOTHROW (current_function_decl) = 1;
+      struct cgraph_edge *e;
+
+      TREE_NOTHROW (current_function_decl) = true;
+      for (e = cgraph_node (current_function_decl)->callers;
+           e; e = e->next_caller)
+       e->can_throw_external = false;
       changed = true;
       if (dump_file)
        fprintf (dump_file, "Function found to be nothrow: %s\n",
index 6f5c751..36cb5f3 100644 (file)
@@ -995,7 +995,7 @@ propagate (void)
   struct cgraph_node *w;
   struct cgraph_node **order =
     XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
-  int order_pos = ipa_utils_reduced_inorder (order, false, true);
+  int order_pos = ipa_utils_reduced_inorder (order, false, true, NULL);
   int i;
 
   cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
@@ -1006,7 +1006,7 @@ propagate (void)
      the global information.  All the nodes within a cycle will have
      the same info so we collapse cycles first.  Then we can do the
      propagation in one pass from the leaves to the roots.  */
-  order_pos = ipa_utils_reduced_inorder (order, true, true);
+  order_pos = ipa_utils_reduced_inorder (order, true, true, NULL);
   if (dump_file)
     ipa_utils_print_order(dump_file, "reduced", order, order_pos);
 
index 3b5d128..2fe0396 100644 (file)
@@ -81,7 +81,8 @@ struct searchc_env {
    searching from.  */
 
 static void
-searchc (struct searchc_env* env, struct cgraph_node *v) 
+searchc (struct searchc_env* env, struct cgraph_node *v,
+        bool (*ignore_edge) (struct cgraph_edge *))
 {
   struct cgraph_edge *edge;
   struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux;
@@ -101,12 +102,15 @@ searchc (struct searchc_env* env, struct cgraph_node *v)
       struct ipa_dfs_info * w_info;
       struct cgraph_node *w = edge->callee;
 
+      if (ignore_edge && ignore_edge (edge))
+        continue;
+
       if (w->aux && cgraph_function_body_availability (edge->callee) > AVAIL_OVERWRITABLE)
        {
          w_info = (struct ipa_dfs_info *) w->aux;
          if (w_info->new_node) 
            {
-             searchc (env, w);
+             searchc (env, w, ignore_edge);
              v_info->low_link =
                (v_info->low_link < w_info->low_link) ?
                v_info->low_link : w_info->low_link;
@@ -152,7 +156,8 @@ searchc (struct searchc_env* env, struct cgraph_node *v)
 
 int
 ipa_utils_reduced_inorder (struct cgraph_node **order, 
-                          bool reduce, bool allow_overwritable)
+                          bool reduce, bool allow_overwritable,
+                          bool (*ignore_edge) (struct cgraph_edge *))
 {
   struct cgraph_node *node;
   struct searchc_env env;
@@ -193,7 +198,7 @@ ipa_utils_reduced_inorder (struct cgraph_node **order,
   while (result)
     {
       node = (struct cgraph_node *)result->value;
-      searchc (&env, node);
+      searchc (&env, node, ignore_edge);
       result = splay_tree_min (env.nodes_marked_new);
     }
   splay_tree_delete (env.nodes_marked_new);
index 3ccdbaf..31d7837 100644 (file)
@@ -39,7 +39,8 @@ struct ipa_dfs_info {
 
 /* In ipa-utils.c  */
 void ipa_utils_print_order (FILE*, const char *, struct cgraph_node**, int);
-int ipa_utils_reduced_inorder (struct cgraph_node **, bool, bool);
+int ipa_utils_reduced_inorder (struct cgraph_node **, bool, bool,
+                              bool (*ignore_edge) (struct cgraph_edge *));
 tree get_base_var (tree);
 
  
index d4aa935..9c70146 100644 (file)
@@ -4156,7 +4156,10 @@ verify_stmt (gimple_stmt_iterator *gsi)
      to match.  */
   if (lookup_stmt_eh_region (stmt) >= 0)
     {
-      if (!stmt_could_throw_p (stmt))
+      /* During IPA passes, ipa-pure-const sets nothrow flags on calls
+         and they are updated on statements only after fixup_cfg
+        is executed at beggining of expansion stage.  */
+      if (!stmt_could_throw_p (stmt) && cgraph_state != CGRAPH_STATE_IPA_SSA)
        {
          error ("statement marked for throw, but doesn%'t");
          goto fail;