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:
Martin Jambor 2008-07-23 21:45:45 +02:00 committed by Martin Jambor
parent e62fe68a64
commit 3e293154d6
17 changed files with 1404 additions and 286 deletions

View File

@ -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

View File

@ -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) \

View File

@ -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;

View File

@ -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 *);

View 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);

View File

@ -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),

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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;

View 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" } } */

View 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" } } */

View 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" } } */

View File

@ -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))