This behavior turns out to be incompatible with ArgPromotion, which can
delete reference edges in distant ancestors of the current SCC. These
reference edges being removed can cause many problems, but the worst
case is when they are part of the lazy in-flight DFS walk forming the
RefSCCs. When this happens we have no really good ways of updating
However, the lazy formation of RefSCCs isn't really the most important
part of the laziness here -- that has to do with walking the functions
themselves -- and isn't essential to maintain. Originally, there were
incremental update algorithms that relied on updates happening
predominantly near the most recent RefSCC formed, but those have been
replaced with ones that have much tighter general case bounds at this
point. So we can simplify the entire analysis by having a single
up-front step that builds all of the RefSCCs in a direct Tarjan walk. We
can even easily replace this with other or better algorithms at will and
with much less confusion now that there is no iterator-based incremental
logic involved. This removes a substantial amount of complexity from LCG
and also gives us an easy way to implement ArgPromote -- we already
support removing edges and doing incremental graph updates. In fact,
updates for removing edges are among the most simple cases.
Another advantage of moving in this direction is that it simplifies
testing the system substantially as we no longer have to worry about
observing and mutating the graph half-way through the RefSCC formation.
We still need a somewhat special iterator for RefSCCs because we want
the iterator to remain stable in the face of graph updates. However,
this now merely involves relative indexing to the current RefSCC's
position in the sequence which isn't too hard.
I've used this in a prototype of a more thorough port of ArgPromotion and it
seems to be working well. That part needs a bit more work though to fully
handle the updates and this seems usefully separable.
Depends on D29277.