combine: Fix find_split_point handling of constant store into ZERO_EXTRACT [PR93908]
commitd9814ee5972b48eb67a7af171957d1a285453f46
authorJakub Jelinek <jakub@redhat.com>
Tue, 25 Feb 2020 12:56:47 +0000 (25 13:56 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 25 Feb 2020 13:04:59 +0000 (25 14:04 +0100)
tree0097d9a869702bf9ea05c25f0ebff2deccb4f61c
parente803bacc36955686a633bfb48d2ee433d503edfa
combine: Fix find_split_point handling of constant store into ZERO_EXTRACT [PR93908]

git is miscompiled on s390x-linux with -O2 -march=zEC12 -mtune=z13.
I've managed to reduce it into the following testcase.  The problem is that
during combine we see the s->k = -1; bitfield store and change the SET_SRC
from a pseudo into a constant:
(set (zero_extract:DI (mem/j:HI (plus:DI (reg/v/f:DI 60 [ s ])
                (const_int 10 [0xa])) [0 +0 S2 A16])
        (const_int 2 [0x2])
        (const_int 7 [0x7]))
    (const_int -1 [0xffffffffffffffff]))
This on s390x with the above option isn't recognized as valid instruction,
so find_split_point decides to handle it as IOR or IOR/AND.
src is -1, mask is 3 and pos is 7.
src != mask (this is also incorrect, we want to set all (both) bits in the
bitfield), so we go for IOR/AND, but instead of trying
mem = (mem & ~0x180) | ((-1 << 7) & 0x180)
we actually try
mem = (mem & ~0x180) | (-1 << 7)
and that is further simplified into:
mem = mem | (-1 << 7)
aka
mem = mem | 0xff80
which doesn't set just the 2-bit bitfield, but also many other bitfields
that shouldn't be touched.
We really should do:
mem = mem | 0x180
instead.
The problem is that we assume that no bits but those low len (2 here) will
be set in the SET_SRC, but there is nothing that can prevent that, we just
should ignore the other bits.

The following patch fixes it by masking src with mask, this way already
the src == mask test will DTRT, and as the code for or_mask uses
gen_int_mode, if the most significant bit is set after shifting it left by
pos, it will be properly sign-extended.

2020-02-25  Jakub Jelinek  <jakub@redhat.com>

PR rtl-optimization/93908
* combine.c (find_split_point): For store into ZERO_EXTRACT, and src
with mask.

* gcc.c-torture/execute/pr93908.c: New test.
gcc/ChangeLog
gcc/combine.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr93908.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/pr93908.c [new file with mode: 0644]