diff options
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/bb-reorder.c | 45 | ||||
-rw-r--r-- | gcc/function.c | 2 | ||||
-rw-r--r-- | gcc/function.h | 4 | ||||
-rw-r--r-- | gcc/stmt.c | 19 |
5 files changed, 79 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4e00dea2e46..bfa89fa3e37 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2003-03-21 Richard Henderson <rth@redhat.com> + + PR opt/2001 + * bb-reorder.c (maybe_duplicate_computed_goto_succ): New. + (make_reorder_chain_1): Call it. + + * function.h (struct function): Add computed_goto_common_label, + computed_goto_common_reg. + * function.c (free_after_compilation): Zap them. + * stmt.c (expand_computed_goto): Use them to produce one + indirect branch per function. + 2003-03-22 Stephane Carrez <stcarrez@nerim.fr> * config/m68hc11/m68hc11.md ("call_value"): Fix trap check. diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 24c41e51ced..857e0fbc6ec 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -89,11 +89,13 @@ #include "flags.h" #include "output.h" #include "cfglayout.h" +#include "function.h" #include "target.h" /* Local function prototypes. */ static void make_reorder_chain PARAMS ((void)); static basic_block make_reorder_chain_1 PARAMS ((basic_block, basic_block)); +static basic_block maybe_duplicate_computed_goto_succ PARAMS ((basic_block)); /* Compute an ordering for a subgraph beginning with block BB. Record the ordering in RBI()->index and chained through RBI()->next. */ @@ -130,6 +132,45 @@ make_reorder_chain () RBI (prev)->next = NULL; } +/* If the successor is our artificial computed_jump block, duplicate it. */ + +static inline basic_block +maybe_duplicate_computed_goto_succ (bb) + basic_block bb; +{ + edge e; + basic_block next; + + /* Note that we can't rely on computed_goto_common_label still being in + the instruction stream -- cfgloop.c likes to munge things about. But + we can still use it's non-null-ness to avoid a fruitless search. */ + if (!cfun->computed_goto_common_label) + return NULL; + + /* Only want to duplicate when coming from a simple branch. */ + e = bb->succ; + if (!e || e->succ_next) + return NULL; + + /* Only duplicate if we've already layed out this block once. */ + next = e->dest; + if (!RBI (next)->visited) + return NULL; + + /* See if the block contains only a computed branch. */ + if ((next->head == next->end + || next_active_insn (next->head) == next->end) + && computed_jump_p (next->end)) + { + if (rtl_dump_file) + fprintf (rtl_dump_file, "Duplicating block %d after %d\n", + next->index, bb->index); + return cfg_layout_duplicate_bb (next, e); + } + + return NULL; +} + /* A helper function for make_reorder_chain. We do not follow EH edges, or non-fallthru edges to noreturn blocks. @@ -206,6 +247,10 @@ make_reorder_chain_1 (bb, prev) next = ((taken && e_taken) ? e_taken : e_fall)->dest; } + /* If the successor is our artificial computed_jump block, duplicate it. */ + else + next = maybe_duplicate_computed_goto_succ (bb); + /* In the absence of a prediction, disturb things as little as possible by selecting the old "next" block from the list of successors. If there had been a fallthru edge, that will be the one. */ diff --git a/gcc/function.c b/gcc/function.c index d5463775a8e..36621d3d938 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -451,6 +451,8 @@ free_after_compilation (f) f->x_nonlocal_goto_stack_level = NULL; f->x_cleanup_label = NULL; f->x_return_label = NULL; + f->computed_goto_common_label = NULL; + f->computed_goto_common_reg = NULL; f->x_save_expr_regs = NULL; f->x_stack_slot_list = NULL; f->x_rtl_expr_chain = NULL; diff --git a/gcc/function.h b/gcc/function.h index 89319ebf2e3..d3fb077fba8 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -273,6 +273,10 @@ struct function GTY(()) on machines which require execution of the epilogue on all returns. */ rtx x_return_label; + /* Label and register for unswitching computed gotos. */ + rtx computed_goto_common_label; + rtx computed_goto_common_reg; + /* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs. So we can mark them all live at the end of the function, if nonopt. */ rtx x_save_expr_regs; diff --git a/gcc/stmt.c b/gcc/stmt.c index 3848d61b678..e3f08ee45f7 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -541,10 +541,23 @@ expand_computed_goto (exp) #endif emit_queue (); - do_pending_stack_adjust (); - emit_indirect_jump (x); - current_function_has_computed_jump = 1; + if (! cfun->computed_goto_common_label) + { + cfun->computed_goto_common_reg = copy_to_mode_reg (Pmode, x); + cfun->computed_goto_common_label = gen_label_rtx (); + emit_label (cfun->computed_goto_common_label); + + do_pending_stack_adjust (); + emit_indirect_jump (cfun->computed_goto_common_reg); + + current_function_has_computed_jump = 1; + } + else + { + emit_move_insn (cfun->computed_goto_common_reg, x); + emit_jump (cfun->computed_goto_common_label); + } } /* Handle goto statements and the labels that they can go to. */ |