]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/match.pd
Update copyright years.
[thirdparty/gcc.git] / gcc / match.pd
index 05009bb7a5ac8ded105fadb9e517b2a704d950a0..fac1dfc13a9c297700311fd8732a70dea3c15bae 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-2019 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>
 
@@ -98,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)))))
@@ -109,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
@@ -325,9 +322,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
              && (TYPE_UNSIGNED (TREE_TYPE (@1))
                  || (element_precision (type)
                      == element_precision (TREE_TYPE (@1)))
-                 || (get_nonzero_bits (@0)
-                     & wi::mask (element_precision (TREE_TYPE (@1)) - 1, true,
-                                 element_precision (type))) == 0))))
+                 || (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
@@ -1426,7 +1425,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.  */
@@ -1453,7 +1452,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))))
 
@@ -1682,7 +1681,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)))
@@ -1691,7 +1690,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))))
@@ -1881,6 +1880,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))
@@ -1934,7 +2139,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)))
@@ -1951,20 +2156,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.  */
@@ -1990,7 +2201,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))
@@ -2029,17 +2240,39 @@ 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
@@ -2057,8 +2290,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                          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 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)
@@ -2072,6 +2306,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      )))
 #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
    (plus:c (bit_not @0) @0)
@@ -2257,18 +2505,42 @@ 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))))))
 
@@ -2425,6 +2697,31 @@ 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))))
+   (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))))
+   (cond (cmp @2 @3) @1 @0))))
+
 /* Simplifications of shift and rotates.  */
 
 (for rotate (lrotate rrotate)
@@ -3503,8 +3800,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)
@@ -3539,56 +3835,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))
@@ -4699,6 +5047,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))
@@ -5286,15 +5639,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)
@@ -5410,6 +5767,71 @@ 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)))))
+#endif
+
 /* Simplify:
 
      a = a1 op a2
@@ -5423,10 +5845,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    on c, so could drop potentially-trapping arithmetic, but that's a valid
    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.  */                                                                                                       
+   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)
@@ -5639,7 +6061,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                || TREE_CODE (cop1) == VECTOR_CST
                || TREE_CODE (cop1) == CONSTRUCTOR))
           {
-           if (sel.series_p (1, 1, nelts + 1, 1))
+           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
@@ -5648,15 +6071,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                if ((ins = fold_read_from_vector (cop0, sel[0])))
                  op0 = op1;
              }
-           else
+           /* 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 && sel.series_p (at + 1, 1, at + 1, 1))
+               if (at < encoded_nelts
+                   && (known_eq (at + 1, nelts)
+                       || sel.series_p (at + 1, 1, at + 1, 1)))
                  {
-                   if (known_lt (at, nelts))
+                   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);