gimple-fold: Handle bitfields in fold_const_aggregate_ref_1 [PR93121]

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.

2020-07-20  Jakub Jelinek  <jakub@redhat.com>

	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.
This commit is contained in:
Jakub Jelinek 2020-07-20 10:24:19 +02:00
parent 83b171655d
commit e4f1cbc35b
2 changed files with 80 additions and 2 deletions

View File

@ -7189,8 +7189,64 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (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:

View File

@ -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 } } } */