diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 65c49558b58..6788883c40b 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -128,6 +128,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "dbgcnt.h"
 #include "symtab-clones.h"
+#include "gimple-range.h"
 
 template <typename valtype> class ipcp_value;
 
@@ -1900,10 +1901,15 @@ ipa_vr_operation_and_type_effects (value_range *dst_vr,
 				   enum tree_code operation,
 				   tree dst_type, tree src_type)
 {
-  range_fold_unary_expr (dst_vr, operation, dst_type, src_vr, src_type);
-  if (dst_vr->varying_p () || dst_vr->undefined_p ())
+  if (!irange::supports_p (dst_type) || !irange::supports_p (src_type))
     return false;
-  return true;
+
+  range_op_handler handler (operation, dst_type);
+  return (handler
+	  && handler.fold_range (*dst_vr, dst_type,
+				 *src_vr, value_range (dst_type))
+	  && !dst_vr->varying_p ()
+	  && !dst_vr->undefined_p ());
 }
 
 /* Determine value_range of JFUNC given that INFO describes the caller node or
@@ -1958,8 +1964,13 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs,
 	  value_range op_res, res;
 	  tree op = ipa_get_jf_pass_through_operand (jfunc);
 	  value_range op_vr (op, op);
+	  range_op_handler handler (operation, vr_type);
+
+	  if (!handler
+	      || !op_res.supports_type_p (vr_type)
+	      || !handler.fold_range (op_res, vr_type, srcvr, op_vr))
+	    op_res.set_varying (vr_type);
 
-	  range_fold_binary_expr (&op_res, operation, vr_type, &srcvr, &op_vr);
 	  if (ipa_vr_operation_and_type_effects (&res,
 						 &op_res,
 						 NOP_EXPR, parm_type,
@@ -2748,9 +2759,14 @@ propagate_vr_across_jump_function (cgraph_edge *cs, ipa_jump_func *jfunc,
 	  tree op = ipa_get_jf_pass_through_operand (jfunc);
 	  value_range op_vr (op, op);
 	  value_range op_res,res;
+	  range_op_handler handler (operation, operand_type);
+
+	  if (!handler
+	      || !op_res.supports_type_p (operand_type)
+	      || !handler.fold_range (op_res, operand_type,
+				      src_lats->m_value_range.m_vr, op_vr))
+	    op_res.set_varying (operand_type);
 
-	  range_fold_binary_expr (&op_res, operation, operand_type,
-				  &src_lats->m_value_range.m_vr, &op_vr);
 	  ipa_vr_operation_and_type_effects (&vr,
 					     &op_res,
 					     NOP_EXPR, param_type,
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index d4b2a073240..03142960e60 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -481,13 +481,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 	      && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ())))
 	    {
 	      if (!useless_type_conversion_p (c->type, vr.type ()))
-		{
-		  value_range res;
-		  range_fold_unary_expr (&res, NOP_EXPR,
-				     c->type, &vr, vr.type ());
-		  vr = res;
-		}
-	      tree type = c->type;
+		range_cast (vr, c->type);
 
 	      for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++)
 		{
@@ -496,26 +490,45 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
 
 		  value_range res;
 		  if (!op->val[0])
-		    range_fold_unary_expr (&res, op->code, op->type, &vr, type);
+		    {
+		      range_op_handler handler (op->code, op->type);
+		      if (!handler
+			  || !res.supports_type_p (op->type)
+			  || !handler.fold_range (res, op->type, vr,
+						  value_range (op->type)))
+			res.set_varying (op->type);
+		    }
 		  else if (!op->val[1])
 		    {
 		      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);
+		      range_op_handler handler (op->code, op->type);
+
+		      if (!handler
+			  || !res.supports_type_p (op->type)
+			  || !handler.fold_range (res, op->type,
+						  op->index ? op0 : vr,
+						  op->index ? vr : op0))
+			res.set_varying (op->type);
 		    }
 		  else
 		    res.set_varying (op->type);
-		  type = op->type;
 		  vr = res;
 		}
 	      if (!vr.varying_p () && !vr.undefined_p ())
 		{
 		  value_range res;
-		  value_range val_vr (c->val, c->val);
-		  range_fold_binary_expr (&res, c->code, boolean_type_node,
-					  &vr,
-					  &val_vr);
+		  value_range val_vr;
+		  if (TREE_CODE (c->val) == INTEGER_CST)
+		    val_vr.set (c->val, c->val);
+		  else
+		    val_vr.set_varying (TREE_TYPE (c->val));
+		  range_op_handler handler (c->code, boolean_type_node);
+
+		  if (!handler
+		      || !res.supports_type_p (boolean_type_node)
+		      || !handler.fold_range (res, boolean_type_node, vr, val_vr))
+		    res.set_varying (boolean_type_node);
+
 		  if (res.zero_p ())
 		    continue;
 		}
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index a55cc72b0fd..f706f099f7a 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2323,9 +2323,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	      && get_range_query (cfun)->range_of_expr (vr, arg)
 	      && !vr.undefined_p ())
 	    {
-	      value_range resvr;
-	      range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
-				     &vr, TREE_TYPE (arg));
+	      value_range resvr = vr;
+	      range_cast (resvr, param_type);
 	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 41e12daf7f8..ea4fbd7af67 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -579,8 +579,10 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 		vr0.set_varying (TREE_TYPE (init));
 	      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);
+
+	      range_op_handler handler (PLUS_EXPR, TREE_TYPE (init));
+	      if (!handler.fold_range (maxvr, TREE_TYPE (init), vr0, vr1))
+		maxvr.set_varying (TREE_TYPE (init));
 
 	      /* Likewise if the addition did.  */
 	      if (maxvr.kind () == VR_RANGE)
