This is an archive of the discontinued LLVM Phabricator instance.

[MustExec][LICM] Handle latch being part of an inner cycle (PR57780)
ClosedPublic

Authored by nikic on Sep 20 2022, 5:57 AM.

Details

Summary

The algorithm in allLoopPathsLeadToBlock() does not handle the case where the loop latch is part of the predecessor set correctly: In this case, we may take the backedge and not execute other latch successors. This can happen if the latch is part of an inner cycle.

Fixes https://github.com/llvm/llvm-project/issues/57780.

Diff Detail

Event Timeline

nikic created this revision.Sep 20 2022, 5:57 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 20 2022, 5:57 AM
nikic requested review of this revision.Sep 20 2022, 5:57 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 20 2022, 5:57 AM

I need to think more about this particular one, but my general preference would be "do nothing if there is an irreducible loop". Is it an option here?

nikic updated this revision to Diff 462883.Sep 26 2022, 6:08 AM
nikic retitled this revision from [MustExec][LICM] Handle latch being part of an irreducible cycle (PR57780) to [MustExec][LICM] Handle latch being part of an inner cycle (PR57780).
nikic edited the summary of this revision. (Show Details)

Rebase over additional tests.

nikic added a comment.Sep 26 2022, 6:10 AM

I need to think more about this particular one, but my general preference would be "do nothing if there is an irreducible loop". Is it an option here?

I've given this some more thought, and the irreducible control flow is ultimately not relevant: We only need the latch to be part of an inner cycle. The LICM issue does not reproduce with an inner natural cycle (because we don't hoist instructions from inner loops), but we can see this when testing MustExecute directly.

nikic added a comment.Oct 3 2022, 9:40 AM

To provide some more context here: What the algorithm essentially does is collect all the predecessors in the loop, and then check that this is a closed set, in the sense that all control flow either stays in the set or goes to the target block. If no loops are involved, then this ensures control flow will eventually hit the target block.

Once loops are involved, we can run into two complications:

  1. The issue fixed here: If we have a loop latch in the set, then control flow can escape the set by going to the next loop iteration. However, this "next iteration" distinction gets lost in the current representation, and it looks as if we were staying in the set. This is why the separate check is necessary.
  1. Separate issue not addressed by this patch: Control flow might infinitely loop around an inner cycle and thus never reach the target block. Haven't tried to reproduce this, but I suspect that this may not be handled correctly (for non-mustprogress semantics).
llvm/lib/Analysis/MustExecute.cpp
204

Should this say latch blocks?

Also, predecessors(CurLoop->getHeader() will include non-latch blocks (i.e. predecessors not in the loop). I suppose it doesn't matter in practice as Predecessors only contains loop blocks but it might be possible to include this in the comment somehow?

fhahn accepted this revision.Oct 10 2022, 12:39 PM

LGTM, thanks!

This revision is now accepted and ready to land.Oct 10 2022, 12:39 PM
This revision was landed with ongoing or failed builds.Oct 11 2022, 12:32 AM
This revision was automatically updated to reflect the committed changes.
nikic marked an inline comment as done.