@@ -96,20 +96,19 @@ static void TestUnsignedBinOpExhaustive(
96
96
}
97
97
98
98
template <typename Fn1, typename Fn2>
99
- static void TestSignedBinOpExhaustive (Fn1 RangeFn, Fn2 IntFn) {
99
+ static void TestSignedBinOpExhaustive (
100
+ Fn1 RangeFn, Fn2 IntFn,
101
+ bool SkipZeroRHS = false , bool CorrectnessOnly = false ) {
100
102
unsigned Bits = 4 ;
101
103
EnumerateTwoConstantRanges (Bits, [&](const ConstantRange &CR1,
102
104
const ConstantRange &CR2) {
103
- ConstantRange CR = RangeFn (CR1, CR2);
104
- if (CR1.isEmptySet () || CR2.isEmptySet ()) {
105
- EXPECT_TRUE (CR.isEmptySet ());
106
- return ;
107
- }
108
-
109
105
APInt Min = APInt::getSignedMaxValue (Bits);
110
106
APInt Max = APInt::getSignedMinValue (Bits);
111
107
ForeachNumInConstantRange (CR1, [&](const APInt &N1) {
112
108
ForeachNumInConstantRange (CR2, [&](const APInt &N2) {
109
+ if (SkipZeroRHS && N2 == 0 )
110
+ return ;
111
+
113
112
APInt N = IntFn (N1, N2);
114
113
if (N.slt (Min))
115
114
Min = N;
@@ -118,7 +117,18 @@ static void TestSignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) {
118
117
});
119
118
});
120
119
121
- EXPECT_EQ (ConstantRange::getNonEmpty (Min, Max + 1 ), CR);
120
+ ConstantRange CR = RangeFn (CR1, CR2);
121
+ if (Min.sgt (Max)) {
122
+ EXPECT_TRUE (CR.isEmptySet ());
123
+ return ;
124
+ }
125
+
126
+ ConstantRange Exact = ConstantRange::getNonEmpty (Min, Max + 1 );
127
+ if (CorrectnessOnly) {
128
+ EXPECT_TRUE (CR.contains (Exact));
129
+ } else {
130
+ EXPECT_EQ (Exact, CR);
131
+ }
122
132
});
123
133
}
124
134
@@ -870,6 +880,79 @@ TEST_F(ConstantRangeTest, URem) {
870
880
/* SkipZeroRHS */ true , /* CorrectnessOnly */ true );
871
881
}
872
882
883
+ TEST_F (ConstantRangeTest, SRem) {
884
+ EXPECT_EQ (Full.srem (Empty), Empty);
885
+ EXPECT_EQ (Empty.srem (Full), Empty);
886
+ // srem by zero is UB.
887
+ EXPECT_EQ (Full.srem (ConstantRange (APInt (16 , 0 ))), Empty);
888
+ // srem by full range doesn't contain SignedMinValue.
889
+ EXPECT_EQ (Full.srem (Full), ConstantRange (APInt::getSignedMinValue (16 ) + 1 ,
890
+ APInt::getSignedMinValue (16 )));
891
+
892
+ ConstantRange PosMod (APInt (16 , 10 ), APInt (16 , 21 )); // [10, 20]
893
+ ConstantRange NegMod (APInt (16 , -20 ), APInt (16 , -9 )); // [-20, -10]
894
+ ConstantRange IntMinMod (APInt::getSignedMinValue (16 ));
895
+
896
+ ConstantRange Expected (16 , true );
897
+
898
+ // srem is bounded by abs(RHS) minus one.
899
+ ConstantRange PosLargeLHS (APInt (16 , 0 ), APInt (16 , 41 ));
900
+ Expected = ConstantRange (APInt (16 , 0 ), APInt (16 , 20 ));
901
+ EXPECT_EQ (PosLargeLHS.srem (PosMod), Expected);
902
+ EXPECT_EQ (PosLargeLHS.srem (NegMod), Expected);
903
+ ConstantRange NegLargeLHS (APInt (16 , -40 ), APInt (16 , 1 ));
904
+ Expected = ConstantRange (APInt (16 , -19 ), APInt (16 , 1 ));
905
+ EXPECT_EQ (NegLargeLHS.srem (PosMod), Expected);
906
+ EXPECT_EQ (NegLargeLHS.srem (NegMod), Expected);
907
+ ConstantRange PosNegLargeLHS (APInt (16 , -32 ), APInt (16 , 38 ));
908
+ Expected = ConstantRange (APInt (16 , -19 ), APInt (16 , 20 ));
909
+ EXPECT_EQ (PosNegLargeLHS.srem (PosMod), Expected);
910
+ EXPECT_EQ (PosNegLargeLHS.srem (NegMod), Expected);
911
+
912
+ // srem is bounded by LHS.
913
+ ConstantRange PosLHS (APInt (16 , 0 ), APInt (16 , 16 ));
914
+ EXPECT_EQ (PosLHS.srem (PosMod), PosLHS);
915
+ EXPECT_EQ (PosLHS.srem (NegMod), PosLHS);
916
+ EXPECT_EQ (PosLHS.srem (IntMinMod), PosLHS);
917
+ ConstantRange NegLHS (APInt (16 , -15 ), APInt (16 , 1 ));
918
+ EXPECT_EQ (NegLHS.srem (PosMod), NegLHS);
919
+ EXPECT_EQ (NegLHS.srem (NegMod), NegLHS);
920
+ EXPECT_EQ (NegLHS.srem (IntMinMod), NegLHS);
921
+ ConstantRange PosNegLHS (APInt (16 , -12 ), APInt (16 , 18 ));
922
+ EXPECT_EQ (PosNegLHS.srem (PosMod), PosNegLHS);
923
+ EXPECT_EQ (PosNegLHS.srem (NegMod), PosNegLHS);
924
+ EXPECT_EQ (PosNegLHS.srem (IntMinMod), PosNegLHS);
925
+
926
+ // srem is LHS if it is smaller than RHS.
927
+ ConstantRange PosSmallLHS (APInt (16 , 3 ), APInt (16 , 8 ));
928
+ EXPECT_EQ (PosSmallLHS.srem (PosMod), PosSmallLHS);
929
+ EXPECT_EQ (PosSmallLHS.srem (NegMod), PosSmallLHS);
930
+ EXPECT_EQ (PosSmallLHS.srem (IntMinMod), PosSmallLHS);
931
+ ConstantRange NegSmallLHS (APInt (16 , -7 ), APInt (16 , -2 ));
932
+ EXPECT_EQ (NegSmallLHS.srem (PosMod), NegSmallLHS);
933
+ EXPECT_EQ (NegSmallLHS.srem (NegMod), NegSmallLHS);
934
+ EXPECT_EQ (NegSmallLHS.srem (IntMinMod), NegSmallLHS);
935
+ ConstantRange PosNegSmallLHS (APInt (16 , -3 ), APInt (16 , 8 ));
936
+ EXPECT_EQ (PosNegSmallLHS.srem (PosMod), PosNegSmallLHS);
937
+ EXPECT_EQ (PosNegSmallLHS.srem (NegMod), PosNegSmallLHS);
938
+ EXPECT_EQ (PosNegSmallLHS.srem (IntMinMod), PosNegSmallLHS);
939
+
940
+ // Example of a suboptimal result:
941
+ // [12, 14] srem 10 is [2, 4], but we conservatively compute [0, 9].
942
+ EXPECT_EQ (ConstantRange (APInt (16 , 12 ), APInt (16 , 15 ))
943
+ .srem (ConstantRange (APInt (16 , 10 ))),
944
+ ConstantRange (APInt (16 , 0 ), APInt (16 , 10 )));
945
+
946
+ TestSignedBinOpExhaustive (
947
+ [](const ConstantRange &CR1, const ConstantRange &CR2) {
948
+ return CR1.srem (CR2);
949
+ },
950
+ [](const APInt &N1, const APInt &N2) {
951
+ return N1.srem (N2);
952
+ },
953
+ /* SkipZeroRHS */ true , /* CorrectnessOnly */ true );
954
+ }
955
+
873
956
TEST_F (ConstantRangeTest, Shl) {
874
957
ConstantRange Some2 (APInt (16 , 0xfff ), APInt (16 , 0x8000 ));
875
958
ConstantRange WrapNullMax (APInt (16 , 0x1 ), APInt (16 , 0x0 ));
0 commit comments