llvm.org GIT mirror llvm / e2e04ea
[ConstantRange] Add urem support Add urem support to ConstantRange, so we can handle in in LVI. This is an approximate implementation that tries to capture the most useful conditions: If the LHS is always strictly smaller than the RHS, then the urem is a no-op and the result is the same as the LHS range. Otherwise the lower bound is zero and the upper bound is min(LHSMax, RHSMax - 1). Differential Revision: https://reviews.llvm.org/D60952 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359019 91177308-0d34-0410-b5e6-96231b3b80d8 Nikita Popov 6 months ago
3 changed file(s) with 74 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
356356 ConstantRange udiv(const ConstantRange &Other) const;
357357
358358 /// Return a new range representing the possible values resulting
359 /// from an unsigned remainder operation of a value in this range and a
360 /// value in \p Other.
361 ConstantRange urem(const ConstantRange &Other) const;
362
363 /// Return a new range representing the possible values resulting
359364 /// from a binary-and of a value in this range by a value in \p Other.
360365 ConstantRange binaryAnd(const ConstantRange &Other) const;
361366
793793 return multiply(Other);
794794 case Instruction::UDiv:
795795 return udiv(Other);
796 case Instruction::URem:
797 return urem(Other);
796798 case Instruction::Shl:
797799 return shl(Other);
798800 case Instruction::LShr:
990992 return getNonEmpty(std::move(Lower), std::move(Upper));
991993 }
992994
995 ConstantRange ConstantRange::urem(const ConstantRange &RHS) const {
996 if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax().isNullValue())
997 return getEmpty();
998
999 // L % R for L < R is L.
1000 if (getUnsignedMax().ult(RHS.getUnsignedMin()))
1001 return *this;
1002
1003 // L % R is <= L and < R.
1004 APInt Upper = APIntOps::umin(getUnsignedMax(), RHS.getUnsignedMax() - 1) + 1;
1005 return getNonEmpty(APInt::getNullValue(getBitWidth()), std::move(Upper));
1006 }
1007
9931008 ConstantRange
9941009 ConstantRange::binaryAnd(const ConstantRange &Other) const {
9951010 if (isEmptySet() || Other.isEmptySet())
5858 }
5959
6060 template
61 static void TestUnsignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) {
61 static void TestUnsignedBinOpExhaustive(
62 Fn1 RangeFn, Fn2 IntFn,
63 bool SkipZeroRHS = false, bool CorrectnessOnly = false) {
6264 unsigned Bits = 4;
6365 EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1,
6466 const ConstantRange &CR2) {
65 ConstantRange CR = RangeFn(CR1, CR2);
66 if (CR1.isEmptySet() || CR2.isEmptySet()) {
67 EXPECT_TRUE(CR.isEmptySet());
68 return;
69 }
70
7167 APInt Min = APInt::getMaxValue(Bits);
7268 APInt Max = APInt::getMinValue(Bits);
7369 ForeachNumInConstantRange(CR1, [&](const APInt &N1) {
7470 ForeachNumInConstantRange(CR2, [&](const APInt &N2) {
71 if (SkipZeroRHS && N2 == 0)
72 return;
73
7574 APInt N = IntFn(N1, N2);
7675 if (N.ult(Min))
7776 Min = N;
8079 });
8180 });
8281
83 EXPECT_EQ(ConstantRange::getNonEmpty(Min, Max + 1), CR);
82 ConstantRange CR = RangeFn(CR1, CR2);
83 if (Min.ugt(Max)) {
84 EXPECT_TRUE(CR.isEmptySet());
85 return;
86 }
87
88 ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1);
89 if (CorrectnessOnly) {
90 EXPECT_TRUE(CR.contains(Exact));
91 } else {
92 EXPECT_EQ(Exact, CR);
93 }
8494 });
8595 }
8696
810820 EXPECT_EQ(Some.udiv(Some), ConstantRange(APInt(16, 0), APInt(16, 0x111)));
811821 EXPECT_EQ(Some.udiv(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xaaa)));
812822 EXPECT_EQ(Wrap.udiv(Wrap), Full);
823 }
824
825 TEST_F(ConstantRangeTest, URem) {
826 EXPECT_EQ(Full.urem(Empty), Empty);
827 EXPECT_EQ(Empty.urem(Full), Empty);
828 // urem by zero is poison.
829 EXPECT_EQ(Full.urem(ConstantRange(APInt(16, 0))), Empty);
830 // urem by full range doesn't contain MaxValue.
831 EXPECT_EQ(Full.urem(Full), ConstantRange(APInt(16, 0), APInt(16, 0xffff)));
832 // urem is upper bounded by maximum RHS minus one.
833 EXPECT_EQ(Full.urem(ConstantRange(APInt(16, 0), APInt(16, 123))),
834 ConstantRange(APInt(16, 0), APInt(16, 122)));
835 // urem is upper bounded by maximum LHS.
836 EXPECT_EQ(ConstantRange(APInt(16, 0), APInt(16, 123)).urem(Full),
837 ConstantRange(APInt(16, 0), APInt(16, 123)));
838 // If the LHS is always lower than the RHS, the result is the LHS.
839 EXPECT_EQ(ConstantRange(APInt(16, 10), APInt(16, 20))
840 .urem(ConstantRange(APInt(16, 20), APInt(16, 30))),
841 ConstantRange(APInt(16, 10), APInt(16, 20)));
842 // It has to be strictly lower, otherwise the top value may wrap to zero.
843 EXPECT_EQ(ConstantRange(APInt(16, 10), APInt(16, 20))
844 .urem(ConstantRange(APInt(16, 19), APInt(16, 30))),
845 ConstantRange(APInt(16, 0), APInt(16, 20)));
846 // [12, 14] % 10 is [2, 4], but we conservatively compute [0, 9].
847 EXPECT_EQ(ConstantRange(APInt(16, 12), APInt(16, 15))
848 .urem(ConstantRange(APInt(16, 10))),
849 ConstantRange(APInt(16, 0), APInt(16, 10)));
850
851 TestUnsignedBinOpExhaustive(
852 [](const ConstantRange &CR1, const ConstantRange &CR2) {
853 return CR1.urem(CR2);
854 },
855 [](const APInt &N1, const APInt &N2) {
856 return N1.urem(N2);
857 },
858 /* SkipZeroRHS */ true, /* CorrectnessOnly */ true);
813859 }
814860
815861 TEST_F(ConstantRangeTest, Shl) {