]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/match.pd
c: Implement C2Y complex increment/decrement support
[thirdparty/gcc.git] / gcc / match.pd
index 5928acbb14e2a18addff38000bf30dd273d4b1a6..3204cf4153878adfec53d47f699df59de630de1b 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>
 
@@ -95,14 +95,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   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
@@ -110,7 +110,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   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_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)
 
@@ -167,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)
@@ -175,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))
@@ -182,6 +183,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (convert (cmp@0 @1 @2))
    (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))))
 )
+/* `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))
+
+#if GIMPLE
+(match (maybe_truncate @0)
+ (convert @0)
+ (if (INTEGRAL_TYPE_P (type)
+      && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))))
 #endif
 
 /* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x>
@@ -447,8 +470,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)
@@ -554,7 +578,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)
@@ -563,10 +588,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.  */
@@ -614,7 +640,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   if (TYPE_OVERFLOW_UNDEFINED (type))
     {
 #if GIMPLE
-      value_range vr0;
+      int_range_max vr0;
       if (ovf1 == wi::OVF_NONE && ovf2 == wi::OVF_NONE
          && get_global_range_query ()->range_of_expr (vr0, @4)
          && !vr0.varying_p () && !vr0.undefined_p ())
@@ -655,7 +681,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   if (TYPE_OVERFLOW_UNDEFINED (type))
     {
 #if GIMPLE
-      value_range vr0;
+      int_range_max vr0;
       if (ovf1 == wi::OVF_NONE && ovf2 == wi::OVF_NONE
          && get_global_range_query ()->range_of_expr (vr0, @0)
          && !vr0.varying_p () && !vr0.undefined_p ())
@@ -930,20 +956,52 @@ 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;}
+    (with {int_range_max vr0, vr1;}
      (if (INTEGRAL_TYPE_P (type)
          && 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))
       @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 {int_range_max 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 {int_range_max 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
    ))))
 
@@ -952,7 +1010,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* Simplify (X + M*N) / N -> X / N + M.  */
  (simplify
   (div (plus:c@4 @0 (mult:c@3 @1 @2)) @2)
-  (with {value_range vr0, vr1, vr2, vr3, vr4;}
+  (with {int_range_max vr0, vr1, vr2, vr3, vr4;}
   (if (INTEGRAL_TYPE_P (type)
        && get_range_query (cfun)->range_of_expr (vr1, @1)
        && get_range_query (cfun)->range_of_expr (vr2, @2)
@@ -973,7 +1031,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  /* Simplify (X - M*N) / N -> X / N - M.  */
  (simplify
   (div (minus@4 @0 (mult:c@3 @1 @2)) @2)
-  (with {value_range vr0, vr1, vr2, vr3, vr4;}
+  (with {int_range_max vr0, vr1, vr2, vr3, vr4;}
   (if (INTEGRAL_TYPE_P (type)
        && get_range_query (cfun)->range_of_expr (vr1, @1)
        && get_range_query (cfun)->range_of_expr (vr2, @2)
@@ -1006,7 +1064,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
                           : wi::div_trunc (v, n, TYPE_SIGN (type)))
 #define exact_mod(v) (shift ? wi::ctz (v) >= n.to_shwi () \
                            : wi::multiple_of_p (v, n, TYPE_SIGN (type)))
-      value_range vr0, vr1, vr3;
+      int_range_max vr0, vr1, vr3;
     }
     (if (INTEGRAL_TYPE_P (type)
         && get_range_query (cfun)->range_of_expr (vr0, @0))
@@ -1033,12 +1091,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)
@@ -1118,18 +1180,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (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)))
-   (abs @0))))
+   (abs @0)
+#if GIMPLE
+   (if (!direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+                                        OPTIMIZE_FOR_BOTH))
+    (negate (abs @0)))
+#endif
+   )))
 
-/* Transform fneg (fabs (X)) -> copysign (X, -1).  */
+#if GIMPLE
+/* Transform fneg (fabs (X)) -> copysign (X, -1) as the canonical
+   representation if the target supports the copysign optab.  */
 (simplify
  (negate (abs @0))
- (IFN_COPYSIGN @0 { build_minus_one_cst (type); }))
-
+ (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
@@ -1162,6 +1236,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
@@ -1264,7 +1349,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))
@@ -1529,7 +1614,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))
@@ -2243,6 +2328,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 }.  */
@@ -2324,12 +2412,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.
@@ -2596,6 +2686,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)
@@ -2775,7 +2874,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    { constant_boolean_node (cmp == NE_EXPR, type); })))
 
 /* ((X inner_op C0) outer_op C1)
-   With X being a tree where value_range has reasoned certain bits to always be
+   With X being a tree where range has reasoned certain bits to always be
    zero throughout its computed value range,
    inner_op = {|,^}, outer_op = {|,^} and inner_op != outer_op
    where zero_mask has 1's for all bits that are sure to be 0 in
@@ -2963,6 +3062,116 @@ 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 */
+/* SAT_ADD = usadd_left_part_1 | usadd_right_part_1, aka:
+   SAT_ADD = (X + Y) | -((X + Y) < X)  */
+(match (usadd_left_part_1 @0 @1)
+ (plus:c @0 @1)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* SAT_ADD = usadd_left_part_2 | usadd_right_part_2, aka:
+   SAT_ADD = REALPART_EXPR <.ADD_OVERFLOW> | (IMAGPART_EXPR <.ADD_OVERFLOW> != 0) */
+(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))))
+
+/* SAT_ADD = usadd_left_part_1 | usadd_right_part_1, aka:
+   SAT_ADD = (X + Y) | -((type)(X + Y) < X)  */
+(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))))
+
+/* SAT_ADD = usadd_left_part_1 | usadd_right_part_1, aka:
+   SAT_ADD = (X + Y) | -(X > (X + Y))  */
+(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))))
+
+/* SAT_ADD = usadd_left_part_2 | usadd_right_part_2, aka:
+   SAT_ADD = REALPART_EXPR <.ADD_OVERFLOW> | (IMAGPART_EXPR <.ADD_OVERFLOW> != 0) */
+(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))))
+
+/* SAT_ADD = usadd_left_part_2 | usadd_right_part_2, aka:
+   SAT_ADD = REALPART_EXPR <.ADD_OVERFLOW> | -IMAGPART_EXPR <.ADD_OVERFLOW> */
+(match (usadd_right_part_2 @0 @1)
+ (negate (imagpart (IFN_ADD_OVERFLOW:c @0 @1)))
+ (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):
+   SAT_ADD = REALPART_EXPR <.ADD_OVERFLOW> | -IMAGPART_EXPR <.ADD_OVERFLOW> or
+   SAT_ADD = REALPART_EXPR <.ADD_OVERFLOW> | (IMAGPART_EXPR <.ADD_OVERFLOW> != 0) */
+(match (unsigned_integer_sat_add @0 @1)
+ (bit_ior:c (usadd_left_part_2 @0 @1) (usadd_right_part_2 @0 @1)))
+
+/* Unsigned saturation add, case 3 (branch with ge):
+   SAT_U_ADD = (X + Y) >= x ? (X + Y) : -1.  */
+(match (unsigned_integer_sat_add @0 @1)
+ (cond^ (ge (usadd_left_part_1@2 @0 @1) @0) @2 integer_minus_onep))
+
+/* Unsigned saturation add, case 4 (branch with lt):
+   SAT_U_ADD = (X + Y) < x ? -1 : (X + Y).  */
+(match (unsigned_integer_sat_add @0 @1)
+ (cond^ (lt (usadd_left_part_1@2 @0 @1) @0) integer_minus_onep @2))
+
+/* Unsigned saturation add, case 5 (branch with eq .ADD_OVERFLOW):
+   SAT_U_ADD = REALPART_EXPR <.ADD_OVERFLOW> == 0 ? .ADD_OVERFLOW : -1.  */
+(match (unsigned_integer_sat_add @0 @1)
+ (cond^ (eq (imagpart (IFN_ADD_OVERFLOW:c @0 @1)) integer_zerop)
+  (usadd_left_part_2 @0 @1) integer_minus_onep))
+
+/* Unsigned saturation add, case 6 (branch with ne .ADD_OVERFLOW):
+   SAT_U_ADD = REALPART_EXPR <.ADD_OVERFLOW> != 0 ? -1 : .ADD_OVERFLOW.  */
+(match (unsigned_integer_sat_add @0 @1)
+ (cond^ (ne (imagpart (IFN_ADD_OVERFLOW:c @0 @1)) integer_zerop)
+  integer_minus_onep (usadd_left_part_2 @0 @1)))
+
+/* Unsigned saturation sub, case 1 (branch with gt):
+   SAT_U_SUB = X > Y ? X - Y : 0  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (gt @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* Unsigned saturation sub, case 2 (branch with ge):
+   SAT_U_SUB = X >= Y ? X - Y : 0.  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (cond (ge @0 @1) (minus @0 @1) integer_zerop)
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* Unsigned saturation sub, case 3 (branchless with gt):
+   SAT_U_SUB = (X - Y) * (X > Y).  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (mult:c (minus @0 @1) (convert (gt @0 @1)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
+/* Unsigned saturation sub, case 4 (branchless with ge):
+   SAT_U_SUB = (X - Y) * (X >= Y).  */
+(match (unsigned_integer_sat_sub @0 @1)
+ (mult:c (minus @0 @1) (convert (ge @0 @1)))
+ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)
+      && types_match (type, @0, @1))))
+
 /* x >  y  &&  x != XXX_MIN  -->  x > y
    x >  y  &&  x == XXX_MIN  -->  false . */
 (for eqne (eq ne)
@@ -3316,6 +3525,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))
 
@@ -3525,7 +3750,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
          = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
                            TYPE_SIGN (inner_type));
 
-       value_range vr;
+       int_range_max vr;
        if (get_global_range_query ()->range_of_expr (vr, @0)
            && !vr.varying_p () && !vr.undefined_p ())
           {
@@ -4134,8 +4359,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)
@@ -4193,6 +4419,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (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)
@@ -4690,11 +4934,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:
@@ -4758,6 +5005,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))
@@ -5062,15 +5310,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)
@@ -5174,6 +5443,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)
@@ -5305,7 +5596,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && (wi::to_widest (@2) + 1 == wi::to_widest (@3)
            || wi::to_widest (@2) == wi::to_widest (@3) + 1))
    (with {
-     value_range r;
+     int_range_max r;
      get_range_query (cfun)->range_of_expr (r, @0);
      if (r.undefined_p ())
        r.set_varying (TREE_TYPE (@0));
@@ -5577,6 +5868,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)
@@ -5605,7 +5917,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))
 )
@@ -5693,6 +6005,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (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
@@ -5730,7 +6057,10 @@ 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.
 
@@ -6624,19 +6954,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)
@@ -6664,11 +6994,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))))))))
 
 
@@ -6929,6 +7260,7 @@ 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 || TYPE_PRECISION (type) == 1))
    (if ((!TYPE_UNSIGNED (type) && TREE_CODE (type) == BOOLEAN_TYPE)
@@ -8285,7 +8617,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)
@@ -8449,9 +8783,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
@@ -8536,31 +8874,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)
@@ -8585,22 +8926,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); })))))))
@@ -8608,19 +8941,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)); })
@@ -8628,13 +9010,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)
@@ -8698,6 +9129,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
@@ -8734,7 +9209,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)
@@ -8757,13 +9287,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)
@@ -8771,13 +9326,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.  */
@@ -8893,8 +9473,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)
@@ -8941,6 +9520,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:
@@ -8959,13 +9582,13 @@ 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)
@@ -8974,13 +9597,13 @@ 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 @4 @5))))
+     (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) @2 @1 @4 @5)))))
+     (cond_op (bit_not @0) (view_convert @2) @1 @4 @5)))))
 
 /* `(a ? -1 : 0) ^ b` can be converted into a conditional not.  */
 (simplify
@@ -9172,18 +9795,18 @@ and,
 
 /* Detect simplification for vector condition folding where
 
-  c = mask1 ? (masked_op mask2 a b) : b
+  c = mask1 ? (masked_op mask2 a b els) : els
 
   into
 
-  c = masked_op (mask1 & mask2) a b
+  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) @3)
+   (cond_op:s @1 @2 @3 @4) @4)
   (cond_op (bit_and @1 @0) @2 @3 @4)))
 
 /* And same for ternary expressions.  */
@@ -9191,7 +9814,7 @@ and,
 (for cond_op (COND_TERNARY)
  (simplify
   (vec_cond @0
-   (cond_op:s @1 @2 @3 @4 @5) @4)
+   (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
@@ -9545,19 +10168,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);
@@ -9579,10 +10204,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>;