]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/match.pd
Fix typo in c-parser.c.
[thirdparty/gcc.git] / gcc / match.pd
index 698d27fe7777ef36a2b7b973548c0a1b0ebecea9..33ee1a920bf4a036cc5fdb3c96b38b52765bdefb 100644 (file)
@@ -2,7 +2,7 @@
    This file is consumed by genmatch which produces gimple-match.c
    and generic-match.c from it.
 
-   Copyright (C) 2014-2018 Free Software Foundation, Inc.
+   Copyright (C) 2014-2020 Free Software Foundation, Inc.
    Contributed by Richard Biener <rguenther@suse.de>
    and Prathamesh Kulkarni  <bilbotheelffriend@gmail.com>
 
@@ -29,13 +29,15 @@ along with GCC; see the file COPYING3.  If not see
    integer_each_onep integer_truep integer_nonzerop
    real_zerop real_onep real_minus_onep
    zerop
+   initializer_each_zero_or_onep
    CONSTANT_CLASS_P
    tree_expr_nonnegative_p
    tree_expr_nonzero_p
    integer_valued_real_p
    integer_pow2p
    uniform_integer_cst_p
-   HONOR_NANS)
+   HONOR_NANS
+   uniform_vector_p)
 
 /* Operator lists.  */
 (define_operator_list tcc_comparison
@@ -81,12 +83,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   plus minus
   mult trunc_div trunc_mod rdiv
   min max
-  bit_and bit_ior bit_xor)
+  bit_and bit_ior bit_xor
+  lshift rshift)
 (define_operator_list COND_BINARY
   IFN_COND_ADD IFN_COND_SUB
   IFN_COND_MUL IFN_COND_DIV IFN_COND_MOD IFN_COND_RDIV
   IFN_COND_MIN IFN_COND_MAX
-  IFN_COND_AND IFN_COND_IOR IFN_COND_XOR)
+  IFN_COND_AND IFN_COND_IOR IFN_COND_XOR
+  IFN_COND_SHL IFN_COND_SHR)
 
 /* Same for ternary operations.  */
 (define_operator_list UNCOND_TERNARY
@@ -94,8 +98,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (define_operator_list COND_TERNARY
   IFN_COND_FMA IFN_COND_FMS IFN_COND_FNMA IFN_COND_FNMS)
 
-/* As opposed to convert?, this still creates a single pattern, so
-   it is not a suitable replacement for convert? in all cases.  */
+/* With nop_convert? combine convert? and view_convert? in one pattern
+   plus conditionalize on tree_nop_conversion_p conversions.  */
 (match (nop_convert @0)
  (convert @0)
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
@@ -105,9 +109,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && known_eq (TYPE_VECTOR_SUBPARTS (type),
                   TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)))
       && tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0))))))
-/* This one has to be last, or it shadows the others.  */
-(match (nop_convert @0)
- @0)
 
 /* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x>
    ABSU_EXPR returns unsigned absolute value of the operand and the operand
@@ -119,6 +120,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
    (convert (absu:utype @0)))))
 
+#if GIMPLE
+/* Optimize (X + (X >> (prec - 1))) ^ (X >> (prec - 1)) into abs (X).  */
+(simplify
+ (bit_xor:c (plus:c @0 (rshift@2 @0 INTEGER_CST@1)) @2)
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && !TYPE_UNSIGNED (TREE_TYPE (@0))
+      && wi::to_widest (@1) == element_precision (TREE_TYPE (@0)) - 1)
+  (abs @0)))
+#endif
 
 /* Simplifications of operations with one constant operand and
    simplifications to constants or single values.  */
@@ -151,6 +161,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (fold_real_zero_addition_p (type, @1, 1))
   (non_lvalue @0)))
 
+/* Even if the fold_real_zero_addition_p can't simplify X + 0.0
+   into X, we can optimize (X + 0.0) + 0.0 or (X + 0.0) - 0.0
+   or (X - 0.0) + 0.0 into X + 0.0 and (X - 0.0) - 0.0 into X - 0.0
+   if not -frounding-math.  For sNaNs the first operation would raise
+   exceptions but turn the result into qNan, so the second operation
+   would not raise it.   */
+(for inner_op (plus minus)
+ (for outer_op (plus minus)
+  (simplify
+   (outer_op (inner_op@3 @0 REAL_CST@1) REAL_CST@2)
+    (if (real_zerop (@1)
+        && real_zerop (@2)
+        && !HONOR_SIGN_DEPENDENT_ROUNDING (type))
+     (with { bool inner_plus = ((inner_op == PLUS_EXPR)
+                               ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1)));
+            bool outer_plus
+              = ((outer_op == PLUS_EXPR)
+                 ^ REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@2))); }
+      (if (outer_plus && !inner_plus)
+       (outer_op @0 @2)
+       @3))))))
+
 /* Simplify x - x.
    This is unsafe for certain floats even in non-IEEE formats.
    In IEEE, it is unsafe because it does wrong for NaNs.
@@ -194,6 +226,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
            || !COMPLEX_FLOAT_TYPE_P (type)))
    (negate @0)))
 
+/* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 } */
+(simplify
+ (mult SSA_NAME@1 SSA_NAME@2)
+  (if (INTEGRAL_TYPE_P (type)
+       && get_nonzero_bits (@1) == 1
+       && get_nonzero_bits (@2) == 1)
+   (bit_and @1 @2)))
+
+/* Transform x * { 0 or 1, 0 or 1, ... } into x & { 0 or -1, 0 or -1, ...},
+   unless the target has native support for the former but not the latter.  */
+(simplify
+ (mult @0 VECTOR_CST@1)
+ (if (initializer_each_zero_or_onep (@1)
+      && !HONOR_SNANS (type)
+      && !HONOR_SIGNED_ZEROS (type))
+  (with { tree itype = FLOAT_TYPE_P (type) ? unsigned_type_for (type) : type; }
+   (if (itype
+       && (!VECTOR_MODE_P (TYPE_MODE (type))
+           || (VECTOR_MODE_P (TYPE_MODE (itype))
+               && optab_handler (and_optab,
+                                 TYPE_MODE (itype)) != CODE_FOR_nothing)))
+    (view_convert (bit_and:itype (view_convert @0)
+                                (ne @1 { build_zero_cst (type); })))))))
+
 (for cmp (gt ge lt le)
      outp (convert convert negate negate)
      outn (negate negate convert convert)
@@ -255,13 +311,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (A / (1 << B)) -> (A >> B).
    Only for unsigned A.  For signed A, this would not preserve rounding
    toward zero.
-   For example: (-1 / ( 1 << B)) !=  -1 >> B.  */
-(simplify
- (trunc_div @0 (lshift integer_onep@1 @2))
+   For example: (-1 / ( 1 << B)) !=  -1 >> B.
+   Also also widening conversions, like:
+   (A / (unsigned long long) (1U << B)) -> (A >> B)
+   or
+   (A / (unsigned long long) (1 << B)) -> (A >> B).
+   If the left shift is signed, it can be done only if the upper bits
+   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 @0 (convert? (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)))
+         || 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)))))
   (rshift @0 @2)))
 
 /* Preserve explicit divisions by 0: the C++ front-end wants to detect
@@ -312,17 +386,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    and floor_div is trickier and combining round_div even more so.  */
 (for div (trunc_div exact_div)
  (simplify
-  (div (div @0 INTEGER_CST@1) INTEGER_CST@2)
+  (div (div@3 @0 INTEGER_CST@1) INTEGER_CST@2)
   (with {
     wi::overflow_type overflow;
     wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
                            TYPE_SIGN (type), &overflow);
    }
-   (if (!overflow)
-    (div @0 { wide_int_to_tree (type, mul); })
-    (if (TYPE_UNSIGNED (type)
-        || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))
-     { build_zero_cst (type); })))))
+   (if (div == EXACT_DIV_EXPR
+       || optimize_successive_divisions_p (@2, @3))
+    (if (!overflow)
+     (div @0 { wide_int_to_tree (type, mul); })
+     (if (TYPE_UNSIGNED (type)
+         || mul != wi::min_value (TYPE_PRECISION (type), SIGNED))
+      { build_zero_cst (type); }))))))
 
 /* Combine successive multiplications.  Similar to above, but handling
    overflow is different.  */
@@ -779,6 +855,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (bit_xor:c (bit_and:cs @0 (bit_not @1)) (bit_not @0))
  (bit_not (bit_and @0 @1)))
 
+/* (~a & b) ^ a  -->   (a | b)   */
+(simplify
+ (bit_xor:c (bit_and:cs (bit_not @0) @1) @0)
+ (bit_ior @0 @1))
+
 /* (a | b) & ~(a ^ b)  -->  a & b  */
 (simplify
  (bit_and:c (bit_ior @0 @1) (bit_not (bit_xor:c @0 @1)))
@@ -938,6 +1019,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   @0))
 #endif
 
+/* ~(~X - Y) -> X + Y and ~(~X + Y) -> X - Y.  */
+(simplify
+ (bit_not (minus (bit_not @0) @1))
+ (plus @0 @1))
+(simplify
+ (bit_not (plus:c (bit_not @0) @1))
+ (minus @0 @1))
+
 /* x + (x & 1) -> (x + 1) & ~1 */
 (simplify
  (plus:c @0 (bit_and:s @0 integer_onep@1))
@@ -1239,7 +1328,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    We combine the above two cases by using a conditional convert.  */
 (for bitop (bit_and bit_ior bit_xor)
  (simplify
-  (bitop (convert @0) (convert? @1))
+  (bitop (convert@2 @0) (convert?@3 @1))
   (if (((TREE_CODE (@1) == INTEGER_CST
         && INTEGRAL_TYPE_P (TREE_TYPE (@0))
         && int_fits_type_p (@1, TREE_TYPE (@0)))
@@ -1258,8 +1347,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
           || GET_MODE_CLASS (TYPE_MODE (type)) != MODE_INT
           /* Or if the precision of TO is not the same as the precision
              of its mode.  */
-          || !type_has_mode_precision_p (type)))
-   (convert (bitop @0 (convert @1))))))
+          || !type_has_mode_precision_p (type)
+          /* In GIMPLE, getting rid of 2 conversions for one new results
+             in smaller IL.  */
+          || (GIMPLE
+              && TREE_CODE (@1) != INTEGER_CST
+              && tree_nop_conversion_p (type, TREE_TYPE (@0))
+              && single_use (@2)
+              && single_use (@3))))
+   (convert (bitop @0 (convert @1)))))
+ /* In GIMPLE, getting rid of 2 conversions for one new results
+    in smaller IL.  */
+ (simplify
+  (convert (bitop:cs@2 (nop_convert:s @0) @1))
+  (if (GIMPLE
+       && TREE_CODE (@1) != INTEGER_CST
+       && tree_nop_conversion_p (type, TREE_TYPE (@2))
+       && types_match (type, @0))
+   (bitop @0 (convert @1)))))
 
 (for bitop (bit_and bit_ior)
      rbitop (bit_ior bit_and)
@@ -1353,7 +1458,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Convert - (~A) to A + 1.  */
 (simplify
- (negate (nop_convert (bit_not @0)))
+ (negate (nop_convert? (bit_not @0)))
  (plus (view_convert @0) { build_each_one_cst (type); }))
 
 /* Convert ~ (A - 1) or ~ (A + -1) to -A.  */
@@ -1380,7 +1485,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Otherwise prefer ~(X ^ Y) to ~X ^ Y as more canonical.  */
 (simplify
- (bit_xor:c (nop_convert:s (bit_not:s @0)) @1)
+ (bit_xor:c (nop_convert?:s (bit_not:s @0)) @1)
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
   (bit_not (bit_xor (view_convert @0) @1))))
 
@@ -1400,7 +1505,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for cmp (gt lt ge le)
 (simplify
  (mult (convert (cmp @0 @1)) @2)
-  (cond (cmp @0 @1) @2 { build_zero_cst (type); })))
+  (if (GIMPLE || !TREE_SIDE_EFFECTS (@2))
+   (cond (cmp @0 @1) @2 { build_zero_cst (type); }))))
 
 /* For integral types with undefined overflow and C != 0 fold
    x * C EQ/NE y * C into x EQ/NE y.  */
@@ -1454,9 +1560,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* X / 4 < Y / 4 iff X < Y when the division is known to be exact.  */
 (for cmp (simple_comparison)
  (simplify
-  (cmp (exact_div @0 INTEGER_CST@2) (exact_div @1 @2))
-  (if (wi::gt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
-   (cmp @0 @1))))
+  (cmp (convert?@3 (exact_div @0 INTEGER_CST@2)) (convert? (exact_div @1 @2)))
+  (if (element_precision (@3) >= element_precision (@0)
+       && types_match (@0, @1))
+   (if (wi::lt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
+    (if (!TYPE_UNSIGNED (TREE_TYPE (@3)))
+     (cmp @1 @0)
+     (if (tree_expr_nonzero_p (@0) && tree_expr_nonzero_p (@1))
+      (with
+       {
+       tree utype = unsigned_type_for (TREE_TYPE (@0));
+       }
+       (cmp (convert:utype @1) (convert:utype @0)))))
+    (if (wi::gt_p (wi::to_wide (@2), 1, TYPE_SIGN (TREE_TYPE (@2))))
+     (if (TYPE_UNSIGNED (TREE_TYPE (@0)) || !TYPE_UNSIGNED (TREE_TYPE (@3)))
+      (cmp @0 @1)
+      (with
+       {
+       tree utype = unsigned_type_for (TREE_TYPE (@0));
+       }
+       (cmp (convert:utype @0) (convert:utype @1)))))))))
 
 /* X / C1 op C2 into a simple range test.  */
 (for cmp (simple_comparison)
@@ -1500,8 +1623,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        tree etype = range_check_type (TREE_TYPE (@0));
        if (etype)
          {
-           if (! TYPE_UNSIGNED (etype))
-             etype = unsigned_type_for (etype);
            hi = fold_convert (etype, hi);
            lo = fold_convert (etype, lo);
            hi = const_binop (MINUS_EXPR, etype, hi, lo);
@@ -1594,7 +1715,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* For equality, this is also true with wrapping overflow.  */
 (for op (eq ne)
  (simplify
-  (op:c (nop_convert@3 (plus:c@2 @0 (convert1? @1))) (convert2? @1))
+  (op:c (nop_convert?@3 (plus:c@2 @0 (convert1? @1))) (convert2? @1))
   (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
        && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
@@ -1603,7 +1724,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1)))
    (op @0 { build_zero_cst (TREE_TYPE (@0)); })))
  (simplify
-  (op:c (nop_convert@3 (pointer_plus@2 (convert1? @0) @1)) (convert2? @0))
+  (op:c (nop_convert?@3 (pointer_plus@2 (convert1? @0) @1)) (convert2? @0))
   (if (tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0))
        && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))
        && (CONSTANT_CLASS_P (@1) || (single_use (@2) && single_use (@3))))
@@ -1776,6 +1897,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (if (ptr_difference_const (@0, @1, &diff))
     { build_int_cst_type (type, diff); }))))
 
+/* Canonicalize (T *)(ptr - ptr-cst) to &MEM[ptr + -ptr-cst].  */
+(simplify
+ (convert (pointer_diff @0 INTEGER_CST@1))
+ (if (POINTER_TYPE_P (type))
+  { build_fold_addr_expr_with_type
+      (build2 (MEM_REF, char_type_node, @0,
+              wide_int_to_tree (ptr_type_node, wi::neg (wi::to_wide (@1)))),
+              type); }))
+
 /* If arg0 is derived from the address of an object or function, we may
    be able to fold this expression using the object or function's
    alignment.  */
@@ -1793,6 +1923,212 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     { wide_int_to_tree (type, (wi::to_wide (@1)
                               & (bitpos / BITS_PER_UNIT))); }))))
 
+(match min_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
+
+(match max_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::max_value (type)))))
+
+/* x >  y  &&  x != XXX_MIN  -->  x > y
+   x >  y  &&  x == XXX_MIN  -->  false . */
+(for eqne (eq ne)
+ (simplify
+  (bit_and:c (gt:c@2 @0 @1) (eqne @0 min_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     { constant_boolean_node (false, type); })
+    (if (eqne == NE_EXPR)
+     @2)
+    )))
+
+/* x <  y  &&  x != XXX_MAX  -->  x < y
+   x <  y  &&  x == XXX_MAX  -->  false.  */
+(for eqne (eq ne)
+ (simplify
+  (bit_and:c (lt:c@2 @0 @1) (eqne @0 max_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     { constant_boolean_node (false, type); })
+    (if (eqne == NE_EXPR)
+     @2)
+    )))
+
+/* x <=  y  &&  x == XXX_MIN  -->  x == XXX_MIN.  */
+(simplify
+ (bit_and:c (le:c @0 @1) (eq@2 @0 min_value))
+  @2)
+
+/* x >=  y  &&  x == XXX_MAX  -->  x == XXX_MAX.  */
+(simplify
+ (bit_and:c (ge:c @0 @1) (eq@2 @0 max_value))
+  @2)
+
+/* x >  y  ||  x != XXX_MIN   -->  x != XXX_MIN.  */
+(simplify
+ (bit_ior:c (gt:c @0 @1) (ne@2 @0 min_value))
+  @2)
+
+/* x <=  y  ||  x != XXX_MIN   -->  true.  */
+(simplify
+ (bit_ior:c (le:c @0 @1) (ne @0 min_value))
+  { constant_boolean_node (true, type); })
+
+/* x <=  y  ||  x == XXX_MIN   -->  x <= y.  */
+(simplify
+ (bit_ior:c (le:c@2 @0 @1) (eq @0 min_value))
+  @2)
+
+/* x <  y  ||  x != XXX_MAX   -->  x != XXX_MAX.  */
+(simplify
+ (bit_ior:c (lt:c @0 @1) (ne@2 @0 max_value))
+  @2)
+
+/* x >=  y  ||  x != XXX_MAX   -->  true
+   x >=  y  ||  x == XXX_MAX   -->  x >= y.  */
+(for eqne (eq ne)
+ (simplify
+  (bit_ior:c (ge:c@2 @0 @1) (eqne @0 max_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     @2)
+    (if (eqne == NE_EXPR)
+     { constant_boolean_node (true, type); }))))
+
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (simplify
+   (bit_and:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+      bool val;
+      switch (code2)
+        {
+       case EQ_EXPR: val = (cmp == 0); break;
+       case NE_EXPR: val = (cmp != 0); break;
+       case LT_EXPR: val = (cmp < 0); break;
+       case GT_EXPR: val = (cmp > 0); break;
+       case LE_EXPR: val = (cmp <= 0); break;
+       case GE_EXPR: val = (cmp >= 0); break;
+       default: gcc_unreachable ();
+       }
+     }
+     (switch
+      (if (code1 == EQ_EXPR && val) @3)
+      (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+      (if (code1 == NE_EXPR && !val) @4))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (simplify
+  (bit_and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+   (with
+    {
+     int cmp = tree_int_cst_compare (@1, @2);
+    }
+    (switch
+     /* Choose the more restrictive of two < or <= comparisons.  */
+     (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+         && (code2 == LT_EXPR || code2 == LE_EXPR))
+      (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+       @3
+       @4))
+     /* Likewise chose the more restrictive of two > or >= comparisons.  */
+     (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+         && (code2 == GT_EXPR || code2 == GE_EXPR))
+      (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+       @3
+       @4))
+     /* Check for singleton ranges.  */
+     (if (cmp == 0
+         && ((code1 == LE_EXPR && code2 == GE_EXPR)
+           || (code1 == GE_EXPR && code2 == LE_EXPR)))
+      (eq @0 @1))
+     /* Check for disjoint ranges.  */
+     (if (cmp <= 0
+         && (code1 == LT_EXPR || code1 == LE_EXPR)
+         && (code2 == GT_EXPR || code2 == GE_EXPR))
+      { constant_boolean_node (false, type); })
+     (if (cmp >= 0
+         && (code1 == GT_EXPR || code1 == GE_EXPR)
+         && (code2 == LT_EXPR || code2 == LE_EXPR))
+      { constant_boolean_node (false, type); })
+     )))))
+
+/* Convert (X == CST1) || (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (simplify
+   (bit_ior:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+      bool val;
+      switch (code2)
+       {
+       case EQ_EXPR: val = (cmp == 0); break;
+       case NE_EXPR: val = (cmp != 0); break;
+       case LT_EXPR: val = (cmp < 0); break;
+       case GT_EXPR: val = (cmp > 0); break;
+       case LE_EXPR: val = (cmp <= 0); break;
+       case GE_EXPR: val = (cmp >= 0); break;
+       default: gcc_unreachable ();
+       }
+     }
+     (switch
+      (if (code1 == EQ_EXPR && val) @4)
+      (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
+      (if (code1 == NE_EXPR && !val) @3))))))
+
+/* Convert (X OP1 CST1) || (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (simplify
+  (bit_ior (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+   (with
+    {
+     int cmp = tree_int_cst_compare (@1, @2);
+    }
+    (switch
+     /* Choose the more restrictive of two < or <= comparisons.  */
+     (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+         && (code2 == LT_EXPR || code2 == LE_EXPR))
+      (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+       @4
+       @3))
+     /* Likewise chose the more restrictive of two > or >= comparisons.  */
+     (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+         && (code2 == GT_EXPR || code2 == GE_EXPR))
+      (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+       @4
+       @3))
+     /* Check for singleton ranges.  */
+     (if (cmp == 0
+         && ((code1 == LT_EXPR && code2 == GT_EXPR)
+             || (code1 == GT_EXPR && code2 == LT_EXPR)))
+      (ne @0 @2))
+     /* Check for disjoint ranges.  */
+     (if (cmp >= 0
+         && (code1 == LT_EXPR || code1 == LE_EXPR)
+         && (code2 == GT_EXPR || code2 == GE_EXPR))
+      { constant_boolean_node (true, type); })
+     (if (cmp <= 0
+         && (code1 == GT_EXPR || code1 == GE_EXPR)
+         && (code2 == LT_EXPR || code2 == LE_EXPR))
+      { constant_boolean_node (true, type); })
+     )))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
@@ -1846,7 +2182,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
           || !HONOR_SIGN_DEPENDENT_ROUNDING (type)))
    (convert (negate @1))))
  (simplify
-  (negate (nop_convert (negate @1)))
+  (negate (nop_convert? (negate @1)))
   (if (!TYPE_OVERFLOW_SANITIZED (type)
        && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@1)))
    (view_convert @1)))
@@ -1863,20 +2199,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   /* A - (A +- B)       -> -+ B */
   /* A +- (B -+ A)      ->  +- B */
   (simplify
-    (minus (plus:c @0 @1) @0)
-    @1)
+   (minus (nop_convert1? (plus:c (nop_convert2? @0) @1)) @0)
+   (view_convert @1))
   (simplify
-    (minus (minus @0 @1) @0)
-    (negate @1))
+   (minus (nop_convert1? (minus (nop_convert2? @0) @1)) @0)
+   (if (!ANY_INTEGRAL_TYPE_P (type)
+       || TYPE_OVERFLOW_WRAPS (type))
+   (negate (view_convert @1))
+   (view_convert (negate @1))))
   (simplify
-    (plus:c (minus @0 @1) @1)
-    @0)
+   (plus:c (nop_convert1? (minus @0 (nop_convert2? @1))) @1)
+   (view_convert @0))
   (simplify
-   (minus @0 (plus:c @0 @1))
-   (negate @1))
+   (minus @0 (nop_convert1? (plus:c (nop_convert2? @0) @1)))
+    (if (!ANY_INTEGRAL_TYPE_P (type)
+        || TYPE_OVERFLOW_WRAPS (type))
+     (negate (view_convert @1))
+     (view_convert (negate @1))))
   (simplify
-   (minus @0 (minus @0 @1))
-   @1)
+   (minus @0 (nop_convert1? (minus (nop_convert2? @0) @1)))
+   (view_convert @1))
   /* (A +- B) + (C - A)   -> C +- B */
   /* (A +  B) - (A - C)   -> B + C */
   /* More cases are handled with comparisons.  */
@@ -1902,7 +2244,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (for inner_op (plus minus)
        neg_inner_op (minus plus)
     (simplify
-     (outer_op (nop_convert (inner_op @0 CONSTANT_CLASS_P@1))
+     (outer_op (nop_convert? (inner_op @0 CONSTANT_CLASS_P@1))
               CONSTANT_CLASS_P@2)
      /* If one of the types wraps, use that one.  */
      (if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
@@ -1941,17 +2283,85 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   /* (CST1 - A) +- CST2 -> CST3 - A  */
   (for outer_op (plus minus)
    (simplify
-    (outer_op (minus CONSTANT_CLASS_P@1 @0) CONSTANT_CLASS_P@2)
-    (with { tree cst = const_binop (outer_op, type, @1, @2); }
-     (if (cst && !TREE_OVERFLOW (cst))
-      (minus { cst; } @0)))))
-
-  /* CST1 - (CST2 - A) -> CST3 + A  */
+    (outer_op (nop_convert? (minus CONSTANT_CLASS_P@1 @0)) CONSTANT_CLASS_P@2)
+    /* If one of the types wraps, use that one.  */
+    (if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
+     /* If all 3 captures are CONSTANT_CLASS_P, punt, as we might recurse
+       forever if something doesn't simplify into a constant.  */
+     (if (!CONSTANT_CLASS_P (@0))
+      (minus (outer_op (view_convert @1) @2) (view_convert @0)))
+     (if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+         || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+      (view_convert (minus (outer_op @1 (view_convert @2)) @0))
+      (if (types_match (type, @0))
+       (with { tree cst = const_binop (outer_op, type, @1, @2); }
+       (if (cst && !TREE_OVERFLOW (cst))
+        (minus { cst; } @0))))))))
+
+  /* CST1 - (CST2 - A) -> CST3 + A
+     Use view_convert because it is safe for vectors and equivalent for
+     scalars.  */
   (simplify
-   (minus CONSTANT_CLASS_P@1 (minus CONSTANT_CLASS_P@2 @0))
-   (with { tree cst = const_binop (MINUS_EXPR, type, @1, @2); }
-    (if (cst && !TREE_OVERFLOW (cst))
-     (plus { cst; } @0))))
+   (minus CONSTANT_CLASS_P@1 (nop_convert? (minus CONSTANT_CLASS_P@2 @0)))
+   /* If one of the types wraps, use that one.  */
+   (if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type))
+    /* If all 3 captures are CONSTANT_CLASS_P, punt, as we might recurse
+      forever if something doesn't simplify into a constant.  */
+    (if (!CONSTANT_CLASS_P (@0))
+     (plus (view_convert @0) (minus @1 (view_convert @2))))
+    (if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+        || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+     (view_convert (plus @0 (minus (view_convert @1) @2)))
+     (if (types_match (type, @0))
+      (with { tree cst = const_binop (MINUS_EXPR, type, @1, @2); }
+       (if (cst && !TREE_OVERFLOW (cst))
+       (plus { cst; } @0)))))))
+
+/* ((T)(A)) + CST -> (T)(A + CST)  */
+#if GIMPLE
+  (simplify
+   (plus (convert SSA_NAME@0) INTEGER_CST@1)
+    (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
+         && TREE_CODE (type) == INTEGER_TYPE
+         && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+         && int_fits_type_p (@1, TREE_TYPE (@0)))
+     /* Perform binary operation inside the cast if the constant fits
+        and (A + CST)'s range does not overflow.  */
+     (with
+      {
+       wi::overflow_type min_ovf = wi::OVF_OVERFLOW,
+                         max_ovf = wi::OVF_OVERFLOW;
+        tree inner_type = TREE_TYPE (@0);
+
+       wide_int w1
+         = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
+                           TYPE_SIGN (inner_type));
+
+        wide_int wmin0, wmax0;
+        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
+          {
+            wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
+            wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
+          }
+      }
+     (if (min_ovf == wi::OVF_NONE && max_ovf == wi::OVF_NONE)
+      (convert (plus @0 { wide_int_to_tree (TREE_TYPE (@0), w1); } )))
+     )))
+#endif
+
+/* ((T)(A + CST1)) + CST2 -> (T)(A) + (T)CST1 + CST2  */
+#if GIMPLE
+  (for op (plus minus)
+   (simplify
+    (plus (convert:s (op:s @0 INTEGER_CST@1)) INTEGER_CST@2)
+     (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
+         && TREE_CODE (type) == INTEGER_TYPE
+         && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+         && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+         && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0))
+         && TYPE_OVERFLOW_WRAPS (type))
+       (plus (convert @0) (op @2 (convert @1))))))
+#endif
 
   /* ~A + A -> -1 */
   (simplify
@@ -2138,21 +2548,80 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (plusminus @0 (mult:c@3 @0 @2))
     (if ((!ANY_INTEGRAL_TYPE_P (type)
          || TYPE_OVERFLOW_WRAPS (type)
+         /* For @0 + @0*@2 this transformation would introduce UB
+            (where there was none before) for @0 in [-1,0] and @2 max.
+            For @0 - @0*@2 this transformation would introduce UB
+            for @0 0 and @2 in [min,min+1] or @0 -1 and @2 min+1.  */
          || (INTEGRAL_TYPE_P (type)
-             && tree_expr_nonzero_p (@0)
-             && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION (type)))))
+             && ((tree_expr_nonzero_p (@0)
+                  && expr_not_equal_to (@0,
+                               wi::minus_one (TYPE_PRECISION (type))))
+                 || (plusminus == PLUS_EXPR
+                     ? expr_not_equal_to (@2,
+                           wi::max_value (TYPE_PRECISION (type), SIGNED))
+                     /* Let's ignore the @0 -1 and @2 min case.  */
+                     : (expr_not_equal_to (@2,
+                           wi::min_value (TYPE_PRECISION (type), SIGNED))
+                        && expr_not_equal_to (@2,
+                               wi::min_value (TYPE_PRECISION (type), SIGNED)
+                               + 1))))))
         && single_use (@3))
      (mult (plusminus { build_one_cst (type); } @2) @0)))
    (simplify
     (plusminus (mult:c@3 @0 @2) @0)
     (if ((!ANY_INTEGRAL_TYPE_P (type)
          || TYPE_OVERFLOW_WRAPS (type)
+         /* For @0*@2 + @0 this transformation would introduce UB
+            (where there was none before) for @0 in [-1,0] and @2 max.
+            For @0*@2 - @0 this transformation would introduce UB
+            for @0 0 and @2 min.  */
          || (INTEGRAL_TYPE_P (type)
-             && tree_expr_nonzero_p (@0)
-             && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION (type)))))
+             && ((tree_expr_nonzero_p (@0)
+                  && (plusminus == MINUS_EXPR
+                      || expr_not_equal_to (@0,
+                               wi::minus_one (TYPE_PRECISION (type)))))
+                 || expr_not_equal_to (@2,
+                       (plusminus == PLUS_EXPR
+                        ? wi::max_value (TYPE_PRECISION (type), SIGNED)
+                        : wi::min_value (TYPE_PRECISION (type), SIGNED))))))
         && single_use (@3))
      (mult (plusminus @2 { build_one_cst (type); }) @0))))))
 
+#if GIMPLE
+/* Canonicalize X + (X << C) into X * (1 + (1 << C)) and
+   (X << C1) + (X << C2) into X * ((1 << C1) + (1 << C2)).  */
+(simplify
+ (plus:c @0 (lshift:s @0 INTEGER_CST@1))
+  (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && tree_fits_uhwi_p (@1)
+       && tree_to_uhwi (@1) < element_precision (type))
+   (with { tree t = type;
+          if (!TYPE_OVERFLOW_WRAPS (t)) t = unsigned_type_for (t);
+          wide_int w = wi::set_bit_in_zero (tree_to_uhwi (@1),
+                                            element_precision (type));
+          w += 1;
+          tree cst = wide_int_to_tree (VECTOR_TYPE_P (t) ? TREE_TYPE (t)
+                                       : t, w);
+          cst = build_uniform_cst (t, cst); }
+    (convert (mult (convert:t @0) { cst; })))))
+(simplify
+ (plus (lshift:s @0 INTEGER_CST@1) (lshift:s @0 INTEGER_CST@2))
+  (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && tree_fits_uhwi_p (@1)
+       && tree_to_uhwi (@1) < element_precision (type)
+       && tree_fits_uhwi_p (@2)
+       && tree_to_uhwi (@2) < element_precision (type))
+   (with { tree t = type;
+          if (!TYPE_OVERFLOW_WRAPS (t)) t = unsigned_type_for (t);
+          unsigned int prec = element_precision (type);
+          wide_int w = wi::set_bit_in_zero (tree_to_uhwi (@1), prec);
+          w += wi::set_bit_in_zero (tree_to_uhwi (@2), prec);
+          tree cst = wide_int_to_tree (VECTOR_TYPE_P (t) ? TREE_TYPE (t)
+                                       : t, w);
+          cst = build_uniform_cst (t, cst); }
+    (convert (mult (convert:t @0) { cst; })))))
+#endif
+
 /* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax().  */
 
 (for minmax (min max FMIN_ALL FMAX_ALL)
@@ -2306,6 +2775,45 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (cmp (minmax @0 INTEGER_CST@1) INTEGER_CST@2)
   (comb (cmp @0 @2) (cmp @1 @2))))
 
+/* Undo fancy way of writing max/min or other ?: expressions,
+   like a - ((a - b) & -(a < b)), in this case into (a < b) ? b : a.
+   People normally use ?: and that is what we actually try to optimize.  */
+(for cmp (simple_comparison)
+ (simplify
+  (minus @0 (bit_and:c (minus @0 @1)
+                      (convert? (negate@4 (convert? (cmp@5 @2 @3))))))
+  (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (TREE_TYPE (@4))
+       && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
+       && INTEGRAL_TYPE_P (TREE_TYPE (@5))
+       && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
+          || !TYPE_UNSIGNED (TREE_TYPE (@4)))
+       && (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
+   (cond (cmp @2 @3) @1 @0)))
+ (simplify
+  (plus:c @0 (bit_and:c (minus @1 @0)
+                       (convert? (negate@4 (convert? (cmp@5 @2 @3))))))
+  (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (TREE_TYPE (@4))
+       && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
+       && INTEGRAL_TYPE_P (TREE_TYPE (@5))
+       && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
+          || !TYPE_UNSIGNED (TREE_TYPE (@4)))
+       && (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
+   (cond (cmp @2 @3) @1 @0)))
+ /* Similarly with ^ instead of - though in that case with :c.  */
+ (simplify
+  (bit_xor:c @0 (bit_and:c (bit_xor:c @0 @1)
+                          (convert? (negate@4 (convert? (cmp@5 @2 @3))))))
+  (if (INTEGRAL_TYPE_P (type)
+       && INTEGRAL_TYPE_P (TREE_TYPE (@4))
+       && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE
+       && INTEGRAL_TYPE_P (TREE_TYPE (@5))
+       && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type)
+          || !TYPE_UNSIGNED (TREE_TYPE (@4)))
+       && (GIMPLE || !TREE_SIDE_EFFECTS (@1)))
+   (cond (cmp @2 @3) @1 @0))))
+
 /* Simplifications of shift and rotates.  */
 
 (for rotate (lrotate rrotate)
@@ -2322,9 +2830,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Optimize (x >> c) << c into x & (-1<<c).  */
 (simplify
- (lshift (rshift @0 INTEGER_CST@1) @1)
+ (lshift (nop_convert? (rshift @0 INTEGER_CST@1)) @1)
  (if (wi::ltu_p (wi::to_wide (@1), element_precision (type)))
-  (bit_and @0 (lshift { build_minus_one_cst (type); } @1))))
+  /* It doesn't matter if the right shift is arithmetic or logical.  */
+  (bit_and (view_convert @0) (lshift { build_minus_one_cst (type); } @1))))
+
+(simplify
+ (lshift (convert (convert@2 (rshift @0 INTEGER_CST@1))) @1)
+ (if (wi::ltu_p (wi::to_wide (@1), element_precision (type))
+      /* Allow intermediate conversion to integral type with whatever sign, as
+        long as the low TYPE_PRECISION (type)
+        - TYPE_PRECISION (TREE_TYPE (@2)) bits are preserved.  */
+      && INTEGRAL_TYPE_P (type)
+      && INTEGRAL_TYPE_P (TREE_TYPE (@2))
+      && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (@0))
+      && (TYPE_PRECISION (TREE_TYPE (@2)) >= TYPE_PRECISION (type)
+         || wi::geu_p (wi::to_wide (@1),
+                       TYPE_PRECISION (type)
+                       - TYPE_PRECISION (TREE_TYPE (@2)))))
+  (bit_and (convert @0) (lshift { build_minus_one_cst (type); } @1))))
 
 /* Optimize (x << c) >> c into x & ((unsigned)-1 >> c) for unsigned
    types.  */
@@ -2577,6 +3102,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
               && TYPE_UNSIGNED (TREE_TYPE (@1)))))
    (view_convert @1)))
 
+/* Simplify a view-converted empty constructor.  */
+(simplify
+  (view_convert CONSTRUCTOR@0)
+  (if (TREE_CODE (@0) != SSA_NAME
+       && CONSTRUCTOR_NELTS (@0) == 0)
+   { build_zero_cst (type); }))
+
 /* Re-association barriers around constants and other re-association
    barriers can be removed.  */
 (simplify
@@ -2710,6 +3242,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (mult (convert1? (exact_div @0 @@1)) (convert2? @1))
   (convert @0))
 
+/* Simplify (A / B) * B + (A % B) -> A.  */
+(for div (trunc_div ceil_div floor_div round_div)
+     mod (trunc_mod ceil_mod floor_mod round_mod)
+  (simplify
+   (plus:c (mult:c (div @0 @1) @1) (mod @0 @1))
+   @0))
+
 /* ((X /[ex] A) +- B) * A  -->  X +- A * B.  */
 (for op (plus minus)
  (simplify
@@ -2863,6 +3402,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (integer_zerop (@0))
    @2)))
 
+/* Sink unary operations to constant branches, but only if we do fold it to
+   constants.  */
+(for op (negate bit_not abs absu)
+ (simplify
+  (op (vec_cond @0 VECTOR_CST@1 VECTOR_CST@2))
+  (with
+   {
+     tree cst1, cst2;
+     cst1 = const_unop (op, type, @1);
+     if (cst1)
+       cst2 = const_unop (op, type, @2);
+   }
+   (if (cst1 && cst2)
+    (vec_cond @0 { cst1; } { cst2; })))))
+
 /* Simplification moved from fold_cond_expr_with_comparison.  It may also
    be extended.  */
 /* This pattern implements two kinds simplification:
@@ -3355,8 +3909,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (cmp { tem; } @1)))))
 
  /* Fold comparisons against built-in math functions.  */
- (if (flag_unsafe_math_optimizations
-      && ! flag_errno_math)
+ (if (flag_unsafe_math_optimizations && ! flag_errno_math)
   (for sq (SQRT)
    (simplify
     (cmp (sq @0) REAL_CST@1)
@@ -3391,56 +3944,108 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
          if x is negative or NaN.  Due to -funsafe-math-optimizations,
          the results for other x follow from natural arithmetic.  */
        (cmp @0 @1)))
-     (if (cmp == GT_EXPR || cmp == GE_EXPR)
+     (if ((cmp == LT_EXPR
+          || cmp == LE_EXPR
+          || cmp == GT_EXPR
+          || cmp == GE_EXPR)
+         && !REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
+         /* Give up for -frounding-math.  */
+         && !HONOR_SIGN_DEPENDENT_ROUNDING (TREE_TYPE (@0)))
       (with
        {
-         REAL_VALUE_TYPE c2;
+        REAL_VALUE_TYPE c2;
+        enum tree_code ncmp = cmp;
+        const real_format *fmt
+          = REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0)));
         real_arithmetic (&c2, MULT_EXPR,
                          &TREE_REAL_CST (@1), &TREE_REAL_CST (@1));
-        real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
-       }
-       (if (REAL_VALUE_ISINF (c2))
-       /* sqrt(x) > y is x == +Inf, when y is very large.  */
-       (if (HONOR_INFINITIES (@0))
-        (eq @0 { build_real (TREE_TYPE (@0), c2); })
-        { constant_boolean_node (false, type); })
-       /* sqrt(x) > c is the same as x > c*c.  */
-       (cmp @0 { build_real (TREE_TYPE (@0), c2); }))))
-     (if (cmp == LT_EXPR || cmp == LE_EXPR)
-      (with
-       {
-                REAL_VALUE_TYPE c2;
-        real_arithmetic (&c2, MULT_EXPR,
-                         &TREE_REAL_CST (@1), &TREE_REAL_CST (@1));
-        real_convert (&c2, TYPE_MODE (TREE_TYPE (@0)), &c2);
+        real_convert (&c2, fmt, &c2);
+        /* See PR91734: if c2 is inexact and sqrt(c2) < c (or sqrt(c2) >= c),
+           then change LT_EXPR into LE_EXPR or GE_EXPR into GT_EXPR.  */
+        if (!REAL_VALUE_ISINF (c2))
+          {
+            tree c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
+                                       build_real (TREE_TYPE (@0), c2));
+            if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
+              ncmp = ERROR_MARK;
+            else if ((cmp == LT_EXPR || cmp == GE_EXPR)
+                     && real_less (&TREE_REAL_CST (c3), &TREE_REAL_CST (@1)))
+              ncmp = cmp == LT_EXPR ? LE_EXPR : GT_EXPR;
+            else if ((cmp == LE_EXPR || cmp == GT_EXPR)
+                     && real_less (&TREE_REAL_CST (@1), &TREE_REAL_CST (c3)))
+              ncmp = cmp == LE_EXPR ? LT_EXPR : GE_EXPR;
+            else
+              {
+                /* With rounding to even, sqrt of up to 3 different values
+                   gives the same normal result, so in some cases c2 needs
+                   to be adjusted.  */
+                REAL_VALUE_TYPE c2alt, tow;
+                if (cmp == LT_EXPR || cmp == GE_EXPR)
+                  tow = dconst0;
+                else
+                  real_inf (&tow);
+                real_nextafter (&c2alt, fmt, &c2, &tow);
+                real_convert (&c2alt, fmt, &c2alt);
+                if (REAL_VALUE_ISINF (c2alt))
+                  ncmp = ERROR_MARK;
+                else
+                  {
+                    c3 = fold_const_call (CFN_SQRT, TREE_TYPE (@0),
+                                          build_real (TREE_TYPE (@0), c2alt));
+                    if (c3 == NULL_TREE || TREE_CODE (c3) != REAL_CST)
+                      ncmp = ERROR_MARK;
+                    else if (real_equal (&TREE_REAL_CST (c3),
+                                         &TREE_REAL_CST (@1)))
+                      c2 = c2alt;
+                  }
+              }
+          }
        }
-       (if (REAL_VALUE_ISINF (c2))
-        (switch
-        /* sqrt(x) < y is always true, when y is a very large
-           value and we don't care about NaNs or Infinities.  */
-        (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
-         { constant_boolean_node (true, type); })
-        /* sqrt(x) < y is x != +Inf when y is very large and we
-           don't care about NaNs.  */
-        (if (! HONOR_NANS (@0))
-         (ne @0 { build_real (TREE_TYPE (@0), c2); }))
-        /* sqrt(x) < y is x >= 0 when y is very large and we
-           don't care about Infinities.  */
-        (if (! HONOR_INFINITIES (@0))
-         (ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
-        /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
-        (if (GENERIC)
-         (truth_andif
-          (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
-          (ne @0 { build_real (TREE_TYPE (@0), c2); }))))
-       /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
-       (if (! HONOR_NANS (@0))
-        (cmp @0 { build_real (TREE_TYPE (@0), c2); })
-        /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
-        (if (GENERIC)
-         (truth_andif
-          (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
-          (cmp @0 { build_real (TREE_TYPE (@0), c2); })))))))))
+       (if (cmp == GT_EXPR || cmp == GE_EXPR)
+       (if (REAL_VALUE_ISINF (c2))
+        /* sqrt(x) > y is x == +Inf, when y is very large.  */
+        (if (HONOR_INFINITIES (@0))
+         (eq @0 { build_real (TREE_TYPE (@0), c2); })
+         { constant_boolean_node (false, type); })
+        /* sqrt(x) > c is the same as x > c*c.  */
+        (if (ncmp != ERROR_MARK)
+         (if (ncmp == GE_EXPR)
+          (ge @0 { build_real (TREE_TYPE (@0), c2); })
+          (gt @0 { build_real (TREE_TYPE (@0), c2); }))))
+       /* else if (cmp == LT_EXPR || cmp == LE_EXPR)  */
+       (if (REAL_VALUE_ISINF (c2))
+        (switch
+         /* sqrt(x) < y is always true, when y is a very large
+            value and we don't care about NaNs or Infinities.  */
+         (if (! HONOR_NANS (@0) && ! HONOR_INFINITIES (@0))
+          { constant_boolean_node (true, type); })
+         /* sqrt(x) < y is x != +Inf when y is very large and we
+            don't care about NaNs.  */
+         (if (! HONOR_NANS (@0))
+          (ne @0 { build_real (TREE_TYPE (@0), c2); }))
+         /* sqrt(x) < y is x >= 0 when y is very large and we
+            don't care about Infinities.  */
+         (if (! HONOR_INFINITIES (@0))
+          (ge @0 { build_real (TREE_TYPE (@0), dconst0); }))
+         /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
+         (if (GENERIC)
+          (truth_andif
+           (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
+           (ne @0 { build_real (TREE_TYPE (@0), c2); }))))
+        /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
+        (if (ncmp != ERROR_MARK && ! HONOR_NANS (@0))
+         (if (ncmp == LT_EXPR)
+          (lt @0 { build_real (TREE_TYPE (@0), c2); })
+          (le @0 { build_real (TREE_TYPE (@0), c2); }))
+         /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
+         (if (ncmp != ERROR_MARK && GENERIC)
+          (if (ncmp == LT_EXPR)
+           (truth_andif
+            (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
+            (lt @0 { build_real (TREE_TYPE (@0), c2); }))
+           (truth_andif
+            (ge @0 { build_real (TREE_TYPE (@0), dconst0); })
+            (le @0 { build_real (TREE_TYPE (@0), c2); })))))))))))
    /* Transform sqrt(x) cmp sqrt(y) -> x cmp y.  */
    (simplify
     (cmp (sq @0) (sq @1))
@@ -3578,6 +4183,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                              != (cmp == LT_EXPR || cmp == LE_EXPR), type); }
      (cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))
 
+/* Fold (size_t)(A /[ex] B) CMP C to (size_t)A CMP (size_t)B * C or A CMP' 0.
+
+   For small C (less than max/B), this is (size_t)A CMP (size_t)B * C.
+   For large C (more than min/B+2^size), this is also true, with the
+   multiplication computed modulo 2^size.
+   For intermediate C, this just tests the sign of A.  */
+(for cmp  (lt le gt ge)
+     cmp2 (ge ge lt lt)
+ (simplify
+  (cmp (convert (exact_div @0 INTEGER_CST@1)) INTEGER_CST@2)
+  (if (tree_nop_conversion_p (TREE_TYPE (@0), TREE_TYPE (@2))
+       && TYPE_UNSIGNED (TREE_TYPE (@2)) && !TYPE_UNSIGNED (TREE_TYPE (@0))
+       && wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
+   (with
+    {
+      tree utype = TREE_TYPE (@2);
+      wide_int denom = wi::to_wide (@1);
+      wide_int right = wi::to_wide (@2);
+      wide_int smax = wi::sdiv_trunc (wi::max_value (TREE_TYPE (@0)), denom);
+      wide_int smin = wi::sdiv_trunc (wi::min_value (TREE_TYPE (@0)), denom);
+      bool small = wi::leu_p (right, smax);
+      bool large = wi::geu_p (right, smin);
+    }
+    (if (small || large)
+     (cmp (convert:utype @0) (mult @2 (convert @1)))
+     (cmp2 @0 { build_zero_cst (TREE_TYPE (@0)); }))))))
+
 /* Unordered tests if either argument is a NaN.  */
 (simplify
  (bit_ior (unordered @0 @0) (unordered @1 @1))
@@ -3727,19 +4359,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
            { constant_boolean_node (above ? false : true, type); }))))))))))))
 
 (for cmp (eq ne)
- /* A local variable can never be pointed to by
-    the default SSA name of an incoming parameter.
-    SSA names are canonicalized to 2nd place.  */
  (simplify
+  /* SSA names are canonicalized to 2nd place.  */
   (cmp addr@0 SSA_NAME@1)
-  (if (SSA_NAME_IS_DEFAULT_DEF (@1)
-       && TREE_CODE (SSA_NAME_VAR (@1)) == PARM_DECL)
-   (with { tree base = get_base_address (TREE_OPERAND (@0, 0)); }
-    (if (TREE_CODE (base) == VAR_DECL
-         && auto_var_in_fn_p (base, current_function_decl))
-     (if (cmp == NE_EXPR)
-      { constant_boolean_node (true, type); }
-      { constant_boolean_node (false, type); }))))))
+  (with
+   { poly_int64 off; tree base; }
+   /* A local variable can never be pointed to by
+      the default SSA name of an incoming parameter.  */
+   (if (SSA_NAME_IS_DEFAULT_DEF (@1)
+       && TREE_CODE (SSA_NAME_VAR (@1)) == PARM_DECL
+       && (base = get_base_address (TREE_OPERAND (@0, 0)))
+       && TREE_CODE (base) == VAR_DECL
+       && auto_var_in_fn_p (base, current_function_decl))
+    (if (cmp == NE_EXPR)
+     { constant_boolean_node (true, type); }
+     { constant_boolean_node (false, type); })
+    /* If the address is based on @1 decide using the offset.  */
+    (if ((base = get_addr_base_and_unit_offset (TREE_OPERAND (@0, 0), &off))
+        && TREE_CODE (base) == MEM_REF
+        && TREE_OPERAND (base, 0) == @1)
+     (with { off += mem_ref_offset (base).force_shwi (); }
+      (if (known_ne (off, 0))
+       { constant_boolean_node (cmp == NE_EXPR, type); }
+       (if (known_eq (off, 0))
+        { constant_boolean_node (cmp == EQ_EXPR, type); }))))))))
 
 /* Equality compare simplifications from fold_binary  */
 (for cmp (eq ne)
@@ -3772,7 +4415,36 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (simplify
   (cmp (convert? addr@0) integer_zerop)
   (if (tree_single_nonzero_warnv_p (@0, NULL))
-   { constant_boolean_node (cmp == NE_EXPR, type); })))
+   { constant_boolean_node (cmp == NE_EXPR, type); }))
+
+ /* (X & C) op (Y & C) into (X ^ Y) & C op 0.  */
+ (simplify
+  (cmp (bit_and:cs @0 @2) (bit_and:cs @1 @2))
+  (cmp (bit_and (bit_xor @0 @1) @2) { build_zero_cst (TREE_TYPE (@2)); })))
+
+/* (X < 0) != (Y < 0) into (X ^ Y) < 0.
+   (X >= 0) != (Y >= 0) into (X ^ Y) < 0.
+   (X < 0) == (Y < 0) into (X ^ Y) >= 0.
+   (X >= 0) == (Y >= 0) into (X ^ Y) >= 0.  */
+(for cmp (eq ne)
+     ncmp (ge lt)
+ (for sgncmp (ge lt)
+  (simplify
+   (cmp (sgncmp @0 integer_zerop@2) (sgncmp @1 integer_zerop))
+   (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && !TYPE_UNSIGNED (TREE_TYPE (@0))
+       && types_match (@0, @1))
+    (ncmp (bit_xor @0 @1) @2)))))
+/* (X < 0) == (Y >= 0) into (X ^ Y) < 0.
+   (X < 0) != (Y >= 0) into (X ^ Y) >= 0.  */
+(for cmp (eq ne)
+     ncmp (lt ge)
+ (simplify
+  (cmp:c (lt @0 integer_zerop@2) (ge @1 integer_zerop))
+   (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && !TYPE_UNSIGNED (TREE_TYPE (@0))
+       && types_match (@0, @1))
+    (ncmp (bit_xor @0 @1) @2))))
 
 /* If we have (A & C) == C where C is a power of 2, convert this into
    (A & C) != 0.  Similarly for NE_EXPR.  */
@@ -3877,6 +4549,69 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                    || TREE_CODE (base1) == SSA_NAME
                    || TREE_CODE (base1) == STRING_CST))
          equal = (base0 == base1);
+       if (equal == 0)
+        {
+          HOST_WIDE_INT ioff0 = -1, ioff1 = -1;
+          off0.is_constant (&ioff0);
+          off1.is_constant (&ioff1);
+          if ((DECL_P (base0) && TREE_CODE (base1) == STRING_CST)
+              || (TREE_CODE (base0) == STRING_CST && DECL_P (base1))
+              || (TREE_CODE (base0) == STRING_CST
+                  && TREE_CODE (base1) == STRING_CST
+                  && ioff0 >= 0 && ioff1 >= 0
+                  && ioff0 < TREE_STRING_LENGTH (base0)
+                  && ioff1 < TREE_STRING_LENGTH (base1)
+                  /* This is a too conservative test that the STRING_CSTs
+                     will not end up being string-merged.  */
+                  && strncmp (TREE_STRING_POINTER (base0) + ioff0,
+                              TREE_STRING_POINTER (base1) + ioff1,
+                              MIN (TREE_STRING_LENGTH (base0) - ioff0,
+                                   TREE_STRING_LENGTH (base1) - ioff1)) != 0))
+            ;
+          else if (!DECL_P (base0) || !DECL_P (base1))
+            equal = 2;
+          else if (cmp != EQ_EXPR && cmp != NE_EXPR)
+            equal = 2;
+          /* If this is a pointer comparison, ignore for now even
+             valid equalities where one pointer is the offset zero
+             of one object and the other to one past end of another one.  */
+          else if (!INTEGRAL_TYPE_P (TREE_TYPE (@2)))
+            ;
+          /* Assume that automatic variables can't be adjacent to global
+             variables.  */
+          else if (is_global_var (base0) != is_global_var (base1))
+            ;
+          else
+            {
+              tree sz0 = DECL_SIZE_UNIT (base0);
+              tree sz1 = DECL_SIZE_UNIT (base1);
+              /* If sizes are unknown, e.g. VLA or not representable,
+                 punt.  */
+              if (!tree_fits_poly_int64_p (sz0)
+                  || !tree_fits_poly_int64_p (sz1))
+                equal = 2;
+              else
+                {
+                  poly_int64 size0 = tree_to_poly_int64 (sz0);
+                  poly_int64 size1 = tree_to_poly_int64 (sz1);
+                  /* If one offset is pointing (or could be) to the beginning
+                     of one object and the other is pointing to one past the
+                     last byte of the other object, punt.  */
+                  if (maybe_eq (off0, 0) && maybe_eq (off1, size1))
+                    equal = 2;
+                  else if (maybe_eq (off1, 0) && maybe_eq (off0, size0))
+                    equal = 2;
+                  /* If both offsets are the same, there are some cases
+                     we know that are ok.  Either if we know they aren't
+                     zero, or if we know both sizes are no zero.  */
+                  if (equal == 2
+                      && known_eq (off0, off1)
+                      && (known_ne (off0, 0)
+                          || (known_ne (size0, 0) && known_ne (size1, 0))))
+                    equal = 0;
+                }
+            }
+        }
      }
      (if (equal == 1
          && (cmp == EQ_EXPR || cmp == NE_EXPR
@@ -3899,16 +4634,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        { constant_boolean_node (known_ge (off0, off1), type); })
        (if (cmp == GT_EXPR && (known_gt (off0, off1) || known_le (off0, off1)))
        { constant_boolean_node (known_gt (off0, off1), type); }))
-      (if (equal == 0
-          && DECL_P (base0) && DECL_P (base1)
-          /* If we compare this as integers require equal offset.  */
-          && (!INTEGRAL_TYPE_P (TREE_TYPE (@2))
-              || known_eq (off0, off1)))
-       (switch
-       (if (cmp == EQ_EXPR)
-        { constant_boolean_node (false, type); })
-       (if (cmp == NE_EXPR)
-        { constant_boolean_node (true, type); })))))))))
+      (if (equal == 0)
+       (switch
+        (if (cmp == EQ_EXPR)
+         { constant_boolean_node (false, type); })
+        (if (cmp == NE_EXPR)
+         { constant_boolean_node (true, type); })))))))))
 
 /* Simplify pointer equality compares using PTA.  */
 (for neeq (ne eq)
@@ -4077,10 +4808,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (cmp:c (minus@2 @0 @1) @0)
   (if (single_use (@2)
        && ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
-       && TYPE_UNSIGNED (TREE_TYPE (@0))
-       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+       && TYPE_UNSIGNED (TREE_TYPE (@0)))
    (cmp @1 @0))))
 
+/* Optimize A - B + -1 >= A into B >= A for unsigned comparisons.  */
+(for cmp (ge lt)
+ (simplify
+  (cmp:c (plus (minus @0 @1) integer_minus_onep) @0)
+   (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_UNSIGNED (TREE_TYPE (@0)))
+    (cmp @1 @0))))
+
 /* Testing for overflow is unnecessary if we already know the result.  */
 /* A - B > A  */
 (for cmp (gt le)
@@ -4109,6 +4847,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
     (out (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
 
+/* Similarly, for unsigned operands, (((type) A * B) >> prec) != 0 where type
+   is at least twice as wide as type of A and B, simplify to
+   __builtin_mul_overflow (A, B, <unused>).  */
+(for cmp (eq ne)
+ (simplify
+  (cmp (rshift (mult:s (convert@3 @0) (convert @1)) INTEGER_CST@2)
+       integer_zerop)
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@3))
+       && TYPE_UNSIGNED (TREE_TYPE (@0))
+       && (TYPE_PRECISION (TREE_TYPE (@3))
+          >= 2 * TYPE_PRECISION (TREE_TYPE (@0)))
+       && tree_fits_uhwi_p (@2)
+       && tree_to_uhwi (@2) == TYPE_PRECISION (TREE_TYPE (@0))
+       && types_match (@0, @1)
+       && type_has_mode_precision_p (TREE_TYPE (@0))
+       && (optab_handler (umulv4_optab, TYPE_MODE (TREE_TYPE (@0)))
+          != CODE_FOR_nothing))
+   (with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
+    (cmp (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
+
 /* Simplification of math builtins.  These rules must all be optimizations
    as well as IL simplifications.  If there is a possibility that the new
    form could be a pessimization, the rule should go in the canonicalization
@@ -4346,7 +5105,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       tree t_one = build_one_cst (type);
      }
     (if (SCALAR_FLOAT_TYPE_P (type))
-     (cond (le (abs @0) { t_cst; })
+     (cond (lt (abs @0) { t_cst; })
       (rdiv @0 (sqrts (plus (mult @0 @0) { t_one; })))
       (copysigns { t_one; } @0))))))
 
@@ -4366,7 +5125,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       tree t_zero = build_zero_cst (type);
      }
     (if (SCALAR_FLOAT_TYPE_P (type))
-     (cond (le (abs @0) { t_cst; })
+     (cond (lt (abs @0) { t_cst; })
       (rdiv { t_one; } (sqrts (plus (mult @0 @0) { t_one; })))
       (copysigns { t_zero; } @0))))))
 
@@ -4465,6 +5224,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (rdiv (SIN:s @0) (COS:s @0))
    (TAN @0))
 
+ /* Simplify sinh(x) / cosh(x) -> tanh(x). */
+ (simplify
+  (rdiv (SINH:s @0) (COSH:s @0))
+   (TANH @0))
+
  /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
  (simplify
   (rdiv (COS:s @0) (SIN:s @0))
@@ -4756,37 +5520,109 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    the C/C++ front-ends by shorten_binary_op and shorten_compare.  Long
    term we want to move all that code out of the front-ends into here.  */
 
-/* If we have a narrowing conversion of an arithmetic operation where
-   both operands are widening conversions from the same type as the outer
-   narrowing conversion.  Then convert the innermost operands to a suitable
-   unsigned type (to avoid introducing undefined behavior), perform the
-   operation and convert the result to the desired type.  */
-(for op (plus minus)
-  (simplify
-    (convert (op:s (convert@2 @0) (convert?@3 @1)))
-    (if (INTEGRAL_TYPE_P (type)
-        /* We check for type compatibility between @0 and @1 below,
-           so there's no need to check that @1/@3 are integral types.  */
-        && INTEGRAL_TYPE_P (TREE_TYPE (@0))
-        && INTEGRAL_TYPE_P (TREE_TYPE (@2))
-        /* The precision of the type of each operand must match the
-           precision of the mode of each operand, similarly for the
-           result.  */
-        && type_has_mode_precision_p (TREE_TYPE (@0))
-        && type_has_mode_precision_p (TREE_TYPE (@1))
-        && type_has_mode_precision_p (type)
-        /* The inner conversion must be a widening conversion.  */
-        && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
-        && types_match (@0, type)
-        && (types_match (@0, @1)
-            /* Or the second operand is const integer or converted const
-               integer from valueize.  */
-            || TREE_CODE (@1) == INTEGER_CST))
-      (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
-       (op @0 (convert @1))
-       (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
-        (convert (op (convert:utype @0)
-                     (convert:utype @1))))))))
+/* Convert (outertype)((innertype0)a+(innertype1)b)
+   into ((newtype)a+(newtype)b) where newtype
+   is the widest mode from all of these.  */
+(for op (plus minus mult rdiv)
+ (simplify
+   (convert (op:s@0 (convert1?@3 @1) (convert2?@4 @2)))
+   /* If we have a narrowing conversion of an arithmetic operation where
+      both operands are widening conversions from the same type as the outer
+      narrowing conversion.  Then convert the innermost operands to a
+      suitable unsigned type (to avoid introducing undefined behavior),
+      perform the operation and convert the result to the desired type.  */
+   (if (INTEGRAL_TYPE_P (type)
+       && op != MULT_EXPR
+       && op != RDIV_EXPR
+       /* We check for type compatibility between @0 and @1 below,
+          so there's no need to check that @2/@4 are integral types.  */
+       && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@3))
+       /* The precision of the type of each operand must match the
+          precision of the mode of each operand, similarly for the
+          result.  */
+       && type_has_mode_precision_p (TREE_TYPE (@1))
+       && type_has_mode_precision_p (TREE_TYPE (@2))
+       && type_has_mode_precision_p (type)
+       /* The inner conversion must be a widening conversion.  */
+       && TYPE_PRECISION (TREE_TYPE (@3)) > TYPE_PRECISION (TREE_TYPE (@1))
+       && types_match (@1, type)
+       && (types_match (@1, @2)
+           /* Or the second operand is const integer or converted const
+              integer from valueize.  */
+           || TREE_CODE (@2) == INTEGER_CST))
+     (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+       (op @1 (convert @2))
+       (with { tree utype = unsigned_type_for (TREE_TYPE (@1)); }
+       (convert (op (convert:utype @1)
+                    (convert:utype @2)))))
+     (if (FLOAT_TYPE_P (type)
+         && DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0))
+              == DECIMAL_FLOAT_TYPE_P (type))
+      (with { tree arg0 = strip_float_extensions (@1);
+             tree arg1 = strip_float_extensions (@2);
+             tree itype = TREE_TYPE (@0);
+             tree ty1 = TREE_TYPE (arg0);
+             tree ty2 = TREE_TYPE (arg1);
+             enum tree_code code = TREE_CODE (itype); }
+       (if (FLOAT_TYPE_P (ty1)
+            && FLOAT_TYPE_P (ty2))
+        (with { tree newtype = type;
+                if (TYPE_MODE (ty1) == SDmode
+                    || TYPE_MODE (ty2) == SDmode
+                    || TYPE_MODE (type) == SDmode)
+                  newtype = dfloat32_type_node;
+                if (TYPE_MODE (ty1) == DDmode
+                    || TYPE_MODE (ty2) == DDmode
+                    || TYPE_MODE (type) == DDmode)
+                  newtype = dfloat64_type_node;
+                if (TYPE_MODE (ty1) == TDmode
+                    || TYPE_MODE (ty2) == TDmode
+                    || TYPE_MODE (type) == TDmode)
+                  newtype = dfloat128_type_node; }
+         (if ((newtype == dfloat32_type_node
+               || newtype == dfloat64_type_node
+               || newtype == dfloat128_type_node)
+             && newtype == type
+             && types_match (newtype, type))
+           (op (convert:newtype @1) (convert:newtype @2))
+           (with { if (TYPE_PRECISION (ty1) > TYPE_PRECISION (newtype))
+                     newtype = ty1;
+                   if (TYPE_PRECISION (ty2) > TYPE_PRECISION (newtype))
+                     newtype = ty2; }
+              /* Sometimes this transformation is safe (cannot
+                 change results through affecting double rounding
+                 cases) and sometimes it is not.  If NEWTYPE is
+                 wider than TYPE, e.g. (float)((long double)double
+                 + (long double)double) converted to
+                 (float)(double + double), the transformation is
+                 unsafe regardless of the details of the types
+                 involved; double rounding can arise if the result
+                 of NEWTYPE arithmetic is a NEWTYPE value half way
+                 between two representable TYPE values but the
+                 exact value is sufficiently different (in the
+                 right direction) for this difference to be
+                 visible in ITYPE arithmetic.  If NEWTYPE is the
+                 same as TYPE, however, the transformation may be
+                 safe depending on the types involved: it is safe
+                 if the ITYPE has strictly more than twice as many
+                 mantissa bits as TYPE, can represent infinities
+                 and NaNs if the TYPE can, and has sufficient
+                 exponent range for the product or ratio of two
+                 values representable in the TYPE to be within the
+                 range of normal values of ITYPE.  */
+             (if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
+                  && (flag_unsafe_math_optimizations
+                      || (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
+                          && real_can_shorten_arithmetic (TYPE_MODE (itype),
+                                                          TYPE_MODE (type))
+                          && !excess_precision_type (newtype)))
+                  && !types_match (itype, newtype))
+                (convert:type (op (convert:newtype @1)
+                                  (convert:newtype @2)))
+        )))) )
+   ))
+)))
 
 /* This is another case of narrowing, specifically when there's an outer
    BIT_AND_EXPR which masks off bits outside the type of the innermost
@@ -4980,15 +5816,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
         (if (elt < CONSTRUCTOR_NELTS (ctor))
          (view_convert { CONSTRUCTOR_ELT (ctor, elt)->value; })
          { build_zero_cst (type); })
-        {
-          vec<constructor_elt, va_gc> *vals;
-          vec_alloc (vals, count);
-          for (unsigned i = 0;
-               i < count && elt + i < CONSTRUCTOR_NELTS (ctor); ++i)
-            CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE,
-                                    CONSTRUCTOR_ELT (ctor, elt + i)->value);
-          build_constructor (type, vals);
-        })))
+        /* We don't want to emit new CTORs unless the old one goes away.
+           ???  Eventually allow this if the CTOR ends up constant or
+           uniform.  */
+        (if (single_use (@0))
+         {
+           vec<constructor_elt, va_gc> *vals;
+           vec_alloc (vals, count);
+           for (unsigned i = 0;
+                i < count && elt + i < CONSTRUCTOR_NELTS (ctor); ++i)
+             CONSTRUCTOR_APPEND_ELT (vals, NULL_TREE,
+                                     CONSTRUCTOR_ELT (ctor, elt + i)->value);
+           build_constructor (type, vals);
+         }))))
       /* The bitfield references a single constructor element.  */
       (if (k.is_constant (&const_k)
           && idx + n <= (idx / const_k + 1) * const_k)
@@ -5104,6 +5944,81 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (cmp (popcount @0) integer_zerop)
       (rep @0 { build_zero_cst (TREE_TYPE (@0)); }))))
 
+#if GIMPLE
+/* 64- and 32-bits branchless implementations of popcount are detected:
+
+   int popcount64c (uint64_t x)
+   {
+     x -= (x >> 1) & 0x5555555555555555ULL;
+     x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+     x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+     return (x * 0x0101010101010101ULL) >> 56;
+   }
+
+   int popcount32c (uint32_t x)
+   {
+     x -= (x >> 1) & 0x55555555;
+     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+     x = (x + (x >> 4)) & 0x0f0f0f0f;
+     return (x * 0x01010101) >> 24;
+   }  */
+(simplify
+ (rshift
+  (mult
+   (bit_and
+    (plus:c
+     (rshift @8 INTEGER_CST@5)
+      (plus:c@8
+       (bit_and @6 INTEGER_CST@7)
+       (bit_and
+        (rshift
+         (minus@6 @0
+          (bit_and (rshift @0 INTEGER_CST@4) INTEGER_CST@11))
+         INTEGER_CST@10)
+        INTEGER_CST@9)))
+    INTEGER_CST@3)
+   INTEGER_CST@2)
+  INTEGER_CST@1)
+  /* Check constants and optab.  */
+  (with { unsigned prec = TYPE_PRECISION (type);
+         int shift = (64 - prec) & 63;
+         unsigned HOST_WIDE_INT c1
+           = HOST_WIDE_INT_UC (0x0101010101010101) >> shift;
+         unsigned HOST_WIDE_INT c2
+           = HOST_WIDE_INT_UC (0x0F0F0F0F0F0F0F0F) >> shift;
+         unsigned HOST_WIDE_INT c3
+           = HOST_WIDE_INT_UC (0x3333333333333333) >> shift;
+         unsigned HOST_WIDE_INT c4
+           = HOST_WIDE_INT_UC (0x5555555555555555) >> shift;
+   }
+   (if (prec >= 16
+       && prec <= 64
+       && pow2p_hwi (prec)
+       && TYPE_UNSIGNED (type)
+       && integer_onep (@4)
+       && wi::to_widest (@10) == 2
+       && wi::to_widest (@5) == 4
+       && wi::to_widest (@1) == prec - 8
+       && tree_to_uhwi (@2) == c1
+       && tree_to_uhwi (@3) == c2
+       && tree_to_uhwi (@9) == c3
+       && tree_to_uhwi (@7) == c3
+       && tree_to_uhwi (@11) == c4
+       && direct_internal_fn_supported_p (IFN_POPCOUNT, type,
+                                          OPTIMIZE_FOR_BOTH))
+    (convert (IFN_POPCOUNT:type @0)))))
+
+/* __builtin_ffs needs to deal on many targets with the possible zero
+   argument.  If we know the argument is always non-zero, __builtin_ctz + 1
+   should lead to better code.  */
+(simplify
+ (FFS tree_expr_nonzero_p@0)
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@0),
+                                        OPTIMIZE_FOR_SPEED))
+  (plus (CTZ:type @0) { build_one_cst (type); })))
+#endif
+
 /* Simplify:
 
      a = a1 op a2
@@ -5115,18 +6030,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
    if the target can do it in one go.  This makes the operation conditional
    on c, so could drop potentially-trapping arithmetic, but that's a valid
-   simplification if the result of the operation isn't needed.  */
+   simplification if the result of the operation isn't needed.
+
+   Avoid speculatively generating a stand-alone vector comparison
+   on targets that might not support them.  Any target implementing
+   conditional internal functions must support the same comparisons
+   inside and outside a VEC_COND_EXPR.  */
+
+#if GIMPLE
 (for uncond_op (UNCOND_BINARY)
      cond_op (COND_BINARY)
  (simplify
   (vec_cond @0 (view_convert? (uncond_op@4 @1 @2)) @3)
   (with { tree op_type = TREE_TYPE (@4); }
-   (if (element_precision (type) == element_precision (op_type))
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && element_precision (type) == element_precision (op_type))
     (view_convert (cond_op @0 @1 @2 (view_convert:op_type @3))))))
  (simplify
   (vec_cond @0 @1 (view_convert? (uncond_op@4 @2 @3)))
   (with { tree op_type = TREE_TYPE (@4); }
-   (if (element_precision (type) == element_precision (op_type))
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && element_precision (type) == element_precision (op_type))
     (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1)))))))
 
 /* Same for ternary operations.  */
@@ -5135,14 +6059,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (simplify
   (vec_cond @0 (view_convert? (uncond_op@5 @1 @2 @3)) @4)
   (with { tree op_type = TREE_TYPE (@5); }
-   (if (element_precision (type) == element_precision (op_type))
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && element_precision (type) == element_precision (op_type))
     (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @4))))))
  (simplify
   (vec_cond @0 @1 (view_convert? (uncond_op@5 @2 @3 @4)))
   (with { tree op_type = TREE_TYPE (@5); }
-   (if (element_precision (type) == element_precision (op_type))
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && element_precision (type) == element_precision (op_type))
     (view_convert (cond_op (bit_not @0) @2 @3 @4
                  (view_convert:op_type @1)))))))
+#endif
 
 /* Detect cases in which a VEC_COND_EXPR effectively replaces the
    "else" value of an IFN_COND_*.  */
@@ -5232,3 +6159,174 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                            { wide_int_to_tree (sizetype, off); })
              { swap_p ? @0 : @2; }))
            { rhs_tree; })))))))))
+
+/* Fold REDUC (@0 & @1) -> @0[I] & @1[I] if element I is the only nonzero
+   element of @1.  */
+(for reduc (IFN_REDUC_PLUS IFN_REDUC_IOR IFN_REDUC_XOR)
+ (simplify (reduc (view_convert? (bit_and @0 VECTOR_CST@1)))
+  (with { int i = single_nonzero_element (@1); }
+   (if (i >= 0)
+    (with { tree elt = vector_cst_elt (@1, i);
+           tree elt_type = TREE_TYPE (elt);
+           unsigned int elt_bits = tree_to_uhwi (TYPE_SIZE (elt_type));
+           tree size = bitsize_int (elt_bits);
+           tree pos = bitsize_int (elt_bits * i); }
+     (view_convert
+      (bit_and:elt_type
+       (BIT_FIELD_REF:elt_type @0 { size; } { pos; })
+       { elt; })))))))
+
+(simplify
+ (vec_perm @0 @1 VECTOR_CST@2)
+ (with
+  {
+    tree op0 = @0, op1 = @1, op2 = @2;
+
+    /* Build a vector of integers from the tree mask.  */
+    vec_perm_builder builder;
+    if (!tree_to_vec_perm_builder (&builder, op2))
+      return NULL_TREE;
+
+    /* Create a vec_perm_indices for the integer vector.  */
+    poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type);
+    bool single_arg = (op0 == op1);
+    vec_perm_indices sel (builder, single_arg ? 1 : 2, nelts);
+  }
+  (if (sel.series_p (0, 1, 0, 1))
+   { op0; }
+   (if (sel.series_p (0, 1, nelts, 1))
+    { op1; }
+    (with
+     {
+       if (!single_arg)
+         {
+          if (sel.all_from_input_p (0))
+            op1 = op0;
+          else if (sel.all_from_input_p (1))
+            {
+              op0 = op1;
+              sel.rotate_inputs (1);
+            }
+          else if (known_ge (poly_uint64 (sel[0]), nelts))
+            {
+              std::swap (op0, op1);
+              sel.rotate_inputs (1);
+            }
+         }
+       gassign *def;
+       tree cop0 = op0, cop1 = op1;
+       if (TREE_CODE (op0) == SSA_NAME
+           && (def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op0)))
+          && gimple_assign_rhs_code (def) == CONSTRUCTOR)
+        cop0 = gimple_assign_rhs1 (def);
+       if (TREE_CODE (op1) == SSA_NAME
+           && (def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op1)))
+          && gimple_assign_rhs_code (def) == CONSTRUCTOR)
+        cop1 = gimple_assign_rhs1 (def);
+
+       tree t;
+    }
+    (if ((TREE_CODE (cop0) == VECTOR_CST
+         || TREE_CODE (cop0) == CONSTRUCTOR)
+        && (TREE_CODE (cop1) == VECTOR_CST
+            || TREE_CODE (cop1) == CONSTRUCTOR)
+        && (t = fold_vec_perm (type, cop0, cop1, sel)))
+     { t; }
+     (with
+      {
+       bool changed = (op0 == op1 && !single_arg);
+       tree ins = NULL_TREE;
+       unsigned at = 0;
+
+       /* See if the permutation is performing a single element
+          insert from a CONSTRUCTOR or constant and use a BIT_INSERT_EXPR
+          in that case.  But only if the vector mode is supported,
+          otherwise this is invalid GIMPLE.  */
+        if (TYPE_MODE (type) != BLKmode
+           && (TREE_CODE (cop0) == VECTOR_CST
+               || TREE_CODE (cop0) == CONSTRUCTOR
+               || TREE_CODE (cop1) == VECTOR_CST
+               || TREE_CODE (cop1) == CONSTRUCTOR))
+          {
+           bool insert_first_p = sel.series_p (1, 1, nelts + 1, 1);
+           if (insert_first_p)
+             {
+               /* After canonicalizing the first elt to come from the
+                  first vector we only can insert the first elt from
+                  the first vector.  */
+               at = 0;
+               if ((ins = fold_read_from_vector (cop0, sel[0])))
+                 op0 = op1;
+             }
+           /* The above can fail for two-element vectors which always
+              appear to insert the first element, so try inserting
+              into the second lane as well.  For more than two
+              elements that's wasted time.  */
+           if (!insert_first_p || (!ins && maybe_eq (nelts, 2u)))
+             {
+               unsigned int encoded_nelts = sel.encoding ().encoded_nelts ();
+               for (at = 0; at < encoded_nelts; ++at)
+                 if (maybe_ne (sel[at], at))
+                   break;
+               if (at < encoded_nelts
+                   && (known_eq (at + 1, nelts)
+                       || sel.series_p (at + 1, 1, at + 1, 1)))
+                 {
+                   if (known_lt (poly_uint64 (sel[at]), nelts))
+                     ins = fold_read_from_vector (cop0, sel[at]);
+                   else
+                     ins = fold_read_from_vector (cop1, sel[at] - nelts);
+                 }
+             }
+         }
+
+       /* Generate a canonical form of the selector.  */
+       if (!ins && sel.encoding () != builder)
+         {
+           /* Some targets are deficient and fail to expand a single
+              argument permutation while still allowing an equivalent
+              2-argument version.  */
+           tree oldop2 = op2;
+           if (sel.ninputs () == 2
+              || can_vec_perm_const_p (TYPE_MODE (type), sel, false))
+             op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel);
+           else
+             {
+               vec_perm_indices sel2 (builder, 2, nelts);
+               if (can_vec_perm_const_p (TYPE_MODE (type), sel2, false))
+                 op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel2);
+               else
+                 /* Not directly supported with either encoding,
+                    so use the preferred form.  */
+                 op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel);
+             }
+           if (!operand_equal_p (op2, oldop2, 0))
+             changed = true;
+         }
+      }
+      (if (ins)
+       (bit_insert { op0; } { ins; }
+         { bitsize_int (at * vector_element_bits (type)); })
+       (if (changed)
+        (vec_perm { op0; } { op1; } { op2; }))))))))))
+
+/* VEC_PERM_EXPR (v, v, mask) -> v where v contains same element.  */
+
+(match vec_same_elem_p
+ @0
+ (if (uniform_vector_p (@0))))
+
+(match vec_same_elem_p
+ (vec_duplicate @0))
+
+(simplify
+ (vec_perm vec_same_elem_p@0 @0 @1)
+ @0)
+
+/* Match count trailing zeroes for simplify_count_trailing_zeroes in fwprop.
+   The canonical form is array[((x & -x) * C) >> SHIFT] where C is a magic
+   constant which when multiplied by a power of 2 contains a unique value
+   in the top 5 or 6 bits.  This is then indexed into a table which maps it
+   to the number of trailing zeroes.  */
+(match (ctz_table_index @1 @2 @3)
+  (rshift (mult (bit_and:c (negate @1) @1) INTEGER_CST@2) INTEGER_CST@3))