summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/cfgcleanup.c111
-rw-r--r--gcc/loop.c45
-rw-r--r--gcc/rtl.h10
-rw-r--r--gcc/rtlanal.c85
5 files changed, 220 insertions, 48 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c449f4fc496..b16ebd3feb2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2003-03-10 Josef Zlomek <zlomekj@suse.cz>
+
+ * cfgcleanup.c (outgoing_edges_match): Compare the jump tables.
+ (try_crossjump_to_edge): Replace refereces to one jump table by
+ references to identical jump table.
+ * loop.c (load_mems): Moved setting the JUMP_LABEL to replace_label.
+ (replace_label): Moved to rtlanal.c.
+ (struct rtx_pair): Moved to rtl.h.
+ * rtl.h (struct rtx_pair): Moved from loop.c.
+ (replace_label): New extern function.
+ (subrtx_p): New extern function.
+ (tablejump_p): New extern function.
+ * rtlanal.c (replace_label): Moved from loop.c.
+ (subrtx_p_1): New static function.
+ (subrtx_p): New function.
+ (tablejump_p): New function.
+
Mon Mar 10 15:30:36 CET 2003 Jan Hubicka <jh@suse.cz>
* cfgcleanup.c (merge_blocks): Return where to iterate next.
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 58b6efddc13..6ccc3eeca3e 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -1254,10 +1254,83 @@ outgoing_edges_match (mode, bb1, bb2)
/* Generic case - we are seeing a computed jump, table jump or trapping
instruction. */
+#ifndef CASE_DROPS_THROUGH
+ /* Check whether there are tablejumps in the end of BB1 and BB2.
+ Return true if they are identical. */
+ {
+ rtx label1, label2;
+ rtx table1, table2;
+
+ if (tablejump_p (bb1->end, &label1, &table1)
+ && tablejump_p (bb2->end, &label2, &table2)
+ && GET_CODE (PATTERN (table1)) == GET_CODE (PATTERN (table2)))
+ {
+ /* The labels should never be the same rtx. If they really are same
+ the jump tables are same too. So disable crossjumping of blocks BB1
+ and BB2 because when deleting the common insns in the end of BB1
+ by flow_delete_block () the jump table would be deleted too. */
+ /* If LABEL2 is contained in BB1->END do not do anything
+ because we would loose information when replacing
+ LABEL1 by LABEL2 and then LABEL2 by LABEL1 in BB1->END. */
+ if (label1 != label2 && !subrtx_p (label2, bb1->end))
+ {
+ /* Set IDENTICAL to true when the tables are identical. */
+ bool identical = false;
+ rtx p1, p2;
+
+ p1 = PATTERN (table1);
+ p2 = PATTERN (table2);
+ if (GET_CODE (p1) == ADDR_VEC && rtx_equal_p (p1, p2))
+ {
+ identical = true;
+ }
+ else if (GET_CODE (p1) == ADDR_DIFF_VEC
+ && (XVECLEN (p1, 1) == XVECLEN (p2, 1))
+ && rtx_equal_p (XEXP (p1, 2), XEXP (p2, 2))
+ && rtx_equal_p (XEXP (p1, 3), XEXP (p2, 3)))
+ {
+ int i;
+
+ identical = true;
+ for (i = XVECLEN (p1, 1) - 1; i >= 0 && identical; i--)
+ if (!rtx_equal_p (XVECEXP (p1, 1, i), XVECEXP (p2, 1, i)))
+ identical = false;
+ }
+
+ if (identical)
+ {
+ rtx_pair rr;
+ bool match;
+
+ /* Temporarily replace references to LABEL1 with LABEL2
+ in BB1->END so that we could compare the instructions. */
+ rr.r1 = label1;
+ rr.r2 = label2;
+ for_each_rtx (&bb1->end, replace_label, &rr);
+
+ match = insns_match_p (mode, bb1->end, bb2->end);
+ if (rtl_dump_file && match)
+ fprintf (rtl_dump_file,
+ "Tablejumps in bb %i and %i match.\n",
+ bb1->index, bb2->index);
+
+ /* Set the original label in BB1->END because when deleting
+ a block whose end is a tablejump, the tablejump referenced
+ from the instruction is deleted too. */
+ rr.r1 = label2;
+ rr.r2 = label1;
+ for_each_rtx (&bb1->end, replace_label, &rr);
+
+ return match;
+ }
+ }
+ return false;
+ }
+ }
+#endif
+
/* First ensure that the instructions match. There may be many outgoing
- edges so this test is generally cheaper.
- ??? Currently the tablejumps will never match, as they do have
- different tables. */
+ edges so this test is generally cheaper. */
if (!insns_match_p (mode, bb1->end, bb2->end))
return false;
@@ -1370,6 +1443,38 @@ try_crossjump_to_edge (mode, e1, e2)
if (!nmatch)
return false;
+#ifndef CASE_DROPS_THROUGH
+ /* Here we know that the insns in the end of SRC1 which are common with SRC2
+ will be deleted.
+ If we have tablejumps in the end of SRC1 and SRC2
+ they have been already compared for equivalence in outgoing_edges_match ()
+ so replace the references to TABLE1 by references to TABLE2. */
+ {
+ rtx label1, label2;
+ rtx table1, table2;
+
+ if (tablejump_p (src1->end, &label1, &table1)
+ && tablejump_p (src2->end, &label2, &table2)
+ && label1 != label2)
+ {
+ rtx_pair rr;
+ rtx insn;
+
+ /* Replace references to LABEL1 with LABEL2. */
+ rr.r1 = label1;
+ rr.r2 = label2;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ /* Do not replace the label in SRC1->END because when deleting
+ a block whose end is a tablejump, the tablejump referenced
+ from the instruction is deleted too. */
+ if (insn != src1->end)
+ for_each_rtx (&insn, replace_label, &rr);
+ }
+ }
+ }
+#endif
+
/* Avoid splitting if possible. */
if (newpos2 == src2->head)
redirect_to = src2;
diff --git a/gcc/loop.c b/gcc/loop.c
index 7a8185d4bad..56012d3ba16 100644
--- a/gcc/loop.c
+++ b/gcc/loop.c
@@ -338,7 +338,6 @@ static void note_reg_stored PARAMS ((rtx, rtx, void *));
static void try_copy_prop PARAMS ((const struct loop *, rtx, unsigned int));
static void try_swap_copy_prop PARAMS ((const struct loop *, rtx,
unsigned int));
-static int replace_label PARAMS ((rtx *, void *));
static rtx check_insn_for_givs PARAMS((struct loop *, rtx, int, int));
static rtx check_insn_for_bivs PARAMS((struct loop *, rtx, int, int));
static rtx gen_add_mult PARAMS ((rtx, rtx, rtx, rtx));
@@ -363,12 +362,6 @@ void debug_giv PARAMS ((const struct induction *));
void debug_loop PARAMS ((const struct loop *));
void debug_loops PARAMS ((const struct loops *));
-typedef struct rtx_pair
-{
- rtx r1;
- rtx r2;
-} rtx_pair;
-
typedef struct loop_replace_args
{
rtx match;
@@ -10151,15 +10144,6 @@ load_mems (loop)
for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
{
for_each_rtx (&p, replace_label, &rr);
-
- /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
- field. This is not handled by for_each_rtx because it doesn't
- handle unprinted ('0') fields. We need to update JUMP_LABEL
- because the immediately following unroll pass will use it.
- replace_label would not work anyways, because that only handles
- LABEL_REFs. */
- if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == end_label)
- JUMP_LABEL (p) = label;
}
}
@@ -10489,35 +10473,6 @@ replace_loop_regs (insn, reg, replacement)
for_each_rtx (&insn, replace_loop_reg, &args);
}
-
-/* Replace occurrences of the old exit label for the loop with the new
- one. DATA is an rtx_pair containing the old and new labels,
- respectively. */
-
-static int
-replace_label (x, data)
- rtx *x;
- void *data;
-{
- rtx l = *x;
- rtx old_label = ((rtx_pair *) data)->r1;
- rtx new_label = ((rtx_pair *) data)->r2;
-
- if (l == NULL_RTX)
- return 0;
-
- if (GET_CODE (l) != LABEL_REF)
- return 0;
-
- if (XEXP (l, 0) != old_label)
- return 0;
-
- XEXP (l, 0) = new_label;
- ++LABEL_NUSES (new_label);
- --LABEL_NUSES (old_label);
-
- return 0;
-}
/* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
(ignored in the interim). */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 89f554da724..1076cf5038a 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1595,6 +1595,13 @@ extern rtx set_unique_reg_note PARAMS ((rtx, enum reg_note, rtx));
: NULL_RTX)
#define single_set_1(I) single_set_2 (I, PATTERN (I))
+/* Structure used for passing data to REPLACE_LABEL. */
+typedef struct rtx_pair
+{
+ rtx r1;
+ rtx r2;
+} rtx_pair;
+
extern int rtx_addr_can_trap_p PARAMS ((rtx));
extern bool nonzero_address_p PARAMS ((rtx));
extern int rtx_unstable_p PARAMS ((rtx));
@@ -1654,6 +1661,9 @@ extern int inequality_comparisons_p PARAMS ((rtx));
extern rtx replace_rtx PARAMS ((rtx, rtx, rtx));
extern rtx replace_regs PARAMS ((rtx, rtx *, unsigned int,
int));
+extern int replace_label PARAMS ((rtx *, void *));
+extern int subrtx_p PARAMS ((rtx, rtx));
+extern bool tablejump_p PARAMS ((rtx, rtx *, rtx *));
extern int computed_jump_p PARAMS ((rtx));
typedef int (*rtx_function) PARAMS ((rtx *, void *));
extern int for_each_rtx PARAMS ((rtx *, rtx_function, void *));
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 8bd7b259a6d..d4817183c4e 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
static void set_of_1 PARAMS ((rtx, rtx, void *));
static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int subrtx_p_1 PARAMS ((rtx *, void *));
static int computed_jump_p_1 PARAMS ((rtx));
static void parms_set PARAMS ((rtx, rtx, void *));
static bool hoist_test_store PARAMS ((rtx, rtx, regset));
@@ -2791,6 +2792,90 @@ replace_regs (x, reg_map, nregs, replace_dest)
return x;
}
+/* Replace occurrences of the old label in *X with the new one.
+ DATA is an rtx_pair containing the old and new labels, respectively. */
+
+int
+replace_label (x, data)
+ rtx *x;
+ void *data;
+{
+ rtx l = *x;
+ rtx old_label = ((rtx_pair *) data)->r1;
+ rtx new_label = ((rtx_pair *) data)->r2;
+
+ if (l == NULL_RTX)
+ return 0;
+
+ /* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
+ field. This is not handled by for_each_rtx because it doesn't
+ handle unprinted ('0') fields. */
+ if (GET_CODE (l) == JUMP_INSN && JUMP_LABEL (l) == old_label)
+ JUMP_LABEL (l) = new_label;
+
+ if (GET_CODE (l) != LABEL_REF)
+ return 0;
+
+ if (XEXP (l, 0) != old_label)
+ return 0;
+
+ XEXP (l, 0) = new_label;
+ ++LABEL_NUSES (new_label);
+ --LABEL_NUSES (old_label);
+
+ return 0;
+}
+
+/* Return RTX_EQUAL_P (*PX, SUBX). If *PX and SUBX are not equal
+ FOR_EACH_RTX continues traversing, if they are equal FOR_EACH_RTX
+ stops traversing and returns the same value as this function. */
+
+static int
+subrtx_p_1 (px, subx)
+ rtx *px;
+ void *subx;
+{
+ return rtx_equal_p (*px, (rtx) subx);
+}
+
+/* Return true if SUBX is equal to some subexpression of X. */
+
+int
+subrtx_p (subx, x)
+ rtx subx;
+ rtx x;
+{
+ return for_each_rtx (&x, subrtx_p_1, subx);
+}
+
+/* If INSN is a jump to jumptable insn rturn true and store the label (which
+ INSN jumps to) to *LABEL and the tablejump insn to *TABLE.
+ LABEL and TABLE may be NULL. */
+
+bool
+tablejump_p (insn, label, table)
+ rtx insn;
+ rtx *label;
+ rtx *table;
+{
+ rtx l, t;
+
+ if (onlyjump_p (insn)
+ && (l = JUMP_LABEL (insn)) != NULL_RTX
+ && (t = NEXT_INSN (l)) != NULL_RTX
+ && GET_CODE (t) == JUMP_INSN
+ && (GET_CODE (PATTERN (t)) == ADDR_VEC
+ || GET_CODE (PATTERN (t)) == ADDR_DIFF_VEC))
+ {
+ if (label)
+ *label = l;
+ if (table)
+ *table = t;
+ return true;
+ }
+ return false;
+}
+
/* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
constant that is not in the constant pool and not in the condition
of an IF_THEN_ELSE. */