OSDN Git Service

PR c++/43509
[pf3gnuchains/gcc-fork.git] / gcc / ipa-cp.c
index 2c3b5b7..f4aab5d 100644 (file)
@@ -1,19 +1,20 @@
 /* Interprocedural constant propagation
-   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Razya Ladelsky <RAZYA@il.ibm.com>
-   
+
 This file is part of GCC.
-   
+
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 3, or (at your option) any later
 version.
-   
+
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
-   
+
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
@@ -27,7 +28,7 @@ along with GCC; see the file COPYING3.  If not see
    {
      printf ("value is %d",y);
    }
-   
+
    int f (int x)
    {
      g (x);
@@ -43,32 +44,32 @@ along with GCC; see the file COPYING3.  If not see
      f (3);
      h (3);
    }
-   
-   
+
+
    The IPCP algorithm will find that g's formal argument y is always called
    with the value 3.
 
    The algorithm used is based on "Interprocedural Constant Propagation", by
    Challahan David, Keith D Cooper, Ken Kennedy, Linda Torczon, Comp86, pg
    152-161
-   
+
    The optimization is divided into three stages:
 
    First stage - intraprocedural analysis
    =======================================
    This phase computes jump_function and modification flags.
-   
+
    A jump function for a callsite represents the values passed as an actual
    arguments of a given callsite. There are three types of values:
    Pass through - the caller's formal parameter is passed as an actual argument.
    Constant - a constant is passed as an actual argument.
    Unknown - neither of the above.
-   
+
    The jump function info, ipa_jump_func, is stored in ipa_edge_args
    structure (defined in ipa_prop.h and pointed to by cgraph_node->aux)
    modified_flags are defined in ipa_node_params structure
    (defined in ipa_prop.h and pointed to by cgraph_edge->aux).
-   
+
    -ipcp_init_stage() is the first stage driver.
 
    Second stage - interprocedural analysis
@@ -79,10 +80,10 @@ along with GCC; see the file COPYING3.  If not see
    TOP - unknown.
    BOTTOM - non constant.
    CONSTANT - constant value.
-   
+
    Lattice describing a formal parameter p will have a constant value if all
    callsites invoking this function have the same constant value passed to p.
-   
+
    The lattices are stored in ipcp_lattice which is itself in ipa_node_params
    structure (defined in ipa_prop.h and pointed to by cgraph_edge->aux).
 
@@ -115,7 +116,7 @@ along with GCC; see the file COPYING3.  If not see
    and many calls redirected back to fit the description above.
 
    -ipcp_insert_stage() is the third phase driver.
-   
+
 */
 
 #include "config.h"
@@ -182,6 +183,7 @@ ipcp_analyze_node (struct cgraph_node *node)
   /* Unreachable nodes should have been eliminated before ipcp.  */
   gcc_assert (node->needed || node->reachable);
 
+  node->local.versionable = tree_versionable_function_p (node->decl);
   ipa_initialize_node_params (node);
   ipa_detect_param_modifications (node);
 }
@@ -226,10 +228,14 @@ ipcp_lats_are_equal (struct ipcp_lattice *lat1, struct ipcp_lattice *lat2)
   if (lat1->type != lat2->type)
     return false;
 
-  if (operand_equal_p (lat1->constant, lat2->constant, 0))
-    return true;
-
-  return false;
+  if (TREE_CODE (lat1->constant) ==  ADDR_EXPR
+      && TREE_CODE (lat2->constant) ==  ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (lat1->constant, 0)) == CONST_DECL
+      && TREE_CODE (TREE_OPERAND (lat2->constant, 0)) == CONST_DECL)
+    return operand_equal_p (DECL_INITIAL (TREE_OPERAND (lat1->constant, 0)),
+                           DECL_INITIAL (TREE_OPERAND (lat2->constant, 0)), 0);
+  else
+    return operand_equal_p (lat1->constant, lat2->constant, 0);
 }
 
 /* Compute Meet arithmetics:
@@ -385,8 +391,16 @@ ipcp_print_all_lattices (FILE * f)
          fprintf (f, "    param [%d]: ", i);
          if (lat->type == IPA_CONST_VALUE)
            {
+             tree cst = lat->constant;
              fprintf (f, "type is CONST ");
-             print_generic_expr (f, lat->constant, 0);
+             print_generic_expr (f, cst, 0);
+             if (TREE_CODE (cst) == ADDR_EXPR
+                 && TREE_CODE (TREE_OPERAND (cst, 0)) == CONST_DECL)
+               {
+                 fprintf (f, " -> ");
+                 print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (cst, 0)),
+                                                      0);
+               }
              fprintf (f, "\n");
            }
          else if (lat->type == IPA_TOP)
@@ -402,35 +416,21 @@ ipcp_print_all_lattices (FILE * f)
 static bool
 ipcp_versionable_function_p (struct cgraph_node *node)
 {
-  tree decl = node->decl;
-  basic_block bb;
+  struct cgraph_edge *edge;
 
   /* There are a number of generic reasons functions cannot be versioned.  */
-  if (!tree_versionable_function_p (decl))
-    return false;
-
-  /* Removing arguments doesn't work if the function takes varargs.  */
-  if (DECL_STRUCT_FUNCTION (decl)->stdarg)
+  if (!node->local.versionable)
     return false;
 
-  /* Removing arguments doesn't work if we use __builtin_apply_args.  */
-  FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (decl))
+  /* Removing arguments doesn't work if the function takes varargs
+     or use __builtin_apply_args. */
+  for (edge = node->callees; edge; edge = edge->next_callee)
     {
-      gimple_stmt_iterator gsi;
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-       {
-         const_gimple stmt = gsi_stmt (gsi);
-         tree t;
-
-         if (!is_gimple_call (stmt))
-           continue;
-         t = gimple_call_fndecl (stmt);
-         if (t == NULL_TREE)
-           continue;
-         if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (t) == BUILT_IN_APPLY_ARGS)
-           return false;
-       }
+      tree t = edge->callee->decl;
+      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
+         && (DECL_FUNCTION_CODE (t) == BUILT_IN_APPLY_ARGS
+            || DECL_FUNCTION_CODE (t) == BUILT_IN_VA_START))
+       return false;
     }
 
   return true;
@@ -473,7 +473,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
       if (cgraph_maybe_hot_edge_p (e))
        n_hot_calls ++;
     }
-  
+
   if (!n_calls)
     {
       if (dump_file)
@@ -487,7 +487,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
         fprintf (dump_file, "Considering %s for cloning; code would shrink.\n",
                 cgraph_node_name (node));
       return true;
-    }  
+    }
 
   if (!flag_ipa_cp_clone)
     {
@@ -578,7 +578,13 @@ build_const_val (struct ipcp_lattice *lat, tree tree_type)
 
 /* Compute the proper scale for NODE.  It is the ratio between the number of
    direct calls (represented on the incoming cgraph_edges) and sum of all
-   invocations of NODE (represented as count in cgraph_node).  */
+   invocations of NODE (represented as count in cgraph_node).
+
+   FIXME: This code is wrong.  Since the callers can be also clones and
+   the clones are not scaled yet, the sums gets unrealistically high.
+   To properly compute the counts, we would need to do propagation across
+   callgraph (as external call to A might imply call to non-clonned B
+   if A's clone calls clonned B).  */
 static void
 ipcp_compute_node_scale (struct cgraph_node *node)
 {
@@ -589,6 +595,12 @@ ipcp_compute_node_scale (struct cgraph_node *node)
   /* Compute sum of all counts of callers. */
   for (cs = node->callers; cs != NULL; cs = cs->next_caller)
     sum += cs->count;
+  /* Work around the unrealistically high sum problem.  We just don't want
+     the non-cloned body to have negative or very low frequency.  Since
+     majority of execution time will be spent in clones anyway, this should
+     give good enough profile.  */
+  if (sum > node->count * 9 / 10)
+    sum = node->count * 9 / 10;
   if (node->count == 0)
     ipcp_set_node_scale (node, 0);
   else
@@ -621,15 +633,8 @@ ipcp_init_stage (void)
          ipa_count_arguments (cs);
          if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
              != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
-           {
-             /* Handle cases of functions with 
-                a variable number of parameters.  */
-             ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
-             if (flag_indirect_inlining)
-               ipa_compute_jump_functions (cs);
-           }
-         else
-           ipa_compute_jump_functions (cs);
+           ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
+         ipa_compute_jump_functions (cs);
        }
     }
 }
@@ -912,12 +917,9 @@ ipcp_update_callgraph (void)
        for (i = 0; i < count; i++)
          {
            struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
-           tree parm_tree = ipa_get_param (info, i);
 
            /* We can proactively remove obviously unused arguments.  */
-           if (is_gimple_reg (parm_tree)
-               && !gimple_default_def (DECL_STRUCT_FUNCTION (orig_node->decl),
-                                       parm_tree))
+           if (!ipa_is_param_used (info, i))
              {
                bitmap_set_bit (args_to_skip, i);
                continue;
@@ -990,12 +992,9 @@ ipcp_estimate_growth (struct cgraph_node *node)
   for (i = 0; i < count; i++)
     {
       struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
-      tree parm_tree = ipa_get_param (info, i);
 
       /* We can proactively remove obviously unused arguments.  */
-      if (is_gimple_reg (parm_tree)
-         && !gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
-                                 parm_tree))
+      if (!ipa_is_param_used (info, i))
        removable_args++;
 
       if (lat->type == IPA_CONST_VALUE)
@@ -1063,12 +1062,9 @@ ipcp_const_param_count (struct cgraph_node *node)
   for (i = 0; i < count; i++)
     {
       struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
-      tree parm_tree = ipa_get_param (info, i);
       if (ipcp_lat_is_insertable (lat)
          /* Do not count obviously unused arguments.  */
-         && (!is_gimple_reg (parm_tree)
-             || gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
-                                    parm_tree)))
+          && ipa_is_param_used (info, i))
        const_param++;
     }
   return const_param;
@@ -1172,9 +1168,7 @@ ipcp_insert_stage (void)
          parm_tree = ipa_get_param (info, i);
 
          /* We can proactively remove obviously unused arguments.  */
-         if (is_gimple_reg (parm_tree)
-             && !gimple_default_def (DECL_STRUCT_FUNCTION (node->decl),
-                                     parm_tree))
+          if (!ipa_is_param_used (info, i))
            {
              bitmap_set_bit (args_to_skip, i);
              continue;
@@ -1264,7 +1258,7 @@ ipcp_driver (void)
       ipcp_print_profile_data (dump_file);
     }
   /* Free all IPCP structures.  */
-  free_all_ipa_structures_after_ipa_cp ();
+  ipa_free_all_structures_after_ipa_cp ();
   if (dump_file)
     fprintf (dump_file, "\nIPA constant propagation end\n");
   return 0;
@@ -1279,14 +1273,15 @@ ipcp_generate_summary (void)
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
   ipa_register_cgraph_hooks ();
-  /* 1. Call the init stage to initialize 
+  /* 1. Call the init stage to initialize
      the ipa_node_params and ipa_edge_args structures.  */
   ipcp_init_stage ();
 }
 
 /* Write ipcp summary for nodes in SET.  */
 static void
-ipcp_write_summary (cgraph_node_set set)
+ipcp_write_summary (cgraph_node_set set,
+                   varpool_node_set vset ATTRIBUTE_UNUSED)
 {
   ipa_prop_write_jump_functions (set);
 }
@@ -1321,13 +1316,14 @@ struct ipa_opt_pass_d pass_ipa_cp =
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
   TODO_dump_cgraph | TODO_dump_func |
-  TODO_remove_functions /* todo_flags_finish */
+  TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */
  },
  ipcp_generate_summary,                        /* generate_summary */
  ipcp_write_summary,                   /* write_summary */
  ipcp_read_summary,                    /* read_summary */
- NULL,                                 /* function_read_summary */
- NULL,                                 /* stmt_fixup */
+ NULL,                                 /* write_optimization_summary */
+ NULL,                                 /* read_optimization_summary */
+ NULL,                                 /* stmt_fixup */
  0,                                    /* TODOs */
  NULL,                                 /* function_transform */
  NULL,                                 /* variable_transform */