diff --git a/gcc/builtins.c b/gcc/builtins.c
index 855ad1e..86dfeae 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -14831,3 +14831,42 @@ builtin_fnspec (tree callee)
 	return "";
     }
 }
+
+/* Return the precision (in bits) of a built-in function.
+   Returns zero for unrecognized built-in functions.  */
+
+unsigned int
+get_builtin_precision (enum built_in_function fn)
+{
+  switch (fn)
+    {
+      case BUILT_IN_BSWAP16:
+	return 16;
+      case BUILT_IN_BSWAP32:
+	return 32;
+      case BUILT_IN_BSWAP64:
+	return 64;
+      case BUILT_IN_BSWAP128:
+	return 128;
+      case BUILT_IN_CLZ:
+      case BUILT_IN_CTZ:
+      case BUILT_IN_FFS:
+      case BUILT_IN_PARITY:
+      case BUILT_IN_POPCOUNT:
+	return TYPE_PRECISION (integer_type_node);
+      case BUILT_IN_CLZL:
+      case BUILT_IN_CTZL:
+      case BUILT_IN_FFSL:
+      case BUILT_IN_PARITYL:
+      case BUILT_IN_POPCOUNTL:
+	return TYPE_PRECISION (long_integer_type_node);
+      case BUILT_IN_CLZLL:
+      case BUILT_IN_CTZLL:
+      case BUILT_IN_FFSLL:
+      case BUILT_IN_PARITYLL:
+      case BUILT_IN_POPCOUNTLL:
+	return TYPE_PRECISION (long_long_integer_type_node);
+      default:
+	return 0;
+    }
+}
diff --git a/gcc/builtins.h b/gcc/builtins.h
index e71f40c..cfb48f0 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -124,6 +124,7 @@ extern void expand_ifn_atomic_bit_test_and (gcall *);
 extern void expand_ifn_atomic_compare_exchange (gcall *);
 extern rtx expand_builtin (tree, rtx, rtx, machine_mode, int);
 extern enum built_in_function builtin_mathfn_code (const_tree);
+extern unsigned int get_builtin_precision (enum built_in_function);
 extern tree fold_builtin_expect (location_t, tree, tree, tree, tree);
 extern bool avoid_folding_inline_builtin (tree);
 extern tree fold_call_expr (location_t, tree, bool);
diff --git a/gcc/match.pd b/gcc/match.pd
index 39fb57e..d5a7fbf 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3610,7 +3610,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (complex (convert:itype @0) (negate (convert:itype @1)))))
 
 /* BSWAP simplifications, transforms checked by gcc.dg/builtin-bswap-8.c.  */
-(for bswap (BUILT_IN_BSWAP16 BUILT_IN_BSWAP32 BUILT_IN_BSWAP64)
+(for bswap (BUILT_IN_BSWAP16 BUILT_IN_BSWAP32
+	    BUILT_IN_BSWAP64 BUILT_IN_BSWAP128)
  (simplify
   (bswap (bswap @0))
   @0)
@@ -3620,8 +3621,69 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (for bitop (bit_xor bit_ior bit_and)
   (simplify
    (bswap (bitop:c (bswap @0) @1))
-   (bitop @0 (bswap @1)))))
-
+   (bitop @0 (bswap @1))))
+ /* (bswap(x) >> C1) & C2 can sometimes be simplified to (x >> C3) & C2.  */
+ (simplify
+  (bit_and (convert1? (rshift@0 (convert2? (bswap @1)) INTEGER_CST@2))
+	   INTEGER_CST@3)
+   (if (tree_fits_uhwi_p (@2)
+	&& tree_fits_uhwi_p (@3))
+    (with
+     {
+      enum built_in_function fncode = as_builtin_fn (bswap);
+      unsigned HOST_WIDE_INT prec = get_builtin_precision (fncode);
+      unsigned HOST_WIDE_INT bits = tree_to_uhwi (@2);
+      unsigned HOST_WIDE_INT mask = tree_to_uhwi (@3);
+      unsigned HOST_WIDE_INT lo = bits & 7;
+      unsigned HOST_WIDE_INT hi = bits - lo;
+     }
+     (if (bits < prec
+	  && mask < (256u>>lo)
+	  && bits < TYPE_PRECISION (TREE_TYPE(@0)))
+      (with { unsigned HOST_WIDE_INT ns = (prec - (hi + 8)) + lo; }
+       (if (ns == 0)
+	(bit_and (convert @1) @3)
+	(with
+	 {
+	  tree utype = unsigned_type_for (TREE_TYPE (@1));
+	  tree nst = build_int_cst (integer_type_node, ns);
+	 }
+	 (bit_and (convert (rshift:utype (convert:utype @1) {nst;})) @3))))))))
+ /* bswap(x) >> C1 can sometimes be simplified to (T)x >> C2.  */
+ (simplify
+  (rshift (convert? (bswap @0)) INTEGER_CST@1)
+   (if (tree_fits_uhwi_p (@1))
+    (with
+     {
+      enum built_in_function fncode = as_builtin_fn (bswap);
+      unsigned HOST_WIDE_INT prec = get_builtin_precision (fncode);
+      unsigned HOST_WIDE_INT bits = tree_to_uhwi (@1);
+     }
+     (if (bits + 8 == prec)
+      (if (TYPE_UNSIGNED (type))
+       (convert (convert:unsigned_char_type_node @0))
+       (convert (convert:signed_char_type_node @0)))
+      (if (bits < prec && bits + 8 > prec)
+       (with 
+	{
+	 tree nst = build_int_cst (integer_type_node, bits & 7);
+	 tree bt = TYPE_UNSIGNED (type) ? unsigned_char_type_node
+					: signed_char_type_node;
+	}
+	(convert (rshift:bt (convert:bt @0) {nst;}))))))))
+ /* bswap(x) & C1 can sometimes be simplified to (x >> C2) & C1.  */
+ (simplify
+  (bit_and (convert? (bswap @0)) INTEGER_CST@1)
+   (if (tree_fits_uhwi_p (@1)
+	&& tree_to_uhwi (@1) < 256)
+    (with
+     {
+      enum built_in_function fncode = as_builtin_fn (bswap);
+      unsigned HOST_WIDE_INT prec = get_builtin_precision (fncode);
+      tree utype = unsigned_type_for (TREE_TYPE (@0));
+      tree nst = build_int_cst (integer_type_node, prec - 8);
+     }
+     (bit_and (convert (rshift:utype (convert:utype @0) {nst;})) @1)))))
 
 /* Combine COND_EXPRs and VEC_COND_EXPRs.  */
 
