This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: VTA merge - sched


sched (63K) - fix schedulers (except for sel-sched, that's only partially
fixed, which means VTA is not ready for -O3 on IA64) to deal properly
with debug insns

Index: gcc/sched-ebb.c
===================================================================
--- gcc/sched-ebb.c.orig	2009-06-05 04:56:43.000000000 -0300
+++ gcc/sched-ebb.c	2009-06-05 05:03:03.000000000 -0300
@@ -606,9 +606,9 @@ schedule_ebbs (void)
 	 a note or two.  */
       while (head != tail)
 	{
-	  if (NOTE_P (head))
+	  if (NOTE_P (head) || BOUNDARY_DEBUG_INSN_P (head))
 	    head = NEXT_INSN (head);
-	  else if (NOTE_P (tail))
+	  else if (NOTE_P (tail) || BOUNDARY_DEBUG_INSN_P (tail))
 	    tail = PREV_INSN (tail);
 	  else if (LABEL_P (head))
 	    head = NEXT_INSN (head);
Index: gcc/ddg.c
===================================================================
--- gcc/ddg.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/ddg.c	2009-06-05 05:07:56.000000000 -0300
@@ -166,6 +166,9 @@ create_ddg_dep_from_intra_loop_link (ddg
   else if (DEP_TYPE (link) == REG_DEP_OUTPUT)
     t = OUTPUT_DEP;
 
+  gcc_assert (!DEBUG_INSN_P (dest_node->insn) || t == ANTI_DEP);
+  gcc_assert (!DEBUG_INSN_P (src_node->insn) || DEBUG_INSN_P (dest_node->insn));
+
   /* We currently choose not to create certain anti-deps edges and
      compensate for that by generating reg-moves based on the life-range
      analysis.  The anti-deps that will be deleted are the ones which
@@ -209,6 +212,9 @@ create_ddg_dep_no_link (ddg_ptr g, ddg_n
   enum reg_note dep_kind;
   struct _dep _dep, *dep = &_dep;
 
+  gcc_assert (!DEBUG_INSN_P (to->insn) || d_t == ANTI_DEP);
+  gcc_assert (!DEBUG_INSN_P (from->insn) || DEBUG_INSN_P (to->insn));
+
   if (d_t == ANTI_DEP)
     dep_kind = REG_DEP_ANTI;
   else if (d_t == OUTPUT_DEP)
@@ -277,10 +283,11 @@ add_cross_iteration_register_deps (ddg_p
 	  /* Add true deps from last_def to it's uses in the next
 	     iteration.  Any such upwards exposed use appears before
 	     the last_def def.  */
-	  create_ddg_dep_no_link (g, last_def_node, use_node, TRUE_DEP,
+	  create_ddg_dep_no_link (g, last_def_node, use_node,
+				  DEBUG_INSN_P (use_insn) ? ANTI_DEP : TRUE_DEP,
 				  REG_DEP, 1);
 	}
-      else
+      else if (!DEBUG_INSN_P (use_insn))
 	{
 	  /* Add anti deps from last_def's uses in the current iteration
 	     to the first def in the next iteration.  We do not add ANTI
@@ -417,6 +424,8 @@ build_intra_loop_deps (ddg_ptr g)
 	  for (j = 0; j <= i; j++)
 	    {
 	      ddg_node_ptr j_node = &g->nodes[j];
+	      if (DEBUG_INSN_P (j_node->insn))
+		continue;
 	      if (mem_access_insn_p (j_node->insn))
  		/* Don't bother calculating inter-loop dep if an intra-loop dep
 		   already exists.  */
@@ -458,10 +467,15 @@ create_ddg (basic_block bb, int closing_
       if (! INSN_P (insn) || GET_CODE (PATTERN (insn)) == USE)
 	continue;
 
-      if (mem_read_insn_p (insn))
-	g->num_loads++;
-      if (mem_write_insn_p (insn))
-	g->num_stores++;
+      if (DEBUG_INSN_P (insn))
+	g->num_debug++;
+      else
+	{
+	  if (mem_read_insn_p (insn))
+	    g->num_loads++;
+	  if (mem_write_insn_p (insn))
+	    g->num_stores++;
+	}
       num_nodes++;
     }
 
Index: gcc/ddg.h
===================================================================
--- gcc/ddg.h.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/ddg.h	2009-06-05 05:07:56.000000000 -0300
@@ -1,5 +1,5 @@
 /* DDG - Data Dependence Graph - interface.
-   Copyright (C) 2004, 2005, 2006, 2007
+   Copyright (C) 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Ayal Zaks and Mustafa Hagog <zaks,mustafa@il.ibm.com>
 
@@ -121,6 +121,9 @@ struct ddg
   int num_loads;
   int num_stores;
 
+  /* Number of debug instructions in the BB.  */
+  int num_debug;
+
   /* This array holds the nodes in the graph; it is indexed by the node
      cuid, which follows the order of the instructions in the BB.  */
   ddg_node_ptr nodes;
@@ -134,8 +137,8 @@ struct ddg
   int closing_branch_deps;
 
   /* Array and number of backarcs (edges with distance > 0) in the DDG.  */
-  ddg_edge_ptr *backarcs;
   int num_backarcs;
+  ddg_edge_ptr *backarcs;
 };
 
 
Index: gcc/haifa-sched.c
===================================================================
--- gcc/haifa-sched.c.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/haifa-sched.c	2009-06-05 05:08:11.000000000 -0300
@@ -310,7 +310,7 @@ size_t dfa_state_size;
 char *ready_try = NULL;
 
 /* The ready list.  */
-struct ready_list ready = {NULL, 0, 0, 0};
+struct ready_list ready = {NULL, 0, 0, 0, 0};
 
 /* The pointer to the ready list (to be removed).  */
 static struct ready_list *readyp = &ready;
@@ -748,6 +748,10 @@ increase_insn_priority (rtx insn, int am
 static bool
 contributes_to_priority_p (dep_t dep)
 {
+  if (DEBUG_INSN_P (DEP_CON (dep))
+      || DEBUG_INSN_P (DEP_PRO (dep)))
+    return false;
+
   /* Critical path is meaningful in block boundaries only.  */
   if (!current_sched_info->contributes_to_priority (DEP_CON (dep),
 						    DEP_PRO (dep)))
@@ -767,6 +771,31 @@ contributes_to_priority_p (dep_t dep)
   return true;
 }
 
+/* Compute the number of nondebug forward deps of an insn.  */
+
+static int
+nondebug_dep_list_size (rtx insn)
+{
+  sd_iterator_def sd_it;
+  dep_t dep;
+  int dbgcount = 0, nodbgcount = 0;
+
+  if (!MAY_HAVE_DEBUG_INSNS)
+    return sd_lists_size (insn, SD_LIST_FORW);
+
+  FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
+    {
+      if (DEBUG_INSN_P (DEP_CON (dep)))
+	dbgcount++;
+      else
+	nodbgcount++;
+    }
+
+  gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, SD_LIST_FORW));
+
+  return nodbgcount;
+}
+
 /* Compute the priority number for INSN.  */
 static int
 priority (rtx insn)
@@ -781,7 +810,7 @@ priority (rtx insn)
     {
       int this_priority = -1;
 
-      if (sd_lists_empty_p (insn, SD_LIST_FORW))
+      if (nondebug_dep_list_size (insn) == 0)
 	/* ??? We should set INSN_PRIORITY to insn_cost when and insn has
 	   some forward deps but all of them are ignored by
 	   contributes_to_priority hook.  At the moment we set priority of
@@ -886,8 +915,19 @@ rank_for_schedule (const void *x, const 
 {
   rtx tmp = *(const rtx *) y;
   rtx tmp2 = *(const rtx *) x;
+  rtx last;
   int tmp_class, tmp2_class;
   int val, priority_val, weight_val, info_val;
+  bool has_debug = MAY_HAVE_DEBUG_INSNS;
+
+  if (has_debug)
+    {
+      /* Schedule debug insns as early as possible.  */
+      if (DEBUG_INSN_P (tmp) && !DEBUG_INSN_P (tmp2))
+	return -1;
+      else if (DEBUG_INSN_P (tmp2))
+	return 1;
+    }
 
   /* The insn in a schedule group should be issued the first.  */
   if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2))
@@ -935,8 +975,17 @@ rank_for_schedule (const void *x, const 
   if (info_val)
     return info_val;
 
-  /* Compare insns based on their relation to the last-scheduled-insn.  */
-  if (INSN_P (last_scheduled_insn))
+  last = last_scheduled_insn;
+
+  if (DEBUG_INSN_P (last) && last != current_sched_info->prev_head)
+    do
+      last = PREV_INSN (last);
+    while (!NONDEBUG_INSN_P (last)
+	   && last != current_sched_info->prev_head);
+
+  /* Compare insns based on their relation to the last scheduled
+     non-debug insn.  */
+  if (NONDEBUG_INSN_P (last))
     {
       dep_t dep1;
       dep_t dep2;
@@ -946,7 +995,7 @@ rank_for_schedule (const void *x, const 
          2) Anti/Output dependent on last scheduled insn.
          3) Independent of last scheduled insn, or has latency of one.
          Choose the insn from the highest numbered class if different.  */
-      dep1 = sd_find_dep_between (last_scheduled_insn, tmp, true);
+      dep1 = sd_find_dep_between (last, tmp, true);
 
       if (dep1 == NULL || dep_cost (dep1) == 1)
 	tmp_class = 3;
@@ -956,7 +1005,7 @@ rank_for_schedule (const void *x, const 
       else
 	tmp_class = 2;
 
-      dep2 = sd_find_dep_between (last_scheduled_insn, tmp2, true);
+      dep2 = sd_find_dep_between (last, tmp2, true);
 
       if (dep2 == NULL || dep_cost (dep2)  == 1)
 	tmp2_class = 3;
@@ -974,8 +1023,13 @@ rank_for_schedule (const void *x, const 
      This gives the scheduler more freedom when scheduling later
      instructions at the expense of added register pressure.  */
 
-  val = (sd_lists_size (tmp2, SD_LIST_FORW)
-	 - sd_lists_size (tmp, SD_LIST_FORW));
+  if (has_debug)
+    val = (nondebug_dep_list_size (tmp2)
+	   - nondebug_dep_list_size (tmp));
+  else
+    val = (sd_lists_size (tmp2, SD_LIST_FORW)
+	   - sd_lists_size (tmp, SD_LIST_FORW));
+
 
   if (val != 0)
     return val;
@@ -1013,6 +1067,7 @@ queue_insn (rtx insn, int n_cycles)
   rtx link = alloc_INSN_LIST (insn, insn_queue[next_q]);
 
   gcc_assert (n_cycles <= max_insn_queue_index);
+  gcc_assert (!DEBUG_INSN_P (insn));
 
   insn_queue[next_q] = link;
   q_size += 1;
@@ -1080,6 +1135,8 @@ ready_add (struct ready_list *ready, rtx
     }
 
   ready->n_ready++;
+  if (DEBUG_INSN_P (insn))
+    ready->n_debug++;
 
   gcc_assert (QUEUE_INDEX (insn) != QUEUE_READY);
   QUEUE_INDEX (insn) = QUEUE_READY;
@@ -1096,6 +1153,8 @@ ready_remove_first (struct ready_list *r
   gcc_assert (ready->n_ready);
   t = ready->vec[ready->first--];
   ready->n_ready--;
+  if (DEBUG_INSN_P (t))
+    ready->n_debug--;
   /* If the queue becomes empty, reset it.  */
   if (ready->n_ready == 0)
     ready->first = ready->veclen - 1;
@@ -1137,6 +1196,8 @@ ready_remove (struct ready_list *ready, 
   gcc_assert (ready->n_ready && index < ready->n_ready);
   t = ready->vec[ready->first - index];
   ready->n_ready--;
+  if (DEBUG_INSN_P (t))
+    ready->n_debug--;
   for (i = index; i < ready->n_ready; i++)
     ready->vec[ready->first - i] = ready->vec[ready->first - i - 1];
   QUEUE_INDEX (t) = QUEUE_NOWHERE;
@@ -1315,7 +1376,8 @@ schedule_insn (rtx insn)
      be aligned.  */
   if (issue_rate > 1
       && GET_CODE (PATTERN (insn)) != USE
-      && GET_CODE (PATTERN (insn)) != CLOBBER)
+      && GET_CODE (PATTERN (insn)) != CLOBBER
+      && !DEBUG_INSN_P (insn))
     {
       if (reload_completed)
 	PUT_MODE (insn, clock_var > last_clock_var ? TImode : VOIDmode);
@@ -1427,7 +1489,7 @@ get_ebb_head_tail (basic_block beg, basi
     beg_head = NEXT_INSN (beg_head);
 
   while (beg_head != beg_tail)
-    if (NOTE_P (beg_head))
+    if (NOTE_P (beg_head) || BOUNDARY_DEBUG_INSN_P (beg_head))
       beg_head = NEXT_INSN (beg_head);
     else
       break;
@@ -1440,7 +1502,7 @@ get_ebb_head_tail (basic_block beg, basi
     end_head = NEXT_INSN (end_head);
 
   while (end_head != end_tail)
-    if (NOTE_P (end_tail))
+    if (NOTE_P (end_tail) || BOUNDARY_DEBUG_INSN_P (end_tail))
       end_tail = PREV_INSN (end_tail);
     else
       break;
@@ -1455,7 +1517,8 @@ no_real_insns_p (const_rtx head, const_r
 {
   while (head != NEXT_INSN (tail))
     {
-      if (!NOTE_P (head) && !LABEL_P (head))
+      if (!NOTE_P (head) && !LABEL_P (head)
+	  && !BOUNDARY_DEBUG_INSN_P (head))
 	return 0;
       head = NEXT_INSN (head);
     }
@@ -1626,9 +1689,13 @@ queue_to_ready (struct ready_list *ready
   q_ptr = NEXT_Q (q_ptr);
 
   if (dbg_cnt (sched_insn) == false)
-    /* If debug counter is activated do not requeue insn next after
-       last_scheduled_insn.  */
-    skip_insn = next_nonnote_insn (last_scheduled_insn);
+    {
+      /* If debug counter is activated do not requeue insn next after
+	 last_scheduled_insn.  */
+      skip_insn = next_nonnote_insn (last_scheduled_insn);
+      while (skip_insn && DEBUG_INSN_P (skip_insn))
+	skip_insn = next_nonnote_insn (skip_insn);
+    }
   else
     skip_insn = NULL_RTX;
 
@@ -1646,7 +1713,7 @@ queue_to_ready (struct ready_list *ready
       /* If the ready list is full, delay the insn for 1 cycle.
 	 See the comment in schedule_block for the rationale.  */
       if (!reload_completed
-	  && ready->n_ready > MAX_SCHED_READY_INSNS
+	  && ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS
 	  && !SCHED_GROUP_P (insn)
 	  && insn != skip_insn)
 	{
@@ -2234,7 +2301,8 @@ choose_ready (struct ready_list *ready, 
 
   if (targetm.sched.first_cycle_multipass_dfa_lookahead)
     lookahead = targetm.sched.first_cycle_multipass_dfa_lookahead ();
-  if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0)))
+  if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
+      || DEBUG_INSN_P (ready_element (ready, 0)))
     {
       *insn_ptr = ready_remove_first (ready);
       return 0;
@@ -2355,6 +2423,10 @@ choose_ready (struct ready_list *ready, 
     }
 }
 
+#ifndef SCHED_DEBUG_INSNS_BEFORE_REORDER
+# define SCHED_DEBUG_INSNS_BEFORE_REORDER 1
+#endif
+
 /* Use forward list scheduling to rearrange insns of block pointed to by
    TARGET_BB, possibly bringing insns from subsequent blocks in the same
    region.  */
@@ -2393,6 +2465,7 @@ schedule_block (basic_block *target_bb)
   /* Clear the ready list.  */
   ready.first = ready.veclen - 1;
   ready.n_ready = 0;
+  ready.n_debug = 0;
 
   /* It is used for first cycle multipass scheduling.  */
   temp_state = alloca (dfa_state_size);
@@ -2403,7 +2476,8 @@ schedule_block (basic_block *target_bb)
   /* We start inserting insns after PREV_HEAD.  */
   last_scheduled_insn = prev_head;
 
-  gcc_assert (NOTE_P (last_scheduled_insn)
+  gcc_assert ((NOTE_P (last_scheduled_insn)
+	       || BOUNDARY_DEBUG_INSN_P (last_scheduled_insn))
 	      && BLOCK_FOR_INSN (last_scheduled_insn) == *target_bb);
 
   /* Initialize INSN_QUEUE.  Q_SIZE is the total number of insns in the
@@ -2424,12 +2498,14 @@ schedule_block (basic_block *target_bb)
   /* The algorithm is O(n^2) in the number of ready insns at any given
      time in the worst case.  Before reload we are more likely to have
      big lists so truncate them to a reasonable size.  */
-  if (!reload_completed && ready.n_ready > MAX_SCHED_READY_INSNS)
+  if (!reload_completed
+      && ready.n_ready - ready.n_debug > MAX_SCHED_READY_INSNS)
     {
       ready_sort (&ready);
 
-      /* Find first free-standing insn past MAX_SCHED_READY_INSNS.  */
-      for (i = MAX_SCHED_READY_INSNS; i < ready.n_ready; i++)
+      /* Find first free-standing insn past MAX_SCHED_READY_INSNS.
+         If there are debug insns, we know they're first.  */
+      for (i = MAX_SCHED_READY_INSNS + ready.n_debug; i < ready.n_ready; i++)
 	if (!SCHED_GROUP_P (ready_element (&ready, i)))
 	  break;
 
@@ -2512,6 +2588,47 @@ schedule_block (basic_block *target_bb)
 	    }
 	}
 
+      /* We don't want md sched reorder to even see debug isns, so put
+	 them out right away.  */
+      if (SCHED_DEBUG_INSNS_BEFORE_REORDER
+	  && ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
+	{
+	  if (control_flow_insn_p (last_scheduled_insn))
+	    {
+	      *target_bb = current_sched_info->advance_target_bb
+		(*target_bb, 0);
+
+	      if (sched_verbose)
+		{
+		  rtx x;
+
+		  x = next_real_insn (last_scheduled_insn);
+		  gcc_assert (x);
+		  dump_new_block_header (1, *target_bb, x, tail);
+		}
+
+	      last_scheduled_insn = bb_note (*target_bb);
+	    }
+
+	  while (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
+	    {
+	      rtx insn = ready_remove_first (&ready);
+	      gcc_assert (DEBUG_INSN_P (insn));
+	      (*current_sched_info->begin_schedule_ready) (insn,
+							   last_scheduled_insn);
+	      move_insn (insn, last_scheduled_insn,
+			 current_sched_info->next_tail);
+	      last_scheduled_insn = insn;
+	      advance = schedule_insn (insn);
+	      gcc_assert (advance == 0);
+	      if (ready.n_ready > 0)
+		ready_sort (&ready);
+	    }
+
+	  if (!ready.n_ready)
+	    continue;
+	}
+
       /* Allow the target to reorder the list, typically for
 	 better instruction bundling.  */
       if (sort_p && targetm.sched.reorder
@@ -2553,7 +2670,10 @@ schedule_block (basic_block *target_bb)
 		ready_sort (&ready);
 	    }
 
-	  if (ready.n_ready == 0 || !can_issue_more
+	  if (ready.n_ready == 0
+	      || (!can_issue_more
+		  && (SCHED_DEBUG_INSNS_BEFORE_REORDER
+		      || !DEBUG_INSN_P (ready_element (&ready, 0))))
 	      || state_dead_lock_p (curr_state)
 	      || !(*current_sched_info->schedule_more_p) ())
 	    break;
@@ -2690,11 +2810,13 @@ schedule_block (basic_block *target_bb)
 	  if (targetm.sched.variable_issue)
 	    can_issue_more =
 	      targetm.sched.variable_issue (sched_dump, sched_verbose,
-					       insn, can_issue_more);
+					    insn, can_issue_more);
 	  /* A naked CLOBBER or USE generates no instruction, so do
 	     not count them against the issue rate.  */
 	  else if (GET_CODE (PATTERN (insn)) != USE
-		   && GET_CODE (PATTERN (insn)) != CLOBBER)
+		   && GET_CODE (PATTERN (insn)) != CLOBBER
+		   && (SCHED_DEBUG_INSNS_BEFORE_REORDER
+		       || !DEBUG_INSN_P (insn)))
 	    can_issue_more--;
 
 	  advance = schedule_insn (insn);
@@ -2705,7 +2827,9 @@ schedule_block (basic_block *target_bb)
 	  if (advance != 0)
 	    break;
 
-	  first_cycle_insn_p = 0;
+	  if (SCHED_DEBUG_INSNS_BEFORE_REORDER
+	      || !DEBUG_INSN_P (insn))
+	    first_cycle_insn_p = 0;
 
 	  /* Sort the ready list based on priority.  This must be
 	     redone here, as schedule_insn may have readied additional
@@ -2713,6 +2837,45 @@ schedule_block (basic_block *target_bb)
 	  if (ready.n_ready > 0)
 	    ready_sort (&ready);
 
+	  /* Quickly go through debug insns such that md sched
+	     reorder2 doesn't have to deal with debug insns.  */
+	  if (SCHED_DEBUG_INSNS_BEFORE_REORDER
+	      && ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0))
+	      && (*current_sched_info->schedule_more_p) ())
+	    {
+	      if (control_flow_insn_p (last_scheduled_insn))
+		{
+		  *target_bb = current_sched_info->advance_target_bb
+		    (*target_bb, 0);
+
+		  if (sched_verbose)
+		    {
+		      rtx x;
+
+		      x = next_real_insn (last_scheduled_insn);
+		      gcc_assert (x);
+		      dump_new_block_header (1, *target_bb, x, tail);
+		    }
+
+		  last_scheduled_insn = bb_note (*target_bb);
+		}
+
+ 	      while (ready.n_ready && DEBUG_INSN_P (ready_element (&ready, 0)))
+		{
+		  insn = ready_remove_first (&ready);
+		  gcc_assert (DEBUG_INSN_P (insn));
+		  (*current_sched_info->begin_schedule_ready)
+		    (insn, last_scheduled_insn);
+		  move_insn (insn, last_scheduled_insn,
+			     current_sched_info->next_tail);
+		  advance = schedule_insn (insn);
+		  last_scheduled_insn = insn;
+		  gcc_assert (advance == 0);
+		  if (ready.n_ready > 0)
+		    ready_sort (&ready);
+		}
+	    }
+
 	  if (targetm.sched.reorder2
 	      && (ready.n_ready == 0
 		  || !SCHED_GROUP_P (ready_element (&ready, 0))))
@@ -2736,7 +2899,7 @@ schedule_block (basic_block *target_bb)
   if (current_sched_info->queue_must_finish_empty)
     /* Sanity check -- queue must be empty now.  Meaningless if region has
        multiple bbs.  */
-    gcc_assert (!q_size && !ready.n_ready);
+    gcc_assert (!q_size && !ready.n_ready && !ready.n_debug);
   else 
     {
       /* We must maintain QUEUE_INDEX between blocks in region.  */
@@ -2815,8 +2978,8 @@ set_priorities (rtx head, rtx tail)
 	current_sched_info->sched_max_insns_priority;
   rtx prev_head;
 
-  if (head == tail && (! INSN_P (head)))
-    return 0;
+  if (head == tail && (! INSN_P (head) || BOUNDARY_DEBUG_INSN_P (head)))
+    gcc_unreachable ();
 
   n_insn = 0;
 
@@ -4584,7 +4747,7 @@ add_jump_dependencies (rtx insn, rtx jum
       if (insn == jump)
 	break;
       
-      if (sd_lists_empty_p (insn, SD_LIST_FORW))
+      if (nondebug_dep_list_size (insn) == 0)
 	{
 	  dep_def _new_dep, *new_dep = &_new_dep;
 
@@ -4627,6 +4790,19 @@ has_edge_p (VEC(edge,gc) *el, int type)
   return 0;
 }
 
+/* Search back, starting at INSN, for an insn that is not a
+   NOTE_INSN_VAR_LOCATION.  Don't search beyond HEAD, and return it if
+   no such insn can be found.  */
+static inline rtx
+prev_non_location_insn (rtx insn, rtx head)
+{
+  while (insn != head && NOTE_P (insn)
+	 && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
+    insn = PREV_INSN (insn);
+
+  return insn;
+}
+
 /* Check few properties of CFG between HEAD and TAIL.
    If HEAD (TAIL) is NULL check from the beginning (till the end) of the
    instruction stream.  */
@@ -4686,8 +4862,9 @@ check_cfg (rtx head, rtx tail)
 	    {
 	      if (control_flow_insn_p (head))
 		{
-		  gcc_assert (BB_END (bb) == head);
-		  
+		  gcc_assert (prev_non_location_insn (BB_END (bb), head)
+			      == head);
+
 		  if (any_uncondjump_p (head))
 		    gcc_assert (EDGE_COUNT (bb->succs) == 1
 				&& BARRIER_P (NEXT_INSN (head)));
@@ -4703,11 +4880,12 @@ check_cfg (rtx head, rtx tail)
 	      if (BB_END (bb) == head)
 		{
 		  if (EDGE_COUNT (bb->succs) > 1)
-		    gcc_assert (control_flow_insn_p (head)
+		    gcc_assert (control_flow_insn_p (prev_non_location_insn
+						     (head, BB_HEAD (bb)))
 				|| has_edge_p (bb->succs, EDGE_COMPLEX));
 		  bb = 0;
 		}
-			      
+
 	      head = NEXT_INSN (head);
 	    }
 	}
Index: gcc/modulo-sched.c
===================================================================
--- gcc/modulo-sched.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/modulo-sched.c	2009-06-05 05:08:11.000000000 -0300
@@ -348,7 +348,7 @@ const_iteration_count (rtx count_reg, ba
   get_ebb_head_tail (pre_header, pre_header, &head, &tail);
 
   for (insn = tail; insn != PREV_INSN (head); insn = PREV_INSN (insn))
-    if (INSN_P (insn) && single_set (insn) &&
+    if (NONDEBUG_INSN_P (insn) && single_set (insn) &&
 	rtx_equal_p (count_reg, SET_DEST (single_set (insn))))
       {
 	rtx pat = single_set (insn);
@@ -374,7 +374,7 @@ res_MII (ddg_ptr g)
   if (targetm.sched.sms_res_mii)
     return targetm.sched.sms_res_mii (g); 
   
-  return (g->num_nodes / issue_rate);
+  return ((g->num_nodes - g->num_debug) / issue_rate);
 }
 
 
@@ -768,7 +768,7 @@ loop_single_full_bb_p (struct loop *loop
       for (; head != NEXT_INSN (tail); head = NEXT_INSN (head))
         {
           if (NOTE_P (head) || LABEL_P (head)
- 	      || (INSN_P (head) && JUMP_P (head)))
+ 	      || (INSN_P (head) && (DEBUG_INSN_P (head) || JUMP_P (head))))
  	    continue;
  	  empty_bb = false;
  	  break;
@@ -1019,7 +1019,7 @@ sms_schedule (void)
 
         if (CALL_P (insn)
             || BARRIER_P (insn)
-            || (INSN_P (insn) && !JUMP_P (insn)
+            || (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
                 && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE)
             || (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
             || (INSN_P (insn) && (set = single_set (insn))
@@ -1037,7 +1037,7 @@ sms_schedule (void)
 		fprintf (dump_file, "SMS loop-with-barrier\n");
               else if (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
                 fprintf (dump_file, "SMS reg inc\n");
-              else if ((INSN_P (insn) && !JUMP_P (insn)
+              else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
                 && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
                 fprintf (dump_file, "SMS loop-with-not-single-set\n");
               else
@@ -1751,7 +1751,7 @@ sms_schedule_by_order (ddg_ptr g, int mi
   	  ddg_node_ptr u_node = &ps->g->nodes[u];
 	  rtx insn = u_node->insn;
 
-	  if (!INSN_P (insn))
+	  if (!NONDEBUG_INSN_P (insn))
 	    {
 	      RESET_BIT (tobe_scheduled, u);
 	      continue;
@@ -2740,7 +2740,7 @@ ps_has_conflicts (partial_schedule_ptr p
 	{
 	  rtx insn = crr_insn->node->insn;
 
-	  if (!INSN_P (insn))
+	  if (!NONDEBUG_INSN_P (insn))
 	    continue;
 
 	  /* Check if there is room for the current insn.  */
Index: gcc/sel-sched.c
===================================================================
--- gcc/sel-sched.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/sel-sched.c	2009-06-05 05:07:56.000000000 -0300
@@ -557,6 +557,7 @@ static int stat_substitutions_total;
 static bool rtx_ok_for_substitution_p (rtx, rtx);
 static int sel_rank_for_schedule (const void *, const void *);
 static av_set_t find_sequential_best_exprs (bnd_t, expr_t, bool);
+static basic_block find_block_for_bookkeeping (edge e1, edge e2, bool lax);
 
 static rtx get_dest_from_orig_ops (av_set_t);
 static basic_block generate_bookkeeping_insn (expr_t, edge, edge);
@@ -2059,6 +2060,56 @@ moveup_expr_inside_insn_group (expr_t ex
 /* True when a conflict on a target register was found during moveup_expr.  */
 static bool was_target_conflict = false;
 
+/* Return true when moving a debug INSN across THROUGH_INSN will
+   create a bookkeeping block.  We don't want to create such blocks,
+   for they would cause codegen differences between compilations with
+   and without debug info.  */
+
+static bool
+moving_insn_creates_bookkeeping_block_p (insn_t insn,
+					 insn_t through_insn)
+{
+  basic_block bbi, bbt;
+  edge e1, e2;
+  edge_iterator ei1, ei2;
+
+  if (!bookkeeping_can_be_created_if_moved_through_p (through_insn))
+    {
+      if (sched_verbose >= 9)
+	sel_print ("no bookkeeping required: ");
+      return FALSE;
+    }
+
+  bbi = BLOCK_FOR_INSN (insn);
+
+  if (EDGE_COUNT (bbi->preds) == 1)
+    {
+      if (sched_verbose >= 9)
+	sel_print ("only one pred edge: ");
+      return TRUE;
+    }
+
+  bbt = BLOCK_FOR_INSN (through_insn);
+
+  FOR_EACH_EDGE (e1, ei1, bbt->succs)
+    {
+      FOR_EACH_EDGE (e2, ei2, bbi->preds)
+	{
+	  if (find_block_for_bookkeeping (e1, e2, TRUE))
+	    {
+	      if (sched_verbose >= 9)
+		sel_print ("found existing block: ");
+	      return FALSE;
+	    }
+	}
+    }
+
+  if (sched_verbose >= 9)
+    sel_print ("would create bookkeeping block: ");
+
+  return TRUE;
+}
+
 /* Modifies EXPR so it can be moved through the THROUGH_INSN,
    performing necessary transformations.  Record the type of transformation 
    made in PTRANS_TYPE, when it is not NULL.  When INSIDE_INSN_GROUP, 
@@ -2110,7 +2161,8 @@ moveup_expr (expr_t expr, insn_t through
           /* And it should be mutually exclusive with through_insn, or 
              be an unconditional jump.  */
           if (! any_uncondjump_p (insn)
-              && ! sched_insns_conditions_mutex_p (insn, through_insn))
+              && ! sched_insns_conditions_mutex_p (insn, through_insn)
+	      && ! DEBUG_INSN_P (through_insn))
             return MOVEUP_EXPR_NULL;
         }
 
@@ -2131,6 +2183,12 @@ moveup_expr (expr_t expr, insn_t through
   else
     gcc_assert (!control_flow_insn_p (insn));
 
+  /* Don't move debug insns if this would require bookkeeping.  */
+  if (DEBUG_INSN_P (insn)
+      && BLOCK_FOR_INSN (through_insn) != BLOCK_FOR_INSN (insn)
+      && moving_insn_creates_bookkeeping_block_p (insn, through_insn))
+    return MOVEUP_EXPR_NULL;
+
   /* Deal with data dependencies.  */
   was_target_conflict = false;
   full_ds = has_dependence_p (expr, through_insn, &has_dep_p);
@@ -2440,7 +2498,12 @@ moveup_expr_cached (expr_t expr, insn_t 
       sel_print (" through %d: ", INSN_UID (insn));
     }
 
-  if (try_bitmap_cache (expr, insn, inside_insn_group, &res))
+  if (DEBUG_INSN_P (EXPR_INSN_RTX (expr))
+      && (sel_bb_head (BLOCK_FOR_INSN (EXPR_INSN_RTX (expr)))
+	  == EXPR_INSN_RTX (expr)))
+    /* Don't use cached information for debug insns that are heads of
+       basic blocks.  */;
+  else if (try_bitmap_cache (expr, insn, inside_insn_group, &res))
     /* When inside insn group, we do not want remove stores conflicting
        with previosly issued loads.  */
     got_answer = ! inside_insn_group || res != MOVEUP_EXPR_NULL;
@@ -2852,6 +2915,9 @@ compute_av_set_inside_bb (insn_t first_i
 	  break;	  
 	}
 
+      if (DEBUG_INSN_P (last_insn))
+	continue;
+
       if (end_ws > max_ws)
 	{
 	  /* We can reach max lookahead size at bb_header, so clean av_set 
@@ -3261,6 +3327,12 @@ sel_rank_for_schedule (const void *x, co
   tmp_insn = EXPR_INSN_RTX (tmp);
   tmp2_insn = EXPR_INSN_RTX (tmp2);
   
+  /* Schedule debug insns as early as possible.  */
+  if (DEBUG_INSN_P (tmp_insn) && !DEBUG_INSN_P (tmp2_insn))
+    return -1;
+  else if (DEBUG_INSN_P (tmp2_insn))
+    return 1;
+
   /* Prefer SCHED_GROUP_P insns to any others.  */
   if (SCHED_GROUP_P (tmp_insn) != SCHED_GROUP_P (tmp2_insn))
     {
@@ -3332,9 +3404,6 @@ sel_rank_for_schedule (const void *x, co
 	return dw;
     }
 
-  tmp_insn = EXPR_INSN_RTX (tmp);
-  tmp2_insn = EXPR_INSN_RTX (tmp2);
-
   /* Prefer an old insn to a bookkeeping insn.  */
   if (INSN_UID (tmp_insn) < first_emitted_uid 
       && INSN_UID (tmp2_insn) >= first_emitted_uid)
@@ -4412,15 +4481,16 @@ block_valid_for_bookkeeping_p (basic_blo
 /* Attempt to find a block that can hold bookkeeping code for path(s) incoming
    into E2->dest, except from E1->src (there may be a sequence of empty basic
    blocks between E1->src and E2->dest).  Return found block, or NULL if new
-   one must be created.  */
+   one must be created.  If LAX holds, don't assume there is a simple path
+   from E1->src to E2->dest.  */
 static basic_block
-find_block_for_bookkeeping (edge e1, edge e2)
+find_block_for_bookkeeping (edge e1, edge e2, bool lax)
 {
   basic_block candidate_block = NULL;
   edge e;
 
   /* Loop over edges from E1 to E2, inclusive.  */
-  for (e = e1; ; e = EDGE_SUCC (e->dest, 0))
+  for (e = e1; !lax || e->dest != EXIT_BLOCK_PTR; e = EDGE_SUCC (e->dest, 0))
     {
       if (EDGE_COUNT (e->dest->preds) == 2)
 	{
@@ -4438,10 +4508,18 @@ find_block_for_bookkeeping (edge e1, edg
 	return NULL;
 
       if (e == e2)
-	return (block_valid_for_bookkeeping_p (candidate_block)
+	return ((!lax || candidate_block)
+		&& block_valid_for_bookkeeping_p (candidate_block)
 		? candidate_block
 		: NULL);
+
+      if (lax && EDGE_COUNT (e->dest->succs) != 1)
+	return NULL;
     }
+
+  if (lax)
+    return NULL;
+
   gcc_unreachable ();
 }
 
@@ -4485,6 +4563,101 @@ create_block_for_bookkeeping (edge e1, e
   gcc_assert (e1->dest == new_bb);
   gcc_assert (sel_bb_empty_p (bb));
 
+  /* To keep basic block numbers in sync between debug and non-debug
+     compilations, we have to rotate blocks here.  Consider that we
+     started from (a,b)->d, (c,d)->e, and d contained only debug
+     insns.  It would have been removed before if the debug insns
+     weren't there, so we'd have split e rather than d.  So what we do
+     now is to swap the block numbers of new_bb and
+     single_succ(new_bb) == e, so that the insns that were in e before
+     get the new block number.  */
+
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      basic_block succ;
+      insn_t insn = sel_bb_head (new_bb);
+      insn_t last;
+
+      if (DEBUG_INSN_P (insn)
+	  && single_succ_p (new_bb)
+	  && (succ = single_succ (new_bb))
+	  && succ != EXIT_BLOCK_PTR
+	  && DEBUG_INSN_P ((last = sel_bb_end (new_bb))))
+	{
+	  while (insn != last && (DEBUG_INSN_P (insn) || NOTE_P (insn)))
+	    insn = NEXT_INSN (insn);
+
+	  if (insn == last)
+	    {
+	      sel_global_bb_info_def gbi;
+	      sel_region_bb_info_def rbi;
+	      int i;
+
+	      if (sched_verbose >= 2)
+		sel_print ("Swapping block ids %i and %i\n",
+			   new_bb->index, succ->index);
+
+	      i = new_bb->index;
+	      new_bb->index = succ->index;
+	      succ->index = i;
+
+	      SET_BASIC_BLOCK (new_bb->index, new_bb);
+	      SET_BASIC_BLOCK (succ->index, succ);
+
+	      memcpy (&gbi, SEL_GLOBAL_BB_INFO (new_bb), sizeof (gbi));
+	      memcpy (SEL_GLOBAL_BB_INFO (new_bb), SEL_GLOBAL_BB_INFO (succ),
+		      sizeof (gbi));
+	      memcpy (SEL_GLOBAL_BB_INFO (succ), &gbi, sizeof (gbi));
+
+	      memcpy (&rbi, SEL_REGION_BB_INFO (new_bb), sizeof (rbi));
+	      memcpy (SEL_REGION_BB_INFO (new_bb), SEL_REGION_BB_INFO (succ),
+		      sizeof (rbi));
+	      memcpy (SEL_REGION_BB_INFO (succ), &rbi, sizeof (rbi));
+
+	      i = BLOCK_TO_BB (new_bb->index);
+	      BLOCK_TO_BB (new_bb->index) = BLOCK_TO_BB (succ->index);
+	      BLOCK_TO_BB (succ->index) = i;
+
+	      i = CONTAINING_RGN (new_bb->index);
+	      CONTAINING_RGN (new_bb->index) = CONTAINING_RGN (succ->index);
+	      CONTAINING_RGN (succ->index) = i;
+
+	      for (i = 0; i < current_nr_blocks; i++)
+		if (BB_TO_BLOCK (i) == succ->index)
+		  BB_TO_BLOCK (i) = new_bb->index;
+		else if (BB_TO_BLOCK (i) == new_bb->index)
+		  BB_TO_BLOCK (i) = succ->index;
+
+	      FOR_BB_INSNS (new_bb, insn)
+		if (INSN_P (insn))
+		  EXPR_ORIG_BB_INDEX (INSN_EXPR (insn)) = new_bb->index;
+
+	      FOR_BB_INSNS (succ, insn)
+		if (INSN_P (insn))
+		  EXPR_ORIG_BB_INDEX (INSN_EXPR (insn)) = succ->index;
+
+	      if (bitmap_bit_p (code_motion_visited_blocks, new_bb->index))
+		{
+		  bitmap_set_bit (code_motion_visited_blocks, succ->index);
+		  bitmap_clear_bit (code_motion_visited_blocks, new_bb->index);
+		}
+
+	      gcc_assert (LABEL_P (BB_HEAD (new_bb))
+			  && LABEL_P (BB_HEAD (succ)));
+
+	      if (sched_verbose >= 4)
+		sel_print ("Swapping code labels %i and %i\n",
+			   CODE_LABEL_NUMBER (BB_HEAD (new_bb)),
+			   CODE_LABEL_NUMBER (BB_HEAD (succ)));
+
+	      i = CODE_LABEL_NUMBER (BB_HEAD (new_bb));
+	      CODE_LABEL_NUMBER (BB_HEAD (new_bb))
+		= CODE_LABEL_NUMBER (BB_HEAD (succ));
+	      CODE_LABEL_NUMBER (BB_HEAD (succ)) = i;
+	    }
+	}
+    }
+
   return bb;
 }
 
@@ -4496,12 +4669,42 @@ find_place_for_bookkeeping (edge e1, edg
   insn_t place_to_insert;
   /* Find a basic block that can hold bookkeeping.  If it can be found, do not
      create new basic block, but insert bookkeeping there.  */
-  basic_block book_block = find_block_for_bookkeeping (e1, e2);
+  basic_block book_block = find_block_for_bookkeeping (e1, e2, FALSE);
 
-  if (!book_block)
-    book_block = create_block_for_bookkeeping (e1, e2);
+  if (book_block)
+    {
+      place_to_insert = BB_END (book_block);
+
+      /* Don't use a block containing only debug insns for
+	 bookkeeping, this causes scheduling differences between debug
+	 and non-debug compilations, for the block would have been
+	 removed already.  */
+      if (DEBUG_INSN_P (place_to_insert))
+	{
+	  rtx insn = sel_bb_head (book_block);
+
+	  while (insn != place_to_insert &&
+		 (DEBUG_INSN_P (insn) || NOTE_P (insn)))
+	    insn = NEXT_INSN (insn);
+
+	  if (insn == place_to_insert)
+	    book_block = NULL;
+	}
+    }
 
-  place_to_insert = BB_END (book_block);
+  if (!book_block)
+    {
+      book_block = create_block_for_bookkeeping (e1, e2);
+      place_to_insert = BB_END (book_block);
+      if (sched_verbose >= 9)
+	sel_print ("New block is %i, split from bookkeeping block %i\n",
+		   EDGE_SUCC (book_block, 0)->dest->index, book_block->index);
+    }
+  else
+    {
+      if (sched_verbose >= 9)
+	sel_print ("Pre-existing bookkeeping block is %i\n", book_block->index);
+    }
 
   /* If basic block ends with a jump, insert bookkeeping code right before it.  */
   if (INSN_P (place_to_insert) && control_flow_insn_p (place_to_insert))
@@ -4587,6 +4790,8 @@ generate_bookkeeping_insn (expr_t c_expr
 
   join_point = sel_bb_head (e2->dest);
   place_to_insert = find_place_for_bookkeeping (e1, e2);
+  if (!place_to_insert)
+    return NULL;
   new_seqno = find_seqno_for_bookkeeping (place_to_insert, join_point);
   need_to_exchange_data_sets
     = sel_bb_empty_p (BLOCK_FOR_INSN (place_to_insert));
@@ -4748,7 +4953,7 @@ move_cond_jump (rtx insn, bnd_t bnd)
 /* Remove nops generated during move_op for preventing removal of empty
    basic blocks.  */
 static void
-remove_temp_moveop_nops (void)
+remove_temp_moveop_nops (bool full_tidying)
 {
   int i;
   insn_t insn;
@@ -4756,7 +4961,7 @@ remove_temp_moveop_nops (void)
   for (i = 0; VEC_iterate (insn_t, vec_temp_moveop_nops, i, insn); i++)
     {
       gcc_assert (INSN_NOP_P (insn));
-      return_nop_to_pool (insn);
+      return_nop_to_pool (insn, full_tidying);
     }
 
   /* Empty the vector.  */
@@ -4949,8 +5154,20 @@ prepare_place_to_insert (bnd_t bnd)
     {
       /* Add it after last scheduled.  */
       place_to_insert = ILIST_INSN (BND_PTR (bnd));
+      if (DEBUG_INSN_P (place_to_insert))
+	{
+	  ilist_t l = BND_PTR (bnd);
+	  while ((l = ILIST_NEXT (l)) &&
+		 DEBUG_INSN_P (ILIST_INSN (l)))
+	    ;
+	  if (!l)
+	    place_to_insert = NULL;
+	}
     }
   else
+    place_to_insert = NULL;
+
+  if (!place_to_insert)
     {
       /* Add it before BND_TO.  The difference is in the
          basic block, where INSN will be added.  */
@@ -5058,7 +5275,8 @@ advance_state_on_fence (fence_t fence, i
 
   if (sched_verbose >= 2)
     debug_state (FENCE_STATE (fence));
-  FENCE_STARTS_CYCLE_P (fence) = 0;
+  if (!DEBUG_INSN_P (insn))
+    FENCE_STARTS_CYCLE_P (fence) = 0;
   return asm_p;
 }
 
@@ -5117,10 +5335,11 @@ update_fence_and_insn (fence_t fence, in
     }
 }
 
-/* Update boundary BND with INSN, remove the old boundary from
-   BNDSP, add new boundaries to BNDS_TAIL_P and return it.  */
+/* Update boundary BND (and, if needed, FENCE) with INSN, remove the
+   old boundary from BNDSP, add new boundaries to BNDS_TAIL_P and
+   return it.  */
 static blist_t *
-update_boundaries (bnd_t bnd, insn_t insn, blist_t *bndsp, 
+update_boundaries (fence_t fence, bnd_t bnd, insn_t insn, blist_t *bndsp,
                    blist_t *bnds_tailp)
 {
   succ_iterator si;
@@ -5133,6 +5352,21 @@ update_boundaries (bnd_t bnd, insn_t ins
       ilist_t ptr = ilist_copy (BND_PTR (bnd));
       
       ilist_add (&ptr, insn);
+
+      if (DEBUG_INSN_P (insn) && sel_bb_end_p (insn)
+	  && is_ineligible_successor (succ, ptr))
+	{
+	  ilist_clear (&ptr);
+	  continue;
+	}
+
+      if (FENCE_INSN (fence) == insn && !sel_bb_end_p (insn))
+	{
+	  if (sched_verbose >= 9)
+	    sel_print ("Updating fence insn from %i to %i\n",
+		       INSN_UID (insn), INSN_UID (succ));
+	  FENCE_INSN (fence) = succ;
+	}
       blist_add (bnds_tailp, succ, ptr, BND_DC (bnd));
       bnds_tailp = &BLIST_NEXT (*bnds_tailp);
     }
@@ -5192,8 +5426,8 @@ schedule_expr_on_boundary (bnd_t bnd, ex
   /* Return the nops generated for preserving of data sets back
      into pool.  */
   if (INSN_NOP_P (place_to_insert))
-    return_nop_to_pool (place_to_insert);
-  remove_temp_moveop_nops ();
+    return_nop_to_pool (place_to_insert, !DEBUG_INSN_P (insn));
+  remove_temp_moveop_nops (!DEBUG_INSN_P (insn));
 
   av_set_clear (&expr_seq);
  
@@ -5251,7 +5485,9 @@ fill_insns (fence_t fence, int seqno, il
       int was_stall = 0, scheduled_insns = 0, stall_iterations = 0;
       int max_insns = pipelining_p ? issue_rate : 2 * issue_rate;
       int max_stall = pipelining_p ? 1 : 3;
-      
+      bool last_insn_was_debug = false;
+      bool was_debug_bb_end_p = false;
+
       compute_av_set_on_boundaries (fence, bnds, &av_vliw);
       remove_insns_that_need_bookkeeping (fence, &av_vliw);
       remove_insns_for_debug (bnds, &av_vliw);
@@ -5309,8 +5545,11 @@ fill_insns (fence_t fence, int seqno, il
 	    }
           
           insn = schedule_expr_on_boundary (bnd, expr_vliw, seqno);
+	  last_insn_was_debug = DEBUG_INSN_P (insn);
+	  if (last_insn_was_debug)
+	    was_debug_bb_end_p = (insn == BND_TO (bnd) && sel_bb_end_p (insn));
           update_fence_and_insn (fence, insn, need_stall);
-          bnds_tailp = update_boundaries (bnd, insn, bndsp, bnds_tailp);
+          bnds_tailp = update_boundaries (fence, bnd, insn, bndsp, bnds_tailp);
 
 	  /* Add insn to the list of scheduled on this cycle instructions.  */
 	  ilist_add (*scheduled_insns_tailpp, insn);
@@ -5319,13 +5558,14 @@ fill_insns (fence_t fence, int seqno, il
       while (*bndsp != *bnds_tailp1);
 
       av_set_clear (&av_vliw);
-      scheduled_insns++;
+      if (!last_insn_was_debug)
+	scheduled_insns++;
 
       /* We currently support information about candidate blocks only for
 	 one 'target_bb' block.  Hence we can't schedule after jump insn,
 	 as this will bring two boundaries and, hence, necessity to handle
 	 information for two or more blocks concurrently.  */
-      if (sel_bb_end_p (insn)
+      if ((last_insn_was_debug ? was_debug_bb_end_p : sel_bb_end_p (insn))
           || (was_stall 
               && (was_stall >= max_stall 
                   || scheduled_insns >= max_insns)))
@@ -5544,7 +5784,7 @@ track_scheduled_insns_and_blocks (rtx in
 	 instruction out of it.  */
       if (INSN_SCHED_TIMES (insn) > 0)
 	bitmap_set_bit (blocks_to_reschedule, BLOCK_FOR_INSN (insn)->index);
-      else if (INSN_UID (insn) < first_emitted_uid)
+      else if (INSN_UID (insn) < first_emitted_uid && !DEBUG_INSN_P (insn))
 	num_insns_scheduled++;
     }
   else
@@ -5636,32 +5876,63 @@ handle_emitting_transformations (rtx ins
   return insn_emitted;
 }  
 
-/* Remove INSN from stream.  When ONLY_DISCONNECT is true, its data 
-   is not removed but reused when INSN is re-emitted.  */
-static void
-remove_insn_from_stream (rtx insn, bool only_disconnect)
+/* If INSN is the only insn in the basic block (not counting JUMP,
+   which may be a jump to next insn, and DEBUG_INSNs), we want to
+   leave a NOP there till the return to fill_insns.  */
+
+static bool
+need_nop_to_preserve_insn_bb (rtx insn)
 {
-  insn_t nop, bb_head, bb_end;
-  bool need_nop_to_preserve_bb;
+  insn_t bb_head, bb_end, bb_next, in_next;
   basic_block bb = BLOCK_FOR_INSN (insn);
 
-  /* If INSN is the only insn in the basic block (not counting JUMP,
-     which may be a jump to next insn), leave NOP there till the 
-     return to fill_insns.  */
   bb_head = sel_bb_head (bb);
   bb_end = sel_bb_end (bb);
-  need_nop_to_preserve_bb = ((bb_head == bb_end)
-                             || (NEXT_INSN (bb_head) == bb_end 
-                                 && JUMP_P (bb_end))
-                             || IN_CURRENT_FENCE_P (NEXT_INSN (insn)));
 
+  if (bb_head == bb_end)
+    return true;
+
+  while (bb_head != bb_end && DEBUG_INSN_P (bb_head))
+    bb_head = NEXT_INSN (bb_head);
+
+  if (bb_head == bb_end)
+    return true;
+
+  while (bb_head != bb_end && DEBUG_INSN_P (bb_end))
+    bb_end = PREV_INSN (bb_end);
+
+  if (bb_head == bb_end)
+    return true;
+
+  bb_next = NEXT_INSN (bb_head);
+  while (bb_next != bb_end && DEBUG_INSN_P (bb_next))
+    bb_next = NEXT_INSN (bb_next);
+
+  if (bb_next == bb_end && JUMP_P (bb_end))
+    return true;
+
+  in_next = NEXT_INSN (insn);
+  while (DEBUG_INSN_P (in_next))
+    in_next = NEXT_INSN (in_next);
+
+  if (IN_CURRENT_FENCE_P (in_next))
+    return true;
+
+  return false;
+}
+
+/* Remove INSN from stream.  When ONLY_DISCONNECT is true, its data
+   is not removed but reused when INSN is re-emitted.  */
+static void
+remove_insn_from_stream (rtx insn, bool only_disconnect)
+{
   /* If there's only one insn in the BB, make sure that a nop is
      inserted into it, so the basic block won't disappear when we'll
      delete INSN below with sel_remove_insn. It should also survive
      till the return to fill_insns.  */	     
-  if (need_nop_to_preserve_bb)
+  if (need_nop_to_preserve_insn_bb (insn))
     {
-      nop = get_nop_from_pool (insn);
+      insn_t nop = get_nop_from_pool (insn);
       gcc_assert (INSN_NOP_P (nop));
       VEC_safe_push (insn_t, heap, vec_temp_moveop_nops, nop);
     }
@@ -5925,6 +6196,8 @@ fur_orig_expr_not_found (insn_t insn, av
 
   if (CALL_P (insn))
     sparams->crosses_call = true;
+  else if (DEBUG_INSN_P (insn))
+    return true;
 
   /* If current insn we are looking at cannot be executed together
      with original insn, then we can skip it safely.
Index: gcc/sel-sched-ir.c
===================================================================
--- gcc/sel-sched-ir.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/sel-sched-ir.c	2009-06-05 05:08:11.000000000 -0300
@@ -157,6 +157,7 @@ static void sel_remove_loop_preheader (v
 static bool insn_is_the_only_one_in_bb_p (insn_t);
 static void create_initial_data_sets (basic_block);
 
+static void free_av_set (basic_block);
 static void invalidate_av_set (basic_block);
 static void extend_insn_data (void);
 static void sel_init_new_insn (insn_t, int);
@@ -1044,10 +1045,10 @@ get_nop_from_pool (insn_t insn)
 
 /* Remove NOP from the instruction stream and return it to the pool.  */
 void
-return_nop_to_pool (insn_t nop)
+return_nop_to_pool (insn_t nop, bool full_tidying)
 {
   gcc_assert (INSN_IN_STREAM_P (nop));
-  sel_remove_insn (nop, false, true);
+  sel_remove_insn (nop, false, full_tidying);
 
   if (nop_pool.n == nop_pool.s)
     nop_pool.v = XRESIZEVEC (rtx, nop_pool.v, 
@@ -2362,6 +2363,8 @@ setup_id_for_insn (idata_t id, insn_t in
     type = SET;
   else if (type == JUMP_INSN && simplejump_p (insn))
     type = PC;
+  else if (type == DEBUG_INSN)
+    type = !force_unique_p ? USE : INSN;
   
   IDATA_TYPE (id) = type;
   IDATA_REG_SETS (id) = get_clear_regset_from_pool ();
@@ -3487,7 +3490,7 @@ maybe_tidy_empty_bb (basic_block bb)
 
   /* Keep empty bb only if this block immediately precedes EXIT and
      has incoming non-fallthrough edge.  Otherwise remove it.  */
-  if (!sel_bb_empty_p (bb) 
+  if (!sel_bb_empty_p (bb)
       || (single_succ_p (bb) 
           && single_succ (bb) == EXIT_BLOCK_PTR
           && (!single_pred_p (bb) 
@@ -3559,6 +3562,7 @@ bool
 tidy_control_flow (basic_block xbb, bool full_tidying)
 {
   bool changed = true;
+  insn_t first, last;
   
   /* First check whether XBB is empty.  */
   changed = maybe_tidy_empty_bb (xbb);
@@ -3575,6 +3579,20 @@ tidy_control_flow (basic_block xbb, bool
       tidy_fallthru_edge (EDGE_SUCC (xbb, 0));
     }
 
+  first = sel_bb_head (xbb);
+  last = sel_bb_end (xbb);
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      if (first != last && DEBUG_INSN_P (first))
+	do
+	  first = NEXT_INSN (first);
+	while (first != last && (DEBUG_INSN_P (first) || NOTE_P (first)));
+
+      if (first != last && DEBUG_INSN_P (last))
+	do
+	  last = PREV_INSN (last);
+	while (first != last && (DEBUG_INSN_P (last) || NOTE_P (last)));
+    }
   /* Check if there is an unnecessary jump in previous basic block leading
      to next basic block left after removing INSN from stream.  
      If it is so, remove that jump and redirect edge to current 
@@ -3582,9 +3600,9 @@ tidy_control_flow (basic_block xbb, bool
      when NOP will be deleted several instructions later with its 
      basic block we will not get a jump to next instruction, which 
      can be harmful.  */
-  if (sel_bb_head (xbb) == sel_bb_end (xbb) 
+  if (first == last
       && !sel_bb_empty_p (xbb)
-      && INSN_NOP_P (sel_bb_end (xbb))
+      && INSN_NOP_P (last)
       /* Flow goes fallthru from current block to the next.  */
       && EDGE_COUNT (xbb->succs) == 1
       && (EDGE_SUCC (xbb, 0)->flags & EDGE_FALLTHRU)
@@ -3624,6 +3642,21 @@ sel_remove_insn (insn_t insn, bool only_
 
   gcc_assert (INSN_IN_STREAM_P (insn));
 
+  if (DEBUG_INSN_P (insn) && BB_AV_SET_VALID_P (bb))
+    {
+      expr_t expr;
+      av_set_iterator i;
+
+      /* When we remove a debug insn that is head of a BB, it remains
+	 in the AV_SET of the block, but it shouldn't.  */
+      FOR_EACH_EXPR_1 (expr, i, &BB_AV_SET (bb))
+	if (EXPR_INSN_RTX (expr) == insn)
+	  {
+	    av_set_iter_remove (&i);
+	    break;
+	  }
+    }
+
   if (only_disconnect)
     {
       insn_t prev = PREV_INSN (insn);
@@ -3662,7 +3695,7 @@ sel_estimate_number_of_insns (basic_bloc
   insn_t insn = NEXT_INSN (BB_HEAD (bb)), next_tail = NEXT_INSN (BB_END (bb));
 
   for (; insn != next_tail; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
+    if (NONDEBUG_INSN_P (insn))
       res++;
 
   return res;
@@ -5363,6 +5396,8 @@ create_insn_rtx_from_pattern (rtx patter
 
   if (label == NULL_RTX)
     insn_rtx = emit_insn (pattern);
+  else if (DEBUG_INSN_P (label))
+    insn_rtx = emit_debug_insn (pattern);
   else
     {
       insn_rtx = emit_jump_insn (pattern);
@@ -5398,6 +5433,10 @@ create_copy_of_insn_rtx (rtx insn_rtx)
 {
   rtx res;
 
+  if (DEBUG_INSN_P (insn_rtx))
+    return create_insn_rtx_from_pattern (copy_rtx (PATTERN (insn_rtx)),
+					 insn_rtx);
+
   gcc_assert (NONJUMP_INSN_P (insn_rtx));
 
   res = create_insn_rtx_from_pattern (copy_rtx (PATTERN (insn_rtx)),
Index: gcc/sel-sched-ir.h
===================================================================
--- gcc/sel-sched-ir.h.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/sel-sched-ir.h	2009-06-05 05:07:56.000000000 -0300
@@ -1,6 +1,6 @@
 /* Instruction scheduling pass.  This file contains definitions used
    internally in the scheduler.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -1019,6 +1019,7 @@ struct succs_info
 extern basic_block after_recovery;
 
 extern insn_t sel_bb_head (basic_block);
+extern insn_t sel_bb_end (basic_block);
 extern bool sel_bb_empty_p (basic_block);
 extern bool in_current_region_p (basic_block);
 
@@ -1079,6 +1080,27 @@ get_loop_exit_edges_unique_dests (const 
   return edges;
 }
 
+static bool
+sel_bb_empty_or_nop_p (basic_block bb)
+{
+  insn_t first = sel_bb_head (bb), last;
+
+  if (first == NULL_RTX)
+    return true;
+
+  if (!INSN_NOP_P (first))
+    return false;
+
+  if (bb == EXIT_BLOCK_PTR)
+    return false;
+
+  last = sel_bb_end (bb);
+  if (first != last)
+    return false;
+
+  return true;
+}
+
 /* Collect all loop exits recursively, skipping empty BBs between them.  
    E.g. if BB is a loop header which has several loop exits,
    traverse all of them and if any of them turns out to be another loop header
@@ -1091,7 +1113,7 @@ get_all_loop_exits (basic_block bb)
 
   /* If bb is empty, and we're skipping to loop exits, then
      consider bb as a possible gate to the inner loop now.  */
-  while (sel_bb_empty_p (bb) 
+  while (sel_bb_empty_or_nop_p (bb)
 	 && in_current_region_p (bb))
     {
       bb = single_succ (bb);
@@ -1350,7 +1372,24 @@ _eligible_successor_edge_p (edge e1, suc
   while (1)
     {
       if (!sel_bb_empty_p (bb))
-        break;
+	{
+	  edge ne;
+	  basic_block nbb;
+
+	  if (!sel_bb_empty_or_nop_p (bb))
+	    break;
+
+	  ne = EDGE_SUCC (bb, 0);
+	  nbb = ne->dest;
+
+	  if (!in_current_region_p (nbb)
+	      && !(flags & SUCCS_OUT))
+	    break;
+
+	  e2 = ne;
+	  bb = nbb;
+	  continue;
+	}
         
       if (!in_current_region_p (bb) 
           && !(flags & SUCCS_OUT))
@@ -1470,7 +1509,7 @@ extern void return_regset_to_pool (regse
 extern void free_regset_pool (void);
 
 extern insn_t get_nop_from_pool (insn_t);
-extern void return_nop_to_pool (insn_t);
+extern void return_nop_to_pool (insn_t, bool);
 extern void free_nop_pool (void);
 
 /* Vinsns functions.  */
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/sched-deps.c	2009-06-05 05:08:11.000000000 -0300
@@ -1,7 +1,7 @@
 /* Instruction scheduling pass.  This file computes dependencies between
    instructions.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
    and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -650,7 +650,8 @@ sd_lists_size (const_rtx insn, sd_list_t
       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;
@@ -673,6 +674,9 @@ sd_init_insn (rtx insn)
   INSN_FORW_DEPS (insn) = create_deps_list ();
   INSN_RESOLVED_FORW_DEPS (insn) = create_deps_list ();
 
+  if (DEBUG_INSN_P (insn))
+    DEBUG_INSN_SCHED_P (insn) = TRUE;
+
   /* ??? It would be nice to allocate dependency caches here.  */
 }
 
@@ -682,6 +686,12 @@ sd_finish_insn (rtx insn)
 {
   /* ??? It would be nice to deallocate dependency caches here.  */
 
+  if (DEBUG_INSN_P (insn))
+    {
+      gcc_assert (DEBUG_INSN_SCHED_P (insn));
+      DEBUG_INSN_SCHED_P (insn) = FALSE;
+    }
+
   free_deps_list (INSN_HARD_BACK_DEPS (insn));
   INSN_HARD_BACK_DEPS (insn) = NULL;
 
@@ -1181,6 +1191,7 @@ sd_add_dep (dep_t dep, bool resolved_p)
   rtx insn = DEP_CON (dep);
 
   gcc_assert (INSN_P (insn) && INSN_P (elem) && insn != elem);
+  gcc_assert (!DEBUG_INSN_P (elem) || DEBUG_INSN_P (insn));
 
   if ((current_sched_info->flags & DO_SPECULATION)
       && !sched_insn_is_legitimate_for_speculation_p (insn, DEP_STATUS (dep)))
@@ -1462,7 +1473,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));
@@ -1472,6 +1483,8 @@ fixup_sched_groups (rtx insn)
   delete_all_dependences (insn);
 
   prev_nonnote = prev_nonnote_insn (insn);
+  while (DEBUG_INSN_P (prev_nonnote))
+    prev_nonnote = prev_nonnote_insn (prev_nonnote);
   if (BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (prev_nonnote)
       && ! sched_insns_conditions_mutex_p (insn, prev_nonnote))
     add_dependence (insn, prev_nonnote, REG_DEP_ANTI);
@@ -1801,8 +1814,7 @@ sched_analyze_reg (struct deps *deps, in
 	 already cross one.  */
       if (REG_N_CALLS_CROSSED (regno) == 0)
 	{
-	  if (!deps->readonly 
-              && ref == USE)
+	  if (!deps->readonly && ref == USE && !DEBUG_INSN_P (insn))
 	    deps->sched_before_next_call
 	      = alloc_INSN_LIST (insn, deps->sched_before_next_call);
 	  else
@@ -2059,6 +2071,12 @@ sched_analyze_2 (struct deps *deps, rtx 
 	rtx pending, pending_mem;
 	rtx t = x;
 
+	if (DEBUG_INSN_P (insn))
+	  {
+	    sched_analyze_2 (deps, XEXP (x, 0), insn);
+	    return;
+	  }
+
 	if (sched_deps_info->use_cselib)
 	  {
 	    t = shallow_copy_rtx (t);
@@ -2287,6 +2305,8 @@ sched_analyze_insn (struct deps *deps, r
     {
       rtx next;
       next = next_nonnote_insn (insn);
+      while (next && DEBUG_INSN_P (next))
+	next = next_nonnote_insn (next);
       if (next && BARRIER_P (next))
 	reg_pending_barrier = MOVE_BARRIER;
       else
@@ -2361,9 +2381,49 @@ sched_analyze_insn (struct deps *deps, r
       || (NONJUMP_INSN_P (insn) && control_flow_insn_p (insn)))
     reg_pending_barrier = MOVE_BARRIER;
 
+  /* Add register dependencies for insn.  */
+  if (DEBUG_INSN_P (insn))
+    {
+      rtx prev = deps->last_debug_insn;
+      rtx u;
+
+      if (!deps->readonly)
+	deps->last_debug_insn = insn;
+
+      if (prev)
+	add_dependence (insn, prev, REG_DEP_ANTI);
+
+      add_dependence_list (insn, deps->last_function_call, 1,
+			   REG_DEP_ANTI);
+
+      for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1))
+	if (! JUMP_P (XEXP (u, 0))
+	    || !sel_sched_p ())
+	  add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+      EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
+	{
+	  struct deps_reg *reg_last = &deps->reg_last[i];
+	  add_dependence_list (insn, reg_last->sets, 1, REG_DEP_ANTI);
+	  add_dependence_list (insn, reg_last->clobbers, 1, REG_DEP_ANTI);
+	}
+      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);
+    }
   /* If the current insn is conditional, we can't free any
      of the lists.  */
-  if (sched_has_condition_p (insn))
+  else if (sched_has_condition_p (insn))
     {
       EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
         {
@@ -2557,7 +2617,30 @@ sched_analyze_insn (struct deps *deps, r
       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)
@@ -2602,6 +2685,7 @@ sched_analyze_insn (struct deps *deps, r
 	}
     }
 
+ 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
@@ -2628,7 +2712,7 @@ deps_analyze_insn (struct deps *deps, rt
   if (sched_deps_info->start_insn)
     sched_deps_info->start_insn (insn);
 
-  if (NONJUMP_INSN_P (insn) || JUMP_P (insn))
+  if (NONJUMP_INSN_P (insn) || DEBUG_INSN_P (insn) || JUMP_P (insn))
     {
       /* Make each JUMP_INSN (but not a speculative check) 
          a scheduling barrier for memory references.  */
@@ -2758,6 +2842,8 @@ deps_start_bb (struct deps *deps, rtx he
     {
       rtx insn = prev_nonnote_insn (head);
 
+      while (insn && DEBUG_INSN_P (insn))
+	insn = prev_nonnote_insn (insn);
       if (insn && CALL_P (insn))
 	deps->in_post_call_group_p = post_call_initial;
     }
@@ -2873,6 +2959,7 @@ init_deps (struct deps *deps)
   deps->last_function_call = 0;
   deps->sched_before_next_call = 0;
   deps->in_post_call_group_p = not_post_call;
+  deps->last_debug_insn = 0;
   deps->last_reg_pending_barrier = NOT_A_BARRIER;
   deps->readonly = 0;
 }
Index: gcc/sched-int.h
===================================================================
--- gcc/sched-int.h.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/sched-int.h	2009-06-05 05:07:56.000000000 -0300
@@ -181,13 +181,15 @@ extern bool sel_insn_is_speculation_chec
    FIRST is the index of the element with the highest priority; i.e. the
    last one in the ready list, since elements are ordered by ascending
    priority.
-   N_READY determines how many insns are on the ready list.  */
+   N_READY determines how many insns are on the ready list.
+   N_DEBUG determines how many debug insns are on the ready list.  */
 struct ready_list
 {
   rtx *vec;
   int veclen;
   int first;
   int n_ready;
+  int n_debug;
 };
 
 extern char *ready_try;
@@ -509,6 +511,9 @@ struct deps
      the call.  */
   enum post_call_group in_post_call_group_p;
 
+  /* The last debug insn we've seen.  */
+  rtx last_debug_insn;
+
   /* The maximum register number for the following arrays.  Before reload
      this is max_reg_num; after reload it is FIRST_PSEUDO_REGISTER.  */
   int max_reg;
@@ -796,6 +801,18 @@ extern VEC(haifa_deps_insn_data_def, hea
 #define IS_SPECULATION_BRANCHY_CHECK_P(INSN) \
   (RECOVERY_BLOCK (INSN) != NULL && RECOVERY_BLOCK (INSN) != EXIT_BLOCK_PTR)
 
+/* The unchanging bit tracks whether a debug insn is to be handled
+   like an insn (i.e., schedule it) or like a note (e.g., it is next
+   to a basic block boundary.  */
+#define DEBUG_INSN_SCHED_P(insn) \
+  (RTL_FLAG_CHECK1("DEBUG_INSN_SCHED_P", (insn), DEBUG_INSN)->unchanging)
+
+/* Convenience predicates.  */
+#define SCHEDULE_DEBUG_INSN_P(insn) \
+  (DEBUG_INSN_P (insn) && DEBUG_INSN_SCHED_P (insn))
+#define BOUNDARY_DEBUG_INSN_P(insn) \
+  (DEBUG_INSN_P (insn) && !DEBUG_INSN_SCHED_P (insn))
+
 /* Dep status (aka ds_t) of the link encapsulates information, that is needed
    for speculative scheduling.  Namely, it is 4 integers in the range
    [0, MAX_DEP_WEAK] and 3 bits.
@@ -1338,7 +1355,8 @@ sd_iterator_cond (sd_iterator_def *it_pt
 
 	  it_ptr->linkp = &DEPS_LIST_FIRST (list);
 
-	  return sd_iterator_cond (it_ptr, dep_ptr);
+	  if (list)
+	    return sd_iterator_cond (it_ptr, dep_ptr);
 	}
 
       *dep_ptr = NULL;
Index: gcc/sched-rgn.c
===================================================================
--- gcc/sched-rgn.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/sched-rgn.c	2009-06-05 05:07:56.000000000 -0300
@@ -530,7 +530,20 @@ find_single_block_region (bool ebbs_p)
 static int
 rgn_estimate_number_of_insns (basic_block bb)
 {
-  return INSN_LUID (BB_END (bb)) - INSN_LUID (BB_HEAD (bb));
+  int count;
+
+  count = INSN_LUID (BB_END (bb)) - INSN_LUID (BB_HEAD (bb));
+
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      rtx insn;
+
+      FOR_BB_INSNS (bb, insn)
+	if (DEBUG_INSN_P (insn))
+	  count--;
+    }
+
+  return count;
 }
 
 /* Update number of blocks and the estimate for number of insns
@@ -2129,7 +2142,7 @@ init_ready_list (void)
 	src_head = head;
 
 	for (insn = src_head; insn != src_next_tail; insn = NEXT_INSN (insn))
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !BOUNDARY_DEBUG_INSN_P (insn))
 	    try_ready (insn);
       }
 }
@@ -2424,6 +2437,9 @@ add_branch_dependences (rtx head, rtx ta
      are not moved before reload because we can wind up with register
      allocation failures.  */
 
+  while (tail != head && DEBUG_INSN_P (tail))
+    tail = PREV_INSN (tail);
+
   insn = tail;
   last = 0;
   while (CALL_P (insn)
@@ -2458,7 +2474,9 @@ add_branch_dependences (rtx head, rtx ta
       if (insn == head)
 	break;
 
-      insn = PREV_INSN (insn);
+      do
+	insn = PREV_INSN (insn);
+      while (insn != head && DEBUG_INSN_P (insn));
     }
 
   /* Make sure these insns are scheduled last in their block.  */
@@ -2468,7 +2486,8 @@ add_branch_dependences (rtx head, rtx ta
       {
 	insn = prev_nonnote_insn (insn);
 
-	if (TEST_BIT (insn_referenced, INSN_LUID (insn)))
+	if (TEST_BIT (insn_referenced, INSN_LUID (insn))
+	    || DEBUG_INSN_P (insn))
 	  continue;
 
 	if (! sched_insns_conditions_mutex_p (last, insn))
@@ -2705,6 +2724,9 @@ free_block_dependencies (int bb)
 
   get_ebb_head_tail (EBB_FIRST_BB (bb), EBB_LAST_BB (bb), &head, &tail);
 
+  if (no_real_insns_p (head, tail))
+    return;
+
   sched_free_deps (head, tail, true);
 }
 
@@ -2862,6 +2884,9 @@ compute_priorities (void) 
       gcc_assert (EBB_FIRST_BB (bb) == EBB_LAST_BB (bb));
       get_ebb_head_tail (EBB_FIRST_BB (bb), EBB_LAST_BB (bb), &head, &tail);
 
+      if (no_real_insns_p (head, tail))
+	continue;
+
       rgn_n_insns += set_priorities (head, tail);
     }
   current_sched_info->sched_max_insns_priority++;
Index: gcc/sched-vis.c
===================================================================
--- gcc/sched-vis.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/sched-vis.c	2009-06-05 05:07:56.000000000 -0300
@@ -556,6 +556,10 @@ print_pattern (char *buf, const_rtx x, i
       print_value (t1, XEXP (x, 0), verbose);
       sprintf (buf, "use %s", t1);
       break;
+    case VAR_LOCATION:
+      print_value (t1, PAT_VAR_LOCATION_LOC (x), verbose);
+      sprintf (buf, "loc %s", t1);
+      break;
     case COND_EXEC:
       if (GET_CODE (COND_EXEC_TEST (x)) == NE
 	  && XEXP (COND_EXEC_TEST (x), 1) == const0_rtx)
@@ -658,6 +662,34 @@ print_insn (char *buf, const_rtx x, int 
 #endif
 	sprintf (buf, " %4d %s", INSN_UID (x), t);
       break;
+
+    case DEBUG_INSN:
+      {
+	const char *name = "?";
+
+	if (DECL_P (INSN_VAR_LOCATION_DECL (insn)))
+	  {
+	    tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (insn));
+	    if (id)
+	      name = IDENTIFIER_POINTER (id);
+	    else
+	      {
+		char idbuf[32];
+		sprintf (idbuf, "D.%i",
+			 DECL_UID (INSN_VAR_LOCATION_DECL (insn)));
+		name = idbuf;
+	      }
+	  }
+	if (VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
+	  sprintf (buf, " %4d: debug %s optimized away", INSN_UID (insn), name);
+	else
+	  {
+	    print_pattern (t, INSN_VAR_LOCATION_LOC (insn), verbose);
+	    sprintf (buf, " %4d: debug %s => %s", INSN_UID (insn), name, t);
+	  }
+      }
+      break;
+
     case JUMP_INSN:
       print_pattern (t, PATTERN (x), verbose);
 #ifdef INSN_SCHEDULING
-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]