@@ -1338,6 +1338,9 @@ class SymbolicRangeInferrer
1338
1338
RangeSet VisitBinaryOperator (RangeSet LHS, BinaryOperator::Opcode Op,
1339
1339
RangeSet RHS, QualType T);
1340
1340
1341
+ RangeSet handleConcreteModulo (Range LHS, llvm::APSInt Modulo, QualType T);
1342
+ RangeSet handleRangeModulo (Range LHS, Range RHS, QualType T);
1343
+
1341
1344
// ===----------------------------------------------------------------------===//
1342
1345
// Ranges and operators
1343
1346
// ===----------------------------------------------------------------------===//
@@ -1771,6 +1774,14 @@ template <>
1771
1774
RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS,
1772
1775
Range RHS,
1773
1776
QualType T) {
1777
+ if (const llvm::APSInt *ModOrNull = RHS.getConcreteValue ())
1778
+ return handleConcreteModulo (LHS, *ModOrNull, T);
1779
+
1780
+ return handleRangeModulo (LHS, RHS, T);
1781
+ }
1782
+
1783
+ RangeSet SymbolicRangeInferrer::handleRangeModulo (Range LHS, Range RHS,
1784
+ QualType T) {
1774
1785
llvm::APSInt Zero = ValueFactory.getAPSIntType (T).getZeroValue ();
1775
1786
1776
1787
Range ConservativeRange = getSymmetricalRange (RHS, T);
@@ -1824,6 +1835,101 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS,
1824
1835
return {RangeFactory, ValueFactory.getValue (Min), ValueFactory.getValue (Max)};
1825
1836
}
1826
1837
1838
+ RangeSet SymbolicRangeInferrer::handleConcreteModulo (Range LHS,
1839
+ llvm::APSInt Modulo,
1840
+ QualType T) {
1841
+ APSIntType ResultType = ValueFactory.getAPSIntType (T);
1842
+ llvm::APSInt Zero = ResultType.getZeroValue ();
1843
+ llvm::APSInt One = ResultType.getValue (1 );
1844
+
1845
+ if (Modulo == Zero)
1846
+ return RangeFactory.getEmptySet ();
1847
+
1848
+ // Quick path, this also avoids unary '-' overflow on MinValue modulo.
1849
+ if (Modulo == ValueFactory.getMinValue (T) ||
1850
+ Modulo == ValueFactory.getMaxValue (T))
1851
+ return RangeFactory.getRangeSet (LHS);
1852
+
1853
+ // Normalize to positive modulo since a % N == a % -N
1854
+ if (Modulo < 0 )
1855
+ Modulo = -Modulo;
1856
+
1857
+ auto ComputeModuloN = [&](llvm::APSInt From, llvm::APSInt To,
1858
+ llvm::APSInt N) -> RangeSet {
1859
+ assert (N > Zero && " Positive N expected!" );
1860
+ bool NonNegative = From >= Zero;
1861
+ assert (NonNegative == (To >= Zero) && " Signedness mismatch!" );
1862
+
1863
+ if (From > To)
1864
+ return RangeFactory.getEmptySet ();
1865
+
1866
+ llvm::APSInt N1 = N - One;
1867
+
1868
+ // spans [0, N - 1] if NonNegative or [-(N - 1), 0] otherwise.
1869
+ if ((To - From) / N > Zero)
1870
+ return {RangeFactory, ValueFactory.getValue (NonNegative ? Zero : -N1),
1871
+ ValueFactory.getValue (NonNegative ? N1 : Zero)};
1872
+
1873
+ llvm::APSInt Min = From % N;
1874
+ llvm::APSInt Max = To % N;
1875
+
1876
+ if (Min < Max) // [Min, Max]
1877
+ return {RangeFactory, ValueFactory.getValue (Min),
1878
+ ValueFactory.getValue (Max)};
1879
+
1880
+ // [0, Max] U [Min, N - 1] if NonNegative, or
1881
+ // [-(N - 1), Max] U [Min, 0] otherwise.
1882
+ const llvm::APSInt &Min1 = ValueFactory.getValue (NonNegative ? Zero : -N1);
1883
+ const llvm::APSInt &Max1 = ValueFactory.getValue (Max);
1884
+ RangeSet RS1{RangeFactory, Min1, Max1};
1885
+
1886
+ const llvm::APSInt &Min2 = ValueFactory.getValue (Min);
1887
+ const llvm::APSInt &Max2 = ValueFactory.getValue (NonNegative ? N1 : Zero);
1888
+ RangeSet RS2{RangeFactory, Min2, Max2};
1889
+
1890
+ return RangeFactory.unite (RS1, RS2);
1891
+ };
1892
+
1893
+ if (!LHS.Includes (Zero))
1894
+ return ComputeModuloN (LHS.From (), LHS.To (), Modulo);
1895
+
1896
+ // split over [From, -1] U [0, To] for easy handling.
1897
+ return RangeFactory.unite (ComputeModuloN (LHS.From (), -One, Modulo),
1898
+ ComputeModuloN (Zero, LHS.To (), Modulo));
1899
+ }
1900
+
1901
+ template <>
1902
+ RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Div>(Range LHS,
1903
+ Range RHS,
1904
+ QualType T) {
1905
+ const llvm::APSInt *DividerOrNull = RHS.getConcreteValue ();
1906
+ if (!DividerOrNull)
1907
+ return infer (T);
1908
+
1909
+ const llvm::APSInt &D = *DividerOrNull;
1910
+
1911
+ APSIntType ResultType = ValueFactory.getAPSIntType (T);
1912
+ llvm::APSInt Zero = ResultType.getZeroValue ();
1913
+ llvm::APSInt One = ResultType.getValue (1 );
1914
+ if (D == Zero)
1915
+ return RangeFactory.getEmptySet ();
1916
+
1917
+ if (D == -One) { // might overflow
1918
+ if (LHS.To ().isMinSignedValue ())
1919
+ return {RangeFactory, LHS.To (), LHS.To ()};
1920
+ else if (LHS.From ().isMinSignedValue ()) {
1921
+ const llvm::APSInt &From = ValueFactory.getValue ((LHS.From () + One) / D);
1922
+ const llvm::APSInt &To = ValueFactory.getValue (LHS.To () / D);
1923
+ RangeSet RS{RangeFactory, To, From};
1924
+ return RangeFactory.unite (RS, LHS.From ());
1925
+ }
1926
+ }
1927
+
1928
+ const llvm::APSInt &From = ValueFactory.getValue (LHS.From () / D);
1929
+ const llvm::APSInt &To = ValueFactory.getValue (LHS.To () / D);
1930
+ return {RangeFactory, D < Zero ? To : From, D < Zero ? From : To};
1931
+ }
1932
+
1827
1933
RangeSet SymbolicRangeInferrer::VisitBinaryOperator (RangeSet LHS,
1828
1934
BinaryOperator::Opcode Op,
1829
1935
RangeSet RHS, QualType T) {
@@ -1842,6 +1948,8 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
1842
1948
return VisitBinaryOperator<BO_And>(LHS, RHS, T);
1843
1949
case BO_Rem:
1844
1950
return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);
1951
+ case BO_Div:
1952
+ return VisitBinaryOperator<BO_Div>(LHS, RHS, T);
1845
1953
default :
1846
1954
return infer (T);
1847
1955
}
@@ -2073,13 +2181,62 @@ class ConstraintAssignor : public ConstraintAssignorBase<ConstraintAssignor> {
2073
2181
if (Sym->getOpcode () != BO_Rem)
2074
2182
return true ;
2075
2183
// a % b != 0 implies that a != 0.
2184
+ // Z3 verification:
2185
+ // (declare-const a Int)
2186
+ // (declare-const m Int)
2187
+ // (assert (not (= m 0)))
2188
+ // (assert (not (= (mod a m) 0)))
2189
+ // (assert (= a 0))
2190
+ // (check-sat)
2191
+ // ; unsat
2076
2192
if (!Constraint.containsZero ()) {
2077
2193
SVal SymSVal = Builder.makeSymbolVal (Sym->getLHS ());
2078
2194
if (auto NonLocSymSVal = SymSVal.getAs <nonloc::SymbolVal>()) {
2079
2195
State = State->assume (*NonLocSymSVal, true );
2080
2196
if (!State)
2081
2197
return false ;
2082
2198
}
2199
+ } else if (const auto *SIE = dyn_cast<SymIntExpr>(Sym);
2200
+ SIE && Constraint.encodesFalseRange ()) {
2201
+ // a % m == 0 && a in [x, y] && y - x < m implies that
2202
+ // a = (y < 0 ? x : y) / m * m which is a 'ConcreteInt'
2203
+ // where x and m are 'ConcreteInt'.
2204
+ //
2205
+ // Z3 verification:
2206
+ // (declare-const a Int)
2207
+ // (declare-const m Int)
2208
+ // (declare-const x Int)
2209
+ // (declare-const y Int)
2210
+ // (assert (= (mod a m) 0))
2211
+ // (assert (< (- y x) m))
2212
+ // (assert (and (>= a x) (<= a y)))
2213
+ // (assert (not (= a (* (div y m) m))))
2214
+ // (check-sat)
2215
+ // ; unsat
2216
+ BasicValueFactory &ValueFactory = RangeFactory.getValueFactory ();
2217
+ APSIntType ResultType = ValueFactory.getAPSIntType (SIE->getType ());
2218
+ llvm::APSInt N = SIE->getRHS ();
2219
+ if (N < 0 )
2220
+ N = -N;
2221
+ N = ResultType.convert (N);
2222
+
2223
+ SymbolRef Sym = SIE->getLHS ();
2224
+ RangeSet RS = SymbolicRangeInferrer::inferRange (RangeFactory, State, Sym);
2225
+ if (RS.size () == 1 ) {
2226
+ Range R = *RS.begin ();
2227
+ llvm::APSInt Distance = ResultType.convert (R.To ()).extend (64 ) -
2228
+ ResultType.convert (R.From ()).extend (64 );
2229
+ if (Distance < 0 ) // overflows
2230
+ return true ;
2231
+
2232
+ if (Distance < N.extend (64 )) {
2233
+ const llvm::APSInt &Point = ValueFactory.getValue (
2234
+ (ResultType.convert (R.To () > 0 ? R.To () : R.From ())) / N * N);
2235
+ State = assign (Sym, {RangeFactory, Point , Point });
2236
+ if (!State)
2237
+ return false ;
2238
+ }
2239
+ }
2083
2240
}
2084
2241
return true ;
2085
2242
}
0 commit comments