https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116405
--- Comment #5 from Manolis Tsamis <tsamismanolis at gmail dot com> --- The basic block that is if-converted and results in wrong code looks like this: if (r107 != -1) { r107 = (not:SI) (r99) r107 = (ior:SI) (r107) (const_int -2) } Then, the if-converted code that emitted is: # sequence generated for the first insn r125 = (not:SI) (r99) r129 = (flags == 0)? r107 : r125 # Stored to a temp register r129, because the original target r107 overlaps with the condition. # sequence generated for the second insn r132 = (ior:SI) (r129) (const_int -2) flags = (compare:CCZ) (r107) (const_int -1) # compare again because r132 clobbers flags r107 = (flags != 0)? r132 : r107 # The result is correct up to here. # Seen in the basic block but not emitted by noce_convert_multiple_sets_1. r107 = r129 # ?? The last and problematic instruction is emitted by this code: /* Now fixup the assignments. */ for (unsigned i = 0; i < insn_info.length (); i++) if (insn_info[i]->target != insn_info[i]->temporary) noce_emit_move_insn (insn_info[i]->target, insn_info[i]->temporary); Previously, due to the limited amount of supported operations, it was impossible to have multiple assignments to the same register (they would have been optimized away previously). Now we need to make sure we don't overwrite the result while fixing up temporaries. I'm preparing a fix based on this analysis.