llvm.org GIT mirror llvm / c686868
[ConstantRange] Add srem() support Add support for srem() to ConstantRange so we can use it in LVI. For srem the sign of the result matches the sign of the LHS. For the RHS only the absolute value is important. Apart from that the logic is like urem. Just like for urem this is only an approximate implementation. The tests check a few specific cases and run an exhaustive test for conservative correctness (but not exactness). Differential Revision: https://reviews.llvm.org/D61207 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360055 91177308-0d34-0410-b5e6-96231b3b80d8 Nikita Popov 1 year, 5 months ago
3 changed file(s) with 140 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
369369 ConstantRange urem(const ConstantRange &Other) const;
370370
371371 /// Return a new range representing the possible values resulting
372 /// from a signed remainder operation of a value in this range and a
373 /// value in \p Other.
374 ConstantRange srem(const ConstantRange &Other) const;
375
376 /// Return a new range representing the possible values resulting
372377 /// from a binary-and of a value in this range by a value in \p Other.
373378 ConstantRange binaryAnd(const ConstantRange &Other) const;
374379
803803 return udiv(Other);
804804 case Instruction::URem:
805805 return urem(Other);
806 case Instruction::SRem:
807 return srem(Other);
806808 case Instruction::Shl:
807809 return shl(Other);
808810 case Instruction::LShr:
10091011 return getNonEmpty(APInt::getNullValue(getBitWidth()), std::move(Upper));
10101012 }
10111013
1014 ConstantRange ConstantRange::srem(const ConstantRange &RHS) const {
1015 if (isEmptySet() || RHS.isEmptySet())
1016 return getEmpty();
1017
1018 ConstantRange AbsRHS = RHS.abs();
1019 APInt MinAbsRHS = AbsRHS.getUnsignedMin();
1020 APInt MaxAbsRHS = AbsRHS.getUnsignedMax();
1021
1022 // Modulus by zero is UB.
1023 if (MaxAbsRHS.isNullValue())
1024 return getEmpty();
1025
1026 if (MinAbsRHS.isNullValue())
1027 ++MinAbsRHS;
1028
1029 APInt MinLHS = getSignedMin(), MaxLHS = getSignedMax();
1030
1031 if (MinLHS.isNonNegative()) {
1032 // L % R for L < R is L.
1033 if (MaxLHS.ult(MinAbsRHS))
1034 return *this;
1035
1036 // L % R is <= L and < R.
1037 APInt Upper = APIntOps::umin(MaxLHS, MaxAbsRHS - 1) + 1;
1038 return ConstantRange(APInt::getNullValue(getBitWidth()), std::move(Upper));
1039 }
1040
1041 // Same basic logic as above, but the result is negative.
1042 if (MaxLHS.isNegative()) {
1043 if (MinLHS.ugt(-MinAbsRHS))
1044 return *this;
1045
1046 APInt Lower = APIntOps::umax(MinLHS, -MaxAbsRHS + 1);
1047 return ConstantRange(std::move(Lower), APInt(getBitWidth(), 1));
1048 }
1049
1050 // LHS range crosses zero.
1051 APInt Lower = APIntOps::umax(MinLHS, -MaxAbsRHS + 1);
1052 APInt Upper = APIntOps::umin(MaxLHS, MaxAbsRHS - 1) + 1;
1053 return ConstantRange(std::move(Lower), std::move(Upper));
1054 }
1055
10121056 ConstantRange
10131057 ConstantRange::binaryAnd(const ConstantRange &Other) const {
10141058 if (isEmptySet() || Other.isEmptySet())
9595 }
9696
9797 template
98 static void TestSignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) {
98 static void TestSignedBinOpExhaustive(
99 Fn1 RangeFn, Fn2 IntFn,
100 bool SkipZeroRHS = false, bool CorrectnessOnly = false) {
99101 unsigned Bits = 4;
100102 EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1,
101103 const ConstantRange &CR2) {
102 ConstantRange CR = RangeFn(CR1, CR2);
103 if (CR1.isEmptySet() || CR2.isEmptySet()) {
104 EXPECT_TRUE(CR.isEmptySet());
105 return;
106 }
107
108104 APInt Min = APInt::getSignedMaxValue(Bits);
109105 APInt Max = APInt::getSignedMinValue(Bits);
110106 ForeachNumInConstantRange(CR1, [&](const APInt &N1) {
111107 ForeachNumInConstantRange(CR2, [&](const APInt &N2) {
108 if (SkipZeroRHS && N2 == 0)
109 return;
110
112111 APInt N = IntFn(N1, N2);
113112 if (N.slt(Min))
114113 Min = N;
117116 });
118117 });
119118
120 EXPECT_EQ(ConstantRange::getNonEmpty(Min, Max + 1), CR);
119 ConstantRange CR = RangeFn(CR1, CR2);
120 if (Min.sgt(Max)) {
121 EXPECT_TRUE(CR.isEmptySet());
122 return;
123 }
124
125 ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1);
126 if (CorrectnessOnly) {
127 EXPECT_TRUE(CR.contains(Exact));
128 } else {
129 EXPECT_EQ(Exact, CR);
130 }
121131 });
122132 }
123133
869879 /* SkipZeroRHS */ true, /* CorrectnessOnly */ true);
870880 }
871881
882 TEST_F(ConstantRangeTest, SRem) {
883 EXPECT_EQ(Full.srem(Empty), Empty);
884 EXPECT_EQ(Empty.srem(Full), Empty);
885 // srem by zero is UB.
886 EXPECT_EQ(Full.srem(ConstantRange(APInt(16, 0))), Empty);
887 // srem by full range doesn't contain SignedMinValue.
888 EXPECT_EQ(Full.srem(Full), ConstantRange(APInt::getSignedMinValue(16) + 1,
889 APInt::getSignedMinValue(16)));
890
891 ConstantRange PosMod(APInt(16, 10), APInt(16, 21)); // [10, 20]
892 ConstantRange NegMod(APInt(16, -20), APInt(16, -9)); // [-20, -10]
893 ConstantRange IntMinMod(APInt::getSignedMinValue(16));
894
895 ConstantRange Expected(16, true);
896
897 // srem is bounded by abs(RHS) minus one.
898 ConstantRange PosLargeLHS(APInt(16, 0), APInt(16, 41));
899 Expected = ConstantRange(APInt(16, 0), APInt(16, 20));
900 EXPECT_EQ(PosLargeLHS.srem(PosMod), Expected);
901 EXPECT_EQ(PosLargeLHS.srem(NegMod), Expected);
902 ConstantRange NegLargeLHS(APInt(16, -40), APInt(16, 1));
903 Expected = ConstantRange(APInt(16, -19), APInt(16, 1));
904 EXPECT_EQ(NegLargeLHS.srem(PosMod), Expected);
905 EXPECT_EQ(NegLargeLHS.srem(NegMod), Expected);
906 ConstantRange PosNegLargeLHS(APInt(16, -32), APInt(16, 38));
907 Expected = ConstantRange(APInt(16, -19), APInt(16, 20));
908 EXPECT_EQ(PosNegLargeLHS.srem(PosMod), Expected);
909 EXPECT_EQ(PosNegLargeLHS.srem(NegMod), Expected);
910
911 // srem is bounded by LHS.
912 ConstantRange PosLHS(APInt(16, 0), APInt(16, 16));
913 EXPECT_EQ(PosLHS.srem(PosMod), PosLHS);
914 EXPECT_EQ(PosLHS.srem(NegMod), PosLHS);
915 EXPECT_EQ(PosLHS.srem(IntMinMod), PosLHS);
916 ConstantRange NegLHS(APInt(16, -15), APInt(16, 1));
917 EXPECT_EQ(NegLHS.srem(PosMod), NegLHS);
918 EXPECT_EQ(NegLHS.srem(NegMod), NegLHS);
919 EXPECT_EQ(NegLHS.srem(IntMinMod), NegLHS);
920 ConstantRange PosNegLHS(APInt(16, -12), APInt(16, 18));
921 EXPECT_EQ(PosNegLHS.srem(PosMod), PosNegLHS);
922 EXPECT_EQ(PosNegLHS.srem(NegMod), PosNegLHS);
923 EXPECT_EQ(PosNegLHS.srem(IntMinMod), PosNegLHS);
924
925 // srem is LHS if it is smaller than RHS.
926 ConstantRange PosSmallLHS(APInt(16, 3), APInt(16, 8));
927 EXPECT_EQ(PosSmallLHS.srem(PosMod), PosSmallLHS);
928 EXPECT_EQ(PosSmallLHS.srem(NegMod), PosSmallLHS);
929 EXPECT_EQ(PosSmallLHS.srem(IntMinMod), PosSmallLHS);
930 ConstantRange NegSmallLHS(APInt(16, -7), APInt(16, -2));
931 EXPECT_EQ(NegSmallLHS.srem(PosMod), NegSmallLHS);
932 EXPECT_EQ(NegSmallLHS.srem(NegMod), NegSmallLHS);
933 EXPECT_EQ(NegSmallLHS.srem(IntMinMod), NegSmallLHS);
934 ConstantRange PosNegSmallLHS(APInt(16, -3), APInt(16, 8));
935 EXPECT_EQ(PosNegSmallLHS.srem(PosMod), PosNegSmallLHS);
936 EXPECT_EQ(PosNegSmallLHS.srem(NegMod), PosNegSmallLHS);
937 EXPECT_EQ(PosNegSmallLHS.srem(IntMinMod), PosNegSmallLHS);
938
939 // Example of a suboptimal result:
940 // [12, 14] srem 10 is [2, 4], but we conservatively compute [0, 9].
941 EXPECT_EQ(ConstantRange(APInt(16, 12), APInt(16, 15))
942 .srem(ConstantRange(APInt(16, 10))),
943 ConstantRange(APInt(16, 0), APInt(16, 10)));
944
945 TestSignedBinOpExhaustive(
946 [](const ConstantRange &CR1, const ConstantRange &CR2) {
947 return CR1.srem(CR2);
948 },
949 [](const APInt &N1, const APInt &N2) {
950 return N1.srem(N2);
951 },
952 /* SkipZeroRHS */ true, /* CorrectnessOnly */ true);
953 }
954
872955 TEST_F(ConstantRangeTest, Shl) {
873956 ConstantRange Some2(APInt(16, 0xfff), APInt(16, 0x8000));
874957 ConstantRange WrapNullMax(APInt(16, 0x1), APInt(16, 0x0));