gengtype.c (open_base_files): Add ipa-inline.h include.

* gengtype.c (open_base_files): Add ipa-inline.h include.
	* ipa-cp.c (ipcp_get_lattice, ipcp_lattice_from_jfunc): Move to ipa-prop.c
	update all uses.
	* ipa-prop.c: (ipa_get_lattice, ipa_lattice_from_jfunc): ... here.
	* ipa-inline-transform.c (inline_call): Use inline_merge_summary to merge
	summary of inlined function into former caller.
	* ipa-inline.c (max_benefit): Remove.
	(edge_badness): Compensate for removal of benefits.
	(update_caller_keys): Use reset_node_growth_cache/reset_edge_growth_cache.
	(update_callee_keys): Likewise.
	(update_all_callee_keys): Likewise.
	(inline_small_functions): Do not collect max_benefit; do not
	reset stimated_growth; call free_growth_caches and initialize_growth_caches.
	* ipa-inline.h (struct condition, type clause_t, struct predicate, struct
	size_time_entry): New structures.
	(INLINE_SIZE_SCALE, INLINE_TIME_SCALE, MAX_CLAUSES): New constants.
	(inline_summary): Remove size_inlining_benefit, time_inlining_benefit and
	estimated_growth.
	(edge_growth_cache_entry): New structure.
	(node_growth_cache, edge_growth_cache): New global vars.
	(estimate_growth): Turn into inline.
	(inline_merge_summary, do_estimate_edge_growth, do_estimate_edge_time,
	initialize_growth_caches, free_growth_caches): Declare.
	(estimate_edge_growth): Rewrite.
	(estimate_edge_time): Implement as inline cache lookup.
	(reset_node_growth_cache, reset_edge_growth_cache): New inline functions.
	(MAX_TIME): Reduce to allow multiplicatoin by INLINE_SIZE_SCALE.
	(NUM_CONDITIONS): New constant.
	(predicate_conditions): New enum.
	(IS_NOT_CONSTANT): New constant.
	(edge_removal_hook_holder): New var.
	(node_growth_cache, edge_growth_cache): New global vars.
	(true_predicate, single_cond_predicate, false_predicate, not_inlined_predicate,
	add_condition, add_clause, and_predicates, or_predicates, predicates_equal_p,
	evaulate_predicate, dump_condition, dump_clause, dump_predicate, account_size_time,
	evaulate_conditions_for_edge): New functions.
	(inline_summary_alloc): Move to heap.
	(inline_node_removal_hook): Clear condition and entry vectors.
	(inline_edge_removal_hook): New function.
	(initialize_growth_caches, free_growth_caches): New function.
	(dump_inline_summary): Update.
	(edge_execution_predicate): New function.
	(will_be_nonconstant_predicate): New function.
	(estimate_function_body_sizes): Compute BB and constantness predicates.
	(compute_inline_parameters): Do not clear estimated_growth.
	(estimate_edge_size_and_time): New function.
	(estimate_calls_size_and_time): New function.
	(estimate_callee_size_and_time): New function.
	(remap_predicate): New function.
	(inline_merge_summary): New function.
	(do_estimate_edge_time): New function based on...
	(estimate_edge_time): ... this one.
	(do_estimate_edge_growth): New function.
	(do_estimate_growth): New function based on....
	(estimate_growth): ... this one.
	(inline_analyze_function): Analyze after deciding on jump functions.
	(inline_read_section): New function.
	(inline_read_summary): Use it.
	(inline_write_summary): Write all the new data.
	* ipa-prop.c (ipa_get_param_decl_index): Export.
	(ipa_lattice_from_jfunc): Move here from ipa-cp.c
	* ipa-prop.h (ipa_get_param_decl_index, ipa_lattice_from_jfunc): Declare.
	(ipa_get_lattice): Move hre from ipa-cp.c
	* Makefile.in (GTFILES): Add ipa-inline.h and ipa-inline-analysis.c
	* params.def (PARAM_EARLY_INLINING_INSNS): Set to 11.
	* cgraph.h (cgraph_clone_inlined_nodes, compute_inline_parameters,
	cgraph_edge_inlinable_p): Remove.
	* cgraphunit.c: Include ipainline.h
	(cgraph_process_new_functions): Update call of compute_inline_parameters.

	* gcc.dg/tree-ssa/pr38699.c: Fix testcase.

From-SVN: r172873
This commit is contained in:
Jan Hubicka 2011-04-22 22:04:42 +02:00 committed by Jan Hubicka
parent 0cfbd28838
commit 632b4f8e8b
17 changed files with 1438 additions and 287 deletions

View File

@ -1,3 +1,75 @@
2011-04-22 Jan Hubicka <jh@suse.cz>
* gengtype.c (open_base_files): Add ipa-inline.h include.
* ipa-cp.c (ipcp_get_lattice, ipcp_lattice_from_jfunc): Move to ipa-prop.c
update all uses.
* ipa-prop.c: (ipa_get_lattice, ipa_lattice_from_jfunc): ... here.
* ipa-inline-transform.c (inline_call): Use inline_merge_summary to merge
summary of inlined function into former caller.
* ipa-inline.c (max_benefit): Remove.
(edge_badness): Compensate for removal of benefits.
(update_caller_keys): Use reset_node_growth_cache/reset_edge_growth_cache.
(update_callee_keys): Likewise.
(update_all_callee_keys): Likewise.
(inline_small_functions): Do not collect max_benefit; do not
reset stimated_growth; call free_growth_caches and initialize_growth_caches.
* ipa-inline.h (struct condition, type clause_t, struct predicate, struct
size_time_entry): New structures.
(INLINE_SIZE_SCALE, INLINE_TIME_SCALE, MAX_CLAUSES): New constants.
(inline_summary): Remove size_inlining_benefit, time_inlining_benefit and
estimated_growth.
(edge_growth_cache_entry): New structure.
(node_growth_cache, edge_growth_cache): New global vars.
(estimate_growth): Turn into inline.
(inline_merge_summary, do_estimate_edge_growth, do_estimate_edge_time,
initialize_growth_caches, free_growth_caches): Declare.
(estimate_edge_growth): Rewrite.
(estimate_edge_time): Implement as inline cache lookup.
(reset_node_growth_cache, reset_edge_growth_cache): New inline functions.
(MAX_TIME): Reduce to allow multiplicatoin by INLINE_SIZE_SCALE.
(NUM_CONDITIONS): New constant.
(predicate_conditions): New enum.
(IS_NOT_CONSTANT): New constant.
(edge_removal_hook_holder): New var.
(node_growth_cache, edge_growth_cache): New global vars.
(true_predicate, single_cond_predicate, false_predicate, not_inlined_predicate,
add_condition, add_clause, and_predicates, or_predicates, predicates_equal_p,
evaulate_predicate, dump_condition, dump_clause, dump_predicate, account_size_time,
evaulate_conditions_for_edge): New functions.
(inline_summary_alloc): Move to heap.
(inline_node_removal_hook): Clear condition and entry vectors.
(inline_edge_removal_hook): New function.
(initialize_growth_caches, free_growth_caches): New function.
(dump_inline_summary): Update.
(edge_execution_predicate): New function.
(will_be_nonconstant_predicate): New function.
(estimate_function_body_sizes): Compute BB and constantness predicates.
(compute_inline_parameters): Do not clear estimated_growth.
(estimate_edge_size_and_time): New function.
(estimate_calls_size_and_time): New function.
(estimate_callee_size_and_time): New function.
(remap_predicate): New function.
(inline_merge_summary): New function.
(do_estimate_edge_time): New function based on...
(estimate_edge_time): ... this one.
(do_estimate_edge_growth): New function.
(do_estimate_growth): New function based on....
(estimate_growth): ... this one.
(inline_analyze_function): Analyze after deciding on jump functions.
(inline_read_section): New function.
(inline_read_summary): Use it.
(inline_write_summary): Write all the new data.
* ipa-prop.c (ipa_get_param_decl_index): Export.
(ipa_lattice_from_jfunc): Move here from ipa-cp.c
* ipa-prop.h (ipa_get_param_decl_index, ipa_lattice_from_jfunc): Declare.
(ipa_get_lattice): Move hre from ipa-cp.c
* Makefile.in (GTFILES): Add ipa-inline.h and ipa-inline-analysis.c
* params.def (PARAM_EARLY_INLINING_INSNS): Set to 11.
* cgraph.h (cgraph_clone_inlined_nodes, compute_inline_parameters,
cgraph_edge_inlinable_p): Remove.
* cgraphunit.c: Include ipainline.h
(cgraph_process_new_functions): Update call of compute_inline_parameters.
2011-04-22 Richard Guenther <rguenther@suse.de>
* tree.c (build_int_cst): Properly create canonicalized integer

View File

@ -2997,7 +2997,7 @@ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) debug.h $(DIAGNOSTIC_H) \
$(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) $(IPA_PROP_H) \
gt-cgraphunit.h tree-iterator.h $(COVERAGE_H) $(TREE_DUMP_H) \
tree-pretty-print.h gimple-pretty-print.h
tree-pretty-print.h gimple-pretty-print.h ipa-inline.h
cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(GIMPLE_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) $(IPA_UTILS_H) $(EXCEPT_H) \
@ -3782,6 +3782,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/ipa-prop.h \
$(srcdir)/lto-streamer.h \
$(srcdir)/target-globals.h \
$(srcdir)/ipa-inline.h \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,

View File

@ -721,11 +721,6 @@ varpool_next_static_initializer (struct varpool_node *node)
for ((node) = varpool_first_static_initializer (); (node); \
(node) = varpool_next_static_initializer (node))
/* In ipa-inline.c */
void cgraph_clone_inlined_nodes (struct cgraph_edge *, bool, bool);
void compute_inline_parameters (struct cgraph_node *);
cgraph_inline_failed_t cgraph_edge_inlinable_p (struct cgraph_edge *);
/* Create a new static variable of type TYPE. */
tree add_new_static_var (tree type);

View File

@ -138,6 +138,7 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "coverage.h"
#include "plugin.h"
#include "ipa-inline.h"
static void cgraph_expand_all_functions (void);
static void cgraph_mark_functions_to_output (void);
@ -252,7 +253,7 @@ cgraph_process_new_functions (void)
|| !optimize)
execute_pass_list (pass_early_local_passes.pass.sub);
else
compute_inline_parameters (node);
compute_inline_parameters (node, true);
free_dominance_info (CDI_POST_DOMINATORS);
free_dominance_info (CDI_DOMINATORS);
pop_cfun ();

View File

@ -1559,7 +1559,8 @@ open_base_files (void)
"optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
"tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
"cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h",
"target.h", "ipa-prop.h", "lto-streamer.h", "target-globals.h", NULL
"target.h", "ipa-prop.h", "lto-streamer.h", "target-globals.h",
"ipa-inline.h", NULL
};
const char *const *ifp;
outf_p gtype_desc_c;

View File

@ -278,77 +278,6 @@ ipa_lattice_meet (struct ipcp_lattice *res, struct ipcp_lattice *lat1,
res->constant = lat1->constant;
}
/* Return the lattice corresponding to the Ith formal parameter of the function
described by INFO. */
static inline struct ipcp_lattice *
ipcp_get_lattice (struct ipa_node_params *info, int i)
{
return &(info->params[i].ipcp_lattice);
}
/* Given the jump function JFUNC, compute the lattice LAT that describes the
value coming down the callsite. INFO describes the caller node so that
pass-through jump functions can be evaluated. */
static void
ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
struct ipa_jump_func *jfunc)
{
if (jfunc->type == IPA_JF_CONST)
{
lat->type = IPA_CONST_VALUE;
lat->constant = jfunc->value.constant;
}
else if (jfunc->type == IPA_JF_PASS_THROUGH)
{
struct ipcp_lattice *caller_lat;
tree cst;
caller_lat = ipcp_get_lattice (info, jfunc->value.pass_through.formal_id);
lat->type = caller_lat->type;
if (caller_lat->type != IPA_CONST_VALUE)
return;
cst = caller_lat->constant;
if (jfunc->value.pass_through.operation != NOP_EXPR)
{
tree restype;
if (TREE_CODE_CLASS (jfunc->value.pass_through.operation)
== tcc_comparison)
restype = boolean_type_node;
else
restype = TREE_TYPE (cst);
cst = fold_binary (jfunc->value.pass_through.operation,
restype, cst, jfunc->value.pass_through.operand);
}
if (!cst || !is_gimple_ip_invariant (cst))
lat->type = IPA_BOTTOM;
lat->constant = cst;
}
else if (jfunc->type == IPA_JF_ANCESTOR)
{
struct ipcp_lattice *caller_lat;
tree t;
caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
lat->type = caller_lat->type;
if (caller_lat->type != IPA_CONST_VALUE)
return;
if (TREE_CODE (caller_lat->constant) != ADDR_EXPR)
{
/* This can happen when the constant is a NULL pointer. */
lat->type = IPA_BOTTOM;
return;
}
t = TREE_OPERAND (caller_lat->constant, 0);
t = build_ref_for_offset (EXPR_LOCATION (t), t,
jfunc->value.ancestor.offset,
jfunc->value.ancestor.type, NULL, false);
lat->constant = build_fold_addr_expr (t);
}
else
lat->type = IPA_BOTTOM;
}
/* True when OLD_LAT and NEW_LAT values are not the same. */
static bool
@ -384,7 +313,7 @@ ipcp_print_all_lattices (FILE * f)
count = ipa_get_param_count (info);
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
fprintf (f, " param [%d]: ", i);
if (lat->type == IPA_CONST_VALUE)
@ -582,7 +511,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
for (i = 0; i < ipa_get_param_count (info) ; i++)
{
ipcp_get_lattice (info, i)->type = type;
ipa_get_lattice (info, i)->type = type;
if (type == IPA_BOTTOM)
ipa_set_param_cannot_devirtualize (info, i);
}
@ -659,7 +588,7 @@ ipcp_change_tops_to_bottom (void)
count = ipa_get_param_count (info);
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
if (lat->type == IPA_TOP)
{
prop_again = true;
@ -842,8 +771,8 @@ ipcp_propagate_stage (void)
for (i = 0; i < count; i++)
{
jump_func = ipa_get_ith_jump_func (args, i);
ipcp_lattice_from_jfunc (info, &inc_lat, jump_func);
dest_lat = ipcp_get_lattice (callee_info, i);
ipa_lattice_from_jfunc (info, &inc_lat, jump_func);
dest_lat = ipa_get_lattice (callee_info, i);
ipa_lattice_meet (&new_lat, &inc_lat, dest_lat);
if (ipcp_lattice_changed (&new_lat, dest_lat))
{
@ -1031,7 +960,7 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
count = ipa_get_param_count (orig_callee_info);
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (orig_callee_info, i);
struct ipcp_lattice *lat = ipa_get_lattice (orig_callee_info, i);
struct ipa_jump_func *jump_func;
jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
@ -1067,7 +996,7 @@ ipcp_update_callgraph (void)
args_to_skip = BITMAP_ALLOC (NULL);
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
/* We can proactively remove obviously unused arguments. */
if (!ipa_is_param_used (info, i))
@ -1155,7 +1084,7 @@ ipcp_estimate_growth (struct cgraph_node *node)
if (node->local.can_change_signature)
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
/* We can proactively remove obviously unused arguments. */
if (!ipa_is_param_used (info, i))
@ -1237,7 +1166,7 @@ ipcp_process_devirtualization_opportunities (struct cgraph_node *node)
if (param_index == -1)
continue;
lat = ipcp_get_lattice (info, param_index);
lat = ipa_get_lattice (info, param_index);
token = ie->indirect_info->otr_token;
anc_offset = ie->indirect_info->anc_offset;
otr_type = ie->indirect_info->otr_type;
@ -1309,7 +1238,7 @@ ipcp_const_param_count (struct cgraph_node *node)
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
if ((ipcp_lat_is_insertable (lat)
/* Do not count obviously unused arguments. */
&& ipa_is_param_used (info, i))
@ -1436,7 +1365,7 @@ ipcp_insert_stage (void)
args_to_skip = NULL;
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
parm_tree = ipa_get_param (info, i);
/* We can proactively remove obviously unused arguments. */
@ -1504,7 +1433,7 @@ ipcp_insert_stage (void)
info = IPA_NODE_REF (node);
for (i = 0; i < count; i++)
{
struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
struct ipcp_lattice *lat = ipa_get_lattice (info, i);
if (lat->type == IPA_CONST_VALUE)
ipcp_discover_new_direct_edges (node1, i, lat->constant);
}

File diff suppressed because it is too large Load Diff

View File

@ -175,7 +175,6 @@ inline_call (struct cgraph_edge *e, bool update_original,
int old_size = 0, new_size = 0;
struct cgraph_node *to = NULL;
struct cgraph_edge *curr = e;
struct inline_summary *info;
/* Don't inline inlined edges. */
gcc_assert (e->inline_failed);
@ -185,18 +184,15 @@ inline_call (struct cgraph_edge *e, bool update_original,
e->inline_failed = CIF_OK;
DECL_POSSIBLY_INLINED (e->callee->decl) = true;
to = e->caller;
if (to->global.inlined_to)
to = to->global.inlined_to;
old_size = inline_summary (to)->size;
inline_merge_summary (e);
new_size = inline_summary (to)->size;
clone_inlined_nodes (e, true, update_original, overall_size);
/* Now update size of caller and all functions caller is inlined into. */
for (;e && !e->inline_failed; e = e->caller->callers)
{
to = e->caller;
info = inline_summary (to);
old_size = info->size;
new_size = estimate_size_after_inlining (to, curr);
info->size = new_size;
info->time = estimate_time_after_inlining (to, curr);
}
gcc_assert (curr->callee->global.inlined_to == to);
if (overall_size && new_size > old_size)
*overall_size += new_size - old_size;

View File

@ -117,7 +117,7 @@ along with GCC; see the file COPYING3. If not see
/* Statistics we collect about inlining algorithm. */
static int overall_size;
static gcov_type max_count, max_benefit;
static gcov_type max_count;
/* Return false when inlining edge E would lead to violating
limits on function unit growth or stack usage growth.
@ -633,27 +633,23 @@ static int
edge_badness (struct cgraph_edge *edge, bool dump)
{
gcov_type badness;
int growth;
int growth, time_growth;
struct inline_summary *callee_info = inline_summary (edge->callee);
if (DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl))
return INT_MIN;
growth = estimate_edge_growth (edge);
time_growth = estimate_edge_time (edge);
if (dump)
{
fprintf (dump_file, " Badness calculation for %s -> %s\n",
cgraph_node_name (edge->caller),
cgraph_node_name (edge->callee));
fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n",
fprintf (dump_file, " growth size %i, time %i\n",
growth,
callee_info->time,
callee_info->time_inlining_benefit
+ edge->call_stmt_time,
callee_info->size,
callee_info->size_inlining_benefit
+ edge->call_stmt_size);
time_growth);
}
/* Always prefer inlining saving code size. */
@ -669,11 +665,16 @@ edge_badness (struct cgraph_edge *edge, bool dump)
So we optimize for overall number of "executed" inlined calls. */
else if (max_count)
{
int benefitperc;
benefitperc = (((gcov_type)callee_info->time
* edge->frequency / CGRAPH_FREQ_BASE - time_growth) * 100
/ (callee_info->time + 1) + 1);
benefitperc = MIN (benefitperc, 100);
benefitperc = MAX (benefitperc, 0);
badness =
((int)
((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) *
(callee_info->time_inlining_benefit
+ edge->call_stmt_time + 1)) / growth;
((double) edge->count * INT_MIN / max_count / 100) *
benefitperc) / growth;
/* Be sure that insanity of the profile won't lead to increasing counts
in the scalling and thus to overflow in the computation above. */
@ -685,9 +686,7 @@ edge_badness (struct cgraph_edge *edge, bool dump)
" * Relative benefit %f\n",
(int) badness, (double) badness / INT_MIN,
(double) edge->count / max_count,
(double) (inline_summary (edge->callee)->
time_inlining_benefit
+ edge->call_stmt_time + 1) / (max_benefit + 1));
(double) benefitperc);
}
}
@ -706,11 +705,11 @@ edge_badness (struct cgraph_edge *edge, bool dump)
int benefitperc;
int growth_for_all;
badness = growth * 10000;
benefitperc =
100 * (callee_info->time_inlining_benefit
+ edge->call_stmt_time)
/ (callee_info->time + 1) + 1;
benefitperc = (((gcov_type)callee_info->time
* edge->frequency / CGRAPH_FREQ_BASE - time_growth) * 100
/ (callee_info->time + 1) + 1);
benefitperc = MIN (benefitperc, 100);
benefitperc = MAX (benefitperc, 0);
div *= benefitperc;
/* Decrease badness if call is nested. */
@ -822,7 +821,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
return;
if (!bitmap_set_bit (updated_nodes, node->uid))
return;
inline_summary (node)->estimated_growth = INT_MIN;
reset_node_growth_cache (node);
/* See if there is something to do. */
for (edge = node->callers; edge; edge = edge->next_caller)
@ -834,6 +833,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
for (; edge; edge = edge->next_caller)
if (edge->inline_failed)
{
reset_edge_growth_cache (edge);
if (can_inline_edge_p (edge, false)
&& want_inline_small_function_p (edge, false))
update_edge_key (heap, edge);
@ -857,7 +857,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
{
struct cgraph_edge *e = node->callees;
inline_summary (node)->estimated_growth = INT_MIN;
reset_node_growth_cache (node);
if (!e)
return;
@ -866,12 +866,13 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
e = e->callee->callees;
else
{
reset_edge_growth_cache (e);
if (e->inline_failed
&& inline_summary (e->callee)->inlinable
&& cgraph_function_body_availability (e->callee) >= AVAIL_AVAILABLE
&& !bitmap_bit_p (updated_nodes, e->callee->uid))
{
inline_summary (node)->estimated_growth = INT_MIN;
reset_node_growth_cache (node);
update_edge_key (heap, e);
}
if (e->next_callee)
@ -899,7 +900,7 @@ update_all_callee_keys (fibheap_t heap, struct cgraph_node *node,
{
struct cgraph_edge *e = node->callees;
inline_summary (node)->estimated_growth = INT_MIN;
reset_node_growth_cache (node);
if (!e)
return;
@ -1131,7 +1132,7 @@ inline_small_functions (void)
metrics. */
max_count = 0;
max_benefit = 0;
initialize_growth_caches ();
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed
@ -1139,20 +1140,12 @@ inline_small_functions (void)
{
struct inline_summary *info = inline_summary (node);
info->estimated_growth = INT_MIN;
if (!DECL_EXTERNAL (node->decl))
initial_size += info->size;
for (edge = node->callers; edge; edge = edge->next_caller)
{
int benefit = (info->time_inlining_benefit
+ edge->call_stmt_time);
if (max_count < edge->count)
max_count = edge->count;
if (max_benefit < benefit)
max_benefit = benefit;
}
if (max_count < edge->count)
max_count = edge->count;
}
overall_size = initial_size;
@ -1354,14 +1347,15 @@ inline_small_functions (void)
}
}
free_growth_caches ();
if (new_indirect_edges)
VEC_free (cgraph_edge_p, heap, new_indirect_edges);
fibheap_delete (heap);
if (dump_file)
fprintf (dump_file,
"Unit growth for small function inlining: %i->%i (%i%%)\n",
overall_size, initial_size,
overall_size * 100 / (initial_size + 1) - 100);
initial_size, overall_size,
initial_size ? overall_size * 100 / (initial_size) - 100: 0);
BITMAP_FREE (updated_nodes);
}
@ -1369,7 +1363,7 @@ inline_small_functions (void)
at IPA inlining time. */
static void
flatten_function (struct cgraph_node *node)
flatten_function (struct cgraph_node *node, bool early)
{
struct cgraph_edge *e;
@ -1398,14 +1392,14 @@ flatten_function (struct cgraph_node *node)
it in order to fully flatten the leaves. */
if (!e->inline_failed)
{
flatten_function (e->callee);
flatten_function (e->callee, early);
continue;
}
/* Flatten attribute needs to be processed during late inlining. For
extra code quality we however do flattening during early optimization,
too. */
if (cgraph_state != CGRAPH_STATE_IPA_SSA
if (!early
? !can_inline_edge_p (e, true)
: !can_early_inline_edge_p (e))
continue;
@ -1435,7 +1429,7 @@ flatten_function (struct cgraph_node *node)
inline_call (e, true, NULL, NULL);
if (e->callee != orig_callee)
orig_callee->aux = (void *) node;
flatten_function (e->callee);
flatten_function (e->callee, early);
if (e->callee != orig_callee)
orig_callee->aux = NULL;
}
@ -1488,7 +1482,7 @@ ipa_inline (void)
if (dump_file)
fprintf (dump_file,
"Flattening %s\n", cgraph_node_name (node));
flatten_function (node);
flatten_function (node, false);
}
}
@ -1696,7 +1690,7 @@ early_inliner (void)
if (dump_file)
fprintf (dump_file,
"Flattening %s\n", cgraph_node_name (node));
flatten_function (node);
flatten_function (node, true);
inlined = true;
}
else

View File

@ -19,9 +19,60 @@ 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/>. */
/* Function inlining information. */
/* Representation of inline parameters that do depend on context function is
inlined into (i.e. known constant values of function parameters.
struct inline_summary
Conditions that are interesting for function body are collected into CONDS
vector. They are of simple for function_param OP VAL, where VAL is
IPA invariant. The conditions are then refered by predicates. */
typedef struct GTY(()) condition
{
tree val;
int operand_num;
enum tree_code code;
} condition;
DEF_VEC_O (condition);
DEF_VEC_ALLOC_O (condition, gc);
typedef VEC(condition,gc) *conditions;
/* Representation of predicates i.e. formulas using conditions defined
above. Predicates are simple logical formulas in conjunctive-disjunctive
form.
Predicate is array of clauses terminated by 0. Every clause must be true
in order to make predicate true.
Clauses are represented as bitmaps of conditions. One of conditions
must be true in order for clause to be true. */
#define MAX_CLAUSES 8
typedef int clause_t;
struct GTY(()) predicate
{
clause_t clause[MAX_CLAUSES + 1];
};
/* Represnetation of function body size and time depending on the inline
context. We keep simple array of record, every containing of predicate
and time/size to account.
We keep values scaled up, so fractional sizes and times can be
accounted. */
#define INLINE_SIZE_SCALE 2
#define INLINE_TIME_SCALE (CGRAPH_FREQ_BASE * 2)
typedef struct GTY(()) size_time_entry
{
struct predicate predicate;
int size;
int time;
} size_time_entry;
DEF_VEC_O (size_time_entry);
DEF_VEC_ALLOC_O (size_time_entry, gc);
/* Function inlining information. */
struct GTY(()) inline_summary
{
/* Information about the function body itself. */
@ -29,12 +80,8 @@ struct inline_summary
HOST_WIDE_INT estimated_self_stack_size;
/* Size of the function body. */
int self_size;
/* How many instructions are likely going to disappear after inlining. */
int size_inlining_benefit;
/* Estimated time spent executing the function body. */
/* Time of the function body. */
int self_time;
/* How much time is going to be saved by inlining. */
int time_inlining_benefit;
/* False when there something makes inlining impossible (such as va_arg). */
unsigned inlinable : 1;
@ -53,15 +100,25 @@ struct inline_summary
/* Estimated size of the function after inlining. */
int time;
int size;
/* Cached estimated growth after inlining.
INT_MIN if not computed. */
int estimated_growth;
conditions conds;
VEC(size_time_entry,gc) *entry;
};
typedef struct inline_summary inline_summary_t;
DEF_VEC_O(inline_summary_t);
DEF_VEC_ALLOC_O(inline_summary_t,heap);
extern VEC(inline_summary_t,heap) *inline_summary_vec;
DEF_VEC_ALLOC_O(inline_summary_t,gc);
extern GTY(()) VEC(inline_summary_t,gc) *inline_summary_vec;
typedef struct edge_growth_cache_entry
{
int time, size;
} edge_growth_cache_entry;
DEF_VEC_O(edge_growth_cache_entry);
DEF_VEC_ALLOC_O(edge_growth_cache_entry,heap);
extern VEC(int,heap) *node_growth_cache;
extern VEC(edge_growth_cache_entry,heap) *edge_growth_cache;
/* In ipa-inline-analysis.c */
void debug_inline_summary (struct cgraph_node *);
@ -73,7 +130,13 @@ void inline_free_summary (void);
void initialize_inline_failed (struct cgraph_edge *);
int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_growth (struct cgraph_node *);
int do_estimate_growth (struct cgraph_node *);
void inline_merge_summary (struct cgraph_edge *edge);
int do_estimate_edge_growth (struct cgraph_edge *edge);
int do_estimate_edge_time (struct cgraph_edge *edge);
void initialize_growth_caches (void);
void free_growth_caches (void);
void compute_inline_parameters (struct cgraph_node *, bool);
/* In ipa-inline-transform.c */
bool inline_call (struct cgraph_edge *, bool, VEC (cgraph_edge_p, heap) **, int *);
@ -89,16 +152,71 @@ inline_summary (struct cgraph_node *node)
return VEC_index (inline_summary_t, inline_summary_vec, node->uid);
}
/* Estimate the growth of the caller when inlining EDGE. */
/* Return estimated unit growth after inlning all calls to NODE.
Quick accesors to the inline growth caches.
For convenience we keep zero 0 as unknown. Because growth
can be both positive and negative, we simply increase positive
growths by 1. */
static inline int
estimate_growth (struct cgraph_node *node)
{
int ret;
if ((int)VEC_length (int, node_growth_cache) <= node->uid
|| !(ret = VEC_index (int, node_growth_cache, node->uid)))
return do_estimate_growth (node);
return ret - (ret > 0);
}
/* Return estimated callee growth after inlining EDGE. */
static inline int
estimate_edge_growth (struct cgraph_edge *edge)
{
int call_stmt_size;
struct inline_summary *info = inline_summary (edge->callee);
call_stmt_size = edge->call_stmt_size;
gcc_checking_assert (call_stmt_size);
return (info->size
- info->size_inlining_benefit
- call_stmt_size);
int ret;
if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) <= edge->uid
|| !(ret = VEC_index (edge_growth_cache_entry,
edge_growth_cache,
edge->uid)->size))
return do_estimate_edge_growth (edge);
return ret - (ret > 0);
}
/* Return estimated callee runtime increase after inlning
EDGE. */
static inline int
estimate_edge_time (struct cgraph_edge *edge)
{
int ret;
if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) <= edge->uid
|| !(ret = VEC_index (edge_growth_cache_entry,
edge_growth_cache,
edge->uid)->size))
return do_estimate_edge_time (edge);
return ret - (ret > 0);
}
/* Reset cached value for NODE. */
static inline void
reset_node_growth_cache (struct cgraph_node *node)
{
if ((int)VEC_length (int, node_growth_cache) > node->uid)
VEC_replace (int, node_growth_cache, node->uid, 0);
}
/* Reset cached value for EDGE. */
static inline void
reset_edge_growth_cache (struct cgraph_edge *edge)
{
if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) > edge->uid)
{
struct edge_growth_cache_entry zero = {0, 0};
VEC_replace (edge_growth_cache_entry, edge_growth_cache, edge->uid, &zero);
}
}

View File

@ -126,7 +126,7 @@ ipa_pop_func_from_list (struct ipa_func_list **wl)
/* Return index of the formal whose tree is PTREE in function which corresponds
to INFO. */
static int
int
ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
{
int i, count;
@ -2986,3 +2986,66 @@ ipa_update_after_lto_read (void)
ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
}
}
/* Given the jump function JFUNC, compute the lattice LAT that describes the
value coming down the callsite. INFO describes the caller node so that
pass-through jump functions can be evaluated. */
void
ipa_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
struct ipa_jump_func *jfunc)
{
if (jfunc->type == IPA_JF_CONST)
{
lat->type = IPA_CONST_VALUE;
lat->constant = jfunc->value.constant;
}
else if (jfunc->type == IPA_JF_PASS_THROUGH)
{
struct ipcp_lattice *caller_lat;
tree cst;
caller_lat = ipa_get_lattice (info, jfunc->value.pass_through.formal_id);
lat->type = caller_lat->type;
if (caller_lat->type != IPA_CONST_VALUE)
return;
cst = caller_lat->constant;
if (jfunc->value.pass_through.operation != NOP_EXPR)
{
tree restype;
if (TREE_CODE_CLASS (jfunc->value.pass_through.operation)
== tcc_comparison)
restype = boolean_type_node;
else
restype = TREE_TYPE (cst);
cst = fold_binary (jfunc->value.pass_through.operation,
restype, cst, jfunc->value.pass_through.operand);
}
if (!cst || !is_gimple_ip_invariant (cst))
lat->type = IPA_BOTTOM;
lat->constant = cst;
}
else if (jfunc->type == IPA_JF_ANCESTOR)
{
struct ipcp_lattice *caller_lat;
tree t;
caller_lat = ipa_get_lattice (info, jfunc->value.ancestor.formal_id);
lat->type = caller_lat->type;
if (caller_lat->type != IPA_CONST_VALUE)
return;
if (TREE_CODE (caller_lat->constant) != ADDR_EXPR)
{
/* This can happen when the constant is a NULL pointer. */
lat->type = IPA_BOTTOM;
return;
}
t = TREE_OPERAND (caller_lat->constant, 0);
t = build_ref_for_offset (EXPR_LOCATION (t), t,
jfunc->value.ancestor.offset,
jfunc->value.ancestor.type, NULL, false);
lat->constant = build_fold_addr_expr (t);
}
else
lat->type = IPA_BOTTOM;
}

View File

@ -515,9 +515,20 @@ void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree);
void ipa_prop_write_jump_functions (cgraph_node_set set);
void ipa_prop_read_jump_functions (void);
void ipa_update_after_lto_read (void);
int ipa_get_param_decl_index (struct ipa_node_params *, tree);
void ipa_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
struct ipa_jump_func *jfunc);
/* From tree-sra.c: */
tree build_ref_for_offset (location_t, tree, HOST_WIDE_INT, tree,
gimple_stmt_iterator *, bool);
/* Return the lattice corresponding to the Ith formal parameter of the function
described by INFO. */
static inline struct ipcp_lattice *
ipa_get_lattice (struct ipa_node_params *info, int i)
{
return &(info->params[i].ipcp_lattice);
}
#endif /* IPA_PROP_H */

View File

@ -1254,7 +1254,7 @@ split_function (struct split_point *split_point)
}
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
compute_inline_parameters (node);
compute_inline_parameters (node, true);
}
/* Execute function splitting pass. */

View File

@ -188,7 +188,7 @@ DEFPARAM(PARAM_IPCP_UNIT_GROWTH,
DEFPARAM(PARAM_EARLY_INLINING_INSNS,
"early-inlining-insns",
"Maximal estimated growth of function body caused by early inlining of single call",
10, 0, 0)
11, 0, 0)
DEFPARAM(PARAM_LARGE_STACK_FRAME,
"large-stack-frame",
"The size of stack frame to be considered large",

View File

@ -1,3 +1,7 @@
2011-04-22 Jan Hubicka <jh@suse.cz>
* gcc.dg/tree-ssa/pr38699.c: Fix testcase.
2011-04-22 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/48717

View File

@ -17,6 +17,7 @@
#define PORTC _SFR_IO8(0x15)
#define PORTD _SFR_IO8(0x12)
static void delay_wait_us( unsigned char timeout ) {
__asm__ __volatile__ ("wdr");
@ -27,8 +28,12 @@ static void delay_wait_us( unsigned char timeout ) {
while(!(TIFR & (1 << (TOV0))));
}
/* The original testcase was multiplying by 1000. Gcc is now smart enough
to work out that actual parameter is 5000 that is not what testcase was
about. Obstructate the code somewhat then. */
int a;
static void delay_wait_us_ms( unsigned char timeout ) {
delay_wait_us( timeout * 1000 );
delay_wait_us( timeout * a );
}

View File

@ -4366,7 +4366,7 @@ convert_callers (struct cgraph_node *node, tree old_decl,
for (cs = node->callers; cs; cs = cs->next_caller)
if (bitmap_set_bit (recomputed_callers, cs->caller->uid)
&& gimple_in_ssa_p (DECL_STRUCT_FUNCTION (cs->caller->decl)))
compute_inline_parameters (cs->caller);
compute_inline_parameters (cs->caller, true);
BITMAP_FREE (recomputed_callers);
current_function_decl = old_cur_fndecl;