--- Comment #4 from Alexander Monakov <amonakov at gcc dot gnu.org> ---
Moreover, without --param selsched-max-lookahead=2 sel-sched moves both the
assignment and <retval> use into middle of BB 2, breaking the assumption in
mode-switching that retval use is the last insn:
249 /* If this function returns a value at the end, we have to
250 insert the final mode switch before the return value copy
251 to its hard register. */
252 if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == 1
253 && NONJUMP_INSN_P ((last_insn = BB_END (src_bb)))
254 && GET_CODE (PATTERN (last_insn)) == USE
255 && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG)
(independently of max-pending-list-length being 0 or not).
It seems a bit surprising that mode-switching needs to treat return value
specially, but more importantly, are the restrictions on return value register
set/use placement written down somewhere?
I don't see any explicit dependencies or barriers either, so isn't this like a
repeat of cc0 situation? What are other (dozens of) RTL passes doing to avoid
disturbing the required order?
Looking via gdb, apparently what pins those uses/clobbers to BB end for
2728 /* Selective scheduling handles control dependencies by itself. */
2729 if (!sel_sched_p ())
2730 add_branch_dependences (head, tail);
but the function doesn't do what it says on the tin:
2432 /* Add dependences so that branches are scheduled to run last in their
2433 block. */
2434 static void
2435 add_branch_dependences (rtx_insn *head, rtx_insn *tail)
2437 rtx_insn *insn, *last;
2439 /* For all branches, calls, uses, clobbers, cc0 setters, and
2440 that can throw exceptions, force them to remain in order at the end
2441 the block by adding dependencies and giving the last a high priority.
2442 There may be notes present, and prev_head may also be a note.