diff --git a/gcc/match.pd b/gcc/match.pd
index 59791f44851230409cad09a0bc9e08e8612cae7e..b30de36e83623a158badd14160e262ca4211ceae 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -8672,6 +8672,50 @@ 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
@@ -8742,6 +8786,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
@@ -8780,6 +8868,54 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (bit_xor (PARITY:s @0) (PARITY:s @1))
   (PARITY (bit_xor @0 @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)
  (simplify
@@ -8987,8 +9123,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)
@@ -9035,6 +9170,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:
diff --git a/gcc/testsuite/gcc.dg/pr112566-1.c b/gcc/testsuite/gcc.dg/pr112566-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e7672ab5830a085bf96bdb5af94f3e59c2d15abf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr112566-1.c
@@ -0,0 +1,14 @@
+/* PR tree-optimization/112566 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-mbmi2 -mlzcnt -mpopcnt" { target i?86-*-* x86_64-*-* } } */
+/* { dg-final { scan-tree-dump-not "ll \\\(" "optimized" { target ia32 } } } */
+/* { dg-final { scan-tree-dump-not "\\\(long long (unsigned )?int\\\)" "optimized" { target ia32 } } } */
+
+int foo (unsigned int x) { return __builtin_ctzll (x); }
+int bar (unsigned int x) { return __builtin_popcountll (x); }
+int baz (unsigned int x) { return __builtin_parityll (x); }
+int qux (int x) { return __builtin_ffsll (x); }
+int corge (int x) { return __builtin_ctzll (x); }
+int garply (int x) { return __builtin_parityll (x); }
+int fred (unsigned int x) { return __builtin_ffsll (x); }
diff --git a/gcc/testsuite/gcc.dg/pr112566-2.c b/gcc/testsuite/gcc.dg/pr112566-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..acf9ab6d8b12623939b36ab6d65e101b35e2ba00
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr112566-2.c
@@ -0,0 +1,12 @@
+/* PR tree-optimization/112566 */
+/* { dg-do compile { target bitint575 } } */
+/* { dg-options "-O2 -fdump-tree-ccp2" } */
+/* { dg-final { scan-tree-dump-not "\\\((unsigned )?_BitInt\\\(512\\\)\\\)" "ccp2" } } */
+
+int foo (unsigned _BitInt(256) x) { return __builtin_ctzg ((unsigned _BitInt(512)) x); }
+int bar (unsigned _BitInt(256) x) { return __builtin_popcountg ((unsigned _BitInt(512)) x); }
+int baz (unsigned _BitInt(256) x) { return __builtin_parityg ((unsigned _BitInt(512)) x); }
+int qux (_BitInt(256) x) { return __builtin_ffsg ((_BitInt(512)) x); }
+int corge (_BitInt(256) x) { return __builtin_ctzg ((unsigned _BitInt(512)) x); }
+int garply (_BitInt(256) x) { return __builtin_parityg ((unsigned _BitInt(512)) x); }
+int fred (unsigned _BitInt(256) x) { return __builtin_ffsg ((_BitInt(512)) x); }
diff --git a/gcc/testsuite/gcc.target/i386/pr78057.c b/gcc/testsuite/gcc.target/i386/pr78057.c
index 493a53332bb1b96df66d70f3c5144597aa79fd40..b1f7a24e7acf34a0b8019f75ceb5db48b2f9d1c7 100644
--- a/gcc/testsuite/gcc.target/i386/pr78057.c
+++ b/gcc/testsuite/gcc.target/i386/pr78057.c
@@ -5,7 +5,7 @@
 extern void link_error (void);
 
 int
-foo (int x)
+foo (int x, long long y)
 {
   if (__builtin_ia32_tzcnt_u16 (16) != 4
       || __builtin_ia32_tzcnt_u16 (0) != 16
@@ -24,13 +24,14 @@ foo (int x)
      )
     link_error ();
   x += 2;
-  if (x == 0)
+  y += 2;
+  if (x == 0 || y == 0)
     return 5;
   return __builtin_ia32_tzcnt_u32 (x)
          + __builtin_ia32_lzcnt_u32 (x)
 #ifdef __x86_64__
-	 + __builtin_ia32_tzcnt_u64 (x)
-	 + __builtin_ia32_lzcnt_u64 (x)
+	 + __builtin_ia32_tzcnt_u64 (y)
+	 + __builtin_ia32_lzcnt_u64 (y)
 #endif
 	 ;
 }