Hi all, sending a v2 of [0], adding support for converts of subexpressions in the extract-bitfield-and-shift folding pattern. This is a complete rework so I briefly considered making this a brand new patch instead.
Changes since v1: - Expand commit message to better explain the transformation. - Perform all operations in unsigned version of `type`, then convert back to signed if needed. - Remove the `type_has_mode_precision_p` check. - Replace the `TYPE_UNSIGNED_P` requirement for `type` and the type of @0 with one on the type of @4. - Add more tests involving signed types. OK for trunk? Thanks, Artemiy [0] https://gcc.gnu.org/pipermail/gcc-patches/2026-September/732547.html ---------- 8< ---------- This patch extends the extract-bitfield-and-shift pattern by allowing (a) X to be a result of an integer conversion as long as the target type is unsigned, (b) the result of the left-shift to be (sometimes as a result of integer promotions) converted to another integer type, and (c) the resulting type of the whole expression to be signed. Firstly, we prepare the new mask C2' from the original mask C2 similar to before, by clearing the first N bits, where N is the difference between the precision of the converted-to type and C1. For instance, for x of type uint32_t in the expression (uint16_t) ((((uint8_t) x >> 5) & 0xFFFF) << 10), C2' = 0x7 is obtained from C2 = 0xFFFF by trimming down to precision (uint8_t) - 5 = 3 bits. This allows us to zero-extend the result of (X >> C1) to the unsigned version of the resulting type of the expression and perform the rest of the operations (AND and SHIFT) in that type. In case the original result type was signed (case (c) above), we convert back to that as the last step. 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 | 27 ++++--- .../tree-ssa/match-bit-extract-shift-2.c | 75 +++++++++++++++++++ 2 files changed, 91 insertions(+), 11 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..2cb72e04875 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1530,24 +1530,29 @@ 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) - (if (TYPE_UNSIGNED (TREE_TYPE (@0)) - && type_has_mode_precision_p (TREE_TYPE (@0))) - (with { int prec = TYPE_PRECISION (TREE_TYPE (@0)); } + (lshift (bit_and (convert1? (rshift (convert2?@4 @0) INTEGER_CST@1)) + INTEGER_CST@2) INTEGER_CST@3) + (if (TYPE_UNSIGNED (TREE_TYPE (@4))) + (with + { + int prec = TYPE_PRECISION (TREE_TYPE (@4)); + tree utype = unsigned_type_for (type); + } (if (wi::ltu_p (wi::to_wide (@1), prec) - && wi::ltu_p (wi::to_wide (@3), prec)) + && wi::ltu_p (wi::to_wide (@3), TYPE_PRECISION (utype))) (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, utype, @2, + wide_int_to_tree (TREE_TYPE (@2), mask_lz)); + tree mask_shifted = fold_build2 (LSHIFT_EXPR, utype, 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; }))))))) + (convert (bit_and (lshift (convert:utype @0) (minus @3 @1)) + { mask_shifted; })) + (convert (bit_and (rshift (convert:utype @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..c61856d916d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/match-bit-extract-shift-2.c @@ -0,0 +1,75 @@ +/* { 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); +} + +uint32_t f6 (uint64_t x) +{ + return (uint16_t) ((((uint8_t) x >> 5ULL) & -0x3) << 10U); +} + +int32_t fs (uint64_t x) +{ + return (int32_t) (((x >> 5UL) & -0x5) << 1ULL); +} + +int32_t f2s (uint64_t x) +{ + return (int32_t) ((((uint16_t)x >> 5ULL) & -0x5) << 1UL); +} + +int32_t f3s (uint64_t x) +{ + return (int16_t) ((((uint8_t) x >> 5ULL) & -0x5) << 1U); +} + +int32_t f4s (uint64_t x) +{ + return (int8_t) ((((uint16_t)x >> 5U) & -0x5) << 1ULL); +} + +int32_t f5s (uint64_t x) +{ + return (int16_t) ((((uint8_t) x >> 5) & -0x5) << 1ULL); +} + +int32_t f6s (uint64_t x) +{ + return (int16_t) ((((uint8_t) x >> 5ULL) & 0x3) << 1U); +} + +/* { dg-final { scan-tree-dump-times "<< 5" 4 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "& 5120" 4 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "return 0" 2 forwprop1 } } */ + +/* { dg-final { scan-tree-dump-times ">> 4" 6 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "& 4294967286" 1 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "& 4086" 1 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "& 6" 3 forwprop1 } } */ +/* { dg-final { scan-tree-dump-times "& 246" 1 forwprop1 } } */ -- 2.43.0
