This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 2/3] cfgcleanup: Fold jumps and conditional branches with returns
- From: Christophe Lyon <christophe dot lyon at linaro dot org>
- To: Segher Boessenkool <segher at kernel dot crashing dot org>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 10 May 2016 21:33:56 +0200
- Subject: Re: [PATCH 2/3] cfgcleanup: Fold jumps and conditional branches with returns
- Authentication-results: sourceware.org; auth=none
- References: <cover dot 1462256244 dot git dot segher at kernel dot crashing dot org> <402b631c47d085a6f2bd8bdbb3b20733e2fcc2be dot 1462256245 dot git dot segher at kernel dot crashing dot org>
On 3 May 2016 at 08:59, Segher Boessenkool <segher@kernel.crashing.org> wrote:
> This patch makes cfgcleanup optimize jumps to returns. There are three
> cases this handles:
>
> -- A jump to a return; this is simplified to just that return.
> -- A conditional branch to a return; simplified to a conditional return.
> -- A conditional branch that falls through to a return. This is simplified
> to a conditional return (with the condition inverted), falling through
> to a jump to the original destination. That jump can then be optimized
> further, as usual.
>
> This handles all cases the current function.c does, and a few it misses.
>
>
> 2016-05-03 Segher Boessenkool <segher@kernel.crashing.org>
>
> * cfgcleanup.c (bb_is_just_return): New function.
> (try_optimize_cfg): Simplify jumps to return, branches to return,
> and branches around return.
>
Hi,
This patch causes an ICE on gcc.dg/20010822-1.c for target arm-none-eabi
--with-cpu=cortex-a9
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/gcc.dg/20010822-1.c:
In function 'bar':
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/testsuite/gcc.dg/20010822-1.c:31:1:
internal compiler error: in redirect_jump, at jump.c:1560
0x949a27 redirect_jump(rtx_jump_insn*, rtx_def*, int)
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/jump.c:1560
0x10ec689 try_optimize_cfg
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgcleanup.c:2899
0x10ec689 cleanup_cfg(int)
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgcleanup.c:3150
0x10ed1f6 execute
/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/cfgcleanup.c:3279
Christophe
> ---
> gcc/cfgcleanup.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 123 insertions(+)
>
> diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
> index 19583a7..4f87811 100644
> --- a/gcc/cfgcleanup.c
> +++ b/gcc/cfgcleanup.c
> @@ -2606,6 +2606,35 @@ trivially_empty_bb_p (basic_block bb)
> }
> }
>
> +/* Return true if BB contains just a return and possibly a USE of the
> + return value. Fill in *RET and *USE with the return and use insns
> + if any found, otherwise NULL. */
> +
> +static bool
> +bb_is_just_return (basic_block bb, rtx_insn **ret, rtx_insn **use)
> +{
> + *ret = *use = NULL;
> + rtx_insn *insn;
> +
> + if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
> + return false;
> +
> + FOR_BB_INSNS (bb, insn)
> + if (NONDEBUG_INSN_P (insn))
> + {
> + if (!*ret && ANY_RETURN_P (PATTERN (insn)))
> + *ret = insn;
> + else if (!*ret && !*use && GET_CODE (PATTERN (insn)) == USE
> + && REG_P (XEXP (PATTERN (insn), 0))
> + && REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))
> + *use = insn;
> + else
> + return false;
> + }
> +
> + return !!*ret;
> +}
> +
> /* Do simple CFG optimizations - basic block merging, simplifying of jump
> instructions etc. Return nonzero if changes were made. */
>
> @@ -2792,6 +2821,100 @@ try_optimize_cfg (int mode)
> }
> }
>
> + /* Try to change a branch to a return to just that return. */
> + rtx_insn *ret, *use;
> + if (single_succ_p (b)
> + && onlyjump_p (BB_END (b))
> + && bb_is_just_return (single_succ (b), &ret, &use))
> + {
> + if (redirect_jump (as_a <rtx_jump_insn *> (BB_END (b)),
> + PATTERN (ret), 0))
> + {
> + if (use)
> + emit_insn_before (copy_insn (PATTERN (use)),
> + BB_END (b));
> + if (dump_file)
> + fprintf (dump_file, "Changed jump %d->%d to return.\n",
> + b->index, single_succ (b)->index);
> + redirect_edge_succ (single_succ_edge (b),
> + EXIT_BLOCK_PTR_FOR_FN (cfun));
> + single_succ_edge (b)->flags &= ~EDGE_CROSSING;
> + changed_here = true;
> + }
> + }
> +
> + /* Try to change a conditional branch to a return to the
> + respective conditional return. */
> + if (EDGE_COUNT (b->succs) == 2
> + && any_condjump_p (BB_END (b))
> + && bb_is_just_return (BRANCH_EDGE (b)->dest, &ret, &use))
> + {
> + if (redirect_jump (as_a <rtx_jump_insn *> (BB_END (b)),
> + PATTERN (ret), 0))
> + {
> + if (use)
> + emit_insn_before (copy_insn (PATTERN (use)),
> + BB_END (b));
> + if (dump_file)
> + fprintf (dump_file, "Changed conditional jump %d->%d "
> + "to conditional return.\n",
> + b->index,
> + BRANCH_EDGE (b)->dest->index);
> + redirect_edge_succ (BRANCH_EDGE (b),
> + EXIT_BLOCK_PTR_FOR_FN (cfun));
> + BRANCH_EDGE (b)->flags &= ~EDGE_CROSSING;
> + changed_here = true;
> + }
> + }
> +
> + /* Try to flip a conditional branch that falls through to
> + a return so that it becomes a conditional return and a
> + new jump to the original branch target. */
> + if (EDGE_COUNT (b->succs) == 2
> + && any_condjump_p (BB_END (b))
> + && bb_is_just_return (FALLTHRU_EDGE (b)->dest, &ret, &use))
> + {
> + if (invert_jump (as_a <rtx_jump_insn *> (BB_END (b)),
> + JUMP_LABEL (BB_END (b)), 0))
> + {
> + basic_block new_ft = BRANCH_EDGE (b)->dest;
> + if (redirect_jump (as_a <rtx_jump_insn *> (BB_END (b)),
> + PATTERN (ret), 0))
> + {
> + if (use)
> + emit_insn_before (copy_insn (PATTERN (use)),
> + BB_END (b));
> + if (dump_file)
> + fprintf (dump_file, "Changed conditional jump "
> + "%d->%d to conditional return, "
> + "adding fall-through jump.\n",
> + b->index,
> + BRANCH_EDGE (b)->dest->index);
> + redirect_edge_succ (BRANCH_EDGE (b),
> + EXIT_BLOCK_PTR_FOR_FN (cfun));
> + BRANCH_EDGE (b)->flags &= ~EDGE_CROSSING;
> + std::swap (BRANCH_EDGE (b)->probability,
> + FALLTHRU_EDGE (b)->probability);
> + update_br_prob_note (b);
> + basic_block jb = force_nonfallthru (FALLTHRU_EDGE (b));
> + notice_new_block (jb);
> + if (!redirect_jump (as_a <rtx_jump_insn *> (BB_END (jb)),
> + block_label (new_ft), 0))
> + gcc_unreachable ();
> + redirect_edge_succ (single_succ_edge (jb), new_ft);
> + changed_here = true;
> + }
> + else
> + {
> + /* Invert the jump back to what it was. This should
> + never fail. */
> + if (!invert_jump (as_a <rtx_jump_insn *> (BB_END (b)),
> + JUMP_LABEL (BB_END (b)), 0))
> + gcc_unreachable ();
> + }
> + }
> + }
> +
> /* Simplify branch over branch. */
> if ((mode & CLEANUP_EXPENSIVE)
> && !(mode & CLEANUP_CFGLAYOUT)
> --
> 1.9.3
>