llvm.org GIT mirror llvm / 13a908d
[ConstantRange] Add sdiv() support The implementation is conceptually simple: We separate the LHS and RHS into positive and negative components and then also compute the positive and negative components of the result, taking into account that e.g. only pos/pos and neg/neg will give a positive result. However, there's one significant complication: SignedMin / -1 is UB for sdiv, and we can't just ignore it, because the APInt result of SignedMin would break the sign segregation. Instead we drop SignedMin or -1 from the corresponding ranges, taking into account some edge cases with wrapped ranges. Because of the sign segregation, the implementation ends up being nearly fully precise even for wrapped ranges (the remaining imprecision is due to ranges that are both signed and unsigned wrapping and are divided by a trivial divisor like 1). This means that the testing cannot just check the signed envelope as we usually do. Instead we collect all possible results in a bitvector and construct a better sign wrapped range (than the full envelope). Differential Revision: https://reviews.llvm.org/D61238 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@362430 91177308-0d34-0410-b5e6-96231b3b80d8 Nikita Popov 3 months ago
3 changed file(s) with 152 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
364364 ConstantRange udiv(const ConstantRange &Other) const;
365365
366366 /// Return a new range representing the possible values resulting
367 /// from a signed division of a value in this range and a value in
368 /// \p Other. Division by zero and division of SignedMin by -1 are considered
369 /// undefined behavior, in line with IR, and do not contribute towards the
370 /// result.
371 ConstantRange sdiv(const ConstantRange &Other) const;
372
373 /// Return a new range representing the possible values resulting
367374 /// from an unsigned remainder operation of a value in this range and a
368375 /// value in \p Other.
369376 ConstantRange urem(const ConstantRange &Other) const;
764764 return multiply(Other);
765765 case Instruction::UDiv:
766766 return udiv(Other);
767 case Instruction::SDiv:
768 return sdiv(Other);
767769 case Instruction::URem:
768770 return urem(Other);
769771 case Instruction::SRem:
961963 return getNonEmpty(std::move(Lower), std::move(Upper));
962964 }
963965
966 ConstantRange ConstantRange::sdiv(const ConstantRange &RHS) const {
967 // We split up the LHS and RHS into positive and negative components
968 // and then also compute the positive and negative components of the result
969 // separately by combining division results with the appropriate signs.
970 APInt Zero = APInt::getNullValue(getBitWidth());
971 APInt SignedMin = APInt::getSignedMinValue(getBitWidth());
972 ConstantRange PosFilter(APInt(getBitWidth(), 1), SignedMin);
973 ConstantRange NegFilter(SignedMin, Zero);
974 ConstantRange PosL = intersectWith(PosFilter);
975 ConstantRange NegL = intersectWith(NegFilter);
976 ConstantRange PosR = RHS.intersectWith(PosFilter);
977 ConstantRange NegR = RHS.intersectWith(NegFilter);
978
979 ConstantRange PosRes = getEmpty();
980 if (!PosL.isEmptySet() && !PosR.isEmptySet())
981 // pos / pos = pos.
982 PosRes = ConstantRange(PosL.Lower.sdiv(PosR.Upper - 1),
983 (PosL.Upper - 1).sdiv(PosR.Lower) + 1);
984
985 if (!NegL.isEmptySet() && !NegR.isEmptySet()) {
986 // neg / neg = pos.
987 //
988 // We need to deal with one tricky case here: SignedMin / -1 is UB on the
989 // IR level, so we'll want to exclude this case when calculating bounds.
990 // (For APInts the operation is well-defined and yields SignedMin.) We
991 // handle this by dropping either SignedMin from the LHS or -1 from the RHS.
992 APInt Lo = (NegL.Upper - 1).sdiv(NegR.Lower);
993 if (NegL.Lower.isMinSignedValue() && NegR.Upper.isNullValue()) {
994 // Remove -1 from the LHS. Skip if it's the only element, as this would
995 // leave us with an empty set.
996 if (!NegR.Lower.isAllOnesValue()) {
997 APInt AdjNegRUpper;
998 if (RHS.Lower.isAllOnesValue())
999 // Negative part of [-1, X] without -1 is [SignedMin, X].
1000 AdjNegRUpper = RHS.Upper;
1001 else
1002 // [X, -1] without -1 is [X, -2].
1003 AdjNegRUpper = NegR.Upper - 1;
1004
1005 PosRes = PosRes.unionWith(
1006 ConstantRange(Lo, NegL.Lower.sdiv(AdjNegRUpper - 1) + 1));
1007 }
1008
1009 // Remove SignedMin from the RHS. Skip if it's the only element, as this
1010 // would leave us with an empty set.
1011 if (NegL.Upper != SignedMin + 1) {
1012 APInt AdjNegLLower;
1013 if (Upper == SignedMin + 1)
1014 // Negative part of [X, SignedMin] without SignedMin is [X, -1].
1015 AdjNegLLower = Lower;
1016 else
1017 // [SignedMin, X] without SignedMin is [SignedMin + 1, X].
1018 AdjNegLLower = NegL.Lower + 1;
1019
1020 PosRes = PosRes.unionWith(
1021 ConstantRange(std::move(Lo),
1022 AdjNegLLower.sdiv(NegR.Upper - 1) + 1));
1023 }
1024 } else {
1025 PosRes = PosRes.unionWith(
1026 ConstantRange(std::move(Lo), NegL.Lower.sdiv(NegR.Upper - 1) + 1));
1027 }
1028 }
1029
1030 ConstantRange NegRes = getEmpty();
1031 if (!PosL.isEmptySet() && !NegR.isEmptySet())
1032 // pos / neg = neg.
1033 NegRes = ConstantRange((PosL.Upper - 1).sdiv(NegR.Upper - 1),
1034 PosL.Lower.sdiv(NegR.Lower) + 1);
1035
1036 if (!NegL.isEmptySet() && !PosR.isEmptySet())
1037 // neg / pos = neg.
1038 NegRes = NegRes.unionWith(
1039 ConstantRange(NegL.Lower.sdiv(PosR.Lower),
1040 (NegL.Upper - 1).sdiv(PosR.Upper - 1) + 1));
1041
1042 // Prefer a non-wrapping signed range here.
1043 ConstantRange Res = NegRes.unionWith(PosRes, PreferredRangeType::Signed);
1044
1045 // Preserve the zero that we dropped when splitting the LHS by sign.
1046 if (contains(Zero) && (!PosR.isEmptySet() || !NegR.isEmptySet()))
1047 Res = Res.unionWith(ConstantRange(Zero));
1048 return Res;
1049 }
1050
9641051 ConstantRange ConstantRange::urem(const ConstantRange &RHS) const {
9651052 if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax().isNullValue())
9661053 return getEmpty();
55 //
66 //===----------------------------------------------------------------------===//
77
8 #include "llvm/ADT/BitVector.h"
89 #include "llvm/IR/ConstantRange.h"
910 #include "llvm/IR/Instructions.h"
1011 #include "llvm/IR/Operator.h"
841842 ConstantRange(APInt(16, 0), APInt(16, 99)));
842843 EXPECT_EQ(ConstantRange(APInt(16, 10), APInt(16, 99)).udiv(Full),
843844 ConstantRange(APInt(16, 0), APInt(16, 99)));
845 }
846
847 TEST_F(ConstantRangeTest, SDiv) {
848 unsigned Bits = 4;
849 EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1,
850 const ConstantRange &CR2) {
851 // Collect possible results in a bit vector. We store the signed value plus
852 // a bias to make it unsigned.
853 int Bias = 1 << (Bits - 1);
854 BitVector Results(1 << Bits);
855 ForeachNumInConstantRange(CR1, [&](const APInt &N1) {
856 ForeachNumInConstantRange(CR2, [&](const APInt &N2) {
857 // Division by zero is UB.
858 if (N2 == 0)
859 return;
860
861 // SignedMin / -1 is UB.
862 if (N1.isMinSignedValue() && N2.isAllOnesValue())
863 return;
864
865 APInt N = N1.sdiv(N2);
866 Results.set(N.getSExtValue() + Bias);
867 });
868 });
869
870 ConstantRange CR = CR1.sdiv(CR2);
871 if (Results.none()) {
872 EXPECT_TRUE(CR.isEmptySet());
873 return;
874 }
875
876 // If there is a non-full signed envelope, that should be the result.
877 APInt SMin(Bits, Results.find_first() - Bias);
878 APInt SMax(Bits, Results.find_last() - Bias);
879 ConstantRange Envelope = ConstantRange::getNonEmpty(SMin, SMax + 1);
880 if (!Envelope.isFullSet()) {
881 EXPECT_EQ(Envelope, CR);
882 return;
883 }
884
885 // If the signed envelope is a full set, try to find a smaller sign wrapped
886 // set that is separated in negative and positive components (or one which
887 // can also additionally contain zero).
888 int LastNeg = Results.find_last_in(0, Bias) - Bias;
889 int LastPos = Results.find_next(Bias) - Bias;
890 if (Results[Bias]) {
891 if (LastNeg == -1)
892 ++LastNeg;
893 else if (LastPos == 1)
894 --LastPos;
895 }
896
897 APInt WMax(Bits, LastNeg);
898 APInt WMin(Bits, LastPos);
899 ConstantRange Wrapped = ConstantRange::getNonEmpty(WMin, WMax + 1);
900 EXPECT_EQ(Wrapped, CR);
901 });
844902 }
845903
846904 TEST_F(ConstantRangeTest, URem) {