This is an archive of the discontinued LLVM Phabricator instance.

[LoopRotate] Forget SCEV values in RewriteUsesOfClonedInstructions
ClosedPublic

Authored by bjope on Sep 30 2021, 4:15 AM.

Details

Summary

This patch fixes problems reported in PR51981.

When rotating a loop it isn't enough to just forget SCEV for that
loop nest. When rotating we might clone some instructions from the
old header into the preheader, and insert new PHI nodes to merge
values together. There could be users of the original value that are
updated to use the PHI result. And those users were not necessarily
depending on a PHI node earlier, so they weren't cleaned up when just
forgetting all SCEV:s for the loop nest. So we need to explicitly
forget those values to avoid invalid cached SCEV expressions.

Diff Detail

Event Timeline

bjope created this revision.Sep 30 2021, 4:15 AM
bjope requested review of this revision.Sep 30 2021, 4:15 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 30 2021, 4:15 AM
bjope added a comment.Sep 30 2021, 4:18 AM

Notice that I feel a bit "on deep water" here. Is the patch (and the description in the commit msg) making sense?

Btw, I'm not sure if this is enough to keep ScalarEvolution valid throughout LoopRotate. There is for example a comment on line 769 that says "I don't believe this invalidates SCEV." that looks a bit fearsome.

bjope added inline comments.Sep 30 2021, 4:21 AM
llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
837

I think that at least SE could be made a reference instead of a pointer here. At least loop-rotate always fetches ScalarEvolution nowadays (but probably also DominatorTree).
So we could get rid of the conditional checks if SE is non-null.

Maybe I'll fix that in a separate patch later. Unless someone beats me to it.

When rotating a loop it isn't enough to just forget SCEV for that loop nest.

I think this analysis is correct; the expression for phi that's now outside the loop won't be cleared by forgetting the loop

Btw, I'm not sure if this is enough to keep ScalarEvolution valid throughout LoopRotate. There is for example a comment on line 769 that says "I don't believe this invalidates SCEV." that looks a bit fearsome.

There are probably still other issue lurking unfortunately, same as in other parts of the codebase.

llvm/lib/Transforms/Utils/LoopRotationUtils.cpp
837

Sounds like a good cleanup!

It looks like the crash/differences may be caused by stale entries in the loop disposition cache. Are those caught by the checks in D110385?

bjope updated this revision to Diff 377497.Oct 6 2021, 4:02 AM

Rebased after modifications in D110812.

bjope added a comment.Oct 6 2021, 7:41 AM

It looks like the crash/differences may be caused by stale entries in the loop disposition cache. Are those caught by the checks in D110385?

Yep. I've downloaded D110385, and used verify<scalar-evolution> after loop-rotate instead of print<scalar-evolution>. Then I see this:

Cached block disposition of SCEV (trunc i32 %wide to i16) for basic block: 
loop.inner:                                       ; preds = %loop.inner, %loop.inner.ph
  %iv = phi i16 [ %narrow, %loop.inner.ph ], [ %iv.plus, %loop.inner ]
  %iv.promoted = zext i16 %iv to i32
  %gep = getelementptr inbounds [11263 x i32], [11263 x i32]* @array, i32 0, i32 %iv.promoted
  store i32 7, i32* %gep, align 1
  %iv.plus = add i16 %iv, 1
  %cmp = icmp ult i16 %iv.plus, 700
  br i1 %cmp, label %loop.inner, label %loop.outer.latch
 has changed!
Cached: 2
Actual: 0
bjope added a comment.Oct 6 2021, 7:52 AM

It looks like the crash/differences may be caused by stale entries in the loop disposition cache. Are those caught by the checks in D110385?

Yep. I've downloaded D110385, and used verify<scalar-evolution> after loop-rotate instead of print<scalar-evolution>. Then I see this:

Cached block disposition of SCEV (trunc i32 %wide to i16) for basic block: 
loop.inner:                                       ; preds = %loop.inner, %loop.inner.ph
  %iv = phi i16 [ %narrow, %loop.inner.ph ], [ %iv.plus, %loop.inner ]
  %iv.promoted = zext i16 %iv to i32
  %gep = getelementptr inbounds [11263 x i32], [11263 x i32]* @array, i32 0, i32 %iv.promoted
  store i32 7, i32* %gep, align 1
  %iv.plus = add i16 %iv, 1
  %cmp = icmp ult i16 %iv.plus, 700
  br i1 %cmp, label %loop.inner, label %loop.outer.latch
 has changed!
Cached: 2
Actual: 0

But only for the RUN-lines that uses print<scalar-evolution> before loop-rotate. When using loop(canon-freeze) I get the same kind of crash in the verifier as when using the print pass.

mkazantsev accepted this revision.Oct 7 2021, 4:33 AM

That's exactly the kind of things I'm hunting. Thanks!
There might be more of this type. It would be nice if we could somehow find and fix them.

This revision is now accepted and ready to land.Oct 7 2021, 4:33 AM
fhahn accepted this revision.Oct 7 2021, 4:43 AM

That's exactly the kind of things I'm hunting. Thanks!
There might be more of this type. It would be nice if we could somehow find and fix them.

Great to see issues like this being caught by the verification!

It looks like the crash/differences may be caused by stale entries in the loop disposition cache. Are those caught by the checks in D110385?

Yep. I've downloaded D110385, and used verify<scalar-evolution> after loop-rotate instead of print<scalar-evolution>. Then I see this:

Cached block disposition of SCEV (trunc i32 %wide to i16) for basic block: 
loop.inner:                                       ; preds = %loop.inner, %loop.inner.ph
  %iv = phi i16 [ %narrow, %loop.inner.ph ], [ %iv.plus, %loop.inner ]
  %iv.promoted = zext i16 %iv to i32
  %gep = getelementptr inbounds [11263 x i32], [11263 x i32]* @array, i32 0, i32 %iv.promoted
  store i32 7, i32* %gep, align 1
  %iv.plus = add i16 %iv, 1
  %cmp = icmp ult i16 %iv.plus, 700
  br i1 %cmp, label %loop.inner, label %loop.outer.latch
 has changed!
Cached: 2
Actual: 0

But only for the RUN-lines that uses print<scalar-evolution> before loop-rotate. When using loop(canon-freeze) I get the same kind of crash in the verifier as when using the print pass.

Thanks for checking!

LGTM!

That's exactly the kind of things I'm hunting. Thanks!
There might be more of this type. It would be nice if we could somehow find and fix them.

Great to see issues like this being caught by the verification!

I'm glad someone can do it, because I'm trying to investigate a bug where verification dies before it can find the bug because of dangling pointers. :)

I've updated verifier patch and added this one as unit test for verifier. I hope you don't mind @bjope. :)

This revision was landed with ongoing or failed builds.Oct 7 2021, 10:56 AM
This revision was automatically updated to reflect the committed changes.