This is an archive of the discontinued LLVM Phabricator instance.

[ConstantRange] Add unsigned and signed intersection type
ClosedPublic

Authored by nikic on Mar 28 2019, 1:56 PM.

Details

Summary

The intersection of two ConstantRanges may consist of two disjoint ranges. As we can only return one range as the result, we need to return one of the two possible ranges that cover both. Currently the result is picked based on set size. However, this is not always optimal: If we're in an unsigned context, we'd prefer to get a large unsigned range over a small signed range -- the latter effectively becomes a full set in the unsigned domain.

This revision adds an IntersectionType, which can be either Smallest, Unsigned or Signed. Smallest is the current behavior and Unsigned and Signed are new variants that prefer not to wrap the unsigned/signed domain. The new type isn't used anywhere yet (but SCEV will be a good first user).

I've also added some comments to illustrate the various cases in intersectWith(), which should hopefully make it more obvious what is going on.

Diff Detail

Repository
rL LLVM

Event Timeline

nikic created this revision.Mar 28 2019, 1:56 PM
lebedev.ri added inline comments.Mar 28 2019, 3:14 PM
llvm/unittests/IR/ConstantRangeTest.cpp
400 ↗(On Diff #192711)

This looks inconsistent?
"Should have at most *two* ranges" maybe?

nikic marked an inline comment as done.Mar 28 2019, 3:46 PM
nikic added inline comments.
llvm/unittests/IR/ConstantRangeTest.cpp
400 ↗(On Diff #192711)

While the intersection consists of at most two ranges in the sense of potentially wrapping ConstantRanges, if we're using a non-wrapping representation (as is the case in this testing code), then there may be three ranges. An example:

----]    [---]   [----   Two ConstantRanges
[---]    [---]   [---]   Three non-wrapping ranges
nikic updated this revision to Diff 192793.Mar 29 2019, 3:40 AM
nikic retitled this revision from [ConstantRange] Add unsigned intersection type to [ConstantRange] Add unsigned and signed intersection type.
nikic edited the summary of this revision. (Show Details)

Also add signed intersection type. I think that adding both makes the implementation more obvious in this case, as the logic for the range preference is extracted more neatly.

Tests look good, but i wonder if @nlopes might want to show-off some Z3 magic..

lebedev.ri accepted this revision.Apr 6 2019, 7:40 AM

Hmm, yes, GetPreferredRange() did make this more obvious.
I would still prefer to see some Z3 magic, but the tests look reassuring to me.

llvm/include/llvm/IR/ConstantRange.h
255–256 ↗(On Diff #192793)

The or if both possibilities wrap or don't wrap, the smaller set. is applicable for both the Unsigned and Signed IntersectionTypes. Maybe move that phrase to the end, after explaining Unsigned?

This revision is now accepted and ready to land.Apr 6 2019, 7:40 AM
nikic added a comment.Apr 6 2019, 8:17 AM

I think I'd like to make two more changes here: Rename IntersectionType to OperationType or similar, as the Smallest/Unsigned/Signed classification will be useful in other places as well (e.g. it is also directly applicable to unions). Furthermore I'd like to change the enum class to an enum, as I don't think that ConstantRange::OperationType::Smallest adds anything over just ConstantRange::Smallest, beyond being unwieldy.

I think I'd like to make two more changes here: Rename IntersectionType to OperationType or similar, as the Smallest/Unsigned/Signed classification will be useful in other places as well (e.g. it is also directly applicable to unions).

So i agree that IntersectionType will be misleading for other ops. But operation is a bit too generic maybe?
We are saying "please intersect these two ranges, and out of all the intersections (common elements? overlapped elements?, ???), try to pick smallest/one with no wrap/...".
So i wonder if it would be better not to talk about *operation*, but about the result of operation?
How does e.g. DesiredRangeVariant sound?

Furthermore I'd like to change the enum class to an enum, as I don't think that ConstantRange::OperationType::Smallest adds anything over just ConstantRange::Smallest, beyond being unwieldy.

As long as it stays within ConstantRange prefix, i think that could be fine.

nikic added a comment.Apr 6 2019, 8:42 AM

I think I'd like to make two more changes here: Rename IntersectionType to OperationType or similar, as the Smallest/Unsigned/Signed classification will be useful in other places as well (e.g. it is also directly applicable to unions).

So i agree that IntersectionType will be misleading for other ops. But operation is a bit too generic maybe?
We are saying "please intersect these two ranges, and out of all the intersections (common elements? overlapped elements?, ???), try to pick smallest/one with no wrap/...".
So i wonder if it would be better not to talk about *operation*, but about the result of operation?
How does e.g. DesiredRangeVariant sound?

Yes, I agree that it makes more sense to talk about the result here. PreferredRangeType would be another possibility, which matches the terminology in the implementation.

I think I'd like to make two more changes here: Rename IntersectionType to OperationType or similar, as the Smallest/Unsigned/Signed classification will be useful in other places as well (e.g. it is also directly applicable to unions).

So i agree that IntersectionType will be misleading for other ops. But operation is a bit too generic maybe?
We are saying "please intersect these two ranges, and out of all the intersections (common elements? overlapped elements?, ???), try to pick smallest/one with no wrap/...".
So i wonder if it would be better not to talk about *operation*, but about the result of operation?
How does e.g. DesiredRangeVariant sound?

Yes, I agree that it makes more sense to talk about the result here. PreferredRangeType would be another possibility, which matches the terminology in the implementation.

Yes, that also is a good alternative.

nikic updated this revision to Diff 194028.Apr 6 2019, 1:02 PM

Rename IntersectionType to PreferredRangeType, switch to plain enum.

This revision was automatically updated to reflect the committed changes.