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.

Reply via email to