OSDN Git Service

2009-09-27 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / sched-deps.c
index b8b3a44..fdc98fb 100644 (file)
@@ -1,7 +1,7 @@
 /* Instruction scheduling pass.  This file computes dependencies between
    instructions.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "sched-int.h"
 #include "params.h"
 #include "cselib.h"
+#include "ira.h"
+#include "target.h"
 
 #ifdef INSN_SCHEDULING
 
@@ -50,6 +52,12 @@ along with GCC; see the file COPYING3.  If not see
 #define CHECK (false)
 #endif
 
+/* Holds current parameters for the dependency analyzer.  */
+struct sched_deps_info_def *sched_deps_info;
+
+/* The data is specific to the Haifa scheduler.  */
+VEC(haifa_deps_insn_data_def, heap) *h_d_i_d = NULL;
+
 /* Return the major type present in the DS.  */
 enum reg_note
 ds_to_dk (ds_t ds)
@@ -204,6 +212,16 @@ sd_debug_dep (dep_t dep)
   fprintf (stderr, "\n");
 }
 
+/* Determine whether DEP is a dependency link of a non-debug insn on a
+   debug insn.  */
+
+static inline bool
+depl_on_debug_p (dep_link_t dep)
+{
+  return (DEBUG_INSN_P (DEP_LINK_PRO (dep))
+         && !DEBUG_INSN_P (DEP_LINK_CON (dep)));
+}
+
 /* Functions to operate with a single link from the dependencies lists -
    dep_link_t.  */
 
@@ -239,7 +257,9 @@ add_to_deps_list (dep_link_t link, deps_list_t l)
 {
   attach_dep_link (link, &DEPS_LIST_FIRST (l));
 
-  ++DEPS_LIST_N_LINKS (l);
+  /* Don't count debug deps.  */
+  if (!depl_on_debug_p (link))
+    ++DEPS_LIST_N_LINKS (l);
 }
 
 /* Detach dep_link L from the list.  */
@@ -264,7 +284,9 @@ remove_from_deps_list (dep_link_t link, deps_list_t list)
 {
   detach_dep_link (link);
 
-  --DEPS_LIST_N_LINKS (list);
+  /* Don't count debug deps.  */
+  if (!depl_on_debug_p (link))
+    --DEPS_LIST_N_LINKS (list);
 }
 
 /* Move link LINK from list FROM to list TO.  */
@@ -388,19 +410,17 @@ clear_deps_list (deps_list_t l)
 static regset reg_pending_sets;
 static regset reg_pending_clobbers;
 static regset reg_pending_uses;
-
-/* The following enumeration values tell us what dependencies we
-   should use to implement the barrier.  We use true-dependencies for
-   TRUE_BARRIER and anti-dependencies for MOVE_BARRIER.  */
-enum reg_pending_barrier_mode
-{
-  NOT_A_BARRIER = 0,
-  MOVE_BARRIER,
-  TRUE_BARRIER
-};
-
 static enum reg_pending_barrier_mode reg_pending_barrier;
 
+/* Hard registers implicitly clobbered or used (or may be implicitly
+   clobbered or used) by the currently analyzed insn.  For example,
+   insn in its constraint has one register class.  Even if there is
+   currently no hard register in the insn, the particular hard
+   register will be in the insn after reload pass because the
+   constraint requires it.  */
+static HARD_REG_SET implicit_reg_pending_clobbers;
+static HARD_REG_SET implicit_reg_pending_uses;
+
 /* To speed up the test for duplicate dependency links we keep a
    record of dependencies created by add_dependence when the average
    number of instructions in a basic block is very large.
@@ -414,15 +434,16 @@ static enum reg_pending_barrier_mode reg_pending_barrier;
    has enough entries to represent a dependency on any other insn in
    the insn chain.  All bitmap for true dependencies cache is
    allocated then the rest two ones are also allocated.  */
-static bitmap_head *true_dependency_cache;
-static bitmap_head *output_dependency_cache;
-static bitmap_head *anti_dependency_cache;
-static bitmap_head *spec_dependency_cache;
+static bitmap_head *true_dependency_cache = NULL;
+static bitmap_head *output_dependency_cache = NULL;
+static bitmap_head *anti_dependency_cache = NULL;
+static bitmap_head *spec_dependency_cache = NULL;
 static int cache_size;
 
 static int deps_may_trap_p (const_rtx);
 static void add_dependence_list (rtx, rtx, int, enum reg_note);
-static void add_dependence_list_and_free (rtx, rtx *, int, enum reg_note);
+static void add_dependence_list_and_free (struct deps *, rtx,
+                                         rtx *, int, enum reg_note);
 static void delete_all_dependences (rtx);
 static void fixup_sched_groups (rtx);
 
@@ -431,14 +452,13 @@ static void sched_analyze_1 (struct deps *, rtx, rtx);
 static void sched_analyze_2 (struct deps *, rtx, rtx);
 static void sched_analyze_insn (struct deps *, rtx, rtx);
 
-static rtx sched_get_condition (const_rtx);
-static int conditions_mutex_p (const_rtx, const_rtx);
+static bool sched_has_condition_p (const_rtx);
+static int conditions_mutex_p (const_rtx, const_rtx, bool, bool);
 
 static enum DEPS_ADJUST_RESULT maybe_add_or_update_dep_1 (dep_t, bool,
                                                          rtx, rtx);
 static enum DEPS_ADJUST_RESULT add_or_update_dep_1 (dep_t, bool, rtx, rtx);
 
-static dw_t estimate_dep_weak (rtx, rtx);
 #ifdef ENABLE_CHECKING
 static void check_dep (dep_t, bool);
 #endif
@@ -459,10 +479,12 @@ deps_may_trap_p (const_rtx mem)
   return rtx_addr_can_trap_p (addr);
 }
 \f
-/* Find the condition under which INSN is executed.  */
 
+/* Find the condition under which INSN is executed.  If REV is not NULL,
+   it is set to TRUE when the returned comparison should be reversed
+   to get the actual condition.  */
 static rtx
-sched_get_condition (const_rtx insn)
+sched_get_condition_with_rev (const_rtx insn, bool *rev)
 {
   rtx pat = PATTERN (insn);
   rtx src;
@@ -470,6 +492,9 @@ sched_get_condition (const_rtx insn)
   if (pat == 0)
     return 0;
 
+  if (rev)
+    *rev = false;
+
   if (GET_CODE (pat) == COND_EXEC)
     return COND_EXEC_TEST (pat);
 
@@ -487,22 +512,34 @@ sched_get_condition (const_rtx insn)
 
       if (revcode == UNKNOWN)
        return 0;
-      return gen_rtx_fmt_ee (revcode, GET_MODE (cond), XEXP (cond, 0),
-                            XEXP (cond, 1));
+
+      if (rev)
+       *rev = true;
+      return cond;
     }
 
   return 0;
 }
 
+/* True when we can find a condition under which INSN is executed.  */
+static bool
+sched_has_condition_p (const_rtx insn)
+{
+  return !! sched_get_condition_with_rev (insn, NULL);
+}
+
 \f
-/* Return nonzero if conditions COND1 and COND2 can never be both true.  */
 
+/* Return nonzero if conditions COND1 and COND2 can never be both true.  */
 static int
-conditions_mutex_p (const_rtx cond1, const_rtx cond2)
+conditions_mutex_p (const_rtx cond1, const_rtx cond2, bool rev1, bool rev2)
 {
   if (COMPARISON_P (cond1)
       && COMPARISON_P (cond2)
-      && GET_CODE (cond1) == reversed_comparison_code (cond2, NULL)
+      && GET_CODE (cond1) ==
+         (rev1==rev2
+         ? reversed_comparison_code (cond2, NULL)
+         : GET_CODE (cond2))
       && XEXP (cond1, 0) == XEXP (cond2, 0)
       && XEXP (cond1, 1) == XEXP (cond2, 1))
     return 1;
@@ -515,15 +552,16 @@ bool
 sched_insns_conditions_mutex_p (const_rtx insn1, const_rtx insn2)
 {
   rtx cond1, cond2;
+  bool rev1 = false, rev2 = false;
 
   /* df doesn't handle conditional lifetimes entirely correctly;
      calls mess up the conditional lifetimes.  */
   if (!CALL_P (insn1) && !CALL_P (insn2))
     {
-      cond1 = sched_get_condition (insn1);
-      cond2 = sched_get_condition (insn2);
+      cond1 = sched_get_condition_with_rev (insn1, &rev1);
+      cond2 = sched_get_condition_with_rev (insn2, &rev2);
       if (cond1 && cond2
-         && conditions_mutex_p (cond1, cond2)
+         && conditions_mutex_p (cond1, cond2, rev1, rev2)
          /* Make sure first instruction doesn't affect condition of second
             instruction if switched.  */
          && !modified_in_p (cond1, insn2)
@@ -536,6 +574,46 @@ sched_insns_conditions_mutex_p (const_rtx insn1, const_rtx insn2)
 }
 \f
 
+/* Return true if INSN can potentially be speculated with type DS.  */
+bool
+sched_insn_is_legitimate_for_speculation_p (const_rtx insn, ds_t ds)
+{
+  if (HAS_INTERNAL_DEP (insn))
+    return false;
+
+  if (!NONJUMP_INSN_P (insn))
+    return false;
+
+  if (SCHED_GROUP_P (insn))
+    return false;
+
+  if (IS_SPECULATION_CHECK_P (CONST_CAST_RTX (insn)))
+    return false;
+
+  if (side_effects_p (PATTERN (insn)))
+    return false;
+
+  if (ds & BE_IN_SPEC)
+    /* The following instructions, which depend on a speculatively scheduled
+       instruction, cannot be speculatively scheduled along.  */
+    {
+      if (may_trap_p (PATTERN (insn)))
+       /* If instruction might trap, it cannot be speculatively scheduled.
+          For control speculation it's obvious why and for data speculation
+          it's because the insn might get wrong input if speculation
+          wasn't successful.  */
+       return false;
+
+      if ((ds & BE_IN_DATA)
+         && sched_has_condition_p (insn))
+       /* If this is a predicated instruction, then it cannot be
+          speculatively scheduled.  See PR35659.  */
+       return false;
+    }
+
+  return true;
+}
+
 /* Initialize LIST_PTR to point to one of the lists present in TYPES_PTR,
    initialize RESOLVED_P_PTR with true if that list consists of resolved deps,
    and remove the type of returned [through LIST_PTR] list from TYPES_PTR.
@@ -597,17 +675,29 @@ sd_lists_size (const_rtx insn, sd_list_types_def list_types)
       bool resolved_p;
 
       sd_next_list (insn, &list_types, &list, &resolved_p);
-      size += DEPS_LIST_N_LINKS (list);
+      if (list)
+       size += DEPS_LIST_N_LINKS (list);
     }
 
   return size;
 }
 
 /* Return true if INSN's lists defined by LIST_TYPES are all empty.  */
+
 bool
 sd_lists_empty_p (const_rtx insn, sd_list_types_def list_types)
 {
-  return sd_lists_size (insn, list_types) == 0;
+  while (list_types != SD_LIST_NONE)
+    {
+      deps_list_t list;
+      bool resolved_p;
+
+      sd_next_list (insn, &list_types, &list, &resolved_p);
+      if (!deps_list_empty_p (list))
+       return false;
+    }
+
+  return true;
 }
 
 /* Initialize data for INSN.  */
@@ -620,6 +710,9 @@ sd_init_insn (rtx insn)
   INSN_FORW_DEPS (insn) = create_deps_list ();
   INSN_RESOLVED_FORW_DEPS (insn) = create_deps_list ();
 
+  if (DEBUG_INSN_P (insn))
+    DEBUG_INSN_SCHED_P (insn) = TRUE;
+
   /* ??? It would be nice to allocate dependency caches here.  */
 }
 
@@ -629,6 +722,12 @@ sd_finish_insn (rtx insn)
 {
   /* ??? It would be nice to deallocate dependency caches here.  */
 
+  if (DEBUG_INSN_P (insn))
+    {
+      gcc_assert (DEBUG_INSN_SCHED_P (insn));
+      DEBUG_INSN_SCHED_P (insn) = FALSE;
+    }
+
   free_deps_list (INSN_HARD_BACK_DEPS (insn));
   INSN_HARD_BACK_DEPS (insn) = NULL;
 
@@ -752,7 +851,7 @@ maybe_add_or_update_dep_1 (dep_t dep, bool resolved_p, rtx mem1, rtx mem2)
   /* Don't depend an insn on itself.  */
   if (insn == elem)
     {
-      if (current_sched_info->flags & DO_SPECULATION)
+      if (sched_deps_info->generate_spec_deps)
         /* INSN has an internal dependence, which we can't overcome.  */
         HAS_INTERNAL_DEP (insn) = 1;
 
@@ -1079,7 +1178,7 @@ add_or_update_dep_1 (dep_t new_dep, bool resolved_p,
 
   if (mem1 != NULL_RTX)
     {
-      gcc_assert (current_sched_info->flags & DO_SPECULATION);
+      gcc_assert (sched_deps_info->generate_spec_deps);
       DEP_STATUS (new_dep) = set_dep_weak (DEP_STATUS (new_dep), BEGIN_DATA,
                                           estimate_dep_weak (mem1, mem2));
     }
@@ -1299,13 +1398,21 @@ add_dependence_list (rtx insn, rtx list, int uncond, enum reg_note dep_type)
     }
 }
 
-/* Similar, but free *LISTP at the same time.  */
+/* Similar, but free *LISTP at the same time, when the context 
+   is not readonly.  */
 
 static void
-add_dependence_list_and_free (rtx insn, rtx *listp, int uncond,
-                             enum reg_note dep_type)
+add_dependence_list_and_free (struct deps *deps, rtx insn, rtx *listp,
+                              int uncond, enum reg_note dep_type)
 {
   rtx list, next;
+
+  if (deps->readonly)
+    {
+      add_dependence_list (insn, *listp, uncond, dep_type);
+      return;
+    }
+
   for (list = *listp, *listp = NULL; list ; list = next)
     {
       next = XEXP (list, 1);
@@ -1315,6 +1422,52 @@ add_dependence_list_and_free (rtx insn, rtx *listp, int uncond,
     }
 }
 
+/* Remove all occurences of INSN from LIST.  Return the number of 
+   occurences removed.  */
+
+static int
+remove_from_dependence_list (rtx insn, rtx* listp)
+{
+  int removed = 0;
+  
+  while (*listp)
+    {
+      if (XEXP (*listp, 0) == insn)
+        {
+          remove_free_INSN_LIST_node (listp);
+          removed++;
+          continue;
+        }
+      
+      listp = &XEXP (*listp, 1);
+    }
+  
+  return removed;
+}
+
+/* Same as above, but process two lists at once.  */
+static int 
+remove_from_both_dependence_lists (rtx insn, rtx *listp, rtx *exprp)
+{
+  int removed = 0;
+  
+  while (*listp)
+    {
+      if (XEXP (*listp, 0) == insn)
+        {
+          remove_free_INSN_LIST_node (listp);
+          remove_free_EXPR_LIST_node (exprp);
+          removed++;
+          continue;
+        }
+      
+      listp = &XEXP (*listp, 1);
+      exprp = &XEXP (*exprp, 1);
+    }
+  
+  return removed;
+}
+
 /* Clear all dependencies for an insn.  */
 static void
 delete_all_dependences (rtx insn)
@@ -1355,7 +1508,7 @@ fixup_sched_groups (rtx insn)
 
          if (pro == i)
            goto next_link;
-       } while (SCHED_GROUP_P (i));
+       } while (SCHED_GROUP_P (i) || DEBUG_INSN_P (i));
 
       if (! sched_insns_conditions_mutex_p (i, pro))
        add_dependence (i, pro, DEP_TYPE (dep));
@@ -1365,6 +1518,8 @@ fixup_sched_groups (rtx insn)
   delete_all_dependences (insn);
 
   prev_nonnote = prev_nonnote_insn (insn);
+  while (DEBUG_INSN_P (prev_nonnote))
+    prev_nonnote = prev_nonnote_insn (prev_nonnote);
   if (BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (prev_nonnote)
       && ! sched_insns_conditions_mutex_p (insn, prev_nonnote))
     add_dependence (insn, prev_nonnote, REG_DEP_ANTI);
@@ -1393,11 +1548,13 @@ add_insn_mem_dependence (struct deps *deps, bool read_p,
   rtx *mem_list;
   rtx link;
 
+  gcc_assert (!deps->readonly);
   if (read_p)
     {
       insn_list = &deps->pending_read_insns;
       mem_list = &deps->pending_read_mems;
-      deps->pending_read_list_length++;
+      if (!DEBUG_INSN_P (insn))
+       deps->pending_read_list_length++;
     }
   else
     {
@@ -1409,7 +1566,7 @@ add_insn_mem_dependence (struct deps *deps, bool read_p,
   link = alloc_INSN_LIST (insn, *insn_list);
   *insn_list = link;
 
-  if (current_sched_info->use_cselib)
+  if (sched_deps_info->use_cselib)
     {
       mem = shallow_copy_rtx (mem);
       XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0));
@@ -1428,183 +1585,718 @@ flush_pending_lists (struct deps *deps, rtx insn, int for_read,
 {
   if (for_write)
     {
-      add_dependence_list_and_free (insn, &deps->pending_read_insns, 1,
-                                   REG_DEP_ANTI);
-      free_EXPR_LIST_list (&deps->pending_read_mems);
-      deps->pending_read_list_length = 0;
+      add_dependence_list_and_free (deps, insn, &deps->pending_read_insns, 
+                                    1, REG_DEP_ANTI);
+      if (!deps->readonly)
+        {
+          free_EXPR_LIST_list (&deps->pending_read_mems);
+          deps->pending_read_list_length = 0;
+        }
     }
 
-  add_dependence_list_and_free (insn, &deps->pending_write_insns, 1,
+  add_dependence_list_and_free (deps, insn, &deps->pending_write_insns, 1,
                                for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
-  free_EXPR_LIST_list (&deps->pending_write_mems);
-  deps->pending_write_list_length = 0;
 
-  add_dependence_list_and_free (insn, &deps->last_pending_memory_flush, 1,
-                               for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
-  deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
-  deps->pending_flush_length = 1;
+  add_dependence_list_and_free (deps, insn, 
+                                &deps->last_pending_memory_flush, 1,
+                                for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
+  if (!deps->readonly)
+    {
+      free_EXPR_LIST_list (&deps->pending_write_mems);
+      deps->pending_write_list_length = 0;
+
+      deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
+      deps->pending_flush_length = 1;
+    }
 }
 \f
-/* Analyze a single reference to register (reg:MODE REGNO) in INSN.
-   The type of the reference is specified by REF and can be SET,
-   CLOBBER, PRE_DEC, POST_DEC, PRE_INC, POST_INC or USE.  */
+/* Instruction which dependencies we are analyzing.  */
+static rtx cur_insn = NULL_RTX;
+
+/* Implement hooks for haifa scheduler.  */
 
 static void
-sched_analyze_reg (struct deps *deps, int regno, enum machine_mode mode,
-                  enum rtx_code ref, rtx insn)
+haifa_start_insn (rtx insn)
 {
-  /* A hard reg in a wide mode may really be multiple registers.
-     If so, mark all of them just like the first.  */
-  if (regno < FIRST_PSEUDO_REGISTER)
-    {
-      int i = hard_regno_nregs[regno][mode];
-      if (ref == SET)
-       {
-         while (--i >= 0)
-           SET_REGNO_REG_SET (reg_pending_sets, regno + i);
-       }
-      else if (ref == USE)
-       {
-         while (--i >= 0)
-           SET_REGNO_REG_SET (reg_pending_uses, regno + i);
-       }
-      else
-       {
-         while (--i >= 0)
-           SET_REGNO_REG_SET (reg_pending_clobbers, regno + i);
-       }
-    }
+  gcc_assert (insn && !cur_insn);
 
-  /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that
-     it does not reload.  Ignore these as they have served their
-     purpose already.  */
-  else if (regno >= deps->max_reg)
+  cur_insn = insn;
+}
+
+static void
+haifa_finish_insn (void)
+{
+  cur_insn = NULL;
+}
+
+void
+haifa_note_reg_set (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_sets, regno);
+}
+
+void
+haifa_note_reg_clobber (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_clobbers, regno);
+}
+
+void
+haifa_note_reg_use (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_uses, regno);
+}
+
+static void
+haifa_note_mem_dep (rtx mem, rtx pending_mem, rtx pending_insn, ds_t ds)
+{
+  if (!(ds & SPECULATIVE))
     {
-      enum rtx_code code = GET_CODE (PATTERN (insn));
-      gcc_assert (code == USE || code == CLOBBER);
+      mem = NULL_RTX;
+      pending_mem = NULL_RTX;
     }
-
   else
-    {
-      if (ref == SET)
-       SET_REGNO_REG_SET (reg_pending_sets, regno);
-      else if (ref == USE)
-       SET_REGNO_REG_SET (reg_pending_uses, regno);
-      else
-       SET_REGNO_REG_SET (reg_pending_clobbers, regno);
+    gcc_assert (ds & BEGIN_DATA);
 
-      /* Pseudos that are REG_EQUIV to something may be replaced
-        by that during reloading.  We need only add dependencies for
-       the address in the REG_EQUIV note.  */
-      if (!reload_completed && get_reg_known_equiv_p (regno))
-       {
-         rtx t = get_reg_known_value (regno);
-         if (MEM_P (t))
-           sched_analyze_2 (deps, XEXP (t, 0), insn);
-       }
+  {
+    dep_def _dep, *dep = &_dep;
+    
+    init_dep_1 (dep, pending_insn, cur_insn, ds_to_dt (ds),
+                current_sched_info->flags & USE_DEPS_LIST ? ds : -1);
+    maybe_add_or_update_dep_1 (dep, false, pending_mem, mem);
+  }
 
-      /* Don't let it cross a call after scheduling if it doesn't
-        already cross one.  */
-      if (REG_N_CALLS_CROSSED (regno) == 0)
-       {
-         if (ref == USE)
-           deps->sched_before_next_call
-             = alloc_INSN_LIST (insn, deps->sched_before_next_call);
-         else
-           add_dependence_list (insn, deps->last_function_call, 1,
-                                REG_DEP_ANTI);
-       }
-    }
 }
 
-/* Analyze a single SET, CLOBBER, PRE_DEC, POST_DEC, PRE_INC or POST_INC
-   rtx, X, creating all dependencies generated by the write to the
-   destination of X, and reads of everything mentioned.  */
+static void
+haifa_note_dep (rtx elem, ds_t ds)
+{
+  dep_def _dep;
+  dep_t dep = &_dep;
+
+  init_dep (dep, elem, cur_insn, ds_to_dt (ds));
+  maybe_add_or_update_dep_1 (dep, false, NULL_RTX, NULL_RTX);
+}
 
 static void
-sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
+note_reg_use (int r)
 {
-  rtx dest = XEXP (x, 0);
-  enum rtx_code code = GET_CODE (x);
+  if (sched_deps_info->note_reg_use)
+    sched_deps_info->note_reg_use (r);
+}
 
-  if (dest == 0)
-    return;
+static void
+note_reg_set (int r)
+{
+  if (sched_deps_info->note_reg_set)
+    sched_deps_info->note_reg_set (r);
+}
 
-  if (GET_CODE (dest) == PARALLEL)
-    {
-      int i;
+static void
+note_reg_clobber (int r)
+{
+  if (sched_deps_info->note_reg_clobber)
+    sched_deps_info->note_reg_clobber (r);
+}
 
-      for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
-       if (XEXP (XVECEXP (dest, 0, i), 0) != 0)
-         sched_analyze_1 (deps,
-                          gen_rtx_CLOBBER (VOIDmode,
-                                           XEXP (XVECEXP (dest, 0, i), 0)),
-                          insn);
+static void
+note_mem_dep (rtx m1, rtx m2, rtx e, ds_t ds)
+{
+  if (sched_deps_info->note_mem_dep)
+    sched_deps_info->note_mem_dep (m1, m2, e, ds);
+}
 
-      if (GET_CODE (x) == SET)
-       sched_analyze_2 (deps, SET_SRC (x), insn);
-      return;
-    }
+static void
+note_dep (rtx e, ds_t ds)
+{
+  if (sched_deps_info->note_dep)
+    sched_deps_info->note_dep (e, ds);
+}
 
-  while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
-        || GET_CODE (dest) == ZERO_EXTRACT)
+/* Return corresponding to DS reg_note.  */
+enum reg_note
+ds_to_dt (ds_t ds)
+{
+  if (ds & DEP_TRUE)
+    return REG_DEP_TRUE;
+  else if (ds & DEP_OUTPUT)
+    return REG_DEP_OUTPUT;
+  else
     {
-      if (GET_CODE (dest) == STRICT_LOW_PART
-        || GET_CODE (dest) == ZERO_EXTRACT
-        || df_read_modify_subreg_p (dest))
-        {
-         /* These both read and modify the result.  We must handle
-             them as writes to get proper dependencies for following
-             instructions.  We must handle them as reads to get proper
-             dependencies from this to previous instructions.
-             Thus we need to call sched_analyze_2.  */
-
-         sched_analyze_2 (deps, XEXP (dest, 0), insn);
-       }
-      if (GET_CODE (dest) == ZERO_EXTRACT)
-       {
-         /* The second and third arguments are values read by this insn.  */
-         sched_analyze_2 (deps, XEXP (dest, 1), insn);
-         sched_analyze_2 (deps, XEXP (dest, 2), insn);
-       }
-      dest = XEXP (dest, 0);
+      gcc_assert (ds & DEP_ANTI);
+      return REG_DEP_ANTI;
     }
+}
 
-  if (REG_P (dest))
-    {
-      int regno = REGNO (dest);
-      enum machine_mode mode = GET_MODE (dest);
+\f
 
-      sched_analyze_reg (deps, regno, mode, code, insn);
+/* Functions for computation of info needed for register pressure
+   sensitive insn scheduling.  */
 
-#ifdef STACK_REGS
-      /* Treat all writes to a stack register as modifying the TOS.  */
-      if (regno >= FIRST_STACK_REG && regno <= LAST_STACK_REG)
+
+/* Allocate and return reg_use_data structure for REGNO and INSN.  */
+static struct reg_use_data *
+create_insn_reg_use (int regno, rtx insn)
+{
+  struct reg_use_data *use;
+
+  use = (struct reg_use_data *) xmalloc (sizeof (struct reg_use_data));
+  use->regno = regno;
+  use->insn = insn;
+  use->next_insn_use = INSN_REG_USE_LIST (insn);
+  INSN_REG_USE_LIST (insn) = use;
+  return use;
+}
+
+/* Allocate and return reg_set_data structure for REGNO and INSN.  */
+static struct reg_set_data *
+create_insn_reg_set (int regno, rtx insn)
+{
+  struct reg_set_data *set;
+
+  set = (struct reg_set_data *) xmalloc (sizeof (struct reg_set_data));
+  set->regno = regno;
+  set->insn = insn;
+  set->next_insn_set = INSN_REG_SET_LIST (insn);
+  INSN_REG_SET_LIST (insn) = set;
+  return set;
+}
+
+/* Set up insn register uses for INSN and dependency context DEPS.  */
+static void
+setup_insn_reg_uses (struct deps *deps, rtx insn)
+{
+  unsigned i;
+  reg_set_iterator rsi;
+  rtx list;
+  struct reg_use_data *use, *use2, *next;
+  struct deps_reg *reg_last;
+
+  EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
+    {
+      if (i < FIRST_PSEUDO_REGISTER
+         && TEST_HARD_REG_BIT (ira_no_alloc_regs, i))
+       continue;
+
+      if (find_regno_note (insn, REG_DEAD, i) == NULL_RTX
+         && ! REGNO_REG_SET_P (reg_pending_sets, i)
+         && ! REGNO_REG_SET_P (reg_pending_clobbers, i))
+       /* Ignore use which is not dying.  */
+       continue;
+
+      use = create_insn_reg_use (i, insn);
+      use->next_regno_use = use;
+      reg_last = &deps->reg_last[i];
+      
+      /* Create the cycle list of uses.  */
+      for (list = reg_last->uses; list; list = XEXP (list, 1))
        {
-         /* Avoid analyzing the same register twice.  */
-         if (regno != FIRST_STACK_REG)
-           sched_analyze_reg (deps, FIRST_STACK_REG, mode, code, insn);
-         sched_analyze_reg (deps, FIRST_STACK_REG, mode, USE, insn);
+         use2 = create_insn_reg_use (i, XEXP (list, 0));
+         next = use->next_regno_use;
+         use->next_regno_use = use2;
+         use2->next_regno_use = next;
        }
-#endif
     }
-  else if (MEM_P (dest))
-    {
-      /* Writing memory.  */
-      rtx t = dest;
+}
 
-      if (current_sched_info->use_cselib)
-       {
-         t = shallow_copy_rtx (dest);
-         cselib_lookup (XEXP (t, 0), Pmode, 1);
-         XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
-       }
-      t = canon_rtx (t);
+/* Register pressure info for the currently processed insn.  */
+static struct reg_pressure_data reg_pressure_info[N_REG_CLASSES];
 
-      if ((deps->pending_read_list_length + deps->pending_write_list_length)
-         > MAX_PENDING_LIST_LENGTH)
-       {
-         /* Flush all pending reads and writes to prevent the pending lists
+/* Return TRUE if INSN has the use structure for REGNO.  */
+static bool
+insn_use_p (rtx insn, int regno)
+{
+  struct reg_use_data *use;
+
+  for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
+    if (use->regno == regno)
+      return true;
+  return false;
+}
+
+/* Update the register pressure info after birth of pseudo register REGNO
+   in INSN.  Arguments CLOBBER_P and UNUSED_P say correspondingly that
+   the register is in clobber or unused after the insn.  */
+static void
+mark_insn_pseudo_birth (rtx insn, int regno, bool clobber_p, bool unused_p)
+{
+  int incr, new_incr;
+  enum reg_class cl;
+
+  gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
+  cl = sched_regno_cover_class[regno];
+  if (cl != NO_REGS)
+    {
+      incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)];
+      if (clobber_p)
+       {
+         new_incr = reg_pressure_info[cl].clobber_increase + incr;
+         reg_pressure_info[cl].clobber_increase = new_incr;
+       }
+      else if (unused_p)
+       {
+         new_incr = reg_pressure_info[cl].unused_set_increase + incr;
+         reg_pressure_info[cl].unused_set_increase = new_incr;
+       }
+      else
+       {
+         new_incr = reg_pressure_info[cl].set_increase + incr;
+         reg_pressure_info[cl].set_increase = new_incr;
+         if (! insn_use_p (insn, regno))
+           reg_pressure_info[cl].change += incr;
+         create_insn_reg_set (regno, insn);
+       }
+      gcc_assert (new_incr < (1 << INCREASE_BITS));
+    }
+}
+
+/* Like mark_insn_pseudo_regno_birth except that NREGS saying how many
+   hard registers involved in the birth.  */
+static void
+mark_insn_hard_regno_birth (rtx insn, int regno, int nregs,
+                           bool clobber_p, bool unused_p)
+{
+  enum reg_class cl;
+  int new_incr, last = regno + nregs;
+  
+  while (regno < last)
+    {
+      gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+      if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
+       {
+         cl = sched_regno_cover_class[regno];
+         if (cl != NO_REGS)
+           {
+             if (clobber_p)
+               {
+                 new_incr = reg_pressure_info[cl].clobber_increase + 1;
+                 reg_pressure_info[cl].clobber_increase = new_incr;
+               }
+             else if (unused_p)
+               {
+                 new_incr = reg_pressure_info[cl].unused_set_increase + 1;
+                 reg_pressure_info[cl].unused_set_increase = new_incr;
+               }
+             else
+               {
+                 new_incr = reg_pressure_info[cl].set_increase + 1;
+                 reg_pressure_info[cl].set_increase = new_incr;
+                 if (! insn_use_p (insn, regno))
+                   reg_pressure_info[cl].change += 1;
+                 create_insn_reg_set (regno, insn);
+               }
+             gcc_assert (new_incr < (1 << INCREASE_BITS));
+           }
+       }
+      regno++;
+    }
+}
+
+/* Update the register pressure info after birth of pseudo or hard
+   register REG in INSN.  Arguments CLOBBER_P and UNUSED_P say
+   correspondingly that the register is in clobber or unused after the
+   insn.  */
+static void
+mark_insn_reg_birth (rtx insn, rtx reg, bool clobber_p, bool unused_p)
+{
+  int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (! REG_P (reg))
+    return;
+
+  regno = REGNO (reg);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    mark_insn_hard_regno_birth (insn, regno,
+                               hard_regno_nregs[regno][GET_MODE (reg)],
+                               clobber_p, unused_p);
+  else
+    mark_insn_pseudo_birth (insn, regno, clobber_p, unused_p);
+}
+
+/* Update the register pressure info after death of pseudo register
+   REGNO.  */
+static void
+mark_pseudo_death (int regno)
+{
+  int incr;
+  enum reg_class cl;
+
+  gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
+  cl = sched_regno_cover_class[regno];
+  if (cl != NO_REGS)
+    {
+      incr = ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (regno)];
+      reg_pressure_info[cl].change -= incr;
+    }
+}
+
+/* Like mark_pseudo_death except that NREGS saying how many hard
+   registers involved in the death.  */
+static void
+mark_hard_regno_death (int regno, int nregs)
+{
+  enum reg_class cl;
+  int last = regno + nregs;
+  
+  while (regno < last)
+    {
+      gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+      if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno))
+       {
+         cl = sched_regno_cover_class[regno];
+         if (cl != NO_REGS)
+           reg_pressure_info[cl].change -= 1;
+       }
+      regno++;
+    }
+}
+
+/* Update the register pressure info after death of pseudo or hard
+   register REG.  */
+static void
+mark_reg_death (rtx reg)
+{
+  int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (! REG_P (reg))
+    return;
+
+  regno = REGNO (reg);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    mark_hard_regno_death (regno, hard_regno_nregs[regno][GET_MODE (reg)]);
+  else
+    mark_pseudo_death (regno);
+}
+
+/* Process SETTER of REG.  DATA is an insn containing the setter.  */
+static void
+mark_insn_reg_store (rtx reg, const_rtx setter, void *data)
+{
+  if (setter != NULL_RTX && GET_CODE (setter) != SET)
+    return;
+  mark_insn_reg_birth
+    ((rtx) data, reg, false,
+     find_reg_note ((const_rtx) data, REG_UNUSED, reg) != NULL_RTX);
+}
+
+/* Like mark_insn_reg_store except notice just CLOBBERs; ignore SETs.  */
+static void
+mark_insn_reg_clobber (rtx reg, const_rtx setter, void *data)
+{
+  if (GET_CODE (setter) == CLOBBER)
+    mark_insn_reg_birth ((rtx) data, reg, true, false);
+}
+
+/* Set up reg pressure info related to INSN.  */
+static void
+setup_insn_reg_pressure_info (rtx insn)
+{
+  int i, len;
+  enum reg_class cl;
+  static struct reg_pressure_data *pressure_info;
+  rtx link;
+
+  gcc_assert (sched_pressure_p);
+
+  if (! INSN_P (insn))
+    return;
+
+  for (i = 0; i < ira_reg_class_cover_size; i++)
+    {
+      cl = ira_reg_class_cover[i];
+      reg_pressure_info[cl].clobber_increase = 0;
+      reg_pressure_info[cl].set_increase = 0;
+      reg_pressure_info[cl].unused_set_increase = 0;
+      reg_pressure_info[cl].change = 0;
+    }
+  
+  note_stores (PATTERN (insn), mark_insn_reg_clobber, insn);
+         
+  note_stores (PATTERN (insn), mark_insn_reg_store, insn);
+  
+#ifdef AUTO_INC_DEC
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_INC)
+      mark_insn_reg_store (XEXP (link, 0), NULL_RTX, insn);
+#endif
+
+  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+    if (REG_NOTE_KIND (link) == REG_DEAD)
+      mark_reg_death (XEXP (link, 0));
+       
+  len = sizeof (struct reg_pressure_data) * ira_reg_class_cover_size;
+  pressure_info
+    = INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len);
+  INSN_MAX_REG_PRESSURE (insn) = (int *) xmalloc (ira_reg_class_cover_size
+                                                 * sizeof (int));
+  for (i = 0; i < ira_reg_class_cover_size; i++)
+    {
+      cl = ira_reg_class_cover[i];
+      pressure_info[i].clobber_increase
+       = reg_pressure_info[cl].clobber_increase;
+      pressure_info[i].set_increase = reg_pressure_info[cl].set_increase;
+      pressure_info[i].unused_set_increase
+       = reg_pressure_info[cl].unused_set_increase;
+      pressure_info[i].change = reg_pressure_info[cl].change;
+    }
+}
+
+
+\f
+
+/* Internal variable for sched_analyze_[12] () functions.
+   If it is nonzero, this means that sched_analyze_[12] looks
+   at the most toplevel SET.  */
+static bool can_start_lhs_rhs_p;
+
+/* Extend reg info for the deps context DEPS given that 
+   we have just generated a register numbered REGNO.  */
+static void
+extend_deps_reg_info (struct deps *deps, int regno)
+{
+  int max_regno = regno + 1;
+
+  gcc_assert (!reload_completed);
+
+  /* In a readonly context, it would not hurt to extend info,
+     but it should not be needed.  */
+  if (reload_completed && deps->readonly)
+    {
+      deps->max_reg = max_regno;
+      return;
+    }
+
+  if (max_regno > deps->max_reg)
+    {
+      deps->reg_last = XRESIZEVEC (struct deps_reg, deps->reg_last, 
+                                   max_regno);
+      memset (&deps->reg_last[deps->max_reg],
+              0, (max_regno - deps->max_reg) 
+              * sizeof (struct deps_reg));
+      deps->max_reg = max_regno;
+    }
+}
+
+/* Extends REG_INFO_P if needed.  */
+void
+maybe_extend_reg_info_p (void)
+{
+  /* Extend REG_INFO_P, if needed.  */
+  if ((unsigned int)max_regno - 1 >= reg_info_p_size)
+    {
+      size_t new_reg_info_p_size = max_regno + 128;
+
+      gcc_assert (!reload_completed && sel_sched_p ());
+
+      reg_info_p = (struct reg_info_t *) xrecalloc (reg_info_p,
+                                                    new_reg_info_p_size,
+                                                    reg_info_p_size,
+                                                    sizeof (*reg_info_p));
+      reg_info_p_size = new_reg_info_p_size;
+    }
+}
+
+/* Analyze a single reference to register (reg:MODE REGNO) in INSN.
+   The type of the reference is specified by REF and can be SET,
+   CLOBBER, PRE_DEC, POST_DEC, PRE_INC, POST_INC or USE.  */
+
+static void
+sched_analyze_reg (struct deps *deps, int regno, enum machine_mode mode,
+                  enum rtx_code ref, rtx insn)
+{
+  /* We could emit new pseudos in renaming.  Extend the reg structures.  */
+  if (!reload_completed && sel_sched_p ()
+      && (regno >= max_reg_num () - 1 || regno >= deps->max_reg))
+    extend_deps_reg_info (deps, regno);
+
+  maybe_extend_reg_info_p ();
+
+  /* A hard reg in a wide mode may really be multiple registers.
+     If so, mark all of them just like the first.  */
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      int i = hard_regno_nregs[regno][mode];
+      if (ref == SET)
+       {
+         while (--i >= 0)
+           note_reg_set (regno + i);
+       }
+      else if (ref == USE)
+       {
+         while (--i >= 0)
+           note_reg_use (regno + i);
+       }
+      else
+       {
+         while (--i >= 0)
+           note_reg_clobber (regno + i);
+       }
+    }
+
+  /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that
+     it does not reload.  Ignore these as they have served their
+     purpose already.  */
+  else if (regno >= deps->max_reg)
+    {
+      enum rtx_code code = GET_CODE (PATTERN (insn));
+      gcc_assert (code == USE || code == CLOBBER);
+    }
+
+  else
+    {
+      if (ref == SET)
+       note_reg_set (regno);
+      else if (ref == USE)
+       note_reg_use (regno);
+      else
+       note_reg_clobber (regno);
+
+      /* Pseudos that are REG_EQUIV to something may be replaced
+        by that during reloading.  We need only add dependencies for
+       the address in the REG_EQUIV note.  */
+      if (!reload_completed && get_reg_known_equiv_p (regno))
+       {
+         rtx t = get_reg_known_value (regno);
+         if (MEM_P (t))
+           sched_analyze_2 (deps, XEXP (t, 0), insn);
+       }
+
+      /* Don't let it cross a call after scheduling if it doesn't
+        already cross one.  */
+      if (REG_N_CALLS_CROSSED (regno) == 0)
+       {
+         if (!deps->readonly && ref == USE && !DEBUG_INSN_P (insn))
+           deps->sched_before_next_call
+             = alloc_INSN_LIST (insn, deps->sched_before_next_call);
+         else
+           add_dependence_list (insn, deps->last_function_call, 1,
+                                REG_DEP_ANTI);
+       }
+    }
+}
+
+/* Analyze a single SET, CLOBBER, PRE_DEC, POST_DEC, PRE_INC or POST_INC
+   rtx, X, creating all dependencies generated by the write to the
+   destination of X, and reads of everything mentioned.  */
+
+static void
+sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
+{
+  rtx dest = XEXP (x, 0);
+  enum rtx_code code = GET_CODE (x);
+  bool cslr_p = can_start_lhs_rhs_p;
+
+  can_start_lhs_rhs_p = false;
+
+  gcc_assert (dest);
+  if (dest == 0)
+    return;
+
+  if (cslr_p && sched_deps_info->start_lhs)
+    sched_deps_info->start_lhs (dest);
+
+  if (GET_CODE (dest) == PARALLEL)
+    {
+      int i;
+
+      for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
+       if (XEXP (XVECEXP (dest, 0, i), 0) != 0)
+         sched_analyze_1 (deps,
+                          gen_rtx_CLOBBER (VOIDmode,
+                                           XEXP (XVECEXP (dest, 0, i), 0)),
+                          insn);
+
+      if (cslr_p && sched_deps_info->finish_lhs)
+       sched_deps_info->finish_lhs ();
+
+      if (code == SET)
+       {
+         can_start_lhs_rhs_p = cslr_p;
+
+         sched_analyze_2 (deps, SET_SRC (x), insn);
+
+         can_start_lhs_rhs_p = false;
+       }
+
+      return;
+    }
+
+  while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
+        || GET_CODE (dest) == ZERO_EXTRACT)
+    {
+      if (GET_CODE (dest) == STRICT_LOW_PART
+        || GET_CODE (dest) == ZERO_EXTRACT
+        || df_read_modify_subreg_p (dest))
+        {
+         /* These both read and modify the result.  We must handle
+             them as writes to get proper dependencies for following
+             instructions.  We must handle them as reads to get proper
+             dependencies from this to previous instructions.
+             Thus we need to call sched_analyze_2.  */
+
+         sched_analyze_2 (deps, XEXP (dest, 0), insn);
+       }
+      if (GET_CODE (dest) == ZERO_EXTRACT)
+       {
+         /* The second and third arguments are values read by this insn.  */
+         sched_analyze_2 (deps, XEXP (dest, 1), insn);
+         sched_analyze_2 (deps, XEXP (dest, 2), insn);
+       }
+      dest = XEXP (dest, 0);
+    }
+
+  if (REG_P (dest))
+    {
+      int regno = REGNO (dest);
+      enum machine_mode mode = GET_MODE (dest);
+
+      sched_analyze_reg (deps, regno, mode, code, insn);
+
+#ifdef STACK_REGS
+      /* Treat all writes to a stack register as modifying the TOS.  */
+      if (regno >= FIRST_STACK_REG && regno <= LAST_STACK_REG)
+       {
+         int nregs;
+
+         /* Avoid analyzing the same register twice.  */
+         if (regno != FIRST_STACK_REG)
+           sched_analyze_reg (deps, FIRST_STACK_REG, mode, code, insn);
+
+         nregs = hard_regno_nregs[FIRST_STACK_REG][mode];
+         while (--nregs >= 0)
+           SET_HARD_REG_BIT (implicit_reg_pending_uses,
+                             FIRST_STACK_REG + nregs);
+       }
+#endif
+    }
+  else if (MEM_P (dest))
+    {
+      /* Writing memory.  */
+      rtx t = dest;
+
+      if (sched_deps_info->use_cselib)
+       {
+         enum machine_mode address_mode
+           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest));
+
+         t = shallow_copy_rtx (dest);
+         cselib_lookup (XEXP (t, 0), address_mode, 1);
+         XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+       }
+      t = canon_rtx (t);
+
+      /* Pending lists can't get larger with a readonly context.  */
+      if (!deps->readonly
+          && ((deps->pending_read_list_length + deps->pending_write_list_length)
+              > MAX_PENDING_LIST_LENGTH))
+       {
+         /* Flush all pending reads and writes to prevent the pending lists
             from getting any larger.  Insn scheduling runs too slowly when
             these lists get long.  When compiling GCC with itself,
             this flush occurs 8 times for sparc, and 10 times for m88k using
@@ -1621,7 +2313,8 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
            {
              if (anti_dependence (XEXP (pending_mem, 0), t)
                  && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0)))
-               add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
+               note_mem_dep (t, XEXP (pending_mem, 0), XEXP (pending, 0),
+                             DEP_ANTI);
 
              pending = XEXP (pending, 1);
              pending_mem = XEXP (pending_mem, 1);
@@ -1633,7 +2326,8 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
            {
              if (output_dependence (XEXP (pending_mem, 0), t)
                  && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0)))
-               add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT);
+               note_mem_dep (t, XEXP (pending_mem, 0), XEXP (pending, 0),
+                             DEP_OUTPUT);
 
              pending = XEXP (pending, 1);
              pending_mem = XEXP (pending_mem, 1);
@@ -1642,18 +2336,27 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
          add_dependence_list (insn, deps->last_pending_memory_flush, 1,
                               REG_DEP_ANTI);
 
-         add_insn_mem_dependence (deps, false, insn, dest);
+          if (!deps->readonly)
+            add_insn_mem_dependence (deps, false, insn, dest);
        }
       sched_analyze_2 (deps, XEXP (dest, 0), insn);
     }
 
+  if (cslr_p && sched_deps_info->finish_lhs)
+    sched_deps_info->finish_lhs ();
+
   /* Analyze reads.  */
   if (GET_CODE (x) == SET)
-    sched_analyze_2 (deps, SET_SRC (x), insn);
+    {
+      can_start_lhs_rhs_p = cslr_p;
+
+      sched_analyze_2 (deps, SET_SRC (x), insn);
+
+      can_start_lhs_rhs_p = false;
+    }
 }
 
 /* Analyze the uses of memory and registers in rtx X in INSN.  */
-
 static void
 sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
 {
@@ -1661,10 +2364,17 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
   int j;
   enum rtx_code code;
   const char *fmt;
+  bool cslr_p = can_start_lhs_rhs_p;
 
+  can_start_lhs_rhs_p = false;
+
+  gcc_assert (x);
   if (x == 0)
     return;
 
+  if (cslr_p && sched_deps_info->start_rhs)
+    sched_deps_info->start_rhs (x);
+
   code = GET_CODE (x);
 
   switch (code)
@@ -1676,9 +2386,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
     case SYMBOL_REF:
     case CONST:
     case LABEL_REF:
-      /* Ignore constants.  Note that we must handle CONST_DOUBLE here
-         because it may have a cc0_rtx in its CONST_DOUBLE_CHAIN field, but
-         this does not mean that this insn is using cc0.  */
+      /* Ignore constants.  */
+      if (cslr_p && sched_deps_info->finish_rhs)
+       sched_deps_info->finish_rhs ();
+
       return;
 
 #ifdef HAVE_cc0
@@ -1688,6 +2399,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
        /* Don't move CC0 setter to another block (it can set up the
         same flag for previous CC0 users which is safe).  */
       CANT_MOVE (prev_nonnote_insn (insn)) = 1;
+
+      if (cslr_p && sched_deps_info->finish_rhs)
+       sched_deps_info->finish_rhs ();
+
       return;
 #endif
 
@@ -1708,6 +2423,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
          sched_analyze_reg (deps, FIRST_STACK_REG, mode, SET, insn);
        }
 #endif
+
+       if (cslr_p && sched_deps_info->finish_rhs)
+         sched_deps_info->finish_rhs ();
+
        return;
       }
 
@@ -1718,64 +2437,79 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
        rtx pending, pending_mem;
        rtx t = x;
 
-       if (current_sched_info->use_cselib)
+       if (sched_deps_info->use_cselib)
          {
+           enum machine_mode address_mode
+             = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
+
            t = shallow_copy_rtx (t);
-           cselib_lookup (XEXP (t, 0), Pmode, 1);
+           cselib_lookup (XEXP (t, 0), address_mode, 1);
            XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
          }
-       t = canon_rtx (t);
-       pending = deps->pending_read_insns;
-       pending_mem = deps->pending_read_mems;
-       while (pending)
-         {
-           if (read_dependence (XEXP (pending_mem, 0), t)
-               && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0)))
-             add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
-
-           pending = XEXP (pending, 1);
-           pending_mem = XEXP (pending_mem, 1);
-         }
 
-       pending = deps->pending_write_insns;
-       pending_mem = deps->pending_write_mems;
-       while (pending)
+       if (!DEBUG_INSN_P (insn))
          {
-           if (true_dependence (XEXP (pending_mem, 0), VOIDmode,
-                                t, rtx_varies_p)
-               && ! sched_insns_conditions_mutex_p (insn, XEXP (pending, 0)))
-              {
-                if ((current_sched_info->flags & DO_SPECULATION)
-                   && (spec_info->mask & BEGIN_DATA))
-                 /* Create a data-speculative dependence between producer
-                    and consumer.  */
+           t = canon_rtx (t);
+           pending = deps->pending_read_insns;
+           pending_mem = deps->pending_read_mems;
+           while (pending)
+             {
+               if (read_dependence (XEXP (pending_mem, 0), t)
+                   && ! sched_insns_conditions_mutex_p (insn,
+                                                        XEXP (pending, 0)))
+                 note_mem_dep (t, XEXP (pending_mem, 0), XEXP (pending, 0),
+                               DEP_ANTI);
+
+               pending = XEXP (pending, 1);
+               pending_mem = XEXP (pending_mem, 1);
+             }
+
+           pending = deps->pending_write_insns;
+           pending_mem = deps->pending_write_mems;
+           while (pending)
+             {
+               if (true_dependence (XEXP (pending_mem, 0), VOIDmode,
+                                    t, rtx_varies_p)
+                   && ! sched_insns_conditions_mutex_p (insn,
+                                                        XEXP (pending, 0)))
+                 note_mem_dep (t, XEXP (pending_mem, 0), XEXP (pending, 0),
+                               sched_deps_info->generate_spec_deps
+                               ? BEGIN_DATA | DEP_TRUE : DEP_TRUE);
+
+               pending = XEXP (pending, 1);
+               pending_mem = XEXP (pending_mem, 1);
+             }
+
+           for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1))
+             {
+               if (! JUMP_P (XEXP (u, 0)))
+                 add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+               else if (deps_may_trap_p (x))
                  {
-                   dep_def _dep, *dep = &_dep;
-
-                   init_dep_1 (dep, XEXP (pending, 0), insn, REG_DEP_TRUE,
-                               BEGIN_DATA | DEP_TRUE);
-
-                   maybe_add_or_update_dep_1 (dep, false,
-                                              XEXP (pending_mem, 0), t);
+                   if ((sched_deps_info->generate_spec_deps)
+                       && sel_sched_p () && (spec_info->mask & BEGIN_CONTROL))
+                     {
+                       ds_t ds = set_dep_weak (DEP_ANTI, BEGIN_CONTROL,
+                                               MAX_DEP_WEAK);
+
+                       note_dep (XEXP (u, 0), ds);
+                     }
+                   else
+                     add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
                  }
-                else
-                  add_dependence (insn, XEXP (pending, 0), REG_DEP_TRUE);
-              }
-
-           pending = XEXP (pending, 1);
-           pending_mem = XEXP (pending_mem, 1);
+             }
          }
 
-       for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1))
-         if (! JUMP_P (XEXP (u, 0)) || deps_may_trap_p (x))
-           add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
-
        /* Always add these dependencies to pending_reads, since
           this insn may be followed by a write.  */
-       add_insn_mem_dependence (deps, true, insn, x);
+        if (!deps->readonly)
+          add_insn_mem_dependence (deps, true, insn, x);
 
-       /* Take advantage of tail recursion here.  */
        sched_analyze_2 (deps, XEXP (x, 0), insn);
+
+       if (cslr_p && sched_deps_info->finish_rhs)
+         sched_deps_info->finish_rhs ();
+
        return;
       }
 
@@ -1784,9 +2518,17 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
       flush_pending_lists (deps, insn, true, false);
       break;
 
+    case PREFETCH:
+      if (PREFETCH_SCHEDULE_BARRIER_P (x))
+       reg_pending_barrier = TRUE_BARRIER;
+      break;
+
+    case UNSPEC_VOLATILE:
+      flush_pending_lists (deps, insn, true, true);
+      /* FALLTHRU */
+
     case ASM_OPERANDS:
     case ASM_INPUT:
-    case UNSPEC_VOLATILE:
       {
        /* Traditional and volatile asm instructions must be considered to use
           and clobber all hard registers, all pseudo-registers and all of
@@ -1807,6 +2549,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
          {
            for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
              sched_analyze_2 (deps, ASM_OPERANDS_INPUT (x, j), insn);
+
+           if (cslr_p && sched_deps_info->finish_rhs)
+             sched_deps_info->finish_rhs ();
+
            return;
          }
        break;
@@ -1824,6 +2570,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
          to get the proper antecedent for the read.  */
       sched_analyze_2 (deps, XEXP (x, 0), insn);
       sched_analyze_1 (deps, x, insn);
+
+      if (cslr_p && sched_deps_info->finish_rhs)
+       sched_deps_info->finish_rhs ();
+
       return;
 
     case POST_MODIFY:
@@ -1832,6 +2582,10 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
       sched_analyze_2 (deps, XEXP (x, 0), insn);
       sched_analyze_2 (deps, XEXP (x, 1), insn);
       sched_analyze_1 (deps, x, insn);
+
+      if (cslr_p && sched_deps_info->finish_rhs)
+       sched_deps_info->finish_rhs ();
+
       return;
 
     default:
@@ -1848,10 +2602,12 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn)
        for (j = 0; j < XVECLEN (x, i); j++)
          sched_analyze_2 (deps, XVECEXP (x, i, j), insn);
     }
+
+  if (cslr_p && sched_deps_info->finish_rhs)
+    sched_deps_info->finish_rhs ();
 }
 
 /* Analyze an INSN with pattern X to find all dependencies.  */
-
 static void
 sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
 {
@@ -1860,6 +2616,25 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
   unsigned i;
   reg_set_iterator rsi;
 
+  if (! reload_completed)
+    {
+      HARD_REG_SET temp;
+
+      extract_insn (insn);
+      preprocess_constraints ();
+      ira_implicitly_set_insn_hard_regs (&temp);
+      IOR_HARD_REG_SET (implicit_reg_pending_clobbers, temp);
+    }
+
+  can_start_lhs_rhs_p = (NONJUMP_INSN_P (insn)
+                        && code == SET);
+
+  if (may_trap_p (x))
+    /* Avoid moving trapping instructions accross function calls that might
+       not always return.  */
+    add_dependence_list (insn, deps->last_function_call_may_noreturn,
+                        1, REG_DEP_ANTI);
+
   if (code == COND_EXEC)
     {
       sched_analyze_2 (deps, COND_EXEC_TEST (x), insn);
@@ -1877,7 +2652,8 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
         and others know that a value is dead.  Depend on the last call
         instruction so that reg-stack won't get confused.  */
       if (code == CLOBBER)
-       add_dependence_list (insn, deps->last_function_call, 1, REG_DEP_OUTPUT);
+       add_dependence_list (insn, deps->last_function_call, 1,
+                            REG_DEP_OUTPUT);
     }
   else if (code == PARALLEL)
     {
@@ -1919,30 +2695,43 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
     {
       rtx next;
       next = next_nonnote_insn (insn);
+      while (next && DEBUG_INSN_P (next))
+       next = next_nonnote_insn (next);
       if (next && BARRIER_P (next))
        reg_pending_barrier = MOVE_BARRIER;
       else
        {
          rtx pending, pending_mem;
-         regset_head tmp_uses, tmp_sets;
-         INIT_REG_SET (&tmp_uses);
-         INIT_REG_SET (&tmp_sets);
-
-         (*current_sched_info->compute_jump_reg_dependencies)
-           (insn, &deps->reg_conditional_sets, &tmp_uses, &tmp_sets);
-         /* Make latency of jump equal to 0 by using anti-dependence.  */
-         EXECUTE_IF_SET_IN_REG_SET (&tmp_uses, 0, i, rsi)
-           {
-             struct deps_reg *reg_last = &deps->reg_last[i];
-             add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
-             add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_ANTI);
-             reg_last->uses_length++;
-             reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
-           }
-         IOR_REG_SET (reg_pending_sets, &tmp_sets);
 
-         CLEAR_REG_SET (&tmp_uses);
-         CLEAR_REG_SET (&tmp_sets);
+          if (sched_deps_info->compute_jump_reg_dependencies)
+            {
+              regset_head tmp_uses, tmp_sets;
+              INIT_REG_SET (&tmp_uses);
+              INIT_REG_SET (&tmp_sets);
+
+              (*sched_deps_info->compute_jump_reg_dependencies)
+                (insn, &deps->reg_conditional_sets, &tmp_uses, &tmp_sets);
+              /* Make latency of jump equal to 0 by using anti-dependence.  */
+              EXECUTE_IF_SET_IN_REG_SET (&tmp_uses, 0, i, rsi)
+                {
+                  struct deps_reg *reg_last = &deps->reg_last[i];
+                  add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
+                  add_dependence_list (insn, reg_last->implicit_sets,
+                                      0, REG_DEP_ANTI);
+                  add_dependence_list (insn, reg_last->clobbers, 0,
+                                      REG_DEP_ANTI);
+
+                  if (!deps->readonly)
+                    {
+                      reg_last->uses_length++;
+                      reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+                    }
+                }
+              IOR_REG_SET (reg_pending_sets, &tmp_sets);
+
+              CLEAR_REG_SET (&tmp_uses);
+              CLEAR_REG_SET (&tmp_sets);
+            }
 
          /* All memory writes and volatile reads must happen before the
             jump.  Non-volatile reads must happen before the jump iff
@@ -1984,35 +2773,54 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
       || (NONJUMP_INSN_P (insn) && control_flow_insn_p (insn)))
     reg_pending_barrier = MOVE_BARRIER;
 
-  /* Add register dependencies for insn.
-     If the current insn is conditional, we can't free any of the lists.  */
-  if (sched_get_condition (insn))
+  if (sched_pressure_p)
+    {
+      setup_insn_reg_uses (deps, insn);
+      setup_insn_reg_pressure_info (insn);
+    }
+
+  /* Add register dependencies for insn.  */
+  if (DEBUG_INSN_P (insn))
     {
+      rtx prev = deps->last_debug_insn;
+      rtx u;
+
+      if (!deps->readonly)
+       deps->last_debug_insn = insn;
+
+      if (prev)
+       add_dependence (insn, prev, REG_DEP_ANTI);
+
+      add_dependence_list (insn, deps->last_function_call, 1,
+                          REG_DEP_ANTI);
+
+      for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1))
+       if (! JUMP_P (XEXP (u, 0))
+           || !sel_sched_p ())
+         add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
       EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
        {
          struct deps_reg *reg_last = &deps->reg_last[i];
-         add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
-         add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
-         reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
-         reg_last->uses_length++;
-       }
-      EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
-       {
-         struct deps_reg *reg_last = &deps->reg_last[i];
-         add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
-         add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
-         reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
-         reg_last->clobbers_length++;
-       }
-      EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
-       {
-         struct deps_reg *reg_last = &deps->reg_last[i];
-         add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
-         add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_OUTPUT);
-         add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
-         reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-         SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+         add_dependence_list (insn, reg_last->sets, 1, REG_DEP_ANTI);
+         add_dependence_list (insn, reg_last->clobbers, 1, REG_DEP_ANTI);
+
+         if (!deps->readonly)
+           reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
        }
+      CLEAR_REG_SET (reg_pending_uses);
+
+      /* Quite often, a debug insn will refer to stuff in the
+        previous instruction, but the reason we want this
+        dependency here is to make sure the scheduler doesn't
+        gratuitously move a debug insn ahead.  This could dirty
+        DF flags and cause additional analysis that wouldn't have
+        occurred in compilation without debug insns, and such
+        additional analysis can modify the generated code.  */
+      prev = PREV_INSN (insn);
+
+      if (prev && NONDEBUG_INSN_P (prev))
+       add_dependence (insn, prev, REG_DEP_ANTI);
     }
   else
     {
@@ -2020,75 +2828,184 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
        {
          struct deps_reg *reg_last = &deps->reg_last[i];
          add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
+         add_dependence_list (insn, reg_last->implicit_sets, 0, REG_DEP_ANTI);
          add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
-         reg_last->uses_length++;
-         reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+         
+         if (!deps->readonly)
+           {
+             reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+             reg_last->uses_length++;
+           }
        }
-      EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
+      
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (TEST_HARD_REG_BIT (implicit_reg_pending_uses, i))
+         {
+           struct deps_reg *reg_last = &deps->reg_last[i];
+           add_dependence_list (insn, reg_last->sets, 0, REG_DEP_TRUE);
+           add_dependence_list (insn, reg_last->implicit_sets, 0,
+                                REG_DEP_ANTI);
+           add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_TRUE);
+           
+           if (!deps->readonly)
+             {
+               reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
+               reg_last->uses_length++;
+             }
+         }
+
+      /* If the current insn is conditional, we can't free any
+        of the lists.  */
+      if (sched_has_condition_p (insn))
        {
-         struct deps_reg *reg_last = &deps->reg_last[i];
-         if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH
-             || reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH)
+         EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
            {
-             add_dependence_list_and_free (insn, &reg_last->sets, 0,
-                                           REG_DEP_OUTPUT);
-             add_dependence_list_and_free (insn, &reg_last->uses, 0,
-                                           REG_DEP_ANTI);
-             add_dependence_list_and_free (insn, &reg_last->clobbers, 0,
-                                           REG_DEP_OUTPUT);
-             reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-             reg_last->clobbers_length = 0;
-             reg_last->uses_length = 0;
+             struct deps_reg *reg_last = &deps->reg_last[i];
+             add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
+             add_dependence_list (insn, reg_last->implicit_sets, 0,
+                                  REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
+             
+             if (!deps->readonly)
+               {
+                 reg_last->clobbers
+                   = alloc_INSN_LIST (insn, reg_last->clobbers);
+                 reg_last->clobbers_length++;
+               }
            }
-         else
+         EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
            {
+             struct deps_reg *reg_last = &deps->reg_last[i];
              add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
+             add_dependence_list (insn, reg_last->implicit_sets, 0,
+                                  REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_OUTPUT);
              add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
+             
+             if (!deps->readonly)
+               {
+                 reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                 SET_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+               }
+           }
+       }
+      else
+       {
+         EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, rsi)
+           {
+             struct deps_reg *reg_last = &deps->reg_last[i];
+             if (reg_last->uses_length > MAX_PENDING_LIST_LENGTH
+                 || reg_last->clobbers_length > MAX_PENDING_LIST_LENGTH)
+               {
+                 add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
+                                               REG_DEP_OUTPUT);
+                 add_dependence_list_and_free (deps, insn,
+                                               &reg_last->implicit_sets, 0,
+                                               REG_DEP_ANTI);
+                 add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
+                                               REG_DEP_ANTI);
+                 add_dependence_list_and_free
+                   (deps, insn, &reg_last->clobbers, 0, REG_DEP_OUTPUT);
+                 
+                 if (!deps->readonly)
+                   {
+                     reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                     reg_last->clobbers_length = 0;
+                     reg_last->uses_length = 0;
+                   }
+               }
+             else
+               {
+                 add_dependence_list (insn, reg_last->sets, 0, REG_DEP_OUTPUT);
+                 add_dependence_list (insn, reg_last->implicit_sets, 0,
+                                      REG_DEP_ANTI);
+                 add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
+               }
+             
+             if (!deps->readonly)
+               {
+                 reg_last->clobbers_length++;
+                 reg_last->clobbers
+                   = alloc_INSN_LIST (insn, reg_last->clobbers);
+               }
+           }
+         EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
+           {
+             struct deps_reg *reg_last = &deps->reg_last[i];
+             
+             add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
+                                           REG_DEP_OUTPUT);
+             add_dependence_list_and_free (deps, insn,
+                                           &reg_last->implicit_sets,
+                                           0, REG_DEP_ANTI);
+             add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
+                                           REG_DEP_OUTPUT);
+             add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
+                                           REG_DEP_ANTI);
+             
+             if (!deps->readonly)
+               {
+                 reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                 reg_last->uses_length = 0;
+                 reg_last->clobbers_length = 0;
+                 CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
+               }
            }
-         reg_last->clobbers_length++;
-         reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
-       }
-      EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, rsi)
-       {
-         struct deps_reg *reg_last = &deps->reg_last[i];
-         add_dependence_list_and_free (insn, &reg_last->sets, 0,
-                                       REG_DEP_OUTPUT);
-         add_dependence_list_and_free (insn, &reg_last->clobbers, 0,
-                                       REG_DEP_OUTPUT);
-         add_dependence_list_and_free (insn, &reg_last->uses, 0,
-                                       REG_DEP_ANTI);
-         reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-         reg_last->uses_length = 0;
-         reg_last->clobbers_length = 0;
-         CLEAR_REGNO_REG_SET (&deps->reg_conditional_sets, i);
        }
     }
 
-  IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
-  IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
-  IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (implicit_reg_pending_clobbers, i))
+      {
+       struct deps_reg *reg_last = &deps->reg_last[i];
+       add_dependence_list (insn, reg_last->sets, 0, REG_DEP_ANTI);
+       add_dependence_list (insn, reg_last->clobbers, 0, REG_DEP_ANTI);
+       add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
+       
+       if (!deps->readonly)
+         reg_last->implicit_sets
+           = alloc_INSN_LIST (insn, reg_last->implicit_sets);
+      }
+
+  if (!deps->readonly)
+    {
+      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
+      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
+      IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (TEST_HARD_REG_BIT (implicit_reg_pending_uses, i)
+           || TEST_HARD_REG_BIT (implicit_reg_pending_clobbers, i))
+         SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
+
+      /* Set up the pending barrier found.  */
+      deps->last_reg_pending_barrier = reg_pending_barrier;
+    }
 
   CLEAR_REG_SET (reg_pending_uses);
   CLEAR_REG_SET (reg_pending_clobbers);
   CLEAR_REG_SET (reg_pending_sets);
+  CLEAR_HARD_REG_SET (implicit_reg_pending_clobbers);
+  CLEAR_HARD_REG_SET (implicit_reg_pending_uses);
 
   /* Add dependencies if a scheduling barrier was found.  */
   if (reg_pending_barrier)
     {
       /* In the case of barrier the most added dependencies are not
          real, so we use anti-dependence here.  */
-      if (sched_get_condition (insn))
+      if (sched_has_condition_p (insn))
        {
          EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi)
            {
              struct deps_reg *reg_last = &deps->reg_last[i];
              add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
-             add_dependence_list
-               (insn, reg_last->sets, 0,
-                reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
-             add_dependence_list
-               (insn, reg_last->clobbers, 0,
-                reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->sets, 0,
+                                  reg_pending_barrier == TRUE_BARRIER
+                                  ? REG_DEP_TRUE : REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->implicit_sets, 0,
+                                  REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->clobbers, 0,
+                                  reg_pending_barrier == TRUE_BARRIER
+                                  ? REG_DEP_TRUE : REG_DEP_ANTI);
            }
        }
       else
@@ -2096,28 +3013,41 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
          EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi)
            {
              struct deps_reg *reg_last = &deps->reg_last[i];
-             add_dependence_list_and_free (insn, &reg_last->uses, 0,
+             add_dependence_list_and_free (deps, insn, &reg_last->uses, 0,
+                                           REG_DEP_ANTI);
+             add_dependence_list_and_free (deps, insn, &reg_last->sets, 0,
+                                           reg_pending_barrier == TRUE_BARRIER
+                                           ? REG_DEP_TRUE : REG_DEP_ANTI);
+             add_dependence_list_and_free (deps, insn,
+                                           &reg_last->implicit_sets, 0,
                                            REG_DEP_ANTI);
-             add_dependence_list_and_free
-               (insn, &reg_last->sets, 0,
-                reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
-             add_dependence_list_and_free
-               (insn, &reg_last->clobbers, 0,
-                reg_pending_barrier == TRUE_BARRIER ? REG_DEP_TRUE : REG_DEP_ANTI);
-             reg_last->uses_length = 0;
-             reg_last->clobbers_length = 0;
+             add_dependence_list_and_free (deps, insn, &reg_last->clobbers, 0,
+                                           reg_pending_barrier == TRUE_BARRIER
+                                           ? REG_DEP_TRUE : REG_DEP_ANTI);
+
+              if (!deps->readonly)
+                {
+                  reg_last->uses_length = 0;
+                  reg_last->clobbers_length = 0;
+                }
            }
        }
 
-      for (i = 0; i < (unsigned)deps->max_reg; i++)
-       {
-         struct deps_reg *reg_last = &deps->reg_last[i];
-         reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
-         SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
-       }
-
-      flush_pending_lists (deps, insn, true, true);
-      CLEAR_REG_SET (&deps->reg_conditional_sets);
+      if (!deps->readonly)
+        for (i = 0; i < (unsigned)deps->max_reg; i++)
+          {
+            struct deps_reg *reg_last = &deps->reg_last[i];
+            reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+            SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
+          }
+
+      /* Flush pending lists on jumps, but not on speculative checks.  */
+      if (JUMP_P (insn) && !(sel_sched_p () 
+                             && sel_insn_is_speculation_check (insn)))
+       flush_pending_lists (deps, insn, true, true);
+      
+      if (!deps->readonly)
+        CLEAR_REG_SET (&deps->reg_conditional_sets);
       reg_pending_barrier = NOT_A_BARRIER;
     }
 
@@ -2136,7 +3066,30 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
       int src_regno, dest_regno;
 
       if (set == NULL)
-       goto end_call_group;
+       {
+         if (DEBUG_INSN_P (insn))
+           /* We don't want to mark debug insns as part of the same
+              sched group.  We know they really aren't, but if we use
+              debug insns to tell that a call group is over, we'll
+              get different code if debug insns are not there and
+              instructions that follow seem like they should be part
+              of the call group.
+
+              Also, if we did, fixup_sched_groups() would move the
+              deps of the debug insn to the call insn, modifying
+              non-debug post-dependency counts of the debug insn
+              dependencies and otherwise messing with the scheduling
+              order.
+
+              Instead, let such debug insns be scheduled freely, but
+              keep the call group open in case there are insns that
+              should be part of it afterwards.  Since we grant debug
+              insns higher priority than even sched group insns, it
+              will all turn out all right.  */
+           goto debug_dont_end_call_group;
+         else
+           goto end_call_group;
+       }
 
       tmp = SET_DEST (set);
       if (GET_CODE (tmp) == SUBREG)
@@ -2163,160 +3116,290 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
       if (src_regno < FIRST_PSEUDO_REGISTER
          || dest_regno < FIRST_PSEUDO_REGISTER)
        {
-         if (deps->in_post_call_group_p == post_call_initial)
+         if (!deps->readonly
+              && deps->in_post_call_group_p == post_call_initial)
            deps->in_post_call_group_p = post_call;
 
-         SCHED_GROUP_P (insn) = 1;
-         CANT_MOVE (insn) = 1;
+          if (!sel_sched_p () || sched_emulate_haifa_p) 
+            {
+              SCHED_GROUP_P (insn) = 1;
+              CANT_MOVE (insn) = 1;
+            }
        }
       else
        {
        end_call_group:
-         deps->in_post_call_group_p = not_post_call;
+          if (!deps->readonly)
+            deps->in_post_call_group_p = not_post_call;
        }
     }
 
-  /* Fixup the dependencies in the sched group.  */
-  if (SCHED_GROUP_P (insn))
-    fixup_sched_groups (insn);
-
+ debug_dont_end_call_group:
   if ((current_sched_info->flags & DO_SPECULATION)
       && !sched_insn_is_legitimate_for_speculation_p (insn, 0))
     /* INSN has an internal dependency (e.g. r14 = [r14]) and thus cannot
        be speculated.  */
     {
-      sd_iterator_def sd_it;
-      dep_t dep;
-
-      for (sd_it = sd_iterator_start (insn, SD_LIST_SPEC_BACK);
-          sd_iterator_cond (&sd_it, &dep);)
-       change_spec_dep_to_hard (sd_it);
+      if (sel_sched_p ())
+        sel_mark_hard_insn (insn);
+      else
+        {
+          sd_iterator_def sd_it;
+          dep_t dep;
+          
+          for (sd_it = sd_iterator_start (insn, SD_LIST_SPEC_BACK);
+               sd_iterator_cond (&sd_it, &dep);)
+            change_spec_dep_to_hard (sd_it);
+        }
     }
 }
 
-/* Analyze every insn between HEAD and TAIL inclusive, creating backward
-   dependencies for each insn.  */
+/* Return TRUE if INSN might not always return normally (e.g. call exit,
+   longjmp, loop forever, ...).  */
+static bool
+call_may_noreturn_p (rtx insn)
+{
+  rtx call;
+
+  /* const or pure calls that aren't looping will always return.  */
+  if (RTL_CONST_OR_PURE_CALL_P (insn)
+      && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn))
+    return false;
+
+  call = PATTERN (insn);
+  if (GET_CODE (call) == PARALLEL)
+    call = XVECEXP (call, 0, 0);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
+  if (GET_CODE (call) == CALL
+      && MEM_P (XEXP (call, 0))
+      && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+    {
+      rtx symbol = XEXP (XEXP (call, 0), 0);
+      if (SYMBOL_REF_DECL (symbol)
+         && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL)
+       {
+         if (DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (symbol))
+             == BUILT_IN_NORMAL)
+           switch (DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol)))
+             {
+             case BUILT_IN_BCMP:
+             case BUILT_IN_BCOPY:
+             case BUILT_IN_BZERO:
+             case BUILT_IN_INDEX:
+             case BUILT_IN_MEMCHR:
+             case BUILT_IN_MEMCMP:
+             case BUILT_IN_MEMCPY:
+             case BUILT_IN_MEMMOVE:
+             case BUILT_IN_MEMPCPY:
+             case BUILT_IN_MEMSET:
+             case BUILT_IN_RINDEX:
+             case BUILT_IN_STPCPY:
+             case BUILT_IN_STPNCPY:
+             case BUILT_IN_STRCAT:
+             case BUILT_IN_STRCHR:
+             case BUILT_IN_STRCMP:
+             case BUILT_IN_STRCPY:
+             case BUILT_IN_STRCSPN:
+             case BUILT_IN_STRLEN:
+             case BUILT_IN_STRNCAT:
+             case BUILT_IN_STRNCMP:
+             case BUILT_IN_STRNCPY:
+             case BUILT_IN_STRPBRK:
+             case BUILT_IN_STRRCHR:
+             case BUILT_IN_STRSPN:
+             case BUILT_IN_STRSTR:
+               /* Assume certain string/memory builtins always return.  */
+               return false;
+             default:
+               break;
+             }
+       }
+    }
+
+  /* For all other calls assume that they might not always return.  */
+  return true;
+}
 
+/* Analyze INSN with DEPS as a context.  */
 void
-sched_analyze (struct deps *deps, rtx head, rtx tail)
+deps_analyze_insn (struct deps *deps, rtx insn)
 {
-  rtx insn;
+  if (sched_deps_info->start_insn)
+    sched_deps_info->start_insn (insn);
 
-  if (current_sched_info->use_cselib)
-    cselib_init (true);
+  if (NONJUMP_INSN_P (insn) || DEBUG_INSN_P (insn) || JUMP_P (insn))
+    {
+      /* Make each JUMP_INSN (but not a speculative check) 
+         a scheduling barrier for memory references.  */
+      if (!deps->readonly
+          && JUMP_P (insn) 
+          && !(sel_sched_p () 
+               && sel_insn_is_speculation_check (insn)))
+        {
+          /* Keep the list a reasonable size.  */
+          if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH)
+            flush_pending_lists (deps, insn, true, true);
+          else
+            deps->last_pending_memory_flush
+              = alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
+        }
+
+      sched_analyze_insn (deps, PATTERN (insn), insn);
+    }
+  else if (CALL_P (insn))
+    {
+      int i;
+
+      CANT_MOVE (insn) = 1;
+
+      if (find_reg_note (insn, REG_SETJMP, NULL))
+        {
+          /* This is setjmp.  Assume that all registers, not just
+             hard registers, may be clobbered by this call.  */
+          reg_pending_barrier = MOVE_BARRIER;
+        }
+      else
+        {
+          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+            /* A call may read and modify global register variables.  */
+            if (global_regs[i])
+              {
+                SET_REGNO_REG_SET (reg_pending_sets, i);
+                SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
+              }
+          /* Other call-clobbered hard regs may be clobbered.
+             Since we only have a choice between 'might be clobbered'
+             and 'definitely not clobbered', we must include all
+             partly call-clobbered registers here.  */
+            else if (HARD_REGNO_CALL_PART_CLOBBERED (i, reg_raw_mode[i])
+                     || TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+              SET_REGNO_REG_SET (reg_pending_clobbers, i);
+          /* We don't know what set of fixed registers might be used
+             by the function, but it is certain that the stack pointer
+             is among them, but be conservative.  */
+            else if (fixed_regs[i])
+             SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
+          /* The frame pointer is normally not used by the function
+             itself, but by the debugger.  */
+          /* ??? MIPS o32 is an exception.  It uses the frame pointer
+             in the macro expansion of jal but does not represent this
+             fact in the call_insn rtl.  */
+            else if (i == FRAME_POINTER_REGNUM
+                     || (i == HARD_FRAME_POINTER_REGNUM
+                         && (! reload_completed || frame_pointer_needed)))
+             SET_HARD_REG_BIT (implicit_reg_pending_uses, i);
+        }
+
+      /* For each insn which shouldn't cross a call, add a dependence
+         between that insn and this call insn.  */
+      add_dependence_list_and_free (deps, insn, 
+                                    &deps->sched_before_next_call, 1,
+                                    REG_DEP_ANTI);
+
+      sched_analyze_insn (deps, PATTERN (insn), insn);
+
+      /* If CALL would be in a sched group, then this will violate
+        convention that sched group insns have dependencies only on the
+        previous instruction.
+
+        Of course one can say: "Hey!  What about head of the sched group?"
+        And I will answer: "Basic principles (one dep per insn) are always
+        the same."  */
+      gcc_assert (!SCHED_GROUP_P (insn));
+
+      /* In the absence of interprocedural alias analysis, we must flush
+         all pending reads and writes, and start new dependencies starting
+         from here.  But only flush writes for constant calls (which may
+         be passed a pointer to something we haven't written yet).  */
+      flush_pending_lists (deps, insn, true, ! RTL_CONST_OR_PURE_CALL_P (insn));
+
+      if (!deps->readonly)
+        {
+          /* Remember the last function call for limiting lifetimes.  */
+          free_INSN_LIST_list (&deps->last_function_call);
+          deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
+
+         if (call_may_noreturn_p (insn))
+           {
+             /* Remember the last function call that might not always return
+                normally for limiting moves of trapping insns.  */
+             free_INSN_LIST_list (&deps->last_function_call_may_noreturn);
+             deps->last_function_call_may_noreturn
+               = alloc_INSN_LIST (insn, NULL_RTX);
+           }
+
+          /* Before reload, begin a post-call group, so as to keep the
+             lifetimes of hard registers correct.  */
+          if (! reload_completed)
+            deps->in_post_call_group_p = post_call;
+        }
+    }
+
+  if (sched_deps_info->use_cselib)
+    cselib_process_insn (insn);
+
+  /* EH_REGION insn notes can not appear until well after we complete
+     scheduling.  */
+  if (NOTE_P (insn))
+    gcc_assert (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
+               && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END);
+
+  if (sched_deps_info->finish_insn)
+    sched_deps_info->finish_insn ();
+
+  /* Fixup the dependencies in the sched group.  */
+  if ((NONJUMP_INSN_P (insn) || JUMP_P (insn)) 
+      && SCHED_GROUP_P (insn) && !sel_sched_p ())
+    fixup_sched_groups (insn);
+}
+
+/* Initialize DEPS for the new block beginning with HEAD.  */
+void
+deps_start_bb (struct deps *deps, rtx head)
+{
+  gcc_assert (!deps->readonly);
 
   /* Before reload, if the previous block ended in a call, show that
      we are inside a post-call group, so as to keep the lifetimes of
      hard registers correct.  */
   if (! reload_completed && !LABEL_P (head))
     {
-      insn = prev_nonnote_insn (head);
+      rtx insn = prev_nonnote_insn (head);
+
+      while (insn && DEBUG_INSN_P (insn))
+       insn = prev_nonnote_insn (insn);
       if (insn && CALL_P (insn))
        deps->in_post_call_group_p = post_call_initial;
     }
+}
+
+/* Analyze every insn between HEAD and TAIL inclusive, creating backward
+   dependencies for each insn.  */
+void
+sched_analyze (struct deps *deps, rtx head, rtx tail)
+{
+  rtx insn;
+
+  if (sched_deps_info->use_cselib)
+    cselib_init (true);
+
+  deps_start_bb (deps, head);
+
   for (insn = head;; insn = NEXT_INSN (insn))
     {
+
       if (INSN_P (insn))
        {
          /* And initialize deps_lists.  */
          sd_init_insn (insn);
        }
 
-      if (NONJUMP_INSN_P (insn) || JUMP_P (insn))
-       {
-         /* Make each JUMP_INSN a scheduling barrier for memory
-             references.  */
-         if (JUMP_P (insn))
-           {
-             /* Keep the list a reasonable size.  */
-             if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH)
-               flush_pending_lists (deps, insn, true, true);
-             else
-               deps->last_pending_memory_flush
-                 = alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
-           }
-         sched_analyze_insn (deps, PATTERN (insn), insn);
-       }
-      else if (CALL_P (insn))
-       {
-         int i;
-
-         CANT_MOVE (insn) = 1;
-
-         if (find_reg_note (insn, REG_SETJMP, NULL))
-           {
-             /* This is setjmp.  Assume that all registers, not just
-                hard registers, may be clobbered by this call.  */
-             reg_pending_barrier = MOVE_BARRIER;
-           }
-         else
-           {
-             for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-               /* A call may read and modify global register variables.  */
-               if (global_regs[i])
-                 {
-                   SET_REGNO_REG_SET (reg_pending_sets, i);
-                   SET_REGNO_REG_SET (reg_pending_uses, i);
-                 }
-               /* Other call-clobbered hard regs may be clobbered.
-                  Since we only have a choice between 'might be clobbered'
-                  and 'definitely not clobbered', we must include all
-                  partly call-clobbered registers here.  */
-               else if (HARD_REGNO_CALL_PART_CLOBBERED (i, reg_raw_mode[i])
-                        || TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
-                 SET_REGNO_REG_SET (reg_pending_clobbers, i);
-               /* We don't know what set of fixed registers might be used
-                  by the function, but it is certain that the stack pointer
-                  is among them, but be conservative.  */
-               else if (fixed_regs[i])
-                 SET_REGNO_REG_SET (reg_pending_uses, i);
-               /* The frame pointer is normally not used by the function
-                  itself, but by the debugger.  */
-               /* ??? MIPS o32 is an exception.  It uses the frame pointer
-                  in the macro expansion of jal but does not represent this
-                  fact in the call_insn rtl.  */
-               else if (i == FRAME_POINTER_REGNUM
-                        || (i == HARD_FRAME_POINTER_REGNUM
-                            && (! reload_completed || frame_pointer_needed)))
-                 SET_REGNO_REG_SET (reg_pending_uses, i);
-           }
-
-         /* For each insn which shouldn't cross a call, add a dependence
-            between that insn and this call insn.  */
-         add_dependence_list_and_free (insn, &deps->sched_before_next_call, 1,
-                                       REG_DEP_ANTI);
-
-         sched_analyze_insn (deps, PATTERN (insn), insn);
-
-         /* In the absence of interprocedural alias analysis, we must flush
-            all pending reads and writes, and start new dependencies starting
-            from here.  But only flush writes for constant calls (which may
-            be passed a pointer to something we haven't written yet).  */
-         flush_pending_lists (deps, insn, true, 
-                              ! RTL_CONST_OR_PURE_CALL_P (insn));
-
-         /* Remember the last function call for limiting lifetimes.  */
-         free_INSN_LIST_list (&deps->last_function_call);
-         deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
-
-         /* Before reload, begin a post-call group, so as to keep the
-            lifetimes of hard registers correct.  */
-         if (! reload_completed)
-           deps->in_post_call_group_p = post_call;
-       }
-
-      /* EH_REGION insn notes can not appear until well after we complete
-        scheduling.  */
-      if (NOTE_P (insn))
-       gcc_assert (NOTE_KIND (insn) != NOTE_INSN_EH_REGION_BEG
-                   && NOTE_KIND (insn) != NOTE_INSN_EH_REGION_END);
-
-      if (current_sched_info->use_cselib)
-       cselib_process_insn (insn);
+      deps_analyze_insn (deps, insn);
 
       if (insn == tail)
        {
-         if (current_sched_info->use_cselib)
+         if (sched_deps_info->use_cselib)
            cselib_finish ();
          return;
        }
@@ -2378,15 +3461,19 @@ sched_free_deps (rtx head, rtx tail, bool resolved_p)
 }
 \f
 /* Initialize variables for region data dependence analysis.
-   n_bbs is the number of region blocks.  */
+   When LAZY_REG_LAST is true, do not allocate reg_last array 
+   of struct deps immediately.  */
 
 void
-init_deps (struct deps *deps)
+init_deps (struct deps *deps, bool lazy_reg_last)
 {
   int max_reg = (reload_completed ? FIRST_PSEUDO_REGISTER : max_reg_num ());
 
   deps->max_reg = max_reg;
-  deps->reg_last = XCNEWVEC (struct deps_reg, max_reg);
+  if (lazy_reg_last)
+    deps->reg_last = NULL;
+  else
+    deps->reg_last = XCNEWVEC (struct deps_reg, max_reg);
   INIT_REG_SET (&deps->reg_last_in_use);
   INIT_REG_SET (&deps->reg_conditional_sets);
 
@@ -2399,10 +3486,26 @@ init_deps (struct deps *deps)
   deps->pending_flush_length = 0;
   deps->last_pending_memory_flush = 0;
   deps->last_function_call = 0;
+  deps->last_function_call_may_noreturn = 0;
   deps->sched_before_next_call = 0;
   deps->in_post_call_group_p = not_post_call;
+  deps->last_debug_insn = 0;
+  deps->last_reg_pending_barrier = NOT_A_BARRIER;
+  deps->readonly = 0;
+}
+
+/* Init only reg_last field of DEPS, which was not allocated before as 
+   we inited DEPS lazily.  */
+void
+init_deps_reg_last (struct deps *deps)
+{
+  gcc_assert (deps && deps->max_reg > 0);
+  gcc_assert (deps->reg_last == NULL);
+
+  deps->reg_last = XCNEWVEC (struct deps_reg, deps->max_reg);
 }
 
+
 /* Free insn lists found in DEPS.  */
 
 void
@@ -2411,6 +3514,14 @@ free_deps (struct deps *deps)
   unsigned i;
   reg_set_iterator rsi;
 
+  /* We set max_reg to 0 when this context was already freed.  */
+  if (deps->max_reg == 0)
+    {
+      gcc_assert (deps->reg_last == NULL);
+      return;
+    }
+  deps->max_reg = 0;
+  
   free_INSN_LIST_list (&deps->pending_read_insns);
   free_EXPR_LIST_list (&deps->pending_read_mems);
   free_INSN_LIST_list (&deps->pending_write_insns);
@@ -2427,49 +3538,118 @@ free_deps (struct deps *deps)
        free_INSN_LIST_list (&reg_last->uses);
       if (reg_last->sets)
        free_INSN_LIST_list (&reg_last->sets);
+      if (reg_last->implicit_sets)
+       free_INSN_LIST_list (&reg_last->implicit_sets);
       if (reg_last->clobbers)
        free_INSN_LIST_list (&reg_last->clobbers);
     }
   CLEAR_REG_SET (&deps->reg_last_in_use);
   CLEAR_REG_SET (&deps->reg_conditional_sets);
 
-  free (deps->reg_last);
+  /* As we initialize reg_last lazily, it is possible that we didn't allocate 
+     it at all.  */
+  if (deps->reg_last)
+    free (deps->reg_last);
+  deps->reg_last = NULL;
+
+  deps = NULL;
+}
+
+/* Remove INSN from dependence contexts DEPS.  Caution: reg_conditional_sets
+   is not handled.  */
+void
+remove_from_deps (struct deps *deps, rtx insn)
+{
+  int removed;
+  unsigned i;
+  reg_set_iterator rsi;
+  
+  removed = remove_from_both_dependence_lists (insn, &deps->pending_read_insns,
+                                               &deps->pending_read_mems);
+  if (!DEBUG_INSN_P (insn))
+    deps->pending_read_list_length -= removed;
+  removed = remove_from_both_dependence_lists (insn, &deps->pending_write_insns,
+                                               &deps->pending_write_mems);
+  deps->pending_write_list_length -= removed;
+  removed = remove_from_dependence_list (insn, &deps->last_pending_memory_flush);
+  deps->pending_flush_length -= removed;
+
+  EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i, rsi)
+    {
+      struct deps_reg *reg_last = &deps->reg_last[i];
+      if (reg_last->uses)
+       remove_from_dependence_list (insn, &reg_last->uses);
+      if (reg_last->sets)
+       remove_from_dependence_list (insn, &reg_last->sets);
+      if (reg_last->implicit_sets)
+       remove_from_dependence_list (insn, &reg_last->implicit_sets);
+      if (reg_last->clobbers)
+       remove_from_dependence_list (insn, &reg_last->clobbers);
+      if (!reg_last->uses && !reg_last->sets && !reg_last->implicit_sets
+         && !reg_last->clobbers)
+        CLEAR_REGNO_REG_SET (&deps->reg_last_in_use, i);
+    }
+
+  if (CALL_P (insn))
+    {
+      remove_from_dependence_list (insn, &deps->last_function_call);
+      remove_from_dependence_list (insn, 
+                                  &deps->last_function_call_may_noreturn);
+    }
+  remove_from_dependence_list (insn, &deps->sched_before_next_call);
 }
 
-/* If it is profitable to use them, initialize caches for tracking
-   dependency information.  LUID is the number of insns to be scheduled,
-   it is used in the estimate of profitability.  */
+/* Init deps data vector.  */
+static void
+init_deps_data_vector (void)
+{
+  int reserve = (sched_max_luid + 1 
+                 - VEC_length (haifa_deps_insn_data_def, h_d_i_d));
+  if (reserve > 0 
+      && ! VEC_space (haifa_deps_insn_data_def, h_d_i_d, reserve))
+    VEC_safe_grow_cleared (haifa_deps_insn_data_def, heap, h_d_i_d,
+                           3 * sched_max_luid / 2);
+}
 
+/* If it is profitable to use them, initialize or extend (depending on
+   GLOBAL_P) dependency data.  */
 void
-init_dependency_caches (int luid)
+sched_deps_init (bool global_p)
 {
   /* Average number of insns in the basic block.
      '+ 1' is used to make it nonzero.  */
-  int insns_in_block = luid / n_basic_blocks + 1;
+  int insns_in_block = sched_max_luid / n_basic_blocks + 1;
 
-  /* ?!? We could save some memory by computing a per-region luid mapping
-     which could reduce both the number of vectors in the cache and the size
-     of each vector.  Instead we just avoid the cache entirely unless the
-     average number of instructions in a basic block is very high.  See
-     the comment before the declaration of true_dependency_cache for
-     what we consider "very high".  */
-  if (insns_in_block > 100 * 5)
+  init_deps_data_vector ();
+  
+  /* We use another caching mechanism for selective scheduling, so 
+     we don't use this one.  */
+  if (!sel_sched_p () && global_p && insns_in_block > 100 * 5)
     {
+      /* ?!? We could save some memory by computing a per-region luid mapping
+         which could reduce both the number of vectors in the cache and the
+         size of each vector.  Instead we just avoid the cache entirely unless
+         the average number of instructions in a basic block is very high.  See
+         the comment before the declaration of true_dependency_cache for
+         what we consider "very high".  */
       cache_size = 0;
-      extend_dependency_caches (luid, true);
+      extend_dependency_caches (sched_max_luid, true);
     }
 
-  dl_pool = create_alloc_pool ("deps_list", sizeof (struct _deps_list),
-                              /* Allocate lists for one block at a time.  */
-                              insns_in_block);
-
-  dn_pool = create_alloc_pool ("dep_node", sizeof (struct _dep_node),
-                              /* Allocate nodes for one block at a time.
-                                 We assume that average insn has
-                                 5 producers.  */
-                              5 * insns_in_block);
+  if (global_p) 
+    {
+      dl_pool = create_alloc_pool ("deps_list", sizeof (struct _deps_list),
+                                   /* Allocate lists for one block at a time.  */
+                                   insns_in_block);
+      dn_pool = create_alloc_pool ("dep_node", sizeof (struct _dep_node),
+                                   /* Allocate nodes for one block at a time.
+                                      We assume that average insn has
+                                      5 producers.  */
+                                   5 * insns_in_block);
+    }
 }
 
+
 /* Create or extend (depending on CREATE_P) dependency caches to
    size N.  */
 void
@@ -2503,16 +3683,18 @@ extend_dependency_caches (int n, bool create_p)
     }
 }
 
-/* Free the caches allocated in init_dependency_caches.  */
-
+/* Finalize dependency information for the whole function.  */
 void
-free_dependency_caches (void)
+sched_deps_finish (void)
 {
   gcc_assert (deps_pools_are_empty_p ());
   free_alloc_pool_if_empty (&dn_pool);
   free_alloc_pool_if_empty (&dl_pool);
   gcc_assert (dn_pool == NULL && dl_pool == NULL);
 
+  VEC_free (haifa_deps_insn_data_def, heap, h_d_i_d);
+  cache_size = 0;
+  
   if (true_dependency_cache)
     {
       int i;
@@ -2523,7 +3705,7 @@ free_dependency_caches (void)
          bitmap_clear (&output_dependency_cache[i]);
          bitmap_clear (&anti_dependency_cache[i]);
 
-          if (current_sched_info->flags & DO_SPECULATION)
+          if (sched_deps_info->generate_spec_deps)
             bitmap_clear (&spec_dependency_cache[i]);
        }
       free (true_dependency_cache);
@@ -2533,11 +3715,12 @@ free_dependency_caches (void)
       free (anti_dependency_cache);
       anti_dependency_cache = NULL;
 
-      if (current_sched_info->flags & DO_SPECULATION)
+      if (sched_deps_info->generate_spec_deps)
         {
           free (spec_dependency_cache);
           spec_dependency_cache = NULL;
         }
+
     }
 }
 
@@ -2547,10 +3730,25 @@ free_dependency_caches (void)
 void
 init_deps_global (void)
 {
+  CLEAR_HARD_REG_SET (implicit_reg_pending_clobbers);
+  CLEAR_HARD_REG_SET (implicit_reg_pending_uses);
   reg_pending_sets = ALLOC_REG_SET (&reg_obstack);
   reg_pending_clobbers = ALLOC_REG_SET (&reg_obstack);
   reg_pending_uses = ALLOC_REG_SET (&reg_obstack);
   reg_pending_barrier = NOT_A_BARRIER;
+
+  if (!sel_sched_p () || sched_emulate_haifa_p)
+    {
+      sched_deps_info->start_insn = haifa_start_insn;
+      sched_deps_info->finish_insn = haifa_finish_insn;
+
+      sched_deps_info->note_reg_set = haifa_note_reg_set;
+      sched_deps_info->note_reg_clobber = haifa_note_reg_clobber;
+      sched_deps_info->note_reg_use = haifa_note_reg_use;
+
+      sched_deps_info->note_mem_dep = haifa_note_mem_dep;
+      sched_deps_info->note_dep = haifa_note_dep;
+   }
 }
 
 /* Free everything used by the dependency analysis code.  */
@@ -2564,7 +3762,7 @@ finish_deps_global (void)
 }
 
 /* Estimate the weakness of dependence between MEM1 and MEM2.  */
-static dw_t
+dw_t
 estimate_dep_weak (rtx mem1, rtx mem2)
 {
   rtx r1, r2;
@@ -2597,17 +3795,38 @@ estimate_dep_weak (rtx mem1, rtx mem2)
 void
 add_dependence (rtx insn, rtx elem, enum reg_note dep_type)
 {
-  dep_def _dep, *dep = &_dep;
+  ds_t ds;
+  bool internal;
 
-  init_dep (dep, elem, insn, dep_type);
-  maybe_add_or_update_dep_1 (dep, false, NULL_RTX, NULL_RTX);
+  if (dep_type == REG_DEP_TRUE)
+    ds = DEP_TRUE;
+  else if (dep_type == REG_DEP_OUTPUT)
+    ds = DEP_OUTPUT;
+  else
+    {
+      gcc_assert (dep_type == REG_DEP_ANTI);
+      ds = DEP_ANTI;
+    }
+
+  /* When add_dependence is called from inside sched-deps.c, we expect
+     cur_insn to be non-null.  */
+  internal = cur_insn != NULL;
+  if (internal)
+    gcc_assert (insn == cur_insn);
+  else
+    cur_insn = insn;
+      
+  note_dep (elem, ds);
+  if (!internal)
+    cur_insn = NULL;
 }
 
 /* Return weakness of speculative type TYPE in the dep_status DS.  */
-static dw_t
+dw_t
 get_dep_weak_1 (ds_t ds, ds_t type)
 {
   ds = ds & type;
+
   switch (type)
     {
     case BEGIN_DATA: ds >>= BEGIN_DATA_BITS_OFFSET; break;
@@ -2620,14 +3839,12 @@ get_dep_weak_1 (ds_t ds, ds_t type)
   return (dw_t) ds;
 }
 
-/* Return weakness of speculative type TYPE in the dep_status DS.  */
 dw_t
 get_dep_weak (ds_t ds, ds_t type)
 {
   dw_t dw = get_dep_weak_1 (ds, type);
 
   gcc_assert (MIN_DEP_WEAK <= dw && dw <= MAX_DEP_WEAK);
-
   return dw;
 }
 
@@ -2650,9 +3867,12 @@ set_dep_weak (ds_t ds, ds_t type, dw_t dw)
   return ds;
 }
 
-/* Return the join of two dep_statuses DS1 and DS2.  */
-ds_t
-ds_merge (ds_t ds1, ds_t ds2)
+/* Return the join of two dep_statuses DS1 and DS2.
+   If MAX_P is true then choose the greater probability,
+   otherwise multiply probabilities.
+   This function assumes that both DS1 and DS2 contain speculative bits.  */
+static ds_t
+ds_merge_1 (ds_t ds1, ds_t ds2, bool max_p)
 {
   ds_t ds, t;
 
@@ -2669,12 +3889,24 @@ ds_merge (ds_t ds1, ds_t ds2)
        ds |= ds2 & t;
       else if ((ds1 & t) && (ds2 & t))
        {
+         dw_t dw1 = get_dep_weak (ds1, t);
+         dw_t dw2 = get_dep_weak (ds2, t);
          ds_t dw;
 
-         dw = ((ds_t) get_dep_weak (ds1, t)) * ((ds_t) get_dep_weak (ds2, t));
-         dw /= MAX_DEP_WEAK;
-         if (dw < MIN_DEP_WEAK)
-           dw = MIN_DEP_WEAK;
+         if (!max_p)
+           {
+             dw = ((ds_t) dw1) * ((ds_t) dw2);
+             dw /= MAX_DEP_WEAK;
+             if (dw < MIN_DEP_WEAK)
+               dw = MIN_DEP_WEAK;
+           }
+         else
+           {
+             if (dw1 >= dw2)
+               dw = dw1;
+             else
+               dw = dw2;
+           }
 
          ds = set_dep_weak (ds, t, (dw_t) dw);
        }
@@ -2688,6 +3920,134 @@ ds_merge (ds_t ds1, ds_t ds2)
   return ds;
 }
 
+/* Return the join of two dep_statuses DS1 and DS2.
+   This function assumes that both DS1 and DS2 contain speculative bits.  */
+ds_t
+ds_merge (ds_t ds1, ds_t ds2)
+{
+  return ds_merge_1 (ds1, ds2, false);
+}
+
+/* Return the join of two dep_statuses DS1 and DS2.  */
+ds_t
+ds_full_merge (ds_t ds, ds_t ds2, rtx mem1, rtx mem2)
+{
+  ds_t new_status = ds | ds2;
+
+  if (new_status & SPECULATIVE)
+    {
+      if ((ds && !(ds & SPECULATIVE))
+         || (ds2 && !(ds2 & SPECULATIVE)))
+       /* Then this dep can't be speculative.  */
+       new_status &= ~SPECULATIVE;
+      else
+       {
+         /* Both are speculative.  Merging probabilities.  */
+         if (mem1)
+           {
+             dw_t dw;
+
+             dw = estimate_dep_weak (mem1, mem2);
+             ds = set_dep_weak (ds, BEGIN_DATA, dw);
+           }
+
+         if (!ds)
+           new_status = ds2;
+         else if (!ds2)
+           new_status = ds;
+         else
+           new_status = ds_merge (ds2, ds);
+       }
+    }
+
+  return new_status;
+}
+
+/* Return the join of DS1 and DS2.  Use maximum instead of multiplying
+   probabilities.  */
+ds_t
+ds_max_merge (ds_t ds1, ds_t ds2)
+{
+  if (ds1 == 0 && ds2 == 0)
+    return 0;
+
+  if (ds1 == 0 && ds2 != 0)
+    return ds2;
+
+  if (ds1 != 0 && ds2 == 0)
+    return ds1;
+
+  return ds_merge_1 (ds1, ds2, true);
+}
+
+/* Return the probability of speculation success for the speculation
+   status DS.  */
+dw_t
+ds_weak (ds_t ds)
+{
+  ds_t res = 1, dt;
+  int n = 0;
+
+  dt = FIRST_SPEC_TYPE;
+  do
+    {
+      if (ds & dt)
+       {
+         res *= (ds_t) get_dep_weak (ds, dt);
+         n++;
+       }
+
+      if (dt == LAST_SPEC_TYPE)
+       break;
+      dt <<= SPEC_TYPE_SHIFT;
+    }
+  while (1);
+
+  gcc_assert (n);
+  while (--n)
+    res /= MAX_DEP_WEAK;
+
+  if (res < MIN_DEP_WEAK)
+    res = MIN_DEP_WEAK;
+
+  gcc_assert (res <= MAX_DEP_WEAK);
+
+  return (dw_t) res;
+}
+
+/* Return a dep status that contains all speculation types of DS.  */
+ds_t
+ds_get_speculation_types (ds_t ds)
+{
+  if (ds & BEGIN_DATA)
+    ds |= BEGIN_DATA;
+  if (ds & BE_IN_DATA)
+    ds |= BE_IN_DATA;
+  if (ds & BEGIN_CONTROL)
+    ds |= BEGIN_CONTROL;
+  if (ds & BE_IN_CONTROL)
+    ds |= BE_IN_CONTROL;
+
+  return ds & SPECULATIVE;
+}
+
+/* Return a dep status that contains maximal weakness for each speculation
+   type present in DS.  */
+ds_t
+ds_get_max_dep_weak (ds_t ds)
+{
+  if (ds & BEGIN_DATA)
+    ds = set_dep_weak (ds, BEGIN_DATA, MAX_DEP_WEAK);
+  if (ds & BE_IN_DATA)
+    ds = set_dep_weak (ds, BE_IN_DATA, MAX_DEP_WEAK);
+  if (ds & BEGIN_CONTROL)
+    ds = set_dep_weak (ds, BEGIN_CONTROL, MAX_DEP_WEAK);
+  if (ds & BE_IN_CONTROL)
+    ds = set_dep_weak (ds, BE_IN_CONTROL, MAX_DEP_WEAK);
+
+  return ds;
+}
+
 /* Dump information about the dependence status S.  */
 static void
 dump_ds (FILE *f, ds_t s)
@@ -2756,7 +4116,7 @@ check_dep (dep_t dep, bool relaxed_p)
 
   /* Check that dependence status is set correctly when speculation is not
      supported.  */
-  if (!(current_sched_info->flags & DO_SPECULATION))
+  if (!sched_deps_info->generate_spec_deps)
     gcc_assert (!(ds & SPECULATIVE));
   else if (ds & SPECULATIVE)
     {