#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "target.h"
#include "cgraph.h"
#include "ipa-prop.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "flags.h"
#include "timevar.h"
#include "diagnostic.h"
static inline struct cgraph_node *
ipcp_method_orig_node (struct cgraph_node *mt)
{
return IPA_NODE_REF (mt)->ipcp_orig_node;
}
static inline bool
ipcp_method_is_cloned (struct cgraph_node *node)
{
return (ipcp_method_orig_node (node) != NULL);
}
static inline void
ipcp_method_set_orig_node (struct cgraph_node *node,
struct cgraph_node *orig_node)
{
IPA_NODE_REF (node)->ipcp_orig_node = orig_node;
}
static void
ipcp_cloned_create (struct cgraph_node *orig_node,
struct cgraph_node *new_node)
{
ipa_node_create (new_node);
ipcp_method_set_orig_node (new_node, orig_node);
ipa_method_formal_compute_count (new_node);
ipa_method_compute_tree_map (new_node);
}
static inline enum cvalue_type
ipcp_cval_get_cvalue_type (struct ipcp_formal *cval)
{
return cval->cval_type;
}
static inline gcov_type
ipcp_method_get_scale (struct cgraph_node *mt)
{
return IPA_NODE_REF (mt)->count_scale;
}
static inline void
ipcp_method_set_scale (struct cgraph_node *node, gcov_type count)
{
IPA_NODE_REF (node)->count_scale = count;
}
static inline void
ipcp_cval_set_cvalue_type (struct ipcp_formal *cval, enum cvalue_type type)
{
cval->cval_type = type;
}
static inline union parameter_info *
ipcp_cval_get_cvalue (struct ipcp_formal *cval)
{
return &(cval->cvalue);
}
static inline void
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;
}
static bool
ipcp_type_is_const (enum cvalue_type type)
{
if (type == CONST_VALUE || type == CONST_VALUE_REF)
return true;
else
return false;
}
static inline bool
ipcp_cval_equal_cvalues (union parameter_info *const_val1,
union parameter_info *const_val2,
enum cvalue_type type1, enum cvalue_type type2)
{
gcc_assert (ipcp_type_is_const (type1) && ipcp_type_is_const (type2));
if (type1 != type2)
return false;
if (operand_equal_p (const_val1->value, const_val2->value, 0))
return true;
return false;
}
static void
ipcp_cval_meet (struct ipcp_formal *cval, struct ipcp_formal *cval1,
struct ipcp_formal *cval2)
{
if (ipcp_cval_get_cvalue_type (cval1) == BOTTOM
|| ipcp_cval_get_cvalue_type (cval2) == BOTTOM)
{
ipcp_cval_set_cvalue_type (cval, BOTTOM);
return;
}
if (ipcp_cval_get_cvalue_type (cval1) == TOP)
{
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval2));
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval2),
ipcp_cval_get_cvalue_type (cval2));
return;
}
if (ipcp_cval_get_cvalue_type (cval2) == TOP)
{
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval1));
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval1),
ipcp_cval_get_cvalue_type (cval1));
return;
}
if (!ipcp_cval_equal_cvalues (ipcp_cval_get_cvalue (cval1),
ipcp_cval_get_cvalue (cval2),
ipcp_cval_get_cvalue_type (cval1),
ipcp_cval_get_cvalue_type (cval2)))
{
ipcp_cval_set_cvalue_type (cval, BOTTOM);
return;
}
ipcp_cval_set_cvalue_type (cval, ipcp_cval_get_cvalue_type (cval1));
ipcp_cval_set_cvalue (cval, ipcp_cval_get_cvalue (cval1),
ipcp_cval_get_cvalue_type (cval1));
}
static inline struct ipcp_formal *
ipcp_method_cval (struct cgraph_node *mt, int info_type)
{
return &(IPA_NODE_REF (mt)->ipcp_cval[info_type]);
}
static void
ipcp_cval_compute (struct ipcp_formal *cval, struct cgraph_node *mt,
enum jump_func_type type, union parameter_info *info_type)
{
if (type == UNKNOWN_IPATYPE)
ipcp_cval_set_cvalue_type (cval, BOTTOM);
else if (type == CONST_IPATYPE)
{
ipcp_cval_set_cvalue_type (cval, CONST_VALUE);
ipcp_cval_set_cvalue (cval, info_type, CONST_VALUE);
}
else if (type == CONST_IPATYPE_REF)
{
ipcp_cval_set_cvalue_type (cval, CONST_VALUE_REF);
ipcp_cval_set_cvalue (cval, info_type, CONST_VALUE_REF);
}
else if (type == FORMAL_IPATYPE)
{
enum cvalue_type type =
ipcp_cval_get_cvalue_type (ipcp_method_cval
(mt, info_type->formal_id));
ipcp_cval_set_cvalue_type (cval, type);
ipcp_cval_set_cvalue (cval,
ipcp_cval_get_cvalue (ipcp_method_cval
(mt, info_type->formal_id)),
type);
}
}
static bool
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)
return false;
if (ipcp_cval_equal_cvalues (ipcp_cval_get_cvalue (cval1),
ipcp_cval_get_cvalue (cval2),
ipcp_cval_get_cvalue_type (cval1),
ipcp_cval_get_cvalue_type (cval2)))
return false;
}
return true;
}
static inline void
ipcp_formal_create (struct cgraph_node *mt)
{
IPA_NODE_REF (mt)->ipcp_cval =
XCNEWVEC (struct ipcp_formal, ipa_method_formal_count (mt));
}
static inline void
ipcp_method_cval_set (struct cgraph_node *mt, int i, struct ipcp_formal *cval)
{
IPA_NODE_REF (mt)->ipcp_cval[i].cval_type = cval->cval_type;
ipcp_cval_set_cvalue (ipcp_method_cval (mt, i),
ipcp_cval_get_cvalue (cval), cval->cval_type);
}
static inline void
ipcp_method_cval_set_cvalue_type (struct cgraph_node *mt, int i,
enum cvalue_type cval_type1)
{
IPA_NODE_REF (mt)->ipcp_cval[i].cval_type = cval_type1;
}
static void
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)
{
fprintf (f, "Printing cvals %s:\n", cgraph_node_name (node));
count = ipa_method_formal_count (node);
for (i = 0; i < count; i++)
{
if (ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i))
== CONST_VALUE
|| ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i)) ==
CONST_VALUE_REF)
{
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");
}
else if (ipcp_method_cval (node, i)->cval_type == TOP)
fprintf (f, "param [%d]: type is TOP \n", i);
else
fprintf (f, "param [%d]: type is BOTTOM \n", i);
}
}
}
static void
ipcp_method_cval_init (struct cgraph_node *mt)
{
int i;
tree parm_tree;
ipcp_formal_create (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))
|| POINTER_TYPE_P (TREE_TYPE (parm_tree)))
ipcp_method_cval_set_cvalue_type (mt, i, TOP);
else
ipcp_method_cval_set_cvalue_type (mt, i, BOTTOM);
}
}
static void
constant_val_insert (tree fn, tree parm1, tree val)
{
struct function *func;
tree init_stmt;
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)
bsi_insert_on_edge_immediate (e_step, init_stmt);
}
static tree
build_const_val (union parameter_info *cvalue, enum cvalue_type type,
tree tree_type)
{
tree const_val = NULL;
gcc_assert (ipcp_type_is_const (type));
const_val = fold_convert (tree_type, cvalue->value);
return const_val;
}
static void
ipcp_propagate_const (struct cgraph_node *mt, int param,
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);
}
static void
ipcp_method_compute_scale (struct cgraph_node *node)
{
gcov_type sum;
struct cgraph_edge *cs;
sum = 0;
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
sum += cs->count;
if (node->count == 0)
ipcp_method_set_scale (node, 0);
else
ipcp_method_set_scale (node, sum * REG_BR_PROB_BASE / node->count);
}
static void
ipcp_init_stage (void)
{
struct cgraph_node *node;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
{
ipa_method_formal_compute_count (node);
ipa_method_compute_tree_map (node);
ipcp_method_cval_init (node);
ipa_method_compute_modify (node);
ipcp_method_compute_scale (node);
}
for (node = cgraph_nodes; node; node = node->next)
{
for (cs = node->callees; cs; cs = cs->next_callee)
{
ipa_callsite_compute_count (cs);
if (ipa_callsite_param_count (cs)
!= ipa_method_formal_count (cs->callee))
{
ipa_callsite_param_count_set (cs, 0);
ipa_method_formal_count_set (cs->callee, 0);
}
else
ipa_callsite_compute_param (cs);
}
}
}
static bool
ipcp_after_propagate (void)
{
int i, count;
struct cgraph_node *node;
bool prop_again;
prop_again = false;
for (node = cgraph_nodes; node; node = node->next)
{
count = ipa_method_formal_count (node);
for (i = 0; i < count; i++)
if (ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i)) == TOP)
{
prop_again = true;
ipcp_method_cval_set_cvalue_type (node, i, BOTTOM);
}
}
return prop_again;
}
static void
ipcp_propagate_stage (void)
{
int i;
struct ipcp_formal cval1 = { 0, {0} }, cval = { 0,{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;
union parameter_info *info_type;
ipa_methodlist_p wl;
int count;
wl = ipa_methodlist_init ();
while (ipa_methodlist_not_empty (wl))
{
mt = ipa_remove_method (&wl);
for (cs = mt->callees; cs; cs = cs->next_callee)
{
callee = ipa_callsite_callee (cs);
count = ipa_callsite_param_count (cs);
for (i = 0; i < count; i++)
{
jump_func = ipa_callsite_param (cs, i);
type = get_type (jump_func);
info_type = ipa_jf_get_info_type (jump_func);
ipcp_cval_compute (&cval1, mt, type, info_type);
cval2 = ipcp_method_cval (callee, i);
ipcp_cval_meet (&cval, &cval1, cval2);
if (ipcp_cval_changed (&cval, cval2))
{
ipcp_method_cval_set (callee, i, &cval);
ipa_add_method (&wl, callee);
}
}
}
}
}
static void
ipcp_iterate_stage (void)
{
ipcp_propagate_stage ();
if (ipcp_after_propagate ())
ipcp_propagate_stage ();
}
static bool
ipcp_method_dont_insert_const (struct cgraph_node *mt)
{
if (DECL_UNINLINABLE (mt->decl))
return true;
return false;
}
static void
ipcp_callsite_param_print (FILE * f)
{
struct cgraph_node *node;
int i, count;
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)
{
for (cs = node->callees; cs; cs = cs->next_callee)
{
fprintf (f, "callsite %s ", cgraph_node_name (node));
fprintf (f, "-> %s :: \n", cgraph_node_name (cs->callee));
count = ipa_callsite_param_count (cs);
for (i = 0; i < count; i++)
{
jump_func = ipa_callsite_param (cs, i);
type = get_type (jump_func);
fprintf (f, " param %d: ", i);
if (type == UNKNOWN_IPATYPE)
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");
}
else if (type == FORMAL_IPATYPE)
{
fprintf (f, "FORMAL : ");
fprintf (f, "%d\n",
ipa_jf_get_info_type (jump_func)->formal_id);
}
}
}
}
}
static void
ipcp_method_scale_print (FILE * f)
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "printing scale for %s: ", cgraph_node_name (node));
fprintf (f, "value is " HOST_WIDE_INT_PRINT_DEC
" \n", (HOST_WIDE_INT) ipcp_method_get_scale (node));
}
}
static void
ipcp_profile_mt_count_print (FILE * f)
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "method %s: ", cgraph_node_name (node));
fprintf (f, "count is " HOST_WIDE_INT_PRINT_DEC
" \n", (HOST_WIDE_INT) node->count);
}
}
static void
ipcp_profile_cs_count_print (FILE * f)
{
struct cgraph_node *node;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
{
for (cs = node->callees; cs; cs = cs->next_callee)
{
fprintf (f, "%s -> %s ", cgraph_node_name (cs->caller),
cgraph_node_name (cs->callee));
fprintf (f, "count is " HOST_WIDE_INT_PRINT_DEC " \n",
(HOST_WIDE_INT) cs->count);
}
}
}
static void
ipcp_profile_edge_print (FILE * f)
{
struct cgraph_node *node;
basic_block bb;
edge_iterator ei;
edge e;
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "method %s: \n", cgraph_node_name (node));
if (DECL_SAVED_TREE (node->decl))
{
bb =
ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
fprintf (f, "ENTRY: ");
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
" %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
if (bb->succs)
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (e->dest ==
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
(node->decl)))
fprintf (f, "edge ENTRY -> EXIT, Count");
else
fprintf (f, "edge ENTRY -> %d, Count", e->dest->index);
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
" Prob %d\n", (HOST_WIDE_INT) e->count,
e->probability);
}
FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
{
fprintf (f, "bb[%d]: ", bb->index);
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
" %d\n", (HOST_WIDE_INT) bb->count, bb->frequency);
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (e->dest ==
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION
(node->decl)))
fprintf (f, "edge %d -> EXIT, Count", e->src->index);
else
fprintf (f, "edge %d -> %d, Count", e->src->index,
e->dest->index);
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC " Prob %d\n",
(HOST_WIDE_INT) e->count, e->probability);
}
}
}
}
}
static void
ipcp_profile_bb_print (FILE * f)
{
basic_block bb;
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
{
fprintf (f, "method %s: \n", cgraph_node_name (node));
if (DECL_SAVED_TREE (node->decl))
{
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,
bb->frequency);
FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
{
fprintf (f, "bb[%d]: Count", bb->index);
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
" Frequency %d\n", (HOST_WIDE_INT) bb->count,
bb->frequency);
}
bb =
EXIT_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (node->decl));
fprintf (f, "EXIT: Count");
fprintf (f, " " HOST_WIDE_INT_PRINT_DEC
" Frequency %d\n", (HOST_WIDE_INT) bb->count,
bb->frequency);
}
}
}
static void
ipcp_structures_print (FILE * f)
{
ipcp_method_cval_print (f);
ipcp_method_scale_print (f);
ipa_method_tree_print (f);
ipa_method_modify_print (f);
ipcp_callsite_param_print (f);
}
static void
ipcp_profile_print (FILE * f)
{
fprintf (f, "\nNODE COUNTS :\n");
ipcp_profile_mt_count_print (f);
fprintf (f, "\nCS COUNTS stage:\n");
ipcp_profile_cs_count_print (f);
fprintf (f, "\nBB COUNTS and FREQUENCIES :\n");
ipcp_profile_bb_print (f);
fprintf (f, "\nCFG EDGES COUNTS and PROBABILITIES :\n");
ipcp_profile_edge_print (f);
}
static struct ipa_replace_map *
ipcp_replace_map_create (enum cvalue_type type, tree parm_tree,
union parameter_info *cvalue)
{
struct ipa_replace_map *replace_map;
tree const_val;
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))
{
const_val = build_const_val (cvalue, 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 = false;
}
else
{
replace_map->old_tree = NULL;
replace_map->new_tree = NULL;
replace_map->replace_p = false;
replace_map->ref_p = false;
}
return replace_map;
}
static bool
ipcp_redirect (struct cgraph_edge *cs)
{
struct cgraph_node *caller, *callee, *orig_callee;
int i, count;
struct ipa_jump_func *jump_func;
enum jump_func_type type;
enum cvalue_type cval_type;
caller = cs->caller;
callee = cs->callee;
orig_callee = ipcp_method_orig_node (callee);
count = ipa_method_formal_count (orig_callee);
for (i = 0; i < count; i++)
{
cval_type =
ipcp_cval_get_cvalue_type (ipcp_method_cval (orig_callee, i));
if (ipcp_type_is_const (cval_type))
{
jump_func = ipa_callsite_param (cs, i);
type = get_type (jump_func);
if (type != CONST_IPATYPE
&& type != CONST_IPATYPE_REF)
return true;
}
}
return false;
}
static void
ipcp_update_callgraph (void)
{
struct cgraph_node *node, *orig_callee;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
{
if (ipcp_method_is_cloned (node))
continue;
for (cs = node->callees; cs; cs = cs->next_callee)
if (ipcp_method_is_cloned (cs->callee))
{
orig_callee = ipcp_method_orig_node (cs->callee);
if (ipcp_redirect (cs))
{
cgraph_redirect_edge_callee (cs, orig_callee);
TREE_OPERAND (TREE_OPERAND
(get_call_expr_in (cs->call_stmt), 0), 0) =
orig_callee->decl;
}
}
}
}
static void
ipcp_update_bb_counts (struct cgraph_node *node, gcov_type scale)
{
basic_block bb;
FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
bb->count = bb->count * scale / REG_BR_PROB_BASE;
}
static void
ipcp_update_edges_counts (struct cgraph_node *node, gcov_type scale)
{
basic_block bb;
edge_iterator ei;
edge e;
FOR_ALL_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
FOR_EACH_EDGE (e, ei, bb->succs)
e->count = e->count * scale / REG_BR_PROB_BASE;
}
static void
ipcp_update_profiling (void)
{
struct cgraph_node *node, *orig_node;
gcov_type scale, scale_complement;
struct cgraph_edge *cs;
for (node = cgraph_nodes; node; node = node->next)
{
if (ipcp_method_is_cloned (node))
{
orig_node = ipcp_method_orig_node (node);
scale = ipcp_method_get_scale (orig_node);
node->count = orig_node->count * scale / REG_BR_PROB_BASE;
scale_complement = REG_BR_PROB_BASE - scale;
orig_node->count =
orig_node->count * scale_complement / REG_BR_PROB_BASE;
for (cs = node->callees; cs; cs = cs->next_callee)
cs->count = cs->count * scale / REG_BR_PROB_BASE;
for (cs = orig_node->callees; cs; cs = cs->next_callee)
cs->count = cs->count * scale_complement / REG_BR_PROB_BASE;
ipcp_update_bb_counts (node, scale);
ipcp_update_bb_counts (orig_node, scale_complement);
ipcp_update_edges_counts (node, scale);
ipcp_update_edges_counts (orig_node, scale_complement);
}
}
}
static void
ipcp_insert_stage (void)
{
struct cgraph_node *node, *node1 = NULL;
int i, const_param;
union parameter_info *cvalue;
VEC(cgraph_edge_p,heap) *redirect_callers;
varray_type replace_trees;
struct cgraph_edge *cs;
int node_callers, count;
tree parm_tree;
enum cvalue_type type;
struct ipa_replace_map *replace_param;
for (node = cgraph_nodes; node; node = node->next)
{
if (ipcp_method_dont_insert_const (node))
continue;
const_param = 0;
count = ipa_method_formal_count (node);
for (i = 0; i < count; i++)
{
type = ipcp_cval_get_cvalue_type (ipcp_method_cval (node, i));
if (ipcp_type_is_const (type))
const_param++;
}
if (const_param == 0)
continue;
VARRAY_GENERIC_PTR_INIT (replace_trees, const_param, "replace_trees");
for (i = 0; i < count; i++)
{
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);
replace_param =
ipcp_replace_map_create (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++;
redirect_callers = VEC_alloc (cgraph_edge_p, heap, node_callers);
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
VEC_quick_push (cgraph_edge_p, redirect_callers, cs);
node1 =
cgraph_function_versioning (node, redirect_callers, replace_trees);
VEC_free (cgraph_edge_p, heap, redirect_callers);
VARRAY_CLEAR (replace_trees);
if (node1 == NULL)
continue;
if (dump_file)
fprintf (dump_file, "versioned function %s\n",
cgraph_node_name (node));
ipcp_cloned_create (node, node1);
for (i = 0; i < count; i++)
{
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
&& !TREE_READONLY (parm_tree))
ipcp_propagate_const (node1, i, cvalue, type);
}
}
}
ipcp_update_callgraph ();
ipcp_update_profiling ();
}
unsigned int
ipcp_driver (void)
{
if (dump_file)
fprintf (dump_file, "\nIPA constant propagation start:\n");
ipa_nodes_create ();
ipa_edges_create ();
ipcp_init_stage ();
if (dump_file)
{
fprintf (dump_file, "\nIPA structures before propagation:\n");
ipcp_structures_print (dump_file);
}
ipcp_iterate_stage ();
if (dump_file)
{
fprintf (dump_file, "\nIPA structures after propagation:\n");
ipcp_structures_print (dump_file);
fprintf (dump_file, "\nProfiling info before insert stage:\n");
ipcp_profile_print (dump_file);
}
ipcp_insert_stage ();
if (dump_file)
{
fprintf (dump_file, "\nProfiling info after insert stage:\n");
ipcp_profile_print (dump_file);
}
ipa_free ();
ipa_nodes_free ();
ipa_edges_free ();
if (dump_file)
fprintf (dump_file, "\nIPA constant propagation end\n");
cgraph_remove_unreachable_nodes (true, NULL);
return 0;
}
static bool
cgraph_gate_cp (void)
{
return flag_ipa_cp;
}
struct tree_opt_pass pass_ipa_cp = {
"cp",
cgraph_gate_cp,
ipcp_driver,
NULL,
NULL,
0,
TV_IPA_CONSTANT_PROP,
0,
PROP_trees,
0,
0,
TODO_dump_cgraph | TODO_dump_func,
0
};