OSDN Git Service

* obj-c++.dg/stubify-1.mm: Only run on powerpc.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 015e1de..cdc5ebe 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,6 +1,7 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -269,17 +270,13 @@ struct change_cc_mode_args
    table since its use is guaranteed to be the insn immediately following
    its definition and any other insn is presumed to invalidate it.
 
-   Instead, we store below the value last assigned to CC0.  If it should
-   happen to be a constant, it is stored in preference to the actual
-   assigned value.  In case it is a constant, we store the mode in which
-   the constant should be interpreted.  */
+   Instead, we store below the current and last value assigned to CC0.
+   If it should happen to be a constant, it is stored in preference
+   to the actual assigned value.  In case it is a constant, we store
+   the mode in which the constant should be interpreted.  */
 
-static rtx prev_insn_cc0;
-static enum machine_mode prev_insn_cc0_mode;
-
-/* Previous actual insn.  0 if at first insn of basic block.  */
-
-static rtx prev_insn;
+static rtx this_insn_cc0, prev_insn_cc0;
+static enum machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
 #endif
 
 /* Insn being scanned.  */
@@ -900,7 +897,6 @@ new_basic_block (void)
     }
 
 #ifdef HAVE_cc0
-  prev_insn = 0;
   prev_insn_cc0 = 0;
 #endif
 }
@@ -3050,11 +3046,37 @@ fold_rtx (rtx x, rtx insn)
       {
        rtx folded_arg = XEXP (x, i), const_arg;
        enum machine_mode mode_arg = GET_MODE (folded_arg);
+
+       switch (GET_CODE (folded_arg))
+         {
+         case MEM:
+         case REG:
+         case SUBREG:
+           const_arg = equiv_constant (folded_arg);
+           break;
+
+         case CONST:
+         case CONST_INT:
+         case SYMBOL_REF:
+         case LABEL_REF:
+         case CONST_DOUBLE:
+         case CONST_VECTOR:
+           const_arg = folded_arg;
+           break;
+
 #ifdef HAVE_cc0
-       if (CC0_P (folded_arg))
-         folded_arg = prev_insn_cc0, mode_arg = prev_insn_cc0_mode;
+         case CC0:
+           folded_arg = prev_insn_cc0;
+           mode_arg = prev_insn_cc0_mode;
+           const_arg = equiv_constant (folded_arg);
+           break;
 #endif
-       const_arg = equiv_constant (folded_arg);
+
+         default:
+           folded_arg = fold_rtx (folded_arg, insn);
+           const_arg = equiv_constant (folded_arg);
+           break;
+         }
 
        /* For the first three operands, see if the operand
           is constant or equivalent to a constant.  */
@@ -4020,12 +4042,6 @@ cse_insn (rtx insn, rtx libcall_insn)
   rtx tem;
   int n_sets = 0;
 
-#ifdef HAVE_cc0
-  /* Records what this insn does to set CC0.  */
-  rtx this_insn_cc0 = 0;
-  enum machine_mode this_insn_cc0_mode = VOIDmode;
-#endif
-
   rtx src_eqv = 0;
   struct table_elt *src_eqv_elt = 0;
   int src_eqv_volatile = 0;
@@ -4035,6 +4051,11 @@ cse_insn (rtx insn, rtx libcall_insn)
   struct set *sets = (struct set *) 0;
 
   this_insn = insn;
+#ifdef HAVE_cc0
+  /* Records what this insn does to set CC0.  */
+  this_insn_cc0 = 0;
+  this_insn_cc0_mode = VOIDmode;
+#endif
 
   /* Find all the SETs and CLOBBERs in this instruction.
      Record all the SETs in the array `set' and count them.
@@ -4504,8 +4525,7 @@ cse_insn (rtx insn, rtx libcall_insn)
                   const_elt; const_elt = const_elt->next_same_value)
                if (REG_P (const_elt->exp))
                  {
-                   src_related = gen_lowpart (mode,
-                                                          const_elt->exp);
+                   src_related = gen_lowpart (mode, const_elt->exp);
                    break;
                  }
            }
@@ -4592,8 +4612,7 @@ cse_insn (rtx insn, rtx libcall_insn)
                   larger_elt; larger_elt = larger_elt->next_same_value)
                if (REG_P (larger_elt->exp))
                  {
-                   src_related = gen_lowpart (mode,
-                                                          larger_elt->exp);
+                   src_related = gen_lowpart (mode, larger_elt->exp);
                    break;
                  }
 
@@ -4863,13 +4882,6 @@ cse_insn (rtx insn, rtx libcall_insn)
              validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
              apply_change_group ();
 
-             /* With non-call exceptions, if this was an insn that could
-                trap, we may have made it non-throwing now.  For example
-                we may have replaced a load with a register.  */
-             if (flag_non_call_exceptions
-                 && insn == BB_END (BLOCK_FOR_INSN (insn)))
-               purge_dead_edges (BLOCK_FOR_INSN (insn));
-
              break;
            }
 
@@ -5269,8 +5281,11 @@ cse_insn (rtx insn, rtx libcall_insn)
                {
                  if (insert_regs (x, NULL, 0))
                    {
+                     rtx dest = SET_DEST (sets[i].rtl);
+
                      rehash_using_reg (x);
                      hash = HASH (x, mode);
+                     sets[i].dest_hash = HASH (dest, GET_MODE (dest));
                    }
                  elt = insert (x, NULL, hash, mode);
                }
@@ -5644,20 +5659,6 @@ cse_insn (rtx insn, rtx libcall_insn)
     }
 
 done:;
-#ifdef HAVE_cc0
-  /* If the previous insn set CC0 and this insn no longer references CC0,
-     delete the previous insn.  Here we use the fact that nothing expects CC0
-     to be valid over an insn, which is true until the final pass.  */
-  if (prev_insn && NONJUMP_INSN_P (prev_insn)
-      && (tem = single_set (prev_insn)) != 0
-      && SET_DEST (tem) == cc0_rtx
-      && ! reg_mentioned_p (cc0_rtx, x))
-    delete_insn_and_edges (prev_insn);
-
-  prev_insn_cc0 = this_insn_cc0;
-  prev_insn_cc0_mode = this_insn_cc0_mode;
-  prev_insn = insn;
-#endif
 }
 \f
 /* Remove from the hash table all expressions that reference memory.  */
@@ -5819,7 +5820,7 @@ cse_process_notes (rtx x, rtx object)
    Otherwise, DATA->path is filled and the function returns TRUE indicating
    that a path to follow was found.
 
-   If FOLLOW_JUMPS is false, the maximum path lenghth is 1 and the only
+   If FOLLOW_JUMPS is false, the maximum path length is 1 and the only
    block in the path will be FIRST_BB.  */
 
 static bool
@@ -5875,13 +5876,20 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
            {
              bb = FALLTHRU_EDGE (previous_bb_in_path)->dest;
              if (bb != EXIT_BLOCK_PTR
-                 && single_pred_p (bb))
+                 && single_pred_p (bb)
+                 /* We used to assert here that we would only see blocks
+                    that we have not visited yet.  But we may end up
+                    visiting basic blocks twice if the CFG has changed
+                    in this run of cse_main, because when the CFG changes
+                    the topological sort of the CFG also changes.  A basic
+                    blocks that previously had more than two predecessors
+                    may now have a single predecessor, and become part of
+                    a path that starts at another basic block.
+
+                    We still want to visit each basic block only once, so
+                    halt the path here if we have already visited BB.  */
+                 && !TEST_BIT (cse_visited_basic_blocks, bb->index))
                {
-#if ENABLE_CHECKING
-                 /* We should only see blocks here that we have not
-                    visited yet.  */
-                 gcc_assert (!TEST_BIT (cse_visited_basic_blocks, bb->index));
-#endif
                  SET_BIT (cse_visited_basic_blocks, bb->index);
                  data->path[path_size++].bb = bb;
                  break;
@@ -5920,15 +5928,12 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
            e = NULL;
 
          if (e && e->dest != EXIT_BLOCK_PTR
-             && single_pred_p (e->dest))
+             && single_pred_p (e->dest)
+             /* Avoid visiting basic blocks twice.  The large comment
+                above explains why this can happen.  */
+             && !TEST_BIT (cse_visited_basic_blocks, e->dest->index))
            {
              basic_block bb2 = e->dest;
-
-#if ENABLE_CHECKING
-             /* We should only see blocks here that we have not
-                visited yet.  */
-             gcc_assert (!TEST_BIT (cse_visited_basic_blocks, bb2->index));
-#endif
              SET_BIT (cse_visited_basic_blocks, bb2->index);
              data->path[path_size++].bb = bb2;
              bb = bb2;
@@ -5959,6 +5964,22 @@ cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
 }
 
 \f
+/* Return true if BB has exception handling successor edges.  */
+
+static bool
+have_eh_succ_edges (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (e->flags & EDGE_EH)
+      return true;
+
+  return false;
+}
+
+\f
 /* Scan to the end of the path described by DATA.  Return an estimate of
    the total number of SETs, and the lowest and highest insn CUID, of all
    insns in the path.  */
@@ -6096,18 +6117,44 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                  && for_each_rtx (&PATTERN (insn), check_for_label_ref,
                                   (void *) insn))
                recorded_label_ref = 1;
+
+#ifdef HAVE_cc0
+             /* If the previous insn set CC0 and this insn no longer
+                references CC0, delete the previous insn.  Here we use
+                fact that nothing expects CC0 to be valid over an insn,
+                which is true until the final pass.  */
+             {
+               rtx prev_insn, tem;
+
+               prev_insn = PREV_INSN (insn);
+               if (prev_insn && NONJUMP_INSN_P (prev_insn)
+                   && (tem = single_set (prev_insn)) != 0
+                   && SET_DEST (tem) == cc0_rtx
+                   && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+                 delete_insn (prev_insn);
+             }
+
+             /* If this insn is not the last insn in the basic block,
+                it will be PREV_INSN(insn) in the next iteration.  If
+                we recorded any CC0-related information for this insn,
+                remember it.  */
+             if (insn != BB_END (bb))
+               {
+                 prev_insn_cc0 = this_insn_cc0;
+                 prev_insn_cc0_mode = this_insn_cc0_mode;
+               }
+#endif
            }
        }
 
       /* Make sure that libcalls don't span multiple basic blocks.  */
       gcc_assert (libcall_insn == NULL_RTX);
 
-#ifdef HAVE_cc0
-      /* Clear the CC0-tracking related insns, they can't provide
-        useful information across basic block boundaries.  */
-      prev_insn_cc0 = 0;
-      prev_insn = 0;
-#endif
+      /* With non-call exceptions, we are not always able to update
+        the CFG properly inside cse_insn.  So clean up possibly
+        redundant EH edges here.  */
+      if (flag_non_call_exceptions && have_eh_succ_edges (bb))
+       purge_dead_edges (bb);
 
       /* If we changed a conditional jump, we may have terminated
         the path we are following.  Check that by verifying that
@@ -6118,7 +6165,21 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
        {
          basic_block next_bb = ebb_data->path[path_entry + 1].bb;
          if (!find_edge (bb, next_bb))
-           ebb_data->path_size = path_entry + 1;
+           {
+             do
+               {
+                 path_size--;
+
+                 /* If we truncate the path, we must also reset the
+                    visited bit on the remaining blocks in the path,
+                    or we will never visit them at all.  */
+                 RESET_BIT (cse_visited_basic_blocks,
+                            ebb_data->path[path_size].bb->index);
+                 ebb_data->path[path_size].bb = NULL;
+               }
+             while (path_size - 1 != path_entry);
+             ebb_data->path_size = path_size;
+           }
        }
 
       /* If this is a conditional jump insn, record any known
@@ -6133,6 +6194,12 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
          bool taken = (next_bb == BRANCH_EDGE (bb)->dest);
          record_jump_equiv (insn, taken);
        }
+
+#ifdef HAVE_cc0
+      /* Clear the CC0-tracking related insns, they can't provide
+        useful information across basic block boundaries.  */
+      prev_insn_cc0 = 0;
+#endif
     }
 
   gcc_assert (next_qty <= max_qty);
@@ -6152,7 +6219,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
 {
   struct cse_basic_block_data ebb_data;
   basic_block bb;
-  int *dfs_order = XNEWVEC (int, last_basic_block);
+  int *rc_order = XNEWVEC (int, last_basic_block);
   int i, n_blocks;
 
   init_cse_reg_info (nregs);
@@ -6190,17 +6257,17 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
        INSN_CUID (insn) = ++i;
     }
 
-  /* Loop over basic blocks in DFS order,
+  /* Loop over basic blocks in reverse completion order (RPO),
      excluding the ENTRY and EXIT blocks.  */
-  n_blocks = pre_and_rev_post_order_compute (dfs_order, NULL, false);
+  n_blocks = pre_and_rev_post_order_compute (NULL, rc_order, false);
   i = 0;
   while (i < n_blocks)
     {
-      /* Find the first block in the DFS queue that we have not yet
+      /* Find the first block in the RPO queue that we have not yet
         processed before.  */
       do
        {
-         bb = BASIC_BLOCK (dfs_order[i++]);
+         bb = BASIC_BLOCK (rc_order[i++]);
        }
       while (TEST_BIT (cse_visited_basic_blocks, bb->index)
             && i < n_blocks);
@@ -6215,7 +6282,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
          if (ebb_data.nsets == 0)
            continue;
 
-         /* Get a reasonable extimate for the maximum number of qty's
+         /* Get a reasonable estimate for the maximum number of qty's
             needed for this path.  For this, we take the number of sets
             and multiply that by MAX_RECOG_OPERANDS.  */
          max_qty = ebb_data.nsets * MAX_RECOG_OPERANDS;
@@ -6236,7 +6303,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   free (reg_eqv_table);
   free (ebb_data.path);
   sbitmap_free (cse_visited_basic_blocks);
-  free (dfs_order);
+  free (rc_order);
   rtl_hooks = general_rtl_hooks;
 
   return cse_jumps_altered || recorded_label_ref;
@@ -6956,9 +7023,7 @@ gate_handle_cse (void)
 static unsigned int
 rest_of_handle_cse (void)
 {
-static int counter = 0;
   int tem;
-counter++;
   if (dump_file)
     dump_flow_info (dump_file, dump_flags);
 
@@ -6970,10 +7035,6 @@ counter++;
      expecting CSE to be run.  But always rerun it in a cheap mode.  */
   cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
 
-  /* If there are dead edges to purge, we haven't properly updated
-     the CFG incrementally.  */
-  gcc_assert (!purge_all_dead_edges ());
-
   if (tem)
     rebuild_jump_labels (get_insns ());
 
@@ -7026,10 +7087,6 @@ rest_of_handle_cse2 (void)
      bypassed safely.  */
   cse_condition_code_reg ();
 
-  /* If there are dead edges to purge, we haven't properly updated
-     the CFG incrementally.  */
-  gcc_assert (!purge_all_dead_edges ());
-
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
 
   if (tem)