aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2010-01-06 10:34:31 -0800
committerRichard Henderson <rth@gcc.gnu.org>2010-01-06 10:34:31 -0800
commite67271bd6571e2a3c6adc842350571e59b5a1f86 (patch)
tree690ad37d4cb1af3217c4867f5546cc48b0c4e34a
parent6209a13e202b97e040f91e57281a2c23e0022bea (diff)
downloadgcc-e67271bd6571e2a3c6adc842350571e59b5a1f86.zip
gcc-e67271bd6571e2a3c6adc842350571e59b5a1f86.tar.gz
gcc-e67271bd6571e2a3c6adc842350571e59b5a1f86.tar.bz2
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
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/haifa-sched.c166
-rw-r--r--gcc/testsuite/gcc.dg/pr42396.c7
3 files changed, 69 insertions, 113 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6435d2a..e8aa64b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
* ipa-inline.c (cgraph_decide_inlining_incrementally): Do
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 204fab6..de75286 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -1,6 +1,6 @@
/* Instruction scheduling pass.
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.
Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -1803,89 +1803,87 @@ schedule_insn (rtx insn)
/* 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. */
void
concat_note_lists (rtx from_end, rtx *to_endp)
{
rtx from_start;
+ /* It's easy when have nothing to concat. */
if (from_end == NULL)
- /* It's easy when have nothing to concat. */
return;
+ /* It's also easy when destination is empty. */
if (*to_endp == NULL)
- /* It's also easy when destination is empty. */
{
*to_endp = from_end;
return;
}
from_start = from_end;
- /* A note list should be traversed via PREV_INSN. */
while (PREV_INSN (from_start) != NULL)
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;
}
-/* Delete notes beginning with INSN and put them in the chain
- of notes ended by NOTE_LIST.
- Returns the insn following the notes. */
-static rtx
-unlink_other_notes (rtx insn, rtx tail)
+/* Delete notes between HEAD and TAIL and put them in the chain
+ of notes ended by NOTE_LIST. */
+void
+remove_notes (rtx head, rtx tail)
{
- rtx prev = PREV_INSN (insn);
+ rtx next_tail, prev, insn, next;
- while (insn != tail && NOTE_NOT_BB_P (insn))
- {
- rtx next = NEXT_INSN (insn);
- basic_block bb = BLOCK_FOR_INSN (insn);
-
- /* Delete the note from its current position. */
- if (prev)
- NEXT_INSN (prev) = next;
- if (next)
- PREV_INSN (next) = prev;
+ note_list = 0;
+ if (head == tail && !INSN_P (head))
+ return;
- if (bb)
- {
- /* Basic block can begin with either LABEL or
- NOTE_INSN_BASIC_BLOCK. */
- gcc_assert (BB_HEAD (bb) != insn);
+ next_tail = NEXT_INSN (tail);
+ prev = PREV_INSN (head);
+ for (insn = head; insn != next_tail; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (!NOTE_P (insn))
+ {
+ prev = insn;
+ continue;
+ }
- /* Check if we are removing last insn in the BB. */
- if (BB_END (bb) == insn)
- BB_END (bb) = prev;
- }
+ switch (NOTE_KIND (insn))
+ {
+ case NOTE_INSN_BASIC_BLOCK:
+ prev = insn;
+ continue;
- /* See sched_analyze to see how these are handled. */
- if (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
- && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END)
- add_to_note_list (insn, &note_list);
+ case NOTE_INSN_EPILOGUE_BEG:
+ if (insn != tail)
+ {
+ remove_insn (insn);
+ add_reg_note (next, REG_SAVE_NOTE,
+ GEN_INT (NOTE_INSN_EPILOGUE_BEG));
+ break;
+ }
+ /* FALLTHRU */
- insn = next;
- }
+ default:
+ remove_insn (insn);
+
+ /* Add the note to list that ends at NOTE_LIST. */
+ PREV_INSN (insn) = note_list;
+ NEXT_INSN (insn) = NULL_RTX;
+ if (note_list)
+ NEXT_INSN (note_list) = insn;
+ note_list = insn;
+ break;
+ }
- if (insn == tail)
- {
- gcc_assert (sel_sched_p ());
- return prev;
+ gcc_assert ((sel_sched_p () || insn != tail) && insn != head);
}
-
- return insn;
}
+
/* Return the head and tail pointers of ebb starting at BEG and ending
at END. */
void
@@ -1939,62 +1937,6 @@ no_real_insns_p (const_rtx head, const_rtx tail)
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
previously found among the insns. Insert them just before HEAD. */
rtx
@@ -2315,11 +2257,9 @@ debug_ready_list (struct ready_list *ready)
fprintf (sched_dump, "\n");
}
-/* Search INSN for REG_SAVE_NOTE note pairs for
- NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
- NOTEs. The REG_SAVE_NOTE note following first one is contains the
- saved value for NOTE_BLOCK_NUMBER which is useful for
- NOTE_INSN_EH_REGION_{BEG,END} NOTEs. */
+/* Search INSN for REG_SAVE_NOTE notes and convert them back into insn
+ NOTEs. This is used for NOTE_INSN_EPILOGUE_BEG, so that sched-ebb
+ replaces the epilogue note in the correct basic block. */
void
reemit_notes (rtx insn)
{
diff --git a/gcc/testsuite/gcc.dg/pr42396.c b/gcc/testsuite/gcc.dg/pr42396.c
new file mode 100644
index 0000000..b3b7e4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr42396.c
@@ -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); }