OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / sched-deps.c
index b62797f..af2892d 100644 (file)
@@ -1,7 +1,8 @@
 /* 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, 2010,
+   2011
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -26,7 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "hard-reg-set.h"
@@ -36,11 +37,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "insn-attr.h"
 #include "except.h"
-#include "toplev.h"
 #include "recog.h"
 #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)
@@ -60,6 +68,9 @@ ds_to_dk (ds_t ds)
   if (ds & DEP_OUTPUT)
     return REG_DEP_OUTPUT;
 
+  if (ds & DEP_CONTROL)
+    return REG_DEP_CONTROL;
+
   gcc_assert (ds & DEP_ANTI);
 
   return REG_DEP_ANTI;
@@ -77,6 +88,9 @@ dk_to_ds (enum reg_note dk)
     case REG_DEP_OUTPUT:
       return DEP_OUTPUT;
 
+    case REG_DEP_CONTROL:
+      return DEP_CONTROL;
+
     default:
       gcc_assert (dk == REG_DEP_ANTI);
       return DEP_ANTI;
@@ -93,6 +107,7 @@ init_dep_1 (dep_t dep, rtx pro, rtx con, enum reg_note type, ds_t ds)
   DEP_CON (dep) = con;
   DEP_TYPE (dep) = type;
   DEP_STATUS (dep) = ds;
+  DEP_COST (dep) = UNKNOWN_DEP_COST;
 }
 
 /* Init DEP with the arguments.
@@ -106,7 +121,7 @@ init_dep (dep_t dep, rtx pro, rtx con, enum reg_note kind)
   if ((current_sched_info->flags & USE_DEPS_LIST))
     ds = dk_to_ds (kind);
   else
-    ds = -1;
+    ds = 0;
 
   init_dep_1 (dep, pro, con, kind, ds);
 }
@@ -172,6 +187,10 @@ dump_dep (FILE *dump, dep_t dep, int flags)
          t = 'o';
          break;
 
+       case REG_DEP_CONTROL:
+         t = 'c';
+         break;
+
        case REG_DEP_ANTI:
          t = 'a';
          break;
@@ -204,6 +223,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 +268,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 +295,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.  */
@@ -385,22 +418,39 @@ clear_deps_list (deps_list_t l)
   while (1);
 }
 
+/* Decide whether a dependency should be treated as a hard or a speculative
+   dependency.  */
+static bool
+dep_spec_p (dep_t dep)
+{
+  if (current_sched_info->flags & DO_SPECULATION)
+    {
+      if (DEP_STATUS (dep) & SPECULATIVE)
+       return true;
+    }
+  if (current_sched_info->flags & DO_PREDICATION)
+    {
+      if (DEP_TYPE (dep) == REG_DEP_CONTROL)
+       return true;
+    }
+  return false;
+}
+
 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 regset reg_pending_control_uses;
 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,31 +464,33 @@ 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 *control_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_1 (rtx, rtx, enum reg_note);
 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_desc *, rtx,
+                                         rtx *, int, enum reg_note);
 static void delete_all_dependences (rtx);
 static void fixup_sched_groups (rtx);
 
-static void flush_pending_lists (struct deps *, rtx, int, int);
-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 void flush_pending_lists (struct deps_desc *, rtx, int, int);
+static void sched_analyze_1 (struct deps_desc *, rtx, rtx);
+static void sched_analyze_2 (struct deps_desc *, rtx, rtx);
+static void sched_analyze_insn (struct deps_desc *, 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 +511,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_uncached (const_rtx insn, bool *rev)
 {
   rtx pat = PATTERN (insn);
   rtx src;
@@ -470,6 +524,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,23 +544,91 @@ 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;
 }
 
+/* Return the condition under which INSN does not execute (i.e.  the
+   not-taken condition for a conditional branch), or NULL if we cannot
+   find such a condition.  The caller should make a copy of the condition
+   before using it.  */
+rtx
+sched_get_reverse_condition_uncached (const_rtx insn)
+{
+  bool rev;
+  rtx cond = sched_get_condition_with_rev_uncached (insn, &rev);
+  if (cond == NULL_RTX)
+    return cond;
+  if (!rev)
+    {
+      enum rtx_code revcode = reversed_comparison_code (cond, insn);
+      cond = gen_rtx_fmt_ee (revcode, GET_MODE (cond),
+                            XEXP (cond, 0),
+                            XEXP (cond, 1));
+    }
+  return cond;
+}
+
+/* Caching variant of sched_get_condition_with_rev_uncached.
+   We only do actual work the first time we come here for an insn; the
+   results are cached in INSN_CACHED_COND and INSN_REVERSE_COND.  */
+static rtx
+sched_get_condition_with_rev (const_rtx insn, bool *rev)
+{
+  bool tmp;
+
+  if (INSN_LUID (insn) == 0)
+    return sched_get_condition_with_rev_uncached (insn, rev);
+
+  if (INSN_CACHED_COND (insn) == const_true_rtx)
+    return NULL_RTX;
+
+  if (INSN_CACHED_COND (insn) != NULL_RTX)
+    {
+      if (rev)
+       *rev = INSN_REVERSE_COND (insn);
+      return INSN_CACHED_COND (insn);
+    }
+
+  INSN_CACHED_COND (insn) = sched_get_condition_with_rev_uncached (insn, &tmp);
+  INSN_REVERSE_COND (insn) = tmp;
+
+  if (INSN_CACHED_COND (insn) == NULL_RTX)
+    {
+      INSN_CACHED_COND (insn) = const_true_rtx;
+      return NULL_RTX;
+    }
+
+  if (rev)
+    *rev = INSN_REVERSE_COND (insn);
+  return INSN_CACHED_COND (insn);
+}
+
+/* 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)
-      && XEXP (cond1, 0) == XEXP (cond2, 0)
+      && GET_CODE (cond1) ==
+         (rev1==rev2
+         ? reversed_comparison_code (cond2, NULL)
+         : GET_CODE (cond2))
+      && rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
       && XEXP (cond1, 1) == XEXP (cond2, 1))
     return 1;
   return 0;
@@ -515,15 +640,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 +662,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_or_fault_p (PATTERN (insn)))
+       /* If instruction might fault, 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 +763,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.  */
@@ -719,12 +897,10 @@ sd_find_dep_between (rtx pro, rtx con, bool resolved_p)
       int elem_luid = INSN_LUID (pro);
       int insn_luid = INSN_LUID (con);
 
-      gcc_assert (output_dependency_cache != NULL
-                 && anti_dependency_cache != NULL);
-
       if (!bitmap_bit_p (&true_dependency_cache[insn_luid], elem_luid)
          && !bitmap_bit_p (&output_dependency_cache[insn_luid], elem_luid)
-         && !bitmap_bit_p (&anti_dependency_cache[insn_luid], elem_luid))
+         && !bitmap_bit_p (&anti_dependency_cache[insn_luid], elem_luid)
+         && !bitmap_bit_p (&control_dependency_cache[insn_luid], elem_luid))
        return NULL;
     }
 
@@ -752,7 +928,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;
 
@@ -777,10 +953,11 @@ ask_dependency_caches (dep_t dep)
 
   gcc_assert (true_dependency_cache != NULL
              && output_dependency_cache != NULL
-             && anti_dependency_cache != NULL);
+             && anti_dependency_cache != NULL
+             && control_dependency_cache != NULL);
 
   if (!(current_sched_info->flags & USE_DEPS_LIST))
-    {          
+    {
       enum reg_note present_dep_type;
 
       if (bitmap_bit_p (&true_dependency_cache[insn_luid], elem_luid))
@@ -789,6 +966,8 @@ ask_dependency_caches (dep_t dep)
        present_dep_type = REG_DEP_OUTPUT;
       else if (bitmap_bit_p (&anti_dependency_cache[insn_luid], elem_luid))
        present_dep_type = REG_DEP_ANTI;
+      else if (bitmap_bit_p (&control_dependency_cache[insn_luid], elem_luid))
+       present_dep_type = REG_DEP_CONTROL;
       else
        /* There is no existing dep so it should be created.  */
        return DEP_CREATED;
@@ -798,15 +977,17 @@ ask_dependency_caches (dep_t dep)
        return DEP_PRESENT;
     }
   else
-    {      
+    {
       ds_t present_dep_types = 0;
-          
+
       if (bitmap_bit_p (&true_dependency_cache[insn_luid], elem_luid))
        present_dep_types |= DEP_TRUE;
       if (bitmap_bit_p (&output_dependency_cache[insn_luid], elem_luid))
        present_dep_types |= DEP_OUTPUT;
       if (bitmap_bit_p (&anti_dependency_cache[insn_luid], elem_luid))
        present_dep_types |= DEP_ANTI;
+      if (bitmap_bit_p (&control_dependency_cache[insn_luid], elem_luid))
+       present_dep_types |= DEP_CONTROL;
 
       if (present_dep_types == 0)
        /* There is no existing dep so it should be created.  */
@@ -860,6 +1041,10 @@ set_dependency_caches (dep_t dep)
          bitmap_set_bit (&anti_dependency_cache[insn_luid], elem_luid);
          break;
 
+       case REG_DEP_CONTROL:
+         bitmap_set_bit (&control_dependency_cache[insn_luid], elem_luid);
+         break;
+
        default:
          gcc_unreachable ();
        }
@@ -874,6 +1059,8 @@ set_dependency_caches (dep_t dep)
        bitmap_set_bit (&output_dependency_cache[insn_luid], elem_luid);
       if (ds & DEP_ANTI)
        bitmap_set_bit (&anti_dependency_cache[insn_luid], elem_luid);
+      if (ds & DEP_CONTROL)
+       bitmap_set_bit (&control_dependency_cache[insn_luid], elem_luid);
 
       if (ds & SPECULATIVE)
        {
@@ -905,8 +1092,12 @@ update_dependency_caches (dep_t dep, enum reg_note old_type)
          bitmap_clear_bit (&anti_dependency_cache[insn_luid], elem_luid);
          break;
 
+       case REG_DEP_CONTROL:
+         bitmap_clear_bit (&control_dependency_cache[insn_luid], elem_luid);
+         break;
+
        default:
-         gcc_unreachable ();                        
+         gcc_unreachable ();
        }
     }
 
@@ -945,6 +1136,7 @@ update_dep (dep_t dep, dep_t new_dep,
 {
   enum DEPS_ADJUST_RESULT res = DEP_PRESENT;
   enum reg_note old_type = DEP_TYPE (dep);
+  bool was_spec = dep_spec_p (dep);
 
   /* If this is a more restrictive type of dependence than the
      existing one, then change the existing dependence to this
@@ -963,20 +1155,13 @@ update_dep (dep_t dep, dep_t new_dep,
       ds_t new_status = ds | dep_status;
 
       if (new_status & SPECULATIVE)
-       /* Either existing dep or a dep we're adding or both are
-          speculative.  */
        {
+         /* Either existing dep or a dep we're adding or both are
+            speculative.  */
          if (!(ds & SPECULATIVE)
              || !(dep_status & SPECULATIVE))
            /* The new dep can't be speculative.  */
-           {
-             new_status &= ~SPECULATIVE;
-
-             if (dep_status & SPECULATIVE)
-               /* The old dep was speculative, but now it
-                  isn't.  */
-               change_spec_dep_to_hard (sd_it);
-           }
+           new_status &= ~SPECULATIVE;
          else
            {
              /* Both are speculative.  Merge probabilities.  */
@@ -987,7 +1172,7 @@ update_dep (dep_t dep, dep_t new_dep,
                  dw = estimate_dep_weak (mem1, mem2);
                  ds = set_dep_weak (ds, BEGIN_DATA, dw);
                }
-                                                        
+
              new_status = ds_merge (dep_status, ds);
            }
        }
@@ -1001,6 +1186,10 @@ update_dep (dep_t dep, dep_t new_dep,
        }
     }
 
+  if (was_spec && !dep_spec_p (dep))
+    /* The old dep was speculative, but now it isn't.  */
+    change_spec_dep_to_hard (sd_it);
+
   if (true_dependency_cache != NULL
       && res == DEP_CHANGED)
     update_dependency_caches (dep, old_type);
@@ -1024,7 +1213,7 @@ add_or_update_dep_1 (dep_t new_dep, bool resolved_p,
 
   gcc_assert (INSN_P (DEP_PRO (new_dep)) && INSN_P (DEP_CON (new_dep))
              && DEP_PRO (new_dep) != DEP_CON (new_dep));
-  
+
 #ifdef ENABLE_CHECKING
   check_dep (new_dep, mem1 != NULL);
 #endif
@@ -1079,13 +1268,13 @@ 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));
     }
 
   sd_add_dep (new_dep, resolved_p);
-  
+
   return DEP_CREATED;
 }
 
@@ -1101,8 +1290,7 @@ get_back_and_forw_lists (dep_t dep, bool resolved_p,
 
   if (!resolved_p)
     {
-      if ((current_sched_info->flags & DO_SPECULATION)
-         && (DEP_STATUS (dep) & SPECULATIVE))
+      if (dep_spec_p (dep))
        *back_list_ptr = INSN_SPEC_BACK_DEPS (con);
       else
        *back_list_ptr = INSN_HARD_BACK_DEPS (con);
@@ -1129,8 +1317,8 @@ sd_add_dep (dep_t dep, bool resolved_p)
 
   gcc_assert (INSN_P (insn) && INSN_P (elem) && insn != elem);
 
-  if ((current_sched_info->flags & DO_SPECULATION)
-      && !sched_insn_is_legitimate_for_speculation_p (insn, DEP_STATUS (dep)))
+  if ((current_sched_info->flags & DO_SPECULATION) == 0
+      || !sched_insn_is_legitimate_for_speculation_p (insn, DEP_STATUS (dep)))
     DEP_STATUS (dep) &= ~SPECULATIVE;
 
   copy_dep (DEP_NODE_DEP (n), dep);
@@ -1170,8 +1358,7 @@ sd_resolve_dep (sd_iterator_def sd_it)
   rtx pro = DEP_PRO (dep);
   rtx con = DEP_CON (dep);
 
-  if ((current_sched_info->flags & DO_SPECULATION)
-      && (DEP_STATUS (dep) & SPECULATIVE))
+  if (dep_spec_p (dep))
     move_dep_link (DEP_NODE_BACK (node), INSN_SPEC_BACK_DEPS (con),
                   INSN_RESOLVED_BACK_DEPS (con));
   else
@@ -1182,6 +1369,27 @@ sd_resolve_dep (sd_iterator_def sd_it)
                 INSN_RESOLVED_FORW_DEPS (pro));
 }
 
+/* Perform the inverse operation of sd_resolve_dep.  Restore the dependence
+   pointed to by SD_IT to unresolved state.  */
+void
+sd_unresolve_dep (sd_iterator_def sd_it)
+{
+  dep_node_t node = DEP_LINK_NODE (*sd_it.linkp);
+  dep_t dep = DEP_NODE_DEP (node);
+  rtx pro = DEP_PRO (dep);
+  rtx con = DEP_CON (dep);
+
+  if (dep_spec_p (dep))
+    move_dep_link (DEP_NODE_BACK (node), INSN_RESOLVED_BACK_DEPS (con),
+                  INSN_SPEC_BACK_DEPS (con));
+  else
+    move_dep_link (DEP_NODE_BACK (node), INSN_RESOLVED_BACK_DEPS (con),
+                  INSN_HARD_BACK_DEPS (con));
+
+  move_dep_link (DEP_NODE_FORW (node), INSN_RESOLVED_FORW_DEPS (pro),
+                INSN_FORW_DEPS (pro));
+}
+
 /* Make TO depend on all the FROM's producers.
    If RESOLVED_P is true add dependencies to the resolved lists.  */
 void
@@ -1222,6 +1430,7 @@ sd_delete_dep (sd_iterator_def sd_it)
 
       bitmap_clear_bit (&true_dependency_cache[insn_luid], elem_luid);
       bitmap_clear_bit (&anti_dependency_cache[insn_luid], elem_luid);
+      bitmap_clear_bit (&control_dependency_cache[insn_luid], elem_luid);
       bitmap_clear_bit (&output_dependency_cache[insn_luid], elem_luid);
 
       if (current_sched_info->flags & DO_SPECULATION)
@@ -1287,6 +1496,57 @@ sd_debug_lists (rtx insn, sd_list_types_def types)
   fprintf (stderr, "\n");
 }
 
+/* A wrapper around add_dependence_1, to add a dependence of CON on
+   PRO, with type DEP_TYPE.  This function implements special handling
+   for REG_DEP_CONTROL dependencies.  For these, we optionally promote
+   the type to REG_DEP_ANTI if we can determine that predication is
+   impossible; otherwise we add additional true dependencies on the
+   INSN_COND_DEPS list of the jump (which PRO must be).  */
+void
+add_dependence (rtx con, rtx pro, enum reg_note dep_type)
+{
+  if (dep_type == REG_DEP_CONTROL
+      && !(current_sched_info->flags & DO_PREDICATION))
+    dep_type = REG_DEP_ANTI;
+
+  /* A REG_DEP_CONTROL dependence may be eliminated through predication,
+     so we must also make the insn dependent on the setter of the
+     condition.  */
+  if (dep_type == REG_DEP_CONTROL)
+    {
+      rtx real_pro = pro;
+      rtx other = real_insn_for_shadow (real_pro);
+      rtx cond;
+
+      if (other != NULL_RTX)
+       real_pro = other;
+      cond = sched_get_reverse_condition_uncached (real_pro);
+      /* Verify that the insn does not use a different value in
+        the condition register than the one that was present at
+        the jump.  */
+      if (cond == NULL_RTX)
+       dep_type = REG_DEP_ANTI;
+      else if (INSN_CACHED_COND (real_pro) == const_true_rtx)
+       {
+         HARD_REG_SET uses;
+         CLEAR_HARD_REG_SET (uses);
+         note_uses (&PATTERN (con), record_hard_reg_uses, &uses);
+         if (TEST_HARD_REG_BIT (uses, REGNO (XEXP (cond, 0))))
+           dep_type = REG_DEP_ANTI;
+       }
+      if (dep_type == REG_DEP_CONTROL)
+       {
+         if (sched_verbose >= 5)
+           fprintf (sched_dump, "making DEP_CONTROL for %d\n",
+                    INSN_UID (real_pro));
+         add_dependence_list (con, INSN_COND_DEPS (real_pro), 0,
+                              REG_DEP_TRUE);
+       }
+    }
+         
+  add_dependence_1 (con, pro, dep_type);
+}
+
 /* A convenience wrapper to operate on an entire list.  */
 
 static void
@@ -1299,13 +1559,24 @@ 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_desc *deps, rtx insn, rtx *listp,
+                              int uncond, enum reg_note dep_type)
 {
   rtx list, next;
+
+  /* We don't want to short-circuit dependencies involving debug
+     insns, because they may cause actual dependencies to be
+     disregarded.  */
+  if (deps->readonly || DEBUG_INSN_P (insn))
+    {
+      add_dependence_list (insn, *listp, uncond, dep_type);
+      return;
+    }
+
   for (list = *listp, *listp = NULL; list ; list = next)
     {
       next = XEXP (list, 1);
@@ -1315,6 +1586,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 +1672,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));
@@ -1364,7 +1681,7 @@ fixup_sched_groups (rtx insn)
 
   delete_all_dependences (insn);
 
-  prev_nonnote = prev_nonnote_insn (insn);
+  prev_nonnote = prev_nonnote_nondebug_insn (insn);
   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);
@@ -1386,18 +1703,20 @@ fixup_sched_groups (rtx insn)
    so that we can do memory aliasing on it.  */
 
 static void
-add_insn_mem_dependence (struct deps *deps, bool read_p,
+add_insn_mem_dependence (struct deps_desc *deps, bool read_p,
                         rtx insn, rtx mem)
 {
   rtx *insn_list;
   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,10 +1728,10 @@ 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));
+      XEXP (mem, 0) = cselib_subst_to_values (XEXP (mem, 0), GET_MODE (mem));
     }
   link = alloc_EXPR_LIST (VOIDmode, canon_rtx (mem), *mem_list);
   *mem_list = link;
@@ -1423,137 +1742,667 @@ add_insn_mem_dependence (struct deps *deps, bool read_p,
    dependencies for a read operation, similarly with FOR_WRITE.  */
 
 static void
-flush_pending_lists (struct deps *deps, rtx insn, int for_read,
+flush_pending_lists (struct deps_desc *deps, rtx insn, int for_read,
                     int for_write)
 {
   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);
+
+  add_dependence_list_and_free (deps, insn, &deps->pending_jump_insns, 1,
+                               REG_DEP_ANTI);
+
+  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)
-    {
-      enum rtx_code code = GET_CODE (PATTERN (insn));
-      gcc_assert (code == USE || code == CLOBBER);
-    }
+  cur_insn = insn;
+}
 
-  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);
+static void
+haifa_finish_insn (void)
+{
+  cur_insn = NULL;
+}
 
-      /* 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);
-       }
+void
+haifa_note_reg_set (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_sets, regno);
+}
 
-      /* 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);
-       }
-    }
+void
+haifa_note_reg_clobber (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_clobbers, regno);
 }
 
-/* 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.  */
+void
+haifa_note_reg_use (int regno)
+{
+  SET_REGNO_REG_SET (reg_pending_uses, regno);
+}
 
 static void
-sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
+haifa_note_mem_dep (rtx mem, rtx pending_mem, rtx pending_insn, ds_t ds)
 {
-  rtx dest = XEXP (x, 0);
-  enum rtx_code code = GET_CODE (x);
+  if (!(ds & SPECULATIVE))
+    {
+      mem = NULL_RTX;
+      pending_mem = NULL_RTX;
+    }
+  else
+    gcc_assert (ds & BEGIN_DATA);
 
-  if (dest == 0)
-    return;
+  {
+    dep_def _dep, *dep = &_dep;
 
-  if (GET_CODE (dest) == PARALLEL)
-    {
-      int i;
+    init_dep_1 (dep, pending_insn, cur_insn, ds_to_dt (ds),
+                current_sched_info->flags & USE_DEPS_LIST ? ds : 0);
+    maybe_add_or_update_dep_1 (dep, false, pending_mem, mem);
+  }
 
-      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 (GET_CODE (x) == SET)
-       sched_analyze_2 (deps, SET_SRC (x), insn);
-      return;
-    }
+static void
+haifa_note_dep (rtx elem, ds_t ds)
+{
+  dep_def _dep;
+  dep_t dep = &_dep;
 
-  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
+  init_dep (dep, elem, cur_insn, ds_to_dt (ds));
+  maybe_add_or_update_dep_1 (dep, false, NULL_RTX, NULL_RTX);
+}
+
+static void
+note_reg_use (int r)
+{
+  if (sched_deps_info->note_reg_use)
+    sched_deps_info->note_reg_use (r);
+}
+
+static void
+note_reg_set (int r)
+{
+  if (sched_deps_info->note_reg_set)
+    sched_deps_info->note_reg_set (r);
+}
+
+static void
+note_reg_clobber (int r)
+{
+  if (sched_deps_info->note_reg_clobber)
+    sched_deps_info->note_reg_clobber (r);
+}
+
+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);
+}
+
+static void
+note_dep (rtx e, ds_t ds)
+{
+  if (sched_deps_info->note_dep)
+    sched_deps_info->note_dep (e, ds);
+}
+
+/* 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 (ds & DEP_ANTI)
+    return REG_DEP_ANTI;
+  else
+    {
+      gcc_assert (ds & DEP_CONTROL);
+      return REG_DEP_CONTROL;
+    }
+}
+
+\f
+
+/* Functions for computation of info needed for register pressure
+   sensitive insn scheduling.  */
+
+
+/* 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_desc *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))
+       {
+         use2 = create_insn_reg_use (i, XEXP (list, 0));
+         next = use->next_regno_use;
+         use->next_regno_use = use2;
+         use2->next_regno_use = next;
+       }
+    }
+}
+
+/* Register pressure info for the currently processed insn.  */
+static struct reg_pressure_data reg_pressure_info[N_REG_CLASSES];
+
+/* 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_pressure_class[regno];
+  if (cl != NO_REGS)
+    {
+      incr = ira_reg_class_max_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_pressure_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_pressure_class[regno];
+  if (cl != NO_REGS)
+    {
+      incr = ira_reg_class_max_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_pressure_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.  */
+void
+init_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_pressure_classes_num; i++)
+    {
+      cl = ira_pressure_classes[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_pressure_classes_num;
+  pressure_info
+    = INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len);
+  INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_pressure_classes_num
+                                                 * sizeof (int), 1);
+  for (i = 0; i < ira_pressure_classes_num; i++)
+    {
+      cl = ira_pressure_classes[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_desc *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_desc *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_desc *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.
@@ -1584,7 +2433,9 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
          /* 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);
+
+         add_to_hard_reg_set (&implicit_reg_pending_uses, mode,
+                              FIRST_STACK_REG);
        }
 #endif
     }
@@ -1593,16 +2444,22 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
       /* Writing memory.  */
       rtx t = dest;
 
-      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 (dest));
+
          t = shallow_copy_rtx (dest);
-         cselib_lookup (XEXP (t, 0), Pmode, 1);
-         XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
+         cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+                                  GET_MODE (t), insn);
+         XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
        }
       t = canon_rtx (t);
 
-      if ((deps->pending_read_list_length + deps->pending_write_list_length)
-         > MAX_PENDING_LIST_LENGTH)
+      /* 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
@@ -1621,7 +2478,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 +2491,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);
@@ -1641,30 +2500,48 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn)
 
          add_dependence_list (insn, deps->last_pending_memory_flush, 1,
                               REG_DEP_ANTI);
+         add_dependence_list (insn, deps->pending_jump_insns, 1,
+                              REG_DEP_CONTROL);
 
-         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)
+sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn)
 {
   int i;
   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 +2553,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 +2566,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 +2590,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 +2604,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)
          {
-           t = shallow_copy_rtx (t);
-           cselib_lookup (XEXP (t, 0), Pmode, 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);
+           enum machine_mode address_mode
+             = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t));
 
-           pending = XEXP (pending, 1);
-           pending_mem = XEXP (pending_mem, 1);
+           t = shallow_copy_rtx (t);
+           cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1,
+                                    GET_MODE (t), insn);
+           XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
          }
 
-       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.  */
-                 {
-                   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);
-                 }
-                else
-                  add_dependence (insn, XEXP (pending, 0), REG_DEP_TRUE);
-              }
-
-           pending = XEXP (pending, 1);
-           pending_mem = XEXP (pending_mem, 1);
+           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))
+             add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+           for (u = deps->pending_jump_insns; u; u = XEXP (u, 1))
+             if (deps_may_trap_p (x))
+               {
+                 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_CONTROL);
+               }
          }
 
-       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 +2685,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 +2716,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 +2737,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 +2749,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,18 +2769,58 @@ 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)
+sched_analyze_insn (struct deps_desc *deps, rtx x, rtx insn)
 {
   RTX_CODE code = GET_CODE (x);
   rtx link;
   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);
+      AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+      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);
+
+  /* We must avoid creating a situation in which two successors of the
+     current block have different unwind info after scheduling.  If at any
+     point the two paths re-join this leads to incorrect unwind info.  */
+  /* ??? There are certain situations involving a forced frame pointer in
+     which, with extra effort, we could fix up the unwind info at a later
+     CFG join.  However, it seems better to notice these cases earlier
+     during prologue generation and avoid marking the frame pointer setup
+     as frame-related at all.  */
+  if (RTX_FRAME_RELATED_P (insn))
+    {
+      /* Make sure prologue insn is scheduled before next jump.  */
+      deps->sched_before_next_jump
+       = alloc_INSN_LIST (insn, deps->sched_before_next_jump);
+
+      /* Make sure epilogue insn is scheduled after preceding jumps.  */
+      add_dependence_list (insn, deps->pending_jump_insns, 1, REG_DEP_ANTI);
+    }
+
   if (code == COND_EXEC)
     {
       sched_analyze_2 (deps, COND_EXEC_TEST (x), insn);
@@ -1877,7 +2838,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)
     {
@@ -1911,38 +2873,40 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
          else
            sched_analyze_2 (deps, XEXP (link, 0), insn);
        }
-      if (find_reg_note (insn, REG_SETJMP, NULL))
+      /* Don't schedule anything after a tail call, tail call needs
+        to use at least all call-saved registers.  */
+      if (SIBLING_CALL_P (insn))
+       reg_pending_barrier = TRUE_BARRIER;
+      else if (find_reg_note (insn, REG_SETJMP, NULL))
        reg_pending_barrier = MOVE_BARRIER;
     }
 
   if (JUMP_P (insn))
     {
       rtx next;
-      next = next_nonnote_insn (insn);
+      next = next_nonnote_nondebug_insn (insn);
       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)
+            {
+              (*sched_deps_info->compute_jump_reg_dependencies)
+               (insn, reg_pending_control_uses);
+
+              /* Make latency of jump equal to 0 by using anti-dependence.  */
+              EXECUTE_IF_SET_IN_REG_SET (reg_pending_control_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);
+                }
+            }
 
          /* All memory writes and volatile reads must happen before the
             jump.  Non-volatile reads must happen before the jump iff
@@ -1971,6 +2935,8 @@ sched_analyze_insn (struct deps *deps, rtx x, rtx insn)
 
          add_dependence_list (insn, deps->last_pending_memory_flush, 1,
                               REG_DEP_ANTI);
+         add_dependence_list (insn, deps->pending_jump_insns, 1,
+                              REG_DEP_ANTI);
        }
     }
 
@@ -1984,111 +2950,279 @@ 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);
+      init_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 (!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);
+         /* There's no point in making REG_DEP_CONTROL dependencies for
+            debug insns.  */
+         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
     {
+      regset_head set_or_clobbered;
+
       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->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 (targetm.sched.exposed_pipeline)
        {
-         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)
+         INIT_REG_SET (&set_or_clobbered);
+         bitmap_ior (&set_or_clobbered, reg_pending_clobbers,
+                     reg_pending_sets);
+         EXECUTE_IF_SET_IN_REG_SET (&set_or_clobbered, 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];
+             rtx list;
+             for (list = reg_last->uses; list; list = XEXP (list, 1))
+               {
+                 rtx other = XEXP (list, 0);
+                 if (INSN_CACHED_COND (other) != const_true_rtx
+                     && refers_to_regno_p (i, i + 1, INSN_CACHED_COND (other), NULL))
+                   INSN_CACHED_COND (other) = const_true_rtx;
+               }
            }
-         else
+       }
+
+      /* If the current insn is conditional, we can't free any
+        of the lists.  */
+      if (sched_has_condition_p (insn))
+       {
+         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->implicit_sets, 0,
+                                  REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->uses, 0, REG_DEP_ANTI);
+             add_dependence_list (insn, reg_last->control_uses, 0,
+                                  REG_DEP_CONTROL);
+
+             if (!deps->readonly)
+               {
+                 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->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);
+             add_dependence_list (insn, reg_last->control_uses, 0,
+                                  REG_DEP_CONTROL);
+
+             if (!deps->readonly)
+               reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
            }
-         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)
+      else
        {
-         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);
+         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->control_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);
+                 add_dependence_list (insn, reg_last->control_uses, 0,
+                                      REG_DEP_CONTROL);
+               }
+
+             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);
+             add_dependence_list (insn, reg_last->control_uses, 0,
+                                  REG_DEP_CONTROL);
+
+             if (!deps->readonly)
+               {
+                 reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
+                 reg_last->uses_length = 0;
+                 reg_last->clobbers_length = 0;
+               }
+           }
+       }
+      if (!deps->readonly)
+       {
+         EXECUTE_IF_SET_IN_REG_SET (reg_pending_control_uses, 0, i, rsi)
+           {
+             struct deps_reg *reg_last = &deps->reg_last[i];
+             reg_last->control_uses
+               = alloc_INSN_LIST (insn, reg_last->control_uses);
+           }
        }
     }
 
-  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);
+       add_dependence_list (insn, reg_last->control_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_REG_SET (reg_pending_control_uses);
+  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,47 +3230,51 @@ 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->control_uses, 0,
+                                           REG_DEP_CONTROL);
+             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);
-       }
+      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 (deps, insn, true, true);
-      CLEAR_REG_SET (&deps->reg_conditional_sets);
-      reg_pending_barrier = NOT_A_BARRIER;
-    }
-
-  /* If we are currently in a libcall scheduling group, then mark the
-     current insn as being in a scheduling group and that it can not
-     be moved into a different basic block.  */
+      /* 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->libcall_block_tail_insn)
-    {
-      SCHED_GROUP_P (insn) = 1;
-      CANT_MOVE (insn) = 1;
+      reg_pending_barrier = NOT_A_BARRIER;
     }
 
   /* If a post-call group is still open, see if it should remain so.
      This insn must be a simple move of a hard reg to a pseudo or
      vice-versa.
 
-     We must avoid moving these insns for correctness on
-     SMALL_REGISTER_CLASS machines, and for special registers like
+     We must avoid moving these insns for correctness on targets
+     with small register classes, and for special registers like
      PIC_OFFSET_TABLE_REGNUM.  For simplicity, extend this to all
      hard regs for all targets.  */
 
@@ -2146,7 +3284,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)
@@ -2173,60 +3334,314 @@ 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;
+      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);
+          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_desc *deps, rtx insn)
 {
-  rtx insn;
+  if (sched_deps_info->start_insn)
+    sched_deps_info->start_insn (insn);
+
+  /* Record the condition for this insn.  */
+  if (NONDEBUG_INSN_P (insn))
+    {
+      rtx t;
+      sched_get_condition_with_rev (insn, NULL);
+      t = INSN_CACHED_COND (insn);
+      INSN_COND_DEPS (insn) = NULL_RTX;
+      if (reload_completed
+         && (current_sched_info->flags & DO_PREDICATION)
+         && COMPARISON_P (t)
+         && REG_P (XEXP (t, 0))
+         && CONSTANT_P (XEXP (t, 1)))
+       {
+         unsigned int regno;
+         int nregs;
+         t = XEXP (t, 0);
+         regno = REGNO (t);
+         nregs = hard_regno_nregs[regno][GET_MODE (t)];
+         t = NULL_RTX;
+         while (nregs-- > 0)
+           {
+             struct deps_reg *reg_last = &deps->reg_last[regno + nregs];
+             t = concat_INSN_LIST (reg_last->sets, t);
+             t = concat_INSN_LIST (reg_last->clobbers, t);
+             t = concat_INSN_LIST (reg_last->implicit_sets, t);
+           }
+         INSN_COND_DEPS (insn) = t;
+       }
+    }
+
+  if (JUMP_P (insn))
+    {
+      /* Make each JUMP_INSN (but not a speculative check)
+         a scheduling barrier for memory references.  */
+      if (!deps->readonly
+          && !(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->pending_jump_insns
+              = alloc_INSN_LIST (insn, deps->pending_jump_insns);
+        }
+
+      /* For each insn which shouldn't cross a jump, add a dependence.  */
+      add_dependence_list_and_free (deps, insn,
+                                   &deps->sched_before_next_jump, 1,
+                                   REG_DEP_ANTI);
+
+      sched_analyze_insn (deps, PATTERN (insn), insn);
+    }
+  else if (NONJUMP_INSN_P (insn) || DEBUG_INSN_P (insn))
+    {
+      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 ();
 
-  if (current_sched_info->use_cselib)
-    cselib_init (true);
+  /* 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_desc *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_nondebug_insn (head);
+
       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_desc *deps, rtx head, rtx tail)
+{
+  rtx insn;
+
+  if (sched_deps_info->use_cselib)
+    cselib_init (CSELIB_RECORD_MEMORY);
+
+  deps_start_bb (deps, head);
+
   for (insn = head;; insn = NEXT_INSN (insn))
     {
-      rtx link, end_seq, r0, set;
 
       if (INSN_P (insn))
        {
@@ -2234,140 +3649,11 @@ sched_analyze (struct deps *deps, rtx head, rtx tail)
          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);
-
-      /* Now that we have completed handling INSN, check and see if it is
-        a CLOBBER beginning a libcall block.   If it is, record the
-        end of the libcall sequence.
-
-        We want to schedule libcall blocks as a unit before reload.  While
-        this restricts scheduling, it preserves the meaning of a libcall
-        block.
-
-        As a side effect, we may get better code due to decreased register
-        pressure as well as less chance of a foreign insn appearing in
-        a libcall block.  */
-      if (!reload_completed
-         /* Note we may have nested libcall sequences.  We only care about
-            the outermost libcall sequence.  */
-         && deps->libcall_block_tail_insn == 0
-         /* The sequence must start with a clobber of a register.  */
-         && NONJUMP_INSN_P (insn)
-         && GET_CODE (PATTERN (insn)) == CLOBBER
-          && (r0 = XEXP (PATTERN (insn), 0), REG_P (r0))
-         && REG_P (XEXP (PATTERN (insn), 0))
-         /* The CLOBBER must also have a REG_LIBCALL note attached.  */
-         && (link = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0
-         && (end_seq = XEXP (link, 0)) != 0
-         /* The insn referenced by the REG_LIBCALL note must be a
-            simple nop copy with the same destination as the register
-            mentioned in the clobber.  */
-         && (set = single_set (end_seq)) != 0
-         && SET_DEST (set) == r0 && SET_SRC (set) == r0
-         /* And finally the insn referenced by the REG_LIBCALL must
-            also contain a REG_EQUAL note and a REG_RETVAL note.  */
-         && find_reg_note (end_seq, REG_EQUAL, NULL_RTX) != 0
-         && find_reg_note (end_seq, REG_RETVAL, NULL_RTX) != 0)
-       deps->libcall_block_tail_insn = XEXP (link, 0);
-
-      /* If we have reached the end of a libcall block, then close the
-        block.  */
-      if (deps->libcall_block_tail_insn == insn)
-       deps->libcall_block_tail_insn = 0;
+      deps_analyze_insn (deps, insn);
 
       if (insn == tail)
        {
-         if (current_sched_info->use_cselib)
+         if (sched_deps_info->use_cselib)
            cselib_finish ();
          return;
        }
@@ -2411,58 +3697,91 @@ sched_free_deps (rtx head, rtx tail, bool resolved_p)
   rtx insn;
   rtx next_tail = NEXT_INSN (tail);
 
+  /* We make two passes since some insns may be scheduled before their
+     dependencies are resolved.  */
   for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
     if (INSN_P (insn) && INSN_LUID (insn) > 0)
       {
-       /* Clear resolved back deps together with its dep_nodes.  */
-       delete_dep_nodes_in_back_deps (insn, resolved_p);
-
        /* Clear forward deps and leave the dep_nodes to the
           corresponding back_deps list.  */
        if (resolved_p)
          clear_deps_list (INSN_RESOLVED_FORW_DEPS (insn));
        else
          clear_deps_list (INSN_FORW_DEPS (insn));
+      }
+  for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+    if (INSN_P (insn) && INSN_LUID (insn) > 0)
+      {
+       /* Clear resolved back deps together with its dep_nodes.  */
+       delete_dep_nodes_in_back_deps (insn, resolved_p);
 
        sd_finish_insn (insn);
       }
 }
 \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_desc immediately.  */
 
 void
-init_deps (struct deps *deps)
+init_deps (struct deps_desc *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);
 
   deps->pending_read_insns = 0;
   deps->pending_read_mems = 0;
   deps->pending_write_insns = 0;
   deps->pending_write_mems = 0;
+  deps->pending_jump_insns = 0;
   deps->pending_read_list_length = 0;
   deps->pending_write_list_length = 0;
   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->sched_before_next_jump = 0;
   deps->in_post_call_group_p = not_post_call;
-  deps->libcall_block_tail_insn = 0;
+  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_desc *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
-free_deps (struct deps *deps)
+free_deps (struct deps_desc *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);
@@ -2479,49 +3798,120 @@ 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->control_uses)
+       free_INSN_LIST_list (&reg_last->control_uses);
       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);
 
+  /* As we initialize reg_last lazily, it is possible that we didn't allocate
+     it at all.  */
   free (deps->reg_last);
+  deps->reg_last = NULL;
+
+  deps = NULL;
+}
+
+/* Remove INSN from dependence contexts DEPS.  */
+void
+remove_from_deps (struct deps_desc *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->pending_jump_insns);
+  deps->pending_flush_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
@@ -2537,6 +3927,8 @@ extend_dependency_caches (int n, bool create_p)
                                            output_dependency_cache, luid);
       anti_dependency_cache = XRESIZEVEC (bitmap_head, anti_dependency_cache,
                                          luid);
+      control_dependency_cache = XRESIZEVEC (bitmap_head, control_dependency_cache,
+                                         luid);
 
       if (current_sched_info->flags & DO_SPECULATION)
         spec_dependency_cache = XRESIZEVEC (bitmap_head, spec_dependency_cache,
@@ -2547,6 +3939,7 @@ extend_dependency_caches (int n, bool create_p)
          bitmap_initialize (&true_dependency_cache[i], 0);
          bitmap_initialize (&output_dependency_cache[i], 0);
          bitmap_initialize (&anti_dependency_cache[i], 0);
+         bitmap_initialize (&control_dependency_cache[i], 0);
 
           if (current_sched_info->flags & DO_SPECULATION)
             bitmap_initialize (&spec_dependency_cache[i], 0);
@@ -2555,16 +3948,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;
@@ -2574,8 +3969,9 @@ free_dependency_caches (void)
          bitmap_clear (&true_dependency_cache[i]);
          bitmap_clear (&output_dependency_cache[i]);
          bitmap_clear (&anti_dependency_cache[i]);
+         bitmap_clear (&control_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);
@@ -2584,12 +3980,15 @@ free_dependency_caches (void)
       output_dependency_cache = NULL;
       free (anti_dependency_cache);
       anti_dependency_cache = NULL;
+      free (control_dependency_cache);
+      control_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;
         }
+
     }
 }
 
@@ -2599,10 +3998,26 @@ 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_control_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.  */
@@ -2613,10 +4028,11 @@ finish_deps_global (void)
   FREE_REG_SET (reg_pending_sets);
   FREE_REG_SET (reg_pending_clobbers);
   FREE_REG_SET (reg_pending_uses);
+  FREE_REG_SET (reg_pending_control_uses);
 }
 
 /* Estimate the weakness of dependence between MEM1 and MEM2.  */
-static dw_t
+dw_t
 estimate_dep_weak (rtx mem1, rtx mem2)
 {
   rtx r1, r2;
@@ -2646,20 +4062,43 @@ estimate_dep_weak (rtx mem1, rtx mem2)
 /* Add or update backward dependence between INSN and ELEM with type DEP_TYPE.
    This function can handle same INSN and ELEM (INSN == ELEM).
    It is a convenience wrapper.  */
-void
-add_dependence (rtx insn, rtx elem, enum reg_note dep_type)
+static void
+add_dependence_1 (rtx insn, rtx elem, enum reg_note dep_type)
 {
-  dep_def _dep, *dep = &_dep;
+  ds_t ds;
+  bool internal;
+
+  if (dep_type == REG_DEP_TRUE)
+    ds = DEP_TRUE;
+  else if (dep_type == REG_DEP_OUTPUT)
+    ds = DEP_OUTPUT;
+  else if (dep_type == REG_DEP_CONTROL)
+    ds = DEP_CONTROL;
+  else
+    {
+      gcc_assert (dep_type == REG_DEP_ANTI);
+      ds = DEP_ANTI;
+    }
 
-  init_dep (dep, elem, insn, dep_type);
-  maybe_add_or_update_dep_1 (dep, false, NULL_RTX, NULL_RTX);
+  /* 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;
@@ -2672,14 +4111,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;
 }
 
@@ -2702,9 +4139,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;
 
@@ -2721,12 +4161,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);
        }
@@ -2740,6 +4192,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)
@@ -2760,15 +4340,17 @@ dump_ds (FILE *f, ds_t s)
 
   if (s & DEP_TRUE)
     fprintf (f, "DEP_TRUE; ");
-  if (s & DEP_ANTI)
-    fprintf (f, "DEP_ANTI; ");
   if (s & DEP_OUTPUT)
     fprintf (f, "DEP_OUTPUT; ");
+  if (s & DEP_ANTI)
+    fprintf (f, "DEP_ANTI; ");
+  if (s & DEP_CONTROL)
+    fprintf (f, "DEP_CONTROL; ");
 
   fprintf (f, "}");
 }
 
-void
+DEBUG_FUNCTION void
 debug_ds (ds_t s)
 {
   dump_ds (stderr, s);
@@ -2788,7 +4370,7 @@ check_dep (dep_t dep, bool relaxed_p)
 
   if (!(current_sched_info->flags & USE_DEPS_LIST))
     {
-      gcc_assert (ds == -1);
+      gcc_assert (ds == 0);
       return;
     }
 
@@ -2797,18 +4379,21 @@ check_dep (dep_t dep, bool relaxed_p)
     gcc_assert (ds & DEP_TRUE);
   else if (dt == REG_DEP_OUTPUT)
     gcc_assert ((ds & DEP_OUTPUT)
-               && !(ds & DEP_TRUE));    
-  else 
-    gcc_assert ((dt == REG_DEP_ANTI)
-               && (ds & DEP_ANTI)
+               && !(ds & DEP_TRUE));
+  else if (dt == REG_DEP_ANTI)
+    gcc_assert ((ds & DEP_ANTI)
                && !(ds & (DEP_OUTPUT | DEP_TRUE)));
+  else
+    gcc_assert (dt == REG_DEP_CONTROL
+               && (ds & DEP_CONTROL)
+               && !(ds & (DEP_OUTPUT | DEP_ANTI | DEP_TRUE)));
 
   /* HARD_DEP can not appear in dep_status of a link.  */
-  gcc_assert (!(ds & HARD_DEP));         
+  gcc_assert (!(ds & HARD_DEP));
 
   /* 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)
     {
@@ -2846,8 +4431,8 @@ check_dep (dep_t dep, bool relaxed_p)
          /* Subsequent speculations should resolve true dependencies.  */
          gcc_assert ((ds & DEP_TYPES) == DEP_TRUE);
        }
-          
-      /* Check that true and anti dependencies can't have other speculative 
+
+      /* Check that true and anti dependencies can't have other speculative
         statuses.  */
       if (ds & DEP_TRUE)
        gcc_assert (ds & (BEGIN_DATA | BE_IN_SPEC));