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


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

Re: VTA merge - ssa (gimple, trees, tuples)


ssa (55K) - introduce debug bind stmts in the tree and tuples level

Index: gcc/tree.def
===================================================================
--- gcc/tree.def.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree.def	2009-06-05 05:07:56.000000000 -0300
@@ -948,6 +948,11 @@ DEFTREECODE (STATEMENT_LIST, "statement_
    The type of the expression is the same as Y.  */
 DEFTREECODE (ASSERT_EXPR, "assert_expr", tcc_expression, 2)
 
+/* Debug bind operation.  Operand 0 is a tree that represents a user
+   variable; 1 is an expression that evaluates to the value of the
+   variable.  */
+DEFTREECODE (VAR_DEBUG_VALUE, "var_debug_value", tcc_statement, 2)
+
 /* Base class information. Holds information about a class as a
    baseclass of itself or another class.  */
 DEFTREECODE (TREE_BINFO, "tree_binfo", tcc_exceptional, 0)
Index: gcc/gimple.def
===================================================================
--- gcc/gimple.def.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/gimple.def	2009-06-05 05:07:56.000000000 -0300
@@ -53,6 +53,9 @@ DEFGSCODE(GIMPLE_ERROR_MARK, "gimple_err
    jump target for the comparison.  */
 DEFGSCODE(GIMPLE_COND, "gimple_cond", struct gimple_statement_with_ops)
 
+/* GIMPLE_DEBUG represents a debug statement.  */
+DEFGSCODE(GIMPLE_DEBUG, "gimple_debug", struct gimple_statement_with_ops)
+
 /* GIMPLE_GOTO <TARGET> represents unconditional jumps.
    TARGET is a LABEL_DECL or an expression node for computed GOTOs.  */
 DEFGSCODE(GIMPLE_GOTO, "gimple_goto", struct gimple_statement_with_ops)
Index: gcc/tree.h
===================================================================
--- gcc/tree.h.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree.h	2009-06-05 05:07:56.000000000 -0300
@@ -1531,6 +1531,16 @@ struct GTY(()) tree_constructor {
 				 && VOID_TYPE_P (TREE_TYPE (NODE)) \
 				 && integer_zerop (TREE_OPERAND (NODE, 0)))
 
+/* Nonzero if NODE is a debug statement.  */
+#define IS_DEBUG_STMT(NODE)     (gimple_code (NODE) == GIMPLE_DEBUG)
+
+/* Nonzero if NODE is a debug bind statement.  */
+#define IS_DEBUG_BIND(NODE)	(IS_DEBUG_STMT (NODE) && \
+				 (NODE)->gsbase.subcode == 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)
@@ -1543,6 +1553,13 @@ struct GTY(()) tree_constructor {
 #define VL_EXP_OPERAND_LENGTH(NODE) \
   ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0]))
 
+/* The second operand of a VAR_DEBUG_VALUE when the value was
+   optimized away.  */
+#define VAR_DEBUG_VALUE_NOVALUE NULL_TREE /* error_mark_node */
+#define VAR_DEBUG_VALUE_SET_VAR(T, V) (gimple_debug_bind_set_var ((T), (V)))
+#define VAR_DEBUG_VALUE_VAR(T) (gimple_debug_bind_get_var (T))
+#define VAR_DEBUG_VALUE_VALUE(T) (*gimple_debug_bind_get_value_ptr (T))
+
 /* In a LOOP_EXPR node.  */
 #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0)
 
@@ -3846,6 +3863,10 @@ extern tree build6_stat (enum tree_code,
 #define build6(c,t1,t2,t3,t4,t5,t6,t7) \
   build6_stat (c,t1,t2,t3,t4,t5,t6,t7 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);
@@ -5311,4 +5332,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-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c.orig	2009-06-05 04:56:43.000000000 -0300
+++ gcc/tree-into-ssa.c	2009-06-05 05:03:03.000000000 -0300
@@ -763,6 +763,9 @@ mark_def_sites (struct dom_walk_data *wa
   set_register_defs (stmt, false);
   set_rewrite_uses (stmt, false);
 
+  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)
@@ -1065,6 +1068,243 @@ mark_phi_for_rewrite (basic_block bb, gi
   VEC_replace (gimple_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 (!DECL_NAME (var))
+    {
+      tree origin = DECL_ABSTRACT_ORIGIN (var);
+
+      if (!origin)
+	return false;
+
+      if (!DECL_P (origin))
+	return false;
+
+      if (!DECL_NAME (origin))
+	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 TOGSIP 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 TOGSIP is unused.  */
+void
+adjust_debug_stmts_for_var_def_move (tree var,
+				     basic_block tobb,
+				     const gimple_stmt_iterator *togsip)
+{
+  imm_use_iterator imm_iter;
+  gimple stmt;
+  use_operand_p use_p;
+  tree value = NULL;
+  bool no_value = false;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+    {
+      basic_block bb;
+      gimple_stmt_iterator si;
+
+      if (!IS_DEBUG_STMT (stmt))
+	continue;
+
+      if (tobb)
+	{
+	  bb = gimple_bb (stmt);
+
+	  if (bb != tobb)
+	    {
+	      if (dominated_by_p (CDI_DOMINATORS, bb, tobb))
+		continue;
+	    }
+	  else
+	    {
+	      si = *togsip;
+
+	      if (gsi_end_p (si))
+		continue;
+
+	      do
+		{
+		  gsi_prev (&si);
+		  if (gsi_end_p (si))
+		    break;
+		}
+	      while (gsi_stmt (si) != stmt);
+
+	      if (gsi_end_p (si))
+		continue;
+	    }
+	}
+
+      if (!value && !no_value)
+	{
+	  if (SSA_NAME_VALUE (var))
+	    value = SSA_NAME_VALUE (var);
+	  else
+	    {
+	      gimple def_stmt = SSA_NAME_DEF_STMT (var);
+
+	      if (gimple_code (def_stmt) == GIMPLE_ASSIGN
+		  && TREE_TYPE (gimple_assign_rhs1 (def_stmt))
+		  && gimple_assign_rhs2 (def_stmt)
+		  && TREE_TYPE (gimple_assign_rhs2 (def_stmt)))
+		value = gimple_assign_rhs_to_tree (def_stmt);
+	    }
+
+	  if (!value)
+	    no_value = true;
+	}
+
+      if (no_value)
+	VAR_DEBUG_VALUE_VALUE (stmt) = VAR_DEBUG_VALUE_NOVALUE;
+      else
+	FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+	  SET_USE (use_p, unshare_expr (value));
+
+      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 (gimple def, basic_block tobb,
+			     const gimple_stmt_iterator *togsip)
+{
+  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, togsip);
+    }
+}
+
+/* Wrapper struct for the function predicate passed to
+   check_and_update_debug_stmt_1 ().  */
+
+struct check_debug_predicate
+{
+  bool (*available_p)(tree);
+  gimple stmt;
+};
+
+/* 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))
+	{
+	  /* Default definitions are never removed.  */
+	  if (SSA_NAME_IS_DEFAULT_DEF (t))
+	    return NULL_TREE;
+	  else
+	    return t;
+	}
+
+      if (gimple_nop_p (SSA_NAME_DEF_STMT (t)))
+	{
+	  if (SSA_NAME_IS_DEFAULT_DEF (t))
+	    return NULL_TREE;
+	  else
+	    return t;
+	}
+
+      if (p->available_p && !p->available_p (t))
+	return t;
+
+      if (dom_info_available_p (CDI_DOMINATORS))
+	{
+	  basic_block bbuse = gimple_bb (p->stmt);
+	  basic_block bbdef = gimple_bb (SSA_NAME_DEF_STMT (t));
+
+	  if (bbuse != bbdef
+	      && !dominated_by_p (CDI_DOMINATORS, bbuse, bbdef))
+	    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 (gimple 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;
+  p.stmt = t;
+  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
@@ -1134,6 +1374,13 @@ insert_phi_nodes_for (tree var, bitmap p
 	{
 	  gcc_assert (DECL_P (var));
 	  phi = create_phi_node (var, bb);
+	  if (!update_p && var_debug_value_for_decl (var))
+	    {
+	      gimple note = gimple_build_debug_bind (var, PHI_RESULT (phi),
+						     phi);
+	      gimple_stmt_iterator si = gsi_after_labels (bb);
+	      gsi_insert_before (&si, note, GSI_SAME_STMT);
+	    }
 	}
 
       /* Mark this PHI node as interesting for update_ssa.  */
@@ -1343,9 +1590,14 @@ rewrite_stmt (struct dom_walk_data *walk
   if (register_defs_p (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))
+	  {
+	    gimple note = gimple_build_debug_bind (var, name, stmt);
+	    gsi_insert_after (&si, note, GSI_SAME_STMT);
+	  }
 	register_new_def (DEF_FROM_PTR (def_p), var);
       }
 }
@@ -1859,6 +2111,34 @@ maybe_replace_use (use_operand_p use_p)
 }
 
 
+/* Same as maybe_replace_use, but without introducing default stmts,
+   returning false to indicate a need to do so.  */
+
+static inline bool
+maybe_replace_use_in_debug_insn (use_operand_p use_p)
+{
+  tree rdef = NULL_TREE;
+  tree use = USE_FROM_PTR (use_p);
+  tree sym = DECL_P (use) ? use : SSA_NAME_VAR (use);
+
+  if (symbol_marked_for_renaming (sym))
+    rdef = get_current_def (sym);
+  else if (is_old_name (use))
+    {
+      rdef = get_current_def (use);
+      if (!rdef && SSA_NAME_DEF_STMT (use))
+	return true;
+    }
+  else
+    return true;
+
+  if (rdef && rdef != use)
+    SET_USE (use_p, rdef);
+
+  return rdef != NULL_TREE;
+}
+
+
 /* If the operand pointed to by DEF_P is an SSA name in NEW_SSA_NAMES
    or OLD_SSA_NAMES, or if it is a symbol marked for renaming,
    register it as the current definition for the names replaced by
@@ -1931,10 +2211,40 @@ rewrite_update_stmt (struct dom_walk_dat
 
   /* Rewrite USES included in OLD_SSA_NAMES and USES whose underlying
      symbol is marked for renaming.  */
-  if (rewrite_uses_p (stmt))
+  if (rewrite_uses_p (stmt) && !IS_DEBUG_STMT (stmt))
     FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
       maybe_replace_use (use_p);
 
+  else if (rewrite_uses_p (stmt) && IS_DEBUG_STMT (stmt))
+    {
+      bool failed = false;
+
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+	if (!maybe_replace_use_in_debug_insn (use_p))
+	  {
+	    failed = true;
+	    break;
+	  }
+
+      if (failed)
+	{
+	  /* DOM sometimes threads jumps in such a way that a debug
+	     stmt ends up referencing a SSA variable that no longer
+	     dominates the debug stmt, but such that all incoming
+	     definitions refer to the same definition in an earlier
+	     dominator.  We could try to recover that definition
+	     somehow, but this will have to do for now.
+
+	     Introducing a default definition, which is what
+	     maybe_replace_use() would do in such cases, may modify
+	     code generation, for the otherwise-unused default
+	     definition would never go away, modifying SSA version
+	     numbers all over.  */
+	  VAR_DEBUG_VALUE_VALUE (stmt) = VAR_DEBUG_VALUE_NOVALUE;
+	  update_stmt (stmt);
+	}
+    }
+
   /* Register definitions of names in NEW_SSA_NAMES and OLD_SSA_NAMES.
      Also register definitions for names whose underlying symbol is
      marked for renaming.  */
@@ -2322,7 +2632,12 @@ mark_use_interesting (tree var, gimple s
   if (gimple_code (stmt) == GIMPLE_PHI)
     mark_phi_for_rewrite (def_bb, stmt);
   else
-    set_rewrite_uses (stmt, true);
+    {
+      set_rewrite_uses (stmt, true);
+
+      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
Index: gcc/tree-ssa-loop-im.c
===================================================================
--- gcc/tree-ssa-loop-im.c.orig	2009-06-05 04:56:43.000000000 -0300
+++ gcc/tree-ssa-loop-im.c	2009-06-05 05:03:03.000000000 -0300
@@ -879,6 +879,7 @@ rewrite_bittest (gimple_stmt_iterator *b
       gimple_cond_set_rhs (use_stmt, build_int_cst_type (TREE_TYPE (name), 0));
 
       gsi_insert_before (bsi, stmt1, GSI_SAME_STMT);
+      adjust_debug_stmts_for_move (gsi_stmt (*bsi), NULL, NULL);
       gsi_replace (bsi, stmt2, true);
 
       return stmt1;
@@ -1059,6 +1060,7 @@ move_computations_stmt (struct dom_walk_
 
       mark_virtual_ops_for_renaming (stmt);
       gsi_insert_on_edge (loop_preheader_edge (level), stmt);
+      adjust_debug_stmts_for_move (gsi_stmt (bsi), NULL, NULL);
       gsi_remove (&bsi, false);
     }
 }
Index: gcc/expr.c
===================================================================
--- gcc/expr.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/expr.c	2009-06-05 05:07:56.000000000 -0300
@@ -5976,7 +5976,7 @@ get_inner_reference (tree exp, HOST_WIDE
 
   /* Compute cumulative bit-offset for nested component-refs and array-refs,
      and find the ultimate containing object.  */
-  while (1)
+  do
     {
       switch (TREE_CODE (exp))
 	{
@@ -6055,6 +6055,7 @@ get_inner_reference (tree exp, HOST_WIDE
 
       exp = TREE_OPERAND (exp, 0);
     }
+  while (exp);
  done:
 
   /* If OFFSET is constant, see if we can return the whole thing as a
@@ -9268,6 +9269,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/tree-parloops.c
===================================================================
--- gcc/tree-parloops.c.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/tree-parloops.c	2009-06-05 05:07:56.000000000 -0300
@@ -658,7 +658,11 @@ eliminate_local_variables_stmt (edge ent
   dta.decl_address = decl_address;
   dta.changed = false;
 
-  walk_gimple_op (stmt, eliminate_local_variables_1, &dta.info);
+  if (IS_DEBUG_BIND (stmt))
+    walk_tree (gimple_debug_bind_get_value_ptr (stmt),
+	       eliminate_local_variables_1, &dta.info, NULL);
+  else
+    walk_gimple_op (stmt, eliminate_local_variables_1, &dta.info);
 
   if (dta.changed)
     update_stmt (stmt);
@@ -842,6 +846,53 @@ separate_decls_in_region_stmt (edge entr
   }
 }
 
+/* Finds the ssa names used in STMT that are defined outside the
+   region between ENTRY and EXIT and replaces such ssa names with
+   their duplicates.  The duplicates are stored to NAME_COPIES.  Base
+   decls of all ssa names used in STMT (including those defined in
+   LOOP) are replaced with the new temporary variables; the
+   replacement decls are stored in DECL_COPIES.  */
+
+static bool
+separate_decls_in_region_debug_bind (gimple stmt,
+				     htab_t name_copies, htab_t decl_copies)
+{
+  use_operand_p use;
+  ssa_op_iter oi;
+  tree var, name;
+  struct int_tree_map ielt;
+  struct name_to_copy_elt elt;
+  void **slot, **dslot;
+
+  var = gimple_debug_bind_get_var (stmt);
+  gcc_assert (DECL_P (var) && SSA_VAR_P (var));
+  ielt.uid = DECL_UID (var);
+  dslot = htab_find_slot_with_hash (decl_copies, &ielt, ielt.uid, NO_INSERT);
+  if (!dslot)
+    return true;
+  gimple_debug_bind_set_var (stmt, ((struct int_tree_map *) *dslot)->to);
+
+  FOR_EACH_PHI_OR_STMT_USE (use, stmt, oi, SSA_OP_USE)
+  {
+    name = USE_FROM_PTR (use);
+    if (TREE_CODE (name) != SSA_NAME)
+      continue;
+
+    elt.version = SSA_NAME_VERSION (name);
+    slot = htab_find_slot_with_hash (name_copies, &elt, elt.version, NO_INSERT);
+    if (!slot)
+      {
+	gimple_debug_bind_set_value (stmt, VAR_DEBUG_VALUE_NOVALUE);
+	update_stmt (stmt);
+	break;
+      }
+
+    SET_USE (use, ((struct name_to_copy_elt *) *slot)->new_name);
+  }
+
+  return false;
+}
+
 /* Callback for htab_traverse.  Adds a field corresponding to the reduction
    specified in SLOT. The type is passed in DATA.  */
 
@@ -1173,6 +1224,7 @@ separate_decls_in_region (edge entry, ed
   basic_block bb;
   basic_block entry_bb = bb1;
   basic_block exit_bb = exit->dest;
+  bool has_debug_stmt = false;
 
   entry = single_succ_edge (entry_bb);
   gather_blocks_in_sese_region (entry_bb, exit_bb, &body);
@@ -1186,11 +1238,43 @@ separate_decls_in_region (edge entry, ed
 					   name_copies, decl_copies);
 
 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-	    separate_decls_in_region_stmt (entry, exit, gsi_stmt (gsi),
-					   name_copies, decl_copies);
+	    {
+	      gimple stmt = gsi_stmt (gsi);
+
+	      if (IS_DEBUG_STMT (stmt))
+		has_debug_stmt = true;
+	      else
+		separate_decls_in_region_stmt (entry, exit, stmt,
+					       name_copies, decl_copies);
+	    }
 	}
     }
 
+  if (has_debug_stmt)
+    for (i = 0; VEC_iterate (basic_block, body, i, bb); i++)
+      if (bb != entry_bb && bb != exit_bb)
+	{
+	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+	    {
+	      gimple stmt = gsi_stmt (gsi);
+
+	      if (IS_DEBUG_BIND (stmt))
+		{
+		  if (separate_decls_in_region_debug_bind (stmt,
+							   name_copies,
+							   decl_copies))
+		    {
+		      gsi_remove (&gsi, true);
+		      continue;
+		    }
+		}
+	      else
+		gcc_assert (!IS_DEBUG_STMT (stmt));
+
+	      gsi_next (&gsi);
+	    }
+	}
+
   VEC_free (basic_block, heap, body);
 
   if (htab_elements (name_copies) == 0 && reduction_list == 0) 
Index: gcc/gimple-pretty-print.c
===================================================================
--- gcc/gimple-pretty-print.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/gimple-pretty-print.c	2009-06-05 05:07:56.000000000 -0300
@@ -780,6 +780,31 @@ dump_gimple_resx (pretty_printer *buffer
     dump_gimple_fmt (buffer, spc, flags, "resx %d", gimple_resx_region (gs));
 }
 
+/* Dump a GIMPLE_DEBUG tuple on the pretty_printer BUFFER, SPC spaces
+   of indent.  FLAGS specifies details to show in the dump (see TDF_*
+   in tree-pass.h).  */
+
+static void
+dump_gimple_debug (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  switch (gs->gsbase.subcode)
+    {
+    case VAR_DEBUG_VALUE:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G BIND <%T, %T>", gs,
+			 gimple_debug_bind_get_var (gs),
+			 gimple_debug_bind_get_value (gs));
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG %T => %T",
+			 gimple_debug_bind_get_var (gs),
+			 gimple_debug_bind_get_value (gs));
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Dump a GIMPLE_OMP_FOR tuple on the pretty_printer BUFFER.  */
 static void
 dump_gimple_omp_for (pretty_printer *buffer, gimple gs, int spc, int flags)
@@ -1499,6 +1524,10 @@ dump_gimple_stmt (pretty_printer *buffer
       dump_gimple_resx (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_DEBUG:
+      dump_gimple_debug (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_PREDICT:
       pp_string (buffer, "// predicted ");
       if (gimple_predict_outcome (gs))
@@ -1552,7 +1581,8 @@ dump_bb_header (pretty_printer *buffer, 
 	  gimple_stmt_iterator gsi;
 
 	  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-	    if (get_lineno (gsi_stmt (gsi)) != -1)
+	    if (!IS_DEBUG_STMT (gsi_stmt (gsi))
+		&& get_lineno (gsi_stmt (gsi)) != UNKNOWN_LOCATION)
 	      {
 		pp_string (buffer, ", starting at line ");
 		pp_decimal_int (buffer, get_lineno (gsi_stmt (gsi)));
Index: gcc/tree-if-conv.c
===================================================================
--- gcc/tree-if-conv.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-if-conv.c	2009-06-05 05:07:56.000000000 -0300
@@ -239,6 +239,15 @@ tree_if_convert_stmt (struct loop *  loo
     case GIMPLE_LABEL:
       break;
 
+    case GIMPLE_DEBUG:
+      /* ??? Should there be conditional VAR_DEBUG_VALUEs?  */
+      if (IS_DEBUG_BIND (gsi_stmt (*gsi)))
+	{
+	  VAR_DEBUG_VALUE_VALUE (gsi_stmt (*gsi)) = VAR_DEBUG_VALUE_NOVALUE;
+	  update_stmt (gsi_stmt (*gsi));
+	}
+      break;
+
     case GIMPLE_ASSIGN:
       /* This GIMPLE_ASSIGN is killing previous value of LHS. Appropriate
 	 value will be selected by PHI node based on condition. It is possible
@@ -422,8 +431,10 @@ if_convertible_stmt_p (struct loop *loop
     case GIMPLE_LABEL:
       break;
 
-    case GIMPLE_ASSIGN:
+    case GIMPLE_DEBUG:
+      break;
 
+    case GIMPLE_ASSIGN:
       if (!if_convertible_gimple_assign_stmt_p (loop, bb, stmt))
 	return false;
       break;
Index: gcc/tree-cfgcleanup.c
===================================================================
--- gcc/tree-cfgcleanup.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-cfgcleanup.c	2009-06-05 05:07:56.000000000 -0300
@@ -252,6 +252,11 @@ tree_forwarder_block_p (basic_block bb, 
 	    return false;
 	  break;
 
+	  /* ??? For now, hope there's a corresponding debug
+	     assignment at the destination.  */
+	case GIMPLE_DEBUG:
+	  break;
+
 	default:
 	  return false;
 	}
@@ -414,9 +419,10 @@ remove_forwarder_block (basic_block bb)
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
 	{
 	  label = gsi_stmt (gsi);
-	  gcc_assert (gimple_code (label) == GIMPLE_LABEL);
+	  gcc_assert (gimple_code (label) == GIMPLE_LABEL
+		      || IS_DEBUG_STMT (label));
 	  gsi_remove (&gsi, false);
-	  gsi_insert_before (&gsi_to, label, GSI_CONTINUE_LINKING);
+	  gsi_insert_before (&gsi_to, label, GSI_SAME_STMT);
 	}
     }
 
Index: gcc/tree-ssa-dce.c
===================================================================
--- gcc/tree-ssa-dce.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-ssa-dce.c	2009-06-05 05:07:56.000000000 -0300
@@ -326,6 +326,10 @@ mark_stmt_if_obviously_necessary (gimple
 	}
       break;
 
+    case GIMPLE_DEBUG:
+      mark_stmt_necessary (stmt, false);
+      return;
+
     case GIMPLE_GOTO:
       gcc_assert (!simple_goto_p (stmt));
       mark_stmt_necessary (stmt, true);
@@ -929,6 +933,15 @@ remove_dead_stmt (gimple_stmt_iterator *
   release_defs (stmt); 
 }
 
+/* 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 gimple_plf (SSA_NAME_DEF_STMT (t), STMT_NECESSARY);
+}
 
 /* Eliminate unnecessary statements. Any instruction not marked as necessary
    contributes nothing to the program, and can be deleted.  */
@@ -994,6 +1007,13 @@ eliminate_unnecessary_stmts (void)
 	    }
 	  else
 	    {
+	      if (IS_DEBUG_BIND (stmt))
+		{
+		  if (something_changed
+		      && (VAR_DEBUG_VALUE_VALUE (stmt)
+			  != VAR_DEBUG_VALUE_NOVALUE))
+		    check_and_update_debug_stmt (stmt, necessary_p);
+		}
 	      gsi_next (&gsi);
 	    }
 	}
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/tree-ssa.c	2009-06-05 05:07:56.000000000 -0300
@@ -632,6 +632,9 @@ verify_ssa (bool check_modified_stmt)
 		  goto err;
 		}
 	    }
+	  else if (IS_DEBUG_BIND (stmt)
+		   && VAR_DEBUG_VALUE_VALUE (stmt) == VAR_DEBUG_VALUE_NOVALUE)
+	    continue;
 
 	  /* Verify the single virtual operand and its constraints.  */
 	  has_err = false;
@@ -1391,6 +1394,8 @@ warn_uninitialized_vars (bool warn_possi
 	{
 	  struct walk_stmt_info wi;
 	  data.stmt = gsi_stmt (gsi);
+	  if (IS_DEBUG_STMT (data.stmt))
+	    continue;
 	  memset (&wi, 0, sizeof (wi));
 	  wi.info = &data;
 	  walk_gimple_op (gsi_stmt (gsi), warn_uninitialized_var, &wi);
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-inline.c	2009-06-05 05:07:56.000000000 -0300
@@ -148,6 +148,30 @@ insert_decl_map (copy_body_data *id, tre
     *pointer_map_insert (id->decl_map, value) = value;
 }
 
+/* Insert a tree->tree mapping for ID.  This is only used for
+   variables.  */
+
+static void
+insert_debug_decl_map (copy_body_data *id, tree key, tree value)
+{
+  if (!gimple_in_ssa_p (id->src_cfun))
+    return;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  if (!var_debug_value_for_decl (key))
+    return;
+
+  gcc_assert (TREE_CODE (key) == PARM_DECL);
+  gcc_assert (TREE_CODE (value) == VAR_DECL);
+
+  if (!id->debug_map)
+    id->debug_map = pointer_map_create ();
+
+  *pointer_map_insert (id->debug_map, key) = value;
+}
+
 /* Construct new SSA name for old NAME. ID is the inline context.  */
 
 static tree
@@ -221,6 +245,12 @@ remap_ssa_name (tree name, copy_body_dat
   return new_tree;
 }
 
+/* If nonzero, we're remapping the contents of inlined debug
+   statements.  If negative, an error has occurred, such as a
+   reference to a variable that isn't available in the inlined
+   context.  */
+int processing_debug_stmt = 0;
+
 /* Remap DECL during the copying of the BLOCK tree for the function.  */
 
 tree
@@ -236,6 +266,12 @@ remap_decl (tree decl, copy_body_data *i
 
   n = (tree *) pointer_map_contains (id->decl_map, decl);
 
+  if (!n && processing_debug_stmt)
+    {
+      processing_debug_stmt = -1;
+      return decl;
+    }
+
   /* If we didn't already have an equivalent for this declaration,
      create one now.  */
   if (!n)
@@ -803,7 +839,8 @@ remap_gimple_op_r (tree *tp, int *walk_s
 	 vars.  If not referenced from types only.  */
       if (gimple_in_ssa_p (cfun)
 	  && TREE_CODE (*tp) == VAR_DECL
-	  && id->remapping_type_depth == 0)
+	  && id->remapping_type_depth == 0
+	  && !processing_debug_stmt)
 	add_referenced_var (*tp);
 
       /* We should never have TREE_BLOCK set on non-statements.  */
@@ -1029,10 +1066,11 @@ copy_tree_body_r (tree *tp, int *walk_su
       copy_tree_r (tp, walk_subtrees, NULL);
 
       /* Global variables we haven't seen yet needs to go into referenced
-	 vars.  If not referenced from types only.  */
+	 vars.  If not referenced from types or debug stmts only.  */
       if (gimple_in_ssa_p (cfun)
 	  && TREE_CODE (*tp) == VAR_DECL
-	  && id->remapping_type_depth == 0)
+	  && id->remapping_type_depth == 0
+	  && !processing_debug_stmt)
 	add_referenced_var (*tp);
        
       /* If EXPR has block defined, map it to newly constructed block.
@@ -1278,8 +1316,17 @@ remap_gimple_stmt (gimple stmt, copy_bod
 	    }
 	}
 
-      /* Create a new deep copy of the statement.  */
-      copy = gimple_copy (stmt);
+      if (IS_DEBUG_BIND (stmt))
+	{
+	  copy = gimple_build_debug_bind (VAR_DEBUG_VALUE_VAR (stmt),
+					  VAR_DEBUG_VALUE_VALUE (stmt),
+					  stmt);
+	  VARRAY_PUSH_GENERIC_PTR (id->debug_stmts, copy);
+	  return copy;
+	}
+      else
+	/* Create a new deep copy of the statement.  */
+	copy = gimple_copy (stmt);
     }
 
   /* If STMT has a block defined, map it to the newly constructed
@@ -1296,6 +1343,9 @@ remap_gimple_stmt (gimple stmt, copy_bod
 
   gimple_set_block (copy, new_block);
 
+  if (IS_DEBUG_BIND (copy))
+    return copy;
+
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
   wi.info = id;
@@ -1585,7 +1635,7 @@ copy_bb (copy_body_data *id, basic_block
 		add_stmt_to_eh_region (stmt, id->eh_region);
 	    }
 
-	  if (gimple_in_ssa_p (cfun))
+	  if (gimple_in_ssa_p (cfun) && !IS_DEBUG_STMT (stmt))
 	    {
 	      ssa_op_iter i;
 	      tree def;
@@ -1714,9 +1764,12 @@ copy_edges_for_bb (basic_block bb, gcov_
       bool can_throw, nonlocal_goto;
 
       copy_stmt = gsi_stmt (si);
-      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.  */
       gsi_next (&si);
@@ -1991,6 +2044,72 @@ copy_cfg_body (copy_body_data * id, gcov
   return new_fndecl;
 }
 
+static void
+copy_debug_stmt (gimple stmt, copy_body_data *id)
+{
+  tree t, *n;
+  struct walk_stmt_info wi;
+
+  t = id->block;
+  if (gimple_block (stmt))
+    {
+      tree *n;
+      n = (tree *) pointer_map_contains (id->decl_map, gimple_block (stmt));
+      if (n)
+	t = *n;
+    }
+  gimple_set_block (stmt, t);
+
+  /* Remap all the operands in COPY.  */
+  memset (&wi, 0, sizeof (wi));
+  wi.info = id;
+
+  processing_debug_stmt = 1;
+
+  t = VAR_DEBUG_VALUE_VAR (stmt);
+
+  if (TREE_CODE (t) == PARM_DECL && id->debug_map
+      && (n = (tree *) pointer_map_contains (id->debug_map, t)))
+    {
+      gcc_assert (TREE_CODE (*n) == VAR_DECL);
+      t = *n;
+    }
+  else
+    walk_tree (&t, remap_gimple_op_r, &wi, NULL);
+
+  VAR_DEBUG_VALUE_SET_VAR (stmt, t);
+
+  if (VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE)
+    walk_tree (&VAR_DEBUG_VALUE_VALUE (stmt), remap_gimple_op_r, &wi, NULL);
+
+  /* Punt if any decl couldn't be remapped.  */
+  if (processing_debug_stmt < 0)
+    VAR_DEBUG_VALUE_VALUE (stmt) = VAR_DEBUG_VALUE_NOVALUE;
+
+  processing_debug_stmt = 0;
+
+  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 ((gimple) VARRAY_GENERIC_PTR (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.  */
+
 static tree
 copy_body (copy_body_data *id, gcov_type count, int frequency,
 	   basic_block entry_block_map, basic_block exit_block_map)
@@ -2001,6 +2120,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;
 }
@@ -2021,8 +2141,51 @@ self_inlining_addr_expr (tree value, tre
   return var && auto_var_in_fn_p (var, fn);
 }
 
+/* Append to BB a debug annotation that binds VAR to VALUE, inheriting
+   lexical block and line number information from base_stmt, if given,
+   or from the last stmt of the block otherwise.  */
+
+static gimple
+insert_init_debug_bind (copy_body_data *id,
+			basic_block bb, tree var, tree value,
+			gimple base_stmt)
+{
+  gimple note;
+  gimple_stmt_iterator gsi;
+
+  if (!gimple_in_ssa_p (id->src_cfun))
+    return NULL;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return NULL;
+
+  if (!var_debug_value_for_decl (var))
+    return NULL;
+
+  if (bb)
+    {
+      gsi = gsi_last_bb (bb);
+      if (!base_stmt && !gsi_end_p (gsi))
+	base_stmt = gsi_stmt (gsi);
+    }
+
+  note = gimple_build_debug_bind (var, value, base_stmt);
+
+  if (bb)
+    {
+      if (!gsi_end_p (gsi))
+	gsi_insert_after (&gsi, note, GSI_SAME_STMT);
+      else
+	gsi_insert_before (&gsi, note, GSI_SAME_STMT);
+    }
+
+  mark_symbols_for_renaming (note);
+
+  return note;
+}
+
 static void
-insert_init_stmt (basic_block bb, gimple init_stmt)
+insert_init_stmt (copy_body_data *id, basic_block bb, gimple init_stmt)
 {
   /* If VAR represents a zero-sized variable, it's possible that the
      assignment statement may result in no gimple statements.  */
@@ -2034,7 +2197,8 @@ insert_init_stmt (basic_block bb, gimple
          from a rhs with a conversion.  Handle that here by forcing the
 	 rhs into a temporary.  gimple_regimplify_operands is not
 	 prepared to do this for us.  */
-      if (!is_gimple_reg (gimple_assign_lhs (init_stmt))
+      if (!IS_DEBUG_STMT (init_stmt)
+	  && !is_gimple_reg (gimple_assign_lhs (init_stmt))
 	  && is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (init_stmt)))
 	  && gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS)
 	{
@@ -2049,6 +2213,18 @@ insert_init_stmt (basic_block bb, gimple
       gsi_insert_after (&si, init_stmt, GSI_NEW_STMT);
       gimple_regimplify_operands (init_stmt, &si);
       mark_symbols_for_renaming (init_stmt);
+
+      if (!IS_DEBUG_STMT (init_stmt) && MAY_HAVE_DEBUG_STMTS)
+	{
+	  tree var, def = gimple_assign_lhs (init_stmt);
+
+	  if (TREE_CODE (def) == SSA_NAME)
+	    var = SSA_NAME_VAR (def);
+	  else
+	    var = def;
+
+	  insert_init_debug_bind (id, bb, var, def, init_stmt);
+	}
     }
 }
 
@@ -2079,9 +2255,29 @@ setup_one_parameter (copy_body_data *id,
 	rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
     }
 
+  /* 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.  */
+  var = copy_decl_to_var (p, id);
+
+  /* We're actually using the newly-created var.  */
+  if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
+    {
+      get_var_ann (var);
+      add_referenced_var (var);
+    }
+
+  /* Declare this new variable.  */
+  TREE_CHAIN (var) = *vars;
+  *vars = var;
+
+  /* Make gimplifier happy about this variable.  */
+  DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
+
   /* 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.  */
+     we would not need to create a new variable here at all, if it
+     weren't for debug info.  Still, we can just use the argument
+     value.  */
   if (TREE_READONLY (p)
       && !TREE_ADDRESSABLE (p)
       && value && !TREE_SIDE_EFFECTS (value)
@@ -2102,32 +2298,16 @@ setup_one_parameter (copy_body_data *id,
 	  && ! self_inlining_addr_expr (value, fn))
 	{
 	  insert_decl_map (id, p, value);
-	  return NULL;
+	  insert_debug_decl_map (id, p, var);
+	  return insert_init_debug_bind (id, bb, var, value, NULL);
 	}
     }
 
-  /* 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.  */
-  var = copy_decl_to_var (p, id);
-  if (gimple_in_ssa_p (cfun) && TREE_CODE (var) == VAR_DECL)
-    {
-      get_var_ann (var);
-      add_referenced_var (var);
-    }
-
   /* Register the VAR_DECL as the equivalent for the PARM_DECL;
      that way, when the PARM_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
   insert_decl_map (id, p, var);
 
-  /* Declare this new variable.  */
-  TREE_CHAIN (var) = *vars;
-  *vars = var;
-
-  /* Make gimplifier happy about this variable.  */
-  DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
-
   /* Even if P was TREE_READONLY, the new VAR should not be.
      In the original code, we would have constructed a
      temporary, and then the function body would have never
@@ -2149,15 +2329,7 @@ setup_one_parameter (copy_body_data *id,
 
      Do replacement at -O0 for const arguments replaced by constant.
      This is important for builtin_constant_p and other construct requiring
-     constant argument to be visible in inlined function body.
-
-     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. */
+     constant argument to be visible in inlined function body.  */
   if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p)
       && (optimize
           || (TREE_READONLY (p)
@@ -2167,7 +2339,7 @@ setup_one_parameter (copy_body_data *id,
       && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
     {
       insert_decl_map (id, def, rhs);
-      return NULL;
+      return insert_init_debug_bind (id, bb, var, rhs, NULL);
     }
 
   /* If the value of argument is never used, don't care about initializing
@@ -2175,7 +2347,7 @@ setup_one_parameter (copy_body_data *id,
   if (optimize && gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
     {
       gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
-      return NULL;
+      return insert_init_debug_bind (id, bb, var, rhs, NULL);
     }
 
   /* Initialize this VAR_DECL from the equivalent argument.  Convert
@@ -2185,7 +2357,7 @@ setup_one_parameter (copy_body_data *id,
       if (rhs == error_mark_node)
 	{
 	  insert_decl_map (id, p, var);
-	  return NULL;
+	  return insert_init_debug_bind (id, bb, var, rhs, NULL);
 	}
 
       STRIP_USELESS_TYPE_CONVERSION (rhs);
@@ -2203,7 +2375,7 @@ setup_one_parameter (copy_body_data *id,
         init_stmt = gimple_build_assign (var, rhs);
 
       if (bb && init_stmt)
-        insert_init_stmt (bb, init_stmt);
+        insert_init_stmt (id, bb, init_stmt);
     }
   return init_stmt;
 }
@@ -3073,6 +3245,7 @@ estimate_num_insns (gimple stmt, eni_wei
     case GIMPLE_PHI:
     case GIMPLE_RETURN:
     case GIMPLE_PREDICT:
+    case GIMPLE_DEBUG:
       return 0;
 
     case GIMPLE_ASM:
@@ -3217,7 +3390,7 @@ expand_call_inline (basic_block bb, gimp
 {
   tree retvar, use_retvar;
   tree fn;
-  struct pointer_map_t *st;
+  struct pointer_map_t *st, *dst;
   tree return_slot;
   tree modify_dest;
   location_t saved_location;
@@ -3357,6 +3530,8 @@ expand_call_inline (basic_block bb, gimp
      map.  */
   st = id->decl_map;
   id->decl_map = pointer_map_create ();
+  dst = id->debug_map;
+  id->debug_map = NULL;
 
   /* Record the function we are about to inline.  */
   id->src_fn = fn;
@@ -3453,6 +3628,11 @@ expand_call_inline (basic_block bb, gimp
     }
 
   /* Clean up.  */
+  if (id->debug_map)
+    {
+      pointer_map_destroy (id->debug_map);
+      id->debug_map = dst;
+    }
   pointer_map_destroy (id->decl_map);
   id->decl_map = st;
 
@@ -3644,6 +3824,8 @@ optimize_inline_calls (tree fn)
   id.transform_return_to_modify = true;
   id.transform_lang_insert_block = NULL;
   id.statements_to_fold = pointer_set_create ();
+  if (MAY_HAVE_DEBUG_STMTS)
+    VARRAY_GENERIC_PTR_INIT (id.debug_stmts, 8, "debug_stmt");
 
   push_gimplify_context (&gctx);
 
@@ -3915,6 +4097,7 @@ unsave_expr_now (tree expr)
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -3930,6 +4113,8 @@ unsave_expr_now (tree expr)
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   return expr;
 }
@@ -4061,6 +4246,7 @@ copy_gimple_seq_and_replace_locals (gimp
   id.src_fn = current_function_decl;
   id.dst_fn = current_function_decl;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
 
   id.copy_decl = copy_decl_no_change;
   id.transform_call_graph_edges = CB_CGE_DUPLICATE;
@@ -4085,6 +4271,8 @@ copy_gimple_seq_and_replace_locals (gimp
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   return copy;
 }
@@ -4426,7 +4614,7 @@ tree_function_versioning (tree old_decl,
   tree p;
   unsigned i;
   struct ipa_replace_map *replace_info;
-  basic_block old_entry_block;
+  basic_block old_entry_block, bb;
   VEC (gimple, heap) *init_stmts = VEC_alloc (gimple, heap, 10);
 
   tree t_step;
@@ -4454,8 +4642,12 @@ tree_function_versioning (tree old_decl,
 
   /* Generate a new name for the new version. */
   id.statements_to_fold = pointer_set_create ();
+
+  if (MAY_HAVE_DEBUG_STMTS)
+    VARRAY_GENERIC_PTR_INIT (id.debug_stmts, 8, "debug_stmt");
   
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
   id.src_fn = old_decl;
   id.dst_fn = new_decl;
   id.src_node = old_version_node;
@@ -4556,15 +4748,17 @@ tree_function_versioning (tree old_decl,
   /* Renumber the lexical scoping (non-code) blocks consecutively.  */
   number_blocks (new_decl);
 
-  if (VEC_length (gimple, init_stmts))
-    {
-      basic_block bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
-      while (VEC_length (gimple, init_stmts))
-	insert_init_stmt (bb, VEC_pop (gimple, init_stmts));
-    }
+  /* We want to create the BB unconditionally, so that the addition of
+     debug stmts doesn't affect BB count, which may in the end cause
+     codegen differences.  */
+  bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
+  while (VEC_length (gimple, init_stmts))
+    insert_init_stmt (&id, bb, VEC_pop (gimple, init_stmts));
 
   /* Clean up.  */
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 
@@ -4596,11 +4790,14 @@ build_duplicate_type (tree type)
   id.dst_fn = current_function_decl;
   id.src_cfun = cfun;
   id.decl_map = pointer_map_create ();
+  id.debug_map = NULL;
   id.copy_decl = copy_decl_no_change;
 
   type = remap_type_1 (type, &id);
 
   pointer_map_destroy (id.decl_map);
+  if (id.debug_map)
+    pointer_map_destroy (id.debug_map);
 
   TYPE_CANONICAL (type) = type;
 
Index: gcc/tree-inline.h
===================================================================
--- gcc/tree-inline.h.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-inline.h	2009-06-05 05:07:56.000000000 -0300
@@ -22,9 +22,9 @@ along with GCC; see the file COPYING3.  
 #ifndef GCC_TREE_INLINE_H
 #define GCC_TREE_INLINE_H
 
+#include "varray.h"
 #include "pointer-set.h"
 
-
 /* Indicate the desired behavior wrt call graph edges.  We can either
    duplicate the edge (inlining, cloning), move the edge (versioning,
    parallelization), or move the edges of the clones (saving).  */
@@ -113,6 +113,15 @@ typedef struct copy_body_data
 
   /* Entry basic block to currently copied body.  */
   struct basic_block_def *entry_bb;
+
+  /* Debug statements that need processing.  */
+  varray_type debug_stmts;
+
+  /* A map from local declarations in the inlined function to
+     equivalents in the function into which it is being inlined, where
+     the originals have been mapped to a value rather than to a
+     variable.  */
+  struct pointer_map_t *debug_map;
 } copy_body_data;
 
 /* Weights of constructions for estimate_num_insns.  */
Index: gcc/gimple.c
===================================================================
--- gcc/gimple.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/gimple.c	2009-06-05 05:07:56.000000000 -0300
@@ -102,6 +102,7 @@ gss_for_code (enum gimple_code code)
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     case GIMPLE_LABEL:
+    case GIMPLE_DEBUG:
     case GIMPLE_SWITCH:			return GSS_WITH_OPS;
     case GIMPLE_ASM:			return GSS_ASM;
     case GIMPLE_BIND:			return GSS_BIND;
@@ -829,6 +830,28 @@ gimple_build_switch_vec (tree index, tre
 }
 
 
+/* Build a new GIMPLE_DEBUG_BIND statement.
+
+   VAR is bound to VALUE.  */
+
+gimple
+gimple_build_debug_bind_stat (tree var, tree value, gimple stmt MEM_STAT_DECL)
+{
+  gimple p = gimple_build_with_ops_stat (GIMPLE_DEBUG, VAR_DEBUG_VALUE, 2
+					 PASS_MEM_STAT);
+
+  gimple_debug_bind_set_var (p, var);
+  gimple_debug_bind_set_value (p, value);
+  if (stmt)
+    {
+      gimple_set_block (p, gimple_block (stmt));
+      gimple_set_location (p, gimple_location (stmt));
+    }
+
+  return p;
+}
+
+
 /* Build a GIMPLE_OMP_CRITICAL statement.
 
    BODY is the sequence of statements for which only one thread can execute.
@@ -1211,11 +1234,11 @@ empty_body_p (gimple_seq body)
 {
   gimple_stmt_iterator i;
 
-
   if (gimple_seq_empty_p (body))
     return true;
   for (i = gsi_start (body); !gsi_end_p (i); gsi_next (&i))
-    if (!empty_stmt_p (gsi_stmt (i)))
+    if (!empty_stmt_p (gsi_stmt (i))
+	&& !IS_DEBUG_STMT (gsi_stmt (i)))
       return false;
 
   return true;
@@ -2221,6 +2244,9 @@ gimple_has_side_effects (const_gimple s)
 {
   unsigned i;
 
+  if (IS_DEBUG_STMT (s))
+    return false;
+
   /* We don't have to scan the arguments to check for
      volatile arguments, though, at present, we still
      do a scan to check for TREE_SIDE_EFFECTS.  */
@@ -2314,6 +2340,8 @@ gimple_rhs_has_side_effects (const_gimpl
 	    return true;
 	  }
     }
+  else if (IS_DEBUG_STMT (s))
+    return false;
   else
     {
       /* For statements without an LHS, examine all arguments.  */
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/gimple.h	2009-06-05 05:07:56.000000000 -0300
@@ -754,6 +754,10 @@ gimple gimple_build_assign_with_ops_stat
 #define gimple_build_assign_with_ops(c,o1,o2,o3) \
   gimple_build_assign_with_ops_stat (c, o1, o2, o3 MEM_STAT_INFO)
 
+gimple gimple_build_debug_bind_stat (tree, tree, gimple MEM_STAT_DECL);
+#define gimple_build_debug_bind(var,val,stmt)			\
+  gimple_build_debug_bind_stat ((var), (val), (stmt) MEM_STAT_INFO)
+
 gimple gimple_build_call_vec (tree, VEC(tree, heap) *);
 gimple gimple_build_call (tree, unsigned, ...);
 gimple gimple_build_call_from_tree (tree);
@@ -3159,6 +3163,59 @@ gimple_switch_set_default_label (gimple 
 }
 
 
+/* Return the variable bound in a GIMPLE_DEBUG bind statement.  */
+
+static inline tree
+gimple_debug_bind_get_var (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_assert (dbg->gsbase.subcode == VAR_DEBUG_VALUE);
+  return gimple_op (dbg, 0);
+}
+
+/* Return the value bound to the variable in a GIMPLE_DEBUG bind
+   statement.  */
+
+static inline tree
+gimple_debug_bind_get_value (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_assert (dbg->gsbase.subcode == VAR_DEBUG_VALUE);
+  return gimple_op (dbg, 1);
+}
+
+/* Return a pointer to the value bound to the variable in a
+   GIMPLE_DEBUG bind statement.  */
+
+static inline tree *
+gimple_debug_bind_get_value_ptr (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_assert (dbg->gsbase.subcode == VAR_DEBUG_VALUE);
+  return gimple_op_ptr (dbg, 1);
+}
+
+/* Set the variable bound in a GIMPLE_DEBUG bind statement.  */
+
+static inline void
+gimple_debug_bind_set_var (gimple dbg, tree var)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_assert (dbg->gsbase.subcode == VAR_DEBUG_VALUE);
+  gimple_set_op (dbg, 0, var);
+}
+
+/* Set the value bound to the variable in a GIMPLE_DEBUG bind
+   statement.  */
+
+static inline void
+gimple_debug_bind_set_value (gimple dbg, tree value)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_assert (dbg->gsbase.subcode == VAR_DEBUG_VALUE);
+  gimple_set_op (dbg, 1, value);
+}
+
 /* Return the body for the OMP statement GS.  */
 
 static inline gimple_seq 
@@ -4308,6 +4365,54 @@ gsi_after_labels (basic_block bb)
   return gsi;
 }
 
+/* Advance the iterator to the next non-debug gimple statement.  */
+
+static inline void
+gsi_next_nondebug (gimple_stmt_iterator *i)
+{
+  do
+    gsi_next (i);
+  while (!gsi_end_p (*i) && IS_DEBUG_STMT (gsi_stmt (*i)));
+}
+
+/* Advance the iterator to the next non-debug gimple statement.  */
+
+static inline void
+gsi_prev_nondebug (gimple_stmt_iterator *i)
+{
+  do
+    gsi_prev (i);
+  while (!gsi_end_p (*i) && IS_DEBUG_STMT (gsi_stmt (*i)));
+}
+
+/* Return a new iterator pointing to the first non-debug statement in
+   basic block BB.  */
+
+static inline gimple_stmt_iterator
+gsi_start_nondebug_bb (basic_block bb)
+{
+  gimple_stmt_iterator i = gsi_start_bb (bb);
+
+  if (!gsi_end_p (i) && IS_DEBUG_STMT (gsi_stmt (i)))
+    gsi_next_nondebug (&i);
+
+  return i;
+}
+
+/* Return a new iterator pointing to the last non-debug statement in
+   basic block BB.  */
+
+static inline gimple_stmt_iterator
+gsi_last_nondebug_bb (basic_block bb)
+{
+  gimple_stmt_iterator i = gsi_last_bb (bb);
+
+  if (!gsi_end_p (i) && IS_DEBUG_STMT (gsi_stmt (i)))
+    gsi_prev_nondebug (&i);
+
+  return i;
+}
+
 /* Return a pointer to the current stmt.
    
   NOTE: You may want to use gsi_replace on the iterator itself,
Index: gcc/tree-flow.h
===================================================================
--- gcc/tree-flow.h.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-flow.h	2009-06-05 05:07:56.000000000 -0300
@@ -645,6 +645,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 (gimple, basic_block,
+				  const gimple_stmt_iterator *);
+void adjust_debug_stmts_for_var_def_move (tree, basic_block,
+					  const gimple_stmt_iterator *);
+void check_and_update_debug_stmt (gimple, bool (*)(tree));
 
 /* In tree-ssanames.c  */
 extern void init_ssanames (struct function *, int);
Index: gcc/tree-ssanames.c
===================================================================
--- gcc/tree-ssanames.c.orig	2009-06-05 05:07:48.000000000 -0300
+++ gcc/tree-ssanames.c	2009-06-05 05:07:56.000000000 -0300
@@ -205,6 +205,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-operands.c
===================================================================
--- gcc/tree-ssa-operands.c.orig	2009-06-05 05:07:49.000000000 -0300
+++ gcc/tree-ssa-operands.c	2009-06-05 05:07:56.000000000 -0300
@@ -1,5 +1,5 @@
 /* SSA operands management for trees.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -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;
 
@@ -634,6 +637,8 @@ add_virtual_operand (gimple stmt ATTRIBU
   if (flags & opf_no_vops)
     return;
 
+  gcc_assert ((flags & opf_debug_use) == 0);
+
   if (flags & opf_def)
     append_vdef (gimple_vop (cfun));
   else
@@ -845,10 +850,14 @@ get_expr_operands (gimple stmt, tree *ex
   enum tree_code code;
   enum tree_code_class codeclass;
   tree expr = *expr_p;
+  int uflags = opf_use;
 
   if (expr == NULL)
     return;
 
+  if ((flags & opf_debug_use) != 0)
+    uflags |= (flags & (opf_debug_use | opf_no_vops));
+
   code = TREE_CODE (expr);
   codeclass = TREE_CODE_CLASS (code);
 
@@ -859,7 +868,8 @@ get_expr_operands (gimple stmt, tree *ex
 	 reference to it, but the fact that the statement takes its
 	 address will be of interest to some passes (e.g. alias
 	 resolution).  */
-      mark_address_taken (TREE_OPERAND (expr, 0));
+      if (!(flags & opf_debug_use))
+	mark_address_taken (TREE_OPERAND (expr, 0));
 
       /* If the address is invariant, there may be no interesting
 	 variable references inside.  */
@@ -913,13 +923,13 @@ get_expr_operands (gimple stmt, tree *ex
 	  {
 	    if (TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1)))
 	      gimple_set_has_volatile_ops (stmt, 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;
@@ -928,15 +938,21 @@ get_expr_operands (gimple stmt, tree *ex
     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;
 
     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 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 | opf_no_vops);
       return;
 
     case CONSTRUCTOR:
@@ -949,7 +965,7 @@ get_expr_operands (gimple stmt, tree *ex
 	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;
       }
@@ -1025,6 +1041,13 @@ parse_ssa_operands (gimple stmt)
 
   if (code == GIMPLE_ASM)
     get_asm_expr_operands (stmt);
+  else if (IS_DEBUG_STMT (stmt))
+    {
+      if (IS_DEBUG_BIND (stmt)
+	  && VAR_DEBUG_VALUE_VALUE (stmt) != VAR_DEBUG_VALUE_NOVALUE)
+	get_expr_operands (stmt, &VAR_DEBUG_VALUE_VALUE (stmt),
+			   opf_use | opf_debug_use | opf_no_vops);
+    }
   else
     {
       size_t i, start = 0;
-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

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