diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index e94bb355de3..6eca0885c09 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -216,9 +216,11 @@ gimple_range_fold (irange &res, const gimple *stmt,
 		   const irange &r1, const irange &r2)
 {
   gcc_checking_assert (gimple_range_handler (stmt));
+  tree type = gimple_expr_type (stmt);
+  unsigned prec = TYPE_PRECISION (type);
 
-  gimple_range_handler (stmt)->fold_range (res, gimple_expr_type (stmt),
-					   r1, r2);
+  gimple_range_handler (stmt)->fold_range (res, type,
+					   r1, r2, wi::shwi (-1, prec), wi::shwi (-1, prec));
 
   // If there are any gimple lookups, do those now.
   gimple_range_adjustment (res, stmt);
@@ -630,6 +632,7 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
 		       || code == MULT_EXPR);
   tree type = gimple_call_return_type (call);
+  unsigned prec = TYPE_PRECISION (type);
   range_operator *op = range_op_handler (code, type);
   gcc_checking_assert (op);
   int_range_max ir0, ir1;
@@ -642,7 +645,7 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
   // Pretend the arithmetic is wrapping.  If there is any overflow,
   // we'll complain, but will actually do wrapping operation.
   flag_wrapv = 1;
-  op->fold_range (r, type, ir0, ir1);
+  op->fold_range (r, type, ir0, ir1, wi::shwi (-1, prec), wi::shwi (-1, prec));
   flag_wrapv = saved_flag_wrapv;
 
   // If for both arguments vrp_valueize returned non-NULL, this should
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 6041f75d824..dc25b28e37a 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -1607,7 +1607,9 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
 	  tree op = ipa_get_jf_pass_through_operand (jfunc);
 	  value_range op_vr (op, op);
 
-	  range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr);
+	  range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr,
+							wi::shwi (-1, TYPE_PRECISION(vr_type)),
+							wi::shwi (-1, TYPE_PRECISION(vr_type)));
 	  if (ipa_vr_operation_and_type_effects (&res,
 						 &op_res,
 						 NOP_EXPR, parm_type,
@@ -2455,7 +2457,9 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
 	  value_range op_res,res;
 
 	  range_fold_binary_expr (&op_res, operation, operand_type,
-				  &src_lats->m_value_range.m_vr, &op_vr);
+				  &src_lats->m_value_range.m_vr, &op_vr,
+				  wi::shwi (-1, TYPE_PRECISION(operand_type)),
+				  wi::shwi (-1, TYPE_PRECISION(operand_type)));
 	  ipa_vr_operation_and_type_effects (&vr,
 					     &op_res,
 					     NOP_EXPR, param_type,
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 18bbae145b9..03ab63a21bd 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -506,7 +506,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 		      value_range op0 (op->val[0], op->val[0]);
 		      range_fold_binary_expr (&res, op->code, op->type,
 					      op->index ? &op0 : &vr,
-					      op->index ? &vr : &op0);
+					      op->index ? &vr : &op0,
+					      wi::shwi (-1, TYPE_PRECISION(op->type)),
+					      wi::shwi (-1, TYPE_PRECISION(op->type)));
 		    }
 		  else
 		    gcc_unreachable ();
@@ -519,7 +521,9 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 		  value_range val_vr (c->val, c->val);
 		  range_fold_binary_expr (&res, c->code, boolean_type_node,
 					  &vr,
-					  &val_vr);
+					  &val_vr,
+					  wi::shwi (-1, TYPE_PRECISION(op->type)),
+					  wi::shwi (-1, TYPE_PRECISION(op->type)));
 		  if (res.zero_p ())
 		    continue;
 		}
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index ab8f4e211ac..3fded17fcfd 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -126,7 +126,9 @@ range_operator::wi_fold (irange &r, tree type,
 			 const wide_int &lh_lb ATTRIBUTE_UNUSED,
 			 const wide_int &lh_ub ATTRIBUTE_UNUSED,
 			 const wide_int &rh_lb ATTRIBUTE_UNUSED,
-			 const wide_int &rh_ub ATTRIBUTE_UNUSED) const
+			 const wide_int &rh_ub ATTRIBUTE_UNUSED,
+       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   gcc_checking_assert (irange::supports_type_p (type));
   r.set_varying (type);
@@ -138,7 +140,9 @@ range_operator::wi_fold (irange &r, tree type,
 bool
 range_operator::fold_range (irange &r, tree type,
 			    const irange &lh,
-			    const irange &rh) const
+			    const irange &rh,
+			    const wide_int& lh_nz,
+			    const wide_int& rh_nz) const
 {
   gcc_checking_assert (irange::supports_type_p (type));
   if (empty_range_varying (r, type, lh, rh))
@@ -151,7 +155,7 @@ range_operator::fold_range (irange &r, tree type,
   if (num_lh == 1 && num_rh == 1)
     {
       wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0),
-	       rh.lower_bound (0), rh.upper_bound (0));
+	       rh.lower_bound (0), rh.upper_bound (0), lh_nz, rh_nz);
       return true;
     }
 
@@ -164,7 +168,7 @@ range_operator::fold_range (irange &r, tree type,
 	wide_int lh_ub = lh.upper_bound (x);
 	wide_int rh_lb = rh.lower_bound (y);
 	wide_int rh_ub = rh.upper_bound (y);
-	wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub);
+	wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub, lh_nz, rh_nz);
 	r.union_ (tmp);
 	if (r.varying_p ())
 	  return true;
@@ -392,7 +396,9 @@ class operator_equal : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &val) const;
@@ -404,7 +410,9 @@ public:
 bool
 operator_equal::fold_range (irange &r, tree type,
 			    const irange &op1,
-			    const irange &op2) const
+			    const irange &op2,
+			    const wide_int &nz1 ATTRIBUTE_UNUSED,
+			    const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -477,7 +485,9 @@ class operator_not_equal : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -489,7 +499,9 @@ public:
 bool
 operator_not_equal::fold_range (irange &r, tree type,
 				const irange &op1,
-				const irange &op2) const
+				const irange &op2,
+				const wide_int &nz1 ATTRIBUTE_UNUSED,
+				const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -608,7 +620,9 @@ class operator_lt :  public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -620,7 +634,9 @@ public:
 bool
 operator_lt::fold_range (irange &r, tree type,
 			 const irange &op1,
-			 const irange &op2) const
+			 const irange &op2,
+       const wide_int &nz1 ATTRIBUTE_UNUSED,
+       const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -685,7 +701,9 @@ class operator_le :  public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -697,7 +715,9 @@ public:
 bool
 operator_le::fold_range (irange &r, tree type,
 			 const irange &op1,
-			 const irange &op2) const
+			 const irange &op2,
+       const wide_int &nz1 ATTRIBUTE_UNUSED,
+       const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -762,7 +782,9 @@ class operator_gt :  public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -773,7 +795,9 @@ public:
 
 bool
 operator_gt::fold_range (irange &r, tree type,
-			 const irange &op1, const irange &op2) const
+			 const irange &op1, const irange &op2,
+       const wide_int &nz1 ATTRIBUTE_UNUSED,
+       const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -837,7 +861,9 @@ class operator_ge :  public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -849,7 +875,9 @@ public:
 bool
 operator_ge::fold_range (irange &r, tree type,
 			 const irange &op1,
-			 const irange &op2) const
+			 const irange &op2,
+			 const wide_int &nz1 ATTRIBUTE_UNUSED,
+			 const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, op1, op2))
     return true;
@@ -922,13 +950,17 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_plus;
 
 void
 operator_plus::wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const
+			const wide_int &rh_lb, const wide_int &rh_ub,
+			const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wi::overflow_type ov_lb, ov_ub;
   signop s = TYPE_SIGN (type);
@@ -942,7 +974,9 @@ operator_plus::op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2,
+			  wi::shwi (-1, TYPE_PRECISION(type)),
+			  wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 bool
@@ -950,7 +984,9 @@ operator_plus::op2_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op1) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
+  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1,
+			  wi::shwi (-1, TYPE_PRECISION(type)),
+			  wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -967,13 +1003,17 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_minus;
 
 void 
 operator_minus::wi_fold (irange &r, tree type,
 			 const wide_int &lh_lb, const wide_int &lh_ub,
-			 const wide_int &rh_lb, const wide_int &rh_ub) const
+			 const wide_int &rh_lb, const wide_int &rh_ub,
+			 const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			 const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wi::overflow_type ov_lb, ov_ub;
   signop s = TYPE_SIGN (type);
@@ -987,7 +1027,9 @@ operator_minus::op1_range (irange &r, tree type,
 			   const irange &lhs,
 			   const irange &op2) const
 {
-  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2,
+			 wi::shwi (-1, TYPE_PRECISION(type)),
+			 wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 bool
@@ -995,7 +1037,8 @@ operator_minus::op2_range (irange &r, tree type,
 			   const irange &lhs,
 			   const irange &op1) const
 {
-  return fold_range (r, type, op1, lhs);
+  return fold_range (r, type, op1, lhs, wi::shwi (-1, TYPE_PRECISION(type)),
+					 wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -1006,13 +1049,17 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_min;
 
 void
 operator_min::wi_fold (irange &r, tree type,
 		       const wide_int &lh_lb, const wide_int &lh_ub,
-		       const wide_int &rh_lb, const wide_int &rh_ub) const
+		       const wide_int &rh_lb, const wide_int &rh_ub,
+		       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+		       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   signop s = TYPE_SIGN (type);
   wide_int new_lb = wi::min (lh_lb, rh_lb, s);
@@ -1028,13 +1075,17 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_max;
 
 void
 operator_max::wi_fold (irange &r, tree type,
 		       const wide_int &lh_lb, const wide_int &lh_ub,
-		       const wide_int &rh_lb, const wide_int &rh_ub) const
+		       const wide_int &rh_lb, const wide_int &rh_ub,
+		       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+		       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   signop s = TYPE_SIGN (type);
   wide_int new_lb = wi::max (lh_lb, rh_lb, s);
@@ -1123,7 +1174,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
   virtual bool wi_op_overflows (wide_int &res, tree type,
 				const wide_int &w0, const wide_int &w1) const;
   virtual bool op1_range (irange &r, tree type,
@@ -1148,7 +1201,8 @@ operator_mult::op1_range (irange &r, tree type,
 
   if (op2.singleton_p (&offset) && !integer_zerop (offset))
     return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
-								lhs, op2);
+								lhs, op2, wi::shwi (-1, TYPE_PRECISION(type)),
+								wi::shwi (-1, TYPE_PRECISION(type)));
   return false;
 }
 
@@ -1182,7 +1236,9 @@ operator_mult::wi_op_overflows (wide_int &res, tree type,
 void 
 operator_mult::wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const
+			const wide_int &rh_lb, const wide_int &rh_ub,
+      const wide_int &lh_nz ATTRIBUTE_UNUSED,
+      const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (TYPE_OVERFLOW_UNDEFINED (type))
     {
@@ -1267,7 +1323,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
   virtual bool wi_op_overflows (wide_int &res, tree type,
 				const wide_int &, const wide_int &) const;
 private:
@@ -1319,7 +1377,9 @@ operator_div::wi_op_overflows (wide_int &res, tree type,
 void
 operator_div::wi_fold (irange &r, tree type,
 		       const wide_int &lh_lb, const wide_int &lh_ub,
-		       const wide_int &rh_lb, const wide_int &rh_ub) const
+		       const wide_int &rh_lb, const wide_int &rh_ub,
+		       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+		       const wide_int &rh_nz) const
 {
   // If we know we will divide by zero...
   if (rh_lb == 0 && rh_ub == 0)
@@ -1376,6 +1436,36 @@ operator_div::wi_fold (irange &r, tree type,
 			wi::one (prec), divisor_max);
       r.union_ (tmp);
     }
+
+  // Handle:
+  // x2.0_1 = x2D.2447;
+  // # RANGE [0, 4294967295] NONZERO 4294967294
+  // _2 = x2.0_1 * 2;
+  // # RANGE [0, 1] NONZERO 1
+  // _3 = 1 / _2;
+  // where the last bit of _2 is known to be zero because of the * 2
+  // From that information, we know that _2 can't hold the value of 1 so _3 can't be 1 as well
+  if (dividend_min == dividend_max
+      && wi::gt_p(dividend_min, wi::zero(prec), sign)
+      && wi::ge_p(divisor_min, wi::zero(prec), sign)
+      && r.num_pairs() == 1
+      && rh_nz != -1
+      && r.lower_bound(0) != r.upper_bound(0))
+    {
+      if (wi::ge_p(r.upper_bound(0), wi::one(prec), sign))
+        {
+          // Use the nonzero bits of the divisor to see if dividend_min is
+          // a possible result. If it isn't, then the result of the division
+          // can never be 1.
+          auto divisorZeroBits = ~rh_nz;
+          if (wi::ge_p(divisorZeroBits, dividend_min, sign))
+            {
+              value_range_with_overflow(r, type, r.lower_bound(0), wi::zero(prec));
+            }
+        }
+    
+    }
+
   // We shouldn't still have undefined here.
   gcc_checking_assert (!r.undefined_p ());
 }
@@ -1410,7 +1500,9 @@ operator_exact_divide::op1_range (irange &r, tree type,
   // If op2 is a multiple of 2, we would be able to set some non-zero bits.
   if (op2.singleton_p (&offset)
       && !integer_zerop (offset))
-    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
+    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2,
+											wi::shwi (-1, TYPE_PRECISION(type)),
+											wi::shwi (-1, TYPE_PRECISION(type)));
   return false;
 }
 
@@ -1423,11 +1515,14 @@ public:
 			  const irange &op2) const;
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
 
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const;
+			const wide_int &rh_lb, const wide_int &rh_ub,
+      const wide_int &lh_nz, const wide_int &rh_nz) const;
   virtual bool wi_op_overflows (wide_int &res,
 				tree type,
 				const wide_int &,
@@ -1439,12 +1534,16 @@ class operator_rshift : public cross_product_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb,
 			const wide_int &lh_ub,
 			const wide_int &rh_lb,
-			const wide_int &rh_ub) const;
+			const wide_int &rh_ub,
+			const wide_int &lh_nz,
+			const wide_int &rh_nz) const;
   virtual bool wi_op_overflows (wide_int &res,
 				tree type,
 				const wide_int &w0,
@@ -1458,7 +1557,9 @@ public:
 bool
 operator_lshift::fold_range (irange &r, tree type,
 			     const irange &op1,
-			     const irange &op2) const
+			     const irange &op2,
+			     const wide_int &nz1 ATTRIBUTE_UNUSED,
+			     const wide_int &nz2 ATTRIBUTE_UNUSED) const
 {
   int_range_max shift_range;
   if (!get_shift_range (shift_range, type, op2))
@@ -1482,20 +1583,26 @@ operator_lshift::fold_range (irange &r, tree type,
       bool saved_flag_wrapv_pointer = flag_wrapv_pointer;
       flag_wrapv = 1;
       flag_wrapv_pointer = 1;
-      bool b = op_mult.fold_range (r, type, op1, mult);
+      bool b = op_mult.fold_range (r, type, op1, mult, 
+											wi::shwi (-1, TYPE_PRECISION(type)),
+											wi::shwi (-1, TYPE_PRECISION(type)));
       flag_wrapv = saved_flag_wrapv;
       flag_wrapv_pointer = saved_flag_wrapv_pointer;
       return b;
     }
   else
     // Otherwise, invoke the generic fold routine.
-    return range_operator::fold_range (r, type, op1, shift_range);
+    return range_operator::fold_range (r, type, op1, shift_range,
+											wi::shwi (-1, TYPE_PRECISION(type)),
+											wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 void
 operator_lshift::wi_fold (irange &r, tree type,
 			  const wide_int &lh_lb, const wide_int &lh_ub,
-			  const wide_int &rh_lb, const wide_int &rh_ub) const
+			  const wide_int &rh_lb, const wide_int &rh_ub,
+			  const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			  const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   signop sign = TYPE_SIGN (type);
   unsigned prec = TYPE_PRECISION (type);
@@ -1598,10 +1705,14 @@ operator_lshift::op1_range (irange &r,
 	  int_range_max tmp = lhs;
 	  utype = unsigned_type_for (type);
 	  range_cast (tmp, utype);
-	  op_rshift.fold_range (r, utype, tmp, op2);
+	  op_rshift.fold_range (r, utype, tmp, op2, 
+													wi::shwi (-1, TYPE_PRECISION(type)),
+													wi::shwi (-1, TYPE_PRECISION(type)));
 	}
       else
-	op_rshift.fold_range (r, utype, lhs, op2);
+	op_rshift.fold_range (r, utype, lhs, op2, 
+												wi::shwi (-1, TYPE_PRECISION(type)),
+												wi::shwi (-1, TYPE_PRECISION(type)));
 
       // Start with ranges which can produce the LHS by right shifting the
       // result by the shift amount.
@@ -1653,7 +1764,9 @@ operator_rshift::op1_range (irange &r,
       // Folding the original operation may discard some impossible
       // ranges from the LHS.
       int_range_max lhs_refined;
-      op_rshift.fold_range (lhs_refined, type, int_range<1> (type), op2);
+      op_rshift.fold_range (lhs_refined, type, int_range<1> (type), op2,
+						wi::shwi (-1, TYPE_PRECISION(type)),
+						wi::shwi (-1, TYPE_PRECISION(type)));
       lhs_refined.intersect (lhs);
       if (lhs_refined.undefined_p ())
 	{
@@ -1662,7 +1775,9 @@ operator_rshift::op1_range (irange &r,
 	}
       int_range_max shift_range (shift, shift);
       int_range_max lb, ub;
-      op_lshift.fold_range (lb, type, lhs_refined, shift_range);
+      op_lshift.fold_range (lb, type, lhs_refined, shift_range,
+						wi::shwi (-1, TYPE_PRECISION(type)),
+						wi::shwi (-1, TYPE_PRECISION(type)));
       //    LHS
       // 0000 0111 = OP1 >> 3
       //
@@ -1674,7 +1789,9 @@ operator_rshift::op1_range (irange &r,
 					    build_minus_one_cst (type),
 					    shift));
       int_range_max mask_range (build_zero_cst (type), mask);
-      op_plus.fold_range (ub, type, lb, mask_range);
+      op_plus.fold_range (ub, type, lb, mask_range, 
+						wi::shwi (-1, TYPE_PRECISION(type)),
+						wi::shwi (-1, TYPE_PRECISION(type)));
       r = lb;
       r.union_ (ub);
       if (!lhs_refined.contains_p (build_zero_cst (type)))
@@ -1709,7 +1826,9 @@ operator_rshift::wi_op_overflows (wide_int &res,
 bool
 operator_rshift::fold_range (irange &r, tree type,
 			     const irange &op1,
-			     const irange &op2) const
+			     const irange &op2,
+			     const wide_int &nz1,
+			     const wide_int &nz2) const
 {
   int_range_max shift;
   if (!get_shift_range (shift, type, op2))
@@ -1721,13 +1840,16 @@ operator_rshift::fold_range (irange &r, tree type,
       return true;
     }
 
-  return range_operator::fold_range (r, type, op1, shift);
+  return range_operator::fold_range (r, type, op1, shift, 
+																		 nz1, nz2);
 }
 
 void
 operator_rshift::wi_fold (irange &r, tree type,
 			  const wide_int &lh_lb, const wide_int &lh_ub,
-			  const wide_int &rh_lb, const wide_int &rh_ub) const
+			  const wide_int &rh_lb, const wide_int &rh_ub,
+			  const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			  const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub);
 }
@@ -1738,7 +1860,9 @@ class operator_cast: public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -1819,7 +1943,9 @@ operator_cast::fold_pair (irange &r, unsigned index,
 bool
 operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 			   const irange &inner,
-			   const irange &outer) const
+			   const irange &outer,
+			   const wide_int &inner_nz ATTRIBUTE_UNUSED,
+			   const wide_int &outer_nz ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, inner, outer))
     return true;
@@ -1903,7 +2029,9 @@ operator_cast::op1_range (irange &r, tree type,
 	  range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
 							  type,
 							  converted_lhs,
-							  lim_range);
+							  lim_range,
+								wi::shwi (-1, TYPE_PRECISION(type)),
+								wi::shwi (-1, TYPE_PRECISION(type)));
 	  // lhs_neg now has all the negative versions of the LHS.
 	  // Now union in all the values from SIGNED MIN (0x80000) to
 	  // lim-1 in order to fill in all the ranges with the upper
@@ -1938,14 +2066,18 @@ operator_cast::op1_range (irange &r, tree type,
       // the range of the RHS by this assignment.
       //
       // Cast the range of the RHS to the type of the LHS.
-      fold_range (tmp, lhs_type, int_range<1> (type), int_range<1> (lhs_type));
+      fold_range (tmp, lhs_type, int_range<1> (type), int_range<1> (lhs_type),
+									wi::shwi (-1, TYPE_PRECISION(lhs_type)),
+									wi::shwi (-1, TYPE_PRECISION(lhs_type)));
       // Intersect this with the LHS range will produce the range,
       // which will be cast to the RHS type before returning.
       tmp.intersect (lhs);
     }
 
   // Cast the calculated range to the type of the RHS.
-  fold_range (r, type, tmp, int_range<1> (type));
+  fold_range (r, type, tmp, int_range<1> (type),
+							wi::shwi (-1, TYPE_PRECISION(type)),
+							wi::shwi (-1, TYPE_PRECISION(type)));
   return true;
 }
 
@@ -1955,7 +2087,9 @@ class operator_logical_and : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int &lh_nz,
+			   const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -1968,7 +2102,9 @@ public:
 bool
 operator_logical_and::fold_range (irange &r, tree type,
 				  const irange &lh,
-				  const irange &rh) const
+				  const irange &rh,
+				  const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				  const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
@@ -2022,7 +2158,9 @@ class operator_bitwise_and : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int &lh_nz,
+			   const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2033,7 +2171,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 private:
   void simple_op1_range_solver (irange &r, tree type,
 				const irange &lhs,
@@ -2107,9 +2247,12 @@ operator_bitwise_and::remove_impossible_ranges (irange &r,
 bool
 operator_bitwise_and::fold_range (irange &r, tree type,
 				  const irange &lh,
-				  const irange &rh) const
+				  const irange &rh,
+				  const wide_int &lh_nz,
+				  const wide_int &rh_nz) const
 {
-  if (range_operator::fold_range (r, type, lh, rh))
+  if (range_operator::fold_range (r, type, lh, rh, 
+																	lh_nz, rh_nz))
     {
       // FIXME: This is temporarily disabled because, though it
       // generates better ranges, it's noticeably slower for evrp.
@@ -2252,7 +2395,9 @@ operator_bitwise_and::wi_fold (irange &r, tree type,
 			       const wide_int &lh_lb,
 			       const wide_int &lh_ub,
 			       const wide_int &rh_lb,
-			       const wide_int &rh_ub) const
+			       const wide_int &rh_ub,
+			       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
     return;
@@ -2432,7 +2577,9 @@ class operator_logical_or : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int &lh_nz,
+			   const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2444,7 +2591,9 @@ public:
 bool
 operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 				 const irange &lh,
-				 const irange &rh) const
+				 const irange &rh,
+				 const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				 const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
@@ -2497,7 +2646,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_bitwise_or;
 
 void
@@ -2505,7 +2656,9 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
 			      const wide_int &lh_lb,
 			      const wide_int &lh_ub,
 			      const wide_int &rh_lb,
-			      const wide_int &rh_ub) const
+			      const wide_int &rh_ub,
+			      const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			      const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub))
     return;
@@ -2577,7 +2730,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2591,7 +2746,9 @@ operator_bitwise_xor::wi_fold (irange &r, tree type,
 			       const wide_int &lh_lb,
 			       const wide_int &lh_ub,
 			       const wide_int &rh_lb,
-			       const wide_int &rh_ub) const
+			       const wide_int &rh_ub,
+			       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   signop sign = TYPE_SIGN (type);
   wide_int maybe_nonzero_lh, mustbe_nonzero_lh;
@@ -2666,7 +2823,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2680,7 +2839,9 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
 			     const wide_int &lh_lb,
 			     const wide_int &lh_ub,
 			     const wide_int &rh_lb,
-			     const wide_int &rh_ub) const
+			     const wide_int &rh_ub,
+			     const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			     const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wide_int new_lb, new_ub, tmp;
   signop sign = TYPE_SIGN (type);
@@ -2784,7 +2945,9 @@ class operator_logical_not : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int &lh_nz,
+			   const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2807,7 +2970,9 @@ public:
 bool
 operator_logical_not::fold_range (irange &r, tree type,
 				  const irange &lh,
-				  const irange &rh ATTRIBUTE_UNUSED) const
+				  const irange &rh ATTRIBUTE_UNUSED,
+				  const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				  const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
@@ -2826,7 +2991,9 @@ operator_logical_not::op1_range (irange &r,
 				 const irange &op2) const
 {
   // Logical NOT is involutary...do it again.
-  return fold_range (r, type, lhs, op2);
+  return fold_range (r, type, lhs, op2, 
+										 wi::shwi (-1, TYPE_PRECISION(type)),
+										 wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -2835,7 +3002,9 @@ class operator_bitwise_not : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int &lh_nz,
+			   const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2844,19 +3013,21 @@ public:
 bool
 operator_bitwise_not::fold_range (irange &r, tree type,
 				  const irange &lh,
-				  const irange &rh) const
+				  const irange &rh,
+				  const wide_int &lh_nz,
+				  const wide_int &rh_nz) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
 
   if (types_compatible_p (type, boolean_type_node))
-    return op_logical_not.fold_range (r, type, lh, rh);
+    return op_logical_not.fold_range (r, type, lh, rh, lh_nz, rh_nz);
 
   // ~X is simply -1 - X.
   int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
 			 wi::minus_one (TYPE_PRECISION (type)));
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
-							  lh);
+							  lh, lh_nz, rh_nz);
 }
 
 bool
@@ -2868,7 +3039,9 @@ operator_bitwise_not::op1_range (irange &r, tree type,
     return op_logical_not.op1_range (r, type, lhs, op2);
 
   // ~X is -1 - X and since bitwise NOT is involutary...do it again.
-  return fold_range (r, type, lhs, op2);
+  return fold_range (r, type, lhs, op2, 
+										 wi::shwi (-1, TYPE_PRECISION(type)),
+										 wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -2877,13 +3050,17 @@ class operator_cst : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
 } op_integer_cst;
 
 bool
 operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 			  const irange &lh,
-			  const irange &rh ATTRIBUTE_UNUSED) const
+			  const irange &rh ATTRIBUTE_UNUSED,
+			  const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			  const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   r = lh;
   return true;
@@ -2895,7 +3072,9 @@ class operator_identity : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2904,7 +3083,9 @@ public:
 bool
 operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 			       const irange &lh,
-			       const irange &rh ATTRIBUTE_UNUSED) const
+			       const irange &rh ATTRIBUTE_UNUSED,
+			       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   r = lh;
   return true;
@@ -2925,13 +3106,17 @@ class operator_unknown : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
 } op_unknown;
 
 bool
 operator_unknown::fold_range (irange &r, tree type,
 			      const irange &lh ATTRIBUTE_UNUSED,
-			      const irange &rh ATTRIBUTE_UNUSED) const
+			      const irange &rh ATTRIBUTE_UNUSED,
+			      const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			      const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   r.set_varying (type);
   return true;
@@ -2945,7 +3130,9 @@ class operator_abs : public range_operator
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -2955,7 +3142,9 @@ void
 operator_abs::wi_fold (irange &r, tree type,
 		       const wide_int &lh_lb, const wide_int &lh_ub,
 		       const wide_int &rh_lb ATTRIBUTE_UNUSED,
-		       const wide_int &rh_ub ATTRIBUTE_UNUSED) const
+		       const wide_int &rh_ub ATTRIBUTE_UNUSED,
+		       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+		       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wide_int min, max;
   signop sign = TYPE_SIGN (type);
@@ -3056,14 +3245,17 @@ class operator_absu : public range_operator
  public:
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const;
+			const wide_int &rh_lb, const wide_int &rh_ub,
+			const wide_int &lh_nz, const wide_int &rh_nz) const;
 } op_absu;
 
 void
 operator_absu::wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
 			const wide_int &rh_lb ATTRIBUTE_UNUSED,
-			const wide_int &rh_ub ATTRIBUTE_UNUSED) const
+			const wide_int &rh_ub ATTRIBUTE_UNUSED,
+			const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   wide_int new_lb, new_ub;
 
@@ -3100,7 +3292,9 @@ class operator_negate : public range_operator
  public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -3109,14 +3303,16 @@ class operator_negate : public range_operator
 bool
 operator_negate::fold_range (irange &r, tree type,
 			     const irange &lh,
-			     const irange &rh) const
+			     const irange &rh,
+			     const wide_int &lh_nz,
+			     const wide_int &rh_nz) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
   // -X is simply 0 - X.
   return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
 							  range_zero (type),
-							  lh);
+							  lh, lh_nz, rh_nz);
 }
 
 bool
@@ -3125,7 +3321,9 @@ operator_negate::op1_range (irange &r, tree type,
 			    const irange &op2) const
 {
   // NEGATE is involutory.
-  return fold_range (r, type, lhs, op2);
+  return fold_range (r, type, lhs, op2, 
+										 wi::shwi (-1, TYPE_PRECISION(type)),
+										 wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -3134,7 +3332,9 @@ class operator_addr_expr : public range_operator
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
-			   const irange &op2) const;
+			   const irange &op2,
+			   const wide_int &nz1,
+			   const wide_int &nz2) const;
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2) const;
@@ -3143,7 +3343,9 @@ public:
 bool
 operator_addr_expr::fold_range (irange &r, tree type,
 				const irange &lh,
-				const irange &rh) const
+				const irange &rh,
+				const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   if (empty_range_varying (r, type, lh, rh))
     return true;
@@ -3163,7 +3365,9 @@ operator_addr_expr::op1_range (irange &r, tree type,
 			       const irange &lhs,
 			       const irange &op2) const
 {
-  return operator_addr_expr::fold_range (r, type, lhs, op2);
+  return operator_addr_expr::fold_range (r, type, lhs, op2,
+			       wi::shwi (-1, TYPE_PRECISION(type)),
+			       wi::shwi (-1, TYPE_PRECISION(type)));
 }
 
 
@@ -3174,7 +3378,9 @@ public:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz,
+		        const wide_int &rh_nz) const;
 } op_pointer_plus;
 
 void
@@ -3182,7 +3388,9 @@ pointer_plus_operator::wi_fold (irange &r, tree type,
 				const wide_int &lh_lb,
 				const wide_int &lh_ub,
 				const wide_int &rh_lb,
-				const wide_int &rh_ub) const
+				const wide_int &rh_ub,
+				const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   // Check for [0,0] + const, and simply return the const.
   if (lh_lb == 0 && lh_ub == 0 && rh_lb == rh_ub)
@@ -3227,7 +3435,8 @@ class pointer_min_max_operator : public range_operator
 public:
   virtual void wi_fold (irange & r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const;
+			const wide_int &rh_lb, const wide_int &rh_ub,
+			const wide_int &lh_nz, const wide_int &rh_nz) const;
 } op_ptr_min_max;
 
 void
@@ -3235,7 +3444,9 @@ pointer_min_max_operator::wi_fold (irange &r, tree type,
 				   const wide_int &lh_lb,
 				   const wide_int &lh_ub,
 				   const wide_int &rh_lb,
-				   const wide_int &rh_ub) const
+				   const wide_int &rh_ub,
+				   const wide_int &lh_nz ATTRIBUTE_UNUSED,
+				   const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   // For MIN/MAX expressions with pointers, we only care about
   // nullness.  If both are non null, then the result is nonnull.
@@ -3256,7 +3467,8 @@ class pointer_and_operator : public range_operator
 public:
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const;
+			const wide_int &rh_lb, const wide_int &rh_ub,
+			const wide_int &lh_nz, const wide_int &rh_nz) const;
 } op_pointer_and;
 
 void
@@ -3264,7 +3476,9 @@ pointer_and_operator::wi_fold (irange &r, tree type,
 			       const wide_int &lh_lb,
 			       const wide_int &lh_ub,
 			       const wide_int &rh_lb ATTRIBUTE_UNUSED,
-			       const wide_int &rh_ub ATTRIBUTE_UNUSED) const
+			       const wide_int &rh_ub ATTRIBUTE_UNUSED,
+			       const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			       const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   // For pointer types, we are really only interested in asserting
   // whether the expression evaluates to non-NULL.
@@ -3286,7 +3500,8 @@ public:
 			  const irange &op1) const;
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
-			const wide_int &rh_lb, const wide_int &rh_ub) const;
+			const wide_int &rh_lb, const wide_int &rh_ub,
+			const wide_int &lh_nz, const wide_int &rh_nz) const;
 } op_pointer_or;
 
 bool
@@ -3317,7 +3532,9 @@ pointer_or_operator::wi_fold (irange &r, tree type,
 			      const wide_int &lh_lb,
 			      const wide_int &lh_ub,
 			      const wide_int &rh_lb,
-			      const wide_int &rh_ub) const
+			      const wide_int &rh_ub,
+			      const wide_int &lh_nz ATTRIBUTE_UNUSED,
+			      const wide_int &rh_nz ATTRIBUTE_UNUSED) const
 {
   // For pointer types, we are really only interested in asserting
   // whether the expression evaluates to non-NULL.
@@ -3464,7 +3681,9 @@ range_cast (irange &r, tree type)
   int_range_max tmp = r;
   range_operator *op = range_op_handler (CONVERT_EXPR, type);
   // Call op_convert, if it fails, the result is varying.
-  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
+  if (!op->fold_range (r, type, tmp, int_range<1> (type),
+											 wi::shwi (-1, TYPE_PRECISION(type)),
+											 wi::shwi (-1, TYPE_PRECISION(type))))
     r.set_varying (type);
 }
 
@@ -3623,7 +3842,9 @@ range_op_lshift_tests ()
 				build_int_cst (big_type, 48));
     op_bitwise_and.fold_range (res, big_type,
 			       int_range <1> (big_type),
-			       int_range <1> (big_num, big_num));
+			       int_range <1> (big_num, big_num),
+			       wi::shwi (-1, TYPE_PRECISION(big_type)),
+			       wi::shwi (-1, TYPE_PRECISION(big_type)));
     // val = 0x8,0000,0000,0000
     tree val = fold_build2 (LSHIFT_EXPR, big_type,
 			    build_int_cst (big_type, 0x8),
@@ -3650,7 +3871,9 @@ range_op_lshift_tests ()
       //  op1 << 1   should be [0x8000,0x8000] << 1,
       //  which should result in [0,0].
       int_range_max result;
-      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
+      op_lshift.fold_range (result, unsigned_type_node, op1, shift,
+			       wi::shwi (-1, TYPE_PRECISION(unsigned_type_node)),
+			       wi::shwi (-1, TYPE_PRECISION(unsigned_type_node)));
       ASSERT_TRUE (result == zero);
     }
   // signed VARYING = op1 << 1 should be VARYING.
@@ -3673,7 +3896,9 @@ range_op_lshift_tests ()
       //  op1 << 1   shuould be [0x8000,0x8000] << 1,
       //  which should result in [0,0].
       int_range_max result;
-      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
+      op_lshift.fold_range (result, unsigned_type_node, op1, shift,
+			       wi::shwi (-1, TYPE_PRECISION(unsigned_type_node)),
+			       wi::shwi (-1, TYPE_PRECISION(unsigned_type_node)));
       ASSERT_TRUE (result == zero);
     }
 }
@@ -3758,4 +3983,4 @@ range_op_tests ()
 
 } // namespace selftest
 
-#endif // CHECKING_P
+#endif // CHECKING_P
\ No newline at end of file
diff --git a/gcc/range-op.h b/gcc/range-op.h
index d3d44083093..2683695f9c1 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -52,7 +52,9 @@ public:
   // Perform an operation between 2 ranges and return it.
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
-			   const irange &rh) const;
+			   const irange &rh,
+			   const wide_int& lh_nz,
+			   const wide_int& rh_nz) const;
 
   // Return the range for op[12] in the general case.  LHS is the range for
   // the LHS of the expression, OP[12]is the range for the other
@@ -78,7 +80,9 @@ protected:
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
-		        const wide_int &rh_ub) const;
+		        const wide_int &rh_ub,
+		        const wide_int &lh_nz, 
+		        const wide_int &rh_nz) const;
 };
 
 extern range_operator *range_op_handler (enum tree_code code, tree type);
diff --git a/gcc/testsuite/gcc.dg/pr77980-neg.c b/gcc/testsuite/gcc.dg/pr77980-neg.c
new file mode 100644
index 00000000000..34d791dd564
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr77980-neg.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+int x1 = 0;
+int x2 = 1;
+
+int test1 ()
+{
+	int t1 = x1*(1/(x2+x2));
+	// y2 can be negative so t1!=0 cannot be optimized away
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test2 (int y1, int y2)
+{
+	int t1 = y1*(1/(y2+y2));
+	// y2 can be negative so t1!=0 cannot be optimized away
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test3 (int y1, unsigned int y2)
+{
+	int t1 = y1*(2/(y2+y2));
+	// y2 can equal 1 so 2/(y2+y2) can equal 1 and the value of t1
+	// would be dependent on y1 so t1!=0 cannot be optimized away
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test4 (int y1, unsigned int y2)
+{
+	int t1 = y1*(4/(y2+y2+y2+y2));
+	// y2 can equal 1 so 4/(y2+y2+y2+y2) can equal 1 and the value of t1
+	// would be dependent on y1 so t1!=0 cannot be optimized away
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+// All if statements shouldn't get optimized away
+/* { dg-final { scan-tree-dump-times "if \\\(" 4 "vrp1" } } */
diff --git a/gcc/testsuite/gcc.dg/pr77980.c b/gcc/testsuite/gcc.dg/pr77980.c
new file mode 100644
index 00000000000..63b6f1ba5f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr77980.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+int x1 = 0;
+unsigned int x2 = 1;
+
+int test1 ()
+{
+	int t1 = x1*(1/(x2+x2));
+	// This check should be optimized away because we know that 
+	// t1 can only be 0 because 1/(x2+x2) can never be 1, because
+	// x2+x2 can never be 1)
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test2 (int y1, unsigned int y2)
+{
+	int t1 = y1*(1/(y2+y2));
+	// This check should be optimized away because we know that 
+	// t1 can only be 0 because 1/(y2+y2) can never be 1 because
+	// y2+y2 can never be 1
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test3 (int y1, unsigned int y2)
+{
+	int t1 = y1*(2/(y2+y2+y2+y2));
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+int test4 (int y1, unsigned int y2)
+{
+	int t1 = y1*(3/(y2+y2+y2+y2));
+	if (t1 != 0) __builtin_abort();
+	return 0;
+}
+
+// All if statements should get optimized away
+/* { dg-final { scan-tree-dump-times "if \\\(" 0 "vrp1" } } */
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index e6dd5f15bed..b005de191e6 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -614,7 +614,9 @@ compute_distributive_range (tree type, value_range &op0_range,
   if (result_range)
     {
       range_operator *op = range_op_handler (code, type);
-      op->fold_range (*result_range, type, op0_range, op1_range);
+      op->fold_range (*result_range, type, op0_range, op1_range, 
+											wi::shwi (-1, TYPE_PRECISION(type)),
+											wi::shwi (-1, TYPE_PRECISION(type)));
     }
 
   /* The distributive property guarantees that if TYPE is no narrower
@@ -662,7 +664,9 @@ compute_distributive_range (tree type, value_range &op0_range,
   range_operator *op = range_op_handler (code, ssizetype);
   bool saved_flag_wrapv = flag_wrapv;
   flag_wrapv = 1;
-  op->fold_range (wide_range, ssizetype, op0_range, op1_range);
+  op->fold_range (wide_range, ssizetype, op0_range, op1_range,
+									wi::shwi (-1, TYPE_PRECISION(type)),
+									wi::shwi (-1, TYPE_PRECISION(type)));
   flag_wrapv = saved_flag_wrapv;
   if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
     return false;
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 12e6e6f3e22..8f262e8a75b 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1026,7 +1026,9 @@ range_fold_binary_symbolics_p (value_range *vr,
       const range_operator *op = get_range_op_handler (vr, code, expr_type);
       vr0.normalize_symbolics ();
       vr1.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0, vr1);
+      return op->fold_range (*vr, expr_type, vr0, vr1,
+						wi::shwi (-1, TYPE_PRECISION(expr_type)),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)));
     }
   return false;
 }
@@ -1047,7 +1049,9 @@ range_fold_unary_symbolics_p (value_range *vr,
 	  /* -X is simply 0 - X.  */
 	  value_range zero;
 	  zero.set_zero (vr0->type ());
-	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0);
+	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0,
+						wi::shwi (-1, TYPE_PRECISION(expr_type)),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)));
 	  return true;
 	}
       if (code == BIT_NOT_EXPR)
@@ -1055,13 +1059,17 @@ range_fold_unary_symbolics_p (value_range *vr,
 	  /* ~X is simply -1 - X.  */
 	  value_range minusone;
 	  minusone.set (build_int_cst (vr0->type (), -1));
-	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
+	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0,
+						wi::shwi (-1, TYPE_PRECISION(expr_type)),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)));
 	  return true;
 	}
       const range_operator *op = get_range_op_handler (vr, code, expr_type);
       value_range vr0_cst (*vr0);
       vr0_cst.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)));
     }
   return false;
 }
@@ -1073,7 +1081,9 @@ range_fold_binary_expr (value_range *vr,
 			enum tree_code code,
 			tree expr_type,
 			const value_range *vr0_,
-			const value_range *vr1_)
+			const value_range *vr1_,
+      const wide_int& nz0,
+      const wide_int& nz1)
 {
   if (!supported_types_p (vr, expr_type)
       || !defined_ranges_p (vr, vr0_, vr1_))
@@ -1093,7 +1103,7 @@ range_fold_binary_expr (value_range *vr,
     vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0, vr1);
+  op->fold_range (*vr, expr_type, vr0, vr1, nz0, nz1);
 }
 
 /* Perform a unary operation on a range.  */
@@ -1116,7 +1126,9 @@ range_fold_unary_expr (value_range *vr,
 
   value_range vr0_cst (*vr0);
   vr0_cst.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)),
+						wi::shwi (-1, TYPE_PRECISION(expr_type)));
 }
 
 /* If the range of values taken by OP can be inferred after STMT executes,
@@ -4618,7 +4630,8 @@ determine_value_range_1 (value_range *vr, tree expr)
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1));
       range_fold_binary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
-			      &vr0, &vr1);
+			      &vr0, &vr1, wi::shwi (-1, TYPE_PRECISION(TREE_TYPE (expr))),
+			      wi::shwi (-1, TYPE_PRECISION(TREE_TYPE (expr))));
     }
   else if (UNARY_CLASS_P (expr))
     {
@@ -4662,4 +4675,4 @@ determine_value_range (tree expr, wide_int *min, wide_int *max)
     }
 
   return VR_VARYING;
-}
+}
\ No newline at end of file
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 989d8430c98..06506ee7af3 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -51,7 +51,8 @@ extern int operand_less_p (tree, tree);
 void range_fold_unary_expr (value_range *, enum tree_code, tree type,
 			    const value_range *, tree op0_type);
 void range_fold_binary_expr (value_range *, enum tree_code, tree type,
-			     const value_range *, const value_range *);
+			     const value_range *, const value_range *, 
+			     const wide_int&, const wide_int&);
 
 extern enum value_range_kind intersect_range_with_nonzero_bits
   (enum value_range_kind, wide_int *, wide_int *, const wide_int &, signop);
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 08b237b2632..f918264e460 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -825,15 +825,22 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
   /* Get value ranges for each operand.  For constant operands, create
      a new value range with the operand to simplify processing.  */
   value_range vr0, vr1;
+  wide_int nonzero0 = wi::shwi (-1, TYPE_PRECISION(expr_type)), nonzero1 = wi::shwi (-1, TYPE_PRECISION(expr_type));
   if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
+    {
+      vr0 = *(get_value_range (op0));
+      nonzero0 = get_nonzero_bits(op0);
+    }
   else if (is_gimple_min_invariant (op0))
     vr0.set (op0);
   else
     vr0.set_varying (TREE_TYPE (op0));
 
   if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
+    {
+      vr1 = *(get_value_range (op1));
+      nonzero1 = get_nonzero_bits(op1);
+    }
   else if (is_gimple_min_invariant (op1))
     vr1.set (op1);
   else
@@ -850,7 +857,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
 	vr1 = value_range (vrp_val_min (expr_type), vrp_val_max (expr_type));
     }
 
-  range_fold_binary_expr (vr, code, expr_type, &vr0, &vr1);
+  range_fold_binary_expr (vr, code, expr_type, &vr0, &vr1, nonzero0, nonzero1);
 
   /* Set value_range for n in following sequence:
      def = __builtin_memchr (arg, 0, sz)
@@ -911,7 +918,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
       else
 	n_vr1.set (op1, op1);
 
-      range_fold_binary_expr (vr, code, expr_type, &vr0, &n_vr1);
+      range_fold_binary_expr (vr, code, expr_type, &vr0, &n_vr1, nonzero0, nonzero1);
     }
 
   if (vr->varying_p ()
@@ -935,7 +942,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
       else
 	n_vr0.set (op0);
 
-      range_fold_binary_expr (vr, code, expr_type, &n_vr0, &vr1);
+      range_fold_binary_expr (vr, code, expr_type, &n_vr0, &vr1, nonzero0, nonzero1);
     }
 
   /* If we didn't derive a range for MINUS_EXPR, and
@@ -1318,7 +1325,8 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 						     type, op0);
 		      extract_range_from_unary_expr (&vr1, NOP_EXPR,
 						     type, op1);
-		      range_fold_binary_expr (vr, subcode, type, &vr0, &vr1);
+		      range_fold_binary_expr (vr, subcode, type, &vr0, &vr1, 
+								 wi::shwi (-1, TYPE_PRECISION(type)), wi::shwi (-1, TYPE_PRECISION(type)));
 		      flag_wrapv = saved_flag_wrapv;
 		    }
 		  return;
@@ -1723,7 +1731,9 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 	      tree tem = wide_int_to_tree (TREE_TYPE (init), wtmp);
 	      vr1.set (tem, tem);
 	      range_fold_binary_expr (&maxvr, PLUS_EXPR,
-				      TREE_TYPE (init), &vr0, &vr1);
+				      TREE_TYPE (init), &vr0, &vr1, 
+				      wi::shwi (-1, TYPE_PRECISION(TREE_TYPE(init))),
+				      wi::shwi (-1, TYPE_PRECISION(TREE_TYPE(init))));
 
 	      /* Likewise if the addition did.  */
 	      if (maxvr.kind () == VR_RANGE)
@@ -4250,4 +4260,4 @@ vr_values::swap_vr_value (tree var, value_range_equiv *vr)
     return NULL;
   std::swap (vr_value[SSA_NAME_VERSION (var)], vr);
   return vr;
-}
+}
\ No newline at end of file
