In PR 44826, we split a pre-reload call into another call followed by a load of GP. The problem is that we're running the split pass after var-tracking, and the original call had a NOTE_INSN_CALL_ARG_LOCATION attached to it. We need to move the note to the new call, just like we already move other properties of the call.
This shows up on 32-bit MIPS GNU/Linux at -O -g, because the first post-epilogue scheduling pass is after var tracking. It doesn't show up on -O2 and above because an earlier pass does the split. I think the bug could in principle trigger on other targets with call-clobbered GPs (e.g. some variants of Alpha, ia64 and PA). However, most other ports split on reload_completed, whereas MIPS does it on epilogue_completed, so perhaps it really is only MIPS. Tested on mips-linux-gnu and x86_64-linux-gnu. OK to install? Richard gcc/ PR rtl-optimization/48826 * emit-rtl.c (try_split): When splitting a call that is followed by a NOTE_INSN_CALL_ARG_LOCATION, move the note after the new call. Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c 2011-05-22 17:13:06.000000000 +0100 +++ gcc/emit-rtl.c 2011-05-22 20:37:09.000000000 +0100 @@ -3476,11 +3476,27 @@ try_split (rtx pat, rtx trial, int last) for (insn = insn_last; insn ; insn = PREV_INSN (insn)) if (CALL_P (insn)) { + rtx next; rtx *p = &CALL_INSN_FUNCTION_USAGE (insn); while (*p) p = &XEXP (*p, 1); *p = CALL_INSN_FUNCTION_USAGE (trial); SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial); + /* If the new call is the last instruction in the sequence, + it will effectively replace the old call in-situ. Otherwise + we must move any following NOTE_INSN_CALL_ARG_LOCATION note + so that it comes immediately after the new call. */ + if (NEXT_INSN (insn)) + { + next = NEXT_INSN (trial); + if (next + && NOTE_P (next) + && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION) + { + remove_insn (next); + add_insn_after (next, insn, NULL); + } + } } }