mirror of git://gcc.gnu.org/git/gcc.git
re PR middle-end/41883 (ICE from '-O -fprofile-arcs -fsched2-use-superblocks -ftree-vrp -fschedule-insns2 -freorder-blocks')
PR middle-end/41883 * haifa-sched.c (add_to_note_list): Merge into ... (concat_note_lists): ... here, and ... (unlink_other_notes, rm_other_notes): Merge into... (remove_notes): ... here. Create REG_SAVE_NOTEs for NOTE_INSN_EPILOGUE_BEG. From-SVN: r155680
This commit is contained in:
parent
6209a13e20
commit
e67271bd65
|
@ -1,3 +1,12 @@
|
||||||
|
2010-01-06 Richard Henderson <rth@redhat.com>
|
||||||
|
|
||||||
|
PR middle-end/41883
|
||||||
|
* haifa-sched.c (add_to_note_list): Merge into ...
|
||||||
|
(concat_note_lists): ... here, and ...
|
||||||
|
(unlink_other_notes, rm_other_notes): Merge into...
|
||||||
|
(remove_notes): ... here. Create REG_SAVE_NOTEs for
|
||||||
|
NOTE_INSN_EPILOGUE_BEG.
|
||||||
|
|
||||||
2010-01-06 Richard Guenther <rguenther@suse.de>
|
2010-01-06 Richard Guenther <rguenther@suse.de>
|
||||||
|
|
||||||
* ipa-inline.c (cgraph_decide_inlining_incrementally): Do
|
* ipa-inline.c (cgraph_decide_inlining_incrementally): Do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* Instruction scheduling pass.
|
/* Instruction scheduling pass.
|
||||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||||
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
|
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
|
||||||
and currently maintained by, Jim Wilson (wilson@cygnus.com)
|
and currently maintained by, Jim Wilson (wilson@cygnus.com)
|
||||||
|
@ -1803,89 +1803,87 @@ schedule_insn (rtx insn)
|
||||||
|
|
||||||
/* Functions for handling of notes. */
|
/* Functions for handling of notes. */
|
||||||
|
|
||||||
/* Insert the INSN note at the end of the notes list. */
|
|
||||||
static void
|
|
||||||
add_to_note_list (rtx insn, rtx *note_list_end_p)
|
|
||||||
{
|
|
||||||
PREV_INSN (insn) = *note_list_end_p;
|
|
||||||
if (*note_list_end_p)
|
|
||||||
NEXT_INSN (*note_list_end_p) = insn;
|
|
||||||
*note_list_end_p = insn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add note list that ends on FROM_END to the end of TO_ENDP. */
|
/* Add note list that ends on FROM_END to the end of TO_ENDP. */
|
||||||
void
|
void
|
||||||
concat_note_lists (rtx from_end, rtx *to_endp)
|
concat_note_lists (rtx from_end, rtx *to_endp)
|
||||||
{
|
{
|
||||||
rtx from_start;
|
rtx from_start;
|
||||||
|
|
||||||
|
/* It's easy when have nothing to concat. */
|
||||||
if (from_end == NULL)
|
if (from_end == NULL)
|
||||||
/* It's easy when have nothing to concat. */
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* It's also easy when destination is empty. */
|
||||||
if (*to_endp == NULL)
|
if (*to_endp == NULL)
|
||||||
/* It's also easy when destination is empty. */
|
|
||||||
{
|
{
|
||||||
*to_endp = from_end;
|
*to_endp = from_end;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
from_start = from_end;
|
from_start = from_end;
|
||||||
/* A note list should be traversed via PREV_INSN. */
|
|
||||||
while (PREV_INSN (from_start) != NULL)
|
while (PREV_INSN (from_start) != NULL)
|
||||||
from_start = PREV_INSN (from_start);
|
from_start = PREV_INSN (from_start);
|
||||||
|
|
||||||
add_to_note_list (from_start, to_endp);
|
PREV_INSN (from_start) = *to_endp;
|
||||||
|
NEXT_INSN (*to_endp) = from_start;
|
||||||
*to_endp = from_end;
|
*to_endp = from_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete notes beginning with INSN and put them in the chain
|
/* Delete notes between HEAD and TAIL and put them in the chain
|
||||||
of notes ended by NOTE_LIST.
|
of notes ended by NOTE_LIST. */
|
||||||
Returns the insn following the notes. */
|
void
|
||||||
static rtx
|
remove_notes (rtx head, rtx tail)
|
||||||
unlink_other_notes (rtx insn, rtx tail)
|
|
||||||
{
|
{
|
||||||
rtx prev = PREV_INSN (insn);
|
rtx next_tail, prev, insn, next;
|
||||||
|
|
||||||
while (insn != tail && NOTE_NOT_BB_P (insn))
|
note_list = 0;
|
||||||
|
if (head == tail && !INSN_P (head))
|
||||||
|
return;
|
||||||
|
|
||||||
|
next_tail = NEXT_INSN (tail);
|
||||||
|
prev = PREV_INSN (head);
|
||||||
|
for (insn = head; insn != next_tail; insn = next)
|
||||||
{
|
{
|
||||||
rtx next = NEXT_INSN (insn);
|
next = NEXT_INSN (insn);
|
||||||
basic_block bb = BLOCK_FOR_INSN (insn);
|
if (!NOTE_P (insn))
|
||||||
|
{
|
||||||
|
prev = insn;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Delete the note from its current position. */
|
switch (NOTE_KIND (insn))
|
||||||
if (prev)
|
{
|
||||||
NEXT_INSN (prev) = next;
|
case NOTE_INSN_BASIC_BLOCK:
|
||||||
if (next)
|
prev = insn;
|
||||||
PREV_INSN (next) = prev;
|
continue;
|
||||||
|
|
||||||
if (bb)
|
case NOTE_INSN_EPILOGUE_BEG:
|
||||||
{
|
if (insn != tail)
|
||||||
/* Basic block can begin with either LABEL or
|
{
|
||||||
NOTE_INSN_BASIC_BLOCK. */
|
remove_insn (insn);
|
||||||
gcc_assert (BB_HEAD (bb) != insn);
|
add_reg_note (next, REG_SAVE_NOTE,
|
||||||
|
GEN_INT (NOTE_INSN_EPILOGUE_BEG));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHRU */
|
||||||
|
|
||||||
/* Check if we are removing last insn in the BB. */
|
default:
|
||||||
if (BB_END (bb) == insn)
|
remove_insn (insn);
|
||||||
BB_END (bb) = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See sched_analyze to see how these are handled. */
|
/* Add the note to list that ends at NOTE_LIST. */
|
||||||
if (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
|
PREV_INSN (insn) = note_list;
|
||||||
&& NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END)
|
NEXT_INSN (insn) = NULL_RTX;
|
||||||
add_to_note_list (insn, ¬e_list);
|
if (note_list)
|
||||||
|
NEXT_INSN (note_list) = insn;
|
||||||
|
note_list = insn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
insn = next;
|
gcc_assert ((sel_sched_p () || insn != tail) && insn != head);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insn == tail)
|
|
||||||
{
|
|
||||||
gcc_assert (sel_sched_p ());
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return insn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the head and tail pointers of ebb starting at BEG and ending
|
/* Return the head and tail pointers of ebb starting at BEG and ending
|
||||||
at END. */
|
at END. */
|
||||||
void
|
void
|
||||||
|
@ -1939,62 +1937,6 @@ no_real_insns_p (const_rtx head, const_rtx tail)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete notes between HEAD and TAIL and put them in the chain
|
|
||||||
of notes ended by NOTE_LIST. */
|
|
||||||
static void
|
|
||||||
rm_other_notes (rtx head, rtx tail)
|
|
||||||
{
|
|
||||||
rtx next_tail;
|
|
||||||
rtx insn;
|
|
||||||
|
|
||||||
note_list = 0;
|
|
||||||
if (head == tail && (! INSN_P (head)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
next_tail = NEXT_INSN (tail);
|
|
||||||
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
|
|
||||||
{
|
|
||||||
rtx prev;
|
|
||||||
|
|
||||||
/* Farm out notes, and maybe save them in NOTE_LIST.
|
|
||||||
This is needed to keep the debugger from
|
|
||||||
getting completely deranged. */
|
|
||||||
if (NOTE_NOT_BB_P (insn))
|
|
||||||
{
|
|
||||||
prev = insn;
|
|
||||||
insn = unlink_other_notes (insn, next_tail);
|
|
||||||
|
|
||||||
gcc_assert ((sel_sched_p ()
|
|
||||||
|| prev != tail) && prev != head && insn != next_tail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Same as above, but also process REG_SAVE_NOTEs of HEAD. */
|
|
||||||
void
|
|
||||||
remove_notes (rtx head, rtx tail)
|
|
||||||
{
|
|
||||||
/* rm_other_notes only removes notes which are _inside_ the
|
|
||||||
block---that is, it won't remove notes before the first real insn
|
|
||||||
or after the last real insn of the block. So if the first insn
|
|
||||||
has a REG_SAVE_NOTE which would otherwise be emitted before the
|
|
||||||
insn, it is redundant with the note before the start of the
|
|
||||||
block, and so we have to take it out. */
|
|
||||||
if (INSN_P (head))
|
|
||||||
{
|
|
||||||
rtx note;
|
|
||||||
|
|
||||||
for (note = REG_NOTES (head); note; note = XEXP (note, 1))
|
|
||||||
if (REG_NOTE_KIND (note) == REG_SAVE_NOTE)
|
|
||||||
remove_note (head, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove remaining note insns from the block, save them in
|
|
||||||
note_list. These notes are restored at the end of
|
|
||||||
schedule_block (). */
|
|
||||||
rm_other_notes (head, tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore-other-notes: NOTE_LIST is the end of a chain of notes
|
/* Restore-other-notes: NOTE_LIST is the end of a chain of notes
|
||||||
previously found among the insns. Insert them just before HEAD. */
|
previously found among the insns. Insert them just before HEAD. */
|
||||||
rtx
|
rtx
|
||||||
|
@ -2315,11 +2257,9 @@ debug_ready_list (struct ready_list *ready)
|
||||||
fprintf (sched_dump, "\n");
|
fprintf (sched_dump, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search INSN for REG_SAVE_NOTE note pairs for
|
/* Search INSN for REG_SAVE_NOTE notes and convert them back into insn
|
||||||
NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
|
NOTEs. This is used for NOTE_INSN_EPILOGUE_BEG, so that sched-ebb
|
||||||
NOTEs. The REG_SAVE_NOTE note following first one is contains the
|
replaces the epilogue note in the correct basic block. */
|
||||||
saved value for NOTE_BLOCK_NUMBER which is useful for
|
|
||||||
NOTE_INSN_EH_REGION_{BEG,END} NOTEs. */
|
|
||||||
void
|
void
|
||||||
reemit_notes (rtx insn)
|
reemit_notes (rtx insn)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O2 -g -ftracer -fsched2-use-superblocks" } */
|
||||||
|
|
||||||
|
static int i;
|
||||||
|
extern void baz(int);
|
||||||
|
void foo() { i = 3; }
|
||||||
|
void bar() { baz(i ? 2 : 1); }
|
Loading…
Reference in New Issue