https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88739
--- Comment #31 from rguenther at suse dot de <rguenther at suse dot de> --- 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. */