OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / postreload-gcse.c
index 79b11ee..16f3f68 100644 (file)
@@ -1,12 +1,12 @@
 /* Post reload partially redundant load elimination
 /* Post reload partially redundant load elimination
-   Copyright (C) 2004, 2005
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,15 +15,14 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 
 #include "rtl.h"
 #include "tree.h"
 
 #include "rtl.h"
 #include "tree.h"
@@ -31,7 +30,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
-#include "real.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "basic-block.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "basic-block.h"
@@ -44,6 +42,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "hashtab.h"
 #include "params.h"
 #include "target.h"
 #include "hashtab.h"
 #include "params.h"
 #include "target.h"
+#include "timevar.h"
+#include "tree-pass.h"
+#include "dbgcnt.h"
 
 /* The following code implements gcse after reload, the purpose of this
    pass is to cleanup redundant loads generated by reload and other
 
 /* The following code implements gcse after reload, the purpose of this
    pass is to cleanup redundant loads generated by reload and other
@@ -173,12 +174,13 @@ static void free_mem (void);
 
 /* Support for hash table construction and transformations.  */
 static bool oprs_unchanged_p (rtx, rtx, bool);
 
 /* Support for hash table construction and transformations.  */
 static bool oprs_unchanged_p (rtx, rtx, bool);
-static void record_last_reg_set_info (rtx, int);
+static void record_last_reg_set_info (rtx, rtx);
+static void record_last_reg_set_info_regno (rtx, int);
 static void record_last_mem_set_info (rtx);
 static void record_last_mem_set_info (rtx);
-static void record_last_set_info (rtx, rtx, void *);
+static void record_last_set_info (rtx, const_rtx, void *);
 static void record_opr_changes (rtx);
 
 static void record_opr_changes (rtx);
 
-static void find_mem_conflicts (rtx, rtx, void *);
+static void find_mem_conflicts (rtx, const_rtx, void *);
 static int load_killed_in_block_p (int, rtx, bool);
 static void reset_opr_set_tables (void);
 
 static int load_killed_in_block_p (int, rtx, bool);
 static void reset_opr_set_tables (void);
 
@@ -195,8 +197,6 @@ static void dump_hash_table (FILE *);
 static bool reg_killed_on_edge (rtx, edge);
 static bool reg_used_on_edge (rtx, edge);
 
 static bool reg_killed_on_edge (rtx, edge);
 static bool reg_used_on_edge (rtx, edge);
 
-static rtx reg_set_between_after_reload_p (rtx, rtx, rtx);
-static rtx reg_used_between_after_reload_p (rtx, rtx, rtx);
 static rtx get_avail_load_store_reg (rtx);
 
 static bool bb_has_well_behaved_predecessors (basic_block);
 static rtx get_avail_load_store_reg (rtx);
 
 static bool bb_has_well_behaved_predecessors (basic_block);
@@ -222,8 +222,8 @@ alloc_mem (void)
   rtx insn;
 
   /* Find the largest UID and create a mapping from UIDs to CUIDs.  */
   rtx insn;
 
   /* Find the largest UID and create a mapping from UIDs to CUIDs.  */
-  uid_cuid = xcalloc (get_max_uid () + 1, sizeof (int));
-  i = 0;
+  uid_cuid = XCNEWVEC (int, get_max_uid () + 1);
+  i = 1;
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
       {
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
       {
@@ -296,7 +296,7 @@ hash_expr (rtx x, int *do_not_record_p)
 static hashval_t
 hash_expr_for_htab (const void *expp)
 {
 static hashval_t
 hash_expr_for_htab (const void *expp)
 {
-  struct expr *exp = (struct expr *) expp;
+  const struct expr *const exp = (const struct expr *) expp;
   return exp->hash;
 }
 
   return exp->hash;
 }
 
@@ -306,10 +306,10 @@ hash_expr_for_htab (const void *expp)
 static int
 expr_equiv_p (const void *exp1p, const void *exp2p)
 {
 static int
 expr_equiv_p (const void *exp1p, const void *exp2p)
 {
-  struct expr *exp1 = (struct expr *) exp1p;
-  struct expr *exp2 = (struct expr *) exp2p;
+  const struct expr *const exp1 = (const struct expr *) exp1p;
+  const struct expr *const exp2 = (const struct expr *) exp2p;
   int equiv_p = exp_equiv_p (exp1->expr, exp2->expr, 0, true);
   int equiv_p = exp_equiv_p (exp1->expr, exp2->expr, 0, true);
-  
+
   gcc_assert (!equiv_p || exp1->hash == exp2->hash);
   return equiv_p;
 }
   gcc_assert (!equiv_p || exp1->hash == exp2->hash);
   return equiv_p;
 }
@@ -348,7 +348,7 @@ insert_expr_in_table (rtx x, rtx insn)
 
   slot = (struct expr **) htab_find_slot_with_hash (expr_table, cur_expr,
                                                    hash, INSERT);
 
   slot = (struct expr **) htab_find_slot_with_hash (expr_table, cur_expr,
                                                    hash, INSERT);
-  
+
   if (! (*slot))
     /* The expression isn't found, so insert it.  */
     *slot = cur_expr;
   if (! (*slot))
     /* The expression isn't found, so insert it.  */
     *slot = cur_expr;
@@ -362,7 +362,8 @@ insert_expr_in_table (rtx x, rtx insn)
 
   /* Search for another occurrence in the same basic block.  */
   avail_occr = cur_expr->avail_occr;
 
   /* Search for another occurrence in the same basic block.  */
   avail_occr = cur_expr->avail_occr;
-  while (avail_occr && BLOCK_NUM (avail_occr->insn) != BLOCK_NUM (insn))
+  while (avail_occr
+        && BLOCK_FOR_INSN (avail_occr->insn) != BLOCK_FOR_INSN (insn))
     {
       /* If an occurrence isn't found, save a pointer to the end of
         the list.  */
     {
       /* If an occurrence isn't found, save a pointer to the end of
         the list.  */
@@ -439,7 +440,7 @@ dump_hash_table_entry (void **slot, void *filep)
   fprintf (file, "expr: ");
   print_rtl (file, expr->expr);
   fprintf (file,"\nhashcode: %u\n", expr->hash);
   fprintf (file, "expr: ");
   print_rtl (file, expr->expr);
   fprintf (file,"\nhashcode: %u\n", expr->hash);
-  fprintf (file,"list of occurences:\n");
+  fprintf (file,"list of occurrences:\n");
   occr = expr->avail_occr;
   while (occr)
     {
   occr = expr->avail_occr;
   while (occr)
     {
@@ -468,6 +469,22 @@ dump_hash_table (FILE *file)
   fprintf (file, "\n");
 }
 \f
   fprintf (file, "\n");
 }
 \f
+/* Return true if register X is recorded as being set by an instruction
+   whose CUID is greater than the one given.  */
+
+static bool
+reg_changed_after_insn_p (rtx x, int cuid)
+{
+  unsigned int regno, end_regno;
+
+  regno = REGNO (x);
+  end_regno = END_HARD_REGNO (x);
+  do
+    if (reg_avail_info[regno] > cuid)
+      return true;
+  while (++regno < end_regno);
+  return false;
+}
 
 /* Return nonzero if the operands of expression X are unchanged
    1) from the start of INSN's basic block up to but not including INSN
 
 /* Return nonzero if the operands of expression X are unchanged
    1) from the start of INSN's basic block up to but not including INSN
@@ -491,14 +508,9 @@ oprs_unchanged_p (rtx x, rtx insn, bool after_insn)
       /* We are called after register allocation.  */
       gcc_assert (REGNO (x) < FIRST_PSEUDO_REGISTER);
       if (after_insn)
       /* We are called after register allocation.  */
       gcc_assert (REGNO (x) < FIRST_PSEUDO_REGISTER);
       if (after_insn)
-       /* If the last CUID setting the insn is less than the CUID of
-          INSN, then reg X is not changed in or after INSN.  */
-       return reg_avail_info[REGNO (x)] < INSN_CUID (insn);
+       return !reg_changed_after_insn_p (x, INSN_CUID (insn) - 1);
       else
       else
-       /* Reg X is not set before INSN in the current basic block if
-          we have not yet recorded the CUID of an insn that touches
-          the reg.  */
-       return reg_avail_info[REGNO (x)] == 0;
+       return !reg_changed_after_insn_p (x, 0);
 
     case MEM:
       if (load_killed_in_block_p (INSN_CUID (insn), x, after_insn))
 
     case MEM:
       if (load_killed_in_block_p (INSN_CUID (insn), x, after_insn))
@@ -511,6 +523,7 @@ oprs_unchanged_p (rtx x, rtx insn, bool after_insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -560,7 +573,7 @@ static int mems_conflict_p;
    to a nonzero value.  */
 
 static void
    to a nonzero value.  */
 
 static void
-find_mem_conflicts (rtx dest, rtx setter ATTRIBUTE_UNUSED,
+find_mem_conflicts (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
                    void *data)
 {
   rtx mem_op = (rtx) data;
                    void *data)
 {
   rtx mem_op = (rtx) data;
@@ -576,8 +589,7 @@ find_mem_conflicts (rtx dest, rtx setter ATTRIBUTE_UNUSED,
   if (! MEM_P (dest))
     return;
 
   if (! MEM_P (dest))
     return;
 
-  if (true_dependence (dest, GET_MODE (dest), mem_op,
-                      rtx_addr_varies_p))
+  if (true_dependence (dest, GET_MODE (dest), mem_op))
     mems_conflict_p = 1;
 }
 \f
     mems_conflict_p = 1;
 }
 \f
@@ -633,7 +645,19 @@ load_killed_in_block_p (int uid_limit, rtx x, bool after_insn)
 /* Record register first/last/block set information for REGNO in INSN.  */
 
 static inline void
 /* Record register first/last/block set information for REGNO in INSN.  */
 
 static inline void
-record_last_reg_set_info (rtx insn, int regno)
+record_last_reg_set_info (rtx insn, rtx reg)
+{
+  unsigned int regno, end_regno;
+
+  regno = REGNO (reg);
+  end_regno = END_HARD_REGNO (reg);
+  do
+    reg_avail_info[regno] = INSN_CUID (insn);
+  while (++regno < end_regno);
+}
+
+static inline void
+record_last_reg_set_info_regno (rtx insn, int regno)
 {
   reg_avail_info[regno] = INSN_CUID (insn);
 }
 {
   reg_avail_info[regno] = INSN_CUID (insn);
 }
@@ -660,7 +684,7 @@ record_last_mem_set_info (rtx insn)
    the SET is taking place.  */
 
 static void
    the SET is taking place.  */
 
 static void
-record_last_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
+record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data)
 {
   rtx last_set_insn = (rtx) data;
 
 {
   rtx last_set_insn = (rtx) data;
 
@@ -668,11 +692,19 @@ record_last_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data)
     dest = SUBREG_REG (dest);
 
   if (REG_P (dest))
     dest = SUBREG_REG (dest);
 
   if (REG_P (dest))
-    record_last_reg_set_info (last_set_insn, REGNO (dest));
-  else if (MEM_P (dest)
-          /* Ignore pushes, they clobber nothing.  */
-          && ! push_operand (dest, GET_MODE (dest)))
-    record_last_mem_set_info (last_set_insn);
+    record_last_reg_set_info (last_set_insn, dest);
+  else if (MEM_P (dest))
+    {
+      /* Ignore pushes, they don't clobber memory.  They may still
+        clobber the stack pointer though.  Some targets do argument
+        pushes without adding REG_INC notes.  See e.g. PR25196,
+        where a pushsi2 on i386 doesn't have REG_INC notes.  Note
+        such changes here too.  */
+      if (! push_operand (dest, GET_MODE (dest)))
+       record_last_mem_set_info (last_set_insn);
+      else
+       record_last_reg_set_info_regno (last_set_insn, STACK_POINTER_REGNUM);
+    }
 }
 
 
 }
 
 
@@ -702,18 +734,30 @@ record_opr_changes (rtx insn)
   /* Also record autoincremented REGs for this insn as changed.  */
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     if (REG_NOTE_KIND (note) == REG_INC)
   /* Also record autoincremented REGs for this insn as changed.  */
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     if (REG_NOTE_KIND (note) == REG_INC)
-      record_last_reg_set_info (insn, REGNO (XEXP (note, 0)));
+      record_last_reg_set_info (insn, XEXP (note, 0));
 
   /* Finally, if this is a call, record all call clobbers.  */
   if (CALL_P (insn))
     {
       unsigned int regno;
 
   /* Finally, if this is a call, record all call clobbers.  */
   if (CALL_P (insn))
     {
       unsigned int regno;
+      rtx link, x;
 
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
 
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
-         record_last_reg_set_info (insn, regno);
-
-      if (! CONST_OR_PURE_CALL_P (insn))
+         record_last_reg_set_info_regno (insn, regno);
+
+      for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+       if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+         {
+           x = XEXP (XEXP (link, 0), 0);
+           if (REG_P (x))
+             {
+               gcc_assert (HARD_REGISTER_P (x));
+               record_last_reg_set_info (insn, x);
+             }
+         }
+
+      if (! RTL_CONST_OR_PURE_CALL_P (insn))
        record_last_mem_set_info (insn);
     }
 }
        record_last_mem_set_info (insn);
     }
 }
@@ -737,15 +781,18 @@ hash_scan_set (rtx insn)
   if (JUMP_P (insn) || set_noop_p (pat))
     return;
 
   if (JUMP_P (insn) || set_noop_p (pat))
     return;
 
-  /* We shouldn't have any EH_REGION notes post reload.  */
-  gcc_assert (!find_reg_note (insn, REG_EH_REGION, NULL_RTX));
-
   if (REG_P (dest))
     {
       if (/* Don't CSE something if we can't do a reg/reg copy.  */
          can_copy_p (GET_MODE (dest))
          /* Is SET_SRC something we want to gcse?  */
          && general_operand (src, GET_MODE (src))
   if (REG_P (dest))
     {
       if (/* Don't CSE something if we can't do a reg/reg copy.  */
          can_copy_p (GET_MODE (dest))
          /* Is SET_SRC something we want to gcse?  */
          && general_operand (src, GET_MODE (src))
+#ifdef STACK_REGS
+         /* Never consider insns touching the register stack.  It may
+            create situations that reg-stack cannot handle (e.g. a stack
+            register live across an abnormal edge).  */
+         && (REGNO (dest) < FIRST_STACK_REG || REGNO (dest) > LAST_STACK_REG)
+#endif
          /* An expression is not available if its operands are
             subsequently modified, including this insn.  */
          && oprs_unchanged_p (src, insn, true))
          /* An expression is not available if its operands are
             subsequently modified, including this insn.  */
          && oprs_unchanged_p (src, insn, true))
@@ -760,6 +807,10 @@ hash_scan_set (rtx insn)
          can_copy_p (GET_MODE (src))
          /* Is SET_DEST something we want to gcse?  */
          && general_operand (dest, GET_MODE (dest))
          can_copy_p (GET_MODE (src))
          /* Is SET_DEST something we want to gcse?  */
          && general_operand (dest, GET_MODE (dest))
+#ifdef STACK_REGS
+         /* As above for STACK_REGS.  */
+         && (REGNO (src) < FIRST_STACK_REG || REGNO (src) > LAST_STACK_REG)
+#endif
          && ! (flag_float_store && FLOAT_MODE_P (GET_MODE (dest)))
          /* Check if the memory expression is killed after insn.  */
          && ! load_killed_in_block_p (INSN_CUID (insn) + 1, dest, true)
          && ! (flag_float_store && FLOAT_MODE_P (GET_MODE (dest)))
          /* Check if the memory expression is killed after insn.  */
          && ! load_killed_in_block_p (INSN_CUID (insn) + 1, dest, true)
@@ -839,96 +890,6 @@ reg_used_on_edge (rtx reg, edge e)
   return false;
 }
 \f
   return false;
 }
 \f
-
-/* Return the insn that sets register REG or clobbers it in between
-   FROM_INSN and TO_INSN (exclusive of those two).
-   Just like reg_set_between but for hard registers and not pseudos.  */
-
-static rtx
-reg_set_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn)
-{
-  rtx insn;
-
-  /* We are called after register allocation.  */
-  gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
-
-  if (from_insn == to_insn)
-    return NULL_RTX;
-
-  for (insn = NEXT_INSN (from_insn);
-       insn != to_insn;
-       insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      {
-       if (set_of (reg, insn) != NULL_RTX)
-         return insn;
-       if ((CALL_P (insn)
-             && call_used_regs[REGNO (reg)])
-           || find_reg_fusage (insn, CLOBBER, reg))
-         return insn;
-
-       if (FIND_REG_INC_NOTE (insn, reg))
-         return insn;
-      }
-
-  return NULL_RTX;
-}
-
-/* Return the insn that uses register REG in between FROM_INSN and TO_INSN
-   (exclusive of those two). Similar to reg_used_between but for hard
-   registers and not pseudos.  */
-
-static rtx
-reg_used_between_after_reload_p (rtx reg, rtx from_insn, rtx to_insn)
-{
-  rtx insn;
-
-  /* We are called after register allocation.  */
-  gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
-
-  if (from_insn == to_insn)
-    return NULL_RTX;
-
-  for (insn = NEXT_INSN (from_insn);
-       insn != to_insn;
-       insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      {
-       if (reg_overlap_mentioned_p (reg, PATTERN (insn))
-           || (CALL_P (insn)
-               && call_used_regs[REGNO (reg)])
-           || find_reg_fusage (insn, USE, reg)
-           || find_reg_fusage (insn, CLOBBER, reg))
-         return insn;
-
-       if (FIND_REG_INC_NOTE (insn, reg))
-         return insn;
-      }
-
-  return NULL_RTX;
-}
-
-/* Return true if REG is used, set, or killed between the beginning of
-   basic block BB and UP_TO_INSN.  Caches the result in reg_avail_info.  */
-
-static bool
-reg_set_or_used_since_bb_start (rtx reg, basic_block bb, rtx up_to_insn)
-{
-  rtx insn, start = PREV_INSN (BB_HEAD (bb));
-
-  if (reg_avail_info[REGNO (reg)] != 0)
-    return true;
-
-  insn = reg_used_between_after_reload_p (reg, start, up_to_insn);
-  if (! insn)
-    insn = reg_set_between_after_reload_p (reg, start, up_to_insn);
-
-  if (insn)
-    reg_avail_info[REGNO (reg)] = INSN_CUID (insn);
-
-  return insn != NULL_RTX;
-}
-
 /* Return the loaded/stored register of a load/store instruction.  */
 
 static rtx
 /* Return the loaded/stored register of a load/store instruction.  */
 
 static rtx
@@ -961,6 +922,9 @@ bb_has_well_behaved_predecessors (basic_block bb)
       if ((pred->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (pred))
        return false;
 
       if ((pred->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (pred))
        return false;
 
+      if ((pred->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
+       return false;
+
       if (JUMP_TABLE_DATA_P (BB_END (pred->src)))
        return false;
     }
       if (JUMP_TABLE_DATA_P (BB_END (pred->src)))
        return false;
     }
@@ -1008,6 +972,7 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
   gcov_type ok_count = 0; /* Redundant load execution count.  */
   gcov_type critical_count = 0; /* Execution count of critical edges.  */
   edge_iterator ei;
   gcov_type ok_count = 0; /* Redundant load execution count.  */
   gcov_type critical_count = 0; /* Execution count of critical edges.  */
   edge_iterator ei;
+  bool critical_edge_split = false;
 
   /* The execution count of the loads to be added to make the
      load fully redundant.  */
 
   /* The execution count of the loads to be added to make the
      load fully redundant.  */
@@ -1019,7 +984,8 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
 
   /* Check that the loaded register is not used, set, or killed from the
      beginning of the block.  */
 
   /* Check that the loaded register is not used, set, or killed from the
      beginning of the block.  */
-  if (reg_set_or_used_since_bb_start (dest, bb, insn))
+  if (reg_changed_after_insn_p (dest, 0)
+      || reg_used_between_p (dest, PREV_INSN (BB_HEAD (bb)), insn))
     return;
 
   /* Check potential for replacing load with copy for predecessors.  */
     return;
 
   /* Check potential for replacing load with copy for predecessors.  */
@@ -1028,6 +994,7 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
       rtx next_pred_bb_end;
 
       avail_insn = NULL_RTX;
       rtx next_pred_bb_end;
 
       avail_insn = NULL_RTX;
+      avail_reg = NULL_RTX;
       pred_bb = pred->src;
       next_pred_bb_end = NEXT_INSN (BB_END (pred_bb));
       for (a_occr = get_bb_avail_insn (pred_bb, expr->avail_occr); a_occr;
       pred_bb = pred->src;
       next_pred_bb_end = NEXT_INSN (BB_END (pred_bb));
       for (a_occr = get_bb_avail_insn (pred_bb, expr->avail_occr); a_occr;
@@ -1037,7 +1004,7 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
          avail_insn = a_occr->insn;
          avail_reg = get_avail_load_store_reg (avail_insn);
          gcc_assert (avail_reg);
          avail_insn = a_occr->insn;
          avail_reg = get_avail_load_store_reg (avail_insn);
          gcc_assert (avail_reg);
-         
+
          /* Make sure we can generate a move from register avail_reg to
             dest.  */
          extract_insn (gen_move_insn (copy_rtx (dest),
          /* Make sure we can generate a move from register avail_reg to
             dest.  */
          extract_insn (gen_move_insn (copy_rtx (dest),
@@ -1049,8 +1016,7 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
              avail_insn = NULL;
              continue;
            }
              avail_insn = NULL;
              continue;
            }
-         if (! reg_set_between_after_reload_p (avail_reg, avail_insn,
-                                               next_pred_bb_end))
+         if (!reg_set_between_p (avail_reg, avail_insn, next_pred_bb_end))
            /* AVAIL_INSN remains non-null.  */
            break;
          else
            /* AVAIL_INSN remains non-null.  */
            break;
          else
@@ -1064,8 +1030,17 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
        {
          npred_ok++;
          ok_count += pred->count;
        {
          npred_ok++;
          ok_count += pred->count;
+         if (! set_noop_p (PATTERN (gen_move_insn (copy_rtx (dest),
+                                                   copy_rtx (avail_reg)))))
+           {
+             /* Check if there is going to be a split.  */
+             if (EDGE_CRITICAL_P (pred))
+               critical_edge_split = true;
+           }
+         else /* Its a dead move no need to generate.  */
+           continue;
          occr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
          occr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
-                                                 sizeof (struct occr));
+                                                 sizeof (struct unoccr));
          occr->insn = avail_insn;
          occr->pred = pred;
          occr->next = avail_occrs;
          occr->insn = avail_insn;
          occr->pred = pred;
          occr->next = avail_occrs;
@@ -1075,6 +1050,9 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
        }
       else
        {
        }
       else
        {
+         /* Adding a load on a critical edge will cause a split.  */
+         if (EDGE_CRITICAL_P (pred))
+           critical_edge_split = true;
          not_ok_count += pred->count;
          unoccr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
                                                    sizeof (struct unoccr));
          not_ok_count += pred->count;
          unoccr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
                                                    sizeof (struct unoccr));
@@ -1089,8 +1067,13 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
 
   if (/* No load can be replaced by copy.  */
       npred_ok == 0
 
   if (/* No load can be replaced by copy.  */
       npred_ok == 0
-      /* Prevent exploding the code.  */ 
-      || (optimize_size && npred_ok > 1))
+      /* Prevent exploding the code.  */
+      || (optimize_bb_for_size_p (bb) && npred_ok > 1)
+      /* If we don't have profile information we cannot tell if splitting
+         a critical edge is profitable or not so don't do it.  */
+      || ((! profile_info || ! flag_branch_probabilities
+          || targetm.cannot_modify_jumps_p ())
+         && critical_edge_split))
     goto cleanup;
 
   /* Check if it's worth applying the partial redundancy elimination.  */
     goto cleanup;
 
   /* Check if it's worth applying the partial redundancy elimination.  */
@@ -1147,10 +1130,21 @@ eliminate_partially_redundant_load (basic_block bb, rtx insn,
      discover additional redundancies, so mark it for later deletion.  */
   for (a_occr = get_bb_avail_insn (bb, expr->avail_occr);
        a_occr && (a_occr->insn != insn);
      discover additional redundancies, so mark it for later deletion.  */
   for (a_occr = get_bb_avail_insn (bb, expr->avail_occr);
        a_occr && (a_occr->insn != insn);
-       a_occr = get_bb_avail_insn (bb, a_occr->next));
+       a_occr = get_bb_avail_insn (bb, a_occr->next))
+    ;
 
   if (!a_occr)
 
   if (!a_occr)
-    delete_insn (insn);
+    {
+      stats.insns_deleted++;
+
+      if (dump_file)
+       {
+         fprintf (dump_file, "deleting insn:\n");
+          print_rtl_single (dump_file, insn);
+          fprintf (dump_file, "\n");
+       }
+      delete_insn (insn);
+    }
   else
     a_occr->deleted_p = 1;
 
   else
     a_occr->deleted_p = 1;
 
@@ -1182,7 +1176,7 @@ eliminate_partially_redundant_loads (void)
        continue;
 
       /* Do not try anything on cold basic blocks.  */
        continue;
 
       /* Do not try anything on cold basic blocks.  */
-      if (probably_cold_bb_p (bb))
+      if (optimize_bb_for_size_p (bb))
        continue;
 
       /* Reset the table of things changed since the start of the current
        continue;
 
       /* Reset the table of things changed since the start of the current
@@ -1209,7 +1203,7 @@ eliminate_partially_redundant_loads (void)
                  /* Are the operands unchanged since the start of the
                     block?  */
                  && oprs_unchanged_p (src, insn, false)
                  /* Are the operands unchanged since the start of the
                     block?  */
                  && oprs_unchanged_p (src, insn, false)
-                 && !(flag_non_call_exceptions && may_trap_p (src))
+                 && !(cfun->can_throw_non_call_exceptions && may_trap_p (src))
                  && !side_effects_p (src)
                  /* Is the expression recorded?  */
                  && (expr = lookup_expr_in_table (src)) != NULL)
                  && !side_effects_p (src)
                  /* Is the expression recorded?  */
                  && (expr = lookup_expr_in_table (src)) != NULL)
@@ -1244,7 +1238,7 @@ delete_redundant_insns_1 (void **slot, void *data ATTRIBUTE_UNUSED)
 
   for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
     {
 
   for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
     {
-      if (occr->deleted_p)
+      if (occr->deleted_p && dbg_cnt (gcse2_delete))
        {
          delete_insn (occr->insn);
          stats.insns_deleted++;
        {
          delete_insn (occr->insn);
          stats.insns_deleted++;
@@ -1272,16 +1266,13 @@ delete_redundant_insns (void)
 /* Main entry point of the GCSE after reload - clean some redundant loads
    due to spilling.  */
 
 /* Main entry point of the GCSE after reload - clean some redundant loads
    due to spilling.  */
 
-void
+static void
 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
 {
 
 gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
 {
 
-  if (targetm.cannot_modify_jumps_p ())
-    return;
-
   memset (&stats, 0, sizeof (stats));
 
   memset (&stats, 0, sizeof (stats));
 
-  /* Allocate ememory for this pass.
+  /* Allocate memory for this pass.
      Also computes and initializes the insns' CUIDs.  */
   alloc_mem ();
 
      Also computes and initializes the insns' CUIDs.  */
   alloc_mem ();
 
@@ -1306,11 +1297,54 @@ gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
          fprintf (dump_file, "insns deleted:   %d\n", stats.insns_deleted);
          fprintf (dump_file, "\n\n");
        }
          fprintf (dump_file, "insns deleted:   %d\n", stats.insns_deleted);
          fprintf (dump_file, "\n\n");
        }
+
+      statistics_counter_event (cfun, "copies inserted",
+                               stats.copies_inserted);
+      statistics_counter_event (cfun, "moves inserted",
+                               stats.moves_inserted);
+      statistics_counter_event (cfun, "insns deleted",
+                               stats.insns_deleted);
     }
     }
-    
+
   /* We are finished with alias.  */
   end_alias_analysis ();
 
   free_mem ();
 }
 
   /* We are finished with alias.  */
   end_alias_analysis ();
 
   free_mem ();
 }
 
+\f
+static bool
+gate_handle_gcse2 (void)
+{
+  return (optimize > 0 && flag_gcse_after_reload
+         && optimize_function_for_speed_p (cfun));
+}
+
+
+static unsigned int
+rest_of_handle_gcse2 (void)
+{
+  gcse_after_reload_main (get_insns ());
+  rebuild_jump_labels (get_insns ());
+  return 0;
+}
+
+struct rtl_opt_pass pass_gcse2 =
+{
+ {
+  RTL_PASS,
+  "gcse2",                              /* name */
+  gate_handle_gcse2,                    /* gate */
+  rest_of_handle_gcse2,                 /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_GCSE_AFTER_RELOAD,                 /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_verify_rtl_sharing
+  | TODO_verify_flow | TODO_ggc_collect /* todo_flags_finish */
+ }
+};