]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/match.pd
i386: Optimize EQ/NE comparison between avx512 kmask and -1.
[thirdparty/gcc.git] / gcc / match.pd
index 0aa815f4118da492127c65f6aec95034fa4478fd..480e36bbbaf90e5b096dcbb50e86ac768fd701dc 100644 (file)
@@ -2,7 +2,7 @@
    This file is consumed by genmatch which produces gimple-match.cc
    and generic-match.cc from it.
 
-   Copyright (C) 2014-2023 Free Software Foundation, Inc.
+   Copyright (C) 2014-2024 Free Software Foundation, Inc.
    Contributed by Richard Biener <rguenther@suse.de>
    and Prathamesh Kulkarni  <bilbotheelffriend@gmail.com>
 
@@ -87,28 +87,40 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   negate bit_not)
 (define_operator_list COND_UNARY
   IFN_COND_NEG IFN_COND_NOT)
+(define_operator_list COND_LEN_UNARY
+  IFN_COND_LEN_NEG IFN_COND_LEN_NOT)
 
 /* Binary operations and their associated IFN_COND_* function.  */
 (define_operator_list UNCOND_BINARY
   plus minus
   mult trunc_div trunc_mod rdiv
   min max
-  IFN_FMIN IFN_FMAX
+  IFN_FMIN IFN_FMAX IFN_COPYSIGN
   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_FMIN IFN_COND_FMAX
+  IFN_COND_FMIN IFN_COND_FMAX IFN_COND_COPYSIGN
   IFN_COND_AND IFN_COND_IOR IFN_COND_XOR
   IFN_COND_SHL IFN_COND_SHR)
+(define_operator_list COND_LEN_BINARY
+  IFN_COND_LEN_ADD IFN_COND_LEN_SUB
+  IFN_COND_LEN_MUL IFN_COND_LEN_DIV
+  IFN_COND_LEN_MOD IFN_COND_LEN_RDIV
+  IFN_COND_LEN_MIN IFN_COND_LEN_MAX
+  IFN_COND_LEN_FMIN IFN_COND_LEN_FMAX IFN_COND_LEN_COPYSIGN
+  IFN_COND_LEN_AND IFN_COND_LEN_IOR IFN_COND_LEN_XOR
+  IFN_COND_LEN_SHL IFN_COND_LEN_SHR)
 
 /* Same for ternary operations.  */
 (define_operator_list UNCOND_TERNARY
   IFN_FMA IFN_FMS IFN_FNMA IFN_FNMS)
 (define_operator_list COND_TERNARY
   IFN_COND_FMA IFN_COND_FMS IFN_COND_FNMA IFN_COND_FNMS)
+(define_operator_list COND_LEN_TERNARY
+  IFN_COND_LEN_FMA IFN_COND_LEN_FMS IFN_COND_LEN_FNMA IFN_COND_LEN_FNMS)
 
 /* __atomic_fetch_or_*, __atomic_fetch_xor_*, __atomic_xor_fetch_*  */
 (define_operator_list ATOMIC_FETCH_OR_XOR_N
@@ -155,7 +167,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                   TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)))
       && tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0))))))
 
-#if GIMPLE
 /* These are used by gimple_bitwise_inverted_equal_p to simplify
    detection of BIT_NOT and comparisons. */
 (match (bit_not_with_nop @0)
@@ -163,6 +174,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (match (bit_not_with_nop @0)
  (convert (bit_not @0))
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
+(match (bit_xor_cst @0 @1)
+ (bit_xor @0 uniform_integer_cst_p@1))
 (for cmp (tcc_comparison)
  (match (maybe_cmp @0)
   (cmp@0 @1 @2))
@@ -170,7 +183,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (convert (cmp@0 @1 @2))
    (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
 )
-#endif
+/* `a ^ b` is another form of `a != b` when the type
+    is a 1bit precission integer.  */
+(match (maybe_cmp @0)
+ (bit_xor@0 @1 @2)
+ (if (INTEGRAL_TYPE_P (type)
+      && TYPE_PRECISION (type) == 1)))
+/* maybe_bit_not is used to match what
+   is acceptable for bitwise_inverted_equal_p. */
+(match (maybe_bit_not @0)
+ (bit_not_with_nop@0 @1))
+(match (maybe_bit_not @0)
+ (INTEGER_CST@0))
+(match (maybe_bit_not @0)
+ (maybe_cmp@0 @1))
+(match (maybe_bit_not @0)
+ (bit_xor_cst@0 @1 @2))
 
 /* 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
@@ -435,8 +463,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* (x >= 0 ? x : 0) + (x <= 0 ? -x : 0) -> abs x.  */
 (simplify
-  (plus:c (max @0 integer_zerop) (max (negate @0) integer_zerop))
-  (abs @0))
+ (plus:c (max @0 integer_zerop) (max (negate @0) integer_zerop))
+ (if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type))
+  (abs @0)))
 
 /* X * 1, X / 1 -> X.  */
 (for op (mult trunc_div ceil_div floor_div round_div exact_div)
@@ -542,7 +571,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    1 / X -> X >= -1 && X <= 1 ? X : 0 for signed integer X.
    But not for 1 / 0 so that we can get proper warnings and errors,
    and not for 1-bit integers as they are edge cases better handled
-   elsewhere.  */
+   elsewhere.  Delay the conversion of the signed division until late
+   because `1 / X` is simplier to handle than the resulting COND_EXPR.  */
 (simplify
  (trunc_div integer_onep@0 @1)
  (if (INTEGRAL_TYPE_P (type)
@@ -551,10 +581,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && (!flag_non_call_exceptions || tree_expr_nonzero_p (@1)))
   (if (TYPE_UNSIGNED (type))
    (convert (eq:boolean_type_node @1 { build_one_cst (type); }))
-   (with { tree utype = unsigned_type_for (type); }
-    (cond (le (plus (convert:utype @1) { build_one_cst (utype); })
-             { build_int_cst (utype, 2); })
-     @1 { build_zero_cst (type); })))))
+   (if (!canonicalize_math_p ())
+    (with { tree utype = unsigned_type_for (type); }
+     (cond (le (plus (convert:utype @1) { build_one_cst (utype); })
+               { build_int_cst (utype, 2); })
+      @1 { build_zero_cst (type); }))))))
 
 /* Combine two successive divisions.  Note that combining ceil_div
    and floor_div is trickier and combining round_div even more so.  */
@@ -918,12 +949,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@0)))
   (bit_and @0 (negate @1))))
 
-/* Simplify (t * 2) / 2) -> t.  */
 (for div (trunc_div ceil_div floor_div round_div exact_div)
+ /* Simplify (t * u) / u -> t.  */
  (simplify
   (div (mult:c @0 @1) @1)
   (if (ANY_INTEGRAL_TYPE_P (type))
-   (if (TYPE_OVERFLOW_UNDEFINED (type))
+   (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
     @0
 #if GIMPLE
     (with {value_range vr0, vr1;}
@@ -932,6 +963,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
          && get_range_query (cfun)->range_of_expr (vr1, @1)
          && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1))
       @0))
+#endif
+   )))
+#if GIMPLE
+ /* Simplify (t * u) / v -> t * (u / v) if u is multiple of v.  */
+ (simplify
+  (div (mult @0 INTEGER_CST@1) INTEGER_CST@2)
+  (if (INTEGRAL_TYPE_P (type)
+       && wi::multiple_of_p (wi::to_widest (@1), wi::to_widest (@2), SIGNED))
+   (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
+    (mult @0 (div! @1 @2))
+    (with {value_range vr0, vr1;}
+     (if (get_range_query (cfun)->range_of_expr (vr0, @0)
+         && get_range_query (cfun)->range_of_expr (vr1, @1)
+         && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1))
+      (mult @0 (div! @1 @2))))
+   )))
+#endif
+ /* Simplify (t * u) / (t * v) -> (u / v) if u is multiple of v.  */
+ (simplify
+  (div (mult @0 INTEGER_CST@1) (mult @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (type)
+       && wi::multiple_of_p (wi::to_widest (@1), wi::to_widest (@2), SIGNED))
+   (if (TYPE_OVERFLOW_UNDEFINED (type) && !TYPE_OVERFLOW_SANITIZED (type))
+    (div @1 @2)
+#if GIMPLE
+    (with {value_range vr0, vr1, vr2;}
+     (if (get_range_query (cfun)->range_of_expr (vr0, @0)
+         && get_range_query (cfun)->range_of_expr (vr1, @1)
+         && get_range_query (cfun)->range_of_expr (vr2, @2)
+         && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr1)
+         && range_op_handler (MULT_EXPR).overflow_free_p (vr0, vr2))
+      (div @1 @2)))
 #endif
    ))))
 
@@ -1021,12 +1084,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (nop_outer_cast)-(inner_cast)var -> -(outer_cast)(var)
    if var is smaller in precision.
    This is always safe for both doing the negative in signed or unsigned
-   as the value for undefined will not show up.  */
+   as the value for undefined will not show up.
+   Note the outer cast cannot be a boolean type as the only valid values
+   are 0,-1/1 (depending on the signedness of the boolean) and the negative
+   is there to get the correct value.  */
 (simplify
  (convert (negate:s@1 (convert:s @0)))
  (if (INTEGRAL_TYPE_P (type)
       && tree_nop_conversion_p (type, TREE_TYPE (@1))
-      && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0)))
+      && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (@0))
+      && TREE_CODE (type) != BOOLEAN_TYPE)
     (negate (convert @0))))
 
 (for op (negate abs)
@@ -1074,46 +1141,62 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* cos(copysign(x, y)) -> cos(x).  Similarly for cosh.  */
 (for coss (COS COSH)
    copysigns (COPYSIGN)
- (simplify
-  (coss (copysigns @0 @1))
-   (coss @0)))
(for copysigns (COPYSIGN)
 (simplify
+   (coss (copysigns @0 @1))
+    (coss @0))))
 
 /* pow(copysign(x, y), z) -> pow(x, z) if z is an even integer.  */
 (for pows (POW)
    copysigns (COPYSIGN)
- (simplify
-  (pows (copysigns @0 @2) REAL_CST@1)
-  (with { HOST_WIDE_INT n; }
-   (if (real_isinteger (&TREE_REAL_CST (@1), &n) && (n & 1) == 0)
-    (pows @0 @1)))))
(for copysigns (COPYSIGN)
 (simplify
+   (pows (copysigns @0 @2) REAL_CST@1)
+   (with { HOST_WIDE_INT n; }
+    (if (real_isinteger (&TREE_REAL_CST (@1), &n) && (n & 1) == 0)
+     (pows @0 @1))))))
 /* Likewise for powi.  */
 (for pows (POWI)
    copysigns (COPYSIGN)
- (simplify
-  (pows (copysigns @0 @2) INTEGER_CST@1)
-  (if ((wi::to_wide (@1) & 1) == 0)
-   (pows @0 @1))))
(for copysigns (COPYSIGN)
 (simplify
+   (pows (copysigns @0 @2) INTEGER_CST@1)
+   (if ((wi::to_wide (@1) & 1) == 0)
+    (pows @0 @1)))))
 
 (for hypots (HYPOT)
    copysigns (COPYSIGN)
- /* hypot(copysign(x, y), z) -> hypot(x, z).  */
- (simplify
-  (hypots (copysigns @0 @1) @2)
-  (hypots @0 @2))
- /* hypot(x, copysign(y, z)) -> hypot(x, y).  */
- (simplify
-  (hypots @0 (copysigns @1 @2))
-  (hypots @0 @1)))
(for copysigns (COPYSIGN)
 /* hypot(copysign(x, y), z) -> hypot(x, z).  */
 (simplify
+   (hypots (copysigns @0 @1) @2)
+   (hypots @0 @2))
 /* hypot(x, copysign(y, z)) -> hypot(x, y).  */
 (simplify
+   (hypots @0 (copysigns @1 @2))
+   (hypots @0 @1))))
 
-/* copysign(x, CST) -> [-]abs (x).  */
+/* copysign(x, CST) -> abs (x).  If the target does not
+   support the copysign optab then canonicalize
+   copysign(x, -CST) -> fneg (abs (x)).   */
 (for copysigns (COPYSIGN_ALL)
  (simplify
   (copysigns @0 REAL_CST@1)
-  (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
-   (negate (abs @0))
-   (abs @0))))
+  (if (!REAL_VALUE_NEGATIVE (TREE_REAL_CST (@1)))
+   (abs @0)
+#if GIMPLE
+   (if (!direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+                                        OPTIMIZE_FOR_BOTH))
+    (negate (abs @0)))
+#endif
+   )))
 
+#if GIMPLE
+/* Transform fneg (fabs (X)) -> copysign (X, -1) as the canonical
+   representation if the target supports the copysign optab.  */
+(simplify
+ (negate (abs @0))
+ (if (direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+                                     OPTIMIZE_FOR_BOTH))
+   (IFN_COPYSIGN @0 { build_minus_one_cst (type); })))
+#endif
 /* copysign(copysign(x, y), z) -> copysign(x, z).  */
 (for copysigns (COPYSIGN_ALL)
  (simplify
@@ -1146,6 +1229,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && tree_nop_conversion_p (type, TREE_TYPE (@1)))
    (lshift @0 @2)))
 
+/* Fold a * !a into 0.  */
+(simplify
+ (mult:c @0 (convert? (eq @0 integer_zerop)))
+  { build_zero_cst (type); })
+(simplify
+ (mult:c @0 (vec_cond (eq @0 integer_zerop) @1 integer_zerop))
+  { build_zero_cst (type); })
+(simplify
+ (mult:c @0 (vec_cond (ne @0 integer_zerop) integer_zerop @1))
+  { build_zero_cst (type); })
+
 /* Shifts by precision or greater result in zero.  */
 (for shift (lshift rshift)
  (simplify
@@ -1248,7 +1342,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Simplify ~X & X as zero.  */
 (simplify
- (bit_and (convert? @0) (convert? @1))
+ (bit_and:c (convert? @0) (convert? (maybe_bit_not @1)))
  (with { bool wascmp; }
   (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1))
        && bitwise_inverted_equal_p (@0, @1, wascmp))
@@ -1350,6 +1444,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && TYPE_PRECISION (TREE_TYPE (@0)) == 1)
   (bit_ior @0 (bit_xor @1 { build_one_cst (type); }))))
 
+/* a | ((~a) ^ b)  -->  a | (~b) (alt version of the above 2) */
+(simplify
+ (bit_ior:c @0 (bit_xor:cs @1 @2))
+ (with { bool wascmp; }
+ (if (bitwise_inverted_equal_p (@0, @1, wascmp)
+      && (!wascmp || element_precision (type) == 1))
+  (bit_ior @0 (bit_not @2)))))
+
+/* a & ~(a ^ b)  -->  a & b  */
+(simplify
+ (bit_and:c @0 (bit_not (bit_xor:c @0 @1)))
+ (bit_and @0 @1))
+
+/* a & (a == b)  -->  a & b (boolean version of the above). */
+(simplify
+ (bit_and:c @0 (nop_convert? (eq:c @0 @1)))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && TYPE_PRECISION (TREE_TYPE (@0)) == 1)
+  (bit_and @0 @1)))
+
+/* a & ((~a) ^ b)  -->  a & b (alt version of the above 2) */
+(simplify
+ (bit_and:c @0 (bit_xor:c @1 @2))
+ (with { bool wascmp; }
+ (if (bitwise_inverted_equal_p (@0, @1, wascmp)
+      && (!wascmp || element_precision (type) == 1))
+  (bit_and @0 @2))))
+
 /* (a | b) | (a &^ b)  -->  a | b  */
 (for op (bit_and bit_xor)
  (simplify
@@ -1485,7 +1607,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* ~x ^ x -> -1 */
 (for op (bit_ior bit_xor)
  (simplify
-  (op (convert? @0) (convert? @1))
+  (op:c (convert? @0) (convert? (maybe_bit_not @1)))
   (with { bool wascmp; }
    (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1))
         && bitwise_inverted_equal_p (@0, @1, wascmp))
@@ -1522,6 +1644,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
       && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
   @0))
+
+/* `a & (x | CST)` -> a if we know that (a & ~CST) == 0   */
+(simplify
+ (bit_and:c SSA_NAME@0 (bit_ior @1 INTEGER_CST@2))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@2)) == 0)
+  @0))
+
 /* x | C -> C if we know that x & ~C == 0.  */
 (simplify
  (bit_ior SSA_NAME@0 INTEGER_CST@1)
@@ -1806,6 +1936,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (simplify
  (bit_xor:c (convert1? (bit_xor:c @0 @@1)) (convert2? @1))
  (convert @0))
+
+/* (X & ~Y) & Y -> 0 */
+(simplify
+ (bit_and:c (bit_and @0 @1) @2)
+ (with { bool wascmp; }
+  (if (bitwise_inverted_equal_p (@0, @2, wascmp)
+       || bitwise_inverted_equal_p (@1, @2, wascmp))
+   { wascmp ? constant_boolean_node (false, type) : build_zero_cst (type); })))
+/* (X | ~Y) | Y -> -1 */
+(simplify
+ (bit_ior:c (bit_ior @0 @1) @2)
+ (with { bool wascmp; }
+  (if ((bitwise_inverted_equal_p (@0, @2, wascmp)
+        || bitwise_inverted_equal_p (@1, @2, wascmp))
+       && (!wascmp || element_precision (type) == 1))
+   { build_all_ones_cst (TREE_TYPE (@0)); })))
+
 /* (X & Y) & (X & Z) -> (X & Y) & Z
    (X | Y) | (X | Z) -> (X | Y) | Z  */
 (for op (bit_and bit_ior)
@@ -2174,6 +2321,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
       && (TYPE_UNSIGNED (TREE_TYPE (@1))
          || TYPE_PRECISION (TREE_TYPE (@1)) > 1)
+      && INTEGRAL_TYPE_P (type)
+      && (TYPE_UNSIGNED (type)
+         || TYPE_PRECISION (type) > 1)
       && wi::leu_p (tree_nonzero_bits (@1), 1))))
 
 /* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 }.  */
@@ -2255,12 +2405,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (mult (convert @0) @1)))
 
 /* Narrow integer multiplication by a zero_one_valued_p operand.
-   Multiplication by [0,1] is guaranteed not to overflow.  */
+   Multiplication by [0,1] is guaranteed not to overflow except for
+   1bit signed types.  */
 (simplify
  (convert (mult@0 zero_one_valued_p@1 INTEGER_CST@2))
  (if (INTEGRAL_TYPE_P (type)
       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
-      && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))
+      && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0))
+      && (TYPE_UNSIGNED (type) || TYPE_PRECISION (type) > 1))
   (mult (convert @1) (convert @2))))
 
 /* (X << C) != 0 can be simplified to X, when C is zero_one_valued_p.
@@ -2527,6 +2679,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
           || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
    (op @0 @1))))
+/* And similar for pointers.  */
+(for op (eq ne)
+ (simplify
+  (op (pointer_plus @0 @1) (pointer_plus @0 @2))
+  (op @1 @2)))
+(simplify
+ (pointer_diff (pointer_plus @0 @1) (pointer_plus @0 @2))
+ (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+  (convert (minus @1 @2))))
 
 /* X - Z < Y - Z is the same as X < Y when there is no overflow.  */
 (for op (lt le ge gt)
@@ -2654,6 +2815,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (TREE_INT_CST_LOW (@1) & 1)
    { constant_boolean_node (cmp == NE_EXPR, type); })))
 
+/*
+   U & N <= U  -> true
+   U & N >  U  -> false
+   U needs to be non-negative.
+
+   U | N <  U  -> false
+   U | N >= U  -> true
+   U and N needs to be non-negative
+
+   U | N <  U  -> true
+   U | N >= U  -> false
+   U needs to be non-negative and N needs to be a negative constant.
+   */
+(for cmp   (lt      ge      le      gt     )
+     bitop (bit_ior bit_ior bit_and bit_and)
+ (simplify
+  (cmp:c (bitop:c tree_expr_nonnegative_p@0 @1) @0)
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))
+   (if (bitop == BIT_AND_EXPR || tree_expr_nonnegative_p (@1))
+    { constant_boolean_node (cmp == GE_EXPR || cmp == LE_EXPR, type); }
+    /* The sign is opposite now so the comparison is swapped around. */
+    (if (TREE_CODE (@1) == INTEGER_CST && wi::neg_p (wi::to_wide (@1)))
+     { constant_boolean_node (cmp == LT_EXPR, type); })))))
+
 /* Arguments on which one can call get_nonzero_bits to get the bits
    possibly set.  */
 (match with_possible_nonzero_bits
@@ -2870,6 +3055,47 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        || POINTER_TYPE_P (itype))
       && wi::eq_p (wi::to_wide (int_cst), wi::max_value (itype))))))
 
+/* Unsigned Saturation Add */
+(match (usadd_left_part_1 @0 @1)
+ (plus:c @0 @1)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+(match (usadd_left_part_2 @0 @1)
+ (realpart (IFN_ADD_OVERFLOW:c @0 @1))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+(match (usadd_right_part_1 @0 @1)
+ (negate (convert (lt (plus:c @0 @1) @0)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+(match (usadd_right_part_1 @0 @1)
+ (negate (convert (gt @0 (plus:c @0 @1))))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+(match (usadd_right_part_2 @0 @1)
+ (negate (convert (ne (imagpart (IFN_ADD_OVERFLOW:c @0 @1)) integer_zerop)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* We cannot merge or overload usadd_left_part_1 and usadd_left_part_2
+   because the sub part of left_part_2 cannot work with right_part_1.
+   For example, left_part_2 pattern focus one .ADD_OVERFLOW but the
+   right_part_1 has nothing to do with .ADD_OVERFLOW.  */
+
+/* Unsigned saturation add, case 1 (branchless):
+   SAT_U_ADD = (X + Y) | - ((X + Y) < X) or
+   SAT_U_ADD = (X + Y) | - (X > (X + Y)).  */
+(match (unsigned_integer_sat_add @0 @1)
+ (bit_ior:c (usadd_left_part_1 @0 @1) (usadd_right_part_1 @0 @1)))
+
+/* Unsigned saturation add, case 2 (branchless with .ADD_OVERFLOW).  */
+(match (unsigned_integer_sat_add @0 @1)
+ (bit_ior:c (usadd_left_part_2 @0 @1) (usadd_right_part_2 @0 @1)))
+
 /* x >  y  &&  x != XXX_MIN  -->  x > y
    x >  y  &&  x == XXX_MIN  -->  false . */
 (for eqne (eq ne)
@@ -2949,7 +3175,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
   (gt @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); }))))
 
-/* Convert (X == CST1) && (X OP2 CST2) to a known value
+/* Convert (X == CST1) && ((other)X OP2 CST2) to a known value
    based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
 /* Convert (X == Y) && (X OP2 Y) to a known value if X is an integral type.
    Similarly for (X != Y).  */
@@ -2957,26 +3183,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for code1 (eq ne)
  (for code2 (eq ne lt gt le ge)
   (simplify
-   (bit_and:c (code1@3 @0 @1) (code2@4 @0 @2))
+   (bit_and:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
    (if ((TREE_CODE (@1) == INTEGER_CST
         && TREE_CODE (@2) == INTEGER_CST)
        || ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
             || POINTER_TYPE_P (TREE_TYPE (@1)))
-           && operand_equal_p (@1, @2)))
+           && bitwise_equal_p (@1, @2)))
     (with
      {
       bool one_before = false;
       bool one_after = false;
       int cmp = 0;
+      bool allbits = true;
       if (TREE_CODE (@1) == INTEGER_CST
          && TREE_CODE (@2) == INTEGER_CST)
        {
-         cmp = tree_int_cst_compare (@1, @2);
+         allbits = TYPE_PRECISION (TREE_TYPE (@1)) <= TYPE_PRECISION (TREE_TYPE (@2));
+         auto t1 = wi::to_wide (fold_convert (TREE_TYPE (@2), @1));
+         auto t2 = wi::to_wide (@2);
+         cmp = wi::cmp (t1, t2, TYPE_SIGN (TREE_TYPE (@2)));
          if (cmp < 0
-             && wi::to_wide (@1) == wi::to_wide (@2) - 1)
+             && t1 == t2 - 1)
            one_before = true;
          if (cmp > 0
-             && wi::to_wide (@1) == wi::to_wide (@2) + 1)
+             && t1 == t2 + 1)
            one_after = true;
        }
       bool val;
@@ -2994,25 +3224,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (switch
       (if (code1 == EQ_EXPR && val) @3)
       (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
-      (if (code1 == NE_EXPR && !val) @4)
+      (if (code1 == NE_EXPR && !val && allbits) @4)
       (if (code1 == NE_EXPR
            && code2 == GE_EXPR
-          && cmp == 0)
-       (gt @0 @1))
+          && cmp == 0
+          && allbits)
+       (gt @c0 (convert @1)))
       (if (code1 == NE_EXPR
            && code2 == LE_EXPR
-          && cmp == 0)
-       (lt @0 @1))
+          && cmp == 0
+          && allbits)
+       (lt @c0 (convert @1)))
       /* (a != (b+1)) & (a > b) -> a > (b+1) */
       (if (code1 == NE_EXPR
            && code2 == GT_EXPR
-          && one_after)
-       (gt @0 @1))
+          && one_after
+          && allbits)
+       (gt @c0 (convert @1)))
       /* (a != (b-1)) & (a < b) -> a < (b-1) */
       (if (code1 == NE_EXPR
            && code2 == LT_EXPR
-          && one_before)
-       (lt @0 @1))
+          && one_before
+          && allbits)
+       (lt @c0 (convert @1)))
      )
     )
    )
@@ -3076,26 +3310,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (for code1 (eq ne)
  (for code2 (eq ne lt gt le ge)
   (simplify
-   (bit_ior:c (code1@3 @0 @1) (code2@4 @0 @2))
+   (bit_ior:c (code1:c@3 @0 @1) (code2:c@4 (convert?@c0 @0) @2))
    (if ((TREE_CODE (@1) == INTEGER_CST
         && TREE_CODE (@2) == INTEGER_CST)
        || ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
            || POINTER_TYPE_P (TREE_TYPE (@1)))
-           && operand_equal_p (@1, @2)))
+           && bitwise_equal_p (@1, @2)))
     (with
      {
       bool one_before = false;
       bool one_after = false;
       int cmp = 0;
+      bool allbits = true;
       if (TREE_CODE (@1) == INTEGER_CST
          && TREE_CODE (@2) == INTEGER_CST)
        {
-         cmp = tree_int_cst_compare (@1, @2);
+         allbits = TYPE_PRECISION (TREE_TYPE (@1)) <= TYPE_PRECISION (TREE_TYPE (@2));
+         auto t1 = wi::to_wide (fold_convert (TREE_TYPE (@2), @1));
+         auto t2 = wi::to_wide (@2);
+         cmp = wi::cmp (t1, t2, TYPE_SIGN (TREE_TYPE (@2)));
          if (cmp < 0
-             && wi::to_wide (@1) == wi::to_wide (@2) - 1)
+             && t1 == t2 - 1)
            one_before = true;
          if (cmp > 0
-             && wi::to_wide (@1) == wi::to_wide (@2) + 1)
+             && t1 == t2 + 1)
            one_after = true;
        }
       bool val;
@@ -3112,26 +3350,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      }
      (switch
       (if (code1 == EQ_EXPR && val) @4)
-      (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
-      (if (code1 == NE_EXPR && !val) @3)
+      (if (code1 == NE_EXPR && val && allbits) { constant_boolean_node (true, type); })
+      (if (code1 == NE_EXPR && !val && allbits) @3)
       (if (code1 == EQ_EXPR
            && code2 == GT_EXPR
-          && cmp == 0)
-       (ge @0 @1))
+          && cmp == 0
+          && allbits)
+       (ge @c0 @2))
       (if (code1 == EQ_EXPR
            && code2 == LT_EXPR
-          && cmp == 0)
-       (le @0 @1))
+          && cmp == 0
+          && allbits)
+       (le @c0 @2))
       /* (a == (b-1)) | (a >= b) -> a >= (b-1) */
       (if (code1 == EQ_EXPR
            && code2 == GE_EXPR
-          && one_before)
-       (ge @0 @1))
+          && one_before
+          && allbits)
+       (ge @c0 (convert @1)))
       /* (a == (b+1)) | (a <= b) -> a <= (b-1) */
       (if (code1 == EQ_EXPR
            && code2 == LE_EXPR
-          && one_after)
-       (le @0 @1))
+          && one_after
+          && allbits)
+       (le @c0 (convert @1)))
      )
     )
    )
@@ -3207,6 +3449,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
     (rcmp @0 @1))))
 
+/* (type)([0,1]@a != 0) -> (type)a
+   (type)([0,1]@a == 1) -> (type)a
+   (type)([0,1]@a == 0) -> a ^ 1
+   (type)([0,1]@a != 1) -> a ^ 1.  */
+(for eqne (eq ne)
+ (simplify
+  (convert (eqne zero_one_valued_p@0 INTEGER_CST@1))
+  (if ((integer_zerop (@1) || integer_onep (@1)))
+   (if ((eqne == EQ_EXPR) ^ integer_zerop (@1))
+    (convert @0)
+    /* Only do this if the types match as (type)(a == 0) is
+       canonical form normally, while `a ^ 1` is canonical when
+       there is no type change. */
+    (if (types_match (type, TREE_TYPE (@0)))
+     (bit_xor @0 { build_one_cst (type); } ))))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
@@ -4025,8 +4283,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* (x <= 0 ? -x : 0) -> max(-x, 0).  */
 (simplify
-  (cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1)
-  (max @2 @1))
+ (cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1)
+ (if (ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_UNDEFINED (type))
+  (max @2 @1)))
 
 /* (zero_one == 0) ? y : z <op> y -> ((typeof(y))zero_one * z) <op> y */
 (for op (bit_xor bit_ior plus)
@@ -4052,6 +4311,56 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && (INTEGRAL_TYPE_P (TREE_TYPE (@0))))
        (op (mult (convert:type @0) @2) @1))))
 
+/* ?: Value replacement. */
+/* a == 0 ? b : b + a  -> b + a */
+(for op (plus bit_ior bit_xor)
+ (simplify
+  (cond (eq @0 integer_zerop) @1 (op:c@2 @1 @0))
+   @2))
+/* a == 0 ? b : b - a  -> b - a */
+/* a == 0 ? b : b ptr+ a  -> b ptr+ a */
+/* a == 0 ? b : b shift/rotate a -> b shift/rotate a */
+(for op (lrotate rrotate lshift rshift minus pointer_plus)
+ (simplify
+  (cond (eq @0 integer_zerop) @1 (op@2 @1 @0))
+   @2))
+
+/* a == 1 ? b : b / a  -> b / a */
+(for op (trunc_div ceil_div floor_div round_div exact_div)
+ (simplify
+  (cond (eq @0 integer_onep) @1 (op@2 @1 @0))
+   @2))
+
+/* a == 1 ? b : a * b -> a * b */
+(for op (mult)
+ (simplify
+  (cond (eq @0 integer_onep) @1 (op:c@2 @1 @0))
+   @2))
+
+/* a == -1 ? b : a & b -> a & b */
+(for op (bit_and)
+ (simplify
+  (cond (eq @0 integer_all_onesp) @1 (op:c@2 @1 @0))
+   @2))
+
+/* a != 0 ? a / b : 0  -> a / b iff b is nonzero. */
+(for op (trunc_div ceil_div floor_div round_div exact_div)
+ (simplify
+  (cond (ne @0 integer_zerop) (op@2 @3 @1) integer_zerop )
+   (if (bitwise_equal_p (@0, @3)
+        && tree_expr_nonzero_p (@1))
+    @2)))
+
+/* Note we prefer the != case here
+   as (a != 0) * (a * b) will generate that version. */
+/* a != 0 ? a * b : 0 -> a * b */
+/* a != 0 ? a & b : 0 -> a & b */
+(for op (mult bit_and)
+ (simplify
+  (cond (ne @0 integer_zerop) (op:c@2 @1 @3) integer_zerop)
+  (if (bitwise_equal_p (@0, @3))
+   @2)))
+
 /* Simplifications of shift and rotates.  */
 
 (for rotate (lrotate rrotate)
@@ -4549,11 +4858,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     /* If we have a sign-extension of a zero-extended value, we can
        replace that by a single zero-extension.  Likewise if the
        final conversion does not change precision we can drop the
-       intermediate conversion.  */
+       intermediate conversion.  Similarly truncation of a sign-extension
+       can be replaced by a single sign-extension.  */
     (if (inside_int && inter_int && final_int
         && ((inside_prec < inter_prec && inter_prec < final_prec
              && inside_unsignedp && !inter_unsignedp)
-            || final_prec == inter_prec))
+            || final_prec == inter_prec
+            || (inside_prec < inter_prec && inter_prec > final_prec
+                && !inside_unsignedp && inter_unsignedp)))
      (ocvt @0))
 
     /* Two conversions in a row are not needed unless:
@@ -4617,6 +4929,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (simplify
    (float (fix_trunc @0))
    (if (!flag_trapping_math
+       && !HONOR_SIGNED_ZEROS (type)
        && types_match (type, TREE_TYPE (@0))
        && direct_internal_fn_supported_p (IFN_TRUNC, type,
                                          OPTIMIZE_FOR_BOTH))
@@ -4921,15 +5234,36 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (c ? a : b) op (c ? d : e)  -->  c ? (a op d) : (b op e) */
  (simplify
   (op (vec_cond:s @0 @1 @2) (vec_cond:s @0 @3 @4))
-  (vec_cond @0 (op! @1 @3) (op! @2 @4)))
+  (if (TREE_CODE_CLASS (op) != tcc_comparison
+       || types_match (type, TREE_TYPE (@1))
+       || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+       || (optimize_vectors_before_lowering_p ()
+          /* The following is optimistic on the side of non-support, we are
+             missing the legacy vcond{,u,eq} cases.  Do this only when
+             lowering will be able to fixup..  */
+          && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+                                      TREE_TYPE (@0), ERROR_MARK)))
+   (vec_cond @0 (op! @1 @3) (op! @2 @4))))
 
 /* (c ? a : b) op d  -->  c ? (a op d) : (b op d) */
  (simplify
   (op (vec_cond:s @0 @1 @2) @3)
-  (vec_cond @0 (op! @1 @3) (op! @2 @3)))
+  (if (TREE_CODE_CLASS (op) != tcc_comparison
+       || types_match (type, TREE_TYPE (@1))
+       || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+       || (optimize_vectors_before_lowering_p ()
+          && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+                                      TREE_TYPE (@0), ERROR_MARK)))
+   (vec_cond @0 (op! @1 @3) (op! @2 @3))))
  (simplify
   (op @3 (vec_cond:s @0 @1 @2))
-  (vec_cond @0 (op! @3 @1) (op! @3 @2))))
+  (if (TREE_CODE_CLASS (op) != tcc_comparison
+       || types_match (type, TREE_TYPE (@1))
+       || expand_vec_cond_expr_p (type, TREE_TYPE (@0), ERROR_MARK)
+       || (optimize_vectors_before_lowering_p ()
+          && !expand_vec_cond_expr_p (TREE_TYPE (@1),
+                                      TREE_TYPE (@0), ERROR_MARK)))
+   (vec_cond @0 (op! @3 @1) (op! @3 @2)))))
 
 #if GIMPLE
 (match (nop_atomic_bit_test_and_p @0 @1 @4)
@@ -5012,6 +5346,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* (v ? w : 0) ? a : b is just (v & w) ? a : b
    Currently disabled after pass lvec because ARM understands
    VEC_COND_EXPR<v==w,-1,0> but not a plain v==w fed to BIT_IOR_EXPR.  */
+#if GIMPLE
+/* These can only be done in gimple as fold likes to convert:
+   (CMP) & N into (CMP) ? N : 0
+   and we try to match the same pattern again and again. */
 (simplify
  (vec_cond (vec_cond:s @0 @3 integer_zerop) @1 @2)
  (if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
@@ -5029,6 +5367,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (optimize_vectors_before_lowering_p () && types_match (@0, @3))
   (vec_cond (bit_and @0 (bit_not @3)) @2 @1)))
 
+/*  ((VCE (a cmp b ? -1 : 0)) < 0) ? c : d is just
+    (VCE ((a cmp b) ? (VCE c) : (VCE d))) when TYPE_PRECISION of the
+    component type of the outer vec_cond is greater equal the inner one.  */
+(for cmp (simple_comparison)
+ (simplify
+  (vec_cond
+    (lt (view_convert@5 (vec_cond@6 (cmp@4 @0 @1)
+                                   integer_all_onesp
+                                   integer_zerop))
+         integer_zerop) @2 @3)
+  (if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0))
+       && VECTOR_INTEGER_TYPE_P (TREE_TYPE (@5))
+       && !TYPE_UNSIGNED (TREE_TYPE (@5))
+       && VECTOR_TYPE_P (TREE_TYPE (@6))
+       && VECTOR_TYPE_P (type)
+       && tree_int_cst_le (TYPE_SIZE (TREE_TYPE (type)),
+                          TYPE_SIZE (TREE_TYPE (TREE_TYPE (@6))))
+       && TYPE_SIZE (type) == TYPE_SIZE (TREE_TYPE (@6)))
+   (with { tree vtype = TREE_TYPE (@6);}
+     (view_convert:type
+       (vec_cond @4 (view_convert:vtype @2) (view_convert:vtype @3)))))))
+
 /* c1 ? c2 ? a : b : b  -->  (c1 & c2) ? a : b  */
 (simplify
  (vec_cond @0 (vec_cond:s @1 @2 @3) @3)
@@ -5046,6 +5406,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (vec_cond @0 @3 (vec_cond:s @1 @2 @3))
  (if (optimize_vectors_before_lowering_p () && types_match (@0, @1))
   (vec_cond (bit_and (bit_not @0) @1) @2 @3)))
+#endif
 
 /* Canonicalize mask ? { 0, ... } : { -1, ...} to ~mask if the mask
    types are compatible.  */
@@ -5067,36 +5428,53 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (switch
   (if (integer_zerop (@2))
    (switch
-    /* a ? 1 : 0 -> a if 0 and 1 are integral types. */
+    /* a ? 1 : 0 -> a if 0 and 1 are integral types.  */
     (if (integer_onep (@1))
      (convert (convert:boolean_type_node @0)))
+    /* a ? -1 : 0 -> -a.  */
+    (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@1))
+     (if (TYPE_PRECISION (type) == 1)
+      /* For signed 1-bit precision just cast bool to the type.  */
+      (convert (convert:boolean_type_node @0))
+      (if (TREE_CODE (type) == BOOLEAN_TYPE)
+       (with {
+         tree intt = build_nonstandard_integer_type (TYPE_PRECISION (type),
+                                                     TYPE_UNSIGNED (type));
+       }
+       (convert (negate (convert:intt (convert:boolean_type_node @0)))))
+       (negate (convert:type (convert:boolean_type_node @0))))))
     /* a ? powerof2cst : 0 -> a << (log2(powerof2cst)) */
     (if (INTEGRAL_TYPE_P (type) && integer_pow2p (@1))
      (with {
        tree shift = build_int_cst (integer_type_node, tree_log2 (@1));
       }
-      (lshift (convert (convert:boolean_type_node @0)) { shift; })))
-    /* a ? -1 : 0 -> -a.  No need to check the TYPE_PRECISION not being 1
-       here as the powerof2cst case above will handle that case correctly.  */
-    (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@1))
-     (negate (convert:type (convert:boolean_type_node @0))))))
+      (lshift (convert (convert:boolean_type_node @0)) { shift; })))))
   (if (integer_zerop (@1))
    (switch
-    /* a ? 0 : 1 -> !a. */
+    /* a ? 0 : 1 -> !a.  */
     (if (integer_onep (@2))
      (convert (bit_xor (convert:boolean_type_node @0) { boolean_true_node; })))
-    /* a ? powerof2cst : 0 -> (!a) << (log2(powerof2cst)) */
+    /* a ? 0 : -1 -> -(!a).  */
+    (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@2))
+     (if (TYPE_PRECISION (type) == 1)
+      /* For signed 1-bit precision just cast bool to the type.  */
+      (convert (bit_xor (convert:boolean_type_node @0) { boolean_true_node; }))
+      (if (TREE_CODE (type) == BOOLEAN_TYPE)
+       (with {
+         tree intt = build_nonstandard_integer_type (TYPE_PRECISION (type),
+                                                     TYPE_UNSIGNED (type));
+       }
+       (convert (negate (convert:intt (bit_xor (convert:boolean_type_node @0)
+                                               { boolean_true_node; })))))
+       (negate (convert:type (bit_xor (convert:boolean_type_node @0)
+                                     { boolean_true_node; }))))))
+    /* a ? 0 : powerof2cst -> (!a) << (log2(powerof2cst)) */
     (if (INTEGRAL_TYPE_P (type) && integer_pow2p (@2))
      (with {
        tree shift = build_int_cst (integer_type_node, tree_log2 (@2));
       }
       (lshift (convert (bit_xor (convert:boolean_type_node @0)
-                               { boolean_true_node; })) { shift; })))
-    /* a ? -1 : 0 -> -(!a).  No need to check the TYPE_PRECISION not being 1
-       here as the powerof2cst case above will handle that case correctly.  */
-    (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@2))
-     (negate (convert:type (bit_xor (convert:boolean_type_node @0)
-                                   { boolean_true_node; }))))))))
+                               { boolean_true_node; })) { shift; })))))))
 
 /* (a > 1) ? 0 : (cast)a is the same as (cast)(a == 1)
    for unsigned types. */
@@ -5128,7 +5506,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Optimize
    # x_5 in range [cst1, cst2] where cst2 = cst1 + 1
-   x_5 ? cstN ? cst4 : cst3
+   x_5 == cstN ? cst4 : cst3
    # op is == or != and N is 1 or 2
    to r_6 = x_5 + (min (cst3, cst4) - cst1) or
    r_6 = (min (cst3, cst4) + cst1) - x_5 depending on op, N and which
@@ -5164,7 +5542,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
         type1 = type;
        auto prec = TYPE_PRECISION (type1);
        auto unsign = TYPE_UNSIGNED (type1);
-       type1 = build_nonstandard_integer_type (prec, unsign);
+       if (TREE_CODE (type1) == BOOLEAN_TYPE)
+       type1 = build_nonstandard_integer_type (prec, unsign);
        min = wide_int::from (min, prec,
                             TYPE_SIGN (TREE_TYPE (@0)));
        wide_int a = wide_int::from (wi::to_wide (arg0), prec,
@@ -5203,14 +5582,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       }
       (if (code == PLUS_EXPR)
        (convert (plus (convert:type1 @0) { arg; }))
-       (convert (minus { arg; } (convert:type1 @0)))
-      )
-     )
-    )
-   )
-  )
- )
-)
+       (convert (minus { arg; } (convert:type1 @0))))))))))
 #endif
 
 (simplify
@@ -5420,6 +5792,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (if (VECTOR_TYPE_P (type))
        (view_convert @c0)
        (convert @c0))))))))
+
+/* This is for VEC_COND_EXPR
+   Optimize A < B ? A : B to MIN (A, B)
+           A > B ? A : B to MAX (A, B).  */
+(for cmp (lt le ungt unge gt ge unlt unle)
+     minmax (min min min min max max max max)
+     MINMAX (MIN_EXPR MIN_EXPR MIN_EXPR MIN_EXPR MAX_EXPR MAX_EXPR MAX_EXPR MAX_EXPR)
+ (simplify
+  (vec_cond (cmp @0 @1) @0 @1)
+   (if (VECTOR_INTEGER_TYPE_P (type)
+       && target_supports_op_p (type, MINMAX, optab_vector))
+    (minmax @0 @1))))
+
+(for cmp (lt le ungt unge gt ge unlt unle)
+     minmax (max max max max min min min min)
+     MINMAX (MAX_EXPR MAX_EXPR MAX_EXPR MAX_EXPR MIN_EXPR MIN_EXPR MIN_EXPR MIN_EXPR)
+ (simplify
+  (vec_cond (cmp @0 @1) @1 @0)
+   (if (VECTOR_INTEGER_TYPE_P (type)
+       && target_supports_op_p (type, MINMAX, optab_vector))
+    (minmax @0 @1))))
 #endif
 
 (for cnd (cond vec_cond)
@@ -5448,7 +5841,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     @2)))
  /* (a != b) ? (a + b) : (2 * a) -> (a + b) */
  (simplify
-  (cnd (ne:c @0 @1) (plus@2 @0 @1) (mult @0 uniform_integer_cst_p@3))
+  (cnd (ne:c @0 @1) (plus:c@2 @0 @1) (mult @0 uniform_integer_cst_p@3))
   (if (wi::to_wide (uniform_integer_cst_p (@3)) == 2)
    @2))
 )
@@ -5526,6 +5919,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (wi::eq_p (wi::bit_not (wi::to_wide (@1)), wi::to_wide (@2)))
   @3))
 
+/* X != C1 ? abs(X) : C2 simplifies to abs(x) when abs(C1) == C2. */
+(for op (abs absu)
+ (simplify
+  (cond (ne @0 INTEGER_CST@1) (op@3 @0) INTEGER_CST@2)
+  (if (wi::abs (wi::to_wide (@1)) == wi::to_wide (@2))
+   (if (op != ABSU_EXPR && wi::only_sign_bit_p (wi::to_wide (@1)))
+    (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+     (convert (absu:utype @0)))
+    @3))))
+
+/* X >  Positive ? X : ABS(X) -> ABS(X) */
+/* X >= Positive ? X : ABS(X) -> ABS(X) */
+/* X == Positive ? X : ABS(X) -> ABS(X) */
+(for cmp (eq gt ge)
+ (simplify
+  (cond (cmp:c @0 tree_expr_nonnegative_p@1) @0 (abs@3 @0))
+  (if (INTEGRAL_TYPE_P (type))
+   @3)))
+
+/* X == Positive ? Positive : ABS(X) -> ABS(X) */
+(simplify
+ (cond (eq:c @0 tree_expr_nonnegative_p@1) @1 (abs@3 @0))
+ (if (INTEGRAL_TYPE_P (type))
+  @3))
+
 /* (X + 1) > Y ? -X : 1 simplifies to X >= Y ? -X : 1 when
    X is unsigned, as when X + 1 overflows, X is -1, so -X == 1.  */
 (simplify
@@ -5563,11 +5981,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* !A ? B : C -> A ? C : B.  */
  (simplify
   (cnd (logical_inverted_value truth_valued_p@0) @1 @2)
-  (cnd @0 @2 @1)))
+  /* For CONDs, don't handle signed values here. */
+  (if (cnd == VEC_COND_EXPR
+       || TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (cnd @0 @2 @1))))
 
-/* abs/negative simplifications moved from fold_cond_expr_with_comparison,
-   Need to handle (A - B) case as fold_cond_expr_with_comparison does.
-   Need to handle UN* comparisons.
+/* abs/negative simplifications moved from fold_cond_expr_with_comparison.
 
    None of these transformations work for modes with signed
    zeros.  If A is +/-0, the first two transformations will
@@ -5583,46 +6002,97 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* A == 0 ? A : -A    same as -A */
  (for cmp (eq uneq)
   (simplify
-   (cnd (cmp @0 zerop) @0 (negate@1 @0))
-    (if (!HONOR_SIGNED_ZEROS (type))
+   (cnd (cmp @0 zerop) @2 (negate@1 @2))
+    (if (!HONOR_SIGNED_ZEROS (type)
+        && bitwise_equal_p (@0, @2))
      @1))
   (simplify
-   (cnd (cmp @0 zerop) zerop (negate@1 @0))
-    (if (!HONOR_SIGNED_ZEROS (type))
+   (cnd (cmp @0 zerop) zerop (negate@1 @2))
+    (if (!HONOR_SIGNED_ZEROS (type)
+        && bitwise_equal_p (@0, @2))
      @1))
  )
  /* A != 0 ? A : -A    same as A */
  (for cmp (ne ltgt)
   (simplify
-   (cnd (cmp @0 zerop) @0 (negate @0))
-    (if (!HONOR_SIGNED_ZEROS (type))
-     @0))
+   (cnd (cmp @0 zerop) @1 (negate @1))
+    (if (!HONOR_SIGNED_ZEROS (type)
+        && bitwise_equal_p (@0, @1))
+     @1))
   (simplify
-   (cnd (cmp @0 zerop) @0 integer_zerop)
-    (if (!HONOR_SIGNED_ZEROS (type))
-     @0))
+   (cnd (cmp @0 zerop) @1 integer_zerop)
+    (if (!HONOR_SIGNED_ZEROS (type)
+        && bitwise_equal_p (@0, @1))
+     @1))
  )
  /* A >=/> 0 ? A : -A    same as abs (A) */
  (for cmp (ge gt)
   (simplify
-   (cnd (cmp @0 zerop) @0 (negate @0))
-    (if (!HONOR_SIGNED_ZEROS (type)
-        && !TYPE_UNSIGNED (type))
-     (abs @0))))
+   (cnd (cmp @0 zerop) @1 (negate @1))
+    (if (!HONOR_SIGNED_ZEROS (TREE_TYPE(@0))
+        && !TYPE_UNSIGNED (TREE_TYPE(@0))
+        && bitwise_equal_p (@0, @1))
+     (if (TYPE_UNSIGNED (type))
+      (absu:type @0)
+      (abs @0)))))
  /* A <=/< 0 ? A : -A    same as -abs (A) */
  (for cmp (le lt)
   (simplify
-   (cnd (cmp @0 zerop) @0 (negate @0))
-    (if (!HONOR_SIGNED_ZEROS (type)
-        && !TYPE_UNSIGNED (type))
-     (if (ANY_INTEGRAL_TYPE_P (type)
-         && !TYPE_OVERFLOW_WRAPS (type))
+   (cnd (cmp @0 zerop) @1 (negate @1))
+    (if (!HONOR_SIGNED_ZEROS (TREE_TYPE(@0))
+        && !TYPE_UNSIGNED (TREE_TYPE(@0))
+        && bitwise_equal_p (@0, @1))
+     (if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+          && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+         || TYPE_UNSIGNED (type))
       (with {
-       tree utype = unsigned_type_for (type);
+       tree utype = unsigned_type_for (TREE_TYPE(@0));
        }
        (convert (negate (absu:utype @0))))
        (negate (abs @0)))))
  )
+
+ /* (A - B) == 0 ? (A - B) : (B - A)    same as (B - A) */
+ (for cmp (eq uneq)
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus@3 @2 @1))
+   (if (!HONOR_SIGNED_ZEROS (type))
+    @3))
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) integer_zerop) integer_zerop (minus@3 @2 @1))
+   @3)
+ )
+ /* (A - B) != 0 ? (A - B) : (B - A)    same as (A - B) */
+ (for cmp (ne ltgt)
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+   (if (!HONOR_SIGNED_ZEROS (type))
+    @0))
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) integer_zerop) @0 integer_zerop)
+   @0)
+ )
+ /* (A - B) >=/> 0 ? (A - B) : (B - A)    same as abs (A - B) */
+ (for cmp (ge gt)
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+   (if (!HONOR_SIGNED_ZEROS (type)
+       && !TYPE_UNSIGNED (type))
+    (abs @0))))
+ /* (A - B) <=/< 0 ? (A - B) : (B - A)    same as -abs (A - B) */
+ (for cmp (le lt)
+  (simplify
+   (cnd (cmp (minus@0 @1 @2) zerop) @0 (minus @2 @1))
+   (if (!HONOR_SIGNED_ZEROS (type)
+       && !TYPE_UNSIGNED (type))
+    (if (ANY_INTEGRAL_TYPE_P (type)
+        && !TYPE_OVERFLOW_WRAPS (type))
+     (with {
+        tree utype = unsigned_type_for (type);
+      }
+      (convert (negate (absu:utype @0))))
+      (negate (abs @0)))))
+ )
 )
 
 /* -(type)!A -> (type)A - 1.  */
@@ -5867,18 +6337,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* Fold ~X op ~Y as Y op X.  */
 (for cmp (simple_comparison)
  (simplify
-  (cmp (bit_not@2 @0) (bit_not@3 @1))
+  (cmp (nop_convert1?@4 (bit_not@2 @0)) (nop_convert2? (bit_not@3 @1)))
   (if (single_use (@2) && single_use (@3))
-   (cmp @1 @0))))
+   (with { tree otype = TREE_TYPE (@4); }
+    (cmp (convert:otype @1) (convert:otype @0))))))
 
 /* Fold ~X op C as X op' ~C, where op' is the swapped comparison.  */
 (for cmp (simple_comparison)
      scmp (swapped_simple_comparison)
  (simplify
-  (cmp (bit_not@2 @0) CONSTANT_CLASS_P@1)
+  (cmp (nop_convert? (bit_not@2 @0)) CONSTANT_CLASS_P@1)
   (if (single_use (@2)
        && (TREE_CODE (@1) == INTEGER_CST || TREE_CODE (@1) == VECTOR_CST))
-   (scmp @0 (bit_not @1)))))
+   (with { tree otype = TREE_TYPE (@1); }
+    (scmp (convert:otype @0) (bit_not @1))))))
 
 (for cmp (simple_comparison)
  (simplify
@@ -6387,8 +6859,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        code and here to avoid a spurious overflow flag on the resulting
        constant which fold_convert produces.  */
     (if (TREE_CODE (@1) == INTEGER_CST)
-     (cmp @00 { force_fit_type (TREE_TYPE (@00), wi::to_widest (@1), 0,
-                               TREE_OVERFLOW (@1)); })
+     (cmp @00 { force_fit_type (TREE_TYPE (@00),
+                               wide_int::from (wi::to_wide (@1),
+                                               MAX (TYPE_PRECISION (TREE_TYPE (@1)),
+                                                    TYPE_PRECISION (TREE_TYPE (@00))),
+                                               TYPE_SIGN (TREE_TYPE (@1))),
+                               0, TREE_OVERFLOW (@1)); })
      (cmp @00 (convert @1)))
 
     (if (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@00)))
@@ -6402,19 +6878,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                   >= TYPE_PRECISION (TREE_TYPE (@10)))
                  && (TYPE_UNSIGNED (TREE_TYPE (@00))
                      == TYPE_UNSIGNED (TREE_TYPE (@10))))
-             || (TREE_CODE (@10) == INTEGER_CST
+             || (TREE_CODE (@1) == INTEGER_CST
                  && INTEGRAL_TYPE_P (TREE_TYPE (@00))
-                 && int_fits_type_p (@10, TREE_TYPE (@00)))))
+                 && int_fits_type_p (@1, TREE_TYPE (@00)))))
       (cmp @00 (convert @10))
-      (if (TREE_CODE (@10) == INTEGER_CST
+      (if (TREE_CODE (@1) == INTEGER_CST
           && INTEGRAL_TYPE_P (TREE_TYPE (@00))
-          && !int_fits_type_p (@10, TREE_TYPE (@00)))
+          && !int_fits_type_p (@1, TREE_TYPE (@00)))
        (with
        {
          tree min = lower_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00));
          tree max = upper_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00));
-         bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @10));
-         bool below = integer_nonzerop (const_binop (LT_EXPR, type, @10, min));
+         bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @1));
+         bool below = integer_nonzerop (const_binop (LT_EXPR, type, @1, min));
        }
        (if (above || below)
         (if (cmp == EQ_EXPR || cmp == NE_EXPR)
@@ -6442,11 +6918,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
               && exact_real_truncate (TYPE_MODE (double_type_node), &orig))
             type1 = double_type_node;
         }
-      tree newtype
-        = (element_precision (TREE_TYPE (@00)) > element_precision (type1)
-          ? TREE_TYPE (@00) : type1);
+       tree newtype
+        = (element_precision (TREE_TYPE (@00)) > element_precision (type1)
+           ? TREE_TYPE (@00) : type1);
      }
-     (if (element_precision (TREE_TYPE (@0)) > element_precision (newtype))
+     (if (element_precision (TREE_TYPE (@0)) > element_precision (newtype)
+         && (!VECTOR_TYPE_P (type) || is_truth_type_for (newtype, type)))
       (cmp (convert:newtype @00) (convert:newtype @10))))))))
 
 
@@ -6707,14 +7184,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (cond @0 @1 @2)
  (with { bool wascmp; }
   (if (INTEGRAL_TYPE_P (type)
+       && TYPE_UNSIGNED (TREE_TYPE (@0))
        && bitwise_inverted_equal_p (@1, @2, wascmp)
-       && (!wascmp || element_precision (type) == 1))
-   (with {
-     auto prec = TYPE_PRECISION (type);
-     auto unsign = TYPE_UNSIGNED (type);
-     tree inttype = build_nonstandard_integer_type (prec, unsign);
-    }
-    (convert (bit_xor (negate (convert:inttype @0)) (convert:inttype @2)))))))
+       && (!wascmp || TYPE_PRECISION (type) == 1))
+   (if ((!TYPE_UNSIGNED (type) && TREE_CODE (type) == BOOLEAN_TYPE)
+       || TYPE_PRECISION (type) == 1)
+    (bit_xor (convert:type @0) @2)
+    (bit_xor (negate (convert:type @0)) @2)))))
 #endif
 
 /* Simplify pointer equality compares using PTA.  */
@@ -7412,6 +7888,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (COPYSIGN_ALL @0 tree_expr_nonnegative_p@1)
  (abs @0))
 
+(simplify
+ /* fabs (copysign(x, y)) -> fabs (x).  */
+ (abs (COPYSIGN_ALL @0 @1))
+ (abs @0))
+
 (for scale (LDEXP SCALBN SCALBLN)
  /* ldexp(0, x) -> 0.  */
  (simplify
@@ -8060,7 +8541,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 (simplify
  (BIT_FIELD_REF (view_convert @0) @1 @2)
- (BIT_FIELD_REF @0 @1 @2))
+ (if (! INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      || type_has_mode_precision_p (TREE_TYPE (@0)))
+  (BIT_FIELD_REF @0 @1 @2)))
 
 (simplify
  (BIT_FIELD_REF @0 @1 integer_zerop)
@@ -8224,9 +8707,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (simplify
  (bit_insert @0 (BIT_FIELD_REF@2 @1 @rsize @rpos) @ipos)
  (if (VECTOR_TYPE_P (type)
+      && (VECTOR_MODE_P (TYPE_MODE (type))
+         || optimize_vectors_before_lowering_p ())
       && types_match (@0, @1)
       && types_match (TREE_TYPE (TREE_TYPE (@0)), TREE_TYPE (@2))
-      && TYPE_VECTOR_SUBPARTS (type).is_constant ())
+      && TYPE_VECTOR_SUBPARTS (type).is_constant ()
+      && multiple_p (wi::to_poly_offset (@rpos),
+                    wi::to_poly_offset (TYPE_SIZE (TREE_TYPE (type)))))
   (with
    {
      unsigned HOST_WIDE_INT elsz
@@ -8311,31 +8798,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (op (clz:s@2 @0) INTEGER_CST@1)
    (if (integer_zerop (@1) && single_use (@2))
     /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0.  */
-    (with { tree type0 = TREE_TYPE (@0);
-           tree stype = signed_type_for (type0);
-           HOST_WIDE_INT val = 0;
-           /* Punt on hypothetical weird targets.  */
-           if (clz == CFN_CLZ
-               && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
-                                             val) == 2
-               && val == 0)
-             stype = NULL_TREE;
-         }
-     (if (stype)
-      (cmp (convert:stype @0) { build_zero_cst (stype); })))
+    (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
+     (cmp (convert:stype @0) { build_zero_cst (stype); }))
     /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1.  */
-    (with { bool ok = true;
-           HOST_WIDE_INT val = 0;
-           tree type0 = TREE_TYPE (@0);
-           /* Punt on hypothetical weird targets.  */
-           if (clz == CFN_CLZ
-               && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
-                                             val) == 2
-               && val == TYPE_PRECISION (type0) - 1)
-             ok = false;
-         }
-     (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
-      (op @0 { build_one_cst (type0); })))))))
+    (if (wi::to_wide (@1) == TYPE_PRECISION (TREE_TYPE (@0)) - 1)
+     (op @0 { build_one_cst (TREE_TYPE (@0)); }))))))
+(for op (eq ne)
+     cmp (lt ge)
+ (simplify
+  (op (IFN_CLZ:s@2 @0 @3) INTEGER_CST@1)
+  (if (integer_zerop (@1) && single_use (@2))
+   /* clz(X) == 0 is (int)X < 0 and clz(X) != 0 is (int)X >= 0.  */
+   (with { tree type0 = TREE_TYPE (@0);
+          tree stype = signed_type_for (TREE_TYPE (@0));
+          /* Punt if clz(0) == 0.  */
+          if (integer_zerop (@3))
+            stype = NULL_TREE;
+        }
+    (if (stype)
+     (cmp (convert:stype @0) { build_zero_cst (stype); })))
+   /* clz(X) == (prec-1) is X == 1 and clz(X) != (prec-1) is X != 1.  */
+   (with { bool ok = true;
+          tree type0 = TREE_TYPE (@0);
+          /* Punt if clz(0) == prec - 1.  */
+          if (wi::to_widest (@3) == TYPE_PRECISION (type0) - 1)
+            ok = false;
+        }
+    (if (ok && wi::to_wide (@1) == (TYPE_PRECISION (type0) - 1))
+     (op @0 { build_one_cst (type0); }))))))
 
 /* CTZ simplifications.  */
 (for ctz (CTZ)
@@ -8360,22 +8850,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                      val++;
                  }
              }
-           bool zero_res = false;
-           HOST_WIDE_INT zero_val = 0;
            tree type0 = TREE_TYPE (@0);
            int prec = TYPE_PRECISION (type0);
-           if (ctz == CFN_CTZ
-               && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
-                                             zero_val) == 2)
-             zero_res = true;
          }
-     (if (val <= 0)
-      (if (ok && (!zero_res || zero_val >= val))
-       { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
-      (if (val >= prec)
-       (if (ok && (!zero_res || zero_val < val))
-       { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
-       (if (ok && (!zero_res || zero_val < 0 || zero_val >= prec))
+     (if (ok && prec <= MAX_FIXED_MODE_SIZE)
+      (if (val <= 0)
+       { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); }
+       (if (val >= prec)
+       { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); }
        (cmp (bit_and @0 { wide_int_to_tree (type0,
                                             wi::mask (val, false, prec)); })
             { build_zero_cst (type0); })))))))
@@ -8383,19 +8865,68 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (simplify
    /* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C).  */
    (op (ctz:s @0) INTEGER_CST@1)
-    (with { bool zero_res = false;
-           HOST_WIDE_INT zero_val = 0;
-           tree type0 = TREE_TYPE (@0);
+    (with { tree type0 = TREE_TYPE (@0);
            int prec = TYPE_PRECISION (type0);
-           if (ctz == CFN_CTZ
-               && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_TYPE_MODE (type0),
-                                             zero_val) == 2)
-             zero_res = true;
          }
+     (if (prec <= MAX_FIXED_MODE_SIZE)
+      (if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
+       { constant_boolean_node (op == EQ_EXPR ? false : true, type); }
+       (op (bit_and @0 { wide_int_to_tree (type0,
+                                          wi::mask (tree_to_uhwi (@1) + 1,
+                                                    false, prec)); })
+          { wide_int_to_tree (type0,
+                              wi::shifted_mask (tree_to_uhwi (@1), 1,
+                                                false, prec)); })))))))
+(for op (ge gt le lt)
+     cmp (eq eq ne ne)
+ (simplify
+  /* __builtin_ctz (x) >= C -> (x & ((1 << C) - 1)) == 0.  */
+  (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+   (with { bool ok = true;
+          HOST_WIDE_INT val = 0;
+          if (!tree_fits_shwi_p (@1))
+            ok = false;
+          else
+            {
+              val = tree_to_shwi (@1);
+              /* Canonicalize to >= or <.  */
+              if (op == GT_EXPR || op == LE_EXPR)
+                {
+                  if (val == HOST_WIDE_INT_MAX)
+                    ok = false;
+                  else
+                    val++;
+                }
+            }
+          HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+          tree type0 = TREE_TYPE (@0);
+          int prec = TYPE_PRECISION (type0);
+          if (prec > MAX_FIXED_MODE_SIZE)
+            ok = false;
+         }
+     (if (val <= 0)
+      (if (ok && zero_val >= val)
+       { constant_boolean_node (cmp == EQ_EXPR ? true : false, type); })
+      (if (val >= prec)
+       (if (ok && zero_val < val)
+       { constant_boolean_node (cmp == EQ_EXPR ? false : true, type); })
+       (if (ok && (zero_val < 0 || zero_val >= prec))
+       (cmp (bit_and @0 { wide_int_to_tree (type0,
+                                            wi::mask (val, false, prec)); })
+            { build_zero_cst (type0); })))))))
+(for op (eq ne)
+ (simplify
+  /* __builtin_ctz (x) == C -> (x & ((1 << (C + 1)) - 1)) == (1 << C).  */
+  (op (IFN_CTZ:s @0 @2) INTEGER_CST@1)
+   (with { HOST_WIDE_INT zero_val = tree_to_shwi (@2);
+          tree type0 = TREE_TYPE (@0);
+          int prec = TYPE_PRECISION (type0);
+        }
+    (if (prec <= MAX_FIXED_MODE_SIZE)
      (if (tree_int_cst_sgn (@1) < 0 || wi::to_widest (@1) >= prec)
-      (if (!zero_res || zero_val != wi::to_widest (@1))
+      (if (zero_val != wi::to_widest (@1))
        { constant_boolean_node (op == EQ_EXPR ? false : true, type); })
-      (if (!zero_res || zero_val < 0 || zero_val >= prec)
+      (if (zero_val < 0 || zero_val >= prec)
        (op (bit_and @0 { wide_int_to_tree (type0,
                                           wi::mask (tree_to_uhwi (@1) + 1,
                                                     false, prec)); })
@@ -8403,13 +8934,62 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                               wi::shifted_mask (tree_to_uhwi (@1), 1,
                                                 false, prec)); })))))))
 
+#if GIMPLE
+/* ctz(ext(X)) == ctz(X).  Valid just for the UB at zero cases though.  */
+(simplify
+  (CTZ (convert@1 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+   (with { combined_fn cfn = CFN_LAST;
+          tree type0 = TREE_TYPE (@0);
+          if (TREE_CODE (type0) == BITINT_TYPE)
+            {
+              if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+                cfn = CFN_CTZ;
+              else
+                type0
+                  = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+                                                    1);
+            }
+          type0 = unsigned_type_for (type0);
+          if (cfn == CFN_LAST
+              && direct_internal_fn_supported_p (IFN_CTZ, type0,
+                                                 OPTIMIZE_FOR_BOTH))
+            cfn = CFN_CTZ;
+          if (cfn == CFN_LAST
+              && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+              && !direct_internal_fn_supported_p (IFN_CTZ,
+                                                  TREE_TYPE (@1),
+                                                  OPTIMIZE_FOR_BOTH))
+            {
+              if (TYPE_PRECISION (type0)
+                  == TYPE_PRECISION (unsigned_type_node))
+                cfn = CFN_BUILT_IN_CTZ;
+              else if (TYPE_PRECISION (type0)
+                       == TYPE_PRECISION (long_long_unsigned_type_node))
+                cfn = CFN_BUILT_IN_CTZLL;
+            } }
+    (if (cfn == CFN_CTZ)
+     (IFN_CTZ (convert:type0 @0))
+     (if (cfn == CFN_BUILT_IN_CTZ)
+      (BUILT_IN_CTZ (convert:type0 @0))
+      (if (cfn == CFN_BUILT_IN_CTZLL)
+       (BUILT_IN_CTZLL (convert:type0 @0))))))))
+#endif
+
 /* POPCOUNT simplifications.  */
 /* popcount(X) + popcount(Y) is popcount(X|Y) when X&Y must be zero.  */
 (simplify
   (plus (POPCOUNT:s @0) (POPCOUNT:s @1))
   (if (INTEGRAL_TYPE_P (type)
-       && wi::bit_and (tree_nonzero_bits (@0), tree_nonzero_bits (@1)) == 0)
-    (POPCOUNT (bit_ior @0 @1))))
+       && (wi::bit_and (widest_int::from (tree_nonzero_bits (@0), UNSIGNED),
+                       widest_int::from (tree_nonzero_bits (@1), UNSIGNED))
+          == 0))
+   (with { tree utype = TREE_TYPE (@0);
+          if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (@1)))
+            utype = TREE_TYPE (@1); }
+    (POPCOUNT (bit_ior (convert:utype @0) (convert:utype @1))))))
 
 /* popcount(X) == 0 is X == 0, and related (in)equalities.  */
 (for popcount (POPCOUNT)
@@ -8457,7 +9037,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* popcount(X&Y) + popcount(X|Y) is popcount(x) + popcount(Y).  */
 (simplify
   (plus:c (POPCOUNT:s (bit_and:s @0 @1)) (POPCOUNT:s (bit_ior:cs @0 @1)))
-  (plus (POPCOUNT @0) (POPCOUNT @1)))
+  (plus (POPCOUNT:type @0) (POPCOUNT:type @1)))
 
 /* popcount(X) + popcount(Y) - popcount(X&Y) is popcount(X|Y).  */
 /* popcount(X) + popcount(Y) - popcount(X|Y) is popcount(X&Y).  */
@@ -8473,6 +9053,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
              (popcount:s @1))
       (popcount (log2 @0 @1)))))
 
+#if GIMPLE
+/* popcount(zext(X)) == popcount(X).  */
+(simplify
+  (POPCOUNT (convert@1 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_UNSIGNED (TREE_TYPE (@0))
+       && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+   (with { combined_fn cfn = CFN_LAST;
+          tree type0 = TREE_TYPE (@0);
+          if (TREE_CODE (type0) == BITINT_TYPE)
+            {
+              if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+                cfn = CFN_POPCOUNT;
+              else
+                type0
+                  = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+                                                    1);
+            }
+          if (cfn == CFN_LAST
+              && direct_internal_fn_supported_p (IFN_POPCOUNT, type0,
+                                                 OPTIMIZE_FOR_BOTH))
+            cfn = CFN_POPCOUNT;
+          if (cfn == CFN_LAST
+              && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+              && !direct_internal_fn_supported_p (IFN_POPCOUNT,
+                                                  TREE_TYPE (@1),
+                                                  OPTIMIZE_FOR_BOTH))
+            {
+              if (TYPE_PRECISION (type0)
+                  == TYPE_PRECISION (unsigned_type_node))
+                cfn = CFN_BUILT_IN_POPCOUNT;
+              else if (TYPE_PRECISION (type0)
+                       == TYPE_PRECISION (long_long_unsigned_type_node))
+                cfn = CFN_BUILT_IN_POPCOUNTLL;
+            } }
+    (if (cfn == CFN_POPCOUNT)
+     (IFN_POPCOUNT (convert:type0 @0))
+     (if (cfn == CFN_BUILT_IN_POPCOUNT)
+      (BUILT_IN_POPCOUNT (convert:type0 @0))
+      (if (cfn == CFN_BUILT_IN_POPCOUNTLL)
+       (BUILT_IN_POPCOUNTLL (convert:type0 @0))))))))
+#endif
+
 /* PARITY simplifications.  */
 /* parity(~X) is parity(X).  */
 (simplify
@@ -8509,7 +9133,62 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* parity(X)^parity(Y) is parity(X^Y).  */
 (simplify
   (bit_xor (PARITY:s @0) (PARITY:s @1))
-  (PARITY (bit_xor @0 @1)))
+  (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+   (PARITY (bit_xor @0 @1))
+   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
+    (with { tree utype = TREE_TYPE (@0);
+           if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (@1)))
+             utype = TREE_TYPE (@1); }
+     (PARITY (bit_xor (convert:utype @0) (convert:utype @1)))))))
+
+#if GIMPLE
+/* parity(zext(X)) == parity(X).  */
+/* parity(sext(X)) == parity(X) if the difference in precision is even.  */
+(simplify
+  (PARITY (convert@1 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0))
+       && (TYPE_UNSIGNED (TREE_TYPE (@0))
+          || ((TYPE_PRECISION (TREE_TYPE (@1))
+               - TYPE_PRECISION (TREE_TYPE (@0))) & 1) == 0))
+   (with { combined_fn cfn = CFN_LAST;
+          tree type0 = TREE_TYPE (@0);
+          if (TREE_CODE (type0) == BITINT_TYPE)
+            {
+              if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+                cfn = CFN_PARITY;
+              else
+                type0
+                  = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+                                                    1);
+            }
+          type0 = unsigned_type_for (type0);
+          if (cfn == CFN_LAST
+              && direct_internal_fn_supported_p (IFN_PARITY, type0,
+                                                 OPTIMIZE_FOR_BOTH))
+            cfn = CFN_PARITY;
+          if (cfn == CFN_LAST
+              && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+              && !direct_internal_fn_supported_p (IFN_PARITY,
+                                                  TREE_TYPE (@1),
+                                                  OPTIMIZE_FOR_BOTH))
+            {
+              if (TYPE_PRECISION (type0)
+                  == TYPE_PRECISION (unsigned_type_node))
+                cfn = CFN_BUILT_IN_PARITY;
+              else if (TYPE_PRECISION (type0)
+                       == TYPE_PRECISION (long_long_unsigned_type_node))
+                cfn = CFN_BUILT_IN_PARITYLL;
+            } }
+    (if (cfn == CFN_PARITY)
+     (IFN_PARITY (convert:type0 @0))
+     (if (cfn == CFN_BUILT_IN_PARITY)
+      (BUILT_IN_PARITY (convert:type0 @0))
+      (if (cfn == CFN_BUILT_IN_PARITYLL)
+       (BUILT_IN_PARITYLL (convert:type0 @0))))))))
+#endif
 
 /* a != 0 ? FUN(a) : 0 -> Fun(a) for some builtin functions. */
 (for func (POPCOUNT BSWAP FFS PARITY)
@@ -8532,13 +9211,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
   (with { int val;
          internal_fn ifn = IFN_LAST;
-         if (direct_internal_fn_supported_p (IFN_CLZ, type, OPTIMIZE_FOR_BOTH)
-             && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
-                                           val) == 2)
+         if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+           {
+             if (tree_fits_shwi_p (@2))
+               {
+                 HOST_WIDE_INT valw = tree_to_shwi (@2);
+                 if ((int) valw == valw)
+                   {
+                     val = valw;
+                     ifn = IFN_CLZ;
+                   }
+               }
+           }
+         else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+                                                  OPTIMIZE_FOR_BOTH)
+                  && CLZ_DEFINED_VALUE_AT_ZERO
+                       (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
            ifn = IFN_CLZ;
        }
    (if (ifn == IFN_CLZ && wi::to_widest (@2) == val)
-    (IFN_CLZ @3)))))
+    (IFN_CLZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CLZ (convert?@3 @0) INTEGER_CST@2) @2)
+  (with { int val;
+         internal_fn ifn = IFN_LAST;
+         if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+           ifn = IFN_CLZ;
+         else if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (@3),
+                                                  OPTIMIZE_FOR_BOTH))
+           ifn = IFN_CLZ;
+       }
+   (if (ifn == IFN_CLZ)
+    (IFN_CLZ @3 @2))))
 
 /* a != 0 ? CTZ(a) : CST -> .CTZ(a) where CST is the result of the internal function for 0. */
 (for func (CTZ)
@@ -8546,13 +9250,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (cond (ne @0 integer_zerop@1) (func (convert?@3 @0)) INTEGER_CST@2)
   (with { int val;
          internal_fn ifn = IFN_LAST;
-         if (direct_internal_fn_supported_p (IFN_CTZ, type, OPTIMIZE_FOR_BOTH)
-             && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type),
-                                           val) == 2)
+         if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+           {
+             if (tree_fits_shwi_p (@2))
+               {
+                 HOST_WIDE_INT valw = tree_to_shwi (@2);
+                 if ((int) valw == valw)
+                   {
+                     val = valw;
+                     ifn = IFN_CTZ;
+                   }
+               }
+           }
+         else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+                                                  OPTIMIZE_FOR_BOTH)
+                  && CTZ_DEFINED_VALUE_AT_ZERO
+                       (SCALAR_INT_TYPE_MODE (TREE_TYPE (@3)), val) == 2)
            ifn = IFN_CTZ;
        }
    (if (ifn == IFN_CTZ && wi::to_widest (@2) == val)
-    (IFN_CTZ @3)))))
+    (IFN_CTZ @3 @2)))))
+(simplify
+ (cond (ne @0 integer_zerop@1) (IFN_CTZ (convert?@3 @0) INTEGER_CST@2) @2)
+  (with { int val;
+         internal_fn ifn = IFN_LAST;
+         if (TREE_CODE (TREE_TYPE (@3)) == BITINT_TYPE)
+           ifn = IFN_CTZ;
+         else if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (@3),
+                                                  OPTIMIZE_FOR_BOTH))
+           ifn = IFN_CTZ;
+       }
+   (if (ifn == IFN_CTZ)
+    (IFN_CTZ @3 @2))))
 #endif
 
 /* Common POPCOUNT/PARITY simplifications.  */
@@ -8668,8 +9397,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (plus (CTZ:type (convert:utype @0)) { build_one_cst (type); }))))
 #endif
 
-(for ffs (BUILT_IN_FFS BUILT_IN_FFSL BUILT_IN_FFSLL
-         BUILT_IN_FFSIMAX)
+(for ffs (FFS)
  /* __builtin_ffs (X) == 0 -> X == 0.
     __builtin_ffs (X) == 6 -> (X & 63) == 32.  */
  (for cmp (eq ne)
@@ -8716,6 +9444,50 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                                                  false, prec)); })
                     { build_zero_cst (TREE_TYPE (@0)); }))))))))
 
+#if GIMPLE
+/* ffs(ext(X)) == ffs(X).  */
+(simplify
+  (FFS (convert@1 @0))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_PRECISION (TREE_TYPE (@1)) > TYPE_PRECISION (TREE_TYPE (@0)))
+   (with { combined_fn cfn = CFN_LAST;
+          tree type0 = TREE_TYPE (@0);
+          if (TREE_CODE (type0) == BITINT_TYPE)
+            {
+              if (TYPE_PRECISION (type0) > MAX_FIXED_MODE_SIZE)
+                cfn = CFN_FFS;
+              else
+                type0
+                  = build_nonstandard_integer_type (TYPE_PRECISION (type0),
+                                                    0);
+            }
+          type0 = signed_type_for (type0);
+          if (cfn == CFN_LAST
+              && direct_internal_fn_supported_p (IFN_FFS, type0,
+                                                 OPTIMIZE_FOR_BOTH))
+            cfn = CFN_FFS;
+          if (cfn == CFN_LAST
+              && TYPE_PRECISION (TREE_TYPE (@1)) > BITS_PER_WORD
+              && !direct_internal_fn_supported_p (IFN_FFS,
+                                                  TREE_TYPE (@1),
+                                                  OPTIMIZE_FOR_BOTH))
+            {
+              if (TYPE_PRECISION (type0)
+                  == TYPE_PRECISION (integer_type_node))
+                cfn = CFN_BUILT_IN_FFS;
+              else if (TYPE_PRECISION (type0)
+                       == TYPE_PRECISION (long_long_integer_type_node))
+                cfn = CFN_BUILT_IN_FFSLL;
+            } }
+    (if (cfn == CFN_FFS)
+     (IFN_FFS (convert:type0 @0))
+     (if (cfn == CFN_BUILT_IN_FFS)
+      (BUILT_IN_FFS (convert:type0 @0))
+      (if (cfn == CFN_BUILT_IN_FFSLL)
+       (BUILT_IN_FFSLL (convert:type0 @0))))))))
+#endif
+
 #if GIMPLE
 
 /* Simplify:
@@ -8734,13 +9506,28 @@ and,
    (with { tree op_type = TREE_TYPE (@3); }
     (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
         && is_truth_type_for (op_type, TREE_TYPE (@0)))
-     (cond_op @0 @1 @2))))
+     (cond_op @0 (view_convert @1) @2))))
  (simplify
   (vec_cond @0 @1 (view_convert? (uncond_op@3 @2)))
    (with { tree op_type = TREE_TYPE (@3); }
     (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
         && is_truth_type_for (op_type, TREE_TYPE (@0)))
-     (cond_op (bit_not @0) @2 @1)))))
+     (cond_op (bit_not @0) (view_convert @2) @1)))))
+
+(for uncond_op (UNCOND_UNARY)
+     cond_op (COND_LEN_UNARY)
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@3 @1)) @2 @4 @5)
+   (with { tree op_type = TREE_TYPE (@3); }
+    (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+        && is_truth_type_for (op_type, TREE_TYPE (@0)))
+     (cond_op @0 (view_convert @1) @2 @4 @5))))
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@3 @2)) @4 @5)
+   (with { tree op_type = TREE_TYPE (@3); }
+    (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+        && is_truth_type_for (op_type, TREE_TYPE (@0)))
+     (cond_op (bit_not @0) (view_convert @2) @1 @4 @5)))))
 
 /* `(a ? -1 : 0) ^ b` can be converted into a conditional not.  */
 (simplify
@@ -8788,6 +9575,23 @@ and,
        && single_use (@4))
     (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1)))))))
 
+(for uncond_op (UNCOND_BINARY)
+     cond_op (COND_LEN_BINARY)
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@4 @1 @2)) @3 @5 @6)
+  (with { tree op_type = TREE_TYPE (@4); }
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && is_truth_type_for (op_type, TREE_TYPE (@0))
+       && single_use (@4))
+    (view_convert (cond_op @0 @1 @2 (view_convert:op_type @3) @5 @6)))))
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@4 @2 @3)) @5 @6)
+  (with { tree op_type = TREE_TYPE (@4); }
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && is_truth_type_for (op_type, TREE_TYPE (@0))
+       && single_use (@4))
+    (view_convert (cond_op (bit_not @0) @2 @3 (view_convert:op_type @1) @5 @6))))))
+
 /* Same for ternary operations.  */
 (for uncond_op (UNCOND_TERNARY)
      cond_op (COND_TERNARY)
@@ -8806,6 +9610,23 @@ and,
        && single_use (@5))
     (view_convert (cond_op (bit_not @0) @2 @3 @4
                  (view_convert:op_type @1)))))))
+
+(for uncond_op (UNCOND_TERNARY)
+     cond_op (COND_LEN_TERNARY)
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 (view_convert? (uncond_op@5 @1 @2 @3)) @4 @6 @7)
+  (with { tree op_type = TREE_TYPE (@5); }
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && is_truth_type_for (op_type, TREE_TYPE (@0))
+       && single_use (@5))
+    (view_convert (cond_op @0 @1 @2 @3 (view_convert:op_type @4) @6 @7)))))
+ (simplify
+  (IFN_VCOND_MASK_LEN @0 @1 (view_convert? (uncond_op@5 @2 @3 @4 @6 @7)))
+  (with { tree op_type = TREE_TYPE (@5); }
+   (if (vectorized_internal_fn_supported_p (as_internal_fn (cond_op), op_type)
+       && is_truth_type_for (op_type, TREE_TYPE (@0))
+       && single_use (@5))
+    (view_convert (cond_op (bit_not @0) @2 @3 @4 (view_convert:op_type @1) @6 @7))))))
 #endif
 
 /* Detect cases in which a VEC_COND_EXPR effectively replaces the
@@ -8837,6 +9658,35 @@ and,
         && element_precision (type) == element_precision (op_type))
     (view_convert (cond_op @2 @3 @4 @5 (view_convert:op_type @1)))))))
 
+/* Detect cases in which a VEC_COND_EXPR effectively replaces the
+   "else" value of an IFN_COND_LEN_*.  */
+(for cond_len_op (COND_LEN_BINARY)
+ (simplify
+  (vec_cond @0 (view_convert? (cond_len_op @0 @1 @2 @3 @4 @5)) @6)
+  (with { tree op_type = TREE_TYPE (@3); }
+   (if (element_precision (type) == element_precision (op_type))
+    (view_convert (cond_len_op @0 @1 @2 (view_convert:op_type @6) @4 @5)))))
+ (simplify
+  (vec_cond @0 @1 (view_convert? (cond_len_op @2 @3 @4 @5 @6 @7)))
+  (with { tree op_type = TREE_TYPE (@5); }
+   (if (inverse_conditions_p (@0, @2)
+        && element_precision (type) == element_precision (op_type))
+    (view_convert (cond_len_op @2 @3 @4 (view_convert:op_type @1) @6 @7))))))
+
+/* Same for ternary operations.  */
+(for cond_len_op (COND_LEN_TERNARY)
+ (simplify
+  (vec_cond @0 (view_convert? (cond_len_op @0 @1 @2 @3 @4 @5 @6)) @7)
+  (with { tree op_type = TREE_TYPE (@4); }
+   (if (element_precision (type) == element_precision (op_type))
+    (view_convert (cond_len_op @0 @1 @2 @3 (view_convert:op_type @7) @5 @6)))))
+ (simplify
+  (vec_cond @0 @1 (view_convert? (cond_len_op @2 @3 @4 @5 @6 @7 @8)))
+  (with { tree op_type = TREE_TYPE (@6); }
+   (if (inverse_conditions_p (@0, @2)
+        && element_precision (type) == element_precision (op_type))
+    (view_convert (cond_len_op @2 @3 @4 @5 (view_convert:op_type @1) @7 @8))))))
+
 /* Detect simplication for a conditional reduction where
 
    a = mask1 ? b : 0
@@ -8846,8 +9696,50 @@ and,
 
    c = mask1 && mask2 ? d + b : d.  */
 (simplify
-  (IFN_COND_ADD @0 @1 (vec_cond @2 @3 integer_zerop) @1)
-   (IFN_COND_ADD (bit_and @0 @2) @1 @3 @1))
+  (IFN_COND_ADD @0 @1 (vec_cond @2 @3 zerop@4) @1)
+   (if (ANY_INTEGRAL_TYPE_P (type)
+       || (FLOAT_TYPE_P (type)
+           && fold_real_zero_addition_p (type, NULL_TREE, @4, 0)))
+   (IFN_COND_ADD (bit_and @0 @2) @1 @3 @1)))
+
+/* Detect simplication for a conditional length reduction where
+
+   a = mask ? b : 0
+   c = i < len + bias ? d + a : d
+
+   is turned into
+
+   c = mask && i < len + bias ? d + b : d.  */
+(simplify
+  (IFN_COND_LEN_ADD integer_truep @0 (vec_cond @1 @2 zerop@5) @0 @3 @4)
+   (if (ANY_INTEGRAL_TYPE_P (type)
+       || (FLOAT_TYPE_P (type)
+           && fold_real_zero_addition_p (type, NULL_TREE, @5, 0)))
+    (IFN_COND_LEN_ADD @1 @0 @2 @0 @3 @4)))
+
+/* Detect simplification for vector condition folding where
+
+  c = mask1 ? (masked_op mask2 a b els) : els
+
+  into
+
+  c = masked_op (mask1 & mask2) a b els
+
+  where the operation can be partially applied to one operand. */
+
+(for cond_op (COND_BINARY)
+ (simplify
+  (vec_cond @0
+   (cond_op:s @1 @2 @3 @4) @4)
+  (cond_op (bit_and @1 @0) @2 @3 @4)))
+
+/* And same for ternary expressions.  */
+
+(for cond_op (COND_TERNARY)
+ (simplify
+  (vec_cond @0
+   (cond_op:s @1 @2 @3 @4 @5) @5)
+  (cond_op (bit_and @1 @0) @2 @3 @4 @5)))
 
 /* For pointers @0 and @2 and nonnegative constant offset @1, look for
    expressions like:
@@ -9200,19 +10092,21 @@ and,
      d = VEC_PERM_EXPR <a, b, NEW_VCST>;  */
 
 (simplify
- (vec_perm (vec_perm@0 @1 @2 VECTOR_CST@3) @0 VECTOR_CST@4)
+ (vec_perm (view_convert?@0 (vec_perm@1 @2 @3 VECTOR_CST@4)) @0 VECTOR_CST@5)
  (if (TYPE_VECTOR_SUBPARTS (type).is_constant ())
   (with
    {
      machine_mode result_mode = TYPE_MODE (type);
-     machine_mode op_mode = TYPE_MODE (TREE_TYPE (@1));
+     machine_mode op_mode = TYPE_MODE (TREE_TYPE (@2));
      int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
      vec_perm_builder builder0;
      vec_perm_builder builder1;
      vec_perm_builder builder2 (nelts, nelts, 1);
    }
-   (if (tree_to_vec_perm_builder (&builder0, @3)
-       && tree_to_vec_perm_builder (&builder1, @4))
+   (if (tree_to_vec_perm_builder (&builder0, @4)
+       && tree_to_vec_perm_builder (&builder1, @5)
+       && TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))
+          == TYPE_SIZE (TREE_TYPE (TREE_TYPE (@1))))
     (with
      {
        vec_perm_indices sel0 (builder0, 2, nelts);
@@ -9234,10 +10128,10 @@ and,
               ? (!can_vec_perm_const_p (result_mode, op_mode, sel0, false)
                  || !can_vec_perm_const_p (result_mode, op_mode, sel1, false))
               : !can_vec_perm_const_p (result_mode, op_mode, sel1, false)))
-        op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2);
+        op0 = vec_perm_indices_to_tree (TREE_TYPE (@5), sel2);
      }
      (if (op0)
-      (vec_perm @1 @2 { op0; })))))))
+      (view_convert (vec_perm @2 @3 { op0; }))))))))
 
 /* Merge
      c = VEC_PERM_EXPR <a, b, VCST0>;