Hi, this patch fixes two issues that reproduce with firefox build configured for LTO&FDO with -O3 -march=native on bdver2 (but probably elsewhere too).
The first is an ICE on out of bound accesss of jump functions. This is becuase inline_call uses speculation_useful_p which in turn evaulates predicates. This can't be done before jump functions are updated after clonning is finished. THe second is a wrong code, where ipa-cp manages to propagate address of non-constant variable and tries to use it as a call target. Both bugs I think exists already in GCC 4.9, but they are latent, so I will backport the patch, too. Bootstrapped/regtested ppc64-linux and also tested on Firefox build, will commit it shortly. Honza PR ipa/65743 * ipa-inline-transform.c (speculation_removed): Remove static var. (check_speculations): New function. (clone_inlined_nodes): Do not check spculations. (inline_call): Call check_speculations. * ipa-prop.c (ipa_make_edge_direct_to_target): Do not consider non-invariants. Index: ipa-inline-transform.c =================================================================== --- ipa-inline-transform.c (revision 222016) +++ ipa-inline-transform.c (working copy) @@ -64,7 +64,6 @@ along with GCC; see the file COPYING3. int ncalls_inlined; int nfunctions_inlined; -bool speculation_removed; /* Scale frequency of NODE edges by FREQ_SCALE. */ @@ -256,12 +255,29 @@ clone_inlined_nodes (struct cgraph_edge next = e->next_callee; if (!e->inline_failed) clone_inlined_nodes (e, duplicate, update_original, overall_size, freq_scale); + } +} + +/* Check all speculations in N and resolve them if they seems useless. */ + +static bool +check_speculations (cgraph_node *n) +{ + bool speculation_removed = false; + cgraph_edge *next; + + for (cgraph_edge *e = n->callees; e; e = next) + { + next = e->next_callee; if (e->speculative && !speculation_useful_p (e, true)) { e->resolve_speculation (NULL); speculation_removed = true; } + else if (!e->inline_failed) + speculation_removed |= check_speculations (e->callee); } + return speculation_removed; } /* Mark all call graph edges coming out of NODE and all nodes that have been @@ -310,7 +326,6 @@ inline_call (struct cgraph_edge *e, bool bool predicated = inline_edge_summary (e)->predicate != NULL; #endif - speculation_removed = false; /* Don't inline inlined edges. */ gcc_assert (e->inline_failed); /* Don't even think of inlining inline clone. */ @@ -360,6 +375,7 @@ inline_call (struct cgraph_edge *e, bool mark_all_inlined_calls_cdtor (e->callee); if (opt_for_fn (e->caller->decl, optimize)) new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges); + check_speculations (e->callee); if (update_overall_summary) inline_update_overall_summary (to); new_size = inline_summaries->get (to)->size; Index: ipa-prop.c =================================================================== --- ipa-prop.c (revision 222016) +++ ipa-prop.c (working copy) @@ -2626,9 +2626,29 @@ ipa_make_edge_direct_to_target (struct c target = canonicalize_constructor_val (target, NULL); if (!target || TREE_CODE (target) != FUNCTION_DECL) { - if (ie->indirect_info->member_ptr) - /* Member pointer call that goes through a VMT lookup. */ - return NULL; + /* Member pointer call that goes through a VMT lookup. */ + if (ie->indirect_info->member_ptr + /* Or if target is not an invariant expression and we do not + know if it will evaulate to function at runtime. + This can happen when folding through &VAR, where &VAR + is IP invariant, but VAR itself is not. + + TODO: Revisit this when GCC 5 is branched. It seems that + member_ptr check is not needed and that we may try to fold + the expression and see if VAR is readonly. */ + || !is_gimple_ip_invariant (target)) + { + if (dump_enabled_p ()) + { + location_t loc = gimple_location_safe (ie->call_stmt); + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, + "discovered direct call non-invariant " + "%s/%i\n", + ie->caller->name (), ie->caller->order); + } + return NULL; + } + if (dump_enabled_p ()) {