OSDN Git Service

2008-04-28 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / ipa-cp.c
index 18d5bc0..4d9e0a4 100644 (file)
@@ -1,12 +1,12 @@
 /* Interprocedural constant propagation
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007 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 2, or (at your option) any later
+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
@@ -15,9 +15,8 @@ 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 COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Interprocedural constant propagation.
    The aim of interprocedural constant propagation (IPCP) is to find which 
@@ -65,7 +64,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    arguments
    of the callsite. There are three types of values :
    Formal - the caller's formal parameter is passed as an actual argument.
-   Constant - a constant is passed as a an actual argument.
+   Constant - a constant is passed as an actual argument.
    Unknown - neither of the above.
    
    In order to compute the jump functions, we need the modify information for 
@@ -143,6 +142,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "flags.h"
 #include "timevar.h"
 #include "diagnostic.h"
+#include "tree-dump.h"
+#include "tree-inline.h"
 
 /* Get orig node field of ipa_node associated with method MT.  */
 static inline struct cgraph_node *
@@ -219,7 +220,7 @@ ipcp_cval_set_cvalue (struct ipcp_formal *cval, union parameter_info *value,
                      enum cvalue_type type)
 {
   if (type == CONST_VALUE || type == CONST_VALUE_REF)
-    cval->cvalue.value =  value->value;
+    cval->cvalue.value = value->value;
 }
 
 /* Return whether TYPE is a constant type.  */
@@ -336,7 +337,7 @@ ipcp_cval_changed (struct ipcp_formal *cval1, struct ipcp_formal *cval2)
   if (ipcp_cval_get_cvalue_type (cval1) == ipcp_cval_get_cvalue_type (cval2))
     {
       if (ipcp_cval_get_cvalue_type (cval1) != CONST_VALUE &&
-         ipcp_cval_get_cvalue_type (cval1) != CONST_VALUE_REF)  
+         ipcp_cval_get_cvalue_type (cval1) != CONST_VALUE_REF)
        return false;
       if (ipcp_cval_equal_cvalues (ipcp_cval_get_cvalue (cval1),
                                   ipcp_cval_get_cvalue (cval2),
@@ -352,7 +353,7 @@ static inline void
 ipcp_formal_create (struct cgraph_node *mt)
 {
   IPA_NODE_REF (mt)->ipcp_cval =
-    xcalloc (ipa_method_formal_count (mt), sizeof (struct ipcp_formal));
+    XCNEWVEC (struct ipcp_formal, ipa_method_formal_count (mt));
 }
 
 /* Set cval structure of I-th formal of MT to CVAL.  */
@@ -379,7 +380,7 @@ ipcp_method_cval_print (FILE * f)
   struct cgraph_node *node;
   int i, count;
   tree cvalue;
+
   fprintf (f, "\nCVAL PRINT\n");
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -395,10 +396,9 @@ ipcp_method_cval_print (FILE * f)
              fprintf (f, " param [%d]: ", i);
              fprintf (f, "type is CONST ");
              cvalue =
-               ipcp_cval_get_cvalue (ipcp_method_cval (node, i))->
-                 value;
-              print_generic_expr (f, cvalue, 0);
-              fprintf (f, "\n");
+               ipcp_cval_get_cvalue (ipcp_method_cval (node, i))->value;
+             print_generic_expr (f, cvalue, 0);
+             fprintf (f, "\n");
            }
          else if (ipcp_method_cval (node, i)->cval_type == TOP)
            fprintf (f, "param [%d]: type is TOP  \n", i);
@@ -424,8 +424,8 @@ ipcp_method_cval_init (struct cgraph_node *mt)
   for (i = 0; i < ipa_method_formal_count (mt); i++)
     {
       parm_tree = ipa_method_get_tree (mt, i);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (parm_tree)) 
-         || SCALAR_FLOAT_TYPE_P (TREE_TYPE (parm_tree)) 
+      if (INTEGRAL_TYPE_P (TREE_TYPE (parm_tree))
+         || SCALAR_FLOAT_TYPE_P (TREE_TYPE (parm_tree))
          || POINTER_TYPE_P (TREE_TYPE (parm_tree)))
        ipcp_method_cval_set_cvalue_type (mt, i, TOP);
       else
@@ -439,20 +439,18 @@ ipcp_method_cval_init (struct cgraph_node *mt)
    PARM1 is the lhs of the assignment and
    VAL is the rhs. */
 static void
-constant_val_insert (tree fn, tree parm1, tree val)
+constant_val_insert (tree parm1, tree val)
 {
-  struct function *func;
-  tree init_stmt;
+  tree init_stmt = NULL;
   edge e_step;
-  edge_iterator ei;
 
-  init_stmt = build2 (MODIFY_EXPR, void_type_node, parm1, val);
-  func = DECL_STRUCT_FUNCTION (fn);
-  cfun = func;
-  current_function_decl = fn;
-  if (ENTRY_BLOCK_PTR_FOR_FUNCTION (func)->succs)
-    FOR_EACH_EDGE (e_step, ei, ENTRY_BLOCK_PTR_FOR_FUNCTION (func)->succs)
+  init_stmt = build_gimple_modify_stmt (parm1, val);
+
+  if (init_stmt)
+    {
+      e_step = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun));
       bsi_insert_on_edge_immediate (e_step, init_stmt);
+    }
 }
 
 /* build INTEGER_CST tree with type TREE_TYPE and 
@@ -472,18 +470,16 @@ build_const_val (union parameter_info *cvalue, enum cvalue_type type,
    constant_val_insert().  */
 static void
 ipcp_propagate_const (struct cgraph_node *mt, int param,
-                     union parameter_info *cvalue ,enum cvalue_type type)
+                     union parameter_info *cvalueenum cvalue_type type)
 {
-  tree fndecl;
   tree const_val;
   tree parm_tree;
 
   if (dump_file)
     fprintf (dump_file, "propagating const to %s\n", cgraph_node_name (mt));
-  fndecl = mt->decl;
   parm_tree = ipa_method_get_tree (mt, param);
   const_val = build_const_val (cvalue, type, TREE_TYPE (parm_tree));
-  constant_val_insert (fndecl, parm_tree, const_val);
+  constant_val_insert (parm_tree, const_val);
 }
 
 /* Compute the proper scale for NODE.  It is the ratio between 
@@ -573,7 +569,7 @@ static void
 ipcp_propagate_stage (void)
 {
   int i;
-  struct ipcp_formal cval1 = { 0, {0} }, cval = { 0,{0} };
+  struct ipcp_formal cval1 = { BOTTOM, {0} }, cval = { BOTTOM, {0} };
   struct ipcp_formal *cval2;
   struct cgraph_node *mt, *callee;
   struct cgraph_edge *cs;
@@ -642,7 +638,7 @@ ipcp_callsite_param_print (FILE * f)
   struct ipa_jump_func *jump_func;
   enum jump_func_type type;
   tree info_type;
+
   fprintf (f, "\nCALLSITE PARAM PRINT\n");
   for (node = cgraph_nodes; node; node = node->next)
     {
@@ -661,11 +657,10 @@ ipcp_callsite_param_print (FILE * f)
                fprintf (f, "UNKNOWN\n");
              else if (type == CONST_IPATYPE || type == CONST_IPATYPE_REF)
                {
-                 info_type =
-                   ipa_jf_get_info_type (jump_func)->value;
-                  fprintf (f, "CONST : ");
-                  print_generic_expr (f, info_type, 0);
-                  fprintf (f, "\n");
+                 info_type = ipa_jf_get_info_type (jump_func)->value;
+                 fprintf (f, "CONST : ");
+                 print_generic_expr (f, info_type, 0);
+                 fprintf (f, "\n");
                }
              else if (type == FORMAL_IPATYPE)
                {
@@ -790,13 +785,13 @@ ipcp_profile_bb_print (FILE * f)
   for (node = cgraph_nodes; node; node = node->next)
     {
       fprintf (f, "method %s: \n", cgraph_node_name (node));
-      if (DECL_SAVED_TREE (node->decl))
+      if (node->analyzed)
        {
          bb =
            ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
          fprintf (f, "ENTRY: Count");
          fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
-                  " Frquency  %d\n", (HOST_WIDE_INT) bb->count,
+                  " Frequency  %d\n", (HOST_WIDE_INT) bb->count,
                   bb->frequency);
 
          FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
@@ -847,27 +842,22 @@ ipcp_profile_print (FILE * f)
    operates according to the flags sent.  PARM_TREE is the 
    formal's tree found to be constant.  CVALUE represents the constant.  */
 static struct ipa_replace_map *
-ipcp_replace_map_create (enum cvalue_type type, tree parm_tree,
-                        union parameter_info *cvalue)
+ipcp_replace_map_create (struct function *func, enum cvalue_type type,
+                        tree parm_tree, union parameter_info *cvalue)
 {
   struct ipa_replace_map *replace_map;
   tree const_val;
 
-  replace_map = xcalloc (1, sizeof (struct ipa_replace_map));
+  replace_map = XCNEW (struct ipa_replace_map);
   gcc_assert (ipcp_type_is_const (type));
-  if (type == CONST_VALUE_REF )
-    {
-      const_val =
-       build_const_val (cvalue, type, TREE_TYPE (TREE_TYPE (parm_tree)));
-      replace_map->old_tree = parm_tree;
-      replace_map->new_tree = const_val;
-      replace_map->replace_p = true;
-      replace_map->ref_p = true;
-    }
-  else if (TREE_READONLY (parm_tree) && !TREE_ADDRESSABLE (parm_tree))
+  if (type != CONST_VALUE_REF
+      && is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
+       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func, parm_tree)))
     {
+      if (dump_file)
+       fprintf (dump_file, "replacing param with const\n");
       const_val = build_const_val (cvalue, type, TREE_TYPE (parm_tree));
-      replace_map->old_tree = parm_tree;
+      replace_map->old_tree =gimple_default_def (func, parm_tree);
       replace_map->new_tree = const_val;
       replace_map->replace_p = true;
       replace_map->ref_p = false;
@@ -906,8 +896,7 @@ ipcp_redirect (struct cgraph_edge *cs)
        {
          jump_func = ipa_callsite_param (cs, i);
          type = get_type (jump_func);
-         if (type != CONST_IPATYPE 
-             && type != CONST_IPATYPE_REF)
+         if (type != CONST_IPATYPE && type != CONST_IPATYPE_REF)
            return true;
        }
     }
@@ -935,8 +924,8 @@ ipcp_update_callgraph (void)
            if (ipcp_redirect (cs))
              {
                cgraph_redirect_edge_callee (cs, orig_callee);
-               TREE_OPERAND (TREE_OPERAND
-                             (get_call_expr_in (cs->call_stmt), 0), 0) =
+               TREE_OPERAND (CALL_EXPR_FN (get_call_expr_in (cs->call_stmt)),
+                             0) =
                  orig_callee->decl;
              }
          }
@@ -1005,7 +994,8 @@ ipcp_insert_stage (void)
   struct cgraph_node *node, *node1 = NULL;
   int i, const_param;
   union parameter_info *cvalue;
-  varray_type redirect_callers, replace_trees;
+  VEC (cgraph_edge_p, heap) * redirect_callers;
+  varray_type replace_trees;
   struct cgraph_edge *cs;
   int node_callers, count;
   tree parm_tree;
@@ -1016,7 +1006,7 @@ ipcp_insert_stage (void)
     {
       /* Propagation of the constant is forbidden in 
          certain conditions.  */
-      if (ipcp_method_dont_insert_const (node))
+      if (!node->analyzed || ipcp_method_dont_insert_const (node))
        continue;
       const_param = 0;
       count = ipa_method_formal_count (node);
@@ -1037,7 +1027,8 @@ ipcp_insert_stage (void)
              cvalue = ipcp_cval_get_cvalue (ipcp_method_cval (node, i));
              parm_tree = ipa_method_get_tree (node, i);
              replace_param =
-               ipcp_replace_map_create (type, parm_tree, cvalue);
+               ipcp_replace_map_create (DECL_STRUCT_FUNCTION (node->decl),
+                                        type, parm_tree, cvalue);
              VARRAY_PUSH_GENERIC_PTR (replace_trees, replace_param);
            }
        }
@@ -1045,15 +1036,14 @@ ipcp_insert_stage (void)
       node_callers = 0;
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
        node_callers++;
-      VARRAY_GENERIC_PTR_INIT (redirect_callers, node_callers,
-                              "redirect_callers");
+      redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
       for (cs = node->callers; cs != NULL; cs = cs->next_caller)
-       VARRAY_PUSH_GENERIC_PTR (redirect_callers, cs);
+       VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
       /* Redirecting all the callers of the node to the
          new versioned node.  */
       node1 =
        cgraph_function_versioning (node, redirect_callers, replace_trees);
-      VARRAY_CLEAR (redirect_callers);
+      VEC_free (cgraph_edge_p, heap, redirect_callers);
       VARRAY_CLEAR (replace_trees);
       if (node1 == NULL)
        continue;
@@ -1061,25 +1051,44 @@ ipcp_insert_stage (void)
        fprintf (dump_file, "versioned function %s\n",
                 cgraph_node_name (node));
       ipcp_cloned_create (node, node1);
-      for (i = 0; i < count; i++)
+      if (const_param > 0)
        {
-         type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
-         if (ipcp_type_is_const (type))
+         push_cfun (DECL_STRUCT_FUNCTION (node1->decl));
+         tree_register_cfg_hooks ();
+         current_function_decl = node1->decl;
+
+         for (i = 0; i < count; i++)
            {
-             cvalue = ipcp_cval_get_cvalue (ipcp_method_cval (node, i));
-             parm_tree = ipa_method_get_tree (node, i);
-             if (type != CONST_VALUE_REF 
-                 && !TREE_READONLY (parm_tree))
-               ipcp_propagate_const (node1, i, cvalue, type);
+             type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
+             if (ipcp_type_is_const (type))
+               {
+                 cvalue = ipcp_cval_get_cvalue (ipcp_method_cval (node, i));
+                 parm_tree = ipa_method_get_tree (node, i);
+                 if (type != CONST_VALUE_REF && !is_gimple_reg (parm_tree))
+                   ipcp_propagate_const (node1, i, cvalue, type);
+               }
+           }
+         if (gimple_in_ssa_p (cfun))
+           {
+             update_ssa (TODO_update_ssa);
+#ifdef   ENABLE_CHECKING
+             verify_ssa (true);
+#endif
            }
+         free_dominance_info (CDI_DOMINATORS);
+         free_dominance_info (CDI_POST_DOMINATORS);
+         pop_cfun ();
+         current_function_decl = NULL;
        }
+      if (dump_file)
+       dump_function_to_file (node1->decl, dump_file, dump_flags);
     }
   ipcp_update_callgraph ();
   ipcp_update_profiling ();
 }
 
 /* The IPCP driver.  */
-void
+static unsigned int
 ipcp_driver (void)
 {
   if (dump_file)
@@ -1117,6 +1126,7 @@ ipcp_driver (void)
   if (dump_file)
     fprintf (dump_file, "\nIPA constant propagation end\n");
   cgraph_remove_unreachable_nodes (true, NULL);
+  return 0;
 }
 
 /* Gate for IPCP optimization.  */
@@ -1126,7 +1136,10 @@ cgraph_gate_cp (void)
   return flag_ipa_cp;
 }
 
-struct tree_opt_pass pass_ipa_cp = {
+struct simple_ipa_opt_pass pass_ipa_cp = 
+{
+ {
+  SIMPLE_IPA_PASS,
   "cp",                                /* name */
   cgraph_gate_cp,              /* gate */
   ipcp_driver,                 /* execute */
@@ -1138,6 +1151,6 @@ struct tree_opt_pass pass_ipa_cp = {
   PROP_trees,                  /* properties_provided */
   0,                           /* properties_destroyed */
   0,                           /* todo_flags_start */
-  TODO_dump_cgraph | TODO_dump_func,   /* todo_flags_finish */
-  0                            /* letter */
+  TODO_dump_cgraph | TODO_dump_func    /* todo_flags_finish */
+ }
 };