> PR middle-end/50496
> * cfgrtl.c (try_redirect_by_replacing_jump): Treat EXIT_BLOCK_PTR case
> separately before call to redirect_jump(). Add assertion.
> (patch_jump_insn): Same.
This will definitely disable redirections to the exit block. Now...
> diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
> index b3f045b..57f561f 100644
> --- a/gcc/cfgrtl.c
> +++ b/gcc/cfgrtl.c
> @@ -846,11 +846,10 @@ try_redirect_by_replacing_jump (edge e, basic_block
> target, bool in_cfglayout) if (dump_file)
> fprintf (dump_file, "Redirecting jump %i from %i to %i.\n",
> INSN_UID (insn), e->dest->index, target->index);
> - if (!redirect_jump (insn, block_label (target), 0))
> - {
> - gcc_assert (target == EXIT_BLOCK_PTR);
> - return NULL;
> - }
> + if (target == EXIT_BLOCK_PTR)
> + return NULL;
> + if (! redirect_jump (insn, block_label (target), 0))
> + gcc_unreachable ();
> }
>
> /* Cannot do anything for target exit block. */
> @@ -1030,11 +1029,10 @@ patch_jump_insn (rtx insn, rtx old_label,
> basic_block new_bb) /* If the substitution doesn't succeed, die. This can
> happen
> if the back end emitted unrecognizable instructions or if
> target is exit block on some arches. */
> - if (!redirect_jump (insn, block_label (new_bb), 0))
> - {
> - gcc_assert (new_bb == EXIT_BLOCK_PTR);
> - return false;
> - }
> + if (new_bb == EXIT_BLOCK_PTR)
> + return false;
> + if (! redirect_jump (insn, block_label (new_bb), 0))
> + gcc_unreachable ();
> }
> }
> return true;
... the code is pretty clear: attempting to redirect to the exit block is a
valid operation (since its potential failure is expected by the assertion).
The problem is that the interface to redirect_jump/redirect_jump_1 has recently
been changed:
2011-07-28 Bernd Schmidt <[email protected]>
[...]
* jump.c (delete_related_insns): Likewise.
(jump_to_label_p): New function.
(redirect_target): New static function.
(redirect_exp_1): Use it. Adjust to handle ret_rtx in JUMP_LABELS.
(redirect_jump_1): Assert that the new label is nonnull.
(redirect_jump): Likewise.
(redirect_jump_2): Check for ANY_RETURN_P rather than NULL labels.
[...]
but all the callers haven't apparently been updated. The model seems to be:
(dead_or_predicable): Change NEW_DEST arg to DEST_EDGE. All callers
changed. Ensure that the right label is passed to redirect_jump.
@@ -4134,10 +4137,16 @@ dead_or_predicable (basic_block test_bb,
old_dest = JUMP_LABEL (jump);
if (other_bb != new_dest)
{
- new_label = block_label (new_dest);
+ if (JUMP_P (BB_END (dest_edge->src)))
+ new_dest_label = JUMP_LABEL (BB_END (dest_edge->src));
+ else if (new_dest == EXIT_BLOCK_PTR)
+ new_dest_label = ret_rtx;
+ else
+ new_dest_label = block_label (new_dest);
+
if (reversep
- ? ! invert_jump_1 (jump, new_label)
- : ! redirect_jump_1 (jump, new_label))
+ ? ! invert_jump_1 (jump, new_dest_label)
+ : ! redirect_jump_1 (jump, new_dest_label))
goto cancel;
}
so the correct fix is very likely something like:
Index: cfgrtl.c
===================================================================
--- cfgrtl.c (revision 179844)
+++ cfgrtl.c (working copy)
@@ -1024,13 +1024,20 @@ patch_jump_insn (rtx insn, rtx old_label
if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label)
{
+ rtx new_label;
+
/* If the insn doesn't go where we think, we're confused. */
gcc_assert (JUMP_LABEL (insn) == old_label);
+ if (new_bb == EXIT_BLOCK_PTR)
+ new_label = ret_rtx;
+ else
+ new_label = block_label (new_bb);
+
/* If the substitution doesn't succeed, die. This can happen
if the back end emitted unrecognizable instructions or if
target is exit block on some arches. */
- if (!redirect_jump (insn, block_label (new_bb), 0))
+ if (!redirect_jump (insn, new_label, 0))
{
gcc_assert (new_bb == EXIT_BLOCK_PTR);
return false;
Bernd, should all the callers of redirect_jump/redirect_jump_1 be audited for
this pattern (there are 3 of them in cfgrtl.c for example)?
--
Eric Botcazou