This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug rtl-optimization/24626] [4.1/4.2 Regression] internal compiler error: verify_flow_info failed



------- 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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]