This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PR 48826: NOTE_INSN_CALL_ARG_LOCATION vs. define_split
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 22 May 2011 22:13:34 +0100
- Subject: PR 48826: NOTE_INSN_CALL_ARG_LOCATION vs. define_split
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);
+ }
+ }
}
}