This is an archive of the discontinued LLVM Phabricator instance.

Fix a type mismatch assert in SCEV division
ClosedPublic

Authored by bcahoon on Apr 14 2015, 1:35 PM.

Details

Summary

An assert was triggered when attempting to create a new SCEV with operands of different types in the visitAddRecExpr. In this test case, the operand types of the numerator and denominator are different. The SCEV division code should generate a conservative answer when this happens.

This patch depends on reviews.llvm.org/D9003.

Diff Detail

Repository
rL LLVM

Event Timeline

bcahoon updated this revision to Diff 23742.Apr 14 2015, 1:35 PM
bcahoon retitled this revision from to Fix a type mismatch assert in SCEV division.
bcahoon updated this object.
bcahoon edited the test plan for this revision. (Show Details)
bcahoon added reviewers: apazos, sebpop.
bcahoon set the repository for this revision to rL LLVM.
bcahoon added a subscriber: Unknown Object (MLST).
sanjoy added a subscriber: sanjoy.Apr 14 2015, 2:54 PM

How do we end up in a situation where the numerator and denominator have different types? I don't think dividing differently typed SCEV expressions should be a valid operation.

In the test case, the numerator ({0,+,(zext i16 %0 to i32)}<nw><%for.cond7.preheader>) is i32 and the denominator (%0) is i16. The second divide() call generates a value with type i32 for StepR (the remainder value for the Step). The types for the values returned by the first divide() call, StartQ and StartR, are both i16.

I think you're suggesting that the check for the type mismatch occur before the calls to divide() in visitAddRecExpr? That seems reasonable.

sanjoy accepted this revision.Apr 15 2015, 6:42 PM
sanjoy added a reviewer: sanjoy.

In the test case, the numerator ({0,+,(zext i16 %0 to i32)}<nw><%for.cond7.preheader>) is i32 and the denominator (%0) is i16. The second divide() call generates a value with type i32 for StepR (the remainder value for the Step). The types for the values returned by the first divide() call, StartQ and StartR, are both i16.

I think you're suggesting that the check for the type mismatch occur before the calls to divide() in visitAddRecExpr? That seems reasonable.

I was initially suggesting that SCEV should not be attempting to divide integers of different bit-widths, and it should be up to the caller to sext or zext as needed. But visitConstant clearly tries to do something for differing bit-widths so that assumption was flawed. Therefore I think this change is okay as it is.

It might be helpful to explicitly document that SCEVDivision::divide sign extends the narrower integer to the width of the wider integer before division. Is it correct to state that invariant here is that if SCEVDivision::divide returns Q and R after dividing N by D then sext_if_needed(N) == sext_if_needed(Q) * sext_if_needed(D) + sext_if_needed(R) where sext_if_needed sign extends to the widest of widths of N and R? If so, it'll be helpful to document that too.

This revision is now accepted and ready to land.Apr 15 2015, 6:42 PM

Hi Sanjoy - thanks for the review and comments. I appreciate the feedback.

It might be helpful to explicitly document that SCEVDivision::divide sign extends the narrower integer to the width of the wider integer before division. Is it correct to state that invariant here is that if SCEVDivision::divide returns Q and R after dividing N by D then sext_if_needed(N) == sext_if_needed(Q) * sext_if_needed(D) + sext_if_needed(R) where sext_if_needed sign extends to the widest of widths of N and R? If so, it'll be helpful to document that too.

I'm also curious if the the invariant you state above is true in all cases. Clearly, it is assumed in some cases, for example, in visitConstant, as you mention. If so, it should be possible to explicitly sign extend when needed, and then remove the various checks for a type mismatch in the visitor functions. This could help generate more precise results.

This revision was automatically updated to reflect the committed changes.