On Tue, 10 Nov 2020, Jakub Jelinek wrote: > Hi! > > This patch fixes a thinko in the left-endian push_partial_def path. > As the testcase shows, we have 3 bitfields in the struct, > bitoff bitsize > 0 3 > 3 28 > 31 1 > the corresponding read is the byte at offset 3 (i.e. 24 bits) > and push_partial_def first handles the full store ({}) to all bits > and then is processing the store to the middle bitfield with value of -1. > Here are the interesting spots: > pd.offset -= offseti; > this adjusts the pd to { -21, 28 }, the (for little-endian lowest) 21 > bits aren't interesting to us, we only care about the upper 7. > len = native_encode_expr (pd.rhs, this_buffer, bufsize, > MAX (0, -pd.offset) / BITS_PER_UNIT); > native_encode_expr has the offset parameter in bytes and we tell it > that we aren't interested in the first (lowest) two bytes of the number. > It encodes 0xff, 0xff with len == 2 then. > HOST_WIDE_INT size = pd.size; > if (pd.offset < 0) > size -= ROUND_DOWN (-pd.offset, BITS_PER_UNIT); > we get 28 - 16, i.e. 12 - the 16 is subtracting those 2 bytes that we > omitted in native_encode_expr. > size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT); > needed_len is how many bytes the read at most needs, and that is 1, > so we get size 8 and copy all 8 bits (i.e. a single byte plus nothing) > from the native_encode_expr filled this_buffer; this incorrectly sets > the byte to 0xff when we want 0x7f. The above line is correct for the > pd.offset >= 0 case when we don't skip anything, but for the pd.offset < 0 > case we need to subtract also the remainder of the bits we aren't interested > in (the code shifts the bytes by that number of bits). > If it weren't for the big-endian path, we could as well do > if (pd.offset < 0) > size += pd.offset; > but the big-endian path needs it differently. > With the following patch, amnt is 3 and we subtract from 12 the (8 - 3) > bits and thus get the 7 which is the value we want. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/10?
OK. Thanks, Richard. > 2020-11-10 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/97764 > * tree-ssa-sccvn.c (vn_walk_cb_data::push_partial_def): For > little-endian stores with negative pd.offset, subtract > BITS_PER_UNIT - amnt from size if amnt is non-zero. > > * gcc.c-torture/execute/pr97764.c: New test. > > --- gcc/tree-ssa-sccvn.c.jj 2020-11-06 20:31:34.298252809 +0100 > +++ gcc/tree-ssa-sccvn.c 2020-11-09 14:45:00.454445644 +0100 > @@ -2039,12 +2039,12 @@ vn_walk_cb_data::push_partial_def (pd_da > } > else > { > - size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT); > if (pd.offset >= 0) > { > /* LSB of this_buffer[0] byte should be at pd.offset bits > in buffer. */ > unsigned int msk; > + size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT); > amnt = pd.offset % BITS_PER_UNIT; > if (amnt) > shift_bytes_in_array_left (this_buffer, len + 1, amnt); > @@ -2074,6 +2074,9 @@ vn_walk_cb_data::push_partial_def (pd_da > { > amnt = (unsigned HOST_WIDE_INT) pd.offset % BITS_PER_UNIT; > if (amnt) > + size -= BITS_PER_UNIT - amnt; > + size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT); > + if (amnt) > shift_bytes_in_array_left (this_buffer, len + 1, amnt); > } > memcpy (p, this_buffer + (amnt != 0), size / BITS_PER_UNIT); > --- gcc/testsuite/gcc.c-torture/execute/pr97764.c.jj 2020-11-09 > 14:36:20.974258322 +0100 > +++ gcc/testsuite/gcc.c-torture/execute/pr97764.c 2020-11-09 > 14:36:56.108865088 +0100 > @@ -0,0 +1,14 @@ > +/* PR tree-optimization/97764 */ > +/* { dg-require-effective-target int32plus } */ > + > +struct S { int b : 3; int c : 28; int d : 1; }; > + > +int > +main () > +{ > + struct S e = {}; > + e.c = -1; > + if (e.d) > + __builtin_abort (); > + return 0; > +} > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imend