This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] Don't invalidate past dependency-breaking instructions
ClosedPublic

Authored by nikic on Apr 27 2023, 1:16 AM.

Details

Summary

When invalidating a value, we walk all users of that value and invalidate them as well. This can be very expensive for large use graphs.

However, we only need to invalidate a user U of instruction I if SCEV(U) can depend on SCEV(I). This is not the case if U is an instruction that always produces a SCEVUnknown, such as a load. If the load pointer operand is invalidated, there is no need to invalidate the load result, which is completely unrelated from a SCEV perspective.

This is a decent compile-time improvement in some cases: http://llvm-compile-time-tracker.com/compare.php?from=da4fcb0c0b281746067f92d8804c18dbce4269bd&to=3d7d37d4cc0118af994c70037753358868f25147&stat=instructions:u

Diff Detail

Event Timeline

nikic created this revision.Apr 27 2023, 1:16 AM
nikic requested review of this revision.Apr 27 2023, 1:16 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 27 2023, 1:16 AM

Consider example:

%sum = add i32 %x, %y
%load_p= gep ptr %p, i32 %sum
%load1 = load %i32 load_p

if (%load_1 == %sum) {
  %load_2 = load %i32 load_p
  %sum_2 = add i32 %load_2, 2
}

Here we can theoretically prove that SCEV for %load_2 is %x + %y (same as %sum) and %sum2 = %x + %y + 1.

Now, imagine that we invalidate %x. With your patch, if I understand it correctly, %sum_2 won't be invalidated.

nikic added a comment.Apr 28 2023, 1:38 AM

Consider example:

%sum = add i32 %x, %y
%load_p= gep ptr %p, i32 %sum
%load1 = load %i32 load_p

if (%load_1 == %sum) {
  %load_2 = load %i32 load_p
  %sum_2 = add i32 %load_2, 2
}

Here we can theoretically prove that SCEV for %load_2 is %x + %y (same as %sum) and %sum2 = %x + %y + 1.

Now, imagine that we invalidate %x. With your patch, if I understand it correctly, %sum_2 won't be invalidated.

Not sure I get the example. %load1 and %load_2 will both always be SCEVUnknown (loads always are, if they are SCEVable at all). The %x + %y is part of the load address, but it doesn't impact the SCEV of the load itself. It's part of %load_p, but that one will continue to be invalidated normally.

mkazantsev added a comment.EditedApr 28 2023, 2:30 AM

If we prove that two values are the same, their SCEVs can also be proven the same (and not necessarity SCEVUnknown). If a load is equal to some non-load. then load's SCEV can be non-SCEVUnknown.

nikic added a comment.Apr 28 2023, 3:25 AM

If we prove that two values are the same, their SCEVs can also be proven the same (and not necessarity SCEVUnknown). If a load is equal to some non-load. then load's SCEV can be non-SCEVUnknown.

I think your example is a bit confusing because it uses %sum both in the load address and the comparison. Let's consider this variant where %v and %load1 are only related by the comparison:

%load1 = load i32, ptr %p
if (%load1 == %v) {
   %load2 = load i32, ptr %p
}

If we determined that getSCEV(%load2) = getSCEV(%v) based on the comparison and memory dependence reasoning here, then invalidating %v would not invalidate %load2 even with the current implementation, because there is no use-def relationship between them. We would have to invalidate based on potential memory dependences, which is not feasible in practice.

While SCEV could in theory do something like this, it doesn't do this currently, and it's very unlikely that it will do so in the future. If it does do so in the future, we can change this code to reflect the new reality...

nikic updated this revision to Diff 517858.Apr 28 2023, 3:33 AM

Add assertion to make sure the assumption about SCEVUnknown is correct.

mkazantsev accepted this revision.Apr 28 2023, 4:07 AM

Ok thanks, at least we'll know if it breaks.

This revision is now accepted and ready to land.Apr 28 2023, 4:07 AM
This revision was landed with ongoing or failed builds.Apr 28 2023, 5:45 AM
This revision was automatically updated to reflect the committed changes.