@@ -59,20 +59,19 @@ static void ForeachNumInConstantRange(const ConstantRange &CR, Fn TestFn) {
59
59
}
60
60
61
61
template <typename Fn1, typename Fn2>
62
- static void TestUnsignedBinOpExhaustive (Fn1 RangeFn, Fn2 IntFn) {
62
+ static void TestUnsignedBinOpExhaustive (
63
+ Fn1 RangeFn, Fn2 IntFn,
64
+ bool SkipZeroRHS = false , bool CorrectnessOnly = false ) {
63
65
unsigned Bits = 4 ;
64
66
EnumerateTwoConstantRanges (Bits, [&](const ConstantRange &CR1,
65
67
const ConstantRange &CR2) {
66
- ConstantRange CR = RangeFn (CR1, CR2);
67
- if (CR1.isEmptySet () || CR2.isEmptySet ()) {
68
- EXPECT_TRUE (CR.isEmptySet ());
69
- return ;
70
- }
71
-
72
68
APInt Min = APInt::getMaxValue (Bits);
73
69
APInt Max = APInt::getMinValue (Bits);
74
70
ForeachNumInConstantRange (CR1, [&](const APInt &N1) {
75
71
ForeachNumInConstantRange (CR2, [&](const APInt &N2) {
72
+ if (SkipZeroRHS && N2 == 0 )
73
+ return ;
74
+
76
75
APInt N = IntFn (N1, N2);
77
76
if (N.ult (Min))
78
77
Min = N;
@@ -81,7 +80,18 @@ static void TestUnsignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) {
81
80
});
82
81
});
83
82
84
- EXPECT_EQ (ConstantRange::getNonEmpty (Min, Max + 1 ), CR);
83
+ ConstantRange CR = RangeFn (CR1, CR2);
84
+ if (Min.ugt (Max)) {
85
+ EXPECT_TRUE (CR.isEmptySet ());
86
+ return ;
87
+ }
88
+
89
+ ConstantRange Exact = ConstantRange::getNonEmpty (Min, Max + 1 );
90
+ if (CorrectnessOnly) {
91
+ EXPECT_TRUE (CR.contains (Exact));
92
+ } else {
93
+ EXPECT_EQ (Exact, CR);
94
+ }
85
95
});
86
96
}
87
97
@@ -813,6 +823,42 @@ TEST_F(ConstantRangeTest, UDiv) {
813
823
EXPECT_EQ (Wrap.udiv (Wrap), Full);
814
824
}
815
825
826
+ TEST_F (ConstantRangeTest, URem) {
827
+ EXPECT_EQ (Full.urem (Empty), Empty);
828
+ EXPECT_EQ (Empty.urem (Full), Empty);
829
+ // urem by zero is poison.
830
+ EXPECT_EQ (Full.urem (ConstantRange (APInt (16 , 0 ))), Empty);
831
+ // urem by full range doesn't contain MaxValue.
832
+ EXPECT_EQ (Full.urem (Full), ConstantRange (APInt (16 , 0 ), APInt (16 , 0xffff )));
833
+ // urem is upper bounded by maximum RHS minus one.
834
+ EXPECT_EQ (Full.urem (ConstantRange (APInt (16 , 0 ), APInt (16 , 123 ))),
835
+ ConstantRange (APInt (16 , 0 ), APInt (16 , 122 )));
836
+ // urem is upper bounded by maximum LHS.
837
+ EXPECT_EQ (ConstantRange (APInt (16 , 0 ), APInt (16 , 123 )).urem (Full),
838
+ ConstantRange (APInt (16 , 0 ), APInt (16 , 123 )));
839
+ // If the LHS is always lower than the RHS, the result is the LHS.
840
+ EXPECT_EQ (ConstantRange (APInt (16 , 10 ), APInt (16 , 20 ))
841
+ .urem (ConstantRange (APInt (16 , 20 ), APInt (16 , 30 ))),
842
+ ConstantRange (APInt (16 , 10 ), APInt (16 , 20 )));
843
+ // It has to be strictly lower, otherwise the top value may wrap to zero.
844
+ EXPECT_EQ (ConstantRange (APInt (16 , 10 ), APInt (16 , 20 ))
845
+ .urem (ConstantRange (APInt (16 , 19 ), APInt (16 , 30 ))),
846
+ ConstantRange (APInt (16 , 0 ), APInt (16 , 20 )));
847
+ // [12, 14] % 10 is [2, 4], but we conservatively compute [0, 9].
848
+ EXPECT_EQ (ConstantRange (APInt (16 , 12 ), APInt (16 , 15 ))
849
+ .urem (ConstantRange (APInt (16 , 10 ))),
850
+ ConstantRange (APInt (16 , 0 ), APInt (16 , 10 )));
851
+
852
+ TestUnsignedBinOpExhaustive (
853
+ [](const ConstantRange &CR1, const ConstantRange &CR2) {
854
+ return CR1.urem (CR2);
855
+ },
856
+ [](const APInt &N1, const APInt &N2) {
857
+ return N1.urem (N2);
858
+ },
859
+ /* SkipZeroRHS */ true , /* CorrectnessOnly */ true );
860
+ }
861
+
816
862
TEST_F (ConstantRangeTest, Shl) {
817
863
ConstantRange Some2 (APInt (16 , 0xfff ), APInt (16 , 0x8000 ));
818
864
ConstantRange WrapNullMax (APInt (16 , 0x1 ), APInt (16 , 0x0 ));
0 commit comments