ipa-cp.c (ipcp_print_edge_profiles): Test for node->analyzed rather than for DECL_SAVED_TREE.
2008-07-23 Martin Jambor <mjambor@suse.cz> * ipa-cp.c (ipcp_print_edge_profiles): Test for node->analyzed rather than for DECL_SAVED_TREE. * ipa-prop.c: Include diagnostic.h. (ipa_check_stmt_modifications): Check LHS of GIMPLE_MODIFY_EXPRs thoroughly. (ipa_detect_param_modifications): Function rewritten from scratch. (ipa_compute_jump_functions): Changed accesses to modification flags. (ipa_free_node_params_substructures): Update flags destruction. (ipa_node_duplication_hook): Update flags duplication. (ipa_print_all_params_modified): Updated flag access. * ipa-prop.h (struct ipa_param_flags): New structure. (struct ipa_node_params): New field modification_analysis_done, modified_flags changed into param_flags. (ipa_is_ith_param_modified): Changed to use new flags. * Makefile.in (ipa-prop.o): Add $(DIAGNOSTIC_H) to dependencies. * ipa-prop.c (ipa_print_all_jump_functions): Moved here from ipa-cp.c and split into two functions. (ipa_print_node_jump_functions): New function. (compute_scalar_jump_functions): New function. (type_like_member_ptr_p): New function. (compute_pass_through_member_ptrs): New function. (fill_member_ptr_cst_jump_function): New function. (determine_cst_member_ptr): New function. (compute_cst_member_ptr_arguments): New function. (ipa_compute_jump_functions): Complete rewrite. * ipa-prop.h (enum jump_func_type): Make explicit that we depend on IPA_UNKNOWN being zero. Added value IPA_CONST_MEMBER_PTR. (struct ipa_member_ptr_cst): New structure. (union jump_func_value): New field member_cst. * ipa-cp.c (ipcp_lat_is_insertable): New function. (ipcp_lattice_from_jfunc): Produces bottom lattices for unhandled jump function types. (ipcp_print_all_lattices): Slight fprintf rearrangement. (ipcp_print_all_structures): Call ipa_print_all_jump_functions instead of ipcp_print_all_jump_functions. (ipcp_insert_stage): Use ipcp_lat_is_insertable, create replace maps only for replacable scalars. * doc/invoke.texi (Optimize options): Add description of -findirect-inlining. * common.opt (flag_indirect_inlining): New flag. * opts.c (decode_options): Set flag_indirect_inlining when optimize >= 3. * ipa-inline.c: Include ipa-prop.h. (inline_indirect_intraprocedural_analysis): New function. (inline_generate_summary): Allocate parameter and argument info structures, call inline_indirect_intraprocedural_analysis on each node when doing indirect inlining and deallocate indirect inlining data structures in the end. * ipa-prop.c (ipa_create_param_decls_array): Return if already done. (free_all_ipa_structures_after_iinln): New function. (free_all_ipa_structures_after_ipa_cp): Checks whether iinln will be done. * Makefile.in (ipa-inline.o): Added $(IPA_PROP_H) to dependencies. * cgraphbuild.c (compute_call_stmt_bb_frequency): New function. (build_cgraph_edges): Call compute_call_stmt_bb_frequency instead of computing the frequency separately. (rebuild_cgraph_edges): Call compute_call_stmt_bb_frequency instead of computing the frequency separately. * ipa-cp.c (ipcp_print_all_structures): Replace a call to ipa_print_all_param_modified with a call to ipa_print_all_param_flags. * ipa-prop.c (ipa_get_member_ptr_load_param): New function. (ipa_get_stmt_member_ptr_load_param): New function. (ipa_is_ssa_with_stmt_def): New function. (ipa_note_param_call): New function. (ipa_analyze_call_uses): New function. (ipa_analyze_stmt_uses): New function. (ipa_analyze_params_uses): New function. (ipa_free_node_params_substructures): Also free the param_calls linked list. (ipa_node_duplication_hook): Also duplicate the param_calls linked list. (ipa_print_node_param_flags): New function. (ipa_print_all_params_modified): Renamed to ipa_print_all_param_flags. (ipa_print_all_param_flags): Calls ipa_print_node_param_flags. * ipa-prop.h (struct ipa_param_flags): New field called. (struct ipa_param_call_note): New structure. (struct ipa_node_params): New fields param_calls and uses_analysis_done. (ipa_is_ith_param_called): New function. * ipa-inline.c (inline_indirect_intraprocedural_analysis): Call ipa_analyze_params_uses and dump parameter flags. * ipa-inline.c (cgraph_decide_recursive_inlining): Call ipa_propagate_indirect_call_infos if performing indirect inlining, pass a new parameter new_edges to it. (add_new_edges_to_heap): New fucntion. (cgraph_decide_inlining_of_small_functions): New vector new_indirect_edges for newly found indirect edges , call ipa_propagate_indirect_call_infos after inlining. (cgraph_decide_inlining): Call ipa_propagate_indirect_call_infos after inlining if performing indirect inlining. Call free_all_ipa_structures_after_iinln when doing so too. (inline_generate_summary): Do not call free_all_ipa_structures_after_iinln here. * ipa-prop.c (update_jump_functions_after_inlining): New function. (print_edge_addition_message): New function. (update_call_notes_after_inlining): New function. (propagate_info_to_inlined_callees): New function. (ipa_propagate_indirect_call_infos): New function. * ipa-prop.h: Include cgraph.h (struct ipa_param_call_note): Fields reordered, new field processed. * cgraph.h (cgraph_edge): Shrink loop_nest field to 31 bits, add a new flag indirect_call. * cgraphunit.c (verify_cgraph_node): Allow indirect edges not to have rediscovered call statements. * cgraph.c (cgraph_create_edge): Initialize indirect_call to zero. (dump_cgraph_node): Dump also the indirect_call flag. (cgraph_clone_edge): Copy also the indirect_call flag. * tree-inline.c (copy_bb): Do not check for fndecls from call expressions, check for edge availability when moving clones. (get_indirect_callee_fndecl): New function. (expand_call_inline): If callee declaration is not apprent from the statement, try calling get_indirect_callee_fndecl. Do not issue warnings or call sorry when not inlinings an indirect edge. * Makefile.in (IPA_PROP_H): Added $(CGRAPH_H) to dependencies. * ipa-prop.c (ipa_print_node_param_flags): Make the dump format a bit more frandly to matching. * testsuite/g++.dg/ipa/iinline-1.C: New testcase. * testsuite/gcc.dg/ipa/iinline-1.c: New testcase. * testsuite/gcc.dg/ipa/modif-1.c: New testcase. From-SVN: r138092
This commit is contained in:
parent
e62fe68a64
commit
3e293154d6
17 changed files with 1404 additions and 286 deletions
127
gcc/ChangeLog
127
gcc/ChangeLog
|
@ -1,3 +1,130 @@
|
|||
2008-07-23 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* ipa-cp.c (ipcp_print_edge_profiles): Test for node->analyzed
|
||||
rather than for DECL_SAVED_TREE.
|
||||
* ipa-prop.c: Include diagnostic.h.
|
||||
(ipa_check_stmt_modifications): Check LHS of GIMPLE_MODIFY_EXPRs
|
||||
thoroughly.
|
||||
(ipa_detect_param_modifications): Function rewritten from scratch.
|
||||
(ipa_compute_jump_functions): Changed accesses to modification flags.
|
||||
(ipa_free_node_params_substructures): Update flags destruction.
|
||||
(ipa_node_duplication_hook): Update flags duplication.
|
||||
(ipa_print_all_params_modified): Updated flag access.
|
||||
* ipa-prop.h (struct ipa_param_flags): New structure.
|
||||
(struct ipa_node_params): New field modification_analysis_done,
|
||||
modified_flags changed into param_flags.
|
||||
(ipa_is_ith_param_modified): Changed to use new flags.
|
||||
* Makefile.in (ipa-prop.o): Add $(DIAGNOSTIC_H) to dependencies.
|
||||
|
||||
* ipa-prop.c (ipa_print_all_jump_functions): Moved here from
|
||||
ipa-cp.c and split into two functions.
|
||||
(ipa_print_node_jump_functions): New function.
|
||||
(compute_scalar_jump_functions): New function.
|
||||
(type_like_member_ptr_p): New function.
|
||||
(compute_pass_through_member_ptrs): New function.
|
||||
(fill_member_ptr_cst_jump_function): New function.
|
||||
(determine_cst_member_ptr): New function.
|
||||
(compute_cst_member_ptr_arguments): New function.
|
||||
(ipa_compute_jump_functions): Complete rewrite.
|
||||
* ipa-prop.h (enum jump_func_type): Make explicit that we depend
|
||||
on IPA_UNKNOWN being zero. Added value IPA_CONST_MEMBER_PTR.
|
||||
(struct ipa_member_ptr_cst): New structure.
|
||||
(union jump_func_value): New field member_cst.
|
||||
* ipa-cp.c (ipcp_lat_is_insertable): New function.
|
||||
(ipcp_lattice_from_jfunc): Produces bottom lattices for unhandled
|
||||
jump function types.
|
||||
(ipcp_print_all_lattices): Slight fprintf rearrangement.
|
||||
(ipcp_print_all_structures): Call ipa_print_all_jump_functions
|
||||
instead of ipcp_print_all_jump_functions.
|
||||
(ipcp_insert_stage): Use ipcp_lat_is_insertable, create replace maps
|
||||
only for replacable scalars.
|
||||
|
||||
* doc/invoke.texi (Optimize options): Add description of
|
||||
-findirect-inlining.
|
||||
* common.opt (flag_indirect_inlining): New flag.
|
||||
* opts.c (decode_options): Set flag_indirect_inlining when
|
||||
optimize >= 3.
|
||||
|
||||
* ipa-inline.c: Include ipa-prop.h.
|
||||
(inline_indirect_intraprocedural_analysis): New function.
|
||||
(inline_generate_summary): Allocate parameter and argument info
|
||||
structures, call inline_indirect_intraprocedural_analysis on each
|
||||
node when doing indirect inlining and deallocate indirect inlining
|
||||
data structures in the end.
|
||||
* ipa-prop.c (ipa_create_param_decls_array): Return if already done.
|
||||
(free_all_ipa_structures_after_iinln): New function.
|
||||
(free_all_ipa_structures_after_ipa_cp): Checks whether iinln will be
|
||||
done.
|
||||
* Makefile.in (ipa-inline.o): Added $(IPA_PROP_H) to dependencies.
|
||||
|
||||
* cgraphbuild.c (compute_call_stmt_bb_frequency): New function.
|
||||
(build_cgraph_edges): Call compute_call_stmt_bb_frequency instead
|
||||
of computing the frequency separately.
|
||||
(rebuild_cgraph_edges): Call compute_call_stmt_bb_frequency instead
|
||||
of computing the frequency separately.
|
||||
* ipa-cp.c (ipcp_print_all_structures): Replace a call to
|
||||
ipa_print_all_param_modified with a call to ipa_print_all_param_flags.
|
||||
* ipa-prop.c (ipa_get_member_ptr_load_param): New function.
|
||||
(ipa_get_stmt_member_ptr_load_param): New function.
|
||||
(ipa_is_ssa_with_stmt_def): New function.
|
||||
(ipa_note_param_call): New function.
|
||||
(ipa_analyze_call_uses): New function.
|
||||
(ipa_analyze_stmt_uses): New function.
|
||||
(ipa_analyze_params_uses): New function.
|
||||
(ipa_free_node_params_substructures): Also free the param_calls linked
|
||||
list.
|
||||
(ipa_node_duplication_hook): Also duplicate the param_calls linked list.
|
||||
(ipa_print_node_param_flags): New function.
|
||||
(ipa_print_all_params_modified): Renamed to ipa_print_all_param_flags.
|
||||
(ipa_print_all_param_flags): Calls ipa_print_node_param_flags.
|
||||
* ipa-prop.h (struct ipa_param_flags): New field called.
|
||||
(struct ipa_param_call_note): New structure.
|
||||
(struct ipa_node_params): New fields param_calls and
|
||||
uses_analysis_done.
|
||||
(ipa_is_ith_param_called): New function.
|
||||
* ipa-inline.c (inline_indirect_intraprocedural_analysis): Call
|
||||
ipa_analyze_params_uses and dump parameter flags.
|
||||
|
||||
* ipa-inline.c (cgraph_decide_recursive_inlining): Call
|
||||
ipa_propagate_indirect_call_infos if performing indirect inlining,
|
||||
pass a new parameter new_edges to it.
|
||||
(add_new_edges_to_heap): New fucntion.
|
||||
(cgraph_decide_inlining_of_small_functions): New vector
|
||||
new_indirect_edges for newly found indirect edges , call
|
||||
ipa_propagate_indirect_call_infos after inlining.
|
||||
(cgraph_decide_inlining): Call ipa_propagate_indirect_call_infos after
|
||||
inlining if performing indirect inlining. Call
|
||||
free_all_ipa_structures_after_iinln when doing so too.
|
||||
(inline_generate_summary): Do not call
|
||||
free_all_ipa_structures_after_iinln here.
|
||||
* ipa-prop.c (update_jump_functions_after_inlining): New function.
|
||||
(print_edge_addition_message): New function.
|
||||
(update_call_notes_after_inlining): New function.
|
||||
(propagate_info_to_inlined_callees): New function.
|
||||
(ipa_propagate_indirect_call_infos): New function.
|
||||
* ipa-prop.h: Include cgraph.h
|
||||
(struct ipa_param_call_note): Fields reordered, new field processed.
|
||||
* cgraph.h (cgraph_edge): Shrink loop_nest field to 31 bits, add a new
|
||||
flag indirect_call.
|
||||
* cgraphunit.c (verify_cgraph_node): Allow indirect edges not to have
|
||||
rediscovered call statements.
|
||||
* cgraph.c (cgraph_create_edge): Initialize indirect_call to zero.
|
||||
(dump_cgraph_node): Dump also the indirect_call flag.
|
||||
(cgraph_clone_edge): Copy also the indirect_call flag.
|
||||
* tree-inline.c (copy_bb): Do not check for fndecls from call
|
||||
expressions, check for edge availability when moving clones.
|
||||
(get_indirect_callee_fndecl): New function.
|
||||
(expand_call_inline): If callee declaration is not apprent from
|
||||
the statement, try calling get_indirect_callee_fndecl. Do not
|
||||
issue warnings or call sorry when not inlinings an indirect edge.
|
||||
* Makefile.in (IPA_PROP_H): Added $(CGRAPH_H) to dependencies.
|
||||
|
||||
* ipa-prop.c (ipa_print_node_param_flags): Make the dump format a
|
||||
bit more frandly to matching.
|
||||
* testsuite/g++.dg/ipa/iinline-1.C: New testcase.
|
||||
* testsuite/gcc.dg/ipa/iinline-1.c: New testcase.
|
||||
* testsuite/gcc.dg/ipa/modif-1.c: New testcase.
|
||||
|
||||
2008-07-23 Michael Meissner <gnu@the-meissners.org>
|
||||
|
||||
PR 36907
|
||||
|
|
|
@ -860,7 +860,7 @@ TREE_INLINE_H = tree-inline.h $(VARRAY_H) pointer-set.h
|
|||
REAL_H = real.h $(MACHMODE_H)
|
||||
DBGCNT_H = dbgcnt.h dbgcnt.def
|
||||
EBIMAP_H = ebitmap.h sbitmap.h
|
||||
IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h
|
||||
IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
|
||||
GSTAB_H = gstab.h stab.def
|
||||
BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h
|
||||
|
||||
|
@ -2564,8 +2564,8 @@ varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
|||
$(TREE_FLOW_H) gt-varpool.h
|
||||
ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
|
||||
tree-pass.h $(TIMEVAR_H)
|
||||
ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) \
|
||||
ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
|
||||
$(TREE_FLOW_H) $(TM_H) tree-pass.h $(FLAGS_H) $(TREE_H) $(TREE_INLINE_H) \
|
||||
$(TIMEVAR_H)
|
||||
ipa-cp.o : ipa-cp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
|
@ -2581,7 +2581,7 @@ matrix-reorg.o : matrix-reorg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
|||
ipa-inline.o : ipa-inline.c gt-ipa-inline.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
|
||||
$(DIAGNOSTIC_H) $(FIBHEAP_H) $(PARAMS_H) $(TIMEVAR_H) tree-pass.h \
|
||||
$(HASHTAB_H) $(COVERAGE_H) $(GGC_H) $(TREE_FLOW_H) $(RTL_H)
|
||||
$(HASHTAB_H) $(COVERAGE_H) $(GGC_H) $(TREE_FLOW_H) $(RTL_H) $(IPA_PROP_H)
|
||||
ipa-utils.o : ipa-utils.c $(IPA_UTILS_H) $(CONFIG_H) $(SYSTEM_H) \
|
||||
coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \
|
||||
pointer-set.h $(GGC_H) $(C_COMMON_H) $(TREE_GIMPLE_H) \
|
||||
|
|
|
@ -625,6 +625,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
|
|||
gcc_assert (freq >= 0);
|
||||
gcc_assert (freq <= CGRAPH_FREQ_MAX);
|
||||
edge->loop_nest = nest;
|
||||
edge->indirect_call = 0;
|
||||
edge->uid = cgraph_edge_max_uid++;
|
||||
if (caller->call_site_hash)
|
||||
{
|
||||
|
@ -1048,6 +1049,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
|
|||
edge->frequency / (double)CGRAPH_FREQ_BASE);
|
||||
if (!edge->inline_failed)
|
||||
fprintf(f, "(inlined) ");
|
||||
if (edge->indirect_call)
|
||||
fprintf(f, "(indirect) ");
|
||||
}
|
||||
|
||||
fprintf (f, "\n calls: ");
|
||||
|
@ -1057,6 +1060,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
|
|||
edge->callee->uid);
|
||||
if (!edge->inline_failed)
|
||||
fprintf(f, "(inlined) ");
|
||||
if (edge->indirect_call)
|
||||
fprintf(f, "(indirect) ");
|
||||
if (edge->count)
|
||||
fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ",
|
||||
(HOST_WIDEST_INT)edge->count);
|
||||
|
@ -1166,6 +1171,7 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
|
|||
e->loop_nest + loop_nest);
|
||||
|
||||
new->inline_failed = e->inline_failed;
|
||||
new->indirect_call = e->indirect_call;
|
||||
if (update_original)
|
||||
{
|
||||
e->count -= new->count;
|
||||
|
|
|
@ -208,7 +208,9 @@ struct cgraph_edge GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_call
|
|||
per function call. The range is 0 to CGRAPH_FREQ_MAX. */
|
||||
int frequency;
|
||||
/* Depth of loop nest, 1 means no loop nest. */
|
||||
int loop_nest;
|
||||
unsigned int loop_nest : 31;
|
||||
/* Whether this edge describes a call that was originally indirect. */
|
||||
unsigned int indirect_call : 1;
|
||||
/* Unique id of the edge. */
|
||||
int uid;
|
||||
};
|
||||
|
@ -376,6 +378,7 @@ void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
|
|||
|
||||
/* In cgraphbuild.c */
|
||||
unsigned int rebuild_cgraph_edges (void);
|
||||
int compute_call_stmt_bb_frequency (basic_block bb);
|
||||
|
||||
/* In ipa.c */
|
||||
bool cgraph_remove_unreachable_nodes (bool, FILE *);
|
||||
|
|
|
@ -122,6 +122,25 @@ initialize_inline_failed (struct cgraph_node *node)
|
|||
}
|
||||
}
|
||||
|
||||
/* Computes the frequency of the call statement so that it can be stored in
|
||||
cgraph_edge. BB is the basic block of the call statement. */
|
||||
int
|
||||
compute_call_stmt_bb_frequency (basic_block bb)
|
||||
{
|
||||
int entry_freq = ENTRY_BLOCK_PTR->frequency;
|
||||
int freq;
|
||||
|
||||
if (!entry_freq)
|
||||
entry_freq = 1;
|
||||
|
||||
freq = (!bb->frequency && !entry_freq ? CGRAPH_FREQ_BASE
|
||||
: bb->frequency * CGRAPH_FREQ_BASE / entry_freq);
|
||||
if (freq > CGRAPH_FREQ_MAX)
|
||||
freq = CGRAPH_FREQ_MAX;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/* Create cgraph edges for function calls.
|
||||
Also look for functions and variables having addresses taken. */
|
||||
|
||||
|
@ -133,10 +152,6 @@ build_cgraph_edges (void)
|
|||
struct pointer_set_t *visited_nodes = pointer_set_create ();
|
||||
block_stmt_iterator bsi;
|
||||
tree step;
|
||||
int entry_freq = ENTRY_BLOCK_PTR->frequency;
|
||||
|
||||
if (!entry_freq)
|
||||
entry_freq = 1;
|
||||
|
||||
/* Create the callgraph edges and record the nodes referenced by the function.
|
||||
body. */
|
||||
|
@ -151,12 +166,8 @@ build_cgraph_edges (void)
|
|||
{
|
||||
int i;
|
||||
int n = call_expr_nargs (call);
|
||||
int freq = (!bb->frequency && !entry_freq ? CGRAPH_FREQ_BASE
|
||||
: bb->frequency * CGRAPH_FREQ_BASE / entry_freq);
|
||||
if (freq > CGRAPH_FREQ_MAX)
|
||||
freq = CGRAPH_FREQ_MAX;
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count, freq,
|
||||
bb->count, compute_call_stmt_bb_frequency (bb),
|
||||
bb->loop_depth);
|
||||
for (i = 0; i < n; i++)
|
||||
walk_tree (&CALL_EXPR_ARG (call, i),
|
||||
|
@ -227,10 +238,6 @@ rebuild_cgraph_edges (void)
|
|||
basic_block bb;
|
||||
struct cgraph_node *node = cgraph_node (current_function_decl);
|
||||
block_stmt_iterator bsi;
|
||||
int entry_freq = ENTRY_BLOCK_PTR->frequency;
|
||||
|
||||
if (!entry_freq)
|
||||
entry_freq = 1;
|
||||
|
||||
cgraph_node_remove_callees (node);
|
||||
|
||||
|
@ -244,14 +251,9 @@ rebuild_cgraph_edges (void)
|
|||
tree decl;
|
||||
|
||||
if (call && (decl = get_callee_fndecl (call)))
|
||||
{
|
||||
int freq = (!bb->frequency && !entry_freq ? CGRAPH_FREQ_BASE
|
||||
: bb->frequency * CGRAPH_FREQ_BASE / entry_freq);
|
||||
if (freq > CGRAPH_FREQ_MAX)
|
||||
freq = CGRAPH_FREQ_MAX;
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count, freq, bb->loop_depth);
|
||||
}
|
||||
cgraph_create_edge (node, cgraph_node (decl), stmt,
|
||||
bb->count, compute_call_stmt_bb_frequency (bb),
|
||||
bb->loop_depth);
|
||||
}
|
||||
initialize_inline_failed (node);
|
||||
gcc_assert (!node->global.inlined_to);
|
||||
|
|
|
@ -796,7 +796,7 @@ verify_cgraph_node (struct cgraph_node *node)
|
|||
|
||||
for (e = node->callees; e; e = e->next_callee)
|
||||
{
|
||||
if (!e->aux)
|
||||
if (!e->aux && !e->indirect_call)
|
||||
{
|
||||
error ("edge %s->%s has no corresponding call_stmt",
|
||||
cgraph_node_name (e->caller),
|
||||
|
|
|
@ -571,6 +571,10 @@ finhibit-size-directive
|
|||
Common Report Var(flag_inhibit_size_directive)
|
||||
Do not generate .size directives
|
||||
|
||||
findirect-inlining
|
||||
Common Report Var(flag_indirect_inlining)
|
||||
Perform indirect inlining
|
||||
|
||||
; Nonzero means that functions declared `inline' will be treated
|
||||
; as `static'. Prevents generation of zillions of copies of unused
|
||||
; static inline functions; instead, `inlines' are written out
|
||||
|
|
|
@ -328,8 +328,8 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-fearly-inlining -fexpensive-optimizations -ffast-math @gol
|
||||
-ffinite-math-only -ffloat-store -fforward-propagate @gol
|
||||
-ffunction-sections -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm @gol
|
||||
-fgcse-sm -fif-conversion -fif-conversion2 -finline-functions @gol
|
||||
-finline-functions-called-once -finline-limit=@var{n} @gol
|
||||
-fgcse-sm -fif-conversion -fif-conversion2 -findirect-inlining @gol
|
||||
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
|
||||
-finline-small-functions -fipa-cp -fipa-marix-reorg -fipa-pta @gol
|
||||
-fipa-pure-const -fipa-reference -fipa-struct-reorg @gol
|
||||
-fipa-type-escape -fivopts -fkeep-inline-functions -fkeep-static-consts @gol
|
||||
|
@ -5199,6 +5199,7 @@ also turns on the following optimization flags:
|
|||
-fdelete-null-pointer-checks @gol
|
||||
-fexpensive-optimizations @gol
|
||||
-fgcse -fgcse-lm @gol
|
||||
-findirect-inlining @gol
|
||||
-foptimize-sibling-calls @gol
|
||||
-fpeephole2 @gol
|
||||
-fregmove @gol
|
||||
|
@ -5216,8 +5217,8 @@ invoking @option{-O2} on programs that use computed gotos.
|
|||
|
||||
@item -O3
|
||||
@opindex O3
|
||||
Optimize yet more. @option{-O3} turns on all optimizations specified by
|
||||
@option{-O2} and also turns on the @option{-finline-functions},
|
||||
Optimize yet more. @option{-O3} turns on all optimizations specified
|
||||
by @option{-O2} and also turns on the @option{-finline-functions},
|
||||
@option{-funswitch-loops}, @option{-fpredictive-commoning},
|
||||
@option{-fgcse-after-reload} and @option{-ftree-vectorize} options.
|
||||
|
||||
|
@ -5319,6 +5320,15 @@ in this way.
|
|||
|
||||
Enabled at level @option{-O2}.
|
||||
|
||||
@item -findirect-inlining
|
||||
@opindex findirect-inlining
|
||||
Inline also indirect calls that are discovered to be known at compile
|
||||
time thanks to previous inlining. This option has any effect only
|
||||
when inlining itself is turned on by the @option{-finline-functions}
|
||||
or @option{-finline-small-functions} options.
|
||||
|
||||
Enabled at level @option{-O2}.
|
||||
|
||||
@item -finline-functions
|
||||
@opindex finline-functions
|
||||
Integrate all simple functions into their callers. The compiler
|
||||
|
|
96
gcc/ipa-cp.c
96
gcc/ipa-cp.c
|
@ -183,6 +183,18 @@ ipcp_lat_is_const (struct ipcp_lattice *lat)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Return whether LAT is a constant lattice that ipa-cp can actually insert
|
||||
into the code (i.e. constants excluding member pointers and pointers). */
|
||||
static inline bool
|
||||
ipcp_lat_is_insertable (struct ipcp_lattice *lat)
|
||||
{
|
||||
if ((lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
|
||||
&& !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if LAT1 and LAT2 are equal. */
|
||||
static inline bool
|
||||
ipcp_lats_are_equal (struct ipcp_lattice *lat1, struct ipcp_lattice *lat2)
|
||||
|
@ -247,9 +259,7 @@ static void
|
|||
ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
|
||||
struct ipa_jump_func *jfunc)
|
||||
{
|
||||
if (jfunc->type == IPA_UNKNOWN)
|
||||
lat->type = IPA_BOTTOM;
|
||||
else if (jfunc->type == IPA_CONST)
|
||||
if (jfunc->type == IPA_CONST)
|
||||
{
|
||||
lat->type = IPA_CONST_VALUE;
|
||||
lat->constant = jfunc->value.constant;
|
||||
|
@ -267,6 +277,8 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
|
|||
lat->type = caller_lat->type;
|
||||
lat->constant = caller_lat->constant;
|
||||
}
|
||||
else
|
||||
lat->type = IPA_BOTTOM;
|
||||
}
|
||||
|
||||
/* True when OLD and NEW values are not the same. */
|
||||
|
@ -303,17 +315,18 @@ ipcp_print_all_lattices (FILE * f)
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
|
||||
|
||||
fprintf (f, " param [%d]: ", i);
|
||||
if (lat->type == IPA_CONST_VALUE || lat->type == IPA_CONST_VALUE_REF)
|
||||
{
|
||||
fprintf (f, " param [%d]: ", i);
|
||||
fprintf (f, "type is CONST ");
|
||||
print_generic_expr (f, lat->constant, 0);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
else if (lat->type == IPA_TOP)
|
||||
fprintf (f, "param [%d]: type is TOP \n", i);
|
||||
fprintf (f, "type is TOP\n");
|
||||
else
|
||||
fprintf (f, "param [%d]: type is BOTTOM \n", i);
|
||||
fprintf (f, "type is BOTTOM\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -551,58 +564,6 @@ ipcp_node_not_modifiable_p (struct cgraph_node *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Print ipa_jump_func data structures to F. */
|
||||
static void
|
||||
ipcp_print_all_jump_functions (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)
|
||||
{
|
||||
if (!node->analyzed)
|
||||
continue;
|
||||
|
||||
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));
|
||||
|
||||
if (!ipa_edge_args_info_available_for_edge_p (cs)
|
||||
|| ipa_is_called_with_var_arguments (IPA_NODE_REF (cs->callee)))
|
||||
continue;
|
||||
|
||||
count = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
|
||||
type = jump_func->type;
|
||||
|
||||
fprintf (f, " param %d: ", i);
|
||||
if (type == IPA_UNKNOWN)
|
||||
fprintf (f, "UNKNOWN\n");
|
||||
else if (type == IPA_CONST || type == IPA_CONST_REF)
|
||||
{
|
||||
info_type = jump_func->value.constant;
|
||||
fprintf (f, "CONST : ");
|
||||
print_generic_expr (f, info_type, 0);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
else if (type == IPA_PASS_THROUGH)
|
||||
{
|
||||
fprintf (f, "PASS THROUGH : ");
|
||||
fprintf (f, "%d\n", jump_func->value.formal_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print count scale data structures. */
|
||||
static void
|
||||
ipcp_function_scale_print (FILE * f)
|
||||
|
@ -664,7 +625,7 @@ ipcp_print_edge_profiles (FILE * f)
|
|||
for (node = cgraph_nodes; node; node = node->next)
|
||||
{
|
||||
fprintf (f, "function %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));
|
||||
|
@ -751,8 +712,8 @@ ipcp_print_all_structures (FILE * f)
|
|||
ipcp_print_all_lattices (f);
|
||||
ipcp_function_scale_print (f);
|
||||
ipa_print_all_tree_maps (f);
|
||||
ipa_print_all_params_modified (f);
|
||||
ipcp_print_all_jump_functions (f);
|
||||
ipa_print_all_param_flags (f);
|
||||
ipa_print_all_jump_functions (f);
|
||||
}
|
||||
|
||||
/* Print profile info for all functions. */
|
||||
|
@ -781,10 +742,8 @@ ipcp_create_replace_map (struct function *func, tree parm_tree,
|
|||
tree const_val;
|
||||
|
||||
replace_map = XCNEW (struct ipa_replace_map);
|
||||
gcc_assert (ipcp_lat_is_const (lat));
|
||||
if (lat->type != IPA_CONST_VALUE_REF
|
||||
&& is_gimple_reg (parm_tree) && gimple_default_def (func, parm_tree)
|
||||
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_default_def (func,
|
||||
if (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)
|
||||
|
@ -944,7 +903,7 @@ ipcp_insert_stage (void)
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
|
||||
if (ipcp_lat_is_const (lat))
|
||||
if (ipcp_lat_is_insertable (lat))
|
||||
const_param++;
|
||||
}
|
||||
if (const_param == 0)
|
||||
|
@ -953,7 +912,8 @@ ipcp_insert_stage (void)
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
|
||||
if (ipcp_lat_is_const (lat))
|
||||
if (lat->type == IPA_CONST_VALUE
|
||||
&& !POINTER_TYPE_P (TREE_TYPE (lat->constant)))
|
||||
{
|
||||
parm_tree = ipa_get_ith_param (info, i);
|
||||
replace_param =
|
||||
|
@ -990,7 +950,7 @@ ipcp_insert_stage (void)
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
struct ipcp_lattice *lat = ipcp_get_ith_lattice (info, i);
|
||||
if (ipcp_lat_is_const (lat))
|
||||
if (ipcp_lat_is_insertable (lat))
|
||||
{
|
||||
parm_tree = ipa_get_ith_param (info, i);
|
||||
if (lat->type != IPA_CONST_VALUE_REF
|
||||
|
|
|
@ -139,6 +139,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "ggc.h"
|
||||
#include "tree-flow.h"
|
||||
#include "rtl.h"
|
||||
#include "ipa-prop.h"
|
||||
|
||||
/* Mode incremental inliner operate on:
|
||||
|
||||
|
@ -660,10 +661,12 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
|
|||
}
|
||||
|
||||
/* Decide on recursive inlining: in the case function has recursive calls,
|
||||
inline until body size reaches given argument. */
|
||||
inline until body size reaches given argument. If any new indirect edges
|
||||
are discovered in the process, add them to NEW_EDGES, unless it is NULL. */
|
||||
|
||||
static bool
|
||||
cgraph_decide_recursive_inlining (struct cgraph_node *node)
|
||||
cgraph_decide_recursive_inlining (struct cgraph_node *node,
|
||||
VEC (cgraph_edge_p, heap) *new_edges)
|
||||
{
|
||||
int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
|
||||
int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO);
|
||||
|
@ -760,6 +763,8 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node)
|
|||
}
|
||||
cgraph_redirect_edge_callee (curr, master_clone);
|
||||
cgraph_mark_inline_edge (curr, false);
|
||||
if (flag_indirect_inlining)
|
||||
ipa_propagate_indirect_call_infos (curr, new_edges);
|
||||
lookup_recursive_calls (node, curr->callee, heap);
|
||||
n++;
|
||||
}
|
||||
|
@ -817,6 +822,20 @@ compute_max_insns (int insns)
|
|||
* (100 + PARAM_VALUE (PARAM_INLINE_UNIT_GROWTH)) / 100);
|
||||
}
|
||||
|
||||
/* Compute badness of all edges in NEW_EDGES and add them to the HEAP. */
|
||||
static void
|
||||
add_new_edges_to_heap (fibheap_t heap, VEC (cgraph_edge_p, heap) *new_edges)
|
||||
{
|
||||
while (VEC_length (cgraph_edge_p, new_edges) > 0)
|
||||
{
|
||||
struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges);
|
||||
|
||||
gcc_assert (!edge->aux);
|
||||
edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We use greedy algorithm for inlining of small functions:
|
||||
All inline candidates are put into prioritized heap based on estimated
|
||||
growth of the overall number of instructions and then update the estimates.
|
||||
|
@ -833,6 +852,10 @@ cgraph_decide_inlining_of_small_functions (void)
|
|||
fibheap_t heap = fibheap_new ();
|
||||
bitmap updated_nodes = BITMAP_ALLOC (NULL);
|
||||
int min_insns, max_insns;
|
||||
VEC (cgraph_edge_p, heap) *new_indirect_edges = NULL;
|
||||
|
||||
if (flag_indirect_inlining)
|
||||
new_indirect_edges = VEC_alloc (cgraph_edge_p, heap, 8);
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "\nDeciding on smaller functions:\n");
|
||||
|
@ -968,8 +991,10 @@ cgraph_decide_inlining_of_small_functions (void)
|
|||
where = edge->caller;
|
||||
if (where->global.inlined_to)
|
||||
where = where->global.inlined_to;
|
||||
if (!cgraph_decide_recursive_inlining (where))
|
||||
if (!cgraph_decide_recursive_inlining (where, new_indirect_edges))
|
||||
continue;
|
||||
if (flag_indirect_inlining)
|
||||
add_new_edges_to_heap (heap, new_indirect_edges);
|
||||
update_callee_keys (heap, where, updated_nodes);
|
||||
}
|
||||
else
|
||||
|
@ -986,6 +1011,11 @@ cgraph_decide_inlining_of_small_functions (void)
|
|||
}
|
||||
callee = edge->callee;
|
||||
cgraph_mark_inline_edge (edge, true);
|
||||
if (flag_indirect_inlining)
|
||||
{
|
||||
ipa_propagate_indirect_call_infos (edge, new_indirect_edges);
|
||||
add_new_edges_to_heap (heap, new_indirect_edges);
|
||||
}
|
||||
update_callee_keys (heap, callee, updated_nodes);
|
||||
}
|
||||
where = edge->caller;
|
||||
|
@ -1028,6 +1058,9 @@ cgraph_decide_inlining_of_small_functions (void)
|
|||
&edge->inline_failed))
|
||||
edge->inline_failed = N_("--param inline-unit-growth limit reached");
|
||||
}
|
||||
|
||||
if (new_indirect_edges)
|
||||
VEC_free (cgraph_edge_p, heap, new_indirect_edges);
|
||||
fibheap_delete (heap);
|
||||
BITMAP_FREE (updated_nodes);
|
||||
}
|
||||
|
@ -1112,6 +1145,8 @@ cgraph_decide_inlining (void)
|
|||
continue;
|
||||
}
|
||||
cgraph_mark_inline_edge (e, true);
|
||||
if (flag_indirect_inlining)
|
||||
ipa_propagate_indirect_call_infos (e, NULL);
|
||||
if (dump_file)
|
||||
fprintf (dump_file,
|
||||
" Inlined into %s which now has %i insns.\n",
|
||||
|
@ -1133,6 +1168,11 @@ cgraph_decide_inlining (void)
|
|||
if (!flag_really_no_inline)
|
||||
cgraph_decide_inlining_of_small_functions ();
|
||||
|
||||
/* After this point, any edge discovery performed by indirect inlining is no
|
||||
good so let's give up. */
|
||||
if (flag_indirect_inlining)
|
||||
free_all_ipa_structures_after_iinln ();
|
||||
|
||||
if (!flag_really_no_inline
|
||||
&& flag_inline_functions_called_once)
|
||||
{
|
||||
|
@ -1612,6 +1652,31 @@ struct gimple_opt_pass pass_inline_parameters =
|
|||
}
|
||||
};
|
||||
|
||||
/* This function performs intraprocedural analyzis in NODE that is required to
|
||||
inline indirect calls. */
|
||||
static void
|
||||
inline_indirect_intraprocedural_analysis (struct cgraph_node *node)
|
||||
{
|
||||
struct cgraph_edge *cs;
|
||||
|
||||
ipa_count_formal_params (node);
|
||||
ipa_create_param_decls_array (node);
|
||||
ipa_detect_param_modifications (node);
|
||||
ipa_analyze_params_uses (node);
|
||||
|
||||
if (dump_file)
|
||||
ipa_print_node_param_flags (dump_file, node);
|
||||
|
||||
for (cs = node->callees; cs; cs = cs->next_callee)
|
||||
{
|
||||
ipa_count_arguments (cs);
|
||||
ipa_compute_jump_functions (cs);
|
||||
}
|
||||
|
||||
if (dump_file)
|
||||
ipa_print_node_jump_functions (dump_file, node);
|
||||
}
|
||||
|
||||
/* Note function body size. */
|
||||
static void
|
||||
inline_generate_summary (void)
|
||||
|
@ -1621,6 +1686,13 @@ inline_generate_summary (void)
|
|||
int nnodes = cgraph_postorder (order);
|
||||
int i;
|
||||
|
||||
if (flag_indirect_inlining)
|
||||
{
|
||||
ipa_register_cgraph_hooks ();
|
||||
ipa_check_create_node_params ();
|
||||
ipa_check_create_edge_args ();
|
||||
}
|
||||
|
||||
for (i = nnodes - 1; i >= 0; i--)
|
||||
{
|
||||
struct cgraph_node *node = order[i];
|
||||
|
@ -1632,6 +1704,10 @@ inline_generate_summary (void)
|
|||
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
|
||||
current_function_decl = node->decl;
|
||||
compute_inline_parameters (node);
|
||||
|
||||
if (flag_indirect_inlining)
|
||||
inline_indirect_intraprocedural_analysis (node);
|
||||
|
||||
pop_cfun ();
|
||||
}
|
||||
}
|
||||
|
|
1049
gcc/ipa-prop.c
1049
gcc/ipa-prop.c
File diff suppressed because it is too large
Load diff
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "tree.h"
|
||||
#include "vec.h"
|
||||
#include "cgraph.h"
|
||||
|
||||
/* The following definitions and interfaces are used by
|
||||
interprocedural analyses. */
|
||||
|
@ -32,21 +33,23 @@ along with GCC; see the file COPYING3. If not see
|
|||
Constant - a constant is passed as an actual argument.
|
||||
Unknown - neither of the above.
|
||||
Integer and real constants are represented as IPA_CONST and Fortran
|
||||
constants are represented as IPA_CONST_REF. */
|
||||
constants are represented as IPA_CONST_REF. Finally, IPA_CONST_MEMBER_PTR
|
||||
stands for C++ member pointers constants. */
|
||||
enum jump_func_type
|
||||
{
|
||||
IPA_UNKNOWN,
|
||||
IPA_UNKNOWN = 0, /* newly allocated and zeroed jump functions default */
|
||||
IPA_CONST,
|
||||
IPA_CONST_REF,
|
||||
IPA_CONST_MEMBER_PTR,
|
||||
IPA_PASS_THROUGH
|
||||
};
|
||||
|
||||
/* All formal parameters in the program have a lattice associated with it
|
||||
computed by the interprocedural stage of IPCP.
|
||||
There are three main values of the lattice:
|
||||
TOP - unknown.
|
||||
BOTTOM - non constant.
|
||||
CONSTANT_TYPE - constant value.
|
||||
IPA_TOP - unknown,
|
||||
IPA_BOTTOM - non constant,
|
||||
IPA_CONST_VALUE - simple scalar constant,
|
||||
Cval of formal f will have a constant value if all callsites to this
|
||||
function have the same constant value passed to f.
|
||||
Integer and real constants are represented as IPA_CONST and Fortran
|
||||
|
@ -59,14 +62,24 @@ enum ipa_lattice_type
|
|||
IPA_TOP
|
||||
};
|
||||
|
||||
/* Represents a value of a jump function.
|
||||
value represents a constant.
|
||||
formal_id is used only in jump function context and represents
|
||||
pass-through parameter (the formal of caller is passed as argument). */
|
||||
/* Structure holding a C++ member pointer constant. Holds a pointer to the
|
||||
method and delta offset. */
|
||||
struct ipa_member_ptr_cst
|
||||
{
|
||||
tree pfn;
|
||||
tree delta;
|
||||
};
|
||||
|
||||
/* Represents a value of a jump function. formal_id is used only in jump
|
||||
function context and represents pass-through parameter (the formal parameter
|
||||
of the caller is passed as argument). constant represents the actual
|
||||
constant in constant jump functions and member_cst holds constant c++ member
|
||||
functions. */
|
||||
union jump_func_value
|
||||
{
|
||||
unsigned int formal_id;
|
||||
tree constant;
|
||||
struct ipa_member_ptr_cst member_cst;
|
||||
};
|
||||
|
||||
/* A jump function for a callsite represents the values passed as actual
|
||||
|
@ -101,10 +114,43 @@ struct ipa_replace_map
|
|||
bool ref_p;
|
||||
};
|
||||
|
||||
/* ipa_param_flags contains various flags that describe how the associated
|
||||
parameter is treated within a function. */
|
||||
struct ipa_param_flags
|
||||
{
|
||||
/* Whether the value parameter has been modified within the function. */
|
||||
unsigned modified : 1;
|
||||
/* Whether the parameter has been used as a call destination. */
|
||||
unsigned called : 1;
|
||||
};
|
||||
|
||||
/* Each instance of the following structure describes a statement that calls a
|
||||
function parameter. Those referring to statements within the same function
|
||||
are linked in a list. */
|
||||
struct ipa_param_call_note
|
||||
{
|
||||
/* Linked list's next */
|
||||
struct ipa_param_call_note *next;
|
||||
/* Statement that contains the call to the parameter above. */
|
||||
tree stmt;
|
||||
/* Index of the parameter that is called. */
|
||||
unsigned int formal_id;
|
||||
/* Expected number of executions: calculated in profile.c. */
|
||||
gcov_type count;
|
||||
/* Expected frequency of executions within the function. see cgraph_edge in
|
||||
cgraph.h for more on this. */
|
||||
int frequency;
|
||||
/* Depth of loop nest, 1 means no loop nest. */
|
||||
int loop_nest;
|
||||
/* Set when we have already found the target to be a compile time constant
|
||||
and turned this into an edge or when the note was found unusable for some
|
||||
reason. */
|
||||
bool processed;
|
||||
};
|
||||
|
||||
/* ipa_node_params stores information related to formal parameters of functions
|
||||
and some other information for interprocedural passes that operate on
|
||||
parameters (such as ipa-cp). */
|
||||
|
||||
struct ipa_node_params
|
||||
{
|
||||
/* Number of formal parameters of this function. When set to 0,
|
||||
|
@ -115,8 +161,10 @@ struct ipa_node_params
|
|||
struct ipcp_lattice *ipcp_lattices;
|
||||
/* Mapping each parameter to its PARM_DECL tree. */
|
||||
tree *param_decls;
|
||||
/* Indicating which parameter is modified in its function. */
|
||||
bool *modified_flags;
|
||||
/* Various flags describing individual parameters. */
|
||||
struct ipa_param_flags *param_flags;
|
||||
/* List of structures enumerating calls to a formal parameter. */
|
||||
struct ipa_param_call_note *param_calls;
|
||||
/* Only for versioned nodes this field would not be NULL,
|
||||
it points to the node that IPA cp cloned from. */
|
||||
struct cgraph_node *ipcp_orig_node;
|
||||
|
@ -130,6 +178,10 @@ struct ipa_node_params
|
|||
/* Whether this function is called with variable number of actual
|
||||
arguments. */
|
||||
unsigned called_with_var_arguments : 1;
|
||||
/* Whether the modification analysis has already been performed. */
|
||||
unsigned modification_analysis_done : 1;
|
||||
/* Whether the param uses analysis has already been performed. */
|
||||
unsigned uses_analysis_done : 1;
|
||||
};
|
||||
|
||||
/* ipa_node_params access functions. Please use these to access fields that
|
||||
|
@ -164,7 +216,16 @@ ipa_get_ith_param (struct ipa_node_params *info, int i)
|
|||
static inline bool
|
||||
ipa_is_ith_param_modified (struct ipa_node_params *info, int i)
|
||||
{
|
||||
return info->modified_flags[i];
|
||||
return info->param_flags[i].modified;
|
||||
}
|
||||
|
||||
/* Returns the called flag corresponding o the ith paramterer. Note there is
|
||||
no setter method as the goal is to set all flags when building the array in
|
||||
ipa_detect_called_params. */
|
||||
static inline bool
|
||||
ipa_is_ith_param_called (struct ipa_node_params *info, int i)
|
||||
{
|
||||
return info->param_flags[i].called;
|
||||
}
|
||||
|
||||
/* Flag this node as having callers with variable number of arguments. */
|
||||
|
@ -255,6 +316,7 @@ void ipa_free_node_params_substructures (struct ipa_node_params *);
|
|||
void ipa_free_all_node_params (void);
|
||||
void ipa_free_all_edge_args (void);
|
||||
void free_all_ipa_structures_after_ipa_cp (void);
|
||||
void free_all_ipa_structures_after_iinln (void);
|
||||
void ipa_register_cgraph_hooks (void);
|
||||
|
||||
/* This function ensures the array of node param infos is big enough to
|
||||
|
@ -318,9 +380,15 @@ void ipa_count_arguments (struct cgraph_edge *);
|
|||
void ipa_count_formal_params (struct cgraph_node *);
|
||||
void ipa_create_param_decls_array (struct cgraph_node *);
|
||||
void ipa_detect_param_modifications (struct cgraph_node *);
|
||||
void ipa_analyze_params_uses (struct cgraph_node *);
|
||||
void ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
|
||||
VEC (cgraph_edge_p, heap) *new_edges);
|
||||
|
||||
/* Debugging interface. */
|
||||
void ipa_print_all_tree_maps (FILE *);
|
||||
void ipa_print_all_params_modified (FILE *);
|
||||
void ipa_print_node_param_flags (FILE * f, struct cgraph_node *node);
|
||||
void ipa_print_all_param_flags (FILE *);
|
||||
void ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node);
|
||||
void ipa_print_all_jump_functions (FILE * f);
|
||||
|
||||
#endif /* IPA_PROP_H */
|
||||
|
|
|
@ -934,6 +934,7 @@ decode_options (unsigned int argc, const char **argv)
|
|||
/* -O2 optimizations. */
|
||||
opt2 = (optimize >= 2);
|
||||
flag_inline_small_functions = opt2;
|
||||
flag_indirect_inlining = opt2;
|
||||
flag_thread_jumps = opt2;
|
||||
flag_crossjumping = opt2;
|
||||
flag_optimize_sibling_calls = opt2;
|
||||
|
|
47
gcc/testsuite/g++.dg/ipa/iinline-1.C
Normal file
47
gcc/testsuite/g++.dg/ipa/iinline-1.C
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* Verify that simple indirect calls are inlined even without early
|
||||
inlining.. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
|
||||
|
||||
extern void non_existent (const char *, int);
|
||||
|
||||
class String
|
||||
{
|
||||
private:
|
||||
const char *data;
|
||||
|
||||
public:
|
||||
String (const char *d) : data(d)
|
||||
{}
|
||||
|
||||
int funcOne (int delim) const;
|
||||
int printStuffTwice (int delim) const;
|
||||
};
|
||||
|
||||
|
||||
int String::funcOne (int delim) const
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < delim; i++)
|
||||
non_existent(data, i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int docalling (int (String::* f)(int delim) const)
|
||||
{
|
||||
String S ("muhehehe");
|
||||
|
||||
return (S.*f)(4);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
i = docalling (&String::funcOne);
|
||||
non_existent ("done", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "String::funcOne\[^\\n\]*inline copy in int main" "inline" } } */
|
||||
/* { dg-final { cleanup-tree-dump "inline" } } */
|
26
gcc/testsuite/gcc.dg/ipa/iinline-1.c
Normal file
26
gcc/testsuite/gcc.dg/ipa/iinline-1.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* Verify that simple indirect calls are inlined even without early
|
||||
inlining.. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
|
||||
|
||||
extern void non_existent(int);
|
||||
|
||||
static void hooray ()
|
||||
{
|
||||
non_existent (1);
|
||||
}
|
||||
|
||||
static void hiphip (void (*f)())
|
||||
{
|
||||
non_existent (2);
|
||||
f ();
|
||||
}
|
||||
|
||||
int main (int argc, int *argv[])
|
||||
{
|
||||
hiphip (hooray);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "hooray\[^\\n\]*inline copy in main" "inline" } } */
|
||||
/* { dg-final { cleanup-tree-dump "inline" } } */
|
44
gcc/testsuite/gcc.dg/ipa/modif-1.c
Normal file
44
gcc/testsuite/gcc.dg/ipa/modif-1.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* Verify that modification analysis detects modfications. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
|
||||
|
||||
struct whatever
|
||||
{
|
||||
int first;
|
||||
unsigned second;
|
||||
};
|
||||
|
||||
void func1 (struct whatever w);
|
||||
void func2 (struct whatever *pw);
|
||||
void func3 (int i);
|
||||
void func4 (int *pi);
|
||||
|
||||
void the_test (struct whatever u, struct whatever v,
|
||||
struct whatever w, struct whatever x,
|
||||
int i, int j, int k, int l)
|
||||
{
|
||||
struct whatever *pw = &w;
|
||||
int *pk = &k;
|
||||
|
||||
j = l+3;
|
||||
v.first = 9;
|
||||
|
||||
func1 (u);
|
||||
func1 (v);
|
||||
func2 (pw);
|
||||
func2 (&x);
|
||||
func3 (i);
|
||||
func3 (j);
|
||||
func4 (pk);
|
||||
func4 (&l);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-not "param 0 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 1 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 2 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 3 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump-not "param 4 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 5 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 6 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 7 flags:\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
|
@ -951,7 +951,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|
|||
pointer_set_insert (id->statements_to_fold, stmt);
|
||||
/* We're duplicating a CALL_EXPR. Find any corresponding
|
||||
callgraph edges and update or duplicate them. */
|
||||
if (call && (decl = get_callee_fndecl (call)))
|
||||
if (call)
|
||||
{
|
||||
struct cgraph_node *node;
|
||||
struct cgraph_edge *edge;
|
||||
|
@ -962,7 +962,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|
|||
edge = cgraph_edge (id->src_node, orig_stmt);
|
||||
if (edge)
|
||||
cgraph_clone_edge (edge, id->dst_node, stmt,
|
||||
REG_BR_PROB_BASE, 1, edge->frequency, true);
|
||||
REG_BR_PROB_BASE, 1,
|
||||
edge->frequency, true);
|
||||
break;
|
||||
|
||||
case CB_CGE_MOVE_CLONES:
|
||||
|
@ -971,8 +972,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|
|||
node = node->next_clone)
|
||||
{
|
||||
edge = cgraph_edge (node, orig_stmt);
|
||||
gcc_assert (edge);
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
if (edge)
|
||||
cgraph_set_call_stmt (edge, stmt);
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
|
@ -2580,6 +2581,20 @@ add_lexical_block (tree current_block, tree new_block)
|
|||
BLOCK_SUPERCONTEXT (new_block) = current_block;
|
||||
}
|
||||
|
||||
/* Fetch callee declaration from the call graph edge going from NODE and
|
||||
associated with STMR call statement. Return NULL_TREE if not found. */
|
||||
static tree
|
||||
get_indirect_callee_fndecl (struct cgraph_node *node, tree stmt)
|
||||
{
|
||||
struct cgraph_edge *cs;
|
||||
|
||||
cs = cgraph_edge (node, stmt);
|
||||
if (cs)
|
||||
return cs->callee->decl;
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* If *TP is a CALL_EXPR, replace it with its inline expansion. */
|
||||
|
||||
static bool
|
||||
|
@ -2621,7 +2636,11 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
If we cannot, then there is no hope of inlining the function. */
|
||||
fn = get_callee_fndecl (t);
|
||||
if (!fn)
|
||||
goto egress;
|
||||
{
|
||||
fn = get_indirect_callee_fndecl (id->dst_node, stmt);
|
||||
if (!fn)
|
||||
goto egress;
|
||||
}
|
||||
|
||||
/* Turn forward declarations into real ones. */
|
||||
fn = cgraph_node (fn)->decl;
|
||||
|
@ -2672,6 +2691,12 @@ expand_call_inline (basic_block bb, tree stmt, tree *tp, void *data)
|
|||
inlining. */
|
||||
if (!cgraph_inline_p (cg_edge, &reason))
|
||||
{
|
||||
/* If this call was originally indirect, we do not want to emit any
|
||||
inlining related warnings or sorry messages because there are no
|
||||
guarantees regarding those. */
|
||||
if (cg_edge->indirect_call)
|
||||
goto egress;
|
||||
|
||||
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
|
||||
/* Avoid warnings during early inline pass. */
|
||||
&& (!flag_unit_at_a_time || cgraph_global_info_ready))
|
||||
|
|
Loading…
Add table
Reference in a new issue