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 ())
{