summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/bb-reorder.c45
-rw-r--r--gcc/function.c2
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/stmt.c19
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. */