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