return value. Fill in *RET and *USE with the return and use insns
if any found, otherwise NULL. All CLOBBERs are ignored. */
-static bool
+bool
bb_is_just_return (basic_block bb, rtx_insn **ret, rtx_insn **use)
{
*ret = *use = NULL;
extern bool delete_unreachable_blocks (void);
extern void delete_dead_jumptables (void);
extern bool cleanup_cfg (int);
+extern bool bb_is_just_return (basic_block, rtx_insn **, rtx_insn **);
#endif /* GCC_CFGCLEANUP_H */
/* Now add jumps and labels as needed to match the blocks new
outgoing edges. */
+ bool remove_unreachable_blocks = false;
for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb ; bb = (basic_block)
bb->aux)
{
continue;
}
+ /* If E_FALL->dest is just a return block, then we can emit a
+ return rather than a jump to the return block. */
+ rtx_insn *ret, *use;
+ basic_block dest;
+ if (bb_is_just_return (e_fall->dest, &ret, &use)
+ && (PATTERN (ret) == simple_return_rtx || PATTERN (ret) == ret_rtx))
+ {
+ ret_label = PATTERN (ret);
+ dest = EXIT_BLOCK_PTR_FOR_FN (cfun);
+
+ /* E_FALL->dest might become unreachable as a result of
+ replacing the jump with a return. So arrange to remove
+ unreachable blocks. */
+ remove_unreachable_blocks = true;
+ }
+ else
+ {
+ dest = e_fall->dest;
+ }
+
/* We got here if we need to add a new jump insn.
Note force_nonfallthru can delete E_FALL and thus we have to
save E_FALL->src prior to the call to force_nonfallthru. */
- nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label);
+ nb = force_nonfallthru_and_redirect (e_fall, dest, ret_label);
if (nb)
{
nb->aux = bb->aux;
ei_next (&ei2);
}
}
+
+ /* Replacing a jump with a return may have exposed an unreachable
+ block. Conditionally remove them if such transformations were
+ made. */
+ if (remove_unreachable_blocks)
+ delete_unreachable_blocks ();
}
\f
/* Perform sanity checks on the insn chain.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -dp" } */
+/* This was extracted from coremark. */
+
+
+typedef signed short ee_s16;
+typedef struct list_data_s
+{
+ ee_s16 data16;
+ ee_s16 idx;
+} list_data;
+
+typedef struct list_head_s
+{
+ struct list_head_s *next;
+ struct list_data_s *info;
+} list_head;
+
+
+list_head *
+core_list_find(list_head *list, list_data *info)
+{
+ if (info->idx >= 0)
+ {
+ while (list && (list->info->idx != info->idx))
+ list = list->next;
+ return list;
+ }
+ else
+ {
+ while (list && ((list->info->data16 & 0xff) != info->data16))
+ list = list->next;
+ return list;
+ }
+}
+
+/* There is only one legitimate unconditional jump, so test for that,
+ which will catch the case where bb-reorder leaves a jump to a ret
+ in the IL. */
+/* { dg-final { scan-assembler-times "jump" 1 } } */
+