https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115576
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org --- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Testcase in C: struct S { unsigned long long a; signed char b, c; unsigned short d; }; struct T { unsigned int a; signed char b, c; unsigned short d; }; struct S foo (const struct T *x) { return (struct S) { x->a, x->b, x->c, x->d }; } I'm afraid combine can't do much, as it generally tries to combine a pseudo setter with its single user, that isn't something that is done here, most of the TImode setters have 2+ users. E.g. that (insn 23 22 8 2 (set (reg:TI 101 [ D.2787 ]) (const_int 0 [0])) "pr115576.c":18:10 -1 (nil)) (insn 8 23 9 2 (set (reg:TI 101 [ D.2787 ]) (ior:TI (and:TI (reg:TI 101 [ D.2787 ]) (const_wide_int 0xffffffffffffffff0000000000000000)) (zero_extend:TI (reg:DI 104 [ _2 ])))) "pr115576.c":18:10 140 {*insvti_lowpart_1} (expr_list:REG_DEAD (reg:DI 104 [ _2 ]) (nil))) is used in both (insn 10 9 11 2 (set (reg:DI 106) (subreg:DI (reg:TI 101 [ D.2787 ]) 8)) "pr115576.c":18:10 88 {*movdi_internal} (nil)) and (insn 14 13 19 2 (set (reg:TI 101 [ D.2787 ]) (ior:TI (and:TI (reg:TI 101 [ D.2787 ]) (const_wide_int 0x0ffffffffffffffff)) (ashift:TI (zero_extend:TI (reg:DI 109)) (const_int 64 [0x40])))) "pr115576.c":18:10 137 {*insvti_highpart_1} (expr_list:REG_DEAD (reg:DI 109) (nil))) What would generally help is if nonzero_bits was able to deal with this and say that all bits in (subreg:DI (reg:TI 101 [ D.2787 ]) 8) are zero. But, nonzero_bits etc. uses unfortunately unsigned HOST_WIDE_INT rather than say wide_int or offset_int or FIXED_WIDE_INT (128) or some other type that can store more than 64 bits. Though, say on 32-bit targets unsigned HOST_WIDE_INT is probably good enough.