Skip to content

Commit 0459273

Browse files
Adar-DaganAdar Dagan
andauthored
[ConstantRange] Expand makeAllowedICmpRegion to use samesign to give tighter range (llvm#174355)
After the addition of samesign then instcombine correctly transforms unsigned greater than to use it if it can prove that value is greater than zero and then removes the assume that allowed it to prove that. For example: ``` define i8 @remove_for_samesign(i8 %x) { %gt = icmp sgt i8 %x, 10 call void @llvm.assume(i1 %gt) %gt.zero = icmp sge i8 %x, 0 call void @llvm.assume(i1 %gt.zero) ret i8 %x } ``` Is optimized to: ``` define i8 @remove_for_samesign(i8 %x) { %gt= icmp samesign ugt i8 [[X:%.*]], 10 call void @llvm.assume(i1 %gt) ret i8 %x } ``` This leads to a wrong range being returned from computeConstantRange because it doesn't look at samesign when constructing a range from assumes, this patch fixes that. --------- Co-authored-by: Adar Dagan <adar.dagan@mobileye.com>
1 parent 9f75001 commit 0459273

5 files changed

Lines changed: 182 additions & 1 deletion

File tree

llvm/include/llvm/IR/ConstantRange.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace llvm {
4141

4242
class MDNode;
4343
class raw_ostream;
44+
class CmpPredicate;
4445
struct KnownBits;
4546

4647
/// This class represents a range of values.
@@ -108,6 +109,13 @@ class [[nodiscard]] ConstantRange {
108109
LLVM_ABI static ConstantRange
109110
makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other);
110111

112+
/// Produce the smallest range such that all values that may satisfy the given
113+
/// predicate with any value contained within Other is contained in the
114+
/// returned range. This overload takes a CmpPredicate, which may carry
115+
/// samesign information for tighter ranges on unsigned predicates.
116+
LLVM_ABI static ConstantRange
117+
makeAllowedICmpRegion(CmpPredicate Pred, const ConstantRange &Other);
118+
111119
/// Produce the largest range such that all values in the returned range
112120
/// satisfy the given predicate with all values contained within Other.
113121
/// Formally, this returns a subset of

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10498,7 +10498,7 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
1049810498
computeConstantRange(Cmp->getOperand(1), /*ForSigned=*/false,
1049910499
SQ.getWithInstruction(I), Depth + 1);
1050010500
CR = CR.intersectWith(
10501-
ConstantRange::makeAllowedICmpRegion(Cmp->getPredicate(), RHS));
10501+
ConstantRange::makeAllowedICmpRegion(Cmp->getCmpPredicate(), RHS));
1050210502
}
1050310503
}
1050410504

llvm/lib/IR/ConstantRange.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/IR/ConstantRange.h"
2424
#include "llvm/ADT/APInt.h"
2525
#include "llvm/Config/llvm-config.h"
26+
#include "llvm/IR/CmpPredicate.h"
2627
#include "llvm/IR/Constants.h"
2728
#include "llvm/IR/InstrTypes.h"
2829
#include "llvm/IR/Instruction.h"
@@ -156,6 +157,15 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
156157
}
157158
}
158159

160+
ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
161+
const ConstantRange &CR) {
162+
ConstantRange Result = makeAllowedICmpRegion(Pred.dropSameSign(), CR);
163+
if (!Pred.hasSameSign())
164+
return Result;
165+
return Result.intersectWith(
166+
makeAllowedICmpRegion(Pred.getPreferredSignedPredicate(), CR));
167+
}
168+
159169
ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
160170
const ConstantRange &CR) {
161171
// Follows from De-Morgan's laws:

llvm/unittests/Analysis/ValueTrackingTest.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3471,6 +3471,110 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
34713471
EXPECT_EQ(10, CR2.getUpper());
34723472
}
34733473

3474+
{
3475+
// Assumptions:
3476+
// * stride >= 5 (unsigned)
3477+
//
3478+
// stride = [5, 0)
3479+
auto M = parseModule(R"(
3480+
declare void @llvm.assume(i1)
3481+
3482+
define i32 @test(i32 %stride) {
3483+
%gt = icmp uge i32 %stride, 5
3484+
call void @llvm.assume(i1 %gt)
3485+
%stride.plus.one = add nsw nuw i32 %stride, 1
3486+
ret i32 %stride.plus.one
3487+
})");
3488+
Function *F = M->getFunction("test");
3489+
3490+
AssumptionCache AC(*F);
3491+
Value *Stride = &*F->arg_begin();
3492+
3493+
Instruction *I = &findInstructionByName(F, "stride.plus.one");
3494+
SimplifyQuery SQ(M->getDataLayout(), /*DT=*/nullptr, &AC, /*CxtI=*/I);
3495+
ConstantRange CR2 = computeConstantRange(Stride, false, SQ);
3496+
EXPECT_EQ(5, CR2.getLower());
3497+
EXPECT_EQ(0, CR2.getUpper());
3498+
}
3499+
3500+
{
3501+
// Assumptions:
3502+
// * stride > 5 (unsigned)
3503+
//
3504+
// stride = [5, 0)
3505+
auto M = parseModule(R"(
3506+
declare void @llvm.assume(i1)
3507+
3508+
define i32 @test(i32 %stride) {
3509+
%gt = icmp ugt i32 %stride, 5
3510+
call void @llvm.assume(i1 %gt)
3511+
%stride.plus.one = add nsw nuw i32 %stride, 1
3512+
ret i32 %stride.plus.one
3513+
})");
3514+
Function *F = M->getFunction("test");
3515+
3516+
AssumptionCache AC(*F);
3517+
Value *Stride = &*F->arg_begin();
3518+
3519+
Instruction *I = &findInstructionByName(F, "stride.plus.one");
3520+
SimplifyQuery SQ(M->getDataLayout(), /*DT=*/nullptr, &AC, /*CxtI=*/I);
3521+
ConstantRange CR2 = computeConstantRange(Stride, false, SQ);
3522+
EXPECT_EQ(6, CR2.getLower());
3523+
EXPECT_EQ(0, CR2.getUpper());
3524+
}
3525+
3526+
{
3527+
// Assumptions:
3528+
// * stride >= 5 (samesign unsigned)
3529+
//
3530+
// stride = [5, MIN_SIGNED)
3531+
auto M = parseModule(R"(
3532+
declare void @llvm.assume(i1)
3533+
3534+
define i32 @test(i32 %stride) {
3535+
%gt = icmp samesign uge i32 %stride, 5
3536+
call void @llvm.assume(i1 %gt)
3537+
%stride.plus.one = add nsw nuw i32 %stride, 1
3538+
ret i32 %stride.plus.one
3539+
})");
3540+
Function *F = M->getFunction("test");
3541+
3542+
AssumptionCache AC(*F);
3543+
Value *Stride = &*F->arg_begin();
3544+
3545+
Instruction *I = &findInstructionByName(F, "stride.plus.one");
3546+
SimplifyQuery SQ(M->getDataLayout(), /*DT=*/nullptr, &AC, /*CxtI=*/I);
3547+
ConstantRange CR2 = computeConstantRange(Stride, false, SQ);
3548+
EXPECT_EQ(5, CR2.getLower());
3549+
EXPECT_EQ(APInt::getSignedMinValue(32), CR2.getUpper());
3550+
}
3551+
3552+
{
3553+
// Assumptions:
3554+
// * stride > 5 (samesign unsigned)
3555+
//
3556+
// stride = [5, MIN_SIGNED)
3557+
auto M = parseModule(R"(
3558+
declare void @llvm.assume(i1)
3559+
3560+
define i32 @test(i32 %stride) {
3561+
%gt = icmp samesign ugt i32 %stride, 5
3562+
call void @llvm.assume(i1 %gt)
3563+
%stride.plus.one = add nsw nuw i32 %stride, 1
3564+
ret i32 %stride.plus.one
3565+
})");
3566+
Function *F = M->getFunction("test");
3567+
3568+
AssumptionCache AC(*F);
3569+
Value *Stride = &*F->arg_begin();
3570+
3571+
Instruction *I = &findInstructionByName(F, "stride.plus.one");
3572+
SimplifyQuery SQ(M->getDataLayout(), /*DT=*/nullptr, &AC, /*CxtI=*/I);
3573+
ConstantRange CR2 = computeConstantRange(Stride, false, SQ);
3574+
EXPECT_EQ(6, CR2.getLower());
3575+
EXPECT_EQ(APInt::getSignedMinValue(32), CR2.getUpper());
3576+
}
3577+
34743578
{
34753579
// Assumptions:
34763580
// * stride >= 5

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "llvm/ADT/BitVector.h"
1111
#include "llvm/ADT/Sequence.h"
1212
#include "llvm/ADT/SmallBitVector.h"
13+
#include "llvm/IR/CmpPredicate.h"
1314
#include "llvm/IR/Instructions.h"
1415
#include "llvm/IR/Operator.h"
1516
#include "llvm/Support/KnownBits.h"
@@ -1730,6 +1731,64 @@ TEST(ConstantRange, MakeAllowedICmpRegionEdgeCases) {
17301731
.isFullSet());
17311732
}
17321733

1734+
template <typename SIV>
1735+
auto getSameSignTester(SIV ShouldIncludeValue, CmpInst::Predicate Cmp) {
1736+
return [Cmp, ShouldIncludeValue](const ConstantRange &CR) {
1737+
uint32_t BitWidth = CR.getBitWidth();
1738+
unsigned Max = 1 << BitWidth;
1739+
SmallBitVector Elems(Max);
1740+
if (!CR.isEmptySet()) {
1741+
for (unsigned I : llvm::seq(Max)) {
1742+
APInt Current(BitWidth, I);
1743+
if (ShouldIncludeValue(Current, CR))
1744+
Elems.set(I);
1745+
}
1746+
}
1747+
1748+
CmpPredicate CmpPred(Cmp, true);
1749+
TestRange(ConstantRange::makeAllowedICmpRegion(CmpPred, CR), Elems,
1750+
PreferSmallest, {});
1751+
};
1752+
}
1753+
1754+
TEST(ConstantRange, MakeAllowedICmpRegionExaustive) {
1755+
EnumerateInterestingConstantRanges(getSameSignTester(
1756+
[](const APInt &A, const ConstantRange &B) {
1757+
if (A.isNegative())
1758+
return A.sge(B.getSignedMin());
1759+
return A.uge(B.getUnsignedMin());
1760+
},
1761+
ICmpInst::ICMP_UGE));
1762+
1763+
EnumerateInterestingConstantRanges(getSameSignTester(
1764+
[](const APInt &A, const ConstantRange &B) {
1765+
if (A.isNegative())
1766+
return A.sgt(B.getSignedMin());
1767+
return A.ugt(B.getUnsignedMin());
1768+
},
1769+
ICmpInst::ICMP_UGT));
1770+
1771+
EnumerateInterestingConstantRanges(getSameSignTester(
1772+
[](const APInt &A, const ConstantRange &B) {
1773+
if (A.isNegative() && B.getUnsignedMax().isNegative())
1774+
return A.sle(B.getUnsignedMax());
1775+
if (A.isNonNegative() && B.getSignedMax().isNonNegative())
1776+
return A.ule(B.getSignedMax());
1777+
return false;
1778+
},
1779+
ICmpInst::ICMP_ULE));
1780+
1781+
EnumerateInterestingConstantRanges(getSameSignTester(
1782+
[](const APInt &A, const ConstantRange &B) {
1783+
if (A.isNegative() && B.getUnsignedMax().isNegative())
1784+
return A.slt(B.getUnsignedMax());
1785+
if (A.isNonNegative() && B.getSignedMax().isNonNegative())
1786+
return A.ult(B.getSignedMax());
1787+
return false;
1788+
},
1789+
ICmpInst::ICMP_ULT));
1790+
}
1791+
17331792
TEST(ConstantRange, MakeExactICmpRegion) {
17341793
for (unsigned Bits : {1, 4}) {
17351794
EnumerateAPInts(Bits, [](const APInt &N) {

0 commit comments

Comments
 (0)