OSDN Git Service

PR tree-optimize/40556
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Oct 2009 11:40:18 +0000 (11:40 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 22 Oct 2009 11:40:18 +0000 (11:40 +0000)
* ipa-reference.c (has_proper_scope_for_analysis): Add fixme about global vars.
(check_call): Handle only indirect calls.
(propagate_bits): Update comment.
(write_node_summary_p): Turn bogus check to assert.
(ipa_reference_write_summary): Stream calls_read_all properly.
(ipa_reference_read_summary): Stream in calls_read_all properly.
(read_write_all_from_decl): New function.
(propagate): Handle OVERWRITABLE nodes and external calls here.
* ipa-pre-const.c (check_call): In IPA mode handle indirect calls
only.
(analyze_function): Do not check visibility here.
(add_new_function): We summary OVERWRITABLE too.
(generate_summary): Stream OVERWRITABLE nodes too.
(propagate): Handle external calls and OVERWRITABLE nodes here.
(local_pure_const): Check visibility here.

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

gcc/ChangeLog
gcc/ipa-pure-const.c
gcc/ipa-reference.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/pr40556.c [new file with mode: 0644]

index d686d0d..a709e53 100644 (file)
@@ -1,5 +1,24 @@
 2009-10-22  Jan Hubicka  <jh@suse.cz>
 
+       PR tree-optimize/40556                                                                                                                                         
+       * ipa-reference.c (has_proper_scope_for_analysis): Add fixme about global vars.                                                                                
+       (check_call): Handle only indirect calls.                                                                                                                      
+       (propagate_bits): Update comment.                                                                                                                              
+       (write_node_summary_p): Turn bogus check to assert.                                                                                                            
+       (ipa_reference_write_summary): Stream calls_read_all properly.                                                                                                 
+       (ipa_reference_read_summary): Stream in calls_read_all properly.                                                                                               
+       (read_write_all_from_decl): New function.                                                                                                                      
+       (propagate): Handle OVERWRITABLE nodes and external calls here.                                                                                                
+       * ipa-pre-const.c (check_call): In IPA mode handle indirect calls                                                                                              
+       only.                                                                                                                                                          
+       (analyze_function): Do not check visibility here.                                                                                                              
+       (add_new_function): We summary OVERWRITABLE too.                                                                                                               
+       (generate_summary): Stream OVERWRITABLE nodes too.                                                                                                             
+       (propagate): Handle external calls and OVERWRITABLE nodes here.                                                                                                
+       (local_pure_const): Check visibility here.                                                                                                                     
+
+2009-10-22  Jan Hubicka  <jh@suse.cz>
+
        * ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions.
        (pass_ipa_cp): Register them.
        (ipcp_init_stage): Analyze all functions for whopr/lto.
index ea1d81e..e37af05 100644 (file)
@@ -330,12 +330,11 @@ check_call (funct_state local, gimple call, bool ipa)
   /* When not in IPA mode, we can still handle self recursion.  */
   if (!ipa && callee_t == current_function_decl)
     local->looping = true;
-  /* The callee is either unknown (indirect call) or there is just no
-     scannable code for it (external call) .  We look to see if there
-     are any bits available for the callee (such as by declaration or
-     because it is builtin) and process solely on the basis of those
-     bits. */
-  else if (avail <= AVAIL_OVERWRITABLE || !ipa)
+  /* Either calle is unknown or we are doing local analysis.
+     Look to see if there are any bits available for the callee (such as by
+     declaration or because it is builtin) and process solely on the basis of
+     those bits. */
+  else if (!ipa || !callee_t)
     {
       if (possibly_throws && flag_non_call_exceptions)
         {
@@ -492,13 +491,6 @@ analyze_function (struct cgraph_node *fn, bool ipa)
   funct_state l;
   basic_block this_block;
 
-  if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
-    {
-      if (dump_file)
-        fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
-      return NULL;
-    }
-
   l = XCNEW (struct funct_state_d);
   l->pure_const_state = IPA_CONST;
   l->state_previously_known = IPA_NEITHER;
@@ -609,7 +601,7 @@ end:
 static void
 add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
- if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
+ if (cgraph_function_body_availability (node) < AVAIL_OVERWRITABLE)
    return;
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
@@ -686,12 +678,12 @@ generate_summary (void)
 
   /* Process all of the functions. 
 
-     We do NOT process any AVAIL_OVERWRITABLE functions, we cannot
-     guarantee that what we learn about the one we see will be true
-     for the one that overrides it.
-  */
+     We process AVAIL_OVERWRITABLE functions.  We can not use the results
+     by default, but the info can be used at LTO with -fwhole-program or
+     when function got clonned and the clone is AVAILABLE.  */
+
   for (node = cgraph_nodes; node; node = node->next)
-    if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
+    if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
       set_function_state (node, analyze_function (node, true));
 
   pointer_set_destroy (visited_nodes);
@@ -878,6 +870,12 @@ propagate (void)
 
          if (w_l->looping)
            looping = true;
+         if (cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE)
+           {
+             looping |= w_l->looping_previously_known;
+             if (pure_const_state < w_l->state_previously_known)
+               pure_const_state = w_l->state_previously_known;
+           }
 
          if (pure_const_state == IPA_NEITHER)
            break;
@@ -901,6 +899,20 @@ propagate (void)
                  if (y_l->looping)
                    looping = true;
                }
+             else
+               {
+                 int flags = flags_from_decl_or_type (y->decl);
+
+                 if (flags & ECF_LOOPING_CONST_OR_PURE)
+                   looping = true;
+                 if (flags & ECF_CONST)
+                   ;
+                 else if ((flags & ECF_PURE) && pure_const_state == IPA_CONST)
+                   pure_const_state = IPA_PURE;
+                 else
+                   pure_const_state = IPA_NEITHER, looping = true;
+
+               }
            }
          w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
@@ -988,7 +1000,8 @@ propagate (void)
          struct cgraph_edge *e;
          funct_state w_l = get_function_state (w);
 
-         if (w_l->can_throw)
+         if (w_l->can_throw
+             || cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE)
            can_throw = true;
 
          if (can_throw)
@@ -1008,6 +1021,8 @@ propagate (void)
                      && e->can_throw_external)
                    can_throw = true;
                }
+             else if (e->can_throw_external && !TREE_NOTHROW (y->decl))
+               can_throw = true;
            }
          w_info = (struct ipa_dfs_info *) w->aux;
          w = w_info->next_cycle;
@@ -1046,7 +1061,7 @@ propagate (void)
          free (node->aux);
          node->aux = NULL;
        }
-      if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
+      if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE)
        free (get_function_state (node));
     }
   
@@ -1109,15 +1124,16 @@ local_pure_const (void)
         fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
       return 0;
     }
-
-  l = analyze_function (cgraph_node (current_function_decl), false);
-  if (!l)
+  if (cgraph_function_body_availability (cgraph_node (current_function_decl))
+      <= AVAIL_OVERWRITABLE)
     {
       if (dump_file)
         fprintf (dump_file, "Function has wrong visibility; ignoring\n");
       return 0;
     }
 
+  l = analyze_function (cgraph_node (current_function_decl), false);
+
   switch (l->pure_const_state)
     {
     case IPA_CONST:
index 2e062e4..f0e8aa0 100644 (file)
@@ -318,6 +318,8 @@ has_proper_scope_for_analysis (tree t)
   if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
     return false;
 
+  /* FIXME: for LTO we should include PUBLIC vars too.  This is bit difficult
+     as summarie would need unsharing.  */
   if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
     return false;
 
@@ -413,31 +415,21 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt)
 {
   int flags = gimple_call_flags (stmt);
   tree callee_t = gimple_call_fndecl (stmt);
-  enum availability avail = AVAIL_NOT_AVAILABLE;
 
-  if (callee_t)
+  /* Process indirect calls.  All direct calles are handled at propagation
+     time.  */
+  if (!callee_t)
     {
-      struct cgraph_node* callee = cgraph_node(callee_t);
-      avail = cgraph_function_body_availability (callee);
-    }
-
-  if (avail <= AVAIL_OVERWRITABLE)
-    if (local) 
-      {
-       if (flags & ECF_CONST) 
-         ;
-       else if (flags & ECF_PURE)
+      if (flags & ECF_CONST) 
+       ;
+      else if (flags & ECF_PURE)
+       local->calls_read_all = true;
+      else 
+       {
          local->calls_read_all = true;
-       else 
-         {
-           local->calls_read_all = true;
-           local->calls_write_all = true;
-         }
-      }
-   /* TODO: To be able to produce sane results, we should also handle
-      common builtins, in particular throw.
-      Indirect calls hsould be only counted and as inliner is replacing them
-      by direct calls, we can conclude if any indirect calls are left in body */
+         local->calls_write_all = true;
+       }
+    }
 }
 
 /* TP is the part of the tree currently under the microscope.
@@ -527,7 +519,7 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x
     {
       struct cgraph_node *y = e->callee;
 
-      /* Only look at the master nodes and skip external nodes.  */
+      /* Only look into nodes we can propagate something.  */
       if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE)
        {
          if (get_reference_vars_info (y))
@@ -1012,8 +1004,8 @@ generate_summary (void)
 static bool
 write_node_summary_p (struct cgraph_node *node)
 {
+  gcc_assert (node->global.inlined_to == NULL);
   return (node->analyzed 
-         && node->global.inlined_to == NULL
          && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE
          && get_reference_vars_info (node) != NULL);
 }
@@ -1053,18 +1045,28 @@ ipa_reference_write_summary (cgraph_node_set set)
          lto_output_uleb128_stream (ob->main_stream, node_ref);
 
          /* Stream out the statics read.  */
-         lto_output_uleb128_stream (ob->main_stream,
-                                    bitmap_count_bits (l->statics_read));
-         EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi)
-           lto_output_var_decl_index(ob->decl_state, ob->main_stream,
-                                     get_static_decl (index));
+         if (l->calls_read_all)
+           lto_output_sleb128_stream (ob->main_stream, -1);
+         else
+           {
+             lto_output_sleb128_stream (ob->main_stream,
+                                        bitmap_count_bits (l->statics_read));
+             EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi)
+               lto_output_var_decl_index(ob->decl_state, ob->main_stream,
+                                         get_static_decl (index));
+           }
 
          /* Stream out the statics written.  */
-         lto_output_uleb128_stream (ob->main_stream,
-                                    bitmap_count_bits (l->statics_written));
-         EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi)
-           lto_output_var_decl_index(ob->decl_state, ob->main_stream,
-                                     get_static_decl (index));
+         if (l->calls_write_all)
+           lto_output_sleb128_stream (ob->main_stream, -1);
+         else
+           {
+             lto_output_sleb128_stream (ob->main_stream,
+                                        bitmap_count_bits (l->statics_written));
+             EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi)
+               lto_output_var_decl_index(ob->decl_state, ob->main_stream,
+                                         get_static_decl (index));
+           }
        }
     }
   lto_destroy_simple_output_block (ob);
@@ -1101,7 +1103,7 @@ ipa_reference_read_summary (void)
              unsigned int j, index;
              struct cgraph_node *node;
              ipa_reference_local_vars_info_t l;
-             unsigned int v_count;
+             int v_count;
              lto_cgraph_encoder_t encoder;
 
              index = lto_input_uleb128 (ib);
@@ -1110,26 +1112,32 @@ ipa_reference_read_summary (void)
              l = init_function_info (node);
 
              /* Set the statics read.  */
-             v_count = lto_input_uleb128 (ib);
-             for (j = 0; j < v_count; j++)
-               {
-                 unsigned int var_index = lto_input_uleb128 (ib);
-                 tree v_decl = lto_file_decl_data_get_var_decl (file_data,
-                                                                var_index);
-                 add_static_var (v_decl);
-                 bitmap_set_bit (l->statics_read, DECL_UID (v_decl));
-               } 
+             v_count = lto_input_sleb128 (ib);
+             if (v_count == -1)
+               l->calls_read_all = true;
+             else
+               for (j = 0; j < (unsigned int)v_count; j++)
+                 {
+                   unsigned int var_index = lto_input_uleb128 (ib);
+                   tree v_decl = lto_file_decl_data_get_var_decl (file_data,
+                                                                  var_index);
+                   add_static_var (v_decl);
+                   bitmap_set_bit (l->statics_read, DECL_UID (v_decl));
+                 } 
 
              /* Set the statics written.  */
-             v_count = lto_input_uleb128 (ib);
-             for (j = 0; j < v_count; j++)
-               {
-                 unsigned int var_index = lto_input_uleb128 (ib);
-                 tree v_decl = lto_file_decl_data_get_var_decl (file_data,
-                                                                var_index);
-                 add_static_var (v_decl);
-                 bitmap_set_bit (l->statics_written, DECL_UID (v_decl));
-               } 
+             v_count = lto_input_sleb128 (ib);
+             if (v_count == -1)
+               l->calls_read_all = true;
+             else
+               for (j = 0; j < (unsigned int)v_count; j++)
+                 {
+                   unsigned int var_index = lto_input_uleb128 (ib);
+                   tree v_decl = lto_file_decl_data_get_var_decl (file_data,
+                                                                  var_index);
+                   add_static_var (v_decl);
+                   bitmap_set_bit (l->statics_written, DECL_UID (v_decl));
+                 } 
            }
 
          lto_destroy_simple_input_block (file_data, 
@@ -1141,6 +1149,26 @@ ipa_reference_read_summary (void)
 
 
 \f
+/* Set READ_ALL/WRITE_ALL based on DECL flags.  */
+static void
+read_write_all_from_decl (tree decl, bool * read_all, bool * write_all)
+{
+  int flags = flags_from_decl_or_type (decl);
+  if (flags & ECF_CONST)
+    ;
+  else if (flags & ECF_PURE)
+    *read_all = true;
+  else
+    {
+       /* TODO: To be able to produce sane results, we should also handle
+         common builtins, in particular throw.
+         Indirect calls hsould be only counted and as inliner is replacing them
+         by direct calls, we can conclude if any indirect calls are left in body */
+      *read_all = true;
+      *write_all = true;
+    }
+}
+
 /* Produce the global information by preforming a transitive closure
    on the local information that was produced by ipa_analyze_function
    and ipa_analyze_variable.  */
@@ -1173,6 +1201,7 @@ propagate (void)
       ipa_reference_global_vars_info_t node_g = 
        XCNEW (struct ipa_reference_global_vars_info_d);
       ipa_reference_local_vars_info_t node_l;
+      struct cgraph_edge *e;
       
       bool read_all;
       bool write_all;
@@ -1193,6 +1222,15 @@ propagate (void)
       read_all = node_l->calls_read_all;
       write_all = node_l->calls_write_all;
 
+      /* When function is overwrittable, we can not assume anything.  */
+      if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
+        read_write_all_from_decl (node->decl, &read_all, &write_all);
+
+      for (e = node->callees; e; e = e->next_callee) 
+        if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE)
+          read_write_all_from_decl (e->callee->decl, &read_all, &write_all);
+
+
       /* If any node in a cycle is calls_read_all or calls_write_all
         they all are. */
       w_info = (struct ipa_dfs_info *) node->aux;
@@ -1201,6 +1239,15 @@ propagate (void)
        {
          ipa_reference_local_vars_info_t w_l = 
            get_reference_vars_info (w)->local;
+
+         /* When function is overwrittable, we can not assume anything.  */
+         if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE)
+           read_write_all_from_decl (w->decl, &read_all, &write_all);
+
+         for (e = w->callees; e; e = e->next_callee) 
+           if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE)
+             read_write_all_from_decl (e->callee->decl, &read_all, &write_all);
+
          read_all |= w_l->calls_read_all;
          write_all |= w_l->calls_write_all;
 
@@ -1208,6 +1255,7 @@ propagate (void)
          w = w_info->next_cycle;
        }
 
+
       /* Initialized the bitmaps for the reduced nodes */
       if (read_all) 
        node_g->statics_read = all_module_statics;
@@ -1217,7 +1265,6 @@ propagate (void)
          bitmap_copy (node_g->statics_read, 
                       node_l->statics_read);
        }
-
       if (write_all) 
        node_g->statics_written = all_module_statics;
       else
index 42ca4b2..78f21bd 100644 (file)
@@ -1,3 +1,7 @@
+2009-10-22  Jan Hubicka  <jh@suse.cz>
+
+       * gcc.c-torture/compile/pr40556.c: New testcase.
+
 2009-10-22  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/41781
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr40556.c b/gcc/testsuite/gcc.c-torture/compile/pr40556.c
new file mode 100644 (file)
index 0000000..a7b25b7
--- /dev/null
@@ -0,0 +1,22 @@
+struct A {};
+
+struct A foo()
+{
+  return foo();
+}
+
+void bar()
+{
+  foo();
+}
+struct A {};
+
+struct A foo()
+{
+  return foo();
+}
+
+void bar()
+{
+  foo();
+}