forked from OSchip/llvm-project
[ConstantRange] Handle wrapping ranges in min/max (PR48643)
When one of the inputs is a wrapping range, intersect with the union of the two inputs. The union of the two inputs corresponds to the result we would get if we treated the min/max as a simple select. This fixes PR48643.
This commit is contained in:
parent
e772618f1e
commit
a852234f70
|
@ -1058,7 +1058,10 @@ ConstantRange::smax(const ConstantRange &Other) const {
|
|||
return getEmpty();
|
||||
APInt NewL = APIntOps::smax(getSignedMin(), Other.getSignedMin());
|
||||
APInt NewU = APIntOps::smax(getSignedMax(), Other.getSignedMax()) + 1;
|
||||
return getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
if (isSignWrappedSet() || Other.isSignWrappedSet())
|
||||
return Res.intersectWith(unionWith(Other, Signed), Signed);
|
||||
return Res;
|
||||
}
|
||||
|
||||
ConstantRange
|
||||
|
@ -1069,7 +1072,10 @@ ConstantRange::umax(const ConstantRange &Other) const {
|
|||
return getEmpty();
|
||||
APInt NewL = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin());
|
||||
APInt NewU = APIntOps::umax(getUnsignedMax(), Other.getUnsignedMax()) + 1;
|
||||
return getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
if (isWrappedSet() || Other.isWrappedSet())
|
||||
return Res.intersectWith(unionWith(Other, Unsigned), Unsigned);
|
||||
return Res;
|
||||
}
|
||||
|
||||
ConstantRange
|
||||
|
@ -1080,7 +1086,10 @@ ConstantRange::smin(const ConstantRange &Other) const {
|
|||
return getEmpty();
|
||||
APInt NewL = APIntOps::smin(getSignedMin(), Other.getSignedMin());
|
||||
APInt NewU = APIntOps::smin(getSignedMax(), Other.getSignedMax()) + 1;
|
||||
return getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
if (isSignWrappedSet() || Other.isSignWrappedSet())
|
||||
return Res.intersectWith(unionWith(Other, Signed), Signed);
|
||||
return Res;
|
||||
}
|
||||
|
||||
ConstantRange
|
||||
|
@ -1091,7 +1100,10 @@ ConstantRange::umin(const ConstantRange &Other) const {
|
|||
return getEmpty();
|
||||
APInt NewL = APIntOps::umin(getUnsignedMin(), Other.getUnsignedMin());
|
||||
APInt NewU = APIntOps::umin(getUnsignedMax(), Other.getUnsignedMax()) + 1;
|
||||
return getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU));
|
||||
if (isWrappedSet() || Other.isWrappedSet())
|
||||
return Res.intersectWith(unionWith(Other, Unsigned), Unsigned);
|
||||
return Res;
|
||||
}
|
||||
|
||||
ConstantRange
|
||||
|
|
|
@ -1080,10 +1080,18 @@ TEST_F(ConstantRangeTest, UMax) {
|
|||
EXPECT_EQ(Some.umax(Some), Some);
|
||||
EXPECT_EQ(Some.umax(Wrap), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
|
||||
EXPECT_EQ(Some.umax(One), Some);
|
||||
// TODO: ConstantRange is currently over-conservative here.
|
||||
EXPECT_EQ(Wrap.umax(Wrap), Full);
|
||||
EXPECT_EQ(Wrap.umax(Wrap), Wrap);
|
||||
EXPECT_EQ(Wrap.umax(One), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
|
||||
EXPECT_EQ(One.umax(One), One);
|
||||
|
||||
TestBinaryOpExhaustive(
|
||||
[](const ConstantRange &CR1, const ConstantRange &CR2) {
|
||||
return CR1.umax(CR2);
|
||||
},
|
||||
[](const APInt &N1, const APInt &N2) {
|
||||
return APIntOps::umax(N1, N2);
|
||||
},
|
||||
PreferSmallestNonFullUnsigned);
|
||||
}
|
||||
|
||||
TEST_F(ConstantRangeTest, SMax) {
|
||||
|
@ -1105,6 +1113,15 @@ TEST_F(ConstantRangeTest, SMax) {
|
|||
EXPECT_EQ(Wrap.smax(One), ConstantRange(APInt(16, 0xa),
|
||||
APInt(16, (uint64_t)INT16_MIN)));
|
||||
EXPECT_EQ(One.smax(One), One);
|
||||
|
||||
TestBinaryOpExhaustive(
|
||||
[](const ConstantRange &CR1, const ConstantRange &CR2) {
|
||||
return CR1.smax(CR2);
|
||||
},
|
||||
[](const APInt &N1, const APInt &N2) {
|
||||
return APIntOps::smax(N1, N2);
|
||||
},
|
||||
PreferSmallestNonFullSigned);
|
||||
}
|
||||
|
||||
TEST_F(ConstantRangeTest, UMin) {
|
||||
|
@ -1119,10 +1136,18 @@ TEST_F(ConstantRangeTest, UMin) {
|
|||
EXPECT_EQ(Some.umin(Some), Some);
|
||||
EXPECT_EQ(Some.umin(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xaaa)));
|
||||
EXPECT_EQ(Some.umin(One), One);
|
||||
// TODO: ConstantRange is currently over-conservative here.
|
||||
EXPECT_EQ(Wrap.umin(Wrap), Full);
|
||||
EXPECT_EQ(Wrap.umin(Wrap), Wrap);
|
||||
EXPECT_EQ(Wrap.umin(One), ConstantRange(APInt(16, 0), APInt(16, 0xb)));
|
||||
EXPECT_EQ(One.umin(One), One);
|
||||
|
||||
TestBinaryOpExhaustive(
|
||||
[](const ConstantRange &CR1, const ConstantRange &CR2) {
|
||||
return CR1.umin(CR2);
|
||||
},
|
||||
[](const APInt &N1, const APInt &N2) {
|
||||
return APIntOps::umin(N1, N2);
|
||||
},
|
||||
PreferSmallestNonFullUnsigned);
|
||||
}
|
||||
|
||||
TEST_F(ConstantRangeTest, SMin) {
|
||||
|
@ -1139,11 +1164,19 @@ TEST_F(ConstantRangeTest, SMin) {
|
|||
EXPECT_EQ(Some.smin(Wrap), ConstantRange(APInt(16, (uint64_t)INT16_MIN),
|
||||
APInt(16, 0xaaa)));
|
||||
EXPECT_EQ(Some.smin(One), One);
|
||||
// TODO: ConstantRange is currently over-conservative here.
|
||||
EXPECT_EQ(Wrap.smin(Wrap), Full);
|
||||
EXPECT_EQ(Wrap.smin(Wrap), Wrap);
|
||||
EXPECT_EQ(Wrap.smin(One), ConstantRange(APInt(16, (uint64_t)INT16_MIN),
|
||||
APInt(16, 0xb)));
|
||||
EXPECT_EQ(One.smin(One), One);
|
||||
|
||||
TestBinaryOpExhaustive(
|
||||
[](const ConstantRange &CR1, const ConstantRange &CR2) {
|
||||
return CR1.smin(CR2);
|
||||
},
|
||||
[](const APInt &N1, const APInt &N2) {
|
||||
return APIntOps::smin(N1, N2);
|
||||
},
|
||||
PreferSmallestNonFullSigned);
|
||||
}
|
||||
|
||||
TEST_F(ConstantRangeTest, UDiv) {
|
||||
|
|
Loading…
Reference in New Issue