/* 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
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
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
#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 *
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. */
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),
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. */
struct cgraph_node *node;
int i, count;
tree cvalue;
-
+
fprintf (f, "\nCVAL PRINT\n");
for (node = cgraph_nodes; node; node = node->next)
{
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);
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
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
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 *cvalue, enum 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
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;
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)
{
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)
{
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))
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;
{
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;
}
}
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;
}
}
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;
{
/* 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);
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);
}
}
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;
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)
if (dump_file)
fprintf (dump_file, "\nIPA constant propagation end\n");
cgraph_remove_unreachable_nodes (true, NULL);
+ return 0;
}
/* Gate for IPCP optimization. */
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 */
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 */
+ }
};