https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120550

--- Comment #6 from Jeffrey A. Law <law at gcc dot gnu.org> ---
So this is an ext-dce bug, it just isn't obvious.

ext-dce removes the extension in this insn:

(insn 26 24 29 3 (set (reg:DI 141 [ pretmp_16 ])
        (zero_extend:DI (subreg:QI (reg:DI 160) 0))) "j.c":8:5 126
{*zero_extendqidi2_internal}
     (expr_list:REG_DEAD (reg:DI 160) 
        (expr_list:REG_EQUAL (zero_extend:DI (mem/c:QI (symbol_ref:DI ("u")
[flags 0x86]  <var_decl 0x7ffff7202d10 u>) [0 u+0 S1 A8]))
            (nil))))

I've traced the values around the CFG and the removal is valid.  But there's a
REG_EQUAL note that gets left around.  So after ext-dce we have:

(insn 26 24 29 3 (set (reg:DI 141 [ pretmp_16 ])
        (reg:DI 160)) "j.c":8:5 277 {*movdi_64bit}
     (expr_list:REG_DEAD (reg:DI 160)
        (expr_list:REG_EQUAL (zero_extend:DI (mem/c:QI (symbol_ref:DI ("u")
[flags 0x86]  <var_decl 0x7ffff7202d10 u>) [0 u+0 S1 A8]))
            (nil))))


That's the bug.  Combine later kicks in and sees the REG_EQUAL note and adjust
the nonzero bits for (reg 141) in the expected way, but they don't accurately
reflect  the value in (reg 141).  Combine later uses the incorrect nonzero_bits
 and eliminates a different (and necessary) extension.

The fix is simple.  When ext-dce makes a change it can just wipe the REG_EQUAL
note.  We could try and be selective about the notes we remove, but I doubt
it's worth the effort and analysis to be selective.

Reply via email to