This is an archive of the discontinued LLVM Phabricator instance.

[SCEV] By more careful when traversing phis in isImpliedViaMerge.
ClosedPublic

Authored by fhahn on May 4 2021, 5:23 AM.

Details

Summary

I think currently isImpliedViaMerge can incorrectly return true for phis
in a loop/cycle, if the found condition involves the previous value of

Consider the case in exit_cond_depends_on_inner_loop.

At some point, we call (modulo simplifications)
isImpliedViaMerge(<=, %x.lcssa, -1, %call, -1).

The existing code tries to prove IncV <= -1 for all incoming values
InvV using the found condition (%call <= -1). At the moment this succeeds,
but only because it does not compare the same runtime value. The found
condition checks the value of the last iteration, but the incoming value
is from the *previous* iteration.

Hence we incorrectly determine that the *previous* value was <= -1,
which may not be true.

I think we need to be more careful when looking at the incoming values
here. In particular, we need to rule out that a found condition refers to
any value that may refer to one of the previous iterations. I'm not sure
there's a reliable way to do so (that also works of irreducible control
flow).

So for now this patch adds an additional requirement that the incoming
value must properly dominate the phi block. This should ensure the
values do not change in a cycle. I am not entirely sure if will catch
all cases and I appreciate a through second look in that regard.

Alternatively we could also unconditionally bail out in this case,
instead of checking the incoming values

Diff Detail

Event Timeline

fhahn created this revision.May 4 2021, 5:23 AM
fhahn requested review of this revision.May 4 2021, 5:23 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 4 2021, 5:23 AM

I'm confused.

On this example:
inner:

%x = phi i32 [ -1, %outer.header ], [ %call, %inner ]
%call = call i32 @match()
%inner.cond = icmp sgt i32 %call, -1
br i1 %inner.cond, label %inner, label %outer.exiting.1

outer.exiting.1:

%x.lcssa = phi i32 [ %x, %inner ]

The value of %x *is* always signed less than or equal to -1. On the last iteration, %call might not be, but the value used in the x.lcssa is the value of the phi, not of the call. Thus, concluding that %x.lcssa <=s -1 seems entirely correct?

fhahn added a comment.May 5 2021, 1:08 PM

I'm confused.

On this example:
inner:

%x = phi i32 [ -1, %outer.header ], [ %call, %inner ]
%call = call i32 @match()
%inner.cond = icmp sgt i32 %call, -1
br i1 %inner.cond, label %inner, label %outer.exiting.1

outer.exiting.1:

%x.lcssa = phi i32 [ %x, %inner ]

The value of %x *is* always signed less than or equal to -1. On the last iteration, %call might not be, but the value used in the x.lcssa is the value of the phi, not of the call. Thus, concluding that %x.lcssa <=s -1 seems entirely correct?

I might be glancing over something, but aren't we continuing the loop if %call >s -1 and exit if `call <=s -1?

So in the iteration before we exit, %call >s -1, hence %x >s -1 in the last iteration. In the last iteration, %call <=s -1, but %x still has the value from the previous iteration.

reames added a comment.May 5 2021, 1:17 PM

I might be glancing over something, but aren't we continuing the loop if %call >s -1 and exit if `call <=s -1?

No, you're entirely correct. I'd swapped the branch order in my head when reading.

So in the iteration before we exit, %call >s -1, hence %x >s -1 in the last iteration. In the last iteration, %call <=s -1, but %x still has the value from the previous iteration.

There are two sub-cases here:

  1. Exit on the first iteration - %x will be -1 (e.g. value on entry).
  2. Exit on second or further iteration - %x will be >s -1. (e.g. value on backedge, last iteration value of call)

We can correctly conclude that x >=s -1, but not x >s -1. Which I think was your original point right? Sorry for the confusion.

fhahn added a comment.May 5 2021, 1:46 PM

I might be glancing over something, but aren't we continuing the loop if %call >s -1 and exit if `call <=s -1?

No, you're entirely correct. I'd swapped the branch order in my head when reading.

So in the iteration before we exit, %call >s -1, hence %x >s -1 in the last iteration. In the last iteration, %call <=s -1, but %x still has the value from the previous iteration.

There are two sub-cases here:

  1. Exit on the first iteration - %x will be -1 (e.g. value on entry).
  2. Exit on second or further iteration - %x will be >s -1. (e.g. value on backedge, last iteration value of call)

We can correctly conclude that x >=s -1, but not x >s -1. Which I think was your original point right? Sorry for the confusion.

Yes I think that matches my understanding of the issue. Plus we cannot conclude that x >s -1 is always false, which happens for the test case IIUC.

nikic added a comment.May 5 2021, 2:20 PM

What BasicAA does for this case is a CFG reachability check from the phi to the value. If it's reachable, you have some kind of cycle. I think what you're doing here is fine though, as this doesn't seem like a terribly important optimization to me, and the nature of SCEV makes those properlyDominates() checks likely to succeed for common cases (as non-SCEVUnknown expressions are effectively hoisted).

fhahn added a comment.May 6 2021, 1:21 PM

What BasicAA does for this case is a CFG reachability check from the phi to the value. If it's reachable, you have some kind of cycle. I think what you're doing here is fine though, as this doesn't seem like a terribly important optimization to me, and the nature of SCEV makes those properlyDominates() checks likely to succeed for common cases (as non-SCEVUnknown expressions are effectively hoisted).

I think we should start out with a relatively simple/safe fix and go from there. The impact of the code seems relatively small, e.g. if unconditionally bail out in this case, ~2 benchmarks out of SPEC2000/SPEC2006/MultiSource have minor binary changes.

nikic accepted this revision.May 6 2021, 1:45 PM

I agree, so this LGTM.

This revision is now accepted and ready to land.May 6 2021, 1:45 PM
reames added a comment.May 7 2021, 9:42 AM

LGTM to me too for the record.

This revision was landed with ongoing or failed builds.May 7 2021, 11:53 AM
This revision was automatically updated to reflect the committed changes.