diff options
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/cfgcleanup.c | 111 | ||||
-rw-r--r-- | gcc/loop.c | 45 | ||||
-rw-r--r-- | gcc/rtl.h | 10 | ||||
-rw-r--r-- | gcc/rtlanal.c | 85 |
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. */ |