This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR rtl-optimization/17027
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 5 Oct 2004 22:43:28 +0200
- Subject: [PATCH] Fix PR rtl-optimization/17027
Hi,
This is an ICE at -O2 on the SPARC, a regression present on the 3.4 branch
only. The testcase is somewhat pathological:
void baz (void) __attribute__ ((noreturn)); /* noreturn is required */
void foo (void)
{
while (bar ()) {
switch (1) {
default:
baz ();
}
}
}
Before the BB reordering pass, the CFG is made up of 3 BBs: the successor of
ENTRY_BLOCK, the block falling through to EXIT_BLOCK and a block containing
the call to baz (so with no successor).
At the beginning of the pass, the first two blocks are merged, leading to a
block both successor of ENTRY_BLOCK and falling through to EXIT_BLOCK. So
when fixup_fallthru_exit_predecessor is invoked, it ICEs because it can't
reorder the blocks as it is meant to:
/* The block falling through to exit must be the last one in the
reordered chain. Ensure that this condition is met. */
static void
fixup_fallthru_exit_predecessor (void)
On the 3.4 branch, this only occurs on targets without RTL prologue/epilogue
because the epilogue creates a new block falling through to EXIT_BLOCK that
is not merged. On the mainline, this can't occur anymore since
fixup_fallthru_exit_predecessor invokes split_block when necessary.
I've attached two fixes: the first one prevents the merging from happening,
the second one is a backport from mainline of the bits needed in order to
split the block (extracted from 2 bigger patches). Both were
bootstrapped/regtested on sparc64-sun-solaris2.9 and sparc-sun-solaris2.8.
2004-10-05 Eric Botcazou <ebotcazou@libertysurf.fr>
* cfglayout.c (fallthru_exit_predecessor): New function extracted from...
(fixup_fallthru_exit_predecessor)...here.
* cfglayout.h (fallthru_exit_predecessor): Declare it.
* cfgrtl.c (cfg_layout_can_merge_blocks_p): Use it. If the target doesn't
have RTL epilogue, prevent two blocks from being merged if the result would
be both the successor of the entry and the block falling through to exit and
there are at least 3 blocks.
2004-10-05 Eric Botcazou <ebotcazou@libertysurf.fr>
Backport from mainline:
* cfglayout.c (fixup_fallthru_exit_predecessor): If the first block falls
through to exit, split it.
* cfgrtl.c (rtl_split_block): If no insn is specified, split on the first
insn in the basic block.
2004-10-05 Christian Ehrhardt <ehrhardt@mathematik.uni-ulm.de>
* gcc.c-torture/compile/20041005-1.c: New test.
--
Eric Botcazou
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50.4.1
diff -c -p -r1.50.4.1 cfglayout.c
*** cfglayout.c 26 Jul 2004 14:42:10 -0000 1.50.4.1
--- cfglayout.c 3 Oct 2004 18:07:25 -0000
*************** verify_insn_chain (void)
*** 849,865 ****
abort ();
}
! /* The block falling through to exit must be the last one in the
! reordered chain. Ensure that this condition is met. */
! static void
! fixup_fallthru_exit_predecessor (void)
{
edge e;
- basic_block bb = NULL;
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
if (e->flags & EDGE_FALLTHRU)
! bb = e->src;
if (bb && bb->rbi->next)
{
--- 849,873 ----
abort ();
}
! /* Return the block falling through to exit if it exists. */
! basic_block
! fallthru_exit_predecessor (void)
{
edge e;
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
if (e->flags & EDGE_FALLTHRU)
! return e->src;
!
! return NULL;
! }
!
! /* The block falling through to exit must be the last one in the
! reordered chain. Ensure that this condition is met. */
! static void
! fixup_fallthru_exit_predecessor (void)
! {
! basic_block bb = fallthru_exit_predecessor ();
if (bb && bb->rbi->next)
{
Index: cfglayout.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.h,v
retrieving revision 1.10.4.1
diff -c -p -r1.10.4.1 cfglayout.h
*** cfglayout.h 26 Jul 2004 14:42:10 -0000 1.10.4.1
--- cfglayout.h 3 Oct 2004 18:07:25 -0000
*************** extern void cfg_layout_initialize (unsig
*** 39,44 ****
--- 39,45 ----
extern void cfg_layout_finalize (void);
extern bool cfg_layout_can_duplicate_bb_p (basic_block);
extern basic_block cfg_layout_duplicate_bb (basic_block, edge);
+ extern basic_block fallthru_exit_predecessor (void);
extern void insn_locators_initialize (void);
extern void reemit_insn_block_notes (void);
extern bool can_copy_bbs_p (basic_block *, unsigned);
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.103.2.5
diff -c -p -r1.103.2.5 cfgrtl.c
*** cfgrtl.c 11 Aug 2004 20:05:05 -0000 1.103.2.5
--- cfgrtl.c 3 Oct 2004 18:07:30 -0000
*************** cfg_layout_can_merge_blocks_p (basic_blo
*** 2602,2608 ****
--- 2602,2619 ----
&& !b->pred->pred_next && a != b
/* Must be simple edge. */
&& !(a->succ->flags & EDGE_COMPLEX)
+ /* Obvious case to be rejected. */
&& a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
+ /* Less obvious case to be rejected: if we don't have epilogue,
+ we must always be able to put the block falling through to
+ exit at the end of the chain. */
+ && (
+ #ifdef HAVE_epilogue
+ HAVE_epilogue ||
+ #endif
+ ! (a == ENTRY_BLOCK_PTR->next_bb
+ && b == fallthru_exit_predecessor ()
+ && n_basic_blocks > 2))
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (BB_END (a)) != JUMP_INSN
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50.4.1
diff -u -p -r1.50.4.1 cfglayout.c
--- cfglayout.c 26 Jul 2004 14:42:10 -0000 1.50.4.1
+++ cfglayout.c 4 Oct 2004 21:50:22 -0000
@@ -865,6 +865,18 @@ fixup_fallthru_exit_predecessor (void)
{
basic_block c = ENTRY_BLOCK_PTR->next_bb;
+ /* If the very first block is the one with the fall-through exit
+ edge, we have to split that block. */
+ if (c == bb)
+ {
+ bb = split_block (bb, NULL)->dest;
+ cfg_layout_initialize_rbi (bb);
+ bb->rbi->next = c->rbi->next;
+ c->rbi->next = bb;
+ bb->rbi->footer = c->rbi->footer;
+ c->rbi->footer = NULL;
+ }
+
while (c->rbi->next != bb)
c = c->rbi->next;
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.103.2.5
diff -u -p -r1.103.2.5 cfgrtl.c
--- cfgrtl.c 11 Aug 2004 20:05:05 -0000 1.103.2.5
+++ cfgrtl.c 4 Oct 2004 21:50:27 -0000
@@ -483,9 +483,21 @@ rtl_split_block (basic_block bb, void *i
edge e;
rtx insn = insnp;
- /* There is no point splitting the block after its end. */
- if (BB_END (bb) == insn)
- return 0;
+ if (!insn)
+ {
+ insn = first_insn_after_basic_block_note (bb);
+
+ if (insn)
+ insn = PREV_INSN (insn);
+ else
+ insn = get_last_insn ();
+ }
+
+ /* We probably should check type of the insn so that we do not create
+ inconsistent cfg. It is checked in verify_flow_info anyway, so do not
+ bother. */
+ if (insn == BB_END (bb))
+ emit_note_after (NOTE_INSN_DELETED, insn);
/* Create the new basic block. */
new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
/* PR rtl-optimization/17027 */
/* Origin: dbk <sfc@village.uunet.be> */
/* Testcase by Christian Ehrhardt <ehrhardt@mathematik.uni-ulm.de> */
int bar(void);
void baz (void) __attribute__ ((noreturn)); /* noreturn is required */
void foo (void)
{
while (bar ()) {
switch (1) {
default:
baz ();
}
}
}