diff options
author | Alexander Shaposhnikov <ashaposhnikov@google.com> | 2022-05-17 21:30:44 +0000 |
---|---|---|
committer | Alexander Shaposhnikov <ashaposhnikov@google.com> | 2022-05-17 22:06:03 +0000 |
commit | 0f4d9f9b71be8a95cd24534bf914fc9a6fb0ff30 (patch) | |
tree | 51524f0afeaeecc61e3c99ef2a4767a91d5a9bcc /llvm | |
parent | c907d6e0e9fd8fafd49e4d0f9e584f58bbac5ead (diff) | |
download | llvm-0f4d9f9b71be8a95cd24534bf914fc9a6fb0ff30.zip llvm-0f4d9f9b71be8a95cd24534bf914fc9a6fb0ff30.tar.gz llvm-0f4d9f9b71be8a95cd24534bf914fc9a6fb0ff30.tar.bz2 |
[ConstantRange] Improve the implementation of binaryAnd
This diff adjusts binaryAnd to take advantage of the analysis
based on KnownBits.
Differential revision: https://reviews.llvm.org/D125603
Test plan:
1/ ninja check-llvm
2/ ninja check-llvm-unit
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 20 | ||||
-rw-r--r-- | llvm/test/Transforms/SCCP/range-and.ll | 4 | ||||
-rw-r--r-- | llvm/unittests/IR/ConstantRangeTest.cpp | 32 |
3 files changed, 42 insertions, 14 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index ce2e537..fb44ca9 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -1386,23 +1386,19 @@ ConstantRange ConstantRange::binaryNot() const { return ConstantRange(APInt::getAllOnes(getBitWidth())).sub(*this); } -ConstantRange -ConstantRange::binaryAnd(const ConstantRange &Other) const { +ConstantRange ConstantRange::binaryAnd(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); - // Use APInt's implementation of AND for single element ranges. - if (isSingleElement() && Other.isSingleElement()) - return {*getSingleElement() & *Other.getSingleElement()}; - - // TODO: replace this with something less conservative - - APInt umin = APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()); - return getNonEmpty(APInt::getZero(getBitWidth()), std::move(umin) + 1); + ConstantRange KnownBitsRange = + fromKnownBits(toKnownBits() & Other.toKnownBits(), false); + ConstantRange UMinUMaxRange = + getNonEmpty(APInt::getZero(getBitWidth()), + APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()) + 1); + return KnownBitsRange.intersectWith(UMinUMaxRange); } -ConstantRange -ConstantRange::binaryOr(const ConstantRange &Other) const { +ConstantRange ConstantRange::binaryOr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); diff --git a/llvm/test/Transforms/SCCP/range-and.ll b/llvm/test/Transforms/SCCP/range-and.ll index 2dd6231..ef8758f 100644 --- a/llvm/test/Transforms/SCCP/range-and.ll +++ b/llvm/test/Transforms/SCCP/range-and.ll @@ -140,7 +140,7 @@ define i64 @constant_range_and_255_100(i1 %cond, i64 %a) { ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R_1]], [[BB1]] ], [ [[R_2]], [[BB2]] ] -; CHECK-NEXT: [[P_AND:%.*]] = and i64 [[P]], 512 +; CHECK-NEXT: [[P_AND:%.*]] = and i64 [[P]], 255 ; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: ret i64 [[P_AND]] ; @@ -157,7 +157,7 @@ bb2: bb3: %p = phi i64 [ %r.1, %bb1 ], [ %r.2, %bb2 ] - %p.and = and i64 %p, 512 + %p.and = and i64 %p, 255 %c = icmp ult i64 %p.and, 256 call void @use(i1 %c) ret i64 %p.and diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 02f8b46..ffd0f00 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -2528,6 +2528,38 @@ TEST_F(ConstantRangeTest, castOps) { EXPECT_TRUE(IntToPtr.isFullSet()); } +TEST_F(ConstantRangeTest, binaryAnd) { + // Single element ranges. + ConstantRange R16(APInt(8, 16)); + ConstantRange R20(APInt(8, 20)); + EXPECT_EQ(*R16.binaryAnd(R16).getSingleElement(), APInt(8, 16)); + EXPECT_EQ(*R16.binaryAnd(R20).getSingleElement(), APInt(8, 16 & 20)); + + ConstantRange R16_32(APInt(8, 16), APInt(8, 32)); + // 'And' with a high bits mask. + ConstantRange R32(APInt(8, 32)); + EXPECT_TRUE(R16_32.binaryAnd(R32).getSingleElement()->isZero()); + EXPECT_TRUE(R32.binaryAnd(R16_32).getSingleElement()->isZero()); + // 'And' with a low bits mask. Handled conservatively for now. + ConstantRange R4(APInt(8, 4)); + ConstantRange R0_5(APInt(8, 0), APInt(8, 5)); + EXPECT_EQ(R16_32.binaryAnd(R4), R0_5); + EXPECT_EQ(R4.binaryAnd(R16_32), R0_5); + + // Ranges with more than one element. Handled conservatively for now. + ConstantRange R0_99(APInt(8, 0), APInt(8, 99)); + ConstantRange R0_32(APInt(8, 0), APInt(8, 32)); + EXPECT_EQ(R16_32.binaryAnd(R0_99), R0_32); + EXPECT_EQ(R0_99.binaryAnd(R16_32), R0_32); + + TestBinaryOpExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.binaryAnd(CR2); + }, + [](const APInt &N1, const APInt &N2) { return N1 & N2; }, PreferSmallest, + CheckSingleElementsOnly); +} + TEST_F(ConstantRangeTest, binaryXor) { // Single element ranges. ConstantRange R16(APInt(8, 16)); |