diff --git a/gcc/match.pd b/gcc/match.pd
index 0455dfa69937b212547832625b23a204cef7de2a..9024277e5d343ec70febbb96265bee349f67c49a 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -492,27 +492,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    of A starting from shift's type sign bit are zero, as
    (unsigned long long) (1 << 31) is -2147483648ULL, not 2147483648ULL,
    so it is valid only if A >> 31 is zero.  */
-(simplify
- (trunc_div (convert?@0 @3) (convert2? (lshift integer_onep@1 @2)))
- (if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
-      && (!VECTOR_TYPE_P (type)
-	  || target_supports_op_p (type, RSHIFT_EXPR, optab_vector)
-	  || target_supports_op_p (type, RSHIFT_EXPR, optab_scalar))
-      && (useless_type_conversion_p (type, TREE_TYPE (@1))
-	  || (element_precision (type) >= element_precision (TREE_TYPE (@1))
-	      && (TYPE_UNSIGNED (TREE_TYPE (@1))
-		  || (element_precision (type)
-		      == element_precision (TREE_TYPE (@1)))
-		  || (INTEGRAL_TYPE_P (type)
-		      && (tree_nonzero_bits (@0)
-			  & wi::mask (element_precision (TREE_TYPE (@1)) - 1,
-				      true,
-				      element_precision (type))) == 0)))))
-   (if (!VECTOR_TYPE_P (type)
-	&& useless_type_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1))
-	&& element_precision (TREE_TYPE (@3)) < element_precision (type))
-    (convert (rshift @3 @2))
-    (rshift @0 @2))))
+(for div (trunc_div exact_div)
+ (simplify
+  (div (convert?@0 @3) (convert2? (lshift integer_onep@1 @2)))
+  (if ((TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (@0))
+       && (!VECTOR_TYPE_P (type)
+	   || target_supports_op_p (type, RSHIFT_EXPR, optab_vector)
+	   || target_supports_op_p (type, RSHIFT_EXPR, optab_scalar))
+       && (useless_type_conversion_p (type, TREE_TYPE (@1))
+	   || (element_precision (type) >= element_precision (TREE_TYPE (@1))
+	       && (TYPE_UNSIGNED (TREE_TYPE (@1))
+		   || (element_precision (type)
+		       == element_precision (TREE_TYPE (@1)))
+		   || (INTEGRAL_TYPE_P (type)
+		       && (tree_nonzero_bits (@0)
+			   & wi::mask (element_precision (TREE_TYPE (@1)) - 1,
+				       true,
+				       element_precision (type))) == 0)))))
+    (if (!VECTOR_TYPE_P (type)
+	 && useless_type_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1))
+	 && element_precision (TREE_TYPE (@3)) < element_precision (type))
+     (convert (rshift @3 @2))
+     (rshift @0 @2)))))
 
 /* Preserve explicit divisions by 0: the C++ front-end wants to detect
    undefined behavior in constexpr evaluation, and assuming that the division
@@ -947,13 +948,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 				{ build_one_cst (utype); })))))))
 
 /* Simplify (unsigned t * 2)/2 -> unsigned t & 0x7FFFFFFF.  */
-(simplify
- (trunc_div (mult @0 integer_pow2p@1) @1)
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@0)))
-  (bit_and @0 { wide_int_to_tree
-		(type, wi::mask (TYPE_PRECISION (type)
-				 - wi::exact_log2 (wi::to_wide (@1)),
-				 false, TYPE_PRECISION (type))); })))
+(for div (trunc_div exact_div)
+ (simplify
+  (div (mult @0 integer_pow2p@1) @1)
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (bit_and @0 { wide_int_to_tree
+		 (type, wi::mask (TYPE_PRECISION (type)
+				  - wi::exact_log2 (wi::to_wide (@1)),
+				  false, TYPE_PRECISION (type))); }))))
 
 /* Simplify (unsigned t / 2) * 2 -> unsigned t & ~1.  */
 (simplify
@@ -5740,7 +5742,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Sink binary operation to branches, but only if we can fold it.  */
 (for op (tcc_comparison plus minus mult bit_and bit_ior bit_xor
-	 lshift rshift rdiv trunc_div ceil_div floor_div round_div
+	 lshift rshift rdiv trunc_div ceil_div floor_div round_div exact_div
 	 trunc_mod ceil_mod floor_mod round_mod min max)
 /* (c ? a : b) op (c ? d : e)  -->  c ? (a op d) : (b op e) */
  (simplify
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index 7441324aec2303655f590842ee571d49ddd8c265..68d091dc4a3a6bcbf5f6b6ddf07c03b792473281 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -4369,6 +4369,7 @@ force_expr_to_var_cost (tree expr, bool speed)
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
+    case EXACT_DIV_EXPR:
     case TRUNC_DIV_EXPR:
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
@@ -4482,6 +4483,7 @@ force_expr_to_var_cost (tree expr, bool speed)
 	return comp_cost (target_spill_cost [speed], 0);
       break;
 
+    case EXACT_DIV_EXPR:
     case TRUNC_DIV_EXPR:
       /* Division by power of two is usually cheap, so we allow it.  Forbid
 	 anything else.  */
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index f87731ef8929acc61e3714dd6c338c3b3b082a66..4583c2beda8578f124f8cfb88818950d56bdbd52 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -2328,7 +2328,7 @@ is_rshift_by_1 (gassign *stmt)
   if (gimple_assign_rhs_code (stmt) == RSHIFT_EXPR
       && integer_onep (gimple_assign_rhs2 (stmt)))
     return true;
-  if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR
+  if (trunc_or_exact_div_p (gimple_assign_rhs_code (stmt))
       && tree_fits_shwi_p (gimple_assign_rhs2 (stmt))
       && tree_to_shwi (gimple_assign_rhs2 (stmt)) == 2)
     return true;
diff --git a/gcc/tree.h b/gcc/tree.h
index f4c89f5477c50cd3fdc3fbfdc7e0360c7da4363a..efda032a220ce7c0f12039538bd6d796dd40e7bb 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5602,6 +5602,19 @@ struct_ptr_hash (const void *a)
   return (intptr_t)*x >> 4;
 }
 
+/* Return true if CODE can be treated as a truncating division.
+
+   EXACT_DIV_EXPR can be treated as a truncating division in which the
+   remainder is known to be zero.  However, if trunc_div_p gates the
+   generation of new IL, the conservative choice for that new IL is
+   TRUNC_DIV_EXPR rather than CODE.  Using CODE (EXACT_DIV_EXPR) would
+   only be correct if the transformation preserves exactness.  */
+inline bool
+trunc_or_exact_div_p (tree_code code)
+{
+  return code == TRUNC_DIV_EXPR || code == EXACT_DIV_EXPR;
+}
+
 /* Return nonzero if CODE is a tree code that represents a truth value.  */
 inline bool
 truth_value_p (enum tree_code code)