Commit d7da5cc8 by Martin Jambor Committed by Martin Jambor

ipa-prop.h (ipa_node_params): Removed fields called_with_var_arguments and node_versionable.

2011-09-02  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (ipa_node_params): Removed fields
	called_with_var_arguments and node_versionable.
	(ipa_set_called_with_variable_arg): Removed.
	(ipa_is_called_with_var_arguments): Likewise.
	* ipa-cp.c (ipa_get_lattice): Fixed index check in an assert.
	(determine_versionability): Do not check for type attributes and va
	builtins.  Record versionability into inline summary.
	(initialize_node_lattices): Do not check
	ipa_is_called_with_var_arguments.
	(propagate_constants_accross_call): Likewise, ignore arguments we do
	not have PARM_DECLs for, set variable flag for parameters that were
	not passed a value.
	(create_specialized_node): Dump info that we cannot change signature.
	* ipa-prop.c (ipa_compute_jump_functions): Do not care about variable
	number of arguments.
	(ipa_make_edge_direct_to_target): Likewise.
	(ipa_update_after_lto_read): Likewise.
	(ipa_node_duplication_hook): Do not copy called_with_var_arguments flag.
	* tree-inline.c (copy_arguments_for_versioning): Copy PARM_DECLs if
	they were remapped.

	* testsuite/gcc.dg/ipa/ipcp-3.c: New test.

From-SVN: r178485
parent e9e1d143
2011-09-02 Martin Jambor <mjambor@suse.cz>
* ipa-prop.h (ipa_node_params): Removed fields
called_with_var_arguments and node_versionable.
(ipa_set_called_with_variable_arg): Removed.
(ipa_is_called_with_var_arguments): Likewise.
* ipa-cp.c (ipa_get_lattice): Fixed index check in an assert.
(determine_versionability): Do not check for type attributes and va
builtins. Record versionability into inline summary.
(initialize_node_lattices): Do not check
ipa_is_called_with_var_arguments.
(propagate_constants_accross_call): Likewise, ignore arguments we do
not have PARM_DECLs for, set variable flag for parameters that were
not passed a value.
(create_specialized_node): Dump info that we cannot change signature.
* ipa-prop.c (ipa_compute_jump_functions): Do not care about variable
number of arguments.
(ipa_make_edge_direct_to_target): Likewise.
(ipa_update_after_lto_read): Likewise.
(ipa_node_duplication_hook): Do not copy called_with_var_arguments flag.
* tree-inline.c (copy_arguments_for_versioning): Copy PARM_DECLs if
they were remapped.
2011-09-02 Richard Guenther <rguenther@suse.de> 2011-09-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/27460 PR tree-optimization/27460
...@@ -221,7 +221,7 @@ static struct ipcp_value *values_topo; ...@@ -221,7 +221,7 @@ static struct ipcp_value *values_topo;
static inline struct ipcp_lattice * static inline struct ipcp_lattice *
ipa_get_lattice (struct ipa_node_params *info, int i) ipa_get_lattice (struct ipa_node_params *info, int i)
{ {
gcc_assert (i >= 0 && i <= ipa_get_param_count (info)); gcc_assert (i >= 0 && i < ipa_get_param_count (info));
gcc_checking_assert (!info->ipcp_orig_node); gcc_checking_assert (!info->ipcp_orig_node);
gcc_checking_assert (info->lattices); gcc_checking_assert (info->lattices);
return &(info->lattices[i]); return &(info->lattices[i]);
...@@ -360,7 +360,6 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits) ...@@ -360,7 +360,6 @@ print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
static void static void
determine_versionability (struct cgraph_node *node) determine_versionability (struct cgraph_node *node)
{ {
struct cgraph_edge *edge;
const char *reason = NULL; const char *reason = NULL;
/* There are a number of generic reasons functions cannot be versioned. We /* There are a number of generic reasons functions cannot be versioned. We
...@@ -369,32 +368,15 @@ determine_versionability (struct cgraph_node *node) ...@@ -369,32 +368,15 @@ determine_versionability (struct cgraph_node *node)
if (node->alias || node->thunk.thunk_p) if (node->alias || node->thunk.thunk_p)
reason = "alias or thunk"; reason = "alias or thunk";
else if (!inline_summary (node)->versionable) else if (!inline_summary (node)->versionable)
reason = "inliner claims it is so"; reason = "not a tree_versionable_function";
else if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
reason = "there are type attributes";
else if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) else if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
reason = "insufficient body availability"; reason = "insufficient body availability";
else
/* Removing arguments doesn't work if the function takes varargs
or use __builtin_apply_args.
FIXME: handle this together with can_change_signature flag. */
for (edge = node->callees; edge; edge = edge->next_callee)
{
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))
{
reason = "prohibitive builtins called";
break;
};
}
if (reason && dump_file && !node->alias && !node->thunk.thunk_p) if (reason && dump_file && !node->alias && !node->thunk.thunk_p)
fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n", fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n",
cgraph_node_name (node), node->uid, reason); cgraph_node_name (node), node->uid, reason);
IPA_NODE_REF (node)->node_versionable = (reason == NULL); inline_summary (node)->versionable = (reason == NULL);
} }
/* Return true if it is at all technically possible to create clones of a /* Return true if it is at all technically possible to create clones of a
...@@ -403,7 +385,7 @@ determine_versionability (struct cgraph_node *node) ...@@ -403,7 +385,7 @@ determine_versionability (struct cgraph_node *node)
static bool static bool
ipcp_versionable_function_p (struct cgraph_node *node) ipcp_versionable_function_p (struct cgraph_node *node)
{ {
return IPA_NODE_REF (node)->node_versionable; return inline_summary (node)->versionable;
} }
/* Structure holding accumulated information about callers of a node. */ /* Structure holding accumulated information about callers of a node. */
...@@ -610,9 +592,7 @@ initialize_node_lattices (struct cgraph_node *node) ...@@ -610,9 +592,7 @@ initialize_node_lattices (struct cgraph_node *node)
int i; int i;
gcc_checking_assert (cgraph_function_with_gimple_body_p (node)); gcc_checking_assert (cgraph_function_with_gimple_body_p (node));
if (ipa_is_called_with_var_arguments (info)) if (!node->local.local)
disable = true;
else if (!node->local.local)
{ {
/* When cloning is allowed, we can assume that externally visible /* When cloning is allowed, we can assume that externally visible
functions are not called. We will compensate this by cloning functions are not called. We will compensate this by cloning
...@@ -1068,18 +1048,17 @@ propagate_constants_accross_call (struct cgraph_edge *cs) ...@@ -1068,18 +1048,17 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
struct cgraph_node *callee, *alias_or_thunk; struct cgraph_node *callee, *alias_or_thunk;
struct ipa_edge_args *args; struct ipa_edge_args *args;
bool ret = false; bool ret = false;
int i, count; int i, args_count, parms_count;
callee = cgraph_function_node (cs->callee, &availability); callee = cgraph_function_node (cs->callee, &availability);
if (!callee->analyzed) if (!callee->analyzed)
return false; return false;
gcc_checking_assert (cgraph_function_with_gimple_body_p (callee)); gcc_checking_assert (cgraph_function_with_gimple_body_p (callee));
callee_info = IPA_NODE_REF (callee); callee_info = IPA_NODE_REF (callee);
if (ipa_is_called_with_var_arguments (callee_info))
return false;
args = IPA_EDGE_REF (cs); args = IPA_EDGE_REF (cs);
count = ipa_get_cs_argument_count (args); args_count = ipa_get_cs_argument_count (args);
parms_count = ipa_get_param_count (callee_info);
/* If this call goes through a thunk we must not propagate to the first (0th) /* If this call goes through a thunk we must not propagate to the first (0th)
parameter. However, we might need to uncover a thunk from below a series parameter. However, we might need to uncover a thunk from below a series
...@@ -1095,7 +1074,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs) ...@@ -1095,7 +1074,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
else else
i = 0; i = 0;
for (; i < count; i++) for (; (i < args_count) && (i < parms_count); i++)
{ {
struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i); struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i);
struct ipcp_lattice *dest_lat = ipa_get_lattice (callee_info, i); struct ipcp_lattice *dest_lat = ipa_get_lattice (callee_info, i);
...@@ -1105,6 +1084,9 @@ propagate_constants_accross_call (struct cgraph_edge *cs) ...@@ -1105,6 +1084,9 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
else else
ret |= propagate_accross_jump_function (cs, jump_func, dest_lat); ret |= propagate_accross_jump_function (cs, jump_func, dest_lat);
} }
for (; i < parms_count; i++)
ret |= set_lattice_contains_variable (ipa_get_lattice (callee_info, i));
return ret; return ret;
} }
...@@ -2004,7 +1986,11 @@ create_specialized_node (struct cgraph_node *node, ...@@ -2004,7 +1986,11 @@ create_specialized_node (struct cgraph_node *node,
} }
} }
else else
args_to_skip = NULL; {
args_to_skip = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " cannot change function signature\n");
}
for (i = 0; i < count ; i++) for (i = 0; i < count ; i++)
{ {
......
...@@ -1032,19 +1032,13 @@ ipa_compute_jump_functions (struct cgraph_node *node, ...@@ -1032,19 +1032,13 @@ ipa_compute_jump_functions (struct cgraph_node *node,
for (cs = node->callees; cs; cs = cs->next_callee) for (cs = node->callees; cs; cs = cs->next_callee)
{ {
struct cgraph_node *callee = cgraph_function_or_thunk_node (cs->callee, NULL); struct cgraph_node *callee = cgraph_function_or_thunk_node (cs->callee,
NULL);
/* We do not need to bother analyzing calls to unknown /* We do not need to bother analyzing calls to unknown
functions unless they may become known during lto/whopr. */ functions unless they may become known during lto/whopr. */
if (!cs->callee->analyzed && !flag_lto) if (!callee->analyzed && !flag_lto)
continue; continue;
ipa_count_arguments (cs); ipa_count_arguments (cs);
/* If the descriptor of the callee is not initialized yet, we have to do
it now. */
if (callee->analyzed)
ipa_initialize_node_params (callee);
if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
!= ipa_get_param_count (IPA_NODE_REF (callee)))
ipa_set_called_with_variable_arg (IPA_NODE_REF (callee));
ipa_compute_jump_functions_for_edge (parms_info, cs); ipa_compute_jump_functions_for_edge (parms_info, cs);
} }
...@@ -1649,10 +1643,6 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target) ...@@ -1649,10 +1643,6 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
} }
callee = cgraph_function_or_thunk_node (callee, NULL); callee = cgraph_function_or_thunk_node (callee, NULL);
if (ipa_get_cs_argument_count (IPA_EDGE_REF (ie))
!= ipa_get_param_count (IPA_NODE_REF (callee)))
ipa_set_called_with_variable_arg (IPA_NODE_REF (callee));
return ie; return ie;
} }
...@@ -1964,7 +1954,6 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst, ...@@ -1964,7 +1954,6 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
new_info->lattices = NULL; new_info->lattices = NULL;
new_info->ipcp_orig_node = old_info->ipcp_orig_node; new_info->ipcp_orig_node = old_info->ipcp_orig_node;
new_info->called_with_var_arguments = old_info->called_with_var_arguments;
new_info->uses_analysis_done = old_info->uses_analysis_done; new_info->uses_analysis_done = old_info->uses_analysis_done;
new_info->node_enqueued = old_info->node_enqueued; new_info->node_enqueued = old_info->node_enqueued;
} }
...@@ -2949,7 +2938,6 @@ void ...@@ -2949,7 +2938,6 @@ void
ipa_update_after_lto_read (void) ipa_update_after_lto_read (void)
{ {
struct cgraph_node *node; struct cgraph_node *node;
struct cgraph_edge *cs;
ipa_check_create_node_params (); ipa_check_create_node_params ();
ipa_check_create_edge_args (); ipa_check_create_edge_args ();
...@@ -2957,17 +2945,4 @@ ipa_update_after_lto_read (void) ...@@ -2957,17 +2945,4 @@ ipa_update_after_lto_read (void)
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed) if (node->analyzed)
ipa_initialize_node_params (node); ipa_initialize_node_params (node);
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed)
for (cs = node->callees; cs; cs = cs->next_callee)
{
struct cgraph_node *callee;
callee = cgraph_function_or_thunk_node (cs->callee, NULL);
if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
!= ipa_get_param_count (IPA_NODE_REF (callee)))
ipa_set_called_with_variable_arg (IPA_NODE_REF (callee));
}
} }
...@@ -168,11 +168,6 @@ struct ipa_node_params ...@@ -168,11 +168,6 @@ struct ipa_node_params
/* If this node is an ipa-cp clone, these are the known values that describe /* If this node is an ipa-cp clone, these are the known values that describe
what it has been specialized for. */ what it has been specialized for. */
VEC (tree, heap) *known_vals; VEC (tree, heap) *known_vals;
/* Whether this function is called with variable number of actual
arguments. */
unsigned called_with_var_arguments : 1;
/* Set when it is possible to create specialized versions of this node. */
unsigned node_versionable : 1;
/* Whether the param uses analysis has already been performed. */ /* Whether the param uses analysis has already been performed. */
unsigned uses_analysis_done : 1; unsigned uses_analysis_done : 1;
/* Whether the function is enqueued in ipa-cp propagation stack. */ /* Whether the function is enqueued in ipa-cp propagation stack. */
...@@ -224,22 +219,6 @@ ipa_is_param_used (struct ipa_node_params *info, int i) ...@@ -224,22 +219,6 @@ ipa_is_param_used (struct ipa_node_params *info, int i)
return VEC_index (ipa_param_descriptor_t, info->descriptors, i)->used; return VEC_index (ipa_param_descriptor_t, info->descriptors, i)->used;
} }
/* Flag this node as having callers with variable number of arguments. */
static inline void
ipa_set_called_with_variable_arg (struct ipa_node_params *info)
{
info->called_with_var_arguments = 1;
}
/* Have we detected this node was called with variable number of arguments? */
static inline bool
ipa_is_called_with_var_arguments (struct ipa_node_params *info)
{
return info->called_with_var_arguments;
}
/* ipa_edge_args stores information related to a callsite and particularly its /* ipa_edge_args stores information related to a callsite and particularly its
arguments. It can be accessed by the IPA_EDGE_REF macro. */ arguments. It can be accessed by the IPA_EDGE_REF macro. */
typedef struct GTY(()) ipa_edge_args typedef struct GTY(()) ipa_edge_args
......
2011-09-02 Martin Jambor <mjambor@suse.cz>
* gcc.dg/ipa/ipcp-3.c: New test.
2011-09-02 Richard Guenther <rguenther@suse.de> 2011-09-02 Richard Guenther <rguenther@suse.de>
PR tree-optimization/27460 PR tree-optimization/27460
......
/* Verify that IPA-CP can clone mark_cell without miscompiling it despite its
type_attributes. */
/* { dg-do run } */
/* { dg-options "-O3 -fdump-ipa-cp" } */
struct PMC {
unsigned flags;
};
typedef struct Pcc_cell
{
struct PMC *p;
long bla;
long type;
} Pcc_cell;
int gi;
extern void abort ();
extern void never_ever(int * interp, struct PMC *pmc)
__attribute__((noinline));
void never_ever (int * interp, struct PMC *pmc)
{
abort ();
}
static void mark_cell(int * interp, Pcc_cell *c)
__attribute__((__nonnull__(1)))
__attribute__((noinline));
static void
mark_cell(int * interp, Pcc_cell *c)
{
if (c && c->type == 4 && c->p
&& !(c->p->flags & (1<<18)))
never_ever(interp, c->p);
}
static void foo(int * interp, Pcc_cell *c)
__attribute__((noinline));
static void
foo(int * interp, Pcc_cell *c)
{
mark_cell(interp, c);
}
static struct Pcc_cell *
__attribute__((noinline,noclone))
getnull(void)
{
return (struct Pcc_cell *) 0;
}
int main()
{
int i;
for (i = 0; i < 100; i++)
foo (&gi, getnull ());
return 0;
}
/* { dg-final { scan-ipa-dump "Creating a specialized node of mark_cell" "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
...@@ -4840,6 +4840,8 @@ copy_arguments_for_versioning (tree orig_parm, copy_body_data * id, ...@@ -4840,6 +4840,8 @@ copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
if (!args_to_skip || !bitmap_bit_p (args_to_skip, i)) if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
{ {
tree new_tree = remap_decl (arg, id); tree new_tree = remap_decl (arg, id);
if (TREE_CODE (new_tree) != PARM_DECL)
new_tree = id->copy_decl (arg, id);
lang_hooks.dup_lang_specific_decl (new_tree); lang_hooks.dup_lang_specific_decl (new_tree);
*parg = new_tree; *parg = new_tree;
parg = &DECL_CHAIN (new_tree); parg = &DECL_CHAIN (new_tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment