]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gimple-fold: Handle bitfields in fold_const_aggregate_ref_1 [PR93121]
authorJakub Jelinek <jakub@redhat.com>
Mon, 20 Jul 2020 08:24:19 +0000 (10:24 +0200)
committerJakub Jelinek <jakub@redhat.com>
Mon, 20 Jul 2020 08:24:19 +0000 (10:24 +0200)
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.

gcc/gimple-fold.c
gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c [new file with mode: 0644]

index dfda6db5e9670166fadd3426c69ab4cce9fb7823..81c77f7e8b458cf484f434e1ea65d2b5299d34a5 100644 (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:
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c
new file mode 100644 (file)
index 0000000..323dca6
--- /dev/null
@@ -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 } } } */