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]

-fvar-tracking-assignments initial patch set


On Oct  1, 2007, "Richard Guenther" <richard.guenther@gmail.com> wrote:

>> I can send you the patches in private if you'd like to get your hands
>> dirty right away, just let me know ;-)

> No need to hurry, I'll happily wait for the patches to arrive on the branch.

I've just completed checking in the patches I had handy.

I've made some major changes just before the check in (DEBUG_INSNs
used to be plain INSNs before, and flag_var_tracking_assignments
didn't exist), so there's a chance that bootstrap-debug doesn't pass
ATM.  I'm looking into it, but I'm going to be away tomorrow.

Feel free to check things into the branch, but if you do, please post
the patch along with the check in revision number, such that we can
easily cherry-pick changes into mainline.

Here are the revision numbers and the patch names I've just checked
in in var-tracking-assignments-branch.

#128935: gcc-debug-unused-scope-block.patch -p0
#128936: gcc-debug-coalesce-all.patch -p0
#128939: gcc-debug-coalesce-inline-fallout.patch -p0
#128940: gcc-gcse-skip-notes.patch -p0
#128941: gcc-ifcvt-bad-noce-else-op.patch -p0
#128942: gcc-debug-keep-inline-decls.patch -p0
#128943: gcc-debug-note-after-call.patch -p0
#128944: gcc-debug-assignments-flag.patch -p0
#128945: gcc-debug-assignments-tree.patch -p0
#128946: gcc-debug-assignments-rtl.patch -p0

for gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* tree-ssa-live.c (remove_unused_scope_block_p): Don't change
	generated code depending on -g.  Reverts part of 2007-07-26's
	patch.
	
Index: gcc/tree-ssa-live.c
===================================================================
--- gcc/tree-ssa-live.c.orig	2007-09-05 04:40:01.000000000 -0300
+++ gcc/tree-ssa-live.c	2007-09-05 04:49:10.000000000 -0300
@@ -468,39 +468,10 @@ mark_scope_block_unused (tree scope)
 static bool
 remove_unused_scope_block_p (tree scope)
 {
-  tree *t, *next;
+  tree *t;
   bool unused = !TREE_USED (scope);
-  var_ann_t ann;
   int nsubblocks = 0;
 
-  for (t = &BLOCK_VARS (scope); *t; t = next)
-    {
-      next = &TREE_CHAIN (*t);
-
-      /* Debug info of nested function refers to the block of the
-	 function.  */
-      if (TREE_CODE (*t) == FUNCTION_DECL)
-	unused = false;
-
-      /* When we are outputting debug info, we usually want to output
-	 info about optimized-out variables in the scope blocks.
-	 Exception are the scope blocks not containing any instructions
-	 at all so user can't get into the scopes at first place.  */
-      else if ((ann = var_ann (*t)) != NULL
-		&& ann->used)
-	unused = false;
-
-      /* When we are not doing full debug info, we however can keep around
-	 only the used variables for cfgexpand's memory packing saving quite
-	 a lot of memory.  */
-      else if (debug_info_level != DINFO_LEVEL_NORMAL
-	       && debug_info_level != DINFO_LEVEL_VERBOSE)
-	{
-	  *t = TREE_CHAIN (*t);
-	  next = t;
-	}
-    }
-
   for (t = &BLOCK_SUBBLOCKS (scope); *t ;)
     if (remove_unused_scope_block_p (*t))
       {
@@ -533,12 +504,10 @@ remove_unused_scope_block_p (tree scope)
    /* When there is only one subblock, see if it is just wrapper we can
       ignore.  Wrappers are not declaring any variables and not changing
       abstract origin.  */
-   else if (nsubblocks == 1
+   else if (nsubblocks <= 1
 	    && (BLOCK_VARS (scope)
-		|| ((debug_info_level == DINFO_LEVEL_NORMAL
-		     || debug_info_level == DINFO_LEVEL_VERBOSE)
-		    && ((BLOCK_ABSTRACT_ORIGIN (scope)
-			!= BLOCK_ABSTRACT_ORIGIN (BLOCK_SUPERCONTEXT (scope)))))))
+		|| (BLOCK_ABSTRACT_ORIGIN (scope)
+		    != BLOCK_ABSTRACT_ORIGIN (BLOCK_SUPERCONTEXT (scope)))))
      unused = false;
    return unused;
 }
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* tree-ssa-copyrename.c (copy_rename_partition_coalesce):
	Permit coalescing of user variables.

Index: gcc/tree-ssa-copyrename.c
===================================================================
--- gcc/tree-ssa-copyrename.c.orig	2007-08-02 06:03:44.000000000 -0300
+++ gcc/tree-ssa-copyrename.c	2007-08-02 16:09:29.000000000 -0300
@@ -190,22 +190,6 @@ copy_rename_partition_coalesce (var_map 
   ign1 = TREE_CODE (root1) == VAR_DECL && DECL_IGNORED_P (root1);
   ign2 = TREE_CODE (root2) == VAR_DECL && DECL_IGNORED_P (root2);
 
-  /* Never attempt to coalesce 2 user variables unless one is an inline 
-     variable.  */
-  if (!ign1 && !ign2)
-    {
-      if (DECL_FROM_INLINE (root2))
-        ign2 = true;
-      else if (DECL_FROM_INLINE (root1))
-	ign1 = true;
-      else 
-	{
-	  if (debug)
-	    fprintf (debug, " : 2 different USER vars. No coalesce.\n");
-	  return false;
-	}
-    }
-
   /* Don't coalesce if there are two different memory tags.  */
   if (ann1->symbol_mem_tag
       && ann2->symbol_mem_tag
for gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	PR tree-optimization/33572
	* tree-cfg.c (verify_stmts): Check for missing PHI defs.
	* tree-inline.c (update_ssa_across_eh_edges): Renamed to...
	(update_ssa_across_abnormal_edges): ... this.  Set slots in the
	return PHI node.
	(copy_edges_for_bb): Handle nonlocal label edges.
	(make_nonlocal_label_edges): Deleted.
	(optimize_inline_calls): Don't call it.

Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c.orig	2007-09-28 00:03:12.000000000 -0300
+++ gcc/tree-inline.c	2007-09-28 00:03:16.000000000 -0300
@@ -1018,7 +1018,8 @@ copy_bb (copy_body_data *id, basic_block
    we might want to change way build CFG pre-inlining to include
    all the possible edges then.  */
 static void
-update_ssa_across_eh_edges (basic_block bb)
+update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
+				  bool can_throw, bool nonlocal_goto)
 {
   edge e;
   edge_iterator ei;
@@ -1029,13 +1030,35 @@ update_ssa_across_eh_edges (basic_block 
       {
 	tree phi;
 
-	gcc_assert (e->flags & EDGE_EH);
+	gcc_assert (e->flags & EDGE_ABNORMAL);
+	if (!nonlocal_goto)
+	  gcc_assert (e->flags & EDGE_EH);
+	if (!can_throw)
+	  gcc_assert (!(e->flags & EDGE_EH));
 	for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
 	  {
+	    edge re;
+
+	    /* There shouldn't be any PHI nodes in the ENTRY_BLOCK.  */
+	    gcc_assert (!e->dest->aux);
+
 	    gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
 			(PHI_RESULT (phi)));
-	    mark_sym_for_renaming
-	      (SSA_NAME_VAR (PHI_RESULT (phi)));
+
+	    if (!is_gimple_reg (PHI_RESULT (phi)))
+	      {
+		mark_sym_for_renaming
+		  (SSA_NAME_VAR (PHI_RESULT (phi)));
+		continue;
+	      }
+
+	    re = find_edge (ret_bb, e->dest);
+	    gcc_assert (re);
+	    gcc_assert ((re->flags & (EDGE_EH | EDGE_ABNORMAL))
+			== (e->flags & (EDGE_EH | EDGE_ABNORMAL)));
+
+	    SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e),
+		     USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, re)));
 	  }
       }
 }
@@ -1044,7 +1067,7 @@ update_ssa_across_eh_edges (basic_block 
    accordingly.  Edges will be taken care of later.  Assume aux
    pointers to point to the copies of each BB.  */
 static void
-copy_edges_for_bb (basic_block bb, int count_scale)
+copy_edges_for_bb (basic_block bb, int count_scale, basic_block ret_bb)
 {
   basic_block new_bb = (basic_block) bb->aux;
   edge_iterator ei;
@@ -1076,6 +1099,7 @@ copy_edges_for_bb (basic_block bb, int c
   for (bsi = bsi_start (new_bb); !bsi_end_p (bsi);)
     {
       tree copy_stmt;
+      bool can_throw, nonlocal_goto;
 
       copy_stmt = bsi_stmt (bsi);
       update_stmt (copy_stmt);
@@ -1096,7 +1120,10 @@ copy_edges_for_bb (basic_block bb, int c
          into a COMPONENT_REF which doesn't.  If the copy
          can throw, the original could also throw.  */
 
-      if (tree_can_throw_internal (copy_stmt))
+      can_throw = tree_can_throw_internal (copy_stmt);
+      nonlocal_goto = tree_can_make_abnormal_goto (copy_stmt);
+
+      if (can_throw || nonlocal_goto)
 	{
 	  if (!bsi_end_p (bsi))
 	    /* Note that bb's predecessor edges aren't necessarily
@@ -1108,12 +1135,18 @@ copy_edges_for_bb (basic_block bb, int c
 	      new_bb->aux = e->src->aux;
 	      bsi = bsi_start (new_bb);
 	    }
+	}
 
-           make_eh_edges (copy_stmt);
+      if (can_throw)
+	make_eh_edges (copy_stmt);
 
-	   if (gimple_in_ssa_p (cfun))
-	     update_ssa_across_eh_edges (bb_for_stmt (copy_stmt));
-	}
+      if (nonlocal_goto)
+	make_abnormal_goto_edges (bb_for_stmt (copy_stmt), true);
+
+      if ((can_throw || nonlocal_goto)
+	  && gimple_in_ssa_p (cfun))
+	update_ssa_across_abnormal_edges (bb_for_stmt (copy_stmt), ret_bb,
+					  can_throw, nonlocal_goto);
     }
 }
 
@@ -1285,7 +1318,7 @@ copy_cfg_body (copy_body_data * id, gcov
   last = last_basic_block;
   /* Now that we've duplicated the blocks, duplicate their edges.  */
   FOR_ALL_BB_FN (bb, cfun_to_copy)
-    copy_edges_for_bb (bb, count_scale);
+    copy_edges_for_bb (bb, count_scale, exit_block_map);
   if (gimple_in_ssa_p (cfun))
     FOR_ALL_BB_FN (bb, cfun_to_copy)
       copy_phis_for_bb (bb, id);
@@ -2803,60 +2836,6 @@ has_abnormal_outgoing_edge_p (basic_bloc
   return false;
 }
 
-/* When a block from the inlined function contains a call with side-effects
-   in the middle gets inlined in a function with non-locals labels, the call
-   becomes a potential non-local goto so we need to add appropriate edge.  */
-
-static void
-make_nonlocal_label_edges (void)
-{
-  block_stmt_iterator bsi;
-  basic_block bb;
-
-  FOR_EACH_BB (bb)
-    {
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-	{
-	  tree stmt = bsi_stmt (bsi);
-	  if (tree_can_make_abnormal_goto (stmt))
-	    {
-	      if (stmt == bsi_stmt (bsi_last (bb)))
-		{
-		  if (!has_abnormal_outgoing_edge_p (bb))
-		    make_abnormal_goto_edges (bb, true);
-		}
-	      else
-		{
-		  edge e = split_block (bb, stmt);
-		  bb = e->src;
-		  make_abnormal_goto_edges (bb, true);
-		}
-	      break;
-	    }
-
-	  /* Update PHIs on nonlocal goto receivers we (possibly)
-	     just created new edges into.  */
-	  if (TREE_CODE (stmt) == LABEL_EXPR
-	      && gimple_in_ssa_p (cfun))
-	    {
-	      tree target = LABEL_EXPR_LABEL (stmt);
-	      if (DECL_NONLOCAL (target))
-		{
-		  tree phi;
-
-		  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-		    {
-		      gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI
-				  (PHI_RESULT (phi)));
-		      mark_sym_for_renaming
-			(SSA_NAME_VAR (PHI_RESULT (phi)));
-		    }
-		}
-	    }
-	}
-    }
-}
-
 /* Expand calls to inline functions in the body of FN.  */
 
 unsigned int
@@ -2935,8 +2914,6 @@ optimize_inline_calls (tree fn)
   cgraph_node_remove_callees (id.dst_node);
 
   fold_cond_expr_cond ();
-  if (current_function_has_nonlocal_label)
-    make_nonlocal_label_edges ();
   /* It would be nice to check SSA/CFG/statement consistency here, but it is
      not possible yet - the IPA passes might make various functions to not
      throw and they don't care to proactively update local EH info.  This is
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c.orig	2007-09-28 00:03:12.000000000 -0300
+++ gcc/tree-cfg.c	2007-09-28 00:03:16.000000000 -0300
@@ -4258,11 +4258,18 @@ verify_stmts (void)
 	      tree t = PHI_ARG_DEF (phi, i);
 	      tree addr;
 
+	      if (!t)
+		{
+		  error ("missing PHI def");
+		  debug_generic_stmt (phi);
+		  err |= true;
+		  continue;
+		}
 	      /* Addressable variables do have SSA_NAMEs but they
 		 are not considered gimple values.  */
-	      if (TREE_CODE (t) != SSA_NAME
-		  && TREE_CODE (t) != FUNCTION_DECL
-		  && !is_gimple_val (t))
+	      else if (TREE_CODE (t) != SSA_NAME
+		       && TREE_CODE (t) != FUNCTION_DECL
+		       && !is_gimple_val (t))
 		{
 		  error ("PHI def is not a GIMPLE value");
 		  debug_generic_stmt (phi);
for gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* gcse.c (hash_scan_set): Insert set in insn before note at
	the end of basic block.

Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2007-08-23 08:26:43.000000000 -0300
+++ gcc/gcse.c	2007-08-23 08:26:48.000000000 -0300
@@ -1760,8 +1760,8 @@ hash_scan_set (rtx pat, rtx insn, struct
 		  modified.  Here we want to search from INSN+1 on, but
 		  oprs_available_p searches from INSN on.  */
 	       && (insn == BB_END (BLOCK_FOR_INSN (insn))
-		   || ((tmp = next_nonnote_insn (insn)) != NULL_RTX
-		       && oprs_available_p (pat, tmp))))
+		   || (tmp = next_nonnote_insn (insn)) == NULL_RTX
+		   || oprs_available_p (pat, tmp)))
 	insert_set_in_table (pat, insn, table);
     }
   /* In case of store we want to consider the memory value as available in
for gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* ifcvt.c (noce_process_if_block): Try to handle only the then
	block if the else block exists but isn't suitable.

Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c.orig	2007-09-08 20:07:17.000000000 -0300
+++ gcc/ifcvt.c	2007-09-08 20:07:22.000000000 -0300
@@ -2204,6 +2204,7 @@ noce_process_if_block (struct noce_if_in
 	  || !NONJUMP_INSN_P (insn_b)
 	  || (set_b = single_set (insn_b)) == NULL_RTX
 	  || ! rtx_equal_p (x, SET_DEST (set_b))
+	  || ! noce_operand_ok (SET_SRC (set_b))
 	  || reg_overlap_mentioned_p (x, SET_SRC (set_b))
 	  || modified_between_p (SET_SRC (set_b),
 				 PREV_INSN (if_info->cond_earliest), jump)
@@ -2249,6 +2250,7 @@ noce_process_if_block (struct noce_if_in
   if (! noce_operand_ok (a) || ! noce_operand_ok (b))
     return FALSE;
 
+ retry:
   /* Set up the info block for our subroutines.  */
   if_info->insn_a = insn_a;
   if_info->insn_b = insn_b;
@@ -2332,6 +2334,13 @@ noce_process_if_block (struct noce_if_in
 	goto success;
     }
 
+  if (!else_bb && set_b)
+    {
+      insn_b = set_b = NULL_RTX;
+      b = orig_x;
+      goto retry;
+    }
+
   return FALSE;
 
  success:
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* tree-inline.c (self_inlining_addr_expr): Delete.
	(setup_one_parameter): Drop fn argument.  Adjust callers.
	Don't short-circuit optimization of declarations.

Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c.orig	2007-10-01 17:18:07.000000000 -0300
+++ gcc/tree-inline.c	2007-10-01 17:19:03.000000000 -0300
@@ -1366,24 +1366,8 @@ copy_body (copy_body_data *id, gcov_type
   return body;
 }
 
-/* Return true if VALUE is an ADDR_EXPR of an automatic variable
-   defined in function FN, or of a data member thereof.  */
-
-static bool
-self_inlining_addr_expr (tree value, tree fn)
-{
-  tree var;
-
-  if (TREE_CODE (value) != ADDR_EXPR)
-    return false;
-
-  var = get_base_address (TREE_OPERAND (value, 0));
-
-  return var && auto_var_in_fn_p (var, fn);
-}
-
 static void
-setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
+setup_one_parameter (copy_body_data *id, tree p, tree value,
 		     basic_block bb, tree *vars)
 {
   tree init_stmt;
@@ -1398,33 +1382,6 @@ setup_one_parameter (copy_body_data *id,
       && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
     rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
 
-  /* If the parameter is never assigned to, has no SSA_NAMEs created,
-     we may not need to create a new variable here at all.  Instead, we may
-     be able to just use the argument value.  */
-  if (TREE_READONLY (p)
-      && !TREE_ADDRESSABLE (p)
-      && value && !TREE_SIDE_EFFECTS (value)
-      && !def)
-    {
-      /* We may produce non-gimple trees by adding NOPs or introduce
-	 invalid sharing when operand is not really constant.
-	 It is not big deal to prohibit constant propagation here as
-	 we will constant propagate in DOM1 pass anyway.  */
-      if (is_gimple_min_invariant (value)
-	  && useless_type_conversion_p (TREE_TYPE (p),
-						 TREE_TYPE (value))
-	  /* We have to be very careful about ADDR_EXPR.  Make sure
-	     the base variable isn't a local variable of the inlined
-	     function, e.g., when doing recursive inlining, direct or
-	     mutually-recursive or whatever, which is why we don't
-	     just test whether fn == current_function_decl.  */
-	  && ! self_inlining_addr_expr (value, fn))
-	{
-	  insert_decl_map (id, p, value);
-	  return;
-	}
-    }
-
   /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
      here since the type of this decl must be visible to the calling
      function.  */
@@ -1472,29 +1429,6 @@ setup_one_parameter (copy_body_data *id,
   if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
     TREE_READONLY (var) = 0;
 
-  /* If there is no setup required and we are in SSA, take the easy route
-     replacing all SSA names representing the function parameter by the
-     SSA name passed to function.
-
-     We need to construct map for the variable anyway as it might be used
-     in different SSA names when parameter is set in function.
-
-     FIXME: This usually kills the last connection in between inlined
-     function parameter and the actual value in debug info.  Can we do
-     better here?  If we just inserted the statement, copy propagation
-     would kill it anyway as it always did in older versions of GCC.
-
-     We might want to introduce a notion that single SSA_NAME might
-     represent multiple variables for purposes of debugging. */
-  if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
-      && (TREE_CODE (rhs) == SSA_NAME
-	  || is_gimple_min_invariant (rhs))
-      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
-    {
-      insert_decl_map (id, def, rhs);
-      return;
-    }
-
   /* Initialize this VAR_DECL from the equivalent argument.  Convert
      the argument to the proper type in case it was promoted.  */
   if (value)
@@ -1578,7 +1512,7 @@ initialize_inlined_parameters (copy_body
      equivalent VAR_DECL, appropriately initialized.  */
   for (p = parms, a = first_call_expr_arg (exp, &iter); p;
        a = next_call_expr_arg (&iter), p = TREE_CHAIN (p))
-    setup_one_parameter (id, p, a, fn, bb, &vars);
+    setup_one_parameter (id, p, a, bb, &vars);
 
   /* Initialize the static chain.  */
   p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
@@ -1588,7 +1522,7 @@ initialize_inlined_parameters (copy_body
       /* No static chain?  Seems like a bug in tree-nested.c.  */
       gcc_assert (static_chain);
 
-      setup_one_parameter (id, p, static_chain, fn, bb, &vars);
+      setup_one_parameter (id, p, static_chain, bb, &vars);
     }
 
   declare_inline_vars (id->block, vars);
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* cfgrtl.c (rtl_block_ends_with_call_p): Skip notes at the end.

Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c.orig	2007-09-17 15:31:48.000000000 -0300
+++ gcc/cfgrtl.c	2007-09-17 15:34:01.000000000 -0300
@@ -2702,7 +2702,8 @@ rtl_block_ends_with_call_p (basic_block 
 
   while (!CALL_P (insn)
 	 && insn != BB_HEAD (bb)
-	 && keep_with_call_p (insn))
+	 && (keep_with_call_p (insn)
+	     || NOTE_P (insn)))
     insn = PREV_INSN (insn);
   return (CALL_P (insn));
 }
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* common.opt (fvar-tracking-assignments): New.
	* doc/invoke.texi: Document it.
	* toplev.c (flag_var_tracking_assignments): New.
	(process_options): Choose its default.

Index: gcc/common.opt
===================================================================
--- gcc/common.opt.orig	2007-10-01 18:00:29.000000000 -0300
+++ gcc/common.opt	2007-10-01 18:23:14.000000000 -0300
@@ -1172,6 +1172,10 @@ fvar-tracking
 Common Report Var(flag_var_tracking) VarExists Optimization
 Perform variable tracking
 
+fvar-tracking-assignments
+Common Report Var(flag_var_tracking_assignments) VarExists Optimization
+Perform variable tracking by annotating assignments
+
 fvar-tracking-uninit
 Common Report Var(flag_var_tracking_uninit) Optimization
 Perform variable tracking and also tag variables that are uninitialized
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi.orig	2007-10-01 18:00:28.000000000 -0300
+++ gcc/doc/invoke.texi	2007-10-01 18:17:39.000000000 -0300
@@ -302,7 +302,7 @@ Objective-C and Objective-C++ Dialects}.
 -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol
 -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
 -ftest-coverage  -ftime-report -fvar-tracking @gol
--g  -g@var{level}  -gcoff -gdwarf-2 @gol
+-fvar-tracking-assigments -g  -g@var{level}  -gcoff -gdwarf-2 @gol
 -ggdb  -gstabs  -gstabs+  -gvms  -gxcoff  -gxcoff+ @gol
 -fdebug-prefix-map=@var{old}=@var{new} @gol
 -femit-struct-debug-baseonly -femit-struct-debug-reduced @gol
@@ -4927,6 +4927,14 @@ It is enabled by default when compiling 
 @option{-O}, @option{-O2}, ...), debugging information (@option{-g}) and
 the debug info format supports it.
 
+@item -fvar-tracking-assignments
+@opindex -fvar-tracking-assignments
+Annotate assignments to user variables early in the compilation and
+attempt to carry the annotations over throughout the compilation all the
+way to the end, in an attempt to improve debug information while
+optimizing.  It is silently disabled if debug information generation,
+optimization or var-tracking are disabled.
+
 @item -print-file-name=@var{library}
 @opindex print-file-name
 Print the full absolute name of the library file @var{library} that
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c.orig	2007-10-01 18:00:29.000000000 -0300
+++ gcc/toplev.c	2007-10-01 18:37:52.000000000 -0300
@@ -329,6 +329,12 @@ rtx stack_limit_rtx;
    to optimize, debug_info_level and debug_hooks in process_options ().  */
 int flag_var_tracking = AUTODETECT_VALUE;
 
+/* Nonzero if we should track variable assignments.  When
+   flag_var_tracking_assignments == AUTODETECT_VALUE it will be set
+   according to flag_var_tracking, optimize, debug_info_level and
+   debug_hooks in process_options ().  */
+int flag_var_tracking_assignments = AUTODETECT_VALUE;
+
 /* True if the user has tagged the function with the 'section'
    attribute.  */
 
@@ -1889,7 +1895,8 @@ process_options (void)
       || debug_hooks->var_location == do_nothing_debug_hooks.var_location)
     {
       if (flag_var_tracking == 1
-	  || flag_var_tracking_uninit == 1)
+	  || flag_var_tracking_uninit == 1
+	  || flag_var_tracking_assignments == 1)
         {
 	  if (debug_info_level < DINFO_LEVEL_NORMAL)
 	    warning (0, "variable tracking requested, but useless unless "
@@ -1900,6 +1907,7 @@ process_options (void)
 	}
       flag_var_tracking = 0;
       flag_var_tracking_uninit = 0;
+      flag_var_tracking_assignments = 0;
     }
 
   if (flag_rename_registers == AUTODETECT_VALUE)
@@ -1909,6 +1917,18 @@ process_options (void)
   if (flag_var_tracking == AUTODETECT_VALUE)
     flag_var_tracking = optimize >= 1;
 
+  if (flag_var_tracking_assignments == AUTODETECT_VALUE)
+    flag_var_tracking_assignments = flag_var_tracking && optimize;
+  else if (flag_var_tracking_assignments)
+    {
+      if (!optimize)
+	{
+	  warning (0, "variable tracking in assignments requested, "
+		   "but useless without optimization");
+	  flag_var_tracking_assignments = 0;
+	}
+    }
+
   if (flag_tree_cselim == AUTODETECT_VALUE)
 #ifdef HAVE_conditional_move
     flag_tree_cselim = 1;
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* tree-inline.c (processing_debug_stmt_p): New variable.
	(remap_decl): Register variables only while not processing debug
	statements.
	(copy_body_r): Enqueue debug statements for later processing.
	(copy_bb): Skip debug statements.
	(copy_edges_for_bb): Likewise.
	(copy_debug_stmt): New fn.
	(copy_debug_stmts): New fn.
	(copy_generic_body, copy_body): Call it.
	(setup_one_parameter): Insert debug notes for inlined parms.
	(estimated_num_insns_1): Handle debug stmts.
	(optimize_inline_calls): Initialize debug stmt queue.
	(tree_function_versioning): Likewise.
	* tree-into-ssa.c (mark_def_sites): Handle debug stmts.
	(var_debug_value_for_decl): New fn.
	(adjust_debug_stmts_for_var_def_move): New fn.
	(adjust_debug_stmts_for_move): New fn.
	(check_debug_predicate): New struct.
	(check_and_update_debug_stmt_1): New fn.
	(check_and_update_debug_stmt): New fn.
	(insert_phi_nodes_for): Introduce debug stmts for phi nodes.
	(rewrite_stmt): Likewise, for SSA defs.
	(mark_use_interesting): Handle debug stmts.
	(prepare_block_for_update): Likewise.
	* tree.c (build_var_debug_value_stat): New fn.
	(empty_body_p): Handle debug stmts.
	* tree.def (VAR_DEBUG_VALUE): New tree code.
	* tree.h (VAR_DEBUG_VALUE_SET_VAR): New macro.
	(VAR_DEBUG_VALUE_VAR): Likewise.
	(VAR_DEBUG_VALUE_VALUE): Likewise.
	(IS_DEBUG_STMT): Likewise.
	(MAY_HAVE_DEBUG_STMTS): Likewise.
	(VAR_DEBUG_VALUE_NOVALUE): Likewise.
	(build_var_debug_value_stat): Declare.
	(build_var_debug_value): New macro.
	(var_debug_value_for_decl): Declare.
	* tree-gimple.c (is_gimple_stmt): Handle debug stmts.
	* tree-ssa-operands.c (opf_debug_use): New flag.
	(get_expr_operands): Handle debug stmts.  Don't mark objects
	addressed in debug stmts as addressable.
	(parse_ssa_operands): Handle debug stmts.
	* tree-dump.c (dequeue_and_dump): Likewise.
	* tree-pretty-print.c (dump_generic_node): Likewise.
	* tree-ssa-dce (mark_stmt_if_obviously_necessary): Likewise.
	(necessary_p): New function.
	(eliminate_unnecessary_stmts): Handle debug stmts.
	* tree-ssa-propagate.c (get_rhs): Likewise.
	* tree-ssa.c (verify_ssa): Likewise.
	(execute_early_warn_uninitialized): Likewise.
	* tree-ssa-live.c (remove_unused_locals): Likewise.
	(set_var_live_on_entry): Likewise.
	* tree-ssa-dom.c (propagate_rhs_into_lhs): Likewise.
	* tree-flow-inline.h (has_zero_uses): Ignore uses in debug stmts.
	(has_single_use): Likewise.
	(single_imm_use): Likewise.
	(num_imm_uses): Likewise.
	(bsi_next_nondebug): New fn.
	(bsi_prev_nondebug): Likewise.
	(bsi_start_nondebug): Likewise.
	(bsi_last_nondebug): Likewise.
	* tree-ssa-phiopt.c (empty_block_p): Ignore debug stmts.
	* tree-ssa-sink.c (all_immediate_uses_same_place): Likewise.
	(nearest_common_dominator_of_uses): Check for debug stmts.
	(statement_sink_location): Handle debug stmts.
	* tree-ssa-threadedge.c
	(record_temporary_equivalences_from_stmts): Skip debug stmts.
	* tree-ssa-threadupdate.c (redirection_block_p): Ignore them.
	* tree-cfgcleanup.c (tree_forwarder_block_p): Likewise.
	* tree-outof-ssa.c (replace_use_variable): Don't clear.
	(analyze_edges_for_bb): Handle debug stmts.
	* tree-cfg.c (first_stmt): Skip debug stmts.
	(last_stmt): Likewise.
	(last_and_only_stmt): Likewise.
	(verify_expr): Verify debug value.
	(tree_block_ends_with_call_p): Skip debug stmts.
	* tree-flow.h (bsi_next_nondebug): Declare.
	(bsi_prev_nondebug): Likewise.
	(bsi_start_nondebug): Likewise.
	(bsi_last_nondebug): Likewise.
	(adjust_debug_stmts_for_move): Likewise.
	(adjust_debug_stmts_for_var_def_move): Likewise.
	(check_and_update_debug_stmt): Likewise.
	* tree-ssa-reassoc.c (linearize_expr): Adjust debug stmts.
	(linearize_expr_tree): Likewise.
	* tree-ssa-loop-ch.c (should_duplicate_loop_header_p): Skip debug
	stmts.
	* tree-ssa-ter.c (find_replaceable_in_bb): Likewise.
	* tree-ssa-loop-ivopts.c (find_interesting_uses_stmt): Likewise.
	(remove_unused_ivs): Adjust debug stmts.
	* tree-ssa-loop-im.c (rewrite_bittest): Likewise.
	(move_computations_stmt): Likewise.
	* tree-ssanames.c (release_ssa_name): Likewise.
	* tree-ssa-alias.c (find_used_portions): Handle debug exprs.
	* tree-ssa-structalias.c (compute_points_to_sets): Ignore debug
	stmts.
	* tree-tailcall.c (find_tail_calls): Handle debug stmts.
	* tree-vrp.c (find_assert_locations): Likewise.
	* tree-ssa-coalesce.c (build_ssa_conflict_graph): Likewise.
	(create_outofssa_var_map): Likewise.
	* tree-ssa-forwprop.c (forward_propagate_addr_expr): Handle debug
	stmts.
	* tree-ssa-pre.c (compute_avail): Skip debug stmts.
	* tree-ssa-loop-manip.c (find_uses_to_rename_stmt): Likewise.
	(check_loop_closed_ssa_stmt): Likewise.
	* tree-inline.h (copy_body_data): Add debug_stmts queue.
	* ipa-pure-const.c (scan_function): Skip debug stmts.
	* ipa-reference.c (scan_for_static_refs): Likewise.
	* ipa-type-escape.c (scan_for_refs): Likewise.
	* tree-stdarg.c (execute_optimize_stdarg): Likewise.

Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-inline.c	2007-10-01 22:41:35.000000000 -0300
@@ -201,6 +201,8 @@ remap_ssa_name (tree name, copy_body_dat
   return new;
 }
 
+bool processing_debug_stmt_p = false;
+
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 tree
@@ -262,7 +264,8 @@ remap_decl (tree decl, copy_body_data *i
 	      if (TREE_CODE (map) == SSA_NAME)
 	        set_default_def (t, map);
 	    }
-	  add_referenced_var (t);
+	  if (!processing_debug_stmt_p)
+	    add_referenced_var (t);
 	}
       return t;
     }
@@ -699,6 +702,13 @@ copy_body_r (tree *tp, int *walk_subtree
 	      return NULL;
 	    }
 	}
+      else if (IS_DEBUG_STMT (*tp))
+	{
+	  *tp = copy_node (*tp);
+	  VARRAY_PUSH_TREE (id->debug_stmts, *tp);
+	  *walk_subtrees = 0;
+	  goto shallow_stmt_copy;
+	}
 
       /* Here is the "usual case".  Copy this tree node, and then
 	 tweak some special cases.  */
@@ -714,6 +724,7 @@ copy_body_r (tree *tp, int *walk_subtree
 	 of function call.  */
       if (EXPR_P (*tp) || GIMPLE_STMT_P (*tp))
 	{
+	shallow_stmt_copy:
 	  new_block = id->block;
 	  if (TREE_BLOCK (*tp))
 	    {
@@ -817,6 +828,13 @@ copy_bb (copy_body_data *id, basic_block
 	    {
 	      tree *stmtp = bsi_stmt_ptr (copy_bsi);
 	      tree stmt = *stmtp;
+
+	      if (IS_DEBUG_STMT (stmt))
+		{
+		  bsi_next (&copy_bsi);
+		  continue;
+		}
+
 	      call = get_call_expr_in (stmt);
 
 	      if (call && CALL_EXPR_VA_ARG_PACK (call) && id->call_expr)
@@ -1102,9 +1120,12 @@ copy_edges_for_bb (basic_block bb, int c
       bool can_throw, nonlocal_goto;
 
       copy_stmt = bsi_stmt (bsi);
-      update_stmt (copy_stmt);
-      if (gimple_in_ssa_p (cfun))
-        mark_symbols_for_renaming (copy_stmt);
+      if (!IS_DEBUG_STMT (copy_stmt))
+	{
+	  update_stmt (copy_stmt);
+	  if (gimple_in_ssa_p (cfun))
+	    mark_symbols_for_renaming (copy_stmt);
+	}
       /* Do this before the possible split_block.  */
       bsi_next (&bsi);
 
@@ -1337,6 +1358,40 @@ copy_cfg_body (copy_body_data * id, gcov
   return new_fndecl;
 }
 
+static void
+copy_debug_stmt (tree stmt, copy_body_data *id)
+{
+  tree t;
+
+  processing_debug_stmt_p = true;
+
+  t = VAR_DEBUG_VALUE_VAR (stmt);
+  walk_tree (&t, copy_body_r, id, NULL);
+  VAR_DEBUG_VALUE_SET_VAR (stmt, t);
+
+  walk_tree (&VAR_DEBUG_VALUE_VALUE (stmt), copy_body_r, id, NULL);
+
+  processing_debug_stmt_p = false;
+
+  update_stmt (stmt);
+  if (gimple_in_ssa_p (cfun))
+    mark_symbols_for_renaming (stmt);
+}
+
+static void
+copy_debug_stmts (copy_body_data *id)
+{
+  size_t i, e;
+
+  if (!id->debug_stmts)
+    return;
+
+  for (i = 0, e = VARRAY_ACTIVE_SIZE (id->debug_stmts); i < e; i++)
+    copy_debug_stmt (VARRAY_TREE (id->debug_stmts, i), id);
+
+  VARRAY_POP_ALL (id->debug_stmts);
+}
+
 /* Make a copy of the body of FN so that it can be inserted inline in
    another function.  */
 
@@ -1348,6 +1403,7 @@ copy_generic_body (copy_body_data *id)
 
   body = DECL_SAVED_TREE (fndecl);
   walk_tree (&body, copy_body_r, id, NULL);
+  copy_debug_stmts (id);
 
   return body;
 }
@@ -1362,6 +1418,7 @@ copy_body (copy_body_data *id, gcov_type
   /* If this body has a CFG, walk CFG and copy.  */
   gcc_assert (ENTRY_BLOCK_PTR_FOR_FUNCTION (DECL_STRUCT_FUNCTION (fndecl)));
   body = copy_cfg_body (id, count, frequency, entry_block_map, exit_block_map);
+  copy_debug_stmts (id);
 
   return body;
 }
@@ -1486,8 +1543,18 @@ setup_one_parameter (copy_body_data *id,
       if (init_stmt)
         bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
       if (gimple_in_ssa_p (cfun))
-	for (;!bsi_end_p (bsi); bsi_next (&bsi))
-	  mark_symbols_for_renaming (bsi_stmt (bsi));
+	{
+	  if (MAY_HAVE_DEBUG_STMTS && var_debug_value_for_decl (var))
+	    {
+	      tree note = build_var_debug_value (var,
+						 is_gimple_reg (p)
+						 ? def : var);
+	      bsi_insert_after (&bsi, note, BSI_SAME_STMT);
+	    }
+
+	  for (;!bsi_end_p (bsi); bsi_next (&bsi))
+	    mark_symbols_for_renaming (bsi_stmt (bsi));
+	}
     }
 }
 
@@ -2093,8 +2160,9 @@ estimate_num_insns_1 (tree *tp, int *wal
       *walk_subtrees = 0;
       return NULL;
 
-      /* CHANGE_DYNAMIC_TYPE_EXPR explicitly expands to nothing.  */
+      /* These explicitly expand to nothing.  */
     case CHANGE_DYNAMIC_TYPE_EXPR:
+    case VAR_DEBUG_VALUE:
       *walk_subtrees = 0;
       return NULL;
 
@@ -2804,6 +2872,8 @@ optimize_inline_calls (tree fn)
   id.transform_return_to_modify = true;
   id.transform_lang_insert_block = false;
   id.statements_to_fold = pointer_set_create ();
+  if (MAY_HAVE_DEBUG_STMTS)
+    VARRAY_TREE_INIT (id.debug_stmts, 8, "debug_stmt");
 
   push_gimplify_context ();
 
@@ -3376,6 +3446,9 @@ tree_function_versioning (tree old_decl,
       SET_DECL_RTL (new_decl, NULL_RTX);
       id.statements_to_fold = pointer_set_create ();
     }
+
+  if (MAY_HAVE_DEBUG_STMTS)
+    VARRAY_TREE_INIT (id.debug_stmts, 8, "debug_stmt");
   
   id.decl_map = pointer_map_create ();
   id.src_fn = old_decl;
Index: gcc/tree-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-into-ssa.c	2007-10-01 22:41:35.000000000 -0300
@@ -742,6 +742,9 @@ mark_def_sites (struct dom_walk_data *wa
   REGISTER_DEFS_IN_THIS_STMT (stmt) = 0;
   REWRITE_THIS_STMT (stmt) = 0;
 
+  if (IS_DEBUG_STMT (stmt))
+    return;
+
   /* If a variable is used before being set, then the variable is live
      across a block boundary, so mark it live-on-entry to BB.  */
   FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
@@ -1104,6 +1107,183 @@ mark_phi_for_rewrite (basic_block bb, tr
   VEC_replace (tree_vec, phis_to_rewrite, idx, phis);
 }
 
+/* Decide whether to emit a VAR_DEBUG_VALUE annotation for VAR.  */
+
+bool
+var_debug_value_for_decl (tree var)
+{
+  if (TREE_CODE (var) != VAR_DECL
+      && TREE_CODE (var) != PARM_DECL)
+    return false;
+
+  if (DECL_IGNORED_P (var))
+    return false;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return false;
+
+  if (!is_gimple_reg (var))
+    return false;
+
+  return true;
+}
+
+/* Given a VAR whose definition STMT is to be moved to the iterator
+   position TOBSIP in the TOBB basic block, verify whether we're
+   moving it across any of the debug statements that use it, and
+   adjust them as needed.  If TOBB is NULL, then the definition is
+   understood as being removed, and TOBSIP is unused.  */
+void
+adjust_debug_stmts_for_var_def_move (tree var,
+				     basic_block tobb,
+				     const block_stmt_iterator *tobsip)
+{
+  imm_use_iterator imm_iter;
+  tree stmt;
+  use_operand_p use_p;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+    {
+      basic_block bb;
+      block_stmt_iterator si;
+
+      if (!IS_DEBUG_STMT (stmt))
+	continue;
+
+      if (tobb)
+	{
+	  bb = bb_for_stmt (stmt);
+
+	  if (bb != tobb)
+	    {
+	      if (dominated_by_p (CDI_DOMINATORS, bb, tobb))
+		continue;
+	    }
+	  else
+	    {
+	      si = *tobsip;
+
+	      if (bsi_end_p (si))
+		continue;
+
+	      do
+		{
+		  bsi_prev (&si);
+		  if (bsi_end_p (si))
+		    break;
+		}
+	      while (bsi_stmt (si) != stmt);
+
+	      if (bsi_end_p (si))
+		continue;
+	    }
+	}
+
+      FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+	SET_USE (use_p, unshare_expr (SSA_NAME_VALUE (var)));
+
+      update_stmt (stmt);
+    }
+}
+
+
+/* Given a STMT to be moved to the iterator position TOBSIP in the
+   TOBB basic block, verify whether we're moving it across any of the
+   debug statements that use it.  If TOBB is NULL, then the definition
+   is understood as being removed, and TOBSIP is unused.  */
+
+void
+adjust_debug_stmts_for_move (tree def, basic_block tobb,
+			     const block_stmt_iterator *tobsip)
+{
+  ssa_op_iter op_iter;
+  def_operand_p def_p;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  FOR_EACH_SSA_DEF_OPERAND (def_p, def, op_iter, SSA_OP_ALL_DEFS)
+    {
+      tree var = DEF_FROM_PTR (def_p);
+
+      if (TREE_CODE (var) != SSA_NAME)
+	continue;
+
+      adjust_debug_stmts_for_var_def_move (var, tobb, tobsip);
+    }
+}
+
+/* Wrapper struct for the function predicate passed to
+   check_and_update_debug_stmt_1 ().  */
+
+struct check_debug_predicate
+{
+  bool (*available_p)(tree);
+};
+
+/* Look for an SSA_NAME in the expression *TP whose definition was
+   removed, or is about to be removed, per the available_p predicate
+   given by the check_debug_predicate *DATA.  */
+
+static tree
+check_and_update_debug_stmt_1 (tree *tp, int *walk_subtrees,
+			       void *data)
+{
+  tree t = *tp;
+
+  if (EXPR_P (t))
+    return NULL_TREE;
+
+  *walk_subtrees = 0;
+
+  if (TREE_CODE (t) == SSA_NAME)
+    {
+      struct check_debug_predicate *p = (struct check_debug_predicate *)data;
+
+      if (SSA_NAME_IN_FREE_LIST (t))
+	return t;
+
+      if (!SSA_NAME_DEF_STMT (t))
+	return t;
+
+      if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (t))
+	  && TREE_CODE (SSA_NAME_VAR (t)) != PARM_DECL)
+	return t;
+
+      if (p->available_p && !p->available_p (t))
+	return t;
+    }
+
+  return NULL_TREE;
+}
+
+/* Look for any SSA_NAMEs in the VALUE of a VAR_DEBUG_VALUE statement
+   T that have become or are about to become unavailable.
+   AVAILABLE_P, if non-NULL, is used to determine whether the variable
+   is about to become unavailable.  */
+
+void
+check_and_update_debug_stmt (tree t, bool (*available_p)(tree))
+{
+  struct check_debug_predicate p;
+
+  gcc_assert (IS_DEBUG_STMT (t));
+
+  if (VAR_DEBUG_VALUE_VALUE (t) == VAR_DEBUG_VALUE_NOVALUE)
+    return;
+
+  p.available_p = available_p;
+  if (walk_tree (&VAR_DEBUG_VALUE_VALUE (t), check_and_update_debug_stmt_1,
+		 &p, NULL))
+    {
+      /* ??? Can we do better?  */
+      VAR_DEBUG_VALUE_VALUE (t) = VAR_DEBUG_VALUE_NOVALUE;
+      update_stmt (t);
+    }
+}
 
 /* Insert PHI nodes for variable VAR using the iterated dominance
    frontier given in PHI_INSERTION_POINTS.  If UPDATE_P is true, this
@@ -1173,6 +1353,12 @@ insert_phi_nodes_for (tree var, bitmap p
 	{
 	  tree sym = DECL_P (var) ? var : SSA_NAME_VAR (var);
 	  phi = create_phi_node (sym, bb);
+	  if (!update_p && var_debug_value_for_decl (sym))
+	    {
+	      tree note = build_var_debug_value (sym, PHI_RESULT (phi));
+	      block_stmt_iterator si = bsi_after_labels (bb);
+	      bsi_insert_before (&si, note, BSI_SAME_STMT);
+	    }
 	}
 
       /* Mark this PHI node as interesting for update_ssa.  */
@@ -1378,9 +1564,14 @@ rewrite_stmt (struct dom_walk_data *walk
   if (REGISTER_DEFS_IN_THIS_STMT (stmt))
     FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
       {
-	tree var = DEF_FROM_PTR (def_p);
+	tree var = DEF_FROM_PTR (def_p), name;
 	gcc_assert (DECL_P (var));
-	SET_DEF (def_p, make_ssa_name (var, stmt));
+	SET_DEF (def_p, name = make_ssa_name (var, stmt));
+	if (var_debug_value_for_decl (var))
+	  {
+	    tree note = build_var_debug_value (var, name);
+	    bsi_insert_after (&si, note, BSI_SAME_STMT);
+	  }
 	register_new_def (DEF_FROM_PTR (def_p), var);
       }
 }
@@ -2363,7 +2554,12 @@ mark_use_interesting (tree var, tree stm
   if (TREE_CODE (stmt) == PHI_NODE)
     mark_phi_for_rewrite (def_bb, stmt);
   else
-    REWRITE_THIS_STMT (stmt) = 1;
+    {
+      REWRITE_THIS_STMT (stmt) = 1;
+
+      if (IS_DEBUG_STMT (stmt))
+	return;
+    }
 
   /* If VAR has not been defined in BB, then it is live-on-entry
      to BB.  Note that we cannot just use the block holding VAR's
@@ -2440,6 +2636,9 @@ prepare_block_for_update (basic_block bb
       
       stmt = bsi_stmt (si);
 
+      if (IS_DEBUG_STMT (stmt))
+	continue;
+
       FOR_EACH_SSA_USE_OPERAND (use_p, stmt, i, SSA_OP_ALL_USES)
 	{
 	  tree use = USE_FROM_PTR (use_p);
Index: gcc/tree.c
===================================================================
--- gcc/tree.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree.c	2007-10-01 22:41:35.000000000 -0300
@@ -3160,6 +3160,21 @@ build_gimple_modify_stmt_stat (tree arg0
   return t;
 }
 
+/* Build a VAR_DEBUG_VALUE node.  This tree code doesn't have a
+   type, so we can't use build2 (a.k.a. build2_stat).  */
+
+tree
+build_var_debug_value_stat (tree arg0, tree arg1 MEM_STAT_DECL)
+{
+  tree t;
+
+  t = make_node_stat (VAR_DEBUG_VALUE PASS_MEM_STAT);
+  /* ?? We don't care about setting flags for tuples...  */
+  VAR_DEBUG_VALUE_SET_VAR (t, arg0);
+  VAR_DEBUG_VALUE_VALUE (t) = arg1;
+  return t;
+}
+
 tree
 build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
 	     tree arg2 MEM_STAT_DECL)
@@ -8647,7 +8662,7 @@ empty_body_p (tree stmt)
   tree_stmt_iterator i;
   tree body;
 
-  if (IS_EMPTY_STMT (stmt))
+  if (IS_EMPTY_STMT (stmt) || IS_DEBUG_STMT (stmt))
     return true;
   else if (TREE_CODE (stmt) == BIND_EXPR)
     body = BIND_EXPR_BODY (stmt);
Index: gcc/tree.def
===================================================================
--- gcc/tree.def.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree.def	2007-10-01 22:41:35.000000000 -0300
@@ -1110,6 +1110,10 @@ DEFTREECODE (VEC_RSHIFT_EXPR, "vec_rshif
 /* Assignment expression.  Operand 0 is the what to set; 1, the new value.  */
 DEFTREECODE (GIMPLE_MODIFY_STMT, "gimple_modify_stmt", tcc_gimple_stmt, 2)
 
+/* Debug annotation.  Operand 0 is a user variable; 1 is an expression
+   with its value, for purposes of debug information.  */
+DEFTREECODE (VAR_DEBUG_VALUE, "var_debug_value", tcc_gimple_stmt, 2)
+
 /* Widening vector multiplication.
    The two operands are vectors with N elements of size S. Multiplying the
    elements of the two vectors will result in N products of size 2*S.
Index: gcc/tree.h
===================================================================
--- gcc/tree.h.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree.h	2007-10-01 22:41:35.000000000 -0300
@@ -829,6 +829,32 @@ enum tree_node_structure_enum {
 				 __FILE__, __LINE__, __FUNCTION__);	\
     &__t->gstmt.operands[__i]; }))
 
+/* Set the variable set by the VAR_DEBUG_VALUE stmt.  */
+#define VAR_DEBUG_VALUE_SET_VAR(T, V) __extension__			\
+  ({const tree __t = VAR_DEBUG_VALUE_CHECK (T);				\
+    if (0 >= TREE_OPERAND_LENGTH (__t))					\
+      tree_operand_check_failed (0, __t,				\
+				 __FILE__, __LINE__, __FUNCTION__);	\
+    __t->gstmt.operands[0] = (V); })
+
+/* Rvalue for the variable set by the VAR_DEBUG_VALUE stmt.  */
+#define VAR_DEBUG_VALUE_VAR(T) __extension__				\
+  ({const tree __t = VAR_DEBUG_VALUE_CHECK (T);				\
+    tree __var;								\
+    if (0 >= TREE_OPERAND_LENGTH (__t))					\
+      tree_operand_check_failed (0, __t,				\
+				 __FILE__, __LINE__, __FUNCTION__);	\
+    __var = __t->gstmt.operands[0];					\
+    __var; })
+
+/* Lvalue for the value of the variable.  */
+#define VAR_DEBUG_VALUE_VALUE(T) __extension__				\
+(*({const tree __t = VAR_DEBUG_VALUE_CHECK (T);				\
+    if (1 >= TREE_OPERAND_LENGTH (__t))					\
+      tree_operand_check_failed (1, __t,				\
+				 __FILE__, __LINE__, __FUNCTION__);	\
+    &__t->gstmt.operands[1]; }))
+
 #define TREE_RTL_OPERAND_CHECK(T, CODE, I) __extension__		\
 (*(rtx *)								\
  ({__typeof (T) const __t = (T);					\
@@ -926,6 +952,9 @@ extern void omp_clause_range_check_faile
 #define TREE_OPERAND_CHECK(T, I)		((T)->exp.operands[I])
 #define TREE_OPERAND_CHECK_CODE(T, CODE, I)	((T)->exp.operands[I])
 #define GIMPLE_STMT_OPERAND_CHECK(T, I)		((T)->gstmt.operands[I])
+#define VAR_DEBUG_VALUE_SET_VAR(T, V)		((T)->gstmt.operands[0] = (V))
+#define VAR_DEBUG_VALUE_VAR(T)			((tree)(T)->gstmt.operands[0])
+#define VAR_DEBUG_VALUE_VALUE(T)		((T)->gstmt.operands[1])
 #define TREE_RTL_OPERAND_CHECK(T, CODE, I)  (*(rtx *) &((T)->exp.operands[I]))
 #define PHI_NODE_ELT_CHECK(T, i)	((T)->phi.a[i])
 #define OMP_CLAUSE_ELT_CHECK(T, i)	        ((T)->omp_clause.ops[i])
@@ -1572,6 +1601,12 @@ struct tree_constructor GTY(())
 				 && VOID_TYPE_P (TREE_TYPE (NODE)) \
 				 && integer_zerop (TREE_OPERAND (NODE, 0)))
 
+/* Nonzero if NODE is a debug statement (VAR_DEBUG_VALUE).  */
+#define IS_DEBUG_STMT(NODE)     (TREE_CODE (NODE) == VAR_DEBUG_VALUE)
+
+/* Nonzero if IS_DEBUG_STMT may possibly.  */
+#define MAY_HAVE_DEBUG_STMTS    (flag_var_tracking_assignments)
+
 /* In ordinary expression nodes.  */
 #define TREE_OPERAND_LENGTH(NODE) tree_operand_length (NODE)
 #define TREE_OPERAND(NODE, I) TREE_OPERAND_CHECK (NODE, I)
@@ -1589,6 +1624,10 @@ struct tree_constructor GTY(())
 #define GIMPLE_STMT_LOCUS(NODE) (GIMPLE_STMT_CHECK (NODE)->gstmt.locus)
 #define GIMPLE_STMT_BLOCK(NODE) (GIMPLE_STMT_CHECK (NODE)->gstmt.block)
 
+/* The second operand of a VAR_DEBUG_VALUE when the value was
+   optimized away.  */
+#define VAR_DEBUG_VALUE_NOVALUE NULL_TREE /* error_mark_node */
+
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
 
@@ -3950,6 +3989,10 @@ extern tree build_gimple_modify_stmt_sta
 #define build_gimple_modify_stmt(t1,t2) \
   build_gimple_modify_stmt_stat (t1,t2 MEM_STAT_INFO)
 
+extern tree build_var_debug_value_stat (tree, tree MEM_STAT_DECL);
+#define build_var_debug_value(t1,t2) \
+  build_var_debug_value_stat (t1,t2 MEM_STAT_INFO)
+
 extern tree build_int_cst (tree, HOST_WIDE_INT);
 extern tree build_int_cst_type (tree, HOST_WIDE_INT);
 extern tree build_int_cstu (tree, unsigned HOST_WIDE_INT);
@@ -5351,4 +5394,8 @@ more_const_call_expr_args_p (const const
   for ((arg) = first_const_call_expr_arg ((call), &(iter)); (arg);	\
        (arg) = next_const_call_expr_arg (&(iter)))
 
+/* Determines whether the given TREE is subject to debug tracking.  */
+
+bool var_debug_value_for_decl (tree);
+
 #endif  /* GCC_TREE_H  */
Index: gcc/tree-gimple.c
===================================================================
--- gcc/tree-gimple.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-gimple.c	2007-10-01 22:41:35.000000000 -0300
@@ -245,6 +245,7 @@ is_gimple_stmt (tree t)
 
     case CALL_EXPR:
     case GIMPLE_MODIFY_STMT:
+    case VAR_DEBUG_VALUE:
       /* These are valid regardless of their type.  */
       return true;
 
Index: gcc/tree-ssa-operands.c
===================================================================
--- gcc/tree-ssa-operands.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-operands.c	2007-10-01 22:41:35.000000000 -0300
@@ -126,6 +126,9 @@ static struct 
    clobbering sites like function calls or ASM_EXPRs.  */
 #define opf_implicit	(1 << 2)
 
+/* Operand is a use only for purposes of debug information.  */
+#define opf_debug_use   (1 << 3)
+
 /* Array for building all the def operands.  */
 static VEC(tree,heap) *build_defs;
 
@@ -2057,6 +2060,7 @@ get_expr_operands (tree stmt, tree *expr
   enum tree_code_class codeclass;
   tree expr = *expr_p;
   stmt_ann_t s_ann = stmt_ann (stmt);
+  int uflags = opf_use | (flags & opf_debug_use);
 
   if (expr == NULL)
     return;
@@ -2071,7 +2075,9 @@ get_expr_operands (tree stmt, tree *expr
 	 reference to it, but the fact that the statement takes its
 	 address will be of interest to some passes (e.g. alias
 	 resolution).  */
-      add_to_addressable_set (TREE_OPERAND (expr, 0), &s_ann->addresses_taken);
+      if (!(flags & opf_debug_use))
+	add_to_addressable_set (TREE_OPERAND (expr, 0),
+				&s_ann->addresses_taken);
 
       /* If the address is invariant, there may be no interesting
 	 variable references inside.  */
@@ -2190,13 +2196,13 @@ get_expr_operands (tree stmt, tree *expr
 	  {
 	    if (TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1)))
 	      s_ann->has_volatile_ops = true; 
-	    get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use);
+	    get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
 	  }
 	else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
 	  {
-            get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use);
-            get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use);
-            get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_use);
+            get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags);
+            get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
+            get_expr_operands (stmt, &TREE_OPERAND (expr, 3), uflags);
 	  }
 
 	return;
@@ -2205,7 +2211,7 @@ get_expr_operands (tree stmt, tree *expr
     case WITH_SIZE_EXPR:
       /* WITH_SIZE_EXPR is a pass-through reference to its first argument,
 	 and an rvalue reference to its second argument.  */
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags);
       get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags);
       return;
 
@@ -2215,15 +2221,21 @@ get_expr_operands (tree stmt, tree *expr
 
     case COND_EXPR:
     case VEC_COND_EXPR:
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_use);
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use);
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_use);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 0), uflags);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 1), uflags);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
       return;
 
     case GIMPLE_MODIFY_STMT:
       get_modify_stmt_operands (stmt, expr);
       return;
 
+    case VAR_DEBUG_VALUE:
+      if (VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE)
+	get_expr_operands (stmt, &VAR_DEBUG_VALUE_VALUE (stmt),
+			   opf_use | opf_debug_use);
+      return;
+
     case CONSTRUCTOR:
       {
 	/* General aggregate CONSTRUCTORs have been decomposed, but they
@@ -2234,7 +2246,7 @@ get_expr_operands (tree stmt, tree *expr
 	for (idx = 0;
 	     VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (expr), idx, ce);
 	     idx++)
-	  get_expr_operands (stmt, &ce->value, opf_use);
+	  get_expr_operands (stmt, &ce->value, uflags);
 
 	return;
       }
@@ -2269,7 +2281,7 @@ get_expr_operands (tree stmt, tree *expr
       }
 
     case CHANGE_DYNAMIC_TYPE_EXPR:
-      get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use);
+      get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), uflags);
       return;
 
     case OMP_FOR:
@@ -2375,6 +2387,12 @@ parse_ssa_operands (tree stmt)
       get_modify_stmt_operands (stmt, stmt);
       break;
 
+    case VAR_DEBUG_VALUE:
+      if (VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE)
+	get_expr_operands (stmt, &VAR_DEBUG_VALUE_VALUE (stmt),
+			   opf_use | opf_debug_use);
+      return;
+
     case COND_EXPR:
       get_expr_operands (stmt, &COND_EXPR_COND (stmt), opf_use);
       break;
Index: gcc/tree-dump.c
===================================================================
--- gcc/tree-dump.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-dump.c	2007-10-01 22:41:35.000000000 -0300
@@ -605,6 +605,11 @@ dequeue_and_dump (dump_info_p di)
       dump_child ("op 1", GIMPLE_STMT_OPERAND (t, 1));
       break;
 
+    case VAR_DEBUG_VALUE:
+      dump_child ("op 0", VAR_DEBUG_VALUE_VAR (t));
+      dump_child ("op 1", VAR_DEBUG_VALUE_VALUE (t));
+      break;
+
     case COMPONENT_REF:
       dump_child ("op 0", TREE_OPERAND (t, 0));
       dump_child ("op 1", TREE_OPERAND (t, 1));
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-pretty-print.c	2007-10-01 22:41:35.000000000 -0300
@@ -1101,6 +1101,19 @@ dump_generic_node (pretty_printer *buffe
 	  		 false);
       break;
 
+    case VAR_DEBUG_VALUE:
+      pp_string (buffer, "# DEBUG ");
+      dump_generic_node (buffer, VAR_DEBUG_VALUE_VAR (node), spc, flags, false);
+      if (VAR_DEBUG_VALUE_VALUE (node) == VAR_DEBUG_VALUE_NOVALUE)
+	pp_string (buffer, " optimized away");
+      else
+	{
+	  pp_string (buffer, " = ");
+	  dump_generic_node (buffer, VAR_DEBUG_VALUE_VALUE (node), spc, flags,
+			     false);
+	}
+      break;
+
     case TARGET_EXPR:
       pp_string (buffer, "TARGET_EXPR <");
       dump_generic_node (buffer, TARGET_EXPR_SLOT (node), spc, flags, false);
Index: gcc/tree-ssa-dce.c
===================================================================
--- gcc/tree-ssa-dce.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-dce.c	2007-10-01 22:41:35.000000000 -0300
@@ -317,6 +317,10 @@ mark_stmt_if_obviously_necessary (tree s
 	}
       break;
 
+    case VAR_DEBUG_VALUE:
+      mark_stmt_necessary (stmt, false);
+      return;
+
     case GOTO_EXPR:
       gcc_assert (!simple_goto_p (stmt));
       mark_stmt_necessary (stmt, true);
@@ -653,6 +657,15 @@ remove_dead_stmt (block_stmt_iterator *i
   release_defs (t); 
 }
 
+/* Predicate used by check_and_update_debug_stmt.  Return TRUE if the
+   T's definition is not about to be removed.  T is assumed to be an
+   SSA_NAME.  */
+
+static bool
+necessary_p (tree t)
+{
+  return NECESSARY (SSA_NAME_DEF_STMT (t));
+}
 
 /* Eliminate unnecessary statements. Any instruction not marked as necessary
    contributes nothing to the program, and can be deleted.  */
@@ -691,8 +704,15 @@ eliminate_unnecessary_stmts (void)
 	    }
 	  else
 	    {
-	      tree call = get_call_expr_in (t);
-	      if (call)
+	      tree call;
+
+	      if (TREE_CODE (t) == VAR_DEBUG_VALUE)
+		{
+		  if (something_changed
+		      && VAR_DEBUG_VALUE_VALUE (t) != VAR_DEBUG_VALUE_NOVALUE)
+		    check_and_update_debug_stmt (t, necessary_p);
+		}
+	      else if ((call = get_call_expr_in (t)))
 		{
 		  tree name;
 
Index: gcc/tree-ssa-propagate.c
===================================================================
--- gcc/tree-ssa-propagate.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-propagate.c	2007-10-01 22:41:35.000000000 -0300
@@ -557,6 +557,9 @@ get_rhs (tree stmt)
       else
 	return stmt;
 
+    case VAR_DEBUG_VALUE:
+      return VAR_DEBUG_VALUE_VALUE (stmt);
+
     case COND_EXPR:
       return COND_EXPR_COND (stmt);
     case SWITCH_EXPR:
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa.c	2007-10-01 22:41:35.000000000 -0300
@@ -699,6 +699,9 @@ verify_ssa (bool check_modified_stmt)
 		  goto err;
 		}
 	    }
+	  else if (TREE_CODE (stmt) == VAR_DEBUG_VALUE
+		   && VAR_DEBUG_VALUE_VALUE (stmt) == VAR_DEBUG_VALUE_NOVALUE)
+	    continue;
 
 	  FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_ALL_VIRTUALS)
 	    {
@@ -1316,6 +1319,10 @@ execute_early_warn_uninitialized (void)
     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
       {
 	tree context = bsi_stmt (bsi);
+
+	if (TREE_CODE (context) == VAR_DEBUG_VALUE)
+	  continue;
+
 	walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var,
 		   context, NULL);
       }
Index: gcc/tree-ssa-live.c
===================================================================
--- gcc/tree-ssa-live.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-live.c	2007-10-01 22:41:35.000000000 -0300
@@ -545,7 +545,8 @@ remove_unused_locals (void)
 
       /* Walk the statements.  */
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-	mark_all_vars_used (bsi_stmt_ptr (bsi));
+	if (TREE_CODE (bsi_stmt (bsi)) != VAR_DEBUG_VALUE)
+	  mark_all_vars_used (bsi_stmt_ptr (bsi));
 
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
         {
@@ -772,6 +773,8 @@ set_var_live_on_entry (tree ssa_name, tr
 		add_block = e->src;
 	    }
 	}
+      else if (IS_DEBUG_STMT (use_stmt))
+	continue;
       else
         {
 	  /* If its not defined in this block, its live on entry.  */
Index: gcc/tree-ssa-dom.c
===================================================================
--- gcc/tree-ssa-dom.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-dom.c	2007-10-01 22:41:35.000000000 -0300
@@ -2233,6 +2233,8 @@ propagate_rhs_into_lhs (tree stmt, tree 
 	      discard_stmt_changes (&use_stmt);
 	      continue;
 	    }
+	  else if (IS_DEBUG_STMT (use_stmt))
+	    check_and_update_debug_stmt (use_stmt, NULL);
 
 	  /* From this point onward we are propagating into a 
 	     real statement.  Folding may (or may not) be possible,
Index: gcc/tree-flow-inline.h
===================================================================
--- gcc/tree-flow-inline.h.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-flow-inline.h	2007-10-01 22:41:35.000000000 -0300
@@ -524,18 +524,48 @@ next_readonly_imm_use (imm_use_iterator 
 static inline bool
 has_zero_uses (const_tree var)
 {
-  const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var));
+  const ssa_use_operand_t *ptr, *start;
+  bool ret;
+
+  ptr = &(SSA_NAME_IMM_USE_NODE (var));
   /* A single use means there is no items in the list.  */
-  return (ptr == ptr->next);
+  ret = (ptr == ptr->next);
+
+  if (ret || !MAY_HAVE_DEBUG_STMTS)
+    return ret;
+
+  start = ptr;
+  for (ptr = start->next; ptr != start; ptr = ptr->next)
+    if (!IS_DEBUG_STMT (ptr->stmt))
+      return false;
+  return true;
 }
 
 /* Return true if VAR has a single use.  */
 static inline bool
 has_single_use (const_tree var)
 {
-  const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var));
+  const ssa_use_operand_t *ptr, *start;
+  bool ret;
+
+  ptr = &(SSA_NAME_IMM_USE_NODE (var));
   /* A single use means there is one item in the list.  */
-  return (ptr != ptr->next && ptr == ptr->next->next);
+  ret = (ptr != ptr->next && ptr == ptr->next->next);
+
+  if (ret)
+    return !IS_DEBUG_STMT (ptr->next->stmt);
+  else if (!MAY_HAVE_DEBUG_STMTS)
+    return ret;
+
+  start = ptr;
+  for (ptr = start->next; ptr != start; ptr = ptr->next)
+    if (!IS_DEBUG_STMT (ptr->stmt))
+      {
+	if (ret)
+	  return false;
+	ret = true;
+      }
+  return ret;
 }
 
 
@@ -544,8 +574,35 @@ has_single_use (const_tree var)
 static inline bool
 single_imm_use (const_tree var, use_operand_p *use_p, tree *stmt)
 {
-  const ssa_use_operand_t *const ptr = &(SSA_NAME_IMM_USE_NODE (var));
-  if (ptr != ptr->next && ptr == ptr->next->next)
+  const ssa_use_operand_t *ptr;
+  bool ret;
+
+  ptr = &(SSA_NAME_IMM_USE_NODE (var));
+
+  ret = ptr != ptr->next && ptr == ptr->next->next;
+
+  if (ret)
+    ret = !IS_DEBUG_STMT (ptr->next->stmt);
+  else if (MAY_HAVE_DEBUG_STMTS)
+    {
+      const ssa_use_operand_t *start = ptr, *prev = ptr, *single_use_prev = 0;
+
+      for (ptr = start->next; ptr != start; prev = ptr, ptr = ptr->next)
+	if (!IS_DEBUG_STMT (ptr->stmt))
+	  {
+	    if (ret)
+	      {
+		ret = false;
+		break;
+	      }
+	    ret = true;
+	    single_use_prev = prev;
+	  }
+
+      ptr = single_use_prev;
+    }
+
+  if (ret)
     {
       *use_p = ptr->next;
       *stmt = ptr->next->stmt;
@@ -564,8 +621,13 @@ num_imm_uses (const_tree var)
   const ssa_use_operand_t *ptr;
   unsigned int num = 0;
 
-  for (ptr = start->next; ptr != start; ptr = ptr->next)
-     num++;
+  if (!MAY_HAVE_DEBUG_STMTS)
+    for (ptr = start->next; ptr != start; ptr = ptr->next)
+      num++;
+  else
+    for (ptr = start->next; ptr != start; ptr = ptr->next)
+      if (!IS_DEBUG_STMT (ptr->stmt))
+	num++;
 
   return num;
 }
@@ -817,6 +879,48 @@ bsi_stmt_ptr (block_stmt_iterator i)
   return tsi_stmt_ptr (i.tsi);
 }
 
+/* Modify block statement iterator I so that it is at the next
+   statement in the basic block.  */
+static inline void
+bsi_next_nondebug (block_stmt_iterator *i)
+{
+  do
+    bsi_next (i);
+  while (!bsi_end_p (*i) && IS_DEBUG_STMT (bsi_stmt (*i)));
+}
+
+/* Modify block statement iterator I so that it is at the previous
+   non-debug statement in the basic block.  */
+static inline void
+bsi_prev_nondebug (block_stmt_iterator *i)
+{
+  do
+    bsi_prev (i);
+  while (!bsi_end_p (*i) && IS_DEBUG_STMT (bsi_stmt (*i)));
+}
+
+static inline block_stmt_iterator
+bsi_start_nondebug (basic_block bb)
+{
+  block_stmt_iterator bsi = bsi_start (bb);
+
+  while (!bsi_end_p (bsi) && IS_DEBUG_STMT (bsi_stmt (bsi)))
+    bsi_next (&bsi);
+
+  return bsi;
+}
+
+static inline block_stmt_iterator
+bsi_last_nondebug (basic_block bb)
+{
+  block_stmt_iterator bsi = bsi_last (bb);
+
+  while (!bsi_end_p (bsi) && IS_DEBUG_STMT (bsi_stmt (bsi)))
+    bsi_prev (&bsi);
+
+  return bsi;
+}
+
 /* Returns the loop of the statement STMT.  */
 
 static inline struct loop *
Index: gcc/tree-ssa-phiopt.c
===================================================================
--- gcc/tree-ssa-phiopt.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-phiopt.c	2007-10-01 22:41:35.000000000 -0300
@@ -387,7 +387,8 @@ empty_block_p (basic_block bb)
   bsi = bsi_start (bb);
   while (!bsi_end_p (bsi)
 	  && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR
-	      || IS_EMPTY_STMT (bsi_stmt (bsi))))
+	      || IS_EMPTY_STMT (bsi_stmt (bsi))
+	      || IS_DEBUG_STMT (bsi_stmt (bsi))))
     bsi_next (&bsi);
 
   if (!bsi_end_p (bsi))
Index: gcc/tree-ssa-sink.c
===================================================================
--- gcc/tree-ssa-sink.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-sink.c	2007-10-01 22:41:35.000000000 -0300
@@ -119,6 +119,8 @@ all_immediate_uses_same_place (tree stmt
     {
       FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
         {
+	  if (IS_DEBUG_STMT (USE_STMT (use_p)))
+	    continue;
 	  if (firstuse == NULL_TREE)
 	    firstuse = USE_STMT (use_p);
 	  else
@@ -213,7 +215,7 @@ is_hidden_global_store (tree stmt)
 /* Find the nearest common dominator of all of the immediate uses in IMM.  */
 
 static basic_block
-nearest_common_dominator_of_uses (tree stmt)
+nearest_common_dominator_of_uses (tree stmt, bool *debug_stmts)
 {  
   bitmap blocks = BITMAP_ALLOC (NULL);
   basic_block commondom;
@@ -238,6 +240,11 @@ nearest_common_dominator_of_uses (tree s
 
 	      useblock = PHI_ARG_EDGE (usestmt, idx)->src;
 	    }
+	  else if (IS_DEBUG_STMT (usestmt))
+	    {
+	      *debug_stmts = true;
+	      continue;
+	    }
 	  else
 	    {
 	      useblock = bb_for_stmt (usestmt);
@@ -284,6 +291,9 @@ statement_sink_location (tree stmt, basi
     {
       FOR_EACH_IMM_USE_FAST (one_use, imm_iter, def)
 	{
+	  if (IS_DEBUG_STMT (USE_STMT (one_use)))
+	    continue;
+
 	  break;
 	}
       if (one_use != NULL_USE_OPERAND_P)
@@ -349,7 +359,9 @@ statement_sink_location (tree stmt, basi
      that is where insertion would have to take place.  */
   if (!all_immediate_uses_same_place (stmt))
     {
-      basic_block commondom = nearest_common_dominator_of_uses (stmt);
+      bool debug_stmts = false;
+      basic_block commondom = nearest_common_dominator_of_uses (stmt,
+								&debug_stmts);
      
       if (commondom == frombb)
 	return false;
@@ -378,8 +390,13 @@ statement_sink_location (tree stmt, basi
 	  fprintf (dump_file, "Common dominator of all uses is %d\n",
 		   commondom->index);
 	}
+
       *tobb = commondom;
       *tobsi = bsi_after_labels (commondom);
+
+      if (debug_stmts)
+	adjust_debug_stmts_for_move (stmt, *tobb, tobsi);
+
       return true;
     }
 
@@ -392,6 +409,9 @@ statement_sink_location (tree stmt, basi
 	return false;
       *tobb = sinkbb;
       *tobsi = bsi_for_stmt (use);
+
+      adjust_debug_stmts_for_move (stmt, *tobb, tobsi);
+
       return true;
     }
 
@@ -421,6 +441,8 @@ statement_sink_location (tree stmt, basi
   *tobb = sinkbb;
   *tobsi = bsi_after_labels (sinkbb);
 
+  adjust_debug_stmts_for_move (stmt, *tobb, tobsi);
+
   return true;
 }
 
Index: gcc/tree-ssa-threadedge.c
===================================================================
--- gcc/tree-ssa-threadedge.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-threadedge.c	2007-10-01 22:41:35.000000000 -0300
@@ -230,7 +230,8 @@ record_temporary_equivalences_from_stmts
       stmt = bsi_stmt (bsi);
 
       /* Ignore empty statements and labels.  */
-      if (IS_EMPTY_STMT (stmt) || TREE_CODE (stmt) == LABEL_EXPR)
+      if (IS_EMPTY_STMT (stmt) || IS_DEBUG_STMT (stmt)
+	  || TREE_CODE (stmt) == LABEL_EXPR)
 	continue;
 
       /* If the statement has volatile operands, then we assume we
Index: gcc/tree-ssa-threadupdate.c
===================================================================
--- gcc/tree-ssa-threadupdate.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-threadupdate.c	2007-10-01 22:41:35.000000000 -0300
@@ -469,7 +469,8 @@ redirection_block_p (basic_block bb)
   bsi = bsi_start (bb);
   while (!bsi_end_p (bsi)
           && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR
-              || IS_EMPTY_STMT (bsi_stmt (bsi))))
+              || IS_EMPTY_STMT (bsi_stmt (bsi))
+	      || IS_DEBUG_STMT (bsi_stmt (bsi))))
     bsi_next (&bsi);
 
   /* Check if this is an empty block.  */
Index: gcc/tree-cfgcleanup.c
===================================================================
--- gcc/tree-cfgcleanup.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-cfgcleanup.c	2007-10-01 22:41:35.000000000 -0300
@@ -270,6 +270,11 @@ tree_forwarder_block_p (basic_block bb, 
 	    return false;
 	  break;
 
+	  /* ??? For now, hope there's a corresponding debug
+	     assignment at the destination.  */
+	case VAR_DEBUG_VALUE:
+	  break;
+
 	default:
 	  return false;
 	}
Index: gcc/tree-outof-ssa.c
===================================================================
--- gcc/tree-outof-ssa.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-outof-ssa.c	2007-10-01 22:41:35.000000000 -0300
@@ -563,7 +563,7 @@ replace_use_variable (var_map map, use_o
 	  SET_USE (p, new_expr);
 
 	  /* Clear the stmt's RHS, or GC might bite us.  */
-	  GIMPLE_STMT_OPERAND (expr[version], 1) = NULL_TREE;
+	  /* GIMPLE_STMT_OPERAND (expr[version], 1) = NULL_TREE; */
 	  return true;
 	}
     }
@@ -918,11 +918,12 @@ analyze_edges_for_bb (basic_block bb)
 	      if (!bsi_end_p (bsi))
 	        {
 		  stmt = bsi_stmt (bsi);
-		  bsi_next (&bsi);
+		  bsi_next_nondebug (&bsi);
 		  gcc_assert (stmt != NULL_TREE);
 		  is_label = (TREE_CODE (stmt) == LABEL_EXPR);
 		  /* Punt if it has non-label stmts, or isn't local.  */
-		  if (!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0)) 
+		  if (((!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0)))
+		       && !IS_DEBUG_STMT (stmt))
 		      || !bsi_end_p (bsi))
 		    {
 		      bsi_commit_one_edge_insert (e, NULL);
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-cfg.c	2007-10-01 22:41:35.000000000 -0300
@@ -2591,7 +2591,13 @@ tree
 first_stmt (basic_block bb)
 {
   block_stmt_iterator i = bsi_start (bb);
-  return !bsi_end_p (i) ? bsi_stmt (i) : NULL_TREE;
+  tree stmt = NULL;
+  while (!bsi_end_p (i) && IS_DEBUG_STMT ((stmt = bsi_stmt (i))))
+    {
+      bsi_next (&i);
+      stmt = NULL;
+    }
+  return stmt;
 }
 
 /* Return the last statement in basic block BB.  */
@@ -2600,7 +2606,14 @@ tree
 last_stmt (basic_block bb)
 {
   block_stmt_iterator b = bsi_last (bb);
-  return !bsi_end_p (b) ? bsi_stmt (b) : NULL_TREE;
+  tree stmt = NULL;
+
+  while (!bsi_end_p (b) && IS_DEBUG_STMT ((stmt = bsi_stmt (b))))
+    {
+      bsi_prev (&b);
+      stmt = NULL;
+    }
+  return stmt;
 }
 
 /* Return the last statement of an otherwise empty block.  Return NULL
@@ -2610,14 +2623,15 @@ last_stmt (basic_block bb)
 tree
 last_and_only_stmt (basic_block bb)
 {
-  block_stmt_iterator i = bsi_last (bb);
+  block_stmt_iterator i = bsi_last_nondebug (bb);
   tree last, prev;
 
   if (bsi_end_p (i))
     return NULL_TREE;
 
   last = bsi_stmt (i);
-  bsi_prev (&i);
+  bsi_prev_nondebug (&i);
+
   if (bsi_end_p (i))
     return last;
 
@@ -3151,6 +3165,15 @@ verify_expr (tree *tp, int *walk_subtree
 	}
       break;
 
+    case VAR_DEBUG_VALUE:
+      check_and_update_debug_stmt (t, NULL);
+      /* Walking sub-trees could fail to verify ADDR_EXPRs referencing
+	 variables that became non-addressable due to optimization,
+	 and perhaps other reasons as well.  We could perform some
+	 more limited form of checking.  */
+      *walk_subtrees = 0;
+      break;
+
     case ADDR_EXPR:
       {
 	bool old_invariant;
@@ -6249,7 +6272,7 @@ debug_loop_ir (void)
 static bool
 tree_block_ends_with_call_p (basic_block bb)
 {
-  block_stmt_iterator bsi = bsi_last (bb);
+  block_stmt_iterator bsi = bsi_last_nondebug (bb);
   return get_call_expr_in (bsi_stmt (bsi)) != NULL;
 }
 
Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-flow.h	2007-10-01 22:41:35.000000000 -0300
@@ -633,6 +633,10 @@ static inline void bsi_next (block_stmt_
 static inline void bsi_prev (block_stmt_iterator *);
 static inline tree bsi_stmt (block_stmt_iterator);
 static inline tree * bsi_stmt_ptr (block_stmt_iterator);
+static inline void bsi_next_nondebug (block_stmt_iterator *);
+static inline void bsi_prev_nondebug (block_stmt_iterator *);
+static inline block_stmt_iterator bsi_start_nondebug (basic_block);
+static inline block_stmt_iterator bsi_last_nondebug (basic_block);
 
 extern void bsi_remove (block_stmt_iterator *, bool);
 extern void bsi_move_before (block_stmt_iterator *, block_stmt_iterator *);
@@ -890,6 +894,11 @@ void mark_sym_for_renaming (tree);
 void mark_set_for_renaming (bitmap);
 tree get_current_def (tree);
 void set_current_def (tree, tree);
+void adjust_debug_stmts_for_move (tree, basic_block,
+				  const block_stmt_iterator *);
+void adjust_debug_stmts_for_var_def_move (tree, basic_block,
+					  const block_stmt_iterator *);
+void check_and_update_debug_stmt (tree, bool (*)(tree));
 
 /* In tree-ssa-ccp.c  */
 bool fold_stmt (tree *);
Index: gcc/tree-ssa-reassoc.c
===================================================================
--- gcc/tree-ssa-reassoc.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-reassoc.c	2007-10-01 22:41:35.000000000 -0300
@@ -945,6 +945,7 @@ linearize_expr (tree stmt)
 
   bsinow = bsi_for_stmt (stmt);
   bsirhs = bsi_for_stmt (binrhs);
+  adjust_debug_stmts_for_move (binrhs, bb_for_stmt (stmt), &bsinow);
   bsi_move_before (&bsirhs, &bsinow);
 
   TREE_OPERAND (rhs, 1) = TREE_OPERAND (GIMPLE_STMT_OPERAND (binrhs, 1), 0);
@@ -1174,6 +1175,8 @@ linearize_expr_tree (VEC(operand_entry_t
 				      rhscode, loop));
   bsinow = bsi_for_stmt (stmt);
   bsilhs = bsi_for_stmt (SSA_NAME_DEF_STMT (binlhs));
+  adjust_debug_stmts_for_move (SSA_NAME_DEF_STMT (binlhs),
+			       bb_for_stmt (stmt), &bsinow);
   bsi_move_before (&bsilhs, &bsinow);
   linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs));
   add_to_ops_vec (ops, binrhs);
Index: gcc/tree-ssa-loop-ch.c
===================================================================
--- gcc/tree-ssa-loop-ch.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-loop-ch.c	2007-10-01 22:41:35.000000000 -0300
@@ -83,6 +83,9 @@ should_duplicate_loop_header_p (basic_bl
       if (TREE_CODE (last) == LABEL_EXPR)
 	continue;
 
+      if (IS_DEBUG_STMT (last))
+	continue;
+
       if (get_call_expr_in (last))
 	return false;
 
Index: gcc/tree-ssa-ter.c
===================================================================
--- gcc/tree-ssa-ter.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-ter.c	2007-10-01 22:41:35.000000000 -0300
@@ -562,6 +562,10 @@ find_replaceable_in_bb (temp_expr_table_
   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
     {
       stmt = bsi_stmt (bsi);
+
+      if (IS_DEBUG_STMT (stmt))
+	continue;
+
       ann = stmt_ann (stmt);
 
       stmt_replaceable = is_replaceable_p (stmt);
Index: gcc/tree-ssa-loop-ivopts.c
===================================================================
--- gcc/tree-ssa-loop-ivopts.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-loop-ivopts.c	2007-10-01 22:41:35.000000000 -0300
@@ -1648,6 +1648,9 @@ find_interesting_uses_stmt (struct ivopt
       if (TREE_CODE (op) != SSA_NAME)
 	continue;
 
+      if (IS_DEBUG_STMT (USE_STMT (use_p)))
+	continue;
+
       iv = get_iv (data, op);
       if (!iv)
 	continue;
@@ -5196,7 +5199,24 @@ remove_unused_ivs (struct ivopts_data *d
 	  && !info->inv_id
 	  && !info->iv->have_use_for
 	  && !info->preserve_biv)
-	remove_statement (SSA_NAME_DEF_STMT (info->iv->ssa_name), true);
+	{
+	  if (MAY_HAVE_DEBUG_STMTS)
+	    {
+	      tree stmt;
+	      imm_use_iterator iter;
+
+	      FOR_EACH_IMM_USE_STMT (stmt, iter, info->iv->ssa_name)
+		{
+		  if (!IS_DEBUG_STMT (stmt))
+		    continue;
+
+		  /* ??? We can probably do better than this.  */
+		  VAR_DEBUG_VALUE_VALUE (stmt) = VAR_DEBUG_VALUE_NOVALUE;
+		  update_stmt (stmt);
+		}
+	    }
+	  remove_statement (SSA_NAME_DEF_STMT (info->iv->ssa_name), true);
+	}
     }
 }
 
Index: gcc/tree-ssa-loop-im.c
===================================================================
--- gcc/tree-ssa-loop-im.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-loop-im.c	2007-10-01 22:41:35.000000000 -0300
@@ -686,6 +686,7 @@ rewrite_bittest (block_stmt_iterator *bs
       SET_USE (use, name);
 
       bsi_insert_before (bsi, stmt1, BSI_SAME_STMT);
+      adjust_debug_stmts_for_move (bsi_stmt (*bsi), NULL, NULL);
       bsi_replace (bsi, stmt2, true);
 
       return stmt1;
@@ -852,6 +853,7 @@ move_computations_stmt (struct dom_walk_
 		   cost, level->num);
 	}
       bsi_insert_on_edge (loop_preheader_edge (level), stmt);
+      adjust_debug_stmts_for_move (bsi_stmt (bsi), NULL, NULL);
       bsi_remove (&bsi, false);
     }
 }
Index: gcc/tree-ssanames.c
===================================================================
--- gcc/tree-ssanames.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssanames.c	2007-10-01 22:41:35.000000000 -0300
@@ -203,6 +203,9 @@ release_ssa_name (tree var)
       int saved_ssa_name_version = SSA_NAME_VERSION (var);
       use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var));
 
+      if (MAY_HAVE_DEBUG_STMTS)
+	adjust_debug_stmts_for_var_def_move (var, NULL, NULL);
+
 #ifdef ENABLE_CHECKING
       verify_imm_links (stderr, var);
 #endif
Index: gcc/tree-ssa-alias.c
===================================================================
--- gcc/tree-ssa-alias.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-alias.c	2007-10-01 22:41:35.000000000 -0300
@@ -3908,6 +3908,10 @@ find_used_portions (tree *tp, int *walk_
 {
   switch (TREE_CODE (*tp))
     {
+    case VAR_DEBUG_VALUE:
+      *walk_subtrees = 0;
+      break;
+
     case GIMPLE_MODIFY_STMT:
       /* Recurse manually here to track whether the use is in the
 	 LHS of an assignment.  */
Index: gcc/tree-ssa-structalias.c
===================================================================
--- gcc/tree-ssa-structalias.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-structalias.c	2007-10-01 22:41:35.000000000 -0300
@@ -5373,7 +5373,8 @@ compute_points_to_sets (struct alias_inf
 	     addresses, pointer dereferences for loads and stores.
 	     This is used when creating name tags and alias
 	     sets.  */
-	  update_alias_info (stmt, ai);
+	  if (!IS_DEBUG_STMT (stmt))
+	    update_alias_info (stmt, ai);
 
 	  /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now
 	     been captured, and we can remove them.  */
Index: gcc/tree-tailcall.c
===================================================================
--- gcc/tree-tailcall.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-tailcall.c	2007-10-01 22:41:35.000000000 -0300
@@ -391,7 +391,7 @@ find_tail_calls (basic_block bb, struct 
       stmt = bsi_stmt (bsi);
 
       /* Ignore labels.  */
-      if (TREE_CODE (stmt) == LABEL_EXPR)
+      if (TREE_CODE (stmt) == LABEL_EXPR || IS_DEBUG_STMT (stmt))
 	continue;
 
       /* Check for a call.  */
@@ -495,6 +495,9 @@ find_tail_calls (basic_block bb, struct 
       if (TREE_CODE (stmt) == RETURN_EXPR)
 	break;
 
+      if (IS_DEBUG_STMT (stmt))
+	continue;
+
       if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
 	return;
 
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-vrp.c	2007-10-01 22:41:35.000000000 -0300
@@ -4067,6 +4067,9 @@ find_assert_locations (basic_block bb)
 
       stmt = bsi_stmt (si);
 
+      if (IS_DEBUG_STMT (stmt))
+	continue;
+
       /* See if we can derive an assertion for any of STMT's operands.  */
       FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE)
 	{
Index: gcc/tree-ssa-coalesce.c
===================================================================
--- gcc/tree-ssa-coalesce.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-coalesce.c	2007-10-01 22:41:35.000000000 -0300
@@ -865,6 +865,8 @@ build_ssa_conflict_graph (tree_live_info
 	      if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
 		live_track_clear_var (live, rhs);
 	    }
+	  else if (IS_DEBUG_STMT (stmt))
+	    continue;
 
 	  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF)
 	    live_track_process_def (live, var, graph);
@@ -1027,6 +1029,9 @@ create_outofssa_var_map (coalesce_list_p
         {
 	  stmt = bsi_stmt (bsi);
 
+	  if (IS_DEBUG_STMT (stmt))
+	    continue;
+
 	  /* Register USE and DEF operands in each statement.  */
 	  FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, (SSA_OP_DEF|SSA_OP_USE))
 	    register_ssa_partition (map, var);
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-forwprop.c	2007-10-01 22:41:35.000000000 -0300
@@ -695,6 +695,7 @@ forward_propagate_addr_expr (tree name, 
   tree use_stmt;
   bool all = true;
   bool single_use_p = has_single_use (name);
+  bool debug = false;
 
   FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
     {
@@ -704,7 +705,10 @@ forward_propagate_addr_expr (tree name, 
 	 there is nothing we can do.  */
       if (TREE_CODE (use_stmt) != GIMPLE_MODIFY_STMT)
 	{
-	  all = false;
+	  if (IS_DEBUG_STMT (use_stmt))
+	    debug = true;
+	  else
+	    all = false;
 	  continue;
 	}
 
@@ -738,6 +742,9 @@ forward_propagate_addr_expr (tree name, 
 	}
     }
 
+  if (all && debug)
+    adjust_debug_stmts_for_var_def_move (name, NULL, NULL);
+
   return all;
 }
 
Index: gcc/tree-ssa-pre.c
===================================================================
--- gcc/tree-ssa-pre.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-pre.c	2007-10-01 22:41:35.000000000 -0300
@@ -3553,7 +3553,6 @@ compute_avail (void)
 		}
 	      continue;
 	    }
-
 	  else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
 	      && !ann->has_volatile_ops
 	      && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) == SSA_NAME
@@ -3562,8 +3561,9 @@ compute_avail (void)
 	    {
 	      if (make_values_for_stmt (stmt, block))
 		continue;
-
 	    }
+	  else if (IS_DEBUG_STMT (stmt))
+	    continue;
 
 	  /* For any other statement that we don't recognize, simply
 	     make the names generated by the statement available in
Index: gcc/tree-ssa-loop-manip.c
===================================================================
--- gcc/tree-ssa-loop-manip.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-ssa-loop-manip.c	2007-10-01 22:41:35.000000000 -0300
@@ -271,6 +271,9 @@ find_uses_to_rename_stmt (tree stmt, bit
   tree var;
   basic_block bb = bb_for_stmt (stmt);
 
+  if (IS_DEBUG_STMT (stmt))
+    return;
+
   FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_USES)
     find_uses_to_rename_use (bb, var, use_blocks, need_phis);
 }
@@ -422,6 +425,9 @@ check_loop_closed_ssa_stmt (basic_block 
   ssa_op_iter iter;
   tree var;
 
+  if (IS_DEBUG_STMT (stmt))
+    return;
+
   FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_USES)
     check_loop_closed_ssa_use (bb, var);
 }
Index: gcc/tree-inline.h
===================================================================
--- gcc/tree-inline.h.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-inline.h	2007-10-01 22:41:35.000000000 -0300
@@ -94,6 +94,9 @@ typedef struct copy_body_data
 
   /* Statements that might be possibly folded.  */
   struct pointer_set_t *statements_to_fold;
+
+  /* Debug statements that need processing.  */
+  varray_type debug_stmts;
 } copy_body_data;
 
 /* Weights of constructions for estimate_num_insns.  */
Index: gcc/ipa-pure-const.c
===================================================================
--- gcc/ipa-pure-const.c.orig	2007-10-01 22:41:08.000000000 -0300
+++ gcc/ipa-pure-const.c	2007-10-01 22:41:35.000000000 -0300
@@ -467,6 +467,10 @@ scan_function (tree *tp, 
       }
       break;
 
+    case VAR_DEBUG_VALUE:
+      *walk_subtrees = 0;
+      break;
+
     case ADDR_EXPR:
       /* This case is here to find addresses on rhs of constructors in
 	 decl_initial of static variables. */
Index: gcc/ipa-reference.c
===================================================================
--- gcc/ipa-reference.c.orig	2007-10-01 22:41:08.000000000 -0300
+++ gcc/ipa-reference.c	2007-10-01 22:41:35.000000000 -0300
@@ -552,6 +552,10 @@ scan_for_static_refs (tree *tp, 
       }
       break;
 
+    case VAR_DEBUG_VALUE:
+      *walk_subtrees = 0;
+      break;
+
     case ADDR_EXPR:
       /* This case is here to find addresses on rhs of constructors in
 	 decl_initial of static variables. */
Index: gcc/ipa-type-escape.c
===================================================================
--- gcc/ipa-type-escape.c.orig	2007-10-01 22:41:08.000000000 -0300
+++ gcc/ipa-type-escape.c	2007-10-01 22:41:35.000000000 -0300
@@ -1612,6 +1612,10 @@ scan_for_refs (tree *tp, int *walk_subtr
       }
       break;
 
+    case VAR_DEBUG_VALUE:
+      *walk_subtrees = 0;
+      break;
+
     case ADDR_EXPR:
       /* This case is here to find addresses on rhs of constructors in
 	 decl_initial of static variables. */
Index: gcc/tree-stdarg.c
===================================================================
--- gcc/tree-stdarg.c.orig	2007-10-01 22:41:09.000000000 -0300
+++ gcc/tree-stdarg.c	2007-10-01 22:41:35.000000000 -0300
@@ -850,6 +850,8 @@ execute_optimize_stdarg (void)
 		    continue;
 		}
 	    }
+	  else if (IS_DEBUG_STMT (stmt))
+	    continue;
 
 	  /* All other uses of va_list are either va_copy (that is not handled
 	     in this optimization), taking address of va_list variable or
for  gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>

	* expr.c (expand_expr_real_1): Reject debug exprs.
	* cfgexpand.c (floor_sdiv_adjust): New fn.
	(ceil_sdiv_adjust): New fn.
	(ceil_udiv_adjust): New fn.
	(round_sdiv_adjust): New fn.
	(round_udiv_adjust): New fn.
	(expand_debug_expr): New fn.
	(expand_gimple_basic_block): Handle debug stmts.
	* cfgrtl.c (rtl_block_ends_with_call_p): Ignore debug insns.
	* rtl.h (DEBUG_INSN_P): New macro.
	(MAY_HAVE_DEBUG_INSNS): New macro.
	(INSN_P): Accept debug insns.
	(RTX_FRAME_RELATED_P): Likewise.
	(INSN_DELETED_P): Likewise.
	(PAT_VAR_LOCATION_DECL): New macro.
	(PAT_VAR_LOCATION_LOC): New macro.
	(NOTE_VAR_LOCATION_DECL): Reimplement.
	(NOTE_VAR_LOCATION_LOC): Likewise.
	(NOTE_VAR_LOCATION_STATUS): Likewise.
	(INSN_VAR_LOCATION): New macro.
	(INSN_VAR_LOCATION_DECL): Likewise.
	(INSN_VAR_LOCATION_LOC): Likewise.
	(INSN_VAR_LOCATION_STATUS): Likewise.
	(gen_rtx_UNKNOWN_VAR_LOC): New macro.
	(VAR_LOC_UNKNOWN_P): New macro.
	(SCHED_GROUP_P): Accept debug insns.
	(emit_debug_insn_before): Declare.
	(emit_debug_insn_before_noloc): Likewise.
	(emit_debug_insn_before_setloc): Likewise.
	(emit_debug_insn_after): Likewise.
	(emit_debug_insn_after_noloc): Likewise.
	(emit_debug_insn_after_setloc): Likewise.
	(emit_debug_insn): Likewise.
	(make_debug_insn_raw): Likewise.
	* recog.c (verify_changes): Accept debug insns.
	(extract_insn): Handle them.
	(peephole2_optimize): Skip them.
	* dce.c (deletable_insn_p): Handle debug insns.
	* reload1.c (reload): Don't scan subregs in debug insns.
	(eliminate_regs_in_insn): Handle debug insns.
	* cse.c (cse_insn): Handle debug insns.
	(cse_extended_basic_block): Likewise.
	(insn_live_p): Likewise.
	* emit-rtl.c (copy_rtx_if_shared_1): Handle debug insns.
	(reset_used_flags): Likewise.
	(set_used_flags): Likewise.
	(active_insn_p): Exclude debug insns.
	(make_debug_insn_raw): New fn.
	(emit_insn_before_noloc): Handle debug insns.
	(emit_jump_insn_before_noloc): Likewise.
	(emit_call_insn_before_noloc): Likewise.
	(emit_debug_insn_before_noloc): New fn.
	(emit_insn_after_noloc): Handle debug insns.
	(emit_jump_insn_after_noloc): Likewise.
	(emit_call_insn_after_noloc): Likewise.
	(emit_debug_insn_after_noloc): New fn.
	(emit_debug_insn_after_setloc): New fn.
	(emit_debug_insn_after): New fn.
	(emit_debug_insn_before_setloc): New fn.
	(emit_debug_insn_before): New fn.
	(emit_insn): Handle debug insn.
	(emit_debug_insn): New fn.
	(emit_jump_insn): Handle debug insn.
	(emit_call_insn): Likewise.
	(emit): Likewise.
	(emit_copy_of_insn_after): Likewise.
	* reg-stack.c (subst_stack_regs_pat): Handle var location rtx.
	* var-tracking.c (MO_LOC_MAIN, MO_LOC_USE): New micro ops.
	(var_reg_decl_set): New fn.
	(var_reg_set): Adjust.
	(var_mem_decl_set): New fn.
	(var_mem_set): Adjust.
	(use_type): New fn.
	(count_uses, add_uses, add_stores): Adjust.
	(compute_bb_dataflow): Handle new micro ops.
	(emit_notes_in_bb): Likewise.
	(vt_initialize): Likewise.
	(delete_debug_insns): New fn.
	(vt_debug_insns_local): New fn.
	(variable_tracking_main): Call it.
	* final.c (get_attr_length_1): Handle debug insns.
	* lower-subreg.c (adjust_decomposed_uses): New fn.
	(resolve_debug): New fn.
	(decompose_multiword_subregs): Handle debug insns.
	* print-rtl.c (print_rtx): Likewise.
	* ifcvt.c (first_active_insn): Skip debug insns.
	(last_active_insn): Likewise.
	(cond_exec_process_insns): Handle debug insns.
	(check_cond_move_block): Likewise.
	(cond_move_convert_if_block): Likewise.
	(block_jumps_and_fallthru_p): Likewise.
	(dead_or_predicable): Likewise.
	* cfgcleanup.c (flow_find_cross_jump): Skip debug insns.
	* combine.c (create_log_links): Skip debug insns.
	(combine_instructions): Likewise.
	(rtx_subst_pair): New struct.
	(propagate_for_debug_subst): New fn.
	(propagate_for_debug): New fn.
	(try_combine): Call it.
	(distribute_links): Handle debug insns.
	* df-problems.c (df_lr_bb_local_compute): Likewise.
	(df_set_note): Reject debug insns.
	(df_set_dead_notes_for_mw): Add added_notes_p argument.
	(df_note_bb_compute): Handle debug insns.
	(df_simulate_uses): Likewise.
	(df_simulate_one_insn_forwards): Likewise.
	(df_simulate_one_insn_backwards): Likewise.
	* df-scan.c (df_insn_rescan_1): Renamed with new argument, from...
	(df_insn_rescan): ... this.  Implement in terms of new name.
	(df_insn_rescan_debug_internal): New fn.
	(df_uses_record): Handle debug insns.
	* haifa-sched.c (contributes_to_priority_p): Likewise.
	(nondebug_dep_list_size): New fn.
	(priority, add_jump_dependencies): Use it.
	(rank_for_schedule): Handle debug insns.
	(schedule_block): Always accept more debug insns.
	* local-alloc.c (block_alloc): Handle debug insns.
	* regrename.c (replace_oldest_value_reg): ??? Test without this
	(replace_oldest_value_addr): Handle debug insns.
	(replace_oldest_value_mem): Likewise.
	(copyprop_hardreg_forward_1): Likewise.
	* regstat.c (regstat_init_n_sets_and_refs): Skip debug uses.
	(regstat_bb_compute_ri): Skip debug insns.
	* sched-rgn.c (add_branch_dependences): Likewise.
	* sched-vis.c (print_pattern): Handle debug insns.
	* regmove.c (optimize_reg_copy_1): Don't count debug insns.
	(fixup_match_2): Likewise.
	(regmove_optimize): Handle debug insns.
	(fixup_match_1): Don't count debug insns.  Adjust them.
	* gcse.c (allolc_gcse_mem): Don't allocate uid for debug isnsn.
	(bypass_conditional_jumps): Skip debug insns.
	(compute_ld_motion_mems): Likewise.
	* sched-deps.c (sched_analyze_2): Handle debug insns.
	(sched_analyze_insn): Likewise.
	(sched_analyze): Likewise.
	* init-regs.c (initialize_uninitialized_regs): Skip debug insns.
	* dse.c (scan_insn): Keep debug insns.
	* resource.c (mark_target_live_regs): Skip debug insns.
	* rtlanal.c (canonicalize_condition): Likewise.
	* df.h (df_insn_rescan_debug_internal): Declare.
	* dwarf2out.c (mem_loc_descriptor): Ignore sign and zero extend.
	(loc_descriptor): Likewise.
	* function.c (instantiate_virtual_regs): Handle debug insns.
	* rtl.def (DEBUG_INSN): New rtl code.
	* cfgbuild.c (inside_basic_block_p): Handle debug insns.
	(control_flow_insn_p): Likewise.
	* cfglayout.c (duplicate_insn_chain): Likewise.

Index: gcc/expr.c
===================================================================
--- gcc/expr.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/expr.c	2007-10-01 18:38:14.000000000 -0300
@@ -9129,6 +9129,10 @@ expand_expr_real_1 (tree exp, rtx target
 	return const0_rtx;
       }
 
+    case VAR_DEBUG_VALUE:
+      /* Expanded by expand_gimple_basic_block only.  */
+      gcc_unreachable ();
+
     case RETURN_EXPR:
       if (!TREE_OPERAND (exp, 0))
 	expand_null_return ();
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/cfgexpand.c	2007-10-01 18:38:14.000000000 -0300
@@ -1465,6 +1465,624 @@ expand_gimple_tailcall (basic_block bb, 
   return bb;
 }
 
+/* Return the difference between the floor and the truncated result of
+   a signed division by OP1 with remainder MOD.  */
+static rtx
+floor_sdiv_adjust (enum machine_mode mode, rtx mod, rtx op1)
+{
+  /* (mod != 0 ? (op1 / mod < 0 ? -1 : 0) : 0) */
+  return gen_rtx_IF_THEN_ELSE
+    (mode, gen_rtx_NE (BImode, mod, const0_rtx),
+     gen_rtx_IF_THEN_ELSE
+     (mode, gen_rtx_LT (BImode,
+			gen_rtx_DIV (mode, op1, mod),
+			const0_rtx),
+      constm1_rtx, const0_rtx),
+     const0_rtx);
+}
+
+/* Return the difference between the ceil and the truncated result of
+   a signed division by OP1 with remainder MOD.  */
+static rtx
+ceil_sdiv_adjust (enum machine_mode mode, rtx mod, rtx op1)
+{
+  /* (mod != 0 ? (op1 / mod > 0 ? 1 : 0) : 0) */
+  return gen_rtx_IF_THEN_ELSE
+    (mode, gen_rtx_NE (BImode, mod, const0_rtx),
+     gen_rtx_IF_THEN_ELSE
+     (mode, gen_rtx_GT (BImode,
+			gen_rtx_DIV (mode, op1, mod),
+			const0_rtx),
+      const1_rtx, const0_rtx),
+     const0_rtx);
+}
+
+/* Return the difference between the ceil and the truncated result of
+   an unsigned division by OP1 with remainder MOD.  */
+static rtx
+ceil_udiv_adjust (enum machine_mode mode, rtx mod, rtx op1 ATTRIBUTE_UNUSED)
+{
+  /* (mod != 0 ? 1 : 0) */
+  return gen_rtx_IF_THEN_ELSE
+    (mode, gen_rtx_NE (BImode, mod, const0_rtx),
+     const1_rtx, const0_rtx);
+}
+
+/* Return the difference between the rounded and the truncated result
+   of a signed division by OP1 with remainder MOD.  Halfway cases are
+   rounded away from zero, rather than to the nearest even number.  */
+static rtx
+round_sdiv_adjust (enum machine_mode mode, rtx mod, rtx op1)
+{
+  /* (abs (mod) >= abs (op1) - abs (mod)
+      ? (op1 / mod > 0 ? 1 : -1)
+      : 0) */
+  return gen_rtx_IF_THEN_ELSE
+    (mode, gen_rtx_GE (BImode, gen_rtx_ABS (mode, mod),
+		       gen_rtx_MINUS (mode,
+				      gen_rtx_ABS (mode, op1),
+				      gen_rtx_ABS (mode, mod))),
+     gen_rtx_IF_THEN_ELSE
+     (mode, gen_rtx_GT (BImode,
+			gen_rtx_DIV (mode, op1, mod),
+			const0_rtx),
+      const1_rtx, constm1_rtx),
+     const0_rtx);
+}
+
+/* Return the difference between the rounded and the truncated result
+   of a unsigned division by OP1 with remainder MOD.  Halfway cases
+   are rounded away from zero, rather than to the nearest even
+   number.  */
+static rtx
+round_udiv_adjust (enum machine_mode mode, rtx mod, rtx op1)
+{
+  /* (mod >= op1 - mod ? 1 : 0) */
+  return gen_rtx_IF_THEN_ELSE
+    (mode, gen_rtx_GE (BImode, mod,
+		       gen_rtx_MINUS (mode, op1, mod)),
+     const1_rtx, const0_rtx);
+}
+
+
+/* Return an RTX equivalent to the value of the tree expression
+   EXP.  */
+
+static rtx
+expand_debug_expr (tree exp)
+{
+  rtx op0 = NULL_RTX, op1 = NULL_RTX, op2 = NULL_RTX;
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
+
+  switch (TREE_CODE_CLASS (TREE_CODE (exp)))
+    {
+    case tcc_expression:
+      switch (TREE_CODE (exp))
+	{
+	case COND_EXPR:
+	  goto ternary;
+
+	case TRUTH_ANDIF_EXPR:
+	case TRUTH_ORIF_EXPR:
+	case TRUTH_AND_EXPR:
+	case TRUTH_OR_EXPR:
+	case TRUTH_XOR_EXPR:
+	  goto binary;
+
+	case TRUTH_NOT_EXPR:
+	  goto unary;
+
+	default:
+	  break;
+	}
+      break;
+
+    ternary:
+      op2 = expand_debug_expr (TREE_OPERAND (exp, 2));
+      if (!op2)
+	return NULL_RTX;
+      /* Fall through.  */
+
+    binary:
+    case tcc_binary:
+    case tcc_comparison:
+      op1 = expand_debug_expr (TREE_OPERAND (exp, 1));
+      if (!op1)
+	return NULL_RTX;
+      /* Fall through.  */
+
+    unary:
+    case tcc_unary:
+      op0 = expand_debug_expr (TREE_OPERAND (exp, 0));
+      if (!op0)
+	return NULL_RTX;
+      break;
+
+    case tcc_type:
+    case tcc_statement:
+    case tcc_gimple_stmt:
+      gcc_unreachable ();
+
+    case tcc_constant:
+    case tcc_exceptional:
+    case tcc_declaration:
+    case tcc_reference:
+    case tcc_vl_exp:
+      break;
+    }
+
+  switch (TREE_CODE (exp))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case FUNCTION_DECL:
+    case LABEL_DECL:
+    case CONST_DECL:
+    case RESULT_DECL:
+      /* This decl was optimized away.  */
+      if (!DECL_RTL_SET_P (exp))
+	return NULL;
+
+      return DECL_RTL (exp);
+
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+    case STRING_CST:
+      op0 = expand_expr (exp, NULL_RTX, mode,
+			 EXPAND_INITIALIZER | EXPAND_CONST_ADDRESS);
+      if (op0 && GET_MODE (op0) == VOIDmode && mode != VOIDmode)
+	return op0 = gen_rtx_CONST (mode, op0);
+      return op0;
+
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+      {
+	enum machine_mode inner_mode
+	  = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+	if (mode == GET_MODE (op0))
+	  return op0;
+
+	if (CONSTANT_P (op0)
+	    || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (GET_MODE (op0)))
+	  op0 = simplify_gen_subreg (mode, op0, inner_mode,
+				     subreg_lowpart_offset (mode,
+							    inner_mode));
+	else if (unsignedp)
+	  op0 = gen_rtx_ZERO_EXTEND (mode, op0);
+	else
+	  op0 = gen_rtx_SIGN_EXTEND (mode, op0);
+
+	return op0;
+      }
+
+    case INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
+      op0 = expand_debug_expr (TREE_OPERAND (exp, 0));
+      if (!op0)
+	return NULL;
+
+      gcc_assert (GET_MODE (op0) == Pmode);
+
+      if (TREE_CODE (exp) == ALIGN_INDIRECT_REF)
+	{
+	  int align = TYPE_ALIGN_UNIT (TREE_TYPE (exp));
+	  op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
+	}
+
+      op0 = gen_rtx_MEM (mode, op0);
+
+      set_mem_attributes (op0, exp, 0);
+
+      return op0;
+
+    case TARGET_MEM_REF:
+      if (TMR_SYMBOL (exp) && !DECL_RTL_SET_P (TMR_SYMBOL (exp)))
+	return NULL;
+
+      op0 = expand_debug_expr
+	(tree_mem_ref_addr (build_pointer_type (TREE_TYPE (exp)),
+			    exp));
+      if (!op0)
+	return NULL;
+
+      gcc_assert (GET_MODE (op0) == Pmode);
+
+      op0 = gen_rtx_MEM (mode, op0);
+
+      set_mem_attributes (op0, exp, 0);
+
+      return op0;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case VIEW_CONVERT_EXPR:
+      {
+	enum machine_mode mode1;
+	HOST_WIDE_INT bitsize, bitpos;
+	tree offset;
+	int volatilep = 0;
+	tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+					&mode1, &unsignedp, &volatilep, true);
+
+	op0 = expand_debug_expr (tem);
+
+	if (!op0)
+	  return NULL;
+
+	if (offset)
+	  {
+	    gcc_assert (MEM_P (op0));
+
+	    op1 = expand_debug_expr (offset);
+	    if (!op1)
+	      return NULL;
+
+	    op0 = gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, XEXP (op0, 0), op1));
+	  }
+
+	if (MEM_P (op0))
+	  {
+	    if (bitpos >= BITS_PER_UNIT)
+	      {
+		op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT);
+		bitpos %= BITS_PER_UNIT;
+	      }
+	    else if (bitpos == 0 && bitsize == GET_MODE_BITSIZE (mode))
+	      op0 = adjust_address_nv (op0, mode, 0);
+	    else if (GET_MODE (op0) != mode1)
+	      op0 = adjust_address_nv (op0, mode1, 0);
+	    else
+	      op0 = copy_rtx (op0);
+	    set_mem_attributes (op0, exp, 0);
+	  }
+
+	if (bitpos == 0 && mode == GET_MODE (op0))
+	  return op0;
+
+	if ((bitpos % BITS_PER_UNIT) == 0
+	    && bitsize == GET_MODE_BITSIZE (mode1))
+	  return simplify_gen_subreg (mode, op0,
+				      GET_MODE (op0) != VOIDmode
+				      ? GET_MODE (op0) : mode1,
+				      bitpos / BITS_PER_UNIT);
+
+	return simplify_gen_ternary (SCALAR_INT_MODE_P (GET_MODE (op0))
+				     && TYPE_UNSIGNED (TREE_TYPE (exp))
+				     ? SIGN_EXTRACT
+				     : ZERO_EXTRACT, mode,
+				     GET_MODE (op0) != VOIDmode
+				     ? GET_MODE (op0) : mode1,
+				     op0, GEN_INT (bitsize), GEN_INT (bitpos));
+      }
+
+    case EXC_PTR_EXPR:
+      /* ??? Do not call get_exception_pointer(), we don't want to gen
+	 it if it hasn't been created yet.  */
+      return get_exception_pointer (cfun);
+
+    case FILTER_EXPR:
+      /* Likewise get_exception_filter().  */
+      return get_exception_filter (cfun);
+
+    case ABS_EXPR:
+      return gen_rtx_ABS (mode, op0);
+
+    case NEGATE_EXPR:
+      return gen_rtx_NEG (mode, op0);
+
+    case BIT_NOT_EXPR:
+      return gen_rtx_NOT (mode, op0);
+
+    case FLOAT_EXPR:
+      if (unsignedp)
+	return gen_rtx_UNSIGNED_FLOAT (mode, op0);
+      else
+	return gen_rtx_FLOAT (mode, op0);
+
+    case FIX_TRUNC_EXPR:
+      if (unsignedp)
+	return gen_rtx_UNSIGNED_FIX (mode, op0);
+      else
+	return gen_rtx_FIX (mode, op0);
+
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+      return gen_rtx_PLUS (mode, op0, op1);
+
+    case MINUS_EXPR:
+      return gen_rtx_MINUS (mode, op0, op1);
+
+    case MULT_EXPR:
+      return gen_rtx_MULT (mode, op0, op1);
+
+    case RDIV_EXPR:
+    case TRUNC_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (unsignedp)
+	return gen_rtx_UDIV (mode, op0, op1);
+      else
+	return gen_rtx_DIV (mode, op0, op1);
+
+    case TRUNC_MOD_EXPR:
+      if (unsignedp)
+	return gen_rtx_UMOD (mode, op0, op1);
+      else
+	return gen_rtx_MOD (mode, op0, op1);
+
+    case FLOOR_DIV_EXPR:
+      if (unsignedp)
+	return gen_rtx_UDIV (mode, op0, op1);
+      else
+	{
+	  rtx div = gen_rtx_DIV (mode, op0, op1);
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = floor_sdiv_adjust (mode, mod, op1);
+	  return gen_rtx_PLUS (mode, div, adj);
+	}
+
+    case FLOOR_MOD_EXPR:
+      if (unsignedp)
+	return gen_rtx_UMOD (mode, op0, op1);
+      else
+	{
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = floor_sdiv_adjust (mode, mod, op1);
+	  adj = gen_rtx_NEG (mode, gen_rtx_MULT (mode, adj, op1));
+	  return gen_rtx_PLUS (mode, mod, adj);
+	}
+
+    case CEIL_DIV_EXPR:
+      if (unsignedp)
+	{
+	  rtx div = gen_rtx_UDIV (mode, op0, op1);
+	  rtx mod = gen_rtx_UMOD (mode, op0, op1);
+	  rtx adj = ceil_udiv_adjust (mode, mod, op1);
+	  return gen_rtx_PLUS (mode, div, adj);
+	}
+      else
+	{
+	  rtx div = gen_rtx_DIV (mode, op0, op1);
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = ceil_sdiv_adjust (mode, mod, op1);
+	  return gen_rtx_PLUS (mode, div, adj);
+	}
+
+    case CEIL_MOD_EXPR:
+      if (unsignedp)
+	{
+	  rtx mod = gen_rtx_UMOD (mode, op0, op1);
+	  rtx adj = ceil_udiv_adjust (mode, mod, op1);
+	  adj = gen_rtx_NEG (mode, gen_rtx_MULT (mode, adj, op1));
+	  return gen_rtx_PLUS (mode, mod, adj);
+	}
+      else
+	{
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = ceil_sdiv_adjust (mode, mod, op1);
+	  adj = gen_rtx_NEG (mode, gen_rtx_MULT (mode, adj, op1));
+	  return gen_rtx_PLUS (mode, mod, adj);
+	}
+
+    case ROUND_DIV_EXPR:
+      if (unsignedp)
+	{
+	  rtx div = gen_rtx_UDIV (mode, op0, op1);
+	  rtx mod = gen_rtx_UMOD (mode, op0, op1);
+	  rtx adj = round_udiv_adjust (mode, mod, op1);
+	  return gen_rtx_PLUS (mode, div, adj);
+	}
+      else
+	{
+	  rtx div = gen_rtx_DIV (mode, op0, op1);
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = round_sdiv_adjust (mode, mod, op1);
+	  return gen_rtx_PLUS (mode, div, adj);
+	}
+
+    case ROUND_MOD_EXPR:
+      if (unsignedp)
+	{
+	  rtx mod = gen_rtx_UMOD (mode, op0, op1);
+	  rtx adj = round_udiv_adjust (mode, mod, op1);
+	  adj = gen_rtx_NEG (mode, gen_rtx_MULT (mode, adj, op1));
+	  return gen_rtx_PLUS (mode, mod, adj);
+	}
+      else
+	{
+	  rtx mod = gen_rtx_MOD (mode, op0, op1);
+	  rtx adj = round_sdiv_adjust (mode, mod, op1);
+	  adj = gen_rtx_NEG (mode, gen_rtx_MULT (mode, adj, op1));
+	  return gen_rtx_PLUS (mode, mod, adj);
+	}
+
+    case LSHIFT_EXPR:
+      return gen_rtx_ASHIFT (mode, op0, op1);
+
+    case RSHIFT_EXPR:
+      if (unsignedp)
+	return gen_rtx_LSHIFTRT (mode, op0, op1);
+      else
+	return gen_rtx_ASHIFTRT (mode, op0, op1);
+
+    case LROTATE_EXPR:
+      return gen_rtx_ROTATE (mode, op0, op1);
+
+    case RROTATE_EXPR:
+      return gen_rtx_ROTATERT (mode, op0, op1);
+
+    case MIN_EXPR:
+      if (unsignedp)
+	return gen_rtx_UMIN (mode, op0, op1);
+      else
+	return gen_rtx_SMIN (mode, op0, op1);
+
+    case MAX_EXPR:
+      if (unsignedp)
+	return gen_rtx_UMAX (mode, op0, op1);
+      else
+	return gen_rtx_SMAX (mode, op0, op1);
+
+    case BIT_AND_EXPR:
+    case TRUTH_AND_EXPR:
+      return gen_rtx_AND (mode, op0, op1);
+
+    case BIT_IOR_EXPR:
+    case TRUTH_OR_EXPR:
+      return gen_rtx_IOR (mode, op0, op1);
+
+    case BIT_XOR_EXPR:
+    case TRUTH_XOR_EXPR:
+      return gen_rtx_XOR (mode, op0, op1);
+
+    case TRUTH_ANDIF_EXPR:
+      return gen_rtx_IF_THEN_ELSE (mode, op0, op1, const0_rtx);
+
+    case TRUTH_ORIF_EXPR:
+      return gen_rtx_IF_THEN_ELSE (mode, op0, const_true_rtx, op1);
+
+    case TRUTH_NOT_EXPR:
+      return gen_rtx_EQ (mode, op0, const0_rtx);
+
+    case LT_EXPR:
+      if (unsignedp)
+	return gen_rtx_LTU (mode, op0, op1);
+      else
+	return gen_rtx_LT (mode, op0, op1);
+
+    case LE_EXPR:
+      if (unsignedp)
+	return gen_rtx_LEU (mode, op0, op1);
+      else
+	return gen_rtx_LE (mode, op0, op1);
+
+    case GT_EXPR:
+      if (unsignedp)
+	return gen_rtx_GTU (mode, op0, op1);
+      else
+	return gen_rtx_GT (mode, op0, op1);
+
+    case GE_EXPR:
+      if (unsignedp)
+	return gen_rtx_GEU (mode, op0, op1);
+      else
+	return gen_rtx_GE (mode, op0, op1);
+
+    case EQ_EXPR:
+      return gen_rtx_EQ (mode, op0, op1);
+
+    case NE_EXPR:
+      return gen_rtx_NE (mode, op0, op1);
+
+    case UNORDERED_EXPR:
+      return gen_rtx_UNORDERED (mode, op0, op1);
+
+    case ORDERED_EXPR:
+      return gen_rtx_ORDERED (mode, op0, op1);
+
+    case UNLT_EXPR:
+      return gen_rtx_UNLT (mode, op0, op1);
+
+    case UNLE_EXPR:
+      return gen_rtx_UNLE (mode, op0, op1);
+
+    case UNGT_EXPR:
+      return gen_rtx_UNGT (mode, op0, op1);
+
+    case UNGE_EXPR:
+      return gen_rtx_UNGE (mode, op0, op1);
+
+    case UNEQ_EXPR:
+      return gen_rtx_UNEQ (mode, op0, op1);
+
+    case LTGT_EXPR:
+      return gen_rtx_LTGT (mode, op0, op1);
+
+    case COND_EXPR:
+      return gen_rtx_IF_THEN_ELSE (mode, op0, op1, op2);
+
+    case COMPLEX_EXPR:
+      gcc_assert (COMPLEX_MODE_P (mode));
+      if (GET_MODE (op0) == VOIDmode)
+	op0 = gen_rtx_CONST (GET_MODE_INNER (mode), op0);
+      if (GET_MODE (op1) == VOIDmode)
+	op1 = gen_rtx_CONST (GET_MODE_INNER (mode), op1);
+      return gen_rtx_CONCAT (mode, op0, op1);
+
+    case ADDR_EXPR:
+      op0 = expand_debug_expr (TREE_OPERAND (exp, 0));
+      if (!op0 || !MEM_P (op0))
+	return NULL;
+
+      return XEXP (op0, 0);
+
+    case VECTOR_CST:
+      exp = build_constructor_from_list (TREE_TYPE (exp),
+					 TREE_VECTOR_CST_ELTS (exp));
+      /* Fall through.  */
+
+    case CONSTRUCTOR:
+      if (TREE_CODE (TREE_TYPE (exp)) == VECTOR_TYPE)
+	{
+	  unsigned i;
+	  tree val;
+
+	  op0 = gen_rtx_CONCATN
+	    (mode, rtvec_alloc (TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp))));
+
+	  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), i, val)
+	    {
+	      op1 = expand_debug_expr (val);
+	      if (!op1)
+		return NULL;
+	      XVECEXP (op0, 0, i) = op1;
+	    }
+
+	  if (i < TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp)))
+	    {
+	      op1 = expand_debug_expr
+		(fold_convert (TREE_TYPE (TREE_TYPE (exp)), integer_zero_node));
+
+	      if (!op1)
+		return NULL;
+
+	      for (; i < TYPE_VECTOR_SUBPARTS (TREE_TYPE (exp)); i++)
+		XVECEXP (op0, 0, i) = op1;
+	    }
+
+	  return op0;
+	}
+      else
+	goto flag_unsupported;
+
+    case CALL_EXPR:
+      /* ??? Maybe handle some builtins?  */
+      return NULL;
+
+      /* SSA names of optimized-away variables can survive un-SSA.  */
+    case SSA_NAME:
+    case ERROR_MARK:
+      return NULL;
+
+
+    default:
+    flag_unsupported:
+#if 0
+      return NULL;
+#endif
+      debug_tree (exp);
+      gcc_unreachable ();
+    }
+}
+
 /* Expand basic block BB from GIMPLE trees to RTL.  */
 
 static basic_block
@@ -1575,6 +2193,36 @@ expand_gimple_basic_block (basic_block b
 	  if (new_bb)
 	    return new_bb;
 	}
+      else if (TREE_CODE (stmt) == VAR_DEBUG_VALUE)
+	{
+	  tree var = VAR_DEBUG_VALUE_VAR (stmt);
+	  tree value = VAR_DEBUG_VALUE_VALUE (stmt);
+	  rtx val;
+
+	  last = get_last_insn ();
+
+	  if (value == VAR_DEBUG_VALUE_NOVALUE)
+	    val = NULL_RTX;
+	  else
+	    val = expand_debug_expr (value);
+
+	  if (!val)
+	    val = gen_rtx_UNKNOWN_VAR_LOC (VOIDmode);
+
+	  val = gen_rtx_VAR_LOCATION
+	    (VOIDmode, var, val, VAR_INIT_STATUS_INITIALIZED);
+
+	  val = emit_debug_insn (val);
+
+	  maybe_dump_rtl_for_tree_stmt (stmt, last);
+
+	  if (last != PREV_INSN (val))
+	    {
+	      debug_generic_expr (stmt);
+	      debug_rtx_range (NEXT_INSN (last), get_last_insn ());
+	      gcc_unreachable ();
+	    }
+	}
       else
 	{
 	  tree call = get_call_expr_in (stmt);
Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/cfgrtl.c	2007-10-01 18:38:14.000000000 -0300
@@ -2703,7 +2703,8 @@ rtl_block_ends_with_call_p (basic_block 
   while (!CALL_P (insn)
 	 && insn != BB_HEAD (bb)
 	 && (keep_with_call_p (insn)
-	     || NOTE_P (insn)))
+	     || NOTE_P (insn)
+	     || DEBUG_INSN_P (insn)))
     insn = PREV_INSN (insn);
   return (CALL_P (insn));
 }
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/rtl.h	2007-10-01 20:45:26.000000000 -0300
@@ -380,9 +380,15 @@ struct rtvec_def GTY(()) {
 /* Predicate yielding nonzero iff X is an insn that cannot jump.  */
 #define NONJUMP_INSN_P(X) (GET_CODE (X) == INSN)
 
+/* Predicate yielding nonzero iff X is a debug note/insn.  */
+#define DEBUG_INSN_P(X) (GET_CODE (X) == DEBUG_INSN)
+
+/* Nonzero if DEBUG_INSN_P may possibly hold.  */
+#define MAY_HAVE_DEBUG_INSNS (flag_var_tracking_assignments)
+
 /* Predicate yielding nonzero iff X is a real insn.  */
 #define INSN_P(X) \
-  (NONJUMP_INSN_P (X) || JUMP_P (X) || CALL_P (X))
+  (NONJUMP_INSN_P (X) || DEBUG_INSN_P (X) || JUMP_P (X) || CALL_P (X))
 
 /* Predicate yielding nonzero iff X is a note insn.  */
 #define NOTE_P(X) (GET_CODE (X) == NOTE)
@@ -753,12 +759,13 @@ extern void rtl_check_failed_flag (const
 #define INSN_CODE(INSN) XINT (INSN, 6)
 
 #define RTX_FRAME_RELATED_P(RTX)					\
-  (RTL_FLAG_CHECK5("RTX_FRAME_RELATED_P", (RTX), INSN, CALL_INSN,	\
-		   JUMP_INSN, BARRIER, SET)->frame_related)
+  (RTL_FLAG_CHECK6("RTX_FRAME_RELATED_P", (RTX), DEBUG_INSN, INSN,	\
+		   CALL_INSN, JUMP_INSN, BARRIER, SET)->frame_related)
 
 /* 1 if RTX is an insn that has been deleted.  */
 #define INSN_DELETED_P(RTX)						\
-  (RTL_FLAG_CHECK6("INSN_DELETED_P", (RTX), INSN, CALL_INSN, JUMP_INSN,	\
+  (RTL_FLAG_CHECK7("INSN_DELETED_P", (RTX), DEBUG_INSN, INSN,		\
+		   CALL_INSN, JUMP_INSN,				\
 		   CODE_LABEL, BARRIER, NOTE)->volatil)
 
 /* 1 if RTX is a call to a const or pure function.  */
@@ -853,16 +860,40 @@ extern const char * const reg_note_name[
    && NOTE_KIND (INSN) == NOTE_INSN_BASIC_BLOCK)
 
 /* Variable declaration and the location of a variable.  */
-#define NOTE_VAR_LOCATION_DECL(INSN)	(XCTREE (XCEXP (INSN, 4, NOTE), \
-						 0, VAR_LOCATION))
-#define NOTE_VAR_LOCATION_LOC(INSN)	(XCEXP (XCEXP (INSN, 4, NOTE),  \
-						1, VAR_LOCATION))
+#define PAT_VAR_LOCATION_DECL(PAT) (XCTREE ((PAT), 0, VAR_LOCATION))
+#define PAT_VAR_LOCATION_LOC(PAT) (XCEXP ((PAT), 1, VAR_LOCATION))
 
 /* Initialization status of the variable in the location.  Status
    can be unknown, uninitialized or initialized.  See enumeration
    type below.  */
-#define NOTE_VAR_LOCATION_STATUS(INSN)  (XCINT (XCEXP (INSN, 4, NOTE), \
-						2, VAR_LOCATION))
+#define PAT_VAR_LOCATION_STATUS(PAT) (XCINT ((PAT), 2, VAR_LOCATION))
+
+/* Accessors for a NOTE_INSN_VAR_LOCATION.  */
+#define NOTE_VAR_LOCATION_DECL(NOTE) \
+  PAT_VAR_LOCATION_DECL (NOTE_VAR_LOCATION (NOTE))
+#define NOTE_VAR_LOCATION_LOC(NOTE) \
+  PAT_VAR_LOCATION_LOC (NOTE_VAR_LOCATION (NOTE))
+#define NOTE_VAR_LOCATION_STATUS(NOTE) \
+  PAT_VAR_LOCATION_STATUS (NOTE_VAR_LOCATION (NOTE))
+
+/* The VAR_LOCATION rtx in a DEBUG_INSN.  */
+#define INSN_VAR_LOCATION(INSN) PATTERN (INSN)
+
+/* Accessors for a tree-expanded var location debug insn.  */
+#define INSN_VAR_LOCATION_DECL(INSN) \
+  PAT_VAR_LOCATION_DECL (INSN_VAR_LOCATION (INSN))
+#define INSN_VAR_LOCATION_LOC(INSN) \
+  PAT_VAR_LOCATION_LOC (INSN_VAR_LOCATION (INSN))
+#define INSN_VAR_LOCATION_STATUS(INSN) \
+  PAT_VAR_LOCATION_STATUS (INSN_VAR_LOCATION (INSN))
+
+/* Expand to the RTL that denotes an unknown variable location in a
+   DEBUG_INSN.  */
+#define gen_rtx_UNKNOWN_VAR_LOC(M) (gen_rtx_CLOBBER (M, const0_rtx))
+
+/* Determine whether X is such an unknown location.  */
+#define VAR_LOC_UNKNOWN_P(X) \
+  (GET_CODE (X) == CLOBBER && XEXP ((X), 0) == const0_rtx)
 
 /* Possible initialization status of a variable.   When requested
    by the user, this information is tracked and recorded in the DWARF
@@ -1238,8 +1269,9 @@ do {						\
 /* During sched, 1 if RTX is an insn that must be scheduled together
    with the preceding insn.  */
 #define SCHED_GROUP_P(RTX)						\
-  (RTL_FLAG_CHECK3("SCHED_GROUP_P", (RTX), INSN, JUMP_INSN, CALL_INSN	\
-		          )->in_struct)
+  (RTL_FLAG_CHECK4("SCHED_GROUP_P", (RTX), DEBUG_INSN, INSN,		\
+		   JUMP_INSN, CALL_INSN					\
+		   )->in_struct)
 
 /* For a SET rtx, SET_DEST is the place that is set
    and SET_SRC is the value it is set to.  */
@@ -1568,6 +1600,9 @@ extern rtx emit_jump_insn_before_setloc 
 extern rtx emit_call_insn_before (rtx, rtx);
 extern rtx emit_call_insn_before_noloc (rtx, rtx);
 extern rtx emit_call_insn_before_setloc (rtx, rtx, int);
+extern rtx emit_debug_insn_before (rtx, rtx);
+extern rtx emit_debug_insn_before_noloc (rtx, rtx);
+extern rtx emit_debug_insn_before_setloc (rtx, rtx, int);
 extern rtx emit_barrier_before (rtx);
 extern rtx emit_label_before (rtx, rtx);
 extern rtx emit_note_before (enum insn_note, rtx);
@@ -1580,10 +1615,14 @@ extern rtx emit_jump_insn_after_setloc (
 extern rtx emit_call_insn_after (rtx, rtx);
 extern rtx emit_call_insn_after_noloc (rtx, rtx);
 extern rtx emit_call_insn_after_setloc (rtx, rtx, int);
+extern rtx emit_debug_insn_after (rtx, rtx);
+extern rtx emit_debug_insn_after_noloc (rtx, rtx);
+extern rtx emit_debug_insn_after_setloc (rtx, rtx, int);
 extern rtx emit_barrier_after (rtx);
 extern rtx emit_label_after (rtx, rtx);
 extern rtx emit_note_after (enum insn_note, rtx);
 extern rtx emit_insn (rtx);
+extern rtx emit_debug_insn (rtx);
 extern rtx emit_jump_insn (rtx);
 extern rtx emit_call_insn (rtx);
 extern rtx emit_label (rtx);
@@ -1591,6 +1630,7 @@ extern rtx emit_barrier (void);
 extern rtx emit_note (enum insn_note);
 extern rtx emit_note_copy (rtx);
 extern rtx make_insn_raw (rtx);
+extern rtx make_debug_insn_raw (rtx);
 extern rtx make_jump_insn_raw (rtx);
 extern void add_function_usage_to (rtx, rtx);
 extern rtx last_call_insn (void);
Index: gcc/recog.c
===================================================================
--- gcc/recog.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/recog.c	2007-10-01 18:38:14.000000000 -0300
@@ -373,6 +373,8 @@ verify_changes (int num)
 	  if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
 	    break;
 	}
+      else if (DEBUG_INSN_P (object))
+	continue;
       else if (insn_invalid_p (object))
 	{
 	  rtx pat = PATTERN (object);
@@ -413,7 +415,8 @@ verify_changes (int num)
 	      validate_change (object, &PATTERN (object), newpat, 1);
 	      continue;
 	    }
-	  else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+	  else if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
+		   || GET_CODE (pat) == VAR_LOCATION)
 	    /* If this insn is a CLOBBER or USE, it is always valid, but is
 	       never recognized.  */
 	    continue;
@@ -1940,6 +1943,7 @@ extract_insn (rtx insn)
     case ASM_INPUT:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
+    case VAR_LOCATION:
       return;
 
     case SET:
@@ -2946,7 +2950,7 @@ peephole2_optimize (void)
       for (insn = BB_END (bb); ; insn = prev)
 	{
 	  prev = PREV_INSN (insn);
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	    {
 	      rtx try, before_try, x;
 	      int match_len;
Index: gcc/dce.c
===================================================================
--- gcc/dce.c.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/dce.c	2007-10-01 18:38:14.000000000 -0300
@@ -104,6 +104,7 @@ deletable_insn_p (rtx insn, bool fast)
   switch (GET_CODE (body))
     {
     case USE:
+    case VAR_LOCATION:
       return false;
 
     case CLOBBER:
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/reload1.c	2007-10-01 18:38:14.000000000 -0300
@@ -791,7 +791,7 @@ reload (rtx first, int global)
 	  && GET_MODE (insn) != VOIDmode)
 	PUT_MODE (insn, VOIDmode);
 
-      if (INSN_P (insn))
+      if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	scan_paradoxical_subregs (PATTERN (insn));
 
       if (set != 0 && REG_P (SET_DEST (set)))
@@ -3071,7 +3071,8 @@ eliminate_regs_in_insn (rtx insn, int re
 		  || GET_CODE (PATTERN (insn)) == CLOBBER
 		  || GET_CODE (PATTERN (insn)) == ADDR_VEC
 		  || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-		  || GET_CODE (PATTERN (insn)) == ASM_INPUT);
+		  || GET_CODE (PATTERN (insn)) == ASM_INPUT
+		  || DEBUG_INSN_P (insn));
       return 0;
     }
 
Index: gcc/cse.c
===================================================================
--- gcc/cse.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/cse.c	2007-10-01 18:38:14.000000000 -0300
@@ -4119,6 +4119,8 @@ cse_insn (rtx insn, rtx libcall_insn)
       apply_change_group ();
       fold_rtx (x, insn);
     }
+  else if (DEBUG_INSN_P (insn))
+    canon_reg (PATTERN (insn), insn);
 
   /* Store the equivalent value in SRC_EQV, if different, or if the DEST
      is a STRICT_LOW_PART.  The latter condition is necessary because SRC_EQV
@@ -5534,7 +5536,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 	    {
 	      prev = PREV_INSN (prev);
 	    }
-	  while (prev != bb_head && NOTE_P (prev));
+	  while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
 
 	  /* Do not swap the registers around if the previous instruction
 	     attaches a REG_EQUIV note to REG1.
@@ -5977,6 +5979,7 @@ cse_extended_basic_block (struct cse_bas
 	     FIXME: This is a real kludge and needs to be done some other
 		    way.  */
 	  if (INSN_P (insn)
+	      && !DEBUG_INSN_P (insn)
 	      && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
 	    {
 	      flush_hash_table ();
@@ -6422,6 +6425,20 @@ insn_live_p (rtx insn, int *counts)
 	}
       return false;
     }
+  else if (DEBUG_INSN_P (insn))
+    {
+      rtx next;
+
+      for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
+	if (NOTE_P (next))
+	  continue;
+	else if (!DEBUG_INSN_P (next))
+	  return true;
+	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
+	  return false;
+
+      return true;
+    }
   else
     return true;
 }
@@ -6494,6 +6511,7 @@ delete_trivially_dead_insns (rtx insns, 
   int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
+
   /* First count the number of times each register is used.  */
   counts = XCNEWVEC (int, nreg);
   for (insn = insns; insn; insn = NEXT_INSN (insn))
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/emit-rtl.c	2007-10-01 20:42:47.000000000 -0300
@@ -2506,6 +2506,7 @@ repeat:
 	return;
       break;
 
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -2612,6 +2613,7 @@ repeat:
     case CC0:
       return;
 
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -2682,6 +2684,7 @@ set_used_flags (rtx x)
     case CC0:
       return;
 
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -2987,6 +2990,7 @@ active_insn_p (const_rtx insn)
 {
   return (CALL_P (insn) || JUMP_P (insn)
 	  || (NONJUMP_INSN_P (insn)
+	      && !DEBUG_INSN_P (insn)
 	      && (! reload_completed
 		  || (GET_CODE (PATTERN (insn)) != USE
 		      && GET_CODE (PATTERN (insn)) != CLOBBER))));
@@ -3422,6 +3426,25 @@ make_insn_raw (rtx pattern)
   return insn;
 }
 
+/* Like `make_insn_raw' but make a DEBUG_INSN instead of an insn.  */
+
+rtx
+make_debug_insn_raw (rtx pattern)
+{
+  rtx insn;
+
+  insn = rtx_alloc (DEBUG_INSN);
+  INSN_UID (insn) = cur_insn_uid++;
+
+  PATTERN (insn) = pattern;
+  INSN_CODE (insn) = -1;
+  REG_NOTES (insn) = NULL;
+  INSN_LOCATOR (insn) = curr_insn_locator ();
+  BLOCK_FOR_INSN (insn) = NULL;
+
+  return insn;
+}
+
 /* Like `make_insn_raw' but make a JUMP_INSN instead of an insn.  */
 
 rtx
@@ -3608,7 +3631,8 @@ add_insn_before (rtx insn, rtx before, b
 
 /* Replace insn with an deleted instruction note.  */
 
-void set_insn_deleted (rtx insn)
+void
+set_insn_deleted (rtx insn)
 {
   df_insn_delete (BLOCK_FOR_INSN (insn), INSN_UID (insn));
   PUT_CODE (insn, NOTE);
@@ -3837,6 +3861,7 @@ emit_insn_before_noloc (rtx x, rtx befor
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -3880,6 +3905,7 @@ emit_jump_insn_before_noloc (rtx x, rtx 
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -3923,6 +3949,7 @@ emit_call_insn_before_noloc (rtx x, rtx 
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -3954,6 +3981,50 @@ emit_call_insn_before_noloc (rtx x, rtx 
   return last;
 }
 
+/* Make an instruction with body X and code DEBUG_INSN
+   and output it before the instruction BEFORE.  */
+
+rtx
+emit_debug_insn_before_noloc (rtx x, rtx before)
+{
+  rtx last = NULL_RTX, insn;
+
+  gcc_assert (before);
+
+  switch (GET_CODE (x))
+    {
+    case DEBUG_INSN:
+    case INSN:
+    case JUMP_INSN:
+    case CALL_INSN:
+    case CODE_LABEL:
+    case BARRIER:
+    case NOTE:
+      insn = x;
+      while (insn)
+	{
+	  rtx next = NEXT_INSN (insn);
+	  add_insn_before (insn, before, NULL);
+	  last = insn;
+	  insn = next;
+	}
+      break;
+
+#ifdef ENABLE_RTL_CHECKING
+    case SEQUENCE:
+      gcc_unreachable ();
+      break;
+#endif
+
+    default:
+      last = make_debug_insn_raw (x);
+      add_insn_before (last, before, NULL);
+      break;
+    }
+
+  return last;
+}
+
 /* Make an insn of code BARRIER
    and output it before the insn BEFORE.  */
 
@@ -4059,6 +4130,7 @@ emit_insn_after_noloc (rtx x, rtx after,
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4096,6 +4168,7 @@ emit_jump_insn_after_noloc (rtx x, rtx a
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4132,6 +4205,7 @@ emit_call_insn_after_noloc (rtx x, rtx a
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4156,6 +4230,43 @@ emit_call_insn_after_noloc (rtx x, rtx a
   return last;
 }
 
+/* Make an instruction with body X and code CALL_INSN
+   and output it after the instruction AFTER.  */
+
+rtx
+emit_debug_insn_after_noloc (rtx x, rtx after)
+{
+  rtx last;
+
+  gcc_assert (after);
+
+  switch (GET_CODE (x))
+    {
+    case DEBUG_INSN:
+    case INSN:
+    case JUMP_INSN:
+    case CALL_INSN:
+    case CODE_LABEL:
+    case BARRIER:
+    case NOTE:
+      last = emit_insn_after_1 (x, after, NULL);
+      break;
+
+#ifdef ENABLE_RTL_CHECKING
+    case SEQUENCE:
+      gcc_unreachable ();
+      break;
+#endif
+
+    default:
+      last = make_debug_insn_raw (x);
+      add_insn_after (last, after, NULL);
+      break;
+    }
+
+  return last;
+}
+
 /* Make an insn of code BARRIER
    and output it after the insn AFTER.  */
 
@@ -4294,6 +4405,37 @@ emit_call_insn_after (rtx pattern, rtx a
     return emit_call_insn_after_noloc (pattern, after);
 }
 
+/* Like emit_debug_insn_after_noloc, but set INSN_LOCATOR according to SCOPE.  */
+rtx
+emit_debug_insn_after_setloc (rtx pattern, rtx after, int loc)
+{
+  rtx last = emit_debug_insn_after_noloc (pattern, after);
+
+  if (pattern == NULL_RTX || !loc)
+    return last;
+
+  after = NEXT_INSN (after);
+  while (1)
+    {
+      if (active_insn_p (after) && !INSN_LOCATOR (after))
+	INSN_LOCATOR (after) = loc;
+      if (after == last)
+	break;
+      after = NEXT_INSN (after);
+    }
+  return last;
+}
+
+/* Like emit_debug_insn_after_noloc, but set INSN_LOCATOR according to AFTER.  */
+rtx
+emit_debug_insn_after (rtx pattern, rtx after)
+{
+  if (INSN_P (after))
+    return emit_debug_insn_after_setloc (pattern, after, INSN_LOCATOR (after));
+  else
+    return emit_debug_insn_after_noloc (pattern, after);
+}
+
 /* Like emit_insn_before_noloc, but set INSN_LOCATOR according to SCOPE.  */
 rtx
 emit_insn_before_setloc (rtx pattern, rtx before, int loc)
@@ -4393,6 +4535,39 @@ emit_call_insn_before (rtx pattern, rtx 
   else
     return emit_call_insn_before_noloc (pattern, before);
 }
+
+/* like emit_insn_before_noloc, but set insn_locator according to scope.  */
+rtx
+emit_debug_insn_before_setloc (rtx pattern, rtx before, int loc)
+{
+  rtx first = PREV_INSN (before);
+  rtx last = emit_debug_insn_before_noloc (pattern, before);
+
+  if (pattern == NULL_RTX)
+    return last;
+
+  first = NEXT_INSN (first);
+  while (1)
+    {
+      if (active_insn_p (first) && !INSN_LOCATOR (first))
+	INSN_LOCATOR (first) = loc;
+      if (first == last)
+	break;
+      first = NEXT_INSN (first);
+    }
+  return last;
+}
+
+/* like emit_debug_insn_before_noloc,
+   but set insn_locator according to before.  */
+rtx
+emit_debug_insn_before (rtx pattern, rtx before)
+{
+  if (INSN_P (before))
+    return emit_debug_insn_before_setloc (pattern, before, INSN_LOCATOR (before));
+  else
+    return emit_debug_insn_before_noloc (pattern, before);
+}
 
 /* Take X and emit it at the end of the doubly-linked
    INSN list.
@@ -4410,6 +4585,7 @@ emit_insn (rtx x)
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4441,6 +4617,52 @@ emit_insn (rtx x)
   return last;
 }
 
+/* Make an insn of code DEBUG_INSN with pattern X
+   and add it to the end of the doubly-linked list.  */
+
+rtx
+emit_debug_insn (rtx x)
+{
+  rtx last = last_insn;
+  rtx insn;
+
+  if (x == NULL_RTX)
+    return last;
+
+  switch (GET_CODE (x))
+    {
+    case DEBUG_INSN:
+    case INSN:
+    case JUMP_INSN:
+    case CALL_INSN:
+    case CODE_LABEL:
+    case BARRIER:
+    case NOTE:
+      insn = x;
+      while (insn)
+	{
+	  rtx next = NEXT_INSN (insn);
+	  add_insn (insn);
+	  last = insn;
+	  insn = next;
+	}
+      break;
+
+#ifdef ENABLE_RTL_CHECKING
+    case SEQUENCE:
+      gcc_unreachable ();
+      break;
+#endif
+
+    default:
+      last = make_debug_insn_raw (x);
+      add_insn (last);
+      break;
+    }
+
+  return last;
+}
+
 /* Make an insn of code JUMP_INSN with pattern X
    and add it to the end of the doubly-linked list.  */
 
@@ -4451,6 +4673,7 @@ emit_jump_insn (rtx x)
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4492,6 +4715,7 @@ emit_call_insn (rtx x)
 
   switch (GET_CODE (x))
     {
+    case DEBUG_INSN:
     case INSN:
     case JUMP_INSN:
     case CALL_INSN:
@@ -4713,6 +4937,8 @@ emit (rtx x)
       }
     case CALL_INSN:
       return emit_call_insn (x);
+    case DEBUG_INSN:
+      return emit_debug_insn (x);
     default:
       gcc_unreachable ();
     }
@@ -5507,6 +5733,10 @@ emit_copy_of_insn_after (rtx insn, rtx a
       new = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
       break;
 
+    case DEBUG_INSN:
+      new = emit_debug_insn_after (copy_insn (PATTERN (insn)), after);
+      break;
+
     case CALL_INSN:
       new = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
       if (CALL_INSN_FUNCTION_USAGE (insn))
Index: gcc/reg-stack.c
===================================================================
--- gcc/reg-stack.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/reg-stack.c	2007-10-01 18:38:14.000000000 -0300
@@ -310,7 +310,7 @@ stack_regs_mentioned (const_rtx insn)
   unsigned int uid, max;
   int test;
 
-  if (! INSN_P (insn) || !stack_regs_mentioned_data)
+  if (! INSN_P (insn) /* || DEBUG_INSN_P (insn) */ || !stack_regs_mentioned_data)
     return 0;
 
   uid = INSN_UID (insn);
@@ -1361,6 +1361,16 @@ subst_stack_regs_pat (rtx insn, stack re
 	 since the REG_DEAD notes are not issued.)  */
       break;
 
+    case VAR_LOCATION:
+      for (dest = &REG_NOTES (insn); *dest; dest = &XEXP (*dest, 1))
+	if (REG_NOTE_KIND (*dest) == REG_DEAD
+	    && STACK_REG_P (*(src = &XEXP (*dest, 0)))
+	    && TEST_HARD_REG_BIT (regstack->reg_set, REGNO (*src)))
+	  /* ??? This is not right.  We want to *avoid* emitting the
+	     pop and the corresponding push.  */
+	  emit_pop_insn (insn, regstack, *src, EMIT_AFTER);
+      break;
+
     case CLOBBER:
       {
 	rtx note;
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/var-tracking.c	2007-10-01 18:38:14.000000000 -0300
@@ -112,6 +112,9 @@ enum micro_operation_type
   MO_USE,	/* Use location (REG or MEM).  */
   MO_USE_NO_VAR,/* Use location which is not associated with a variable
 		   or the variable is not trackable.  */
+  MO_LOC_MAIN,	/* Use location from the debug insn.  */
+  MO_LOC_USE,	/* The location appears in a debug insn, but it's not
+		   the location of the debug insn's decl.  */
   MO_SET,	/* Set location.  */
   MO_COPY,	/* Copy the same portion of a variable from one
 		   location to another.  */
@@ -836,14 +839,12 @@ var_debug_decl (tree decl)
   return decl;
 }
 
-/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+/* Set the register LOC to contain DECL, OFFSET.  */
 
 static void
-var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized, 
-	     rtx set_src)
+var_reg_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+		  tree decl, HOST_WIDE_INT offset, rtx set_src)
 {
-  tree decl = REG_EXPR (loc);
-  HOST_WIDE_INT offset = REG_OFFSET (loc);
   attrs node;
 
   decl = var_debug_decl (decl);
@@ -856,6 +857,18 @@ var_reg_set (dataflow_set *set, rtx loc,
   set_variable_part (set, loc, decl, offset, initialized, set_src);
 }
 
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+
+static void
+var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+	     rtx set_src)
+{
+  tree decl = REG_EXPR (loc);
+  HOST_WIDE_INT offset = REG_OFFSET (loc);
+
+  var_reg_decl_set (set, loc, initialized, decl, offset, set_src);
+}
+
 static int
 get_init_value (dataflow_set *set, rtx loc, tree decl)
 {
@@ -975,6 +988,17 @@ var_regno_delete (dataflow_set *set, int
   *reg = NULL;
 }
 
+/* Set the location of DECL, OFFSET as the MEM LOC.  */
+
+static void
+var_mem_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
+		  tree decl, HOST_WIDE_INT offset, rtx set_src)
+{
+  decl = var_debug_decl (decl);
+
+  set_variable_part (set, loc, decl, offset, initialized, set_src);
+}
+
 /* Set the location part of variable MEM_EXPR (LOC) in dataflow set
    SET to LOC.
    Adjust the address first if it is stack pointer based.  */
@@ -986,9 +1010,7 @@ var_mem_set (dataflow_set *set, rtx loc,
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
 
-  decl = var_debug_decl (decl);
-
-  set_variable_part (set, loc, decl, offset, initialized, set_src);
+  var_mem_decl_set (set, loc, initialized, decl, offset, set_src);
 }
 
 /* Delete and set the location part of variable MEM_EXPR (LOC) in
@@ -1672,27 +1694,72 @@ same_variable_part_p (rtx loc, tree expr
   return (expr == expr2 && offset == offset2);
 }
 
+/* Determine what kind of micro operation to choose for a USE.  Return
+   MO_CLOBBER if no micro operation is to be generated.  */
 
-/* Count uses (register and memory references) LOC which will be tracked.
-   INSN is instruction which the LOC is part of.  */
-
-static int
-count_uses (rtx *loc, void *insn)
+static enum micro_operation_type
+use_type (rtx *loc, rtx insn)
 {
-  basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
+  tree expr;
+
+  if (DEBUG_INSN_P (insn))
+    {
+      if (!VAR_LOC_UNKNOWN_P (*loc) && !REG_P (*loc) && !MEM_P (*loc))
+	return MO_CLOBBER;
+
+      expr = INSN_VAR_LOCATION_DECL (insn);
 
-  if (REG_P (*loc))
+      if (!track_expr_p (expr))
+	return MO_CLOBBER;
+
+      if (&INSN_VAR_LOCATION_LOC (insn) == loc)
+	return MO_LOC_MAIN;
+      else
+	return MO_LOC_USE;
+    }
+  else if (REG_P (*loc))
     {
       gcc_assert (REGNO (*loc) < FIRST_PSEUDO_REGISTER);
-      VTI (bb)->n_mos++;
+
+      expr = REG_EXPR (*loc);
+
+      if (!expr)
+	return MO_USE_NO_VAR;
+      else if (var_debug_value_for_decl (expr))
+	return MO_CLOBBER;
+      else if (track_expr_p (expr))
+	return MO_USE;
+      else
+	return MO_USE_NO_VAR;
     }
-  else if (MEM_P (*loc)
-	   && MEM_EXPR (*loc)
-	   && track_expr_p (MEM_EXPR (*loc)))
+  else if (MEM_P (*loc))
     {
-      VTI (bb)->n_mos++;
+      expr = MEM_EXPR (*loc);
+
+      if (!expr)
+	return MO_CLOBBER;
+      else if (var_debug_value_for_decl (expr))
+	return MO_CLOBBER;
+      else if (track_expr_p (expr))
+	return MO_USE;
+      else
+	return MO_CLOBBER;
     }
 
+  return MO_CLOBBER;
+}
+
+/* Count uses (register and memory references) LOC which will be tracked.
+   INSN is instruction which the LOC is part of.  */
+
+static int
+count_uses (rtx *loc, void *data)
+{
+  rtx insn = (rtx) data;
+
+  if (use_type (loc, insn) != MO_CLOBBER)
+    VTI (BLOCK_FOR_INSN (insn))->n_mos++;
+
   return 0;
 }
 
@@ -1717,28 +1784,19 @@ count_stores (rtx loc, const_rtx expr AT
    to VTI (bb)->mos.  INSN is instruction which the LOC is part of.  */
 
 static int
-add_uses (rtx *loc, void *insn)
+add_uses (rtx *loc, void *data)
 {
-  if (REG_P (*loc))
-    {
-      basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
-      micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
+  rtx insn = (rtx)data;
+  enum micro_operation_type type = use_type (loc, insn);
 
-      mo->type = ((REG_EXPR (*loc) && track_expr_p (REG_EXPR (*loc)))
-		  ? MO_USE : MO_USE_NO_VAR);
-      mo->u.loc = *loc;
-      mo->insn = (rtx) insn;
-    }
-  else if (MEM_P (*loc)
-	   && MEM_EXPR (*loc)
-	   && track_expr_p (MEM_EXPR (*loc)))
+  if (type != MO_CLOBBER)
     {
-      basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
+      basic_block bb = BLOCK_FOR_INSN (insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
-      mo->type = MO_USE;
+      mo->type = type;
       mo->u.loc = *loc;
-      mo->insn = (rtx) insn;
+      mo->insn = insn;
     }
 
   return 0;
@@ -1759,6 +1817,9 @@ add_uses_1 (rtx *x, void *insn)
 static void
 add_stores (rtx loc, const_rtx expr, void *insn)
 {
+  if (use_type (&loc, (rtx) insn) == MO_CLOBBER)
+    return;
+
   if (REG_P (loc))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
@@ -1944,6 +2005,32 @@ compute_bb_dataflow (basic_block bb)
 	    }
 	    break;
 
+	  case MO_LOC_MAIN:
+	    {
+	      rtx loc = VTI (bb)->mos[i].u.loc;
+	      rtx insn = VTI (bb)->mos[i].insn;
+
+	      if (VAR_LOC_UNKNOWN_P (loc))
+		clobber_variable_part (out, NULL_RTX,
+				       INSN_VAR_LOCATION_DECL (insn), 0,
+				       NULL_RTX);
+	      else if (REG_P (loc))
+		var_reg_decl_set (out, loc, VAR_INIT_STATUS_INITIALIZED,
+				  INSN_VAR_LOCATION_DECL (insn), 0, NULL_RTX);
+	      else if (MEM_P (loc))
+		var_mem_decl_set (out, loc, VAR_INIT_STATUS_INITIALIZED,
+				  INSN_VAR_LOCATION_DECL (insn), 0, NULL_RTX);
+	    }
+	    break;
+
+	  case MO_LOC_USE:
+	    {
+	      /* ??? Note that this reg or mem is part of the value of
+		 decl such that, when it's set, we know the variable
+		 no longer holds its value.  */
+	    }
+	    break;
+
 	  case MO_SET:
 	    {
 	      rtx loc = VTI (bb)->mos[i].u.loc;
@@ -2867,8 +2954,8 @@ emit_notes_in_bb (basic_block bb)
 	  case MO_USE:
 	    {
 	      rtx loc = VTI (bb)->mos[i].u.loc;
-      
 	      enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
 	      if (! flag_var_tracking_uninit)
 		status = VAR_INIT_STATUS_INITIALIZED;
 	      if (GET_CODE (loc) == REG)
@@ -2880,6 +2967,42 @@ emit_notes_in_bb (basic_block bb)
 	    }
 	    break;
 
+	  case MO_LOC_MAIN:
+	    {
+	      rtx loc = VTI (bb)->mos[i].u.loc;
+	      rtx insn = VTI (bb)->mos[i].insn, next;
+
+	      if (VAR_LOC_UNKNOWN_P (loc))
+		clobber_variable_part (&set, NULL_RTX,
+				       INSN_VAR_LOCATION_DECL (insn), 0,
+				       NULL_RTX);
+	      else if (REG_P (loc))
+		var_reg_decl_set (&set, loc, VAR_INIT_STATUS_INITIALIZED,
+				  INSN_VAR_LOCATION_DECL (insn), 0, NULL_RTX);
+	      else if (MEM_P (loc))
+		var_mem_decl_set (&set, loc, VAR_INIT_STATUS_INITIALIZED,
+				  INSN_VAR_LOCATION_DECL (insn), 0, NULL_RTX);
+
+	      for (next = NEXT_INSN (insn);
+		   next && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (next);
+		   next = NEXT_INSN (next))
+		if (DEBUG_INSN_P (next))
+		  insn = next;
+		else if (!NOTE_P (next))
+		  break;
+
+	      emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+	    }
+	    break;
+
+	  case MO_LOC_USE:
+	    {
+	      /* ??? Note that this reg or mem is part of the value of
+		 decl such that, when it's set, we know the variable
+		 no longer holds its value.  */
+	    }
+	    break;
+
 	  case MO_SET:
 	    {
 	      rtx loc = VTI (bb)->mos[i].u.loc;
@@ -3087,6 +3210,7 @@ vt_initialize (void)
     {
       rtx insn;
       HOST_WIDE_INT pre, post = 0;
+      int count;
 
       /* Count the number of micro operations.  */
       VTI (bb)->n_mos = 0;
@@ -3110,6 +3234,8 @@ vt_initialize (void)
 	    }
 	}
 
+      count = VTI (bb)->n_mos;
+
       /* Add the micro-operations to the array.  */
       VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
       VTI (bb)->n_mos = 0;
@@ -3137,12 +3263,13 @@ vt_initialize (void)
 	      note_uses (&PATTERN (insn), add_uses_1, insn);
 	      n2 = VTI (bb)->n_mos - 1;
 
-	      /* Order the MO_USEs to be before MO_USE_NO_VARs.  */
+	      /* Order the MO_USEs to be before MO_USE_NO_VARs,
+		 MO_LOC_MAIN and MO_LOC_USE.  */
 	      while (n1 < n2)
 		{
 		  while (n1 < n2 && VTI (bb)->mos[n1].type == MO_USE)
 		    n1++;
-		  while (n1 < n2 && VTI (bb)->mos[n2].type == MO_USE_NO_VAR)
+		  while (n1 < n2 && VTI (bb)->mos[n2].type != MO_USE)
 		    n2--;
 		  if (n1 < n2)
 		    {
@@ -3197,6 +3324,7 @@ vt_initialize (void)
 		}
 	    }
 	}
+      gcc_assert (count == VTI (bb)->n_mos);
     }
 
   /* Init the IN and OUT sets.  */
@@ -3219,6 +3347,38 @@ vt_initialize (void)
   vt_add_function_parameters ();
 }
 
+/* Get rid of all debug insns from the insn stream.  */
+
+static void
+delete_debug_insns (void)
+{
+  basic_block bb;
+  rtx insn, next;
+
+  if (!MAY_HAVE_DEBUG_INSNS)
+    return;
+
+  FOR_EACH_BB (bb)
+    {
+      FOR_BB_INSNS_SAFE (bb, insn, next)
+	if (DEBUG_INSN_P (insn))
+	  delete_insn (insn);
+    }
+}
+
+/* Run a fast, BB-local only version of var tracking, to take care of
+   information that we don't do global analysis on, such that not all
+   information is lost.  If SKIPPED holds, we're skipping the global
+   pass entirely, so we should try to use information it would have
+   handled as well..  */
+
+static void
+vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
+{
+  /* ??? Just skip it all for now.  */
+  delete_debug_insns ();
+}
+
 /* Free the data structures needed for variable tracking.  */
 
 static void
@@ -3249,7 +3409,10 @@ unsigned int
 variable_tracking_main (void)
 {
   if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
-    return 0;
+    {
+      vt_debug_insns_local (true);
+      return 0;
+    }
 
   mark_dfs_back_edges ();
   vt_initialize ();
@@ -3258,6 +3421,7 @@ variable_tracking_main (void)
       if (!vt_stack_adjustments ())
 	{
 	  vt_finalize ();
+	  vt_debug_insns_local (true);
 	  return 0;
 	}
     }
@@ -3272,6 +3436,7 @@ variable_tracking_main (void)
     }
 
   vt_finalize ();
+  vt_debug_insns_local (false);
   return 0;
 }
 
Index: gcc/final.c
===================================================================
--- gcc/final.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/final.c	2007-10-01 18:38:14.000000000 -0300
@@ -407,7 +407,8 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UN
 
       case INSN:
 	body = PATTERN (insn);
-	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
+	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER
+	    || DEBUG_INSN_P (insn))
 	  return 0;
 
 	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
Index: gcc/lower-subreg.c
===================================================================
--- gcc/lower-subreg.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/lower-subreg.c	2007-10-01 18:38:14.000000000 -0300
@@ -533,6 +533,32 @@ resolve_subreg_use (rtx *px, void *data)
   return 0;
 }
 
+/* This is called via for_each_rtx.  Look for SUBREGs which can be
+   decomposed and decomposed REGs that need copying.  */
+
+static int
+adjust_decomposed_uses (rtx *px, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x = *px;
+
+  if (x == NULL_RTX)
+    return 0;
+
+  if (resolve_subreg_p (x))
+    {
+      x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
+				   SUBREG_BYTE (x));
+
+      if (x)
+	*px = x;
+    }
+
+  if (resolve_reg_p (x))
+    *px = copy_rtx (x);
+
+  return 0;
+}
+
 /* We are deleting INSN.  Move any EH_REGION notes to INSNS.  */
 
 static void
@@ -960,6 +986,18 @@ resolve_use (rtx pat, rtx insn)
   return false;
 }
 
+/* A VAR_LOCATION can be simplified.  */
+
+static void
+resolve_debug (rtx insn)
+{
+  for_each_rtx (&PATTERN (insn), adjust_decomposed_uses, NULL_RTX);
+
+  df_insn_rescan (insn);
+
+  resolve_reg_notes (insn);
+}
+
 /* Checks if INSN is a decomposable multiword-shift or zero-extend and
    sets the decomposable_context bitmap accordingly.  A non-zero value
    is returned if a decomposable insn has been found.  */
@@ -1270,6 +1308,8 @@ decompose_multiword_subregs (void)
 		resolve_clobber (pat, insn);
 	      else if (GET_CODE (pat) == USE)
 		resolve_use (pat, insn);
+	      else if (DEBUG_INSN_P (insn))
+		resolve_debug (insn);
 	      else
 		{
 		  rtx set;
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/print-rtl.c	2007-10-01 18:38:14.000000000 -0300
@@ -207,6 +207,21 @@ print_rtx (const_rtx in_rtx)
 	  /* For other rtl, print the mode if it's not VOID.  */
 	  else if (GET_MODE (in_rtx) != VOIDmode)
 	    fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
+
+#ifndef GENERATOR_FILE
+	  if (GET_CODE (in_rtx) == VAR_LOCATION)
+	    {
+	      print_mem_expr (outfile, PAT_VAR_LOCATION_DECL (in_rtx));
+	      fputc (' ', outfile);
+	      print_rtx (PAT_VAR_LOCATION_LOC (in_rtx));
+	      if (PAT_VAR_LOCATION_STATUS (in_rtx)
+		  == VAR_INIT_STATUS_UNINITIALIZED)
+		fprintf (outfile, " [uninit]");
+	      fputc (')', outfile);
+	      sawclose = 1;
+	      i = GET_RTX_LENGTH (VAR_LOCATION);
+	    }
+#endif
 	}
     }
 
@@ -320,14 +335,8 @@ print_rtx (const_rtx in_rtx)
 		
 	      case NOTE_INSN_VAR_LOCATION:
 #ifndef GENERATOR_FILE
-		fprintf (outfile, " (");
-		print_mem_expr (outfile, NOTE_VAR_LOCATION_DECL (in_rtx));
-		fprintf (outfile, " ");
-		print_rtx (NOTE_VAR_LOCATION_LOC (in_rtx));
-		if (NOTE_VAR_LOCATION_STATUS (in_rtx) == 
-		                                 VAR_INIT_STATUS_UNINITIALIZED)
-		  fprintf (outfile, " [uninit]");
-		fprintf (outfile, ")");
+		fputc (' ', outfile);
+		print_rtx (NOTE_VAR_LOCATION (in_rtx));
 #endif
 		break;
 
Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/ifcvt.c	2007-10-01 18:38:14.000000000 -0300
@@ -193,7 +193,7 @@ first_active_insn (basic_block bb)
       insn = NEXT_INSN (insn);
     }
 
-  while (NOTE_P (insn))
+  while (NOTE_P (insn) || DEBUG_INSN_P (insn))
     {
       if (insn == BB_END (bb))
 	return NULL_RTX;
@@ -216,6 +216,7 @@ last_active_insn (basic_block bb, int sk
 
   while (NOTE_P (insn)
 	 || JUMP_P (insn)
+	 || DEBUG_INSN_P (insn)
 	 || (skip_use_p
 	     && NONJUMP_INSN_P (insn)
 	     && GET_CODE (PATTERN (insn)) == USE))
@@ -268,7 +269,7 @@ cond_exec_process_insns (ce_if_block_t *
 
   for (insn = start; ; insn = NEXT_INSN (insn))
     {
-      if (NOTE_P (insn))
+      if (NOTE_P (insn) || DEBUG_INSN_P (insn))
 	goto insn_done;
 
       gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
@@ -2196,6 +2197,8 @@ noce_process_if_block (struct noce_if_in
   else
     {
       insn_b = prev_nonnote_insn (if_info->cond_earliest);
+      while (insn_b && DEBUG_INSN_P (insn_b))
+	insn_b = PREV_INSN (insn_b);
       /* We're going to be moving the evaluation of B down from above
 	 COND_EARLIEST to JUMP.  Make sure the relevant data is still
 	 intact.  */
@@ -2400,6 +2403,8 @@ check_cond_move_block (basic_block bb, r
    /* We can only handle simple jumps at the end of the basic block.
       It is almost impossible to update the CFG otherwise.  */
   insn = BB_END (bb);
+  while (DEBUG_INSN_P (insn))
+    insn = PREV_INSN (insn);
   if (JUMP_P (insn) && !onlyjump_p (insn))
     return FALSE;
 
@@ -2407,7 +2412,7 @@ check_cond_move_block (basic_block bb, r
     {
       rtx set, dest, src;
 
-      if (!INSN_P (insn) || JUMP_P (insn))
+      if (!INSN_P (insn) || DEBUG_INSN_P (insn) || JUMP_P (insn))
 	continue;
       set = single_set (insn);
       if (!set)
@@ -2485,7 +2490,8 @@ cond_move_convert_if_block (struct noce_
       rtx set, target, dest, t, e;
       unsigned int regno;
 
-      if (!INSN_P (insn) || JUMP_P (insn))
+      /* ??? Maybe emit conditional debug insn?  */
+      if (!INSN_P (insn) || DEBUG_INSN_P (insn) || JUMP_P (insn))
 	continue;
       set = single_set (insn);
       gcc_assert (set && REG_P (SET_DEST (set)));
@@ -3026,6 +3032,7 @@ block_jumps_and_fallthru_p (basic_block 
 
       if (INSN_P (insn)
 	  && !JUMP_P (insn)
+	  && !DEBUG_INSN_P (insn)
 	  && GET_CODE (PATTERN (insn)) != USE
 	  && GET_CODE (PATTERN (insn)) != CLOBBER)
 	n_insns++;
@@ -3689,6 +3696,9 @@ dead_or_predicable (basic_block test_bb,
   head = BB_HEAD (merge_bb);
   end = BB_END (merge_bb);
 
+  while (DEBUG_INSN_P (end) && end != head)
+    end = PREV_INSN (end);
+
   /* If merge_bb ends with a tablejump, predicating/moving insn's
      into test_bb and then deleting merge_bb will result in the jumptable
      that follows merge_bb being removed along with merge_bb and then we
@@ -3698,6 +3708,8 @@ dead_or_predicable (basic_block test_bb,
 
   if (LABEL_P (head))
     head = NEXT_INSN (head);
+  while (DEBUG_INSN_P (head) && head != end)
+    head = NEXT_INSN (head);
   if (NOTE_P (head))
     {
       if (head == end)
@@ -3706,6 +3718,8 @@ dead_or_predicable (basic_block test_bb,
 	  goto no_body;
 	}
       head = NEXT_INSN (head);
+      while (DEBUG_INSN_P (head) && head != end)
+	head = NEXT_INSN (head);
     }
 
   if (JUMP_P (end))
@@ -3716,6 +3730,8 @@ dead_or_predicable (basic_block test_bb,
 	  goto no_body;
 	}
       end = PREV_INSN (end);
+      while (DEBUG_INSN_P (end) && end != head)
+	end = PREV_INSN (end);
     }
 
   /* Disable handling dead code by conditional execution if the machine needs
@@ -3773,7 +3789,7 @@ dead_or_predicable (basic_block test_bb,
 	{
 	  if (CALL_P (insn))
 	    return FALSE;
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	    {
 	      if (may_trap_p (PATTERN (insn)))
 		return FALSE;
@@ -3819,7 +3835,7 @@ dead_or_predicable (basic_block test_bb,
 
       FOR_BB_INSNS (merge_bb, insn)
 	{
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	    {
 	      unsigned int uid = INSN_UID (insn);
 	      struct df_ref **def_rec;
Index: gcc/cfgcleanup.c
===================================================================
--- gcc/cfgcleanup.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/cfgcleanup.c	2007-10-01 18:38:14.000000000 -0300
@@ -1056,10 +1056,10 @@ flow_find_cross_jump (int mode ATTRIBUTE
   while (true)
     {
       /* Ignore notes.  */
-      while (!INSN_P (i1) && i1 != BB_HEAD (bb1))
+      while ((!INSN_P (i1) || DEBUG_INSN_P (i1)) && i1 != BB_HEAD (bb1))
 	i1 = PREV_INSN (i1);
 
-      while (!INSN_P (i2) && i2 != BB_HEAD (bb2))
+      while ((!INSN_P (i2) || DEBUG_INSN_P (i2)) && i2 != BB_HEAD (bb2))
 	i2 = PREV_INSN (i2);
 
       if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
@@ -1110,13 +1110,15 @@ flow_find_cross_jump (int mode ATTRIBUTE
      Two, it keeps line number notes as matched as may be.  */
   if (ninsns)
     {
-      while (last1 != BB_HEAD (bb1) && !INSN_P (PREV_INSN (last1)))
+      while (last1 != BB_HEAD (bb1) && (!INSN_P (PREV_INSN (last1))
+					|| DEBUG_INSN_P (PREV_INSN (last1))))
 	last1 = PREV_INSN (last1);
 
       if (last1 != BB_HEAD (bb1) && LABEL_P (PREV_INSN (last1)))
 	last1 = PREV_INSN (last1);
 
-      while (last2 != BB_HEAD (bb2) && !INSN_P (PREV_INSN (last2)))
+      while (last2 != BB_HEAD (bb2) && (!INSN_P (PREV_INSN (last2))
+					|| DEBUG_INSN_P (PREV_INSN (last2))))
 	last2 = PREV_INSN (last2);
 
       if (last2 != BB_HEAD (bb2) && LABEL_P (PREV_INSN (last2)))
Index: gcc/combine.c
===================================================================
--- gcc/combine.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/combine.c	2007-10-01 18:38:14.000000000 -0300
@@ -932,7 +932,7 @@ create_log_links (void)
     {
       FOR_BB_INSNS_REVERSE (bb, insn)
         {
-          if (!INSN_P (insn))
+          if (!INSN_P (insn) || DEBUG_INSN_P (insn))
             continue;
 
 	  /* Log links are created only once.  */
@@ -1123,7 +1123,7 @@ combine_instructions (rtx f, unsigned in
 	   insn = next ? next : NEXT_INSN (insn))
 	{
 	  next = 0;
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	    {
 	      /* See if we know about function return values before this
 		 insn based upon SUBREG flags.  */
@@ -2163,6 +2163,51 @@ reg_subword_p (rtx x, rtx reg)
 	 && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
 }
 
+/* Auxiliary data structure for propagate_for_debug_stmt.  */
+
+struct rtx_subst_pair
+{
+  rtx from, to;
+};
+
+/* If *LOC is the same as FROM in the struct rtx_subst_pair passed as
+   DATA, replace it with a copy of TO.  */
+
+static int
+propagate_for_debug_subst (rtx *loc, void *data)
+{
+  struct rtx_subst_pair *pair = data;
+  rtx from = pair->from, to = pair->to;
+  rtx x = *loc;
+
+  if (rtx_equal_p (x, from))
+    {
+      *loc = copy_rtx (to);
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Replace occurrences of DEST with SRC in DEBUG_INSNs between INSN
+   and LAST.  */
+
+static void
+propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src)
+{
+  struct rtx_subst_pair p;
+
+  p.from = dest;
+  p.to = src;
+
+  while ((insn = NEXT_INSN (insn)) != last)
+    if (DEBUG_INSN_P (insn))
+      {
+	for_each_rtx (&INSN_VAR_LOCATION_LOC (insn),
+		      propagate_for_debug_subst, &p);
+	df_insn_rescan (insn);
+      }
+}
 
 /* Try to combine the insns I1 and I2 into I3.
    Here I1 and I2 appear earlier than I3.
@@ -3569,12 +3614,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	PATTERN (i2) = newi2pat;
       }
     else
-      SET_INSN_DELETED (i2);
+      {
+	if (MAY_HAVE_DEBUG_INSNS)
+	  propagate_for_debug (i2, i3, i2dest, i2src);
+	SET_INSN_DELETED (i2);
+      }
 
     if (i1)
       {
 	LOG_LINKS (i1) = 0;
 	REG_NOTES (i1) = 0;
+	if (MAY_HAVE_DEBUG_INSNS)
+	  propagate_for_debug (i1, i3, i1dest, i1src);
 	SET_INSN_DELETED (i1);
       }
 
@@ -12902,7 +12953,9 @@ distribute_links (rtx links)
 	   (insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
 		     || BB_HEAD (this_basic_block->next_bb) != insn));
 	   insn = NEXT_INSN (insn))
-	if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+	if (DEBUG_INSN_P (insn))
+	  continue;
+	else if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
 	  {
 	    if (reg_referenced_p (reg, PATTERN (insn)))
 	      place = insn;
Index: gcc/df-problems.c
===================================================================
--- gcc/df-problems.c.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/df-problems.c	2007-10-01 18:38:14.000000000 -0300
@@ -856,7 +856,7 @@ df_lr_bb_local_compute (unsigned int bb_
     {
       unsigned int uid = INSN_UID (insn);
 
-      if (!INSN_P (insn))
+      if (!INSN_P (insn) || DEBUG_INSN_P (insn))
 	continue;	
 
       for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
@@ -3127,6 +3127,8 @@ df_set_note (enum reg_note note_type, rt
   rtx this = old;
   rtx prev = NULL;
 
+  gcc_assert (!DEBUG_INSN_P (insn));
+
   while (this)
     if (XEXP (this, 0) == reg)
       {
@@ -3259,9 +3261,12 @@ df_whole_mw_reg_dead_p (struct df_mw_har
 static rtx
 df_set_dead_notes_for_mw (rtx insn, rtx old, struct df_mw_hardreg *mws,
 			  bitmap live, bitmap do_not_gen,
-			  bitmap artificial_uses)
+			  bitmap artificial_uses, bool *added_notes_p)
 {
   unsigned int r;
+  bool is_debug = *added_notes_p;
+
+  *added_notes_p = false;
   
 #ifdef REG_DEAD_DEBUGGING
   if (dump_file)
@@ -3279,6 +3284,11 @@ df_set_dead_notes_for_mw (rtx insn, rtx 
   if (df_whole_mw_reg_dead_p (mws, live, artificial_uses, do_not_gen))
     {
       /* Add a dead note for the entire multi word register.  */
+      if (is_debug)
+	{
+	  *added_notes_p = true;
+	  return old;
+	}
       old = df_set_note (REG_DEAD, insn, old, mws->mw_reg);
 #ifdef REG_DEAD_DEBUGGING
       df_print_note ("adding 1: ", insn, REG_NOTES (insn));
@@ -3291,6 +3301,11 @@ df_set_dead_notes_for_mw (rtx insn, rtx 
 	    && !bitmap_bit_p (artificial_uses, r)
 	    && !bitmap_bit_p (do_not_gen, r))
 	  {
+	    if (is_debug)
+	      {
+		*added_notes_p = true;
+		return old;
+	      }
 	    old = df_set_note (REG_DEAD, insn, old, regno_reg_rtx[r]);
 #ifdef REG_DEAD_DEBUGGING
 	    df_print_note ("adding 2: ", insn, REG_NOTES (insn));
@@ -3401,10 +3416,13 @@ df_note_bb_compute (unsigned int bb_inde
       struct df_mw_hardreg **mws_rec;
       rtx old_dead_notes;
       rtx old_unused_notes;
+      int debug_insn;
  
       if (!INSN_P (insn))
 	continue;
 
+      debug_insn = DEBUG_INSN_P (insn);
+
       bitmap_clear (do_not_gen);
       df_kill_notes (insn, &old_dead_notes, &old_unused_notes);
 
@@ -3489,10 +3507,18 @@ df_note_bb_compute (unsigned int bb_inde
 	  struct df_mw_hardreg *mws = *mws_rec; 
 	  if ((mws->type != DF_REF_REG_DEF)  
 	      && !df_ignore_stack_reg (mws->start_regno))
-	    old_dead_notes
-	      = df_set_dead_notes_for_mw (insn, old_dead_notes, 
-					  mws, live, do_not_gen,
-					  artificial_uses);
+	    {
+	      bool really_add_notes = debug_insn != 0;
+
+	      old_dead_notes
+		= df_set_dead_notes_for_mw (insn, old_dead_notes,
+					    mws, live, do_not_gen,
+					    artificial_uses,
+					    &really_add_notes);
+
+	      if (really_add_notes)
+		debug_insn = -1;
+	    }
 	  mws_rec++;
 	}
 
@@ -3510,6 +3536,12 @@ df_note_bb_compute (unsigned int bb_inde
 #endif
 	  if (!bitmap_bit_p (live, uregno))
 	    {
+	      if (debug_insn)
+		{
+		  debug_insn = -1;
+		  break;
+		}
+
 	      if ( (!(DF_REF_FLAGS (use) & DF_REF_MW_HARDREG))
 		   && (!bitmap_bit_p (do_not_gen, uregno))
 		   && (!bitmap_bit_p (artificial_uses, uregno))
@@ -3541,6 +3573,14 @@ df_note_bb_compute (unsigned int bb_inde
 	  free_EXPR_LIST_node (old_dead_notes);
 	  old_dead_notes = next;
 	}
+
+      if (debug_insn == -1)
+	{
+	  /* ??? We could probably do better here, replacing dead
+	     registers with their definitions.  */
+	  INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (VOIDmode);
+	  df_insn_rescan_debug_internal (insn);
+	}
     }
 }
 
@@ -3691,6 +3731,9 @@ df_simulate_uses (rtx insn, bitmap live)
   struct df_ref **use_rec;
   unsigned int uid = INSN_UID (insn);
 
+  if (DEBUG_INSN_P (insn))
+    return;
+
   for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
     {
       struct df_ref *use = *use_rec;
@@ -3745,7 +3788,7 @@ df_simulate_artificial_refs_at_top (basi
 void 
 df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live)
 {
-  if (! INSN_P (insn))
+  if (! INSN_P (insn) || DEBUG_INSN_P (insn))
     return;	
   
   df_simulate_uses (insn, live);
@@ -3785,7 +3828,7 @@ df_simulate_artificial_refs_at_end (basi
 void 
 df_simulate_one_insn_backwards (basic_block bb, rtx insn, bitmap live)
 {
-  if (! INSN_P (insn))
+  if (! INSN_P (insn) || DEBUG_INSN_P (insn))
     return;	
   
   df_simulate_defs (insn, live);
Index: gcc/df-scan.c
===================================================================
--- gcc/df-scan.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/df-scan.c	2007-10-01 18:38:14.000000000 -0300
@@ -1070,11 +1070,12 @@ df_free_collection_rec (struct df_collec
       pool_free (problem_data->mw_reg_pool, *mw);
 }
 
+/* Rescan INSN.  Return TRUE if the rescanning produced any changes.
+   If KEEPCLEAN is false, don't mark the basic block as dirty even if
+   there have been changes.  */
 
-/* Rescan INSN.  Return TRUE if the rescanning produced any changes.  */
-
-bool 
-df_insn_rescan (rtx insn)
+static bool
+df_insn_rescan_1 (rtx insn, bool keepclean)
 {
   unsigned int uid = INSN_UID (insn);
   struct df_insn_info *insn_info = NULL;
@@ -1154,10 +1155,29 @@ df_insn_rescan (rtx insn)
     }
 
   df_refs_add_to_chains (&collection_rec, bb, insn);
-  df_set_bb_dirty (bb);
+  if (!keepclean)
+    df_set_bb_dirty (bb);
   return true;
 }
 
+/* Rescan INSN.  Return TRUE if the rescanning produced any changes.  */
+
+bool
+df_insn_rescan (rtx insn)
+{
+  return df_insn_rescan_1 (insn, false);
+}
+
+/* Same as df_insn_rescan, but don't mark the basic block as
+   dirty.  */
+
+bool
+df_insn_rescan_debug_internal (rtx insn)
+{
+  gcc_assert (DEBUG_INSN_P (insn));
+  return df_insn_rescan_1 (insn, true);
+}
+
 
 /* Rescan all of the insns in the function.  Note that the artificial
    uses and defs are not touched.  This function will destroy def-se
@@ -2967,6 +2987,13 @@ df_uses_record (struct df_collection_rec
 	break;
       }
 
+    case VAR_LOCATION:
+      df_uses_record (collection_rec,
+		      &PAT_VAR_LOCATION_LOC (x),
+		      DF_REF_REG_USE, bb, insn,
+		      flags);
+      return;
+
     case PRE_DEC:
     case POST_DEC:
     case PRE_INC:
Index: gcc/haifa-sched.c
===================================================================
--- gcc/haifa-sched.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/haifa-sched.c	2007-10-01 18:38:14.000000000 -0300
@@ -708,6 +708,10 @@ dep_cost (dep_t link)
 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)))
@@ -727,6 +731,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)
@@ -741,7 +770,7 @@ priority (rtx insn)
     {
       int this_priority = 0;
 
-      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
@@ -837,8 +866,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))
@@ -886,8 +926,15 @@ 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 (has_debug)
+    while (DEBUG_INSN_P (last))
+      last = PREV_INSN (last);
+
+  /* Compare insns based on their relation to the last scheduled
+     non-debug insn.  */
+  if (INSN_P (last))
     {
       dep_t dep1;
       dep_t dep2;
@@ -897,7 +944,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;
@@ -907,7 +954,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;
@@ -925,8 +972,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;
@@ -2467,7 +2519,8 @@ schedule_block (basic_block *target_bb, 
 	  /* 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
+		   && !DEBUG_INSN_P (insn))
 	    can_issue_more--;
 
 	  advance = schedule_insn (insn);
@@ -4368,7 +4421,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;
 
Index: gcc/local-alloc.c
===================================================================
--- gcc/local-alloc.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/local-alloc.c	2007-10-01 18:38:14.000000000 -0300
@@ -1283,7 +1283,7 @@ block_alloc (int b)
   insn = BB_END (BASIC_BLOCK (b));
   while (1)
     {
-      if (!NOTE_P (insn))
+      if (!NOTE_P (insn) && !DEBUG_INSN_P (insn))
 	{
 	  ++insn_count;
 	  gcc_assert (insn_count <= max_uid);
@@ -1308,10 +1308,10 @@ block_alloc (int b)
   insn = BB_HEAD (BASIC_BLOCK (b));
   while (1)
     {
-      if (!NOTE_P (insn))
+      if (!NOTE_P (insn) && !DEBUG_INSN_P (insn))
 	insn_number++;
 
-      if (INSN_P (insn))
+      if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	{
 	  rtx link, set;
 	  int win = 0;
Index: gcc/regrename.c
===================================================================
--- gcc/regrename.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/regrename.c	2007-10-01 18:38:14.000000000 -0300
@@ -1397,7 +1397,10 @@ replace_oldest_value_reg (rtx *loc, enum
 	fprintf (dump_file, "insn %u: replaced reg %u with %u\n",
 		 INSN_UID (insn), REGNO (*loc), REGNO (new));
 
-      validate_change (insn, loc, new, 1);
+      if (DEBUG_INSN_P (insn))
+	*loc = new;
+      else
+	validate_change (insn, loc, new, 1);
       return true;
     }
   return false;
@@ -1421,6 +1424,9 @@ replace_oldest_value_addr (rtx *loc, enu
   switch (code)
     {
     case PLUS:
+      if (DEBUG_INSN_P (insn))
+	break;
+
       {
 	rtx orig_op0 = XEXP (x, 0);
 	rtx orig_op1 = XEXP (x, 1);
@@ -1555,9 +1561,14 @@ replace_oldest_value_addr (rtx *loc, enu
 static bool
 replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd)
 {
-  return replace_oldest_value_addr (&XEXP (x, 0),
-				    base_reg_class (GET_MODE (x), MEM,
-						    SCRATCH),
+  enum reg_class cl;
+
+  if (DEBUG_INSN_P (insn))
+    cl = ALL_REGS;
+  else
+    cl = base_reg_class (GET_MODE (x), MEM, SCRATCH);
+
+  return replace_oldest_value_addr (&XEXP (x, 0), cl,
 				    GET_MODE (x), insn, vd);
 }
 
@@ -1566,7 +1577,7 @@ replace_oldest_value_mem (rtx x, rtx ins
 static bool
 copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
 {
-  bool changed = false;
+  bool anything_changed = false;
   rtx insn;
 
   for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
@@ -1575,8 +1586,22 @@ copyprop_hardreg_forward_1 (basic_block 
       bool is_asm, any_replacements;
       rtx set;
       bool replaced[MAX_RECOG_OPERANDS];
+      bool changed = false;
 
-      if (! INSN_P (insn))
+      if (DEBUG_INSN_P (insn))
+	{
+	  rtx loc = INSN_VAR_LOCATION_LOC (insn);
+	  if (!VAR_LOC_UNKNOWN_P (loc)
+	      && replace_oldest_value_addr (&INSN_VAR_LOCATION_LOC (insn),
+					    ALL_REGS, GET_MODE (loc),
+					    insn, vd))
+	    {
+	      df_insn_rescan (insn);
+	      anything_changed = true;
+	    }
+	}
+
+      if (DEBUG_INSN_P (insn) || ! INSN_P (insn))
 	{
 	  if (insn == BB_END (bb))
 	    break;
@@ -1763,6 +1788,12 @@ copyprop_hardreg_forward_1 (basic_block 
 	}
 
     did_replacement:
+      if (changed)
+	{
+	  df_insn_rescan (insn);
+	  anything_changed = true;
+	}
+
       /* Clobber call-clobbered registers.  */
       if (CALL_P (insn))
 	for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -1780,7 +1811,7 @@ copyprop_hardreg_forward_1 (basic_block 
 	break;
     }
 
-  return changed;
+  return anything_changed;
 }
 
 /* Main entry point for the forward copy propagation optimization.  */
Index: gcc/regstat.c
===================================================================
--- gcc/regstat.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/regstat.c	2007-10-01 18:38:14.000000000 -0300
@@ -62,11 +62,27 @@ regstat_init_n_sets_and_refs (void)
 
   regstat_n_sets_and_refs = xmalloc (max_regno * sizeof (struct regstat_n_sets_and_refs_t));
 
-  for (i = 0; i < max_regno; i++)
-    {
-      SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
-      SET_REG_N_REFS (i, DF_REG_USE_COUNT (i) + REG_N_SETS (i));
-    }
+  if (MAY_HAVE_DEBUG_INSNS)
+    for (i = 0; i < max_regno; i++)
+      {
+	int use_count;
+	struct df_ref *use;
+
+	use_count = DF_REG_USE_COUNT (i);
+	for (use = DF_REG_USE_CHAIN (i); use; use = DF_REF_NEXT_REG (use))
+	  if (DF_REF_INSN (use) && DEBUG_INSN_P (DF_REF_INSN (use)))
+	    use_count--;
+
+
+	SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
+	SET_REG_N_REFS (i, use_count + REG_N_SETS (i));
+      }
+  else
+    for (i = 0; i < max_regno; i++)
+      {
+	SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
+	SET_REG_N_REFS (i, DF_REG_USE_COUNT (i) + REG_N_SETS (i));
+      }
   timevar_pop (TV_REG_STATS);
 
 }
@@ -150,7 +166,7 @@ regstat_bb_compute_ri (unsigned int bb_i
       struct df_mw_hardreg **mws_rec;
       rtx link;
  
-      if (!INSN_P (insn))
+      if (!INSN_P (insn) || DEBUG_INSN_P (insn))
 	continue;
 
       /* Increment the live_length for all of the registers that
Index: gcc/sched-rgn.c
===================================================================
--- gcc/sched-rgn.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/sched-rgn.c	2007-10-01 18:38:15.000000000 -0300
@@ -2247,6 +2247,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)
@@ -2282,6 +2285,13 @@ add_branch_dependences (rtx head, rtx ta
 	break;
 
       insn = PREV_INSN (insn);
+      if (DEBUG_INSN_P (insn))
+	{
+	  if (last)
+	    add_dependence (last, insn, REG_DEP_ANTI);
+	  while (insn != head && DEBUG_INSN_P (insn))
+	    insn = PREV_INSN (insn);
+	}
     }
 
   /* Make sure these insns are scheduled last in their block.  */
Index: gcc/sched-vis.c
===================================================================
--- gcc/sched-vis.c.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/sched-vis.c	2007-10-01 18:38:15.000000000 -0300
@@ -557,6 +557,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)
Index: gcc/regmove.c
===================================================================
--- gcc/regmove.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/regmove.c	2007-10-01 18:38:15.000000000 -0300
@@ -545,9 +545,12 @@ optimize_reg_copy_1 (rtx insn, rtx dest,
 	      /* For SREGNO, count the total number of insns scanned.
 		 For DREGNO, count the total number of insns scanned after
 		 passing the death note for DREGNO.  */
-	      s_length++;
-	      if (dest_death)
-		d_length++;
+	      if (!DEBUG_INSN_P (p))
+		{
+		  s_length++;
+		  if (dest_death)
+		    d_length++;
+		}
 
 	      /* If the insn in which SRC dies is a CALL_INSN, don't count it
 		 as a call that has been crossed.  Otherwise, count it.  */
@@ -976,7 +979,7 @@ fixup_match_2 (rtx insn, rtx dst, rtx sr
 
       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
 	dst_death = p;
-      if (! dst_death)
+      if (! dst_death && !DEBUG_INSN_P (p))
 	length++;
 
       pset = single_set (p);
@@ -1421,7 +1424,8 @@ regmove_optimize (rtx f, int nregs)
 		  else if (! INSN_P (p))
 		    continue;
 
-		  length++;
+		  if (!DEBUG_INSN_P (p))
+		    length++;
 
 		  /* ??? See if all of SRC is set in P.  This test is much
 		     more conservative than it needs to be.  */
@@ -1431,22 +1435,9 @@ regmove_optimize (rtx f, int nregs)
 		      /* We use validate_replace_rtx, in case there
 			 are multiple identical source operands.  All of
 			 them have to be changed at the same time.  */
+		      validate_change (p, &SET_DEST (pset), dst, 1);
 		      if (validate_replace_rtx (src, dst, insn))
-			{
-			  if (validate_change (p, &SET_DEST (pset),
-					       dst, 0))
-			    success = 1;
-			  else
-			    {
-			      /* Change all source operands back.
-				 This modifies the dst as a side-effect.  */
-			      validate_replace_rtx (dst, src, insn);
-			      /* Now make sure the dst is right.  */
-			      validate_change (insn,
-					       recog_data.operand_loc[match_no],
-					       dst, 0);
-			    }
-			}
+			success = 1;
 		      break;
 		    }
 
@@ -1455,9 +1446,21 @@ regmove_optimize (rtx f, int nregs)
 		     eliminate SRC. We can't make this change 
 		     if DST is mentioned at all in P,
 		     since we are going to change its value.  */
-		  if (reg_overlap_mentioned_p (src, PATTERN (p))
-		      || reg_mentioned_p (dst, PATTERN (p)))
-		    break;
+		  if (reg_overlap_mentioned_p (src, PATTERN (p)))
+		    {
+		      if (DEBUG_INSN_P (p))
+			validate_replace_rtx_group (dst, src, insn);
+		      else
+			break;
+		    }
+		  if (reg_mentioned_p (dst, PATTERN (p)))
+		    {
+		      if (DEBUG_INSN_P (p))
+			validate_change (p, &INSN_VAR_LOCATION_LOC (p),
+					 gen_rtx_UNKNOWN_VAR_LOC (VOIDmode), 1);
+		      else
+			break;
+		    }
 
 		  /* If we have passed a call instruction, and the
 		     pseudo-reg DST is not already live across a call,
@@ -1516,6 +1519,8 @@ regmove_optimize (rtx f, int nregs)
 
 		  break;
 		}
+	      else if (num_changes_pending () > 0)
+		cancel_changes (0);
 	    }
 
 	  /* If we weren't able to replace any of the alternatives, try an
@@ -1737,9 +1742,12 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
       else if (! INSN_P (p))
 	continue;
 
-      length++;
-      if (src_note)
-	s_length++;
+      if (!DEBUG_INSN_P (p))
+	{
+	  length++;
+	  if (src_note)
+	    s_length++;
+	}
 
       if (reg_set_p (src, p) || reg_set_p (dst, p)
 	  || (GET_CODE (PATTERN (p)) == USE
@@ -1849,16 +1857,30 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
 	}
 
       if (reg_overlap_mentioned_p (dst, PATTERN (p)))
-	break;
+	{
+	  if (DEBUG_INSN_P (p))
+	    validate_replace_rtx_group (dst, src_subreg, p);
+	  else
+	    break;
+	}
       if (! src_note && reg_overlap_mentioned_p (src, PATTERN (p)))
 	{
-	  /* INSN was already checked to be movable wrt. the registers that it
-	     sets / uses when we found no REG_DEAD note for src on it, but it
-	     still might clobber the flags register.  We'll have to check that
-	     we won't insert it into the shadow of a live flags register when
-	     we finally know where we are to move it.  */
-	  overlap = p;
-	  src_note = find_reg_note (p, REG_DEAD, src);
+	  if (DEBUG_INSN_P (p))
+	    /* ??? Can we do better?  */
+	    validate_change (p, &INSN_VAR_LOCATION_LOC (p),
+			     gen_rtx_UNKNOWN_VAR_LOC (VOIDmode), 1);
+	  else
+	    {
+	      /* INSN was already checked to be movable wrt. the
+		 registers that it sets / uses when we found no
+		 REG_DEAD note for src on it, but it still might
+		 clobber the flags register.  We'll have to check that
+		 we won't insert it into the shadow of a live flags
+		 register when we finally know where we are to move
+		 it.  */
+	      overlap = p;
+	      src_note = find_reg_note (p, REG_DEAD, src);
+	    }
 	}
 
       /* If we have passed a call instruction, and the pseudo-reg SRC is not
@@ -1877,7 +1899,11 @@ fixup_match_1 (rtx insn, rtx set, rtx sr
     }
 
   if (! success)
-    return 0;
+    {
+      if (num_changes_pending () > 0)
+	cancel_changes (0);
+      return 0;
+    }
 
   /* Remove the death note for DST from P.  */
   remove_note (p, dst_note);
Index: gcc/gcse.c
===================================================================
--- gcc/gcse.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/gcse.c	2007-10-01 18:38:15.000000000 -0300
@@ -936,7 +936,7 @@ alloc_gcse_mem (void)
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
       {
-	if (INSN_P (insn))
+	if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	  uid_cuid[INSN_UID (insn)] = i++;
 	else
 	  uid_cuid[INSN_UID (insn)] = i;
@@ -949,7 +949,7 @@ alloc_gcse_mem (void)
   i = 0;
   FOR_EACH_BB (bb)
     FOR_BB_INSNS (bb, insn)
-      if (INSN_P (insn))
+      if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	CUID_INSN (i++) = insn;
 
   /* Allocate vars to track sets of regs.  */
@@ -3710,7 +3710,9 @@ bypass_conditional_jumps (void)
 	{
 	  setcc = NULL_RTX;
 	  FOR_BB_INSNS (bb, insn)
-	    if (NONJUMP_INSN_P (insn))
+	    if (DEBUG_INSN_P (insn))
+	      continue;
+	    else if (NONJUMP_INSN_P (insn))
 	      {
 		if (setcc)
 		  break;
@@ -5307,7 +5309,7 @@ compute_ld_motion_mems (void)
     {
       FOR_BB_INSNS (bb, insn)
 	{
-	  if (INSN_P (insn))
+	  if (INSN_P (insn) && !DEBUG_INSN_P (insn))
 	    {
 	      if (GET_CODE (PATTERN (insn)) == SET)
 		{
Index: gcc/sched-deps.c
===================================================================
--- gcc/sched-deps.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/sched-deps.c	2007-10-01 18:38:15.000000000 -0300
@@ -1729,6 +1729,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 (current_sched_info->use_cselib)
 	  {
 	    t = shallow_copy_rtx (t);
@@ -1930,6 +1936,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 = TRUE_BARRIER;
       else
@@ -1985,6 +1993,21 @@ sched_analyze_insn (struct deps *deps, r
 	}
     }
 
+  if (DEBUG_INSN_P (insn))
+    {
+      rtx head = BB_HEAD (BLOCK_FOR_INSN (insn)), prev;
+
+      if (insn != head)
+	{
+	  for (prev = PREV_INSN (insn); prev != head; prev = PREV_INSN (prev))
+	    if (INSN_P (prev))
+	      {
+		add_dependence (insn, prev, REG_DEP_TRUE);
+		break;
+	      }
+	}
+    }
+
   /* If this instruction can throw an exception, then moving it changes
      where block boundaries fall.  This is mighty confusing elsewhere.
      Therefore, prevent such an instruction from being moved.  Same for
@@ -2045,9 +2068,19 @@ sched_analyze_insn (struct deps *deps, r
     }
   else
     {
+      if (DEBUG_INSN_P (insn))
+	{
+	  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);
+	    }
+	  CLEAR_REG_SET (reg_pending_uses);
+	}
       /* If the current insn is conditional, we can't free any
 	 of the lists.  */
-      if (sched_get_condition (insn))
+      else if (sched_get_condition (insn))
 	{
 	  EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i, rsi)
 	    {
@@ -2248,7 +2281,7 @@ sched_analyze (struct deps *deps, rtx he
 	  sd_init_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 a scheduling barrier for memory
              references.  */
Index: gcc/init-regs.c
===================================================================
--- gcc/init-regs.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/init-regs.c	2007-10-01 18:38:15.000000000 -0300
@@ -71,7 +71,7 @@ initialize_uninitialized_regs (void)
 	{
 	  unsigned int uid = INSN_UID (insn);
 	  struct df_ref **use_rec;
-	  if (!INSN_P (insn))
+	  if (!INSN_P (insn) || DEBUG_INSN_P (insn))
 	    continue;
 
 	  for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
Index: gcc/dse.c
===================================================================
--- gcc/dse.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/dse.c	2007-10-01 18:38:15.000000000 -0300
@@ -1931,6 +1931,12 @@ scan_insn (bb_info_t bb_info, rtx insn)
   bb_info->last_insn = insn_info;
   
 
+  if (DEBUG_INSN_P (insn))
+    {
+      insn_info->cannot_delete = true;
+      return;
+    }
+
   /* Cselib clears the table for this case, so we have to essentially
      do the same.  */
   if (NONJUMP_INSN_P (insn)
Index: gcc/resource.c
===================================================================
--- gcc/resource.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/resource.c	2007-10-01 18:38:15.000000000 -0300
@@ -996,6 +996,9 @@ mark_target_live_regs (rtx insns, rtx ta
 	  rtx real_insn = insn;
 	  enum rtx_code code = GET_CODE (insn);
 
+	  if (DEBUG_INSN_P (insn))
+	    continue;
+
 	  /* If this insn is from the target of a branch, it isn't going to
 	     be used in the sequel.  If it is used in both cases, this
 	     test will not be true.  */
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/rtlanal.c	2007-10-01 18:38:15.000000000 -0300
@@ -4620,7 +4620,11 @@ canonicalize_condition (rtx insn, rtx co
 	 stop if it isn't a single set or if it has a REG_INC note because
 	 we don't want to bother dealing with it.  */
 
-      if ((prev = prev_nonnote_insn (prev)) == 0
+      do
+	prev = prev_nonnote_insn (prev);
+      while (prev && DEBUG_INSN_P (prev));
+
+      if (prev == 0
 	  || !NONJUMP_INSN_P (prev)
 	  || FIND_REG_INC_NOTE (prev, NULL_RTX)
 	  /* In cfglayout mode, there do not have to be labels at the
Index: gcc/df.h
===================================================================
--- gcc/df.h.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/df.h	2007-10-01 18:38:15.000000000 -0300
@@ -896,6 +896,7 @@ extern struct df_insn_info * df_insn_cre
 extern void df_insn_delete (basic_block, unsigned int);
 extern void df_bb_refs_record (int, bool);
 extern bool df_insn_rescan (rtx);
+extern bool df_insn_rescan_debug_internal (rtx);
 extern void df_insn_rescan_all (void);
 extern void df_process_deferred_rescans (void);
 extern bool df_has_eh_preds (basic_block);
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/dwarf2out.c	2007-10-01 18:38:15.000000000 -0300
@@ -9073,6 +9073,8 @@ mem_loc_descriptor (rtx rtl, enum machin
       /* ... fall through ...  */
 
     case SUBREG:
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
       /* The case of a subreg may arise when we have a local (register)
 	 variable or a formal (register) parameter which doesn't quite fill
 	 up an entire register.  For now, just assume that it is
@@ -9317,6 +9319,8 @@ loc_descriptor (rtx rtl, enum var_init_s
   switch (GET_CODE (rtl))
     {
     case SUBREG:
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
       /* The case of a subreg may arise when we have a local (register)
 	 variable or a formal (register) parameter which doesn't quite fill
 	 up an entire register.  For now, just assume that it is
Index: gcc/function.c
===================================================================
--- gcc/function.c.orig	2007-10-01 18:37:16.000000000 -0300
+++ gcc/function.c	2007-10-01 18:38:15.000000000 -0300
@@ -1695,8 +1695,11 @@ instantiate_virtual_regs (void)
 	    || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
 	    || GET_CODE (PATTERN (insn)) == ASM_INPUT)
 	  continue;
-
-	instantiate_virtual_regs_in_insn (insn);
+	else if (DEBUG_INSN_P (insn))
+	  for_each_rtx (&INSN_VAR_LOCATION (insn),
+			instantiate_virtual_regs_in_rtx, NULL);
+	else
+	  instantiate_virtual_regs_in_insn (insn);
 
 	if (INSN_DELETED_P (insn))
 	  continue;
Index: gcc/rtl.def
===================================================================
--- gcc/rtl.def.orig	2007-10-01 18:37:15.000000000 -0300
+++ gcc/rtl.def	2007-10-01 18:38:15.000000000 -0300
@@ -111,6 +111,9 @@ DEF_RTL_EXPR(ADDRESS, "address", "e", RT
 
    ---------------------------------------------------------------------- */
 
+/* An annotation for variable assignment tracking.  */
+DEF_RTL_EXPR(DEBUG_INSN, "debug_insn", "iuuBieie", RTX_INSN)
+
 /* An instruction that cannot jump.  */
 DEF_RTL_EXPR(INSN, "insn", "iuuBieie", RTX_INSN)
 
Index: gcc/cfgbuild.c
===================================================================
--- gcc/cfgbuild.c.orig	2007-08-15 22:34:41.000000000 -0300
+++ gcc/cfgbuild.c	2007-10-01 20:29:37.000000000 -0300
@@ -73,6 +73,7 @@ inside_basic_block_p (const_rtx insn)
 
     case CALL_INSN:
     case INSN:
+    case DEBUG_INSN:
       return true;
 
     case BARRIER:
@@ -96,6 +97,7 @@ control_flow_insn_p (const_rtx insn)
     {
     case NOTE:
     case CODE_LABEL:
+    case DEBUG_INSN:
       return false;
 
     case JUMP_INSN:
Index: gcc/cfglayout.c
===================================================================
--- gcc/cfglayout.c.orig	2007-09-05 04:40:01.000000000 -0300
+++ gcc/cfglayout.c	2007-10-01 20:34:17.000000000 -0300
@@ -1062,6 +1062,7 @@ duplicate_insn_chain (rtx from, rtx to)
     {
       switch (GET_CODE (insn))
 	{
+	case DEBUG_INSN:
 	case INSN:
 	case CALL_INSN:
 	case JUMP_INSN:

-- 
Alexandre Oliva         http://www.lsd.ic.unicamp.br/~oliva/
FSF Latin America Board Member         http://www.fsfla.org/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}

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