The problem is fixed by simply moving the code that skips insns that don't set a part of the return value below the code that checks if the insn needs a non-MODE_EXIT mode setting.
bootstrapped/regtested on i686-pc-linux-gnu 2013-07-24 Joern Rennecke <joern.renne...@embecosm.com> PR rtl-optimization/57968 * mode-switching.c (create_pre_exit): Allow instructions that don't set a return register to need a non-exit mode.
Index: mode-switching.c =================================================================== --- mode-switching.c (revision 201202) +++ mode-switching.c (working copy) @@ -330,12 +330,10 @@ create_pre_exit (int n_entities, int *en break; } if (!targetm.calls.function_value_regno_p (copy_start)) - { - last_insn = return_copy; - continue; - } - copy_num - = hard_regno_nregs[copy_start][GET_MODE (copy_reg)]; + copy_num = 0; + else + copy_num + = hard_regno_nregs[copy_start][GET_MODE (copy_reg)]; /* If the return register is not likely spilled, - as is the case for floating point on SH4 - then it might @@ -372,6 +370,11 @@ create_pre_exit (int n_entities, int *en forced_late_switch = 1; break; } + if (copy_num == 0) + { + last_insn = return_copy; + continue; + } if (copy_start >= ret_start && copy_start + copy_num <= ret_end)