baloghadamsoftware updated this revision to Diff 159012.
baloghadamsoftware edited the summary of this revision.
baloghadamsoftware added a comment.

Completely rewritten: works correctly for modular arithmetic (multiplication), 
works correctly for truncation (division), only uses integers, no floats.


https://reviews.llvm.org/D49074

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
  lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
  test/Analysis/multiplicative-folding.c

Index: test/Analysis/multiplicative-folding.c
===================================================================
--- test/Analysis/multiplicative-folding.c
+++ test/Analysis/multiplicative-folding.c
@@ -467,6 +467,1442 @@
   }
 }
 
+void signed_multiplication_lt_0(int32_t n) {
+  if (n * 2 < 3) {
+    int32_t                  U1 = 0x80000001,
+            L2 = 0xc0000000, U2 = 1,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 < 3);
+    assert(U1 * 2 < 3);
+    assert((U1 + 1) * 2 >= 3);
+    assert(L2 * 2 < 3);
+    assert((L2 - 1) * 2 >= 3);
+    assert(U2 * 2 < 3);
+    assert((U2 + 1) * 2 >= 3);
+    assert(L3 * 2 < 3);
+    assert((L3 - 1) * 2 >= 3);
+    assert(INT_MAX * 2 < 3);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2){
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_lt_1(int32_t n) {
+  if (n * 2 < 4) {
+    int32_t                  U1 = 0x80000001,
+            L2 = 0xc0000000, U2 = 1,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 < 4);
+    assert(U1 * 2 < 4);
+    assert((U1 + 1) * 2 >= 4);
+    assert(L2 * 2 < 4);
+    assert((L2 - 1) * 2 >= 4);
+    assert(U2 * 2 < 4);
+    assert((U2 + 1) * 2 >= 4);
+    assert(L3 * 2 < 4);
+    assert((L3 - 1) * 2 >= 4);
+    assert(INT_MAX * 2 < 4);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2){
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_lt_2(int32_t n) {
+  if (n * 2 < 5) {
+    int32_t                  U1 = 0x80000002,
+            L2 = 0xc0000000, U2 = 2,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 < 5);
+    assert(U1 * 2 < 5);
+    assert((U1 + 1) * 2 >= 5);
+    assert(L2 * 2 < 5);
+    assert((L2 - 1) * 2 >= 5);
+    assert(U2 * 2 < 5);
+    assert((U2 + 1) * 2 >= 5);
+    assert(L3 * 2 < 5);
+    assert((L3 - 1) * 2 >= 5);
+    assert(INT_MAX * 2 < 5);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2){
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_lt_3(int32_t n) {
+  if (n * 3 < 4) {
+    int32_t                  U1 = 0xaaaaaaab,
+            L2 = 0xd5555556, U2 = 1,
+            L3 = 0x2aaaaaab, U3 = 0x55555556;
+
+    assert(INT_MIN * 3 < 4);
+    assert(U1 * 3 < 4);
+    assert((U1 + 1) * 3 >= 4);
+    assert(L2 * 3 < 4);
+    assert((L2 - 1) * 3 >= 4);
+    assert(U2 * 3 < 4);
+    assert((U2 + 1) * 3 >= 4);
+    assert(L3 * 3 < 4);
+    assert((L3 - 1) * 3 >= 4);
+    assert(U3 * 3 < 4);
+    assert((U3 + 1) * 3 >= 4);
+
+    if (n < (int32_t) 0xc0000000) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x15555556) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_lt_4(int32_t n) {
+  if (n * 6 < -2) {
+    int32_t L1 = 0x95555556, U1 = 0xaaaaaaaa,
+            L2 = 0xc0000000, U2 = 0x55555554,
+            L3 = 0xeaaaaaab, U3 = -1,
+            L4 = 0x15555556, U4 = 0x2aaaaaaa,
+            L5 = 0x40000000, U5 = 0x55555554,
+            L6 = 0x6aaaaaab;
+
+    assert(L1 * 6 < -2);
+    assert((L1 - 1) * 6 >= -2);
+    assert(U1 * 6 < -2);
+    assert((U1 + 1) * 6 >= -2);
+    assert(L2 * 6 < -2);
+    assert((L2 - 1) * 6 >= -2);
+    assert(U2 * 6 < -2);
+    assert((U2 + 1) * 6 >= -2);
+    assert(L3 * 6 < -2);
+    assert((L3 - 1) * 6 >= -2);
+    assert(U3 * 6 < -2);
+    assert((U3 + 1) * 6 >= -2);
+    assert(L4 * 6 < -2);
+    assert((L4 - 1) * 6 >= -2);
+    assert(U4 * 6 < -2);
+    assert((U4 + 1) * 6 >= -2);
+    assert(L5 * 6 < -2);
+    assert((L5 - 1) * 6 >= -2);
+    assert(U5 * 6 < -2);
+    assert((U5 + 1) * 6 >= -2);
+    assert(L6 * 6 < -2);
+    assert((L6 - 1) * 6 >= -2);
+    assert(INT_MAX * 6 < -2);
+
+    if (n < (int32_t) 0xb5555555) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xdfffffff) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x0aaaaaaa) {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x35555555) {
+      clang_analyzer_eval(n < L4); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U4); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x5fffffff) {
+      clang_analyzer_eval(n < L5); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U5); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L6); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_division_lt_0(int32_t n) {
+  if (n / 4 < 0) {
+    const int32_t C = -4;
+
+    assert(C / 4 < 0);
+    assert((C + 1) / 4 >= 0);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_lt_1(int32_t n) {
+  if (n / 3 < 2) {
+    const int32_t C = 5;
+
+    assert(C / 3 < 2);
+    assert((C + 1) / 3 >= 2);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_lt_2(int32_t n) {
+  if (n / 5 < -7) {
+    const int32_t C = -40;
+
+    assert(C / 5 < -7);
+    assert((C + 1) / 5 >= -7);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_multiplication_lt_0(uint32_t n) {
+  if (n * 2 < 3) {
+    uint32_t                  U1 = 1,
+             L2 = 0x80000000, U2 = 0x80000001;
+
+    assert(U1 * 2 < 3);
+    assert((U1 + 1) * 2 >= 3);
+    assert(L2 * 2 < 3);
+    assert((L2 - 1) * 2 >= 3);
+    assert(U2 * 2 < 3);
+    assert((U2 + 1) * 2 >= 3);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_lt_1(uint32_t n) {
+  if (n * 2 < 4) {
+    uint32_t                  U1 = 1,
+             L2 = 0x80000000, U2 = 0x80000001;
+
+    assert(U1 * 2 < 4);
+    assert((U1 + 1) * 2 >= 4);
+    assert(L2 * 2 < 4);
+    assert((L2 - 1) * 2 >= 4);
+    assert(U2 * 2 < 4);
+    assert((U2 + 1) * 2 >= 4);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_lt_2(uint32_t n) {
+  if (n * 2 < 5) {
+    uint32_t                  U1 = 2,
+             L2 = 0x80000000, U2 = 0x80000002;
+
+    assert(U1 * 2 < 5);
+    assert((U1 + 1) * 2 >= 5);
+    assert(L2 * 2 < 5);
+    assert((L2 - 1) * 2 >= 5);
+    assert(U2 * 2 < 5);
+    assert((U2 + 1) * 2 >= 5);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_lt_3(uint32_t n) {
+  if (n * 3 < 4) {
+    uint32_t U1 = 1, C2 = 0x55555556, C3 = 0xaaaaaaab;
+
+    assert(U1 * 3 < 4);
+    assert((U1 + 1) * 3 >= 4);
+    assert(C2 * 3 < 4);
+    assert((C2 - 1) * 3 >= 4);
+    assert((C2 + 1) * 3 >= 4);
+    assert(C3 * 3 < 4);
+    assert((C3 - 1) * 3 >= 4);
+    assert((C3 + 1) * 3 >= 4);
+
+    if (n < 0x2aaaaaab) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < 0x80000000) {
+      clang_analyzer_eval(n < C2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n == C2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > C2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < C3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n == C3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > C3); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_division_lt_0(uint32_t n) {
+  if (n / 3 < 2) {
+    const uint32_t C = 5;
+
+    assert(C / 3 < 2);
+    assert((C + 1) / 3 >= 2);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_multiplication_le_0(int32_t n) {
+  if (n * 2 <= 3) {
+    int32_t                  U1 = 0x80000001,
+            L2 = 0xc0000000, U2 = 1,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 <= 3);
+    assert(U1 * 2 <= 3);
+    assert((U1 + 1) * 2 > 3);
+    assert(L2 * 2 <= 3);
+    assert((L2 - 1) * 2 > 3);
+    assert(U2 * 2 <= 3);
+    assert((U2 + 1) * 2 > 3);
+    assert(L3 * 2 <= 3);
+    assert((L3 - 1) * 2 > 3);
+    assert(INT_MAX * 2 <= 3);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_le_1(int32_t n) {
+  if (n * 2 <= 4) {
+    int32_t                  U1 = 0x80000002,
+            L2 = 0xc0000000, U2 = 2,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 <= 4);
+    assert(U1 * 2 <= 4);
+    assert((U1 + 1) * 2 > 4);
+    assert(L2 * 2 <= 4);
+    assert((L2 - 1) * 2 > 4);
+    assert(U2 * 2 <= 4);
+    assert((U2 + 1) * 2 > 4);
+    assert(L3 * 2 <= 4);
+    assert((L3 - 1) * 2 > 4);
+    assert(INT_MAX * 2 <= 4);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2){
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_le_2(int32_t n) {
+  if (n * 2 <= 5) {
+    int32_t                  U1 = 0x80000002,
+            L2 = 0xc0000000, U2 = 2,
+            L3 = 0x40000000;
+
+    assert(INT_MIN * 2 <= 5);
+    assert(U1 * 2 <= 5);
+    assert((U1 + 1) * 2 > 5);
+    assert(L2 * 2 <= 5);
+    assert((L2 - 1) * 2 > 5);
+    assert(U2 * 2 <= 5);
+    assert((U2 + 1) * 2 > 5);
+    assert(L3 * 2 <= 5);
+    assert((L3 - 1) * 2 > 5);
+    assert(INT_MAX * 2 <= 5);
+
+    if (n < INT_MIN / 2) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_le_3(int32_t n) {
+  if (n * 3 <= 4) {
+    int32_t                  U1 = 0xaaaaaaac,
+            L2 = 0xd5555556, U2 = 1,
+            L3 = 0x2aaaaaab, U3 = 0x55555556;
+
+    assert(INT_MIN * 3 <= 4);
+    assert(U1 * 3 <= 4);
+    assert((U1 + 1) * 3 > 4);
+    assert(L2 * 3 <= 4);
+    assert((L2 - 1) * 3 > 4);
+    assert(U2 * 3 <= 4);
+    assert((U2 + 1) * 3 > 4);
+    assert(L3 * 3 <= 4);
+    assert((L3 - 1) * 3 > 4);
+    assert(U3 * 3 <= 4);
+    assert((U3 + 1) * 3 > 4);
+
+    if (n < (int32_t) 0xc0000001) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x15555556) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_le_4(int32_t n) {
+  if (n * 6 <= -2) {
+    int32_t L1 = 0x95555556, U1 = 0xaaaaaaaa,
+            L2 = 0xc0000000, U2 = 0x55555555,
+            L3 = 0xeaaaaaab, U3 = -1,
+            L4 = 0x15555556, U4 = 0x2aaaaaaa,
+            L5 = 0x40000000, U5 = 0x55555555,
+            L6 = 0x6aaaaaab;
+
+    assert(L1 * 6 <= -2);
+    assert((L1 - 1) * 6 > -2);
+    assert(U1 * 6 <= -2);
+    assert((U1 + 1) * 6 > -2);
+    assert(L2 * 6 <= -2);
+    assert((L2 - 1) * 6 > -2);
+    assert(U2 * 6 <= -2);
+    assert((U2 + 1) * 6 > -2);
+    assert(L3 * 6 <= -2);
+    assert((L3 - 1) * 6 > -2);
+    assert(U3 * 6 <= -2);
+    assert((U3 + 1) * 6 > -2);
+    assert(L4 * 6 <= -2);
+    assert((L4 - 1) * 6 > -2);
+    assert(U4 * 6 <= -2);
+    assert((U4 + 1) * 6 > -2);
+    assert(L5 * 6 <= -2);
+    assert((L5 - 1) * 6 > -2);
+    assert(U5 * 6 <= -2);
+    assert((U5 + 1) * 6 > -2);
+    assert(L6 * 6 <= -2);
+    assert((L6 - 1) * 6 > -2);
+    assert(INT_MAX * 6 <= -2);
+
+    if (n < (int32_t) 0xb5555555) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xe0000000) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x0aaaaaaa) {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x35555555) {
+      clang_analyzer_eval(n < L4); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U4); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x60000000) {
+      clang_analyzer_eval(n < L5); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U5); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L6); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_division_le_0(int32_t n) {
+  if (n / 4 <= 0) {
+    const int32_t C = 3;
+
+    assert(C / 4 <= 0);
+    assert((C + 1) / 4 > 0);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_le_1(int32_t n) {
+  if (n / 3 <= 2) {
+    const int32_t C = 8;
+
+    assert(C / 3 <= 2);
+    assert((C + 1) / 3 > 2);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_le_2(int32_t n) {
+  if (n / 5 <= -7) {
+    const int32_t C = -35;
+
+    assert(C / 5 <= -7);
+    assert((C + 1) / 5 > -7);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_multiplication_le_0(uint32_t n) {
+  if (n * 2 <= 3) {
+    uint32_t                  U1 = 1,
+             L2 = 0x80000000, U2 = 0x80000001;
+
+    assert(U1 * 2 <= 3);
+    assert((U1 + 1) * 2 > 3);
+    assert(L2 * 2 <= 3);
+    assert((L2 - 1) * 2 > 3);
+    assert(U2 * 2 <= 3);
+    assert((U2 + 1) * 2 > 3);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_le_1(uint32_t n) {
+  if (n * 2 <= 4) {
+    uint32_t                  U1 = 2,
+             L2 = 0x80000000, U2 = 0x80000002;
+
+    assert(U1 * 2 <= 4);
+    assert((U1 + 1) * 2 > 4);
+    assert(L2 * 2 <= 4);
+    assert((L2 - 1) * 2 > 4);
+    assert(U2 * 2 <= 4);
+    assert((U2 + 1) * 2 > 4);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_le_2(uint32_t n) {
+  if (n * 2 <= 5) {
+    uint32_t                  U1 = 2,
+             L2 = 0x80000000, U2 = 0x80000002;
+
+    assert(U1 * 2 <= 5);
+    assert((U1 + 1) * 2 > 5);
+    assert(L2 * 2 <= 5);
+    assert((L2 - 1) * 2 > 5);
+    assert(U2 * 2 <= 5);
+    assert((U2 + 1) * 2 > 5);
+
+    if (n < UINT_MAX / 2) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_multiplication_le_3(uint32_t n) {
+  if (n * 3 <= 4) {
+    uint32_t                  U1 = 1,
+                     C2 = 0x55555556,
+             L3 = 0xaaaaaaab, U3 = 0xaaaaaaac;
+
+    assert(U1 * 3 <= 4);
+    assert((U1 + 1) * 3 > 4);
+    assert(C2 * 3 <= 4);
+    assert((C2 - 1) * 3 > 4);
+    assert((C2 + 1) * 3 > 4);
+    assert(L3 * 3 <= 4);
+    assert((L3 - 1) * 3 > 4);
+    assert(U3 * 3 <= 4);
+    assert((U3 + 1) * 3 > 4);
+
+    if (n < 0x2aaaaaab) {
+      clang_analyzer_eval(n == 0); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < 0x80000000) {
+      clang_analyzer_eval(n < C2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n == C2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > C2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void unsigned_division_le_0(uint32_t n) {
+  if (n / 4 <= 0) {
+    const uint32_t C = 3;
+
+    assert(C / 4 <= 0);
+    assert((C + 1) / 4 > 0);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_division_le_1(uint32_t n) {
+  if (n / 3 <= 2) {
+    const uint32_t C = 8;
+
+    assert(C / 3 <= 2);
+    assert((C + 1) / 3 > 2);
+
+    clang_analyzer_eval(n <= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n > C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_multiplication_gt_0(int32_t n) {
+  if (n * 2 > 3) {
+    int32_t L1 = 0x80000002, U1 = 0xbfffffff,
+            L2 = 2,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 > 3);
+    assert((L1 - 1) * 2 <= 3);
+    assert(U1 * 2 > 3);
+    assert((U1 + 1) * 2 <= 3);
+    assert(L2 * 2 > 3);
+    assert((L2 - 1) * 2 <= 3);
+    assert(U2 * 2 > 3);
+    assert((U2 + 1) * 2 <= 3);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_gt_1(int32_t n) {
+  if (n * 2 > 4) {
+    int32_t L1 = 0x80000003, U1 = 0xbfffffff,
+            L2 = 3,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 > 4);
+    assert((L1 - 1) * 2 <= 4);
+    assert(U1 * 2 > 4);
+    assert((U1 + 1) * 2 <= 4);
+    assert(L2 * 2 > 4);
+    assert((L2 - 1) * 2 <= 4);
+    assert(U2 * 2 > 4);
+    assert((U2 + 1) * 2 <= 4);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_gt_2(int32_t n) {
+  if (n * 2 > 5) {
+    int32_t L1 = 0x80000003, U1 = 0xbfffffff,
+            L2 = 3,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 > 5);
+    assert((L1 - 1) * 2 <= 5);
+    assert(U1 * 2 > 5);
+    assert((U1 + 1) * 2 <= 5);
+    assert(L2 * 2 > 5);
+    assert((L2 - 1) * 2 <= 5);
+    assert(U2 * 2 > 5);
+    assert((U2 + 1) * 2 <= 5);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_gt_3(int32_t n) {
+  if (n * 3 > 4) {
+    int32_t L1 = 0xaaaaaaad, U1 = 0xd5555555,
+            L2 = 2,          U2 = 0x2aaaaaaa,
+            L3 = 0x55555557;
+
+    assert(L1 * 3 > 4);
+    assert((L1 - 1) * 3 <= 4);
+    assert(U1 * 3 > 4);
+    assert((U1 + 1) * 3 <= 4);
+    assert(L2 * 3 > 4);
+    assert((L2 - 1) * 3 <= 4);
+    assert(U2 * 3 > 4);
+    assert((U2 + 1) * 3 <= 4);
+    assert(L3 * 3 > 4);
+    assert((L3 - 1) * 3 <= 4);
+    assert(INT_MAX * 3 > 4);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_gt_4(int32_t n) {
+  if (n * 6 > -2) {
+    int32_t                  U1 = 0x95555555,
+            L2 = 0xaaaaaaab, U2 = 0xbfffffff,
+            L3 = 0xd5555556, U3 = 0xeaaaaaaa,
+            L4 = 0,          U4 = 0x15555555,
+            L5 = 0x2aaaaaab, U5 = 0x3fffffff,
+            L6 = 0x55555556, U6 = 0x6aaaaaaa;
+
+    assert(INT_MIN * 6 > -2);
+    assert(U1 * 6 > -2);
+    assert((U1 + 1) * 6 <= -2);
+    assert(L2 * 6 > -2);
+    assert((L2 - 1) * 6 <= -2);
+    assert(U2 * 6 > -2);
+    assert((U2 + 1) * 6 <= -2);
+    assert(L3 * 6 > -2);
+    assert((L3 - 1) * 6 <= -2);
+    assert(U3 * 6 > -2);
+    assert((U3 + 1) * 6 <= -2);
+    assert(L4 * 6 > -2);
+    assert((L4 - 1) * 6 <= -2);
+    assert(U4 * 6 > -2);
+    assert((U4 + 1) * 6 <= -2);
+    assert(L5 * 6 > -2);
+    assert((L5 - 1) * 6 <= -2);
+    assert(U5 * 6 > -2);
+    assert((U5 + 1) * 6 <= -2);
+    assert(L6 * 6 > -2);
+    assert((L6 - 1) * 6 <= -2);
+    assert(U6 * 6 > -2);
+    assert((U6 + 1) * 6 <= -2);
+
+    if (n < (int32_t) 0xa0000000) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xcaaaaaaa) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xf5555555) {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x20000000) {
+      clang_analyzer_eval(n < L4); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U4); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x4aaaaaaa) {
+      clang_analyzer_eval(n < L5); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U5); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L6); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U6); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_division_gt_0(int32_t n) {
+  if (n / 4 > 0) {
+    const int32_t C = 4;
+
+    assert(C / 4 > 0);
+    assert((C - 1) / 4 <= 0);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_gt_1(int32_t n) {
+  if (n / 3 > 2) {
+    const int32_t C = 9;
+
+    assert(C / 3 > 2);
+    assert((C - 1) / 3 <= 2);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_gt_2(int32_t n) {
+  if (n / 5 > -7) {
+    const int32_t C = -34;
+
+    assert(C / 5 > -7);
+    assert((C - 1) / 5 <= -7);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_multiplication_gt_0(uint32_t n) {
+  if (n * 2 > 3) {
+    uint32_t L1 = 2,          U1 = 0x7fffffff,
+             L2 = 0x80000002;
+
+    assert(L1 * 2 > 3);
+    assert((L1 - 1) * 2 <= 3);
+    assert(U1 * 2 > 3);
+    assert((U1 + 1) * 2 <= 3);
+    assert(L2 * 2 > 3);
+    assert((L2 - 1) * 2 <= 3);
+    assert(UINT_MAX * 2 > 3);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_gt_1(uint32_t n) {
+  if (n * 2 > 4) {
+    uint32_t L1 = 3,          U1 = 0x7fffffff,
+             L2 = 0x80000003;
+
+    assert(L1 * 2 > 4);
+    assert((L1 - 1) * 2 <= 4);
+    assert(U1 * 2 > 4);
+    assert((U1 + 1) * 2 <= 4);
+    assert(L2 * 2 > 4);
+    assert((L2 - 1) * 2 <= 4);
+    assert(UINT_MAX * 2 > 4);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_gt_2(uint32_t n) {
+  if (n * 2 > 5) {
+    uint32_t L1 = 3,          U1 = 0x7fffffff,
+             L2 = 0x80000003;
+
+    assert(L1 * 2 > 5);
+    assert((L1 - 1) * 2 <= 5);
+    assert(U1 * 2 > 5);
+    assert((U1 + 1) * 2 <= 5);
+    assert(L2 * 2 > 5);
+    assert((L2 - 1) * 2 <= 5);
+    assert(UINT_MAX * 2 > 5);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_gt_3(uint32_t n) {
+  if (n * 3 > 4) {
+    uint32_t L1 = 2,          U1 = 0x55555555,
+             L2 = 0x55555557, U2 = 0xaaaaaaaa,
+             L3 = 0xaaaaaaad;
+
+    assert(L1 * 3 > 4);
+    assert((L1 - 1) * 3 <= 4);
+    assert(U1 * 3 > 4);
+    assert((U1 + 1) * 3 <= 4);
+    assert(L2 * 3 > 4);
+    assert((L2 - 1) * 3 <= 4);
+    assert(U2 * 3 > 4);
+    assert((U2 + 1) * 3 <= 4);
+    assert(L3 * 3 > 4);
+    assert((L3 - 1) * 3 <= 4);
+    assert(INT_MAX * 3 > 4);
+
+    if (n < UINT_MAX / 3 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < 2 * (UINT_MAX / 3 + 1)) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_division_gt_0(uint32_t n) {
+  if (n / 4 > 0) {
+    const uint32_t C = 4;
+
+    assert(C / 4 > 0);
+    assert((C - 1) / 4 <= 0);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_division_gt_1(uint32_t n) {
+  if (n / 3 > 2) {
+    const uint32_t C = 9;
+
+    assert(C / 3 > 2);
+    assert((C - 1) / 3 <= 2);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_multiplication_ge_0(int32_t n) {
+  if (n * 2 >= 3) {
+    int32_t L1 = 0x80000002, U1 = 0xbfffffff,
+            L2 = 2,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 >= 3);
+    assert((L1 - 1) * 2 < 3);
+    assert(U1 * 2 >= 3);
+    assert((U1 + 1) * 2 < 3);
+    assert(L2 * 2 >= 3);
+    assert((L2 - 1) * 2 < 3);
+    assert(U2 * 2 >= 3);
+    assert((U2 + 1) * 2 < 3);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_ge_1(int32_t n) {
+  if (n * 2 >= 4) {
+    int32_t L1 = 0x80000002, U1 = 0xbfffffff,
+            L2 = 2,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 >= 4);
+    assert((L1 - 1) * 2 < 4);
+    assert(U1 * 2 >= 4);
+    assert((U1 + 1) * 2 < 4);
+    assert(L2 * 2 >= 4);
+    assert((L2 - 1) * 2 < 4);
+    assert(U2 * 2 >= 4);
+    assert((U2 + 1) * 2 < 4);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_ge_2(int32_t n) {
+  if (n * 2 >= 5) {
+    int32_t L1 = 0x80000003, U1 = 0xbfffffff,
+            L2 = 3,          U2 = 0x3fffffff;
+
+    assert(L1 * 2 >= 5);
+    assert((L1 - 1) * 2 < 5);
+    assert(U1 * 2 >= 5);
+    assert((U1 + 1) * 2 < 5);
+    assert(L2 * 2 >= 5);
+    assert((L2 - 1) * 2 < 5);
+    assert(U2 * 2 >= 5);
+    assert((U2 + 1) * 2 < 5);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_multiplication_ge_3(int32_t n) {
+  if (n * 3 >= 4) {
+    int32_t L1 = 0xaaaaaaac, U1 = 0xd5555555,
+            L2 = 2,          U2 = 0x2aaaaaaa,
+            L3 = 0x55555557;
+
+    assert(L1 * 3 >= 4);
+    assert((L1 - 1) * 3 < 4);
+    assert(U1 * 3 >= 4);
+    assert((U1 + 1) * 3 < 4);
+    assert(L2 * 3 >= 4);
+    assert((L2 - 1) * 3 < 4);
+    assert(U2 * 3 >= 4);
+    assert((U2 + 1) * 3 < 4);
+    assert(L3 * 3 >= 4);
+    assert((L3 - 1) * 3 < 4);
+    assert(INT_MAX * 3 >= 4);
+
+    if (n < 0) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < INT_MAX / 2) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == INT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void signed_multiplication_ge_4(int32_t n) {
+  if (n * 6 >= -2) {
+    int32_t                  U1 = 0x95555555,
+            L2 = 0xaaaaaaab, U2 = 0xbfffffff,
+            L3 = 0xd5555555, U3 = 0xeaaaaaaa,
+            L4 = 0,          U4 = 0x15555555,
+            L5 = 0x2aaaaaab, U5 = 0x3fffffff,
+            L6 = 0x55555555, U6 = 0x6aaaaaaa;
+
+    assert(INT_MIN * 6 >= -2);
+    assert(U1 * 6 >= -2);
+    assert((U1 + 1) * 6 < -2);
+    assert(L2 * 6 >= -2);
+    assert((L2 - 1) * 6 < -2);
+    assert(U2 * 6 >= -2);
+    assert((U2 + 1) * 6 < -2);
+    assert(L3 * 6 >= -2);
+    assert((L3 - 1) * 6 < -2);
+    assert(U3 * 6 >= -2);
+    assert((U3 + 1) * 6 < -2);
+    assert(L4 * 6 >= -2);
+    assert((L4 - 1) * 6 < -2);
+    assert(U4 * 6 >= -2);
+    assert((U4 + 1) * 6 < -2);
+    assert(L5 * 6 >= -2);
+    assert((L5 - 1) * 6 < -2);
+    assert(U5 * 6 >= -2);
+    assert((U5 + 1) * 6 < -2);
+    assert(L6 * 6 >= -2);
+    assert((L6 - 1) * 6 < -2);
+    assert(U6 * 6 >= -2);
+    assert((U6 + 1) * 6 < -2);
+
+    if (n < (int32_t) 0xa0000000) {
+      clang_analyzer_eval(n == INT_MIN); //expected-warning{{UNKNOWN}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xcaaaaaaa) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0xf5555555) {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U3); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x20000000) {
+      clang_analyzer_eval(n < L4); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U4); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U4); //expected-warning{{FALSE}}
+    } else if (n < (int32_t) 0x4aaaaaaa) {
+      clang_analyzer_eval(n < L5); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U5); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U5); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L6); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U6); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U6); //expected-warning{{FALSE}}
+    }
+  }
+}
+
+void signed_division_ge_0(int32_t n) {
+  if (n / 4 >= 0) {
+    const int32_t C = -3;
+
+    assert(C / 4 >= 0);
+    assert((C - 1) / 4 < 0);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_ge_1(int32_t n) {
+  if (n / 3 >= 2) {
+    const int32_t C = 6;
+
+    assert(C / 3 >= 2);
+    assert((C - 1) / 3 < 2);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void signed_division_ge_2(int32_t n) {
+  if (n / 5 >= -7) {
+    const int32_t C = -39;
+
+    assert(C / 5 >= -7);
+    assert((C - 1) / 5 < -7);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
+void unsigned_multiplication_ge_0(uint32_t n) {
+  if (n * 2 >= 3) {
+    uint32_t L1 = 2,          U1 = 0x7fffffff,
+             L2 = 0x80000002;
+
+    assert(L1 * 2 >= 3);
+    assert((L1 - 1) * 2 < 3);
+    assert(U1 * 2 >= 3);
+    assert((U1 + 1) * 2 < 3);
+    assert(L2 * 2 >= 3);
+    assert((L2 - 1) * 2 < 3);
+    assert(UINT_MAX * 2 >= 3);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_ge_1(uint32_t n) {
+  if (n * 2 >= 4) {
+    uint32_t L1 = 2,          U1 = 0x7fffffff,
+             L2 = 0x80000002;
+
+    assert(L1 * 2 >= 4);
+    assert((L1 - 1) * 2 < 4);
+    assert(U1 * 2 >= 4);
+    assert((U1 + 1) * 2 < 4);
+    assert(L2 * 2 >= 4);
+    assert((L2 - 1) * 2 < 4);
+    assert(UINT_MAX * 2 >= 4);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_ge_2(uint32_t n) {
+  if (n * 2 >= 5) {
+    uint32_t L1 = 3,          U1 = 0x7fffffff,
+             L2 = 0x80000003;
+
+    assert(L1 * 2 >= 5);
+    assert((L1 - 1) * 2 < 5);
+    assert(U1 * 2 >= 5);
+    assert((U1 + 1) * 2 < 5);
+    assert(L2 * 2 >= 5);
+    assert((L2 - 1) * 2 < 5);
+    assert(UINT_MAX * 2 >= 5);
+
+    if (n < UINT_MAX / 2 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_multiplication_ge_3(uint32_t n) {
+  if (n * 3 >= 4) {
+    uint32_t L1 = 2,          U1 = 0x55555555,
+             L2 = 0x55555557, U2 = 0xaaaaaaaa,
+             L3 = 0xaaaaaaac;
+
+    assert(L1 * 3 >= 4);
+    assert((L1 - 1) * 3 < 4);
+    assert(U1 * 3 >= 4);
+    assert((U1 + 1) * 3 < 4);
+    assert(L2 * 3 >= 4);
+    assert((L2 - 1) * 3 < 4);
+    assert(U2 * 3 >= 4);
+    assert((U2 + 1) * 3 < 4);
+    assert(L3 * 3 >= 4);
+    assert((L3 - 1) * 3 < 4);
+    assert(INT_MAX * 3 >= 4);
+
+    if (n < UINT_MAX / 3 + 1) {
+      clang_analyzer_eval(n < L1); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U1); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U1); //expected-warning{{FALSE}}
+    } else if (n < 2 * (UINT_MAX / 3 + 1)) {
+      clang_analyzer_eval(n < L2); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n <= U2); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n > U2); //expected-warning{{FALSE}}
+    } else {
+      clang_analyzer_eval(n < L3); //expected-warning{{FALSE}}
+      clang_analyzer_eval(n >= L3); //expected-warning{{TRUE}}
+      clang_analyzer_eval(n == UINT_MAX); //expected-warning{{UNKNOWN}}
+    }
+  }
+}
+
+void unsigned_division_ge_0(uint32_t n) {
+  if (n / 3 >= 2) {
+    const uint32_t C = 6;
+
+    assert(C / 3 >= 2);
+    assert((C - 1) / 3 < 2);
+
+    clang_analyzer_eval(n >= C); //expected-warning{{TRUE}}
+    clang_analyzer_eval(n < C); //expected-warning{{FALSE}}
+  }
+}
+
 void additive(int32_t n) {
   if (n * 2 + 1 == 4) {
     clang_analyzer_warnIfReached(); // no-warning
Index: lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
+++ lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
@@ -82,21 +82,27 @@
   SymbolRef AdjustedSym = Sym;
   computeAdjustment(AdjustedSym, Adjustment);
 
+  ScalingFactor Scale = {WraparoundType.getValue(1), false};
+  SymbolRef ScaledSym = AdjustedSym;
+  computeScale(ScaledSym, Scale);
+
   // Convert the right-hand side integer as necessary.
   APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From));
   llvm::APSInt ConvertedFrom = ComparisonType.convert(From);
   llvm::APSInt ConvertedTo = ComparisonType.convert(To);
 
   // Prefer unsigned comparisons.
   if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
-      ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
+      ComparisonType.isUnsigned() && !WraparoundType.isUnsigned()) {
+    Scale.Val.setIsSigned(false);
     Adjustment.setIsSigned(false);
+  }
 
   if (InRange)
     return assumeSymWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
-                                         ConvertedTo, Adjustment);
+                                         ConvertedTo, Scale, Adjustment);
   return assumeSymOutsideInclusiveRange(State, AdjustedSym, ConvertedFrom,
-                                        ConvertedTo, Adjustment);
+                                        ConvertedTo, Scale, Adjustment);
 }
 
 ProgramStateRef
@@ -157,9 +163,7 @@
   // SimpleConstraintManager to handle the scaling.
 
   ScalingFactor Scale = {WraparoundType.getValue(1), false};
-  // FIXME: For now scaling only works for == and !=
-  if (Op == BO_EQ || Op == BO_NE)
-    computeScale(Sym, Scale);
+  computeScale(Sym, Scale);
 
   // Convert the right-hand side integer as necessary.
   APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
@@ -183,16 +187,16 @@
     return assumeSymNE(State, Sym, ConvertedInt, Scale, Adjustment);
 
   case BO_GT:
-    return assumeSymGT(State, Sym, ConvertedInt, Adjustment);
+    return assumeSymGT(State, Sym, ConvertedInt, Scale, Adjustment);
 
   case BO_GE:
-    return assumeSymGE(State, Sym, ConvertedInt, Adjustment);
+    return assumeSymGE(State, Sym, ConvertedInt, Scale, Adjustment);
 
   case BO_LT:
-    return assumeSymLT(State, Sym, ConvertedInt, Adjustment);
+    return assumeSymLT(State, Sym, ConvertedInt, Scale, Adjustment);
 
   case BO_LE:
-    return assumeSymLE(State, Sym, ConvertedInt, Adjustment);
+    return assumeSymLE(State, Sym, ConvertedInt, Scale, Adjustment);
   } // end switch
 }
 
Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -260,27 +260,33 @@
 
   ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
                               const llvm::APSInt &V,
+                              const ScalingFactor &Scale,
                               const llvm::APSInt &Adjustment) override;
 
   ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
                               const llvm::APSInt &V,
+                              const ScalingFactor &Scale,
                               const llvm::APSInt &Adjustment) override;
 
   ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
                               const llvm::APSInt &V,
+                              const ScalingFactor &Scale,
                               const llvm::APSInt &Adjustment) override;
 
   ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
                               const llvm::APSInt &V,
+                              const ScalingFactor &Scale,
                               const llvm::APSInt &Adjustment) override;
 
   ProgramStateRef assumeSymWithinInclusiveRange(
       ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-      const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
+      const llvm::APSInt &To, const ScalingFactor &Scale,
+      const llvm::APSInt &Adjustment) override;
 
   ProgramStateRef assumeSymOutsideInclusiveRange(
       ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-      const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
+      const llvm::APSInt &To, const ScalingFactor &Scale,
+      const llvm::APSInt &Adjustment) override;
 
 private:
   RangeSet::Factory F;
@@ -291,22 +297,28 @@
 
   RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
                          const llvm::APSInt &Int,
+                         const ScalingFactor &Scale,
                          const llvm::APSInt &Adjustment);
   RangeSet getSymGTRange(ProgramStateRef St, SymbolRef Sym,
                          const llvm::APSInt &Int,
+                         const ScalingFactor &Scale,
                          const llvm::APSInt &Adjustment);
   RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym,
                          const llvm::APSInt &Int,
+                         const ScalingFactor &Scale,
                          const llvm::APSInt &Adjustment);
   RangeSet getSymLERange(llvm::function_ref<RangeSet()> RS,
                          const llvm::APSInt &Int,
+                         const ScalingFactor &Scale,
                          const llvm::APSInt &Adjustment);
   RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym,
                          const llvm::APSInt &Int,
+                         const ScalingFactor &Scale,
                          const llvm::APSInt &Adjustment);
 
   bool rescale(llvm::APSInt &Int, const ScalingFactor &Scale,
-               const llvm::APSInt &Index);
+               const llvm::APSInt &Index,
+               const ScalingFactor::RoundingMode Rounding);
 };
 
 } // end anonymous namespace
@@ -514,9 +526,11 @@
   return nullptr;
 }
 
-bool RangeConstraintManager::rescale(llvm::APSInt &Int,
-                                     const ScalingFactor &Scale,
-                                     const llvm::APSInt &Index) {
+bool
+RangeConstraintManager::rescale(llvm::APSInt &Int,
+                                const ScalingFactor &Scale,
+                                const llvm::APSInt &Index,
+                                const ScalingFactor::RoundingMode Rounding) {
   if (Scale.Val == 1)
     return true;
 
@@ -544,7 +558,22 @@
     llvm::APSInt Frac = Remainder + Index * PeriodFrac;
     Int = Quotient + Index * PeriodInt + Frac / Scale.Val;
 
-    return (Frac % Scale.Val).isNullValue();
+    switch(Rounding) {
+    default:
+      llvm_unreachable("Invalid rounding mode!");
+    case ScalingFactor::rmExact:
+      return (Frac % Scale.Val).isNullValue();
+    case ScalingFactor::rmDown:
+      if (Frac % Scale.Val < ScaleType.getZeroValue()) {
+        --Int;
+      }
+      return true;
+    case ScalingFactor::rmUp:
+      if (Frac % Scale.Val > ScaleType.getZeroValue()) {
+        ++Int;
+      }
+      return true;
+    }
   }
 }
 
@@ -579,7 +608,7 @@
       I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
 
     llvm::APSInt ScInt = AdjInt;
-    if (!rescale(ScInt, Scale, I))
+    if (!rescale(ScInt, Scale, I, ScalingFactor::rmExact))
       continue;
 
     llvm::APSInt Lower = ScInt;
@@ -618,7 +647,7 @@
       I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
   
     llvm::APSInt ScInt = AdjInt;
-    if (!rescale(ScInt, Scale, I))
+    if (!rescale(ScInt, Scale, I, ScalingFactor::rmExact))
       continue;
 
     llvm::APSInt Lower = ScInt;
@@ -641,6 +670,7 @@
 RangeSet RangeConstraintManager::getSymLTRange(ProgramStateRef St,
                                                SymbolRef Sym,
                                                const llvm::APSInt &Int,
+                                               const ScalingFactor &Scale,
                                                const llvm::APSInt &Adjustment) {
   // Before we do any real work, see if the value can even show up.
   APSIntType AdjustmentType(Adjustment);
@@ -659,24 +689,42 @@
   if (ComparisonVal == Min)
     return F.getEmptySet();
 
-  llvm::APSInt Lower = Min - Adjustment;
-  llvm::APSInt Upper = ComparisonVal - Adjustment;
-  --Upper;
+  llvm::APSInt AdjCompVal = ComparisonVal - Adjustment;
+  llvm::APSInt AdjMin = Min - Adjustment;
+  RangeSet New = F.getEmptySet();
+  for (llvm::APSInt I = AdjustmentType.getZeroValue();
+      I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
+
+    llvm::APSInt Lower = AdjMin;
+    rescale(Lower, Scale, I, ScalingFactor::rmUp);
+    llvm::APSInt Upper = AdjCompVal;
+    rescale(Upper, Scale, I, ScalingFactor::rmUp);
+    Upper -= (Scale.Reciprocal && Upper <= 0) ? Scale.Val :
+                                               AdjustmentType.getValue(1);
+
+    if (Lower == Upper + AdjustmentType.getValue(1))
+      continue;
+
+    New = New.addRange(F, getRange(St, Sym).Intersect(getBasicVals(), F, Lower,
+                                                      Upper));
+  }
 
-  return getRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
+  return New;
 }
 
 ProgramStateRef
 RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
                                     const llvm::APSInt &Int,
+                                    const ScalingFactor &Scale,
                                     const llvm::APSInt &Adjustment) {
-  RangeSet New = getSymLTRange(St, Sym, Int, Adjustment);
+  RangeSet New = getSymLTRange(St, Sym, Int, Scale, Adjustment);
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
 RangeSet RangeConstraintManager::getSymGTRange(ProgramStateRef St,
                                                SymbolRef Sym,
                                                const llvm::APSInt &Int,
+                                               const ScalingFactor &Scale,
                                                const llvm::APSInt &Adjustment) {
   // Before we do any real work, see if the value can even show up.
   APSIntType AdjustmentType(Adjustment);
@@ -695,24 +743,42 @@
   if (ComparisonVal == Max)
     return F.getEmptySet();
 
-  llvm::APSInt Lower = ComparisonVal - Adjustment;
-  llvm::APSInt Upper = Max - Adjustment;
-  ++Lower;
+  llvm::APSInt AdjCompVal = ComparisonVal - Adjustment;
+  llvm::APSInt AdjMax = Max - Adjustment;
+  RangeSet New = F.getEmptySet();
+  for (llvm::APSInt I = AdjustmentType.getZeroValue();
+      I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
+
+    llvm::APSInt Lower = AdjCompVal;
+    rescale(Lower, Scale, I, ScalingFactor::rmDown);
+    llvm::APSInt Upper = AdjMax;
+    rescale(Upper, Scale, I, ScalingFactor::rmDown);
+    Lower += (Scale.Reciprocal && Lower >= 0) ? Scale.Val :
+                                               AdjustmentType.getValue(1);
+
+    if (Lower == Upper + AdjustmentType.getValue(1))
+      continue;
+
+    New = New.addRange(F, getRange(St, Sym).Intersect(getBasicVals(), F, Lower,
+                                                      Upper));
+  }
 
-  return getRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
+  return New;
 }
 
 ProgramStateRef
 RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
                                     const llvm::APSInt &Int,
+                                    const ScalingFactor &Scale,
                                     const llvm::APSInt &Adjustment) {
-  RangeSet New = getSymGTRange(St, Sym, Int, Adjustment);
+  RangeSet New = getSymGTRange(St, Sym, Int, Scale, Adjustment);
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
 RangeSet RangeConstraintManager::getSymGERange(ProgramStateRef St,
                                                SymbolRef Sym,
                                                const llvm::APSInt &Int,
+                                               const ScalingFactor &Scale,
                                                const llvm::APSInt &Adjustment) {
   // Before we do any real work, see if the value can even show up.
   APSIntType AdjustmentType(Adjustment);
@@ -732,23 +798,45 @@
     return getRange(St, Sym);
 
   llvm::APSInt Max = AdjustmentType.getMaxValue();
-  llvm::APSInt Lower = ComparisonVal - Adjustment;
-  llvm::APSInt Upper = Max - Adjustment;
 
-  return getRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
+  llvm::APSInt AdjCompVal = ComparisonVal - Adjustment;
+  llvm::APSInt AdjMax = Max - Adjustment;
+  RangeSet New = F.getEmptySet();
+  for (llvm::APSInt I = AdjustmentType.getZeroValue();
+      I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
+
+    llvm::APSInt Lower = AdjCompVal;
+    rescale(Lower, Scale, I, ScalingFactor::rmUp);
+    llvm::APSInt Upper = AdjMax;
+    rescale(Upper, Scale, I, ScalingFactor::rmDown);
+
+    if (Scale.Reciprocal && Lower <= 0) {
+      Lower -= Scale.Val - AdjustmentType.getValue(1);
+    }
+
+    if (Lower == Upper + AdjustmentType.getValue(1))
+      continue;
+
+    New = New.addRange(F, getRange(St, Sym).Intersect(getBasicVals(), F, Lower,
+                                                      Upper));
+  }
+
+  return New;
 }
 
 ProgramStateRef
 RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
                                     const llvm::APSInt &Int,
+                                    const ScalingFactor &Scale,
                                     const llvm::APSInt &Adjustment) {
-  RangeSet New = getSymGERange(St, Sym, Int, Adjustment);
+  RangeSet New = getSymGERange(St, Sym, Int, Scale, Adjustment);
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
 RangeSet RangeConstraintManager::getSymLERange(
       llvm::function_ref<RangeSet()> RS,
       const llvm::APSInt &Int,
+      const ScalingFactor &Scale,
       const llvm::APSInt &Adjustment) {
   // Before we do any real work, see if the value can even show up.
   APSIntType AdjustmentType(Adjustment);
@@ -768,42 +856,66 @@
     return RS();
 
   llvm::APSInt Min = AdjustmentType.getMinValue();
-  llvm::APSInt Lower = Min - Adjustment;
-  llvm::APSInt Upper = ComparisonVal - Adjustment;
 
-  return RS().Intersect(getBasicVals(), F, Lower, Upper);
+  llvm::APSInt AdjCompVal = ComparisonVal - Adjustment;
+  llvm::APSInt AdjMin = Min - Adjustment;
+  RangeSet New = F.getEmptySet();
+  for (llvm::APSInt I = AdjustmentType.getZeroValue();
+      I < (Scale.Reciprocal ? AdjustmentType.getValue(1) : Scale.Val); ++I) {
+
+    llvm::APSInt Lower = AdjMin;
+    rescale(Lower, Scale, I, ScalingFactor::rmUp);
+    llvm::APSInt Upper = AdjCompVal;
+    rescale(Upper, Scale, I, ScalingFactor::rmDown);
+
+    if (Scale.Reciprocal && Upper >= 0) {
+      Upper += Scale.Val - AdjustmentType.getValue(1);
+    }
+
+    if (Lower == Upper + AdjustmentType.getValue(1))
+      continue;
+
+    New = New.addRange(F, RS().Intersect(getBasicVals(), F, Lower, Upper));
+  }
+
+  return New;
 }
 
 RangeSet RangeConstraintManager::getSymLERange(ProgramStateRef St,
                                                SymbolRef Sym,
                                                const llvm::APSInt &Int,
+                                               const ScalingFactor &Scale,
                                                const llvm::APSInt &Adjustment) {
-  return getSymLERange([&] { return getRange(St, Sym); }, Int, Adjustment);
+  return getSymLERange([&] { return getRange(St, Sym); }, Int, Scale,
+                       Adjustment);
 }
 
 ProgramStateRef
 RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
                                     const llvm::APSInt &Int,
+                                    const ScalingFactor &Scale,
                                     const llvm::APSInt &Adjustment) {
-  RangeSet New = getSymLERange(St, Sym, Int, Adjustment);
+  RangeSet New = getSymLERange(St, Sym, Int, Scale, Adjustment);
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
 ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange(
     ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-    const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
-  RangeSet New = getSymGERange(State, Sym, From, Adjustment);
+    const llvm::APSInt &To, const ScalingFactor &Scale,
+    const llvm::APSInt &Adjustment) {
+  RangeSet New = getSymGERange(State, Sym, From, Scale, Adjustment);
   if (New.isEmpty())
     return nullptr;
-  RangeSet Out = getSymLERange([&] { return New; }, To, Adjustment);
+  RangeSet Out = getSymLERange([&] { return New; }, To, Scale, Adjustment);
   return Out.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, Out);
 }
 
 ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange(
     ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-    const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
-  RangeSet RangeLT = getSymLTRange(State, Sym, From, Adjustment);
-  RangeSet RangeGT = getSymGTRange(State, Sym, To, Adjustment);
+    const llvm::APSInt &To, const ScalingFactor &Scale,
+    const llvm::APSInt &Adjustment) {
+  RangeSet RangeLT = getSymLTRange(State, Sym, From, Scale, Adjustment);
+  RangeSet RangeGT = getSymGTRange(State, Sym, To, Scale, Adjustment);
   RangeSet New(RangeLT.addRange(F, RangeGT));
   return New.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, New);
 }
Index: include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -161,6 +161,8 @@
   struct ScalingFactor {
     llvm::APSInt Val;
     bool Reciprocal;
+
+    enum RoundingMode {rmExact, rmDown, rmUp};
   };
 
   /// Assume a constraint between a symbolic expression and a concrete integer.
@@ -187,27 +189,33 @@
 
   virtual ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
                                       const llvm::APSInt &V,
+                                      const ScalingFactor &Scale,
                                       const llvm::APSInt &Adjustment) = 0;
 
   virtual ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
                                       const llvm::APSInt &V,
+                                      const ScalingFactor &Scale,
                                       const llvm::APSInt &Adjustment) = 0;
 
   virtual ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
                                       const llvm::APSInt &V,
+                                      const ScalingFactor &Scale,
                                       const llvm::APSInt &Adjustment) = 0;
 
   virtual ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
                                       const llvm::APSInt &V,
+                                      const ScalingFactor &Scale,
                                       const llvm::APSInt &Adjustment) = 0;
 
   virtual ProgramStateRef assumeSymWithinInclusiveRange(
       ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-      const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+      const llvm::APSInt &To, const ScalingFactor &Scale,
+      const llvm::APSInt &Adjustment) = 0;
 
   virtual ProgramStateRef assumeSymOutsideInclusiveRange(
       ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
-      const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+      const llvm::APSInt &To, const ScalingFactor &Scale,
+      const llvm::APSInt &Adjustment) = 0;
 
   //===------------------------------------------------------------------===//
   // Internal implementation.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D49074: [Analyzer... Balogh , Ádám via Phabricator via cfe-commits

Reply via email to