Skip to content

Commit 6990e74

Browse files
[ConstantRange] Improve the implementation of binaryOr
This diff adjusts binaryOr to take advantage of the analysis based on KnownBits. Differential revision: https://reviews.llvm.org/D125933 Test plan: 1/ ninja check-llvm 2/ ninja check-llvm-unit
1 parent 221b7a4 commit 6990e74

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

llvm/lib/IR/ConstantRange.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,14 +1410,13 @@ ConstantRange ConstantRange::binaryOr(const ConstantRange &Other) const {
14101410
if (isEmptySet() || Other.isEmptySet())
14111411
return getEmpty();
14121412

1413-
// Use APInt's implementation of OR for single element ranges.
1414-
if (isSingleElement() && Other.isSingleElement())
1415-
return {*getSingleElement() | *Other.getSingleElement()};
1416-
1417-
// TODO: replace this with something less conservative
1418-
1419-
APInt umax = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin());
1420-
return getNonEmpty(std::move(umax), APInt::getZero(getBitWidth()));
1413+
ConstantRange KnownBitsRange =
1414+
fromKnownBits(toKnownBits() | Other.toKnownBits(), false);
1415+
// Upper wrapped range.
1416+
ConstantRange UMaxUMinRange =
1417+
getNonEmpty(APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()),
1418+
APInt::getZero(getBitWidth()));
1419+
return KnownBitsRange.intersectWith(UMaxUMinRange);
14211420
}
14221421

14231422
ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const {

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2560,6 +2560,44 @@ TEST_F(ConstantRangeTest, binaryAnd) {
25602560
CheckSingleElementsOnly);
25612561
}
25622562

2563+
TEST_F(ConstantRangeTest, binaryOr) {
2564+
// Single element ranges.
2565+
ConstantRange R16(APInt(8, 16));
2566+
ConstantRange R20(APInt(8, 20));
2567+
EXPECT_EQ(*R16.binaryOr(R16).getSingleElement(), APInt(8, 16));
2568+
EXPECT_EQ(*R16.binaryOr(R20).getSingleElement(), APInt(8, 16 | 20));
2569+
2570+
ConstantRange R16_32(APInt(8, 16), APInt(8, 32));
2571+
// 'Or' with a high bits mask.
2572+
// KnownBits estimate is important, otherwise the maximum included element
2573+
// would be 2^8 - 1.
2574+
ConstantRange R32(APInt(8, 32));
2575+
ConstantRange R48_64(APInt(8, 48), APInt(8, 64));
2576+
EXPECT_EQ(R16_32.binaryOr(R32), R48_64);
2577+
EXPECT_EQ(R32.binaryOr(R16_32), R48_64);
2578+
// 'Or' with a low bits mask.
2579+
ConstantRange R4(APInt(8, 4));
2580+
ConstantRange R0_16(APInt(8, 0), APInt(8, 16));
2581+
ConstantRange R4_16(APInt(8, 4), APInt(8, 16));
2582+
EXPECT_EQ(R0_16.binaryOr(R4), R4_16);
2583+
EXPECT_EQ(R4.binaryOr(R0_16), R4_16);
2584+
2585+
// Ranges with more than one element. Handled conservatively for now.
2586+
// UMaxUMin estimate is important, otherwise the lower bound would be zero.
2587+
ConstantRange R0_64(APInt(8, 0), APInt(8, 64));
2588+
ConstantRange R5_32(APInt(8, 5), APInt(8, 32));
2589+
ConstantRange R5_64(APInt(8, 5), APInt(8, 64));
2590+
EXPECT_EQ(R0_64.binaryOr(R5_32), R5_64);
2591+
EXPECT_EQ(R5_32.binaryOr(R0_64), R5_64);
2592+
2593+
TestBinaryOpExhaustive(
2594+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
2595+
return CR1.binaryOr(CR2);
2596+
},
2597+
[](const APInt &N1, const APInt &N2) { return N1 | N2; }, PreferSmallest,
2598+
CheckSingleElementsOnly);
2599+
}
2600+
25632601
TEST_F(ConstantRangeTest, binaryXor) {
25642602
// Single element ranges.
25652603
ConstantRange R16(APInt(8, 16));

0 commit comments

Comments
 (0)