This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug rtl-optimization/24626] [4.1/4.2 Regression] internal compiler error: verify_flow_info failed
- From: "steven at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 13 Jan 2006 19:24:26 -0000
- Subject: [Bug rtl-optimization/24626] [4.1/4.2 Regression] internal compiler error: verify_flow_info failed
- References: <bug-24626-10053@http.gcc.gnu.org/bugzilla/>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Comment #31 from steven at gcc dot gnu dot org 2006-01-13 19:24 -------
First, we need the following patch to try_simplify_condjump.
-----------------------------------------------------------------------------
Index: cfgcleanup.c
===================================================================
--- cfgcleanup.c (revision 109649)
+++ cfgcleanup.c (working copy)
@@ -114,9 +114,10 @@ try_simplify_condjump (basic_block cbran
return false;
/* Verify that we've got a normal conditional branch at the end
- of the block. */
+ of the block. Some targets, e.g. HP-PA, have insns that do a
+ jump and a set in one. We can't handle that here. */
cbranch_insn = BB_END (cbranch_block);
- if (!any_condjump_p (cbranch_insn))
+ if (!any_condjump_p (cbranch_insn) || !onlyjump_p (cbranch_insn))
return false;
cbranch_fallthru_edge = FALLTHRU_EDGE (cbranch_block);
-----------------------------------------------------------------------------
Without the patch. try_simplify_condjump messes up the CFG because it only
tests any_condjump_p on the jump instruction, but not onlyjump_p. This is what
happens on mainline.
But unfortunately we only move the problem elsewhere with that patch.
At the point of failure we have the following CFG:
ENTRY
|
2
|\
| 3
|/
4
|
5
|
EXIT
with basic block 2 ending in the !onlyjump_p jump:
(jump_insn 18 16 21 2 (parallel [
(set (pc)
(if_then_else (ne (reg:SI 28 %r28)
(const_int 0 [0x0]))
(label_ref 29)
(pc)))
(set (reg/v:SI 3 %r3 [orig:95 call_result ] [95])
(reg:SI 28 %r28))
]) 227 {*pa.md:8779} (insn_list:REG_DEP_TRUE 16 (nil))
(expr_list:REG_DEAD (reg:SI 28 %r28)
(expr_list:REG_BR_PROB (const_int 5000 [0x1388])
(nil))))
and basic block 3 a trivial forwarder block:
;; basic block 3, loop depth 0, count 0
;; prev block 2, next block 4
;; pred: 2 [50.0%] (fallthru)
;; succ: 4 [100.0%] (fallthru)
;; Registers live at start: 3 [%r3] 30 [%r30] 48 [%fr12]
(note 21 18 29 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
;; Registers live at end: 3 [%r3] 30 [%r30] 48 [%fr12]
So try_optimize_cfg tries to turn the CFG into straight-line code, i.e. it
tries the following transformation:
ENTRY ENTRY
| |
2 2
|\ |
| 3 ==> |
|/ |
4 4
| |
5 5
| |
EXIT EXIT
This transformation is done in the following code, with basic block 3 as B:
/* If B has a single outgoing edge, but uses a
non-trivial jump instruction without side-effects, we
can either delete the jump entirely, or replace it
with a simple unconditional jump. */
if (single_succ_p (b)
&& single_succ (b) != EXIT_BLOCK_PTR
&& onlyjump_p (BB_END (b))
&& !find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
&& try_redirect_by_replacing_jump (single_succ_edge (b),
single_succ (b),
(mode & CLEANUP_CFGLAYOUT)
!= 0))
{
update_forwarder_flag (b);
changed_here = true;
}
So B, basic block 3, has only one successor, which is not the EXIT block, and
it ends in an onlyjump_p jump. try_redirect_by_replacing_jump has no trouble
with this jump, it simply removes it. Now we have:
ENTRY
|
2
|\
| 3 (empty)
|/
4
|
5
|
EXIT
and we mark basic block 3 as (still) a forwarder block. Then we iterate, and
try to optimize basic block 3 again. And we remove the whole block because it
is empty now (NB: b is still basic block 3):
/* If we fall through an empty block, we can remove it. */
if (!(mode & CLEANUP_CFGLAYOUT)
&& single_pred_p (b)
&& (single_pred_edge (b)->flags & EDGE_FALLTHRU)
&& !LABEL_P (BB_HEAD (b))
&& FORWARDER_BLOCK_P (b)
/* Note that forwarder_block_p true ensures that
there is a successor for this block. */
&& (single_succ_edge (b)->flags & EDGE_FALLTHRU)
&& n_basic_blocks > NUM_FIXED_BLOCKS + 1)
{
if (dump_file)
fprintf (dump_file,
"Deleting fallthru block %i.\n",
b->index);
c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
redirect_edge_succ_nodup (single_pred_edge (b),
single_succ (b));
delete_basic_block (b);
changed = true;
b = c;
}
So I plugged a little hole there:
-----------------------------------------------------------------------------
@@ -2039,6 +2040,9 @@ try_optimize_cfg (int mode)
/* If we fall through an empty block, we can remove it. */
if (!(mode & CLEANUP_CFGLAYOUT)
&& single_pred_p (b)
+ && ((c = single_pred (b)) == ENTRY_BLOCK_PTR
+ || !JUMP_P (BB_END (c))
+ || onlyjump_p (BB_END (c)))
&& (single_pred_edge (b)->flags & EDGE_FALLTHRU)
&& !LABEL_P (BB_HEAD (b))
&& FORWARDER_BLOCK_P (b)
-----------------------------------------------------------------------------
but that leaves us with the empty basic block 3, and we later on (not yet
determined where) we die on it again in cfgcleanup.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24626