This patch extends the pattern by allowing (a) X to be a result of an
integer conversion as long as both source and target type are unsigned,
and (b) the result of the left-shift to be (sometimes as a result of
integer promotions) converted to another integer type. This is achieved
by changing all operations to be performed in the resulting type of the
expression. The patch was partially inspired by the testcase provided in
PR127552.
Some new tests involving combinations of casts have been added as
match-bit-extract-shift-2.c.
Bootstrapped and regtested on aarch64-linux-gnu and x86_64-linux-gnu.
gcc/ChangeLog:
* match.pd: Support conversions in ((X >> C1) & C2) << C3.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/match-bit-extract-shift-2.c: New test.
---
gcc/match.pd | 19 ++++++-----
.../tree-ssa/match-bit-extract-shift-2.c | 34 +++++++++++++++++++
2 files changed, 44 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/match-bit-extract-shift-2.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 688357f0ecd..eb21ed8ad96 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1530,24 +1530,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Fold (((X >> C1) & C2) << C3) into (X >>/<< |C1 - C3|) & (C2' << C3),
where C2' is obtained from C2 by clearing all but the rightmost C1 bits. */
(simplify
- (lshift (bit_and (rshift @0 INTEGER_CST@1) INTEGER_CST@2) INTEGER_CST@3)
+ (lshift (bit_and (convert1? (rshift (convert2?@5 @0) INTEGER_CST@1))
+ INTEGER_CST@2) INTEGER_CST@3)
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
+ && TYPE_UNSIGNED (TREE_TYPE (@5))
&& type_has_mode_precision_p (TREE_TYPE (@0)))
- (with { int prec = TYPE_PRECISION (TREE_TYPE (@0)); }
- (if (wi::ltu_p (wi::to_wide (@1), prec)
+ (with { int prec = TYPE_PRECISION (type); }
+ (if (wi::ltu_p (wi::to_wide (@1), TYPE_PRECISION (TREE_TYPE (@0)))
&& wi::ltu_p (wi::to_wide (@3), prec))
(with
{
/* Clear the first PREC - @1 bits of the mask, then shift it. */
wide_int mask_lz = wi::mask (prec - tree_to_uhwi (@1), false, prec);
- tree mask = fold_build2 (BIT_AND_EXPR, TREE_TYPE (@0),
- @2, wide_int_to_tree (TREE_TYPE (@0), mask_lz));
- tree mask_shifted = fold_build2 (LSHIFT_EXPR, TREE_TYPE (@0),
- mask, @3);
+ tree mask = fold_build2 (BIT_AND_EXPR, type, @2,
+ wide_int_to_tree (TREE_TYPE (@2), mask_lz));
+ tree mask_shifted = fold_build2 (LSHIFT_EXPR, type, mask, @3);
}
(if (wi::to_widest (@1) <= wi::to_widest (@3))
- (bit_and (lshift @0 (minus @3 @1)) { mask_shifted; })
- (bit_and (rshift @0 (minus @1 @3)) { mask_shifted; })))))))
+ (bit_and (lshift (convert @0) (minus @3 @1)) { mask_shifted; })
+ (bit_and (rshift (convert @0) (minus @1 @3)) { mask_shifted; })))))))
/* Fold ((type)(a<0)) << SIGNBITOFA into ((type)a) & signbit. */
(simplify
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/match-bit-extract-shift-2.c
b/gcc/testsuite/gcc.dg/tree-ssa/match-bit-extract-shift-2.c
new file mode 100644
index 00000000000..1b022ecb83a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/match-bit-extract-shift-2.c
@@ -0,0 +1,34 @@
+/* { dg-require-effective-target stdint_types } */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop1" } */
+
+#include <stdint.h>
+
+uint32_t f (uint64_t x)
+{
+ return ((x >> 5UL) & 0x5) << 10ULL;
+}
+
+uint32_t f2 (uint64_t x)
+{
+ return (((uint16_t)x >> 5ULL) & 0x5) << 10UL;
+}
+
+uint32_t f3 (uint64_t x)
+{
+ return (uint16_t) ((((uint8_t) x >> 5ULL) & 0x5) << 10U);
+}
+
+uint32_t f4 (uint64_t x)
+{
+ return (uint8_t) ((((uint16_t)x >> 5U) & 0x5) << 10ULL);
+}
+
+uint32_t f5 (uint64_t x)
+{
+ return (uint16_t) ((((uint8_t) x >> 10) & 0x5) << 5ULL);
+}
+
+/* { dg-final { scan-tree-dump-times "<< 5" 3 forwprop1 } } */
+/* { dg-final { scan-tree-dump-times "& 5120" 3 forwprop1 } } */
+/* { dg-final { scan-tree-dump-times "return 0" 2 forwprop1 } } */
--
2.43.0