Hi!
When working on __builtin_bit_cast that needs to handle bitfields too,
I've made the following change to handle at least some bitfields in
fold_const_aggregate_ref_1 (those that have integral representative).
It already handles some, but only those that start and end at byte
boundaries.
Bootstrapped/regtested on {x86_64,i686,powerpc64{,le}}-linux, ok for trunk?
2020-07-18 Jakub Jelinek <[email protected]>
PR libstdc++/93121
* gimple-fold.c (fold_const_aggregate_ref_1): For COMPONENT_REF
of a bitfield not aligned on byte boundaries try to
fold_ctor_reference DECL_BIT_FIELD_REPRESENTATIVE if any and
adjust it depending on endianity.
* gcc.dg/tree-ssa/pr93121-2.c: New test.
--- gcc/gimple-fold.c.jj 2020-07-13 19:09:33.218871556 +0200
+++ gcc/gimple-fold.c 2020-07-17 19:17:59.694537680 +0200
@@ -7189,8 +7189,64 @@ fold_const_aggregate_ref_1 (tree t, tree
if (maybe_lt (offset, 0))
return NULL_TREE;
- return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size,
- base);
+ tem = fold_ctor_reference (TREE_TYPE (t), ctor, offset, size, base);
+ if (tem)
+ return tem;
+
+ /* For bit field reads try to read the representative and
+ adjust. */
+ if (TREE_CODE (t) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (t, 1))
+ && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)))
+ {
+ HOST_WIDE_INT csize, coffset;
+ tree field = TREE_OPERAND (t, 1);
+ tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (repr))
+ && size.is_constant (&csize)
+ && offset.is_constant (&coffset)
+ && (coffset % BITS_PER_UNIT != 0
+ || csize % BITS_PER_UNIT != 0)
+ && !reverse
+ && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN)
+ {
+ poly_int64 bitoffset;
+ poly_uint64 field_offset, repr_offset;
+ if (poly_int_tree_p (DECL_FIELD_OFFSET (field), &field_offset)
+ && poly_int_tree_p (DECL_FIELD_OFFSET (repr), &repr_offset))
+ bitoffset = (field_offset - repr_offset) * BITS_PER_UNIT;
+ else
+ bitoffset = 0;
+ bitoffset += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field))
+ - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (repr)));
+ HOST_WIDE_INT bitoff;
+ int diff = (TYPE_PRECISION (TREE_TYPE (repr))
+ - TYPE_PRECISION (TREE_TYPE (field)));
+ if (bitoffset.is_constant (&bitoff)
+ && bitoff >= 0
+ && bitoff <= diff)
+ {
+ offset -= bitoff;
+ size = tree_to_uhwi (DECL_SIZE (repr));
+
+ tem = fold_ctor_reference (TREE_TYPE (repr), ctor, offset,
+ size, base);
+ if (tem && TREE_CODE (tem) == INTEGER_CST)
+ {
+ if (!BYTES_BIG_ENDIAN)
+ tem = wide_int_to_tree (TREE_TYPE (field),
+ wi::lrshift (wi::to_wide (tem),
+ bitoff));
+ else
+ tem = wide_int_to_tree (TREE_TYPE (field),
+ wi::lrshift (wi::to_wide (tem),
+ diff - bitoff));
+ return tem;
+ }
+ }
+ }
+ }
+ break;
case REALPART_EXPR:
case IMAGPART_EXPR:
--- gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c.jj 2020-07-17
19:47:31.842426096 +0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c 2020-07-17 19:48:24.551649910
+0200
@@ -0,0 +1,22 @@
+/* PR libstdc++/93121 */
+/* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+union U { int a[3]; struct S { int d; int a : 3; int b : 24; int c : 5; int e;
} b; };
+const union U u = { .a = { 0x7efa3412, 0x5a876543, 0x1eeffeed } };
+int a, b, c;
+
+void
+foo ()
+{
+ a = u.b.a;
+ b = u.b.b;
+ c = u.b.c;
+}
+
+/* { dg-final { scan-tree-dump-times "a = 3;" 1 "optimized" { target le } } }
*/
+/* { dg-final { scan-tree-dump-times "b = 5303464;" 1 "optimized" { target le
} } } */
+/* { dg-final { scan-tree-dump-times "c = 11;" 1 "optimized" { target le } } }
*/
+/* { dg-final { scan-tree-dump-times "a = 2;" 1 "optimized" { target be } } }
*/
+/* { dg-final { scan-tree-dump-times "b = -2868438;" 1 "optimized" { target be
} } } */
+/* { dg-final { scan-tree-dump-times "c = 3;" 1 "optimized" { target be } } }
*/
Jakub