ipa-prop: Fix multiple-target speculation resolution

As the FIXME which this patch removes states, the current code does
not work when a call with multiple speculative targets gets resolved
through parameter tracking during inlining - it feeds the inliner an
edge it has already dealt with.  The patch makes the code which should
prevent it aware of the possibility that that speculation can have
more than one target now.

gcc/ChangeLog:

2020-09-30  Martin Jambor  <mjambor@suse.cz>

	PR ipa/96394
	* ipa-prop.c (update_indirect_edges_after_inlining): Do not add
	resolved speculation edges to vector of new direct edges even in
	presence of multiple speculative direct edges for a single call.

gcc/testsuite/ChangeLog:

2020-09-30  Martin Jambor  <mjambor@suse.cz>

	PR ipa/96394
	* gcc.dg/tree-prof/pr96394.c: New test.
This commit is contained in:
Martin Jambor 2020-10-07 14:12:49 +02:00
parent 99e9b54313
commit e089e43365
2 changed files with 70 additions and 4 deletions

View File

@ -3787,11 +3787,13 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
param_index = ici->param_index;
jfunc = ipa_get_ith_jump_func (top, param_index);
cgraph_node *spec_target = NULL;
/* FIXME: This may need updating for multiple calls. */
auto_vec<cgraph_node *, 4> spec_targets;
if (ie->speculative)
spec_target = ie->first_speculative_call_target ()->callee;
for (cgraph_edge *direct = ie->first_speculative_call_target ();
direct;
direct = direct->next_speculative_call_target ())
spec_targets.safe_push (direct->callee);
if (!opt_for_fn (node->decl, flag_indirect_inlining))
new_direct_edge = NULL;
@ -3814,7 +3816,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
/* If speculation was removed, then we need to do nothing. */
if (new_direct_edge && new_direct_edge != ie
&& new_direct_edge->callee == spec_target)
&& spec_targets.contains (new_direct_edge->callee))
{
new_direct_edge->indirect_inlining_edge = 1;
top = IPA_EDGE_REF (cs);

View File

@ -0,0 +1,64 @@
/* PR ipa/96394 */
/* { dg-options "-O2" } */
typedef struct _entry {
int has_next;
int next_ix;
int count;
} entry;
extern entry table[];
void *
__attribute__((noipa))
PyErr_Format(entry * e){ return 0; }
void ae(entry *);
int h(entry *);
int ap(entry *);
int ag(entry *);
int ag(entry *j) {
if (j->has_next)
h(&table[j->next_ix]);
return 0;
}
static int ai(entry *j, int k(entry *), int l, int m) {
int am = 1;
int ab;
/* k is either 'h' or 'ap': 50%/50% */
ab = k(j);
/* loop never gets executed on real data */
for (; j->count >= 2; am += 2)
if (l) {
entry *i = &table[am + m];
PyErr_Format(i);
}
return ab;
}
void
__attribute__((noipa))
bug() {
h(table);
h(table);
}
int h(entry *j) { return ai(j, ap, 4, 5); }
int ap(entry *j) { return ai(j, ag, 14, 4); }
int main(void)
{
bug();
}
entry table[2] = {
{ .has_next = 1
, .next_ix = 1
, .count = 0
},
{ .has_next = 0
, .next_ix = 0
, .count = 0
},
};