http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51374
--- Comment #6 from Georg-Johann Lay <gjl at gcc dot gnu.org> 2011-12-18 19:01:56 UTC --- In combine.c:try_combine, just after the "Trying..." dump output, there is: i0 = 0 i1 = 0 i2 = (set (reg/v:QI 43 [ status ]) (mem/v:QI (const_int 43 [0x2b]))) i3 = (set (pc) (if_then_else (eq (zero_extract:QI (reg/v:QI 43 [ status ]) (const_int 1) (const_int 4)) (const_int 0)) (label_ref:HI 16) (pc))) where the potential insertion is i2 into i3. These insns are fed into can_combine_p with src = (mem/v:QI (const_int 43)) dest = (reg/v:QI 43) and then there is this part of an if-clause: /* Make sure that the value that is to be substituted for the register does not use any registers whose values alter in between. However, If the insns are adjacent, a use can't cross a set even though we think it might (this can happen for a sequence of insns each setting the same destination; last_set of that register might point to a NOTE). If INSN has a REG_EQUIV note, the register is always equivalent to the memory so the substitution is valid even if there are intervening stores. Also, don't move a volatile asm or UNSPEC_VOLATILE across any other insns. */ || (! all_adjacent && (((!MEM_P (src) || ! find_reg_note (insn, REG_EQUIV, src)) && use_crosses_set_p (src, DF_INSN_LUID (insn))) || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src)) || GET_CODE (src) == UNSPEC_VOLATILE)) In addition to these tests, the following must be disallowed: If src contains volatile memory, then disallow moving it across: * volatile memory * unspec_volatile * asm volatile As far as I can see, use_crosses_set_p (src,...) returns 0 (false) which is incorrect. So either use_crosses_set_p is incorrect or it relies on incorrect data from data flow analysis or from wherever.