fold-const: Fix native_encode_initializer bitfield handling [PR98199]
authorJakub Jelinek <jakub@redhat.com>
Wed, 9 Dec 2020 08:36:11 +0000 (09:36 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 9 Dec 2020 08:36:11 +0000 (09:36 +0100)
With the bit_cast changes, I have added support for bitfields which don't
have scalar representatives.  For bit_cast it works fine, as when mask
is non-NULL, off is asserted to be 0.  But when native_encode_initializer
is called e.g. from sccvn with off > 0 (i.e. we are interested in encoding
just a few bytes out of it somewhere from the middle or at the end), the
following computations are incorrect.
pos is a byte position from the start of the constructor, repr_size is the
size in bytes of the bit-field representative and len is the length
of the buffer.  If the buffer is offsetted by positive off, those numbers
are uncomparable though, we need to add off to len to make both
count bytes from the start of the constructor, and o is a utility temporary
set to off != -1 ? off : 0 (because off -1 also means start at offset 0
and just force special behavior).

2020-12-09  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/98199
* fold-const.c (native_encode_initializer): Fix handling bit-fields
when off > 0.

* gcc.c-torture/compile/pr98199.c: New test.

gcc/fold-const.c
gcc/testsuite/gcc.c-torture/compile/pr98199.c [new file with mode: 0644]

index 81467f19fdb203231fe45ff89c2cd57a1c1bfd25..b78f3ab145f776770ebf30f203bad7aa3299a1d9 100644 (file)
@@ -8320,11 +8320,11 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
                        return 0;
                      HOST_WIDE_INT repr_size = int_size_in_bytes (repr_type);
                      gcc_assert (repr_size > 0 && repr_size <= len);
-                     if (pos + repr_size <= len)
+                     if (pos + repr_size <= o + len)
                        rpos = pos;
                      else
                        {
-                         rpos = len - repr_size;
+                         rpos = o + len - repr_size;
                          gcc_assert (rpos <= pos);
                        }
                    }
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr98199.c b/gcc/testsuite/gcc.c-torture/compile/pr98199.c
new file mode 100644 (file)
index 0000000..b5c8d20
--- /dev/null
@@ -0,0 +1,7 @@
+/* PR tree-optimization/98199 */
+
+struct A { long a; short d; int c, f, e, g; };
+struct B { int a, i; short j; struct A k; signed : 20; int e, g; } __attribute__((packed));
+struct C { short a; unsigned i, k; struct B d; const int : 30; signed e : 20; signed : 18; };
+const struct C l = { 1, 6, 0, {}, 0 };
+int foo (void) { return l.e || 0; }