https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88739
--- Comment #32 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to rguent...@suse.de from comment #31) > On Wed, 9 Jan 2019, wilco at gcc dot gnu.org wrote: > > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88739 > > > > --- Comment #29 from Wilco <wilco at gcc dot gnu.org> --- > > (In reply to Richard Biener from comment #26) > > > > > Did anybody test the patch? Testing on x86_64 will be quite pointless... > > > > Well that generates _18 = BIT_FIELD_REF <_2, 16, 14>; and becomes: > > > > ubfx x1, x20, 2, 16 > > > > This extracts bits 2-17 of the 30-bit value instead of bits 14-29. The > > issue is > > that we're using a bitfield reference on a value that is claimed not to be a > > bitfield in comment 6. So I can't see how using BIT_FIELD_REF could ever > > work > > correctly. > > So that's because TYPE_PRECISION != GET_MODE_PRECISION and the > BIT_FIELD_REF expansion counting from GET_MODE_PRECISION I suppose. > > Thus there is a RTL expansion side of the bug after all? > > The "fixed" RTL is > > (insn 6 5 7 (set (reg:SI 95) > (lshiftrt:SI (reg/v:SI 94 [ ulAddr ]) > (const_int 2 [0x2]))) "t.c":42:48 -1 > (nil)) > > (insn 7 6 8 (set (reg:SI 96) > (and:SI (reg:SI 95) > (const_int 1073741823 [0x3fffffff]))) "t.c":42:48 -1 > (nil)) > > (insn 8 7 9 (set (subreg:DI (reg:HI 97) 0) > (zero_extract:DI (subreg:DI (reg:SI 96) 0) > (const_int 16 [0x10]) > (const_int 2 [0x2]))) "t.c":44:8 -1 > (nil)) > > so the 30bit value is in reg:SI 96 (the :30 cast causes the > and with 0x3fffffff) but then the zero_extract we generate > is bogus. > > So maybe the :30 cast should have been a shift for BYTES_BIG_ENDIAN? > > We might be able to work around this by optimization on GIMPLE, > combining > > _1 = ulAddr_3(D) >> 2; > _2 = (<unnamed-unsigned:30>) _1; > _6 = BIT_FIELD_REF <_2, 16, 14>; > > as far as eliminating at least the non-mode precision type... > > Of course that would just work around the underlying RTL expansion > bug? > > Note we can end up with things like > > _2 = (<unnamed-unsigned:35) _1; > _3 = (<unnamed-unsigned:35) _4; > _5 = _2 + 3; > > as well so shifting at the conversion might not be the correct > answer (but instead BIT_FIELD_REF expansion needs to be fixed). > > Alternatively we could declare it invalid GIMPLE and require > BIT_FIELD_REF positions to be always relative to the mode > (but then I'd rather disallow BIT_FIELD_REF on non-mode > precision entities...). > > Sth like the following might fix the RTL expansion issue > which then generates > > Test_func: > ubfx x0, x0, 2, 16 > cmp w0, 1 > bne .L6 > mov w0, 0 > > and just > > (insn 6 5 7 (set (reg:SI 95) > (lshiftrt:SI (reg/v:SI 94 [ ulAddr ]) > (const_int 2 [0x2]))) "t.c":42:48 -1 > (nil)) > > (insn 7 6 8 (set (reg:SI 96) > (and:SI (reg:SI 95) > (const_int 1073741823 [0x3fffffff]))) "t.c":42:48 -1 > (nil)) > > (insn 8 7 9 (set (reg:SI 97) > (zero_extend:SI (subreg:HI (reg:SI 96) 2))) "t.c":44:8 -1 > (nil)) > > Index: gcc/expr.c > =================================================================== > --- gcc/expr.c (revision 267553) > +++ gcc/expr.c (working copy) > @@ -10562,6 +10562,15 @@ expand_expr_real_1 (tree exp, rtx target > infinitely recurse. */ > gcc_assert (tem != exp); > > + /* When extracting from non-mode bitsize entities adjust the > + bit position for BYTES_BIG_ENDIAN. */ > + if (INTEGRAL_TYPE_P (TREE_TYPE (tem)) > + && (TYPE_PRECISION (TREE_TYPE (tem)) > + < GET_MODE_BITSIZE (as_a <scalar_int_mode> (TYPE_MODE > (TREE_TYPE (tem))))) > + && BYTES_BIG_ENDIAN) > + bitpos += (GET_MODE_BITSIZE (as_a <scalar_int_mode> (TYPE_MODE > (TREE_TYPE (tem)))) > + - TYPE_PRECISION (TREE_TYPE (tem))); > + > /* If TEM's type is a union of variable size, pass TARGET to the > inner > computation, since it will need a temporary and TARGET is known > to have to do. This occurs in unchecked conversion in Ada. */ Btw, this needs to be amended for WORDS_BIG_ENDIAN of course. I guess we might even run into the case that such BIT_FIELD_REF references a non-contiguous set of bits... (that's also true for BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN I guess).