https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124291
--- Comment #12 from Martin Jambor <jamborm at gcc dot gnu.org> ---
Looking at the dump attached in comment #4, I think I know what is
happening.
Similarly to PR123629, the issue again stems from that when propagating
polymorphic contexts, when there are no known "values" in the corresponding
lattice of the caller we use just the information on the edge and when
there are some we combine them with the information, and from the fact that
we iterate the propagation in strongly connected components of the call
graph (SCCs).
In the first iteration over such SCC, we process the edge from
unmark/1097720 to onChild/1097719 before we determined the lattices of the
caller. In the second iteration, we already know what context there will
be in the first unmarks's parameter and so can add a more precise value to
the corresponding lattice of onChild. Because we always add values to the
lattices and never "improve" them, we get two values for the call.
In PR123629, that actually described reality well because the caller's
lattice had the variable flag set, without cloning the caller we could not
assume we could use the caller's lattice value and so both values were
possible (and in fact both cases happened, the problem was that their meet
failed).
In this case however, one could argue that the lattices contain wrong info
or at least information that is misleading because the caller's lattice
contains just that single "constant" and the variable flag is not set. We
know that regardless of cloning decisions for the caller the more precise
derived value will be the case. And indeed since I changed the cloning
code to re-gather all constants for the given set of callers, that code
arrives at the more precise context. For the record they only differ in
the fact that the more precise one has the dynamic flag cleared.
I have thought about how to fix up the lattices in one way or another but
so far it has always turned ugly. Now I am inclined to simply allow this
situation in the verifier because the final result is just a bit more
precise than what was expected, it is however correct. There will not be
any attempt to clone for the more precise context because all the call
graph edges will have been redirected away. The only "issue" is that the
less precise contexts take up place in the lattice, which has a limited
length. But I don't think that is a problem in practice.
Too bad I cannot reproduce the ICE myself, I would have tried the
following:
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index b4e01a92344..4765ef972b9 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -5920,11 +5920,19 @@ ipcp_val_replacement_ok_p (vec<tree> &,
int index, HOST_WIDE_INT offset,
ipa_polymorphic_call_context value)
{
- if (offset != -1)
+ if (offset != -1
+ || known_contexts.length () <= (unsigned) index
+ || known_contexts[index].useless_p ())
return false;
- return (known_contexts.length () > (unsigned) index
- && !known_contexts[index].useless_p ()
- && known_contexts[index].equal_to (value));
+
+ if (known_contexts[index].equal_to (value))
+ return true;
+
+ /* In some corner cases, the final gathering of contexts can figure out that
+ the available context is actually more precise than what we wanted to
+ clone for. Allow it. */
+ value.combine_with (known_contexts[index]);
+ return known_contexts[index].equal_to (value);
}
/* Decide whether to create a special version of NODE for value VAL of