cfgcleanup.c (outgoing_edges_match): Compare the jump tables.
authorJosef Zlomek <zlomekj@suse.cz>
Mon, 10 Mar 2003 17:23:44 +0000 (18:23 +0100)
committerJosef Zlomek <zlomek@gcc.gnu.org>
Mon, 10 Mar 2003 17:23:44 +0000 (17:23 +0000)
* 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.

From-SVN: r64096

gcc/ChangeLog
gcc/cfgcleanup.c
gcc/loop.c
gcc/rtl.h
gcc/rtlanal.c

index c449f4fc4961b253215cfd349898ab1bb8c44a45..b16ebd3feb2d1cdee4d920db0d13eb6bec7ee471 100644 (file)
@@ -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.
index 58b6efddc1390267d514b5dde55b55baa78505f4..6ccc3eeca3e94ac900958b0a5625f07207d83ed0 100644 (file)
@@ -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;
index 7a8185d4bad37178d9953dd6b7048463ca5b4f03..56012d3ba1641b8daa186b9717702bf6177f6167 100644 (file)
@@ -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;
-}
 \f
 /* Emit insn for PATTERN after WHERE_INSN in basic block WHERE_BB
    (ignored in the interim).  */
index 89f554da724291f222ebfe1197b5dbda7675daf8..1076cf5038a7e325ee7f94df3bf608a1ea498e3d 100644 (file)
--- 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 *));
index 8bd7b259a6d3e7885ac710164b6e918cff22c9df..d4817183c4ed1e0403f4cdfd9d6a06e7ed308c7f 100644 (file)
@@ -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.  */