public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Improve debug info for IPA-SRA optimized code - add DW_OP_GNU_parameter_ref support (PR debug/47858)
@ 2011-06-08 14:19 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2011-06-08 14:19 UTC (permalink / raw)
  To: Richard Guenther, Jason Merrill, Richard Henderson
  Cc: gcc-patches, Tom Tromey, Jan Kratochvil, Mark Wielaard, Josh Stone

Hi!

This is something I've already briefly talked about in my GCC Summit talk.
E.g. given a simple testcase like:

volatile int vv;

static __attribute__((noinline)) int
foo (int x, int y, int z)
{
  int a = x * 2;
  int b = y * 2;
  int c = z * 2;
  vv++;
  return x + z;
}

int
bar (int x)
{
  return foo (x, 2, 3) + foo (x, 4, 3) + foo (x + 6, x, 3) + x;
}

or the slightly larger testcase from this PR distilled from Linux kernel,
when this is compiled with -O2 -g, there is no debug info for
variable b and parameter y in foo.  The problem is that IPA-SRA decides
that y isn't really used and clones foo into a function which isn't passed
that argument at all.  z isn't passed at all either, as it is IPA-CP
optimized too, but there we emit already DEBUG z => 3 stmt (and similarly
for c debug stmt; we can do that because the passed parameter is constant
and always the same).

This patch introduces a new DWARF GNU extension opcode,
DW_OP_GNU_parameter_ref, which is similar to DW_OP_GNU_entry_value in that
it can use parent's DW_TAG_call_site DIE and its children, but is identified
by a DIE reference to the abstract optimized away DW_TAG_formal_parameter
(and corresponding DW_TAG_GNU_call_site_parameter should have the same
DW_AT_abstract_origin).  The operand is 4 byte CU relative reference like
in DW_OP_call4, the caller and callee should be in the same CU for this
anyway.

The patch has multiple parts:
1) introduces source bind debug stmts, printed as
   DEBUG x s=> y
   where x can be either some decl or DEBUG_EXPR_DECL and y is some
   parameter or variable.  This says that x at this spot has the same
   location as y at that spot, so in the future something representable
   by DW_OP_call*, currently just used early in the function
   to refer to PARM_DECLs or optimized away PARM_DECLs.
   tree_versioning and IPA-SRA modifications then can use these
   source binds to say that something is based on an original value
   of a parameter.  This alone fixes the above testcase with
   -O2 -g -fno-ipa-sra, where during versioning no SSA_NAME is created
   for the y parameter which isn't otherwise used, thus we were
   resetting DEBUG b => y_3(D) * 2 stmt because to avoid -g/-g0 codegen
   differences we couldn't create SSA_NAME in that case.
   In that case the source debug bind resulted in DEBUG_INSN mapping
   b to 2 * ENTRY_VALUE (y) and var-tracking even figured out it is still
   alive in %rsi.
2) introduces debug args vector, attached to the called function, which
   maps the abstract origin PARM_DECLs that were optimized out to
   some DEBUG_EXPR_DECLs.  This is populated by IPA-SRA (or, in the
   future other passes that do similar argument changes), the
   DEBUG_EXPR_DECLs are the same in all callers of the IPA-SRA modified
   function and there are debug bind stmts in front of the calls
   mapping the temps to some expressions.
3) introduces DEBUG_PARAMETER_REF rtl, whose parameter is the abstract
   origin PARM_DECL.  This is used in DEBUG_INSNs (from source debug binds
   of optimized away parameters) and during vartracking and in
   NOTE_INSN_CALL_ARG_LOCATION to reference call site values for the
   optimized away parameters.
4) and include/dwarf2.h and dwarf2out.c introduce the new
   DW_OP_GNU_parameter_ref op and emit it.

E.g. on the testcase distilled from the kernel the argument isn't removed,
but replaced by a field from a structure pointed out by the original
parameter, in that case still DW_OP_GNU_parameter_ref allows (when possible)
to query the value of it in the debugger.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-06-08  Jakub Jelinek  <jakub@redhat.com>

	PR debug/47858
	* gimple.h (enum gimple_debug_subcode): Add GIMPLE_DEBUG_SOURCE_BIND.
	(gimple_build_debug_source_bind_stat): New prototype.
	(gimple_build_debug_source_bind): Define.
	(gimple_debug_source_bind_p, gimple_debug_source_bind_get_var,
	gimple_debug_source_bind_get_value,
	gimple_debug_source_bind_get_value_ptr,
	gimple_debug_source_bind_set_var,
	gimple_debug_source_bind_set_value): New inlines.
	* gimple.c (gimple_build_debug_source_bind_stat): New function.
	* gimple-pretty-print.c (dump_gimple_debug): Handle
	GIMPLE_DEBUG_SOURCE_BIND.
	* sese.c (rename_uses): Handle gimple_debug_source_bind_p.
	* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Likewise.
	* tree-parloops.c (eliminate_local_variables,
	separate_decls_in_region): Likewise.
	(separate_decls_in_region_debug): Renamed from
	separate_decls_in_region_debug_bind.  Handle
	gimple_debug_source_bind_p.
	* tree.h (decl_debug_args_lookup, decl_debug_args_insert): New
	prototypes.
	(DECL_HAS_DEBUG_ARGS_P): Define.
	(struct tree_function_decl): Add has_debug_args_flag field.
	* tree.c (debug_args_for_decl): New variable.
	(decl_debug_args_lookup, decl_debug_args_insert): New functions.
	* tree-into-ssa.c (mark_def_sites): Handle uses in debug stmts.
	(rewrite_debug_stmt_uses): New function.
	(rewrite_stmt): Use it to rewrite debug stmt uses.
	* rtl.def (DEBUG_PARAMETER_REF): New.
	* rtl.h (DEBUG_PARAMETER_REF_DECL): Define.
	* cselib.c (rtx_equal_for_cselib_1, cselib_hash_rtx): Handle
	DEBUG_PARAMETER_REF.
	* rtl.c (rtx_equal_p_cb, rtx_equal_p, iterative_hash_rtx): Likewise.
	* print-rtl.c (print_rtx): Likewise.
	* tree-sra.c (sra_ipa_reset_debug_stmts): Prefer replacing of
	SSA_NAMEs with DEBUG_EXPR_DECLs initialized in source bind
	debug stmts in the first bb.
	* tree-inline.c (remap_ssa_name): If remapping default def
	of a PARM_DECL fails, map to a DEBUG_EXPR_DECL set in
	a source bind debug stmt.
	(remap_gimple_stmt): Handle gimple_debug_source_bind_p.
	(maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.  Avoid shadowing a variable.
	(tree_function_versioning): If DECL_HAS_DEBUG_ARGS_P, copy
	debug args vector from old_decl to new_decl.
	* ipa-prop.c (ipa_modify_call_arguments): For optimized away
	or modified parameters, add debug bind stmts before call
	setting DEBUG_EXPR_DECL which is remembered in debug args
	vector.
	* cfgexpand.c (expand_call_stmt): Call expand_debug_expr
	on DECL_DEBUG_EXPRs from debug args vector.
	(expand_debug_source_expr): New function.
	(expand_debug_locations): Use it for source bind insns.
	(expand_gimple_basic_block): Handle gimple_debug_source_bind_p.
	* var-tracking.c (prepare_call_arguments): Add debug args
	to call_arguments if any.
	* dwarf2out.c (dwarf_stack_op_name, size_of_loc_descr,
	output_loc_operands, output_loc_operands_raw,
	resolve_addr_in_expr, compare_loc_operands): Handle
	DW_OP_GNU_parameter_ref.
	(get_ref_die_offset, parameter_ref_descriptor): New functions.
	(mem_loc_descriptor): Handle DEBUG_PARAMETER_REF.
	(gen_subprogram_die): Handle parameters identified by
	DEBUG_PARAMETER_REF.

	* dwarf2.h (enum dwarf_location_atom): Add DW_OP_GNU_parameter_ref.

--- gcc/tree-into-ssa.c.jj	2011-06-08 08:53:10.000000000 +0200
+++ gcc/tree-into-ssa.c	2011-06-08 10:43:25.000000000 +0200
@@ -1,5 +1,5 @@
 /* Rewrite a program in Normal form into SSA.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
@@ -745,7 +745,17 @@ mark_def_sites (basic_block bb, gimple s
   set_rewrite_uses (stmt, false);
 
   if (is_gimple_debug (stmt))
-    return;
+    {
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+	{
+	  tree sym = USE_FROM_PTR (use_p);
+	  gcc_assert (DECL_P (sym));
+	  set_rewrite_uses (stmt, true);
+	}
+      if (rewrite_uses_p (stmt))
+	SET_BIT (interesting_blocks, bb->index);
+      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.  */
@@ -1279,6 +1289,73 @@ get_reaching_def (tree var)
 }
 
 
+/* Helper function for rewrite_stmt.  Rewrite uses in a debug stmt.  */
+
+static void
+rewrite_debug_stmt_uses (gimple stmt)
+{
+  use_operand_p use_p;
+  ssa_op_iter iter;
+  bool update = false;
+
+  FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+    {
+      tree var = USE_FROM_PTR (use_p), def = NULL_TREE;
+      gcc_assert (DECL_P (var));
+      if (var_ann (var) == NULL)
+	{
+	  if (TREE_CODE (var) == PARM_DECL && single_succ_p (ENTRY_BLOCK_PTR))
+	    {
+	      gimple_stmt_iterator gsi
+		= gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+	      int lim;
+	      /* Search a few source bind stmts at the start of first bb to
+		 see if a DEBUG_EXPR_DECL can't be reused.  */
+	      for (lim = 32;
+		   !gsi_end_p (gsi) && lim > 0;
+		   gsi_next (&gsi), lim--)
+		{
+		  gimple gstmt = gsi_stmt (gsi);
+		  if (!gimple_debug_source_bind_p (gstmt))
+		    break;
+		  if (gimple_debug_source_bind_get_value (gstmt) == var)
+		    {
+		      def = gimple_debug_source_bind_get_var (gstmt);
+		      if (TREE_CODE (def) == DEBUG_EXPR_DECL)
+			break;
+		      else
+			def = NULL_TREE;
+		    }
+		}
+	      /* If not, add a new source bind stmt.  */
+	      if (def == NULL_TREE)
+		{
+		  gimple def_temp;
+		  def = make_node (DEBUG_EXPR_DECL);
+		  def_temp = gimple_build_debug_source_bind (def, var, NULL);
+		  DECL_ARTIFICIAL (def) = 1;
+		  TREE_TYPE (def) = TREE_TYPE (var);
+		  DECL_MODE (def) = DECL_MODE (var);
+		  gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+		  gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+		}
+	      update = true;
+	    }
+	}
+      else
+	def = get_current_def (var);
+      if (def == NULL)
+	{
+	  gimple_debug_bind_reset_value (stmt);
+	  update_stmt (stmt);
+	  return;
+	}
+      SET_USE (use_p, def);
+    }
+  if (update)
+    update_stmt (stmt);
+}
+
 /* SSA Rewriting Step 2.  Rewrite every variable used in each statement in
    the block with its immediate reaching definitions.  Update the current
    definition of a variable when a new real or virtual definition is found.  */
@@ -1306,12 +1383,17 @@ rewrite_stmt (gimple_stmt_iterator si)
 
   /* Step 1.  Rewrite USES in the statement.  */
   if (rewrite_uses_p (stmt))
-    FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
-      {
-	tree var = USE_FROM_PTR (use_p);
-	gcc_assert (DECL_P (var));
-	SET_USE (use_p, get_reaching_def (var));
-      }
+    {
+      if (is_gimple_debug (stmt))
+	rewrite_debug_stmt_uses (stmt);
+      else
+	FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+	  {
+	    tree var = USE_FROM_PTR (use_p);
+	    gcc_assert (DECL_P (var));
+	    SET_USE (use_p, get_reaching_def (var));
+	  }
+    }
 
   /* Step 2.  Register the statement's DEF operands.  */
   if (register_defs_p (stmt))
--- gcc/sese.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/sese.c	2011-06-08 09:38:11.000000000 +0200
@@ -1,5 +1,5 @@
 /* Single entry single exit control flow regions.
-   Copyright (C) 2008, 2009, 2010
+   Copyright (C) 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Jan Sjodin <jan.sjodin@amd.com> and
    Sebastian Pop <sebastian.pop@amd.com>.
@@ -472,6 +472,8 @@ rename_uses (gimple copy, htab_t rename_
     {
       if (gimple_debug_bind_p (copy))
 	gimple_debug_bind_reset_value (copy);
+      else if (gimple_debug_source_bind_p (copy))
+	return false;
       else
 	gcc_unreachable ();
 
--- gcc/rtl.def.jj	2011-06-08 08:53:10.000000000 +0200
+++ gcc/rtl.def	2011-06-08 09:38:11.000000000 +0200
@@ -723,6 +723,10 @@ DEF_RTL_EXPR(DEBUG_IMPLICIT_PTR, "debug_
    parameter.  */
 DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "0", RTX_OBJ)
 
+/* Used in VAR_LOCATION for a reference to a parameter that has
+   been optimized away completely.  */
+DEF_RTL_EXPR(DEBUG_PARAMETER_REF, "debug_parameter_ref", "t", RTX_OBJ)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
--- gcc/gimple-pretty-print.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/gimple-pretty-print.c	2011-06-08 09:38:11.000000000 +0200
@@ -1,6 +1,6 @@
 /* Pretty formatting of GIMPLE statements and expressions.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011  Free Software Foundation, Inc.
    Contributed by Aldy Hernandez <aldyh@redhat.com> and
    Diego Novillo <dnovillo@google.com>
 
@@ -966,6 +966,17 @@ dump_gimple_debug (pretty_printer *buffe
 			 gimple_debug_bind_get_value (gs));
       break;
 
+    case GIMPLE_DEBUG_SOURCE_BIND:
+      if (flags & TDF_RAW)
+	dump_gimple_fmt (buffer, spc, flags, "%G SRCBIND <%T, %T>", gs,
+			 gimple_debug_source_bind_get_var (gs),
+			 gimple_debug_source_bind_get_value (gs));
+      else
+	dump_gimple_fmt (buffer, spc, flags, "# DEBUG %T s=> %T",
+			 gimple_debug_source_bind_get_var (gs),
+			 gimple_debug_source_bind_get_value (gs));
+      break;
+
     default:
       gcc_unreachable ();
     }
--- gcc/cselib.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/cselib.c	2011-06-08 09:38:11.000000000 +0200
@@ -812,6 +812,10 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, en
       return DEBUG_IMPLICIT_PTR_DECL (x)
 	     == DEBUG_IMPLICIT_PTR_DECL (y);
 
+    case DEBUG_PARAMETER_REF:
+      return DEBUG_PARAMETER_REF_DECL (x)
+	     == DEBUG_PARAMETER_REF_DECL (y);
+
     case ENTRY_VALUE:
       /* ENTRY_VALUEs are function invariant, it is thus undesirable to
 	 use rtx_equal_for_cselib_1 to compare the operands.  */
@@ -963,6 +967,11 @@ cselib_hash_rtx (rtx x, int create, enum
 	      + DECL_UID (DEBUG_IMPLICIT_PTR_DECL (x));
       return hash ? hash : (unsigned int) DEBUG_IMPLICIT_PTR;
 
+    case DEBUG_PARAMETER_REF:
+      hash += ((unsigned) DEBUG_PARAMETER_REF << 7)
+	      + DECL_UID (DEBUG_PARAMETER_REF_DECL (x));
+      return hash ? hash : (unsigned int) DEBUG_PARAMETER_REF;
+
     case ENTRY_VALUE:
       /* ENTRY_VALUEs are function invariant, thus try to avoid
 	 recursing on argument if ENTRY_VALUE is one of the
--- gcc/rtl.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/rtl.c	2011-06-08 09:38:11.000000000 +0200
@@ -413,6 +413,10 @@ rtx_equal_p_cb (const_rtx x, const_rtx y
       return DEBUG_IMPLICIT_PTR_DECL (x)
 	     == DEBUG_IMPLICIT_PTR_DECL (y);
 
+    case DEBUG_PARAMETER_REF:
+      return DEBUG_PARAMETER_REF_DECL (x)
+	     == DEBUG_PARAMETER_REF_DECL (x);
+
     case ENTRY_VALUE:
       return rtx_equal_p_cb (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y), cb);
 
@@ -548,6 +552,10 @@ rtx_equal_p (const_rtx x, const_rtx y)
       return DEBUG_IMPLICIT_PTR_DECL (x)
 	     == DEBUG_IMPLICIT_PTR_DECL (y);
 
+    case DEBUG_PARAMETER_REF:
+      return DEBUG_PARAMETER_REF_DECL (x)
+	     == DEBUG_PARAMETER_REF_DECL (y);
+
     case ENTRY_VALUE:
       return rtx_equal_p (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y));
 
@@ -660,6 +668,7 @@ iterative_hash_rtx (const_rtx x, hashval
     case CONST_DOUBLE:
     case CONST_FIXED:
     case DEBUG_IMPLICIT_PTR:
+    case DEBUG_PARAMETER_REF:
       return hash;
     default:
       break;
--- gcc/tree.c.jj	2011-06-08 08:53:15.000000000 +0200
+++ gcc/tree.c	2011-06-08 09:38:11.000000000 +0200
@@ -202,6 +202,9 @@ static GTY ((if_marked ("tree_decl_map_m
 static GTY ((if_marked ("tree_decl_map_marked_p"), param_is (struct tree_decl_map)))
      htab_t value_expr_for_decl;
 
+static GTY ((if_marked ("tree_vec_map_marked_p"), param_is (struct tree_vec_map)))
+     htab_t debug_args_for_decl;
+
 static GTY ((if_marked ("tree_priority_map_marked_p"),
 	     param_is (struct tree_priority_map)))
   htab_t init_priority_for_decl;
@@ -5994,6 +5997,49 @@ decl_value_expr_insert (tree from, tree 
   *(struct tree_decl_map **) loc = h;
 }
 
+/* Lookup a vector of debug arguments for FROM, and return it if we
+   find one.  */
+
+VEC(tree, gc) **
+decl_debug_args_lookup (tree from)
+{
+  struct tree_vec_map *h, in;
+
+  if (!DECL_HAS_DEBUG_ARGS_P (from))
+    return NULL;
+  gcc_checking_assert (debug_args_for_decl != NULL);
+  in.base.from = from;
+  h = (struct tree_vec_map *)
+      htab_find_with_hash (debug_args_for_decl, &in, DECL_UID (from));
+  if (h)
+    return &h->to;
+  return NULL;
+}
+
+/* Insert a mapping FROM->empty vector of debug arguments in the value
+   expression hashtable.  */
+
+VEC(tree, gc) **
+decl_debug_args_insert (tree from)
+{
+  struct tree_vec_map *h;
+  void **loc;
+
+  if (DECL_HAS_DEBUG_ARGS_P (from))
+    return decl_debug_args_lookup (from);
+  if (debug_args_for_decl == NULL)
+    debug_args_for_decl = htab_create_ggc (64, tree_vec_map_hash,
+					   tree_vec_map_eq, 0);
+  h = ggc_alloc_tree_vec_map ();
+  h->base.from = from;
+  h->to = NULL;
+  loc = htab_find_slot_with_hash (debug_args_for_decl, h, DECL_UID (from),
+				  INSERT);
+  *(struct tree_vec_map **) loc = h;
+  DECL_HAS_DEBUG_ARGS_P (from) = 1;
+  return &h->to;
+}
+
 /* Hashing of types so that we don't make duplicates.
    The entry point is `type_hash_canon'.  */
 
--- gcc/gimple.h.jj	2011-06-08 08:53:15.000000000 +0200
+++ gcc/gimple.h	2011-06-08 09:38:11.000000000 +0200
@@ -1,6 +1,6 @@
 /* Gimple IR definitions.
 
-   Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Aldy Hernandez <aldyh@redhat.com>
 
 This file is part of GCC.
@@ -117,12 +117,13 @@ enum gf_mask {
     GF_PREDICT_TAKEN		= 1 << 15
 };
 
-/* Currently, there's only one type of gimple debug stmt.  Others are
+/* Currently, there are only two types of gimple debug stmt.  Others are
    envisioned, for example, to enable the generation of is_stmt notes
    in line number information, to mark sequence points, etc.  This
    subcode is to be used to tell them apart.  */
 enum gimple_debug_subcode {
-  GIMPLE_DEBUG_BIND = 0
+  GIMPLE_DEBUG_BIND = 0,
+  GIMPLE_DEBUG_SOURCE_BIND = 1
 };
 
 /* Masks for selecting a pass local flag (PLF) to work on.  These
@@ -823,6 +824,9 @@ gimple gimple_build_assign_with_ops_stat
 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_debug_source_bind_stat (tree, tree, gimple MEM_STAT_DECL);
+#define gimple_build_debug_source_bind(var,val,stmt)			\
+  gimple_build_debug_source_bind_stat ((var), (val), (stmt) MEM_STAT_INFO)
 
 gimple gimple_build_call_vec (tree, VEC(tree, heap) *);
 gimple gimple_build_call (tree, unsigned, ...);
@@ -3583,6 +3587,70 @@ gimple_debug_bind_has_value_p (gimple db
 
 #undef GIMPLE_DEBUG_BIND_NOVALUE
 
+/* Return true if S is a GIMPLE_DEBUG SOURCE BIND statement.  */
+
+static inline bool
+gimple_debug_source_bind_p (const_gimple s)
+{
+  if (is_gimple_debug (s))
+    return s->gsbase.subcode == GIMPLE_DEBUG_SOURCE_BIND;
+
+  return false;
+}
+
+/* Return the variable bound in a GIMPLE_DEBUG source bind statement.  */
+
+static inline tree
+gimple_debug_source_bind_get_var (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_gimple_checking_assert (gimple_debug_source_bind_p (dbg));
+  return gimple_op (dbg, 0);
+}
+
+/* Return the value bound to the variable in a GIMPLE_DEBUG source bind
+   statement.  */
+
+static inline tree
+gimple_debug_source_bind_get_value (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_gimple_checking_assert (gimple_debug_source_bind_p (dbg));
+  return gimple_op (dbg, 1);
+}
+
+/* Return a pointer to the value bound to the variable in a
+   GIMPLE_DEBUG source bind statement.  */
+
+static inline tree *
+gimple_debug_source_bind_get_value_ptr (gimple dbg)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_gimple_checking_assert (gimple_debug_source_bind_p (dbg));
+  return gimple_op_ptr (dbg, 1);
+}
+
+/* Set the variable bound in a GIMPLE_DEBUG source bind statement.  */
+
+static inline void
+gimple_debug_source_bind_set_var (gimple dbg, tree var)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_gimple_checking_assert (gimple_debug_source_bind_p (dbg));
+  gimple_set_op (dbg, 0, var);
+}
+
+/* Set the value bound to the variable in a GIMPLE_DEBUG source bind
+   statement.  */
+
+static inline void
+gimple_debug_source_bind_set_value (gimple dbg, tree value)
+{
+  GIMPLE_CHECK (dbg, GIMPLE_DEBUG);
+  gcc_gimple_checking_assert (gimple_debug_source_bind_p (dbg));
+  gimple_set_op (dbg, 1, value);
+}
+
 /* Return the body for the OMP statement GS.  */
 
 static inline gimple_seq
--- gcc/dwarf2out.c.jj	2011-06-08 08:53:10.000000000 +0200
+++ gcc/dwarf2out.c	2011-06-08 09:38:11.000000000 +0200
@@ -4807,6 +4807,8 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_GNU_convert";
     case DW_OP_GNU_reinterpret:
       return "DW_OP_GNU_reinterpret";
+    case DW_OP_GNU_parameter_ref:
+      return "DW_OP_GNU_parameter_ref";
 
     default:
       return "OP_<unknown>";
@@ -5081,6 +5083,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
 	  = get_base_type_offset (loc->dw_loc_oprnd1.v.val_die_ref.die);
 	size += size_of_uleb128 (o);
       }
+      break;
+    case DW_OP_GNU_parameter_ref:
+      size += 4;
+      break;
     default:
       break;
     }
@@ -5118,6 +5124,7 @@ size_of_locs (dw_loc_descr_ref loc)
 
 static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void get_ref_die_offset_label (char *, dw_die_ref);
+static unsigned long int get_ref_die_offset (dw_die_ref);
 static void output_loc_sequence (dw_loc_descr_ref, int);
 
 /* Output location description stack opcode's operands (if any).
@@ -5463,6 +5470,15 @@ output_loc_operands (dw_loc_descr_ref lo
       }
       break;
 
+    case DW_OP_GNU_parameter_ref:
+      {
+	unsigned long o;
+	gcc_assert (val1->val_class == dw_val_class_die_ref);
+	o = get_ref_die_offset (val1->v.val_die_ref.die);
+	dw2_asm_output_data (4, o, NULL);
+      }
+      break;
+
     default:
       /* Other codes have no operands.  */
       break;
@@ -5645,6 +5661,7 @@ output_loc_operands_raw (dw_loc_descr_re
     case DW_OP_GNU_deref_type:
     case DW_OP_GNU_convert:
     case DW_OP_GNU_reinterpret:
+    case DW_OP_GNU_parameter_ref:
       gcc_unreachable ();
       break;
 
@@ -6960,6 +6977,15 @@ get_base_type_offset (dw_die_ref ref)
   return ref->die_offset;
 }
 
+/* Return die_offset of a DIE reference other than base type.  */
+
+static unsigned long int
+get_ref_die_offset (dw_die_ref ref)
+{
+  gcc_assert (ref->die_offset);
+  return ref->die_offset;
+}
+
 /* Convert a DIE tag into its string name.  */
 
 static const char *
@@ -14476,6 +14502,34 @@ rotate_loc_descriptor (rtx rtl, enum mac
   return ret;
 }
 
+/* Helper function for mem_loc_descriptor.  Return DW_OP_GNU_parameter_ref
+   for DEBUG_PARAMETER_REF RTL.  */
+
+static dw_loc_descr_ref
+parameter_ref_descriptor (rtx rtl)
+{
+  dw_loc_descr_ref ret;
+  dw_die_ref ref;
+
+  if (dwarf_strict)
+    return NULL;
+  gcc_assert (TREE_CODE (DEBUG_PARAMETER_REF_DECL (rtl)) == PARM_DECL);
+  ref = lookup_decl_die (DEBUG_PARAMETER_REF_DECL (rtl));
+  ret = new_loc_descr (DW_OP_GNU_parameter_ref, 0, 0);
+  if (ref)
+    {
+      ret->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+      ret->dw_loc_oprnd1.v.val_die_ref.die = ref;
+      ret->dw_loc_oprnd1.v.val_die_ref.external = 0;
+    }
+  else
+    {
+      ret->dw_loc_oprnd1.val_class = dw_val_class_decl_ref;
+      ret->dw_loc_oprnd1.v.val_decl_ref = DEBUG_PARAMETER_REF_DECL (rtl);
+    }
+  return ret;
+}
+
 /* The following routine converts the RTL for a variable or parameter
    (resident in memory) into an equivalent Dwarf representation of a
    mechanism for getting the address of that same variable onto the top of a
@@ -14822,7 +14876,11 @@ mem_loc_descriptor (rtx rtl, enum machin
       mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
       mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
       mem_loc_result->dw_loc_oprnd1.v.val_loc = op0;
-      return mem_loc_result;
+      break;
+
+    case DEBUG_PARAMETER_REF:
+      mem_loc_result = parameter_ref_descriptor (rtl);
+      break;
 
     case PRE_MODIFY:
       /* Extract the PLUS expression nested inside and fall into
@@ -20528,7 +20586,7 @@ gen_subprogram_die (tree decl, dw_die_re
 		{
 		  dw_loc_descr_ref reg, val;
 		  enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
-		  dw_die_ref cdie;
+		  dw_die_ref cdie, tdie = NULL;
 
 		  next_arg = XEXP (arg, 1);
 		  if (REG_P (XEXP (XEXP (arg, 0), 0))
@@ -20559,6 +20617,7 @@ gen_subprogram_die (tree decl, dw_die_re
 		      tlocc = XEXP (XEXP (arg, 0), 1);
 		      continue;
 		    }
+		  reg = NULL;
 		  if (REG_P (XEXP (XEXP (arg, 0), 0)))
 		    reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
 					      VAR_INIT_STATUS_INITIALIZED);
@@ -20570,9 +20629,20 @@ gen_subprogram_die (tree decl, dw_die_re
 						GET_MODE (mem),
 						VAR_INIT_STATUS_INITIALIZED);
 		    }
+		  else if (GET_CODE (XEXP (XEXP (arg, 0), 0))
+			   == DEBUG_PARAMETER_REF)
+		    {
+		      tree tdecl
+			= DEBUG_PARAMETER_REF_DECL (XEXP (XEXP (arg, 0), 0));
+		      tdie = lookup_decl_die (tdecl);
+		      if (tdie == NULL)
+			continue;
+		    }
 		  else
 		    continue;
-		  if (reg == NULL)
+		  if (reg == NULL
+		      && GET_CODE (XEXP (XEXP (arg, 0), 0))
+			 != DEBUG_PARAMETER_REF)
 		    continue;
 		  val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), mode,
 					    VOIDmode,
@@ -20582,8 +20652,11 @@ gen_subprogram_die (tree decl, dw_die_re
 		  if (die == NULL)
 		    die = gen_call_site_die (decl, subr_die, ca_loc);
 		  cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
-				  NULL_TREE);		
-		  add_AT_loc (cdie, DW_AT_location, reg);
+				  NULL_TREE);
+		  if (reg != NULL)
+		    add_AT_loc (cdie, DW_AT_location, reg);
+		  else if (tdie != NULL)
+		    add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
 		  add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
 		  if (next_arg != XEXP (arg, 1))
 		    {
@@ -24165,6 +24238,7 @@ resolve_addr_in_expr (dw_loc_descr_ref l
 	  return false;
 	break;
       case DW_OP_GNU_implicit_pointer:
+      case DW_OP_GNU_parameter_ref:
 	if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
 	  {
 	    dw_die_ref ref
@@ -24705,6 +24779,10 @@ compare_loc_operands (dw_loc_descr_ref x
     case DW_OP_GNU_convert:
     case DW_OP_GNU_reinterpret:
       return valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
+    case DW_OP_GNU_parameter_ref:
+      return valx1->val_class == dw_val_class_die_ref
+	     && valx1->val_class == valy1->val_class
+	     && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die;
     default:
       /* Other codes have no operands.  */
       return true;
--- gcc/gimple.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/gimple.c	2011-06-08 09:38:11.000000000 +0200
@@ -1,6 +1,6 @@
 /* Gimple IR support functions.
 
-   Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Aldy Hernandez <aldyh@redhat.com>
 
 This file is part of GCC.
@@ -866,6 +866,30 @@ gimple_build_debug_bind_stat (tree var, 
 }
 
 
+/* Build a new GIMPLE_DEBUG_SOURCE_BIND statement.
+
+   VAR is bound to VALUE; block and location are taken from STMT.  */
+
+gimple
+gimple_build_debug_source_bind_stat (tree var, tree value,
+				     gimple stmt MEM_STAT_DECL)
+{
+  gimple p = gimple_build_with_ops_stat (GIMPLE_DEBUG,
+					 (unsigned)GIMPLE_DEBUG_SOURCE_BIND, 2
+					 PASS_MEM_STAT);
+
+  gimple_debug_source_bind_set_var (p, var);
+  gimple_debug_source_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.
--- gcc/print-rtl.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/print-rtl.c	2011-06-08 09:38:11.000000000 +0200
@@ -552,6 +552,8 @@ print_rtx (const_rtx in_rtx)
 #ifndef GENERATOR_FILE
 	if (i == 0 && GET_CODE (in_rtx) == DEBUG_IMPLICIT_PTR)
 	  print_mem_expr (outfile, DEBUG_IMPLICIT_PTR_DECL (in_rtx));
+	else if (i == 0 && GET_CODE (in_rtx) == DEBUG_PARAMETER_REF)
+	  print_mem_expr (outfile, DEBUG_PARAMETER_REF_DECL (in_rtx));
 	else
 	  dump_addr (outfile, " ", XTREE (in_rtx, i));
 #endif
--- gcc/tree-sra.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/tree-sra.c	2011-06-08 09:38:11.000000000 +0200
@@ -4295,28 +4295,87 @@ static void
 sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
 {
   int i, len;
+  gimple_stmt_iterator *gsip = NULL, gsi;
 
+  if (MAY_HAVE_DEBUG_STMTS && single_succ_p (ENTRY_BLOCK_PTR))
+    {
+      gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+      gsip = &gsi;
+    }
   len = VEC_length (ipa_parm_adjustment_t, adjustments);
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
       imm_use_iterator ui;
-      gimple stmt;
-      tree name;
+      gimple stmt, def_temp;
+      tree name, vexpr, copy = NULL_TREE;
+      use_operand_p use_p;
 
       adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
       if (adj->copy_param || !is_gimple_reg (adj->base))
 	continue;
       name = gimple_default_def (cfun, adj->base);
-      if (!name)
-	continue;
-      FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+      vexpr = NULL;
+      if (name)
+	FOR_EACH_IMM_USE_STMT (stmt, ui, name)
+	  {
+	    /* All other users must have been removed by
+	       ipa_sra_modify_function_body.  */
+	    gcc_assert (is_gimple_debug (stmt));
+	    if (vexpr == NULL && gsip != NULL)
+	      {
+		gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+		vexpr = make_node (DEBUG_EXPR_DECL);
+		def_temp = gimple_build_debug_source_bind (vexpr, adj->base,
+							   NULL);
+		DECL_ARTIFICIAL (vexpr) = 1;
+		TREE_TYPE (vexpr) = TREE_TYPE (name);
+		DECL_MODE (vexpr) = DECL_MODE (adj->base);
+		gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
+	      }
+	    if (vexpr)
+	      {
+		FOR_EACH_IMM_USE_ON_STMT (use_p, ui)
+		  SET_USE (use_p, vexpr);
+	      }
+	    else
+	      gimple_debug_bind_reset_value (stmt);
+	    update_stmt (stmt);
+	  }
+      /* Create a VAR_DECL for debug info purposes.  */
+      if (!DECL_IGNORED_P (adj->base))
+	{
+	  copy = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+			     VAR_DECL, DECL_NAME (adj->base),
+			     TREE_TYPE (adj->base));
+	  if (DECL_PT_UID_SET_P (adj->base))
+	    SET_DECL_PT_UID (copy, DECL_PT_UID (adj->base));
+	  TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (adj->base);
+	  TREE_READONLY (copy) = TREE_READONLY (adj->base);
+	  TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (adj->base);
+	  DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (adj->base);
+	  DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (adj->base);
+	  DECL_IGNORED_P (copy) = DECL_IGNORED_P (adj->base);
+	  DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (adj->base);
+	  DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
+	  SET_DECL_RTL (copy, 0);
+	  TREE_USED (copy) = 1;
+	  DECL_CONTEXT (copy) = current_function_decl;
+	  add_referenced_var (copy);
+	  add_local_decl (cfun, copy);
+	  DECL_CHAIN (copy) =
+	    BLOCK_VARS (DECL_INITIAL (current_function_decl));
+	  BLOCK_VARS (DECL_INITIAL (current_function_decl)) = copy;
+	}
+      if (gsip != NULL && copy && target_for_debug_bind (adj->base))
 	{
-	  /* All other users must have been removed by
-	     ipa_sra_modify_function_body.  */
-	  gcc_assert (is_gimple_debug (stmt));
-	  gimple_debug_bind_reset_value (stmt);
-	  update_stmt (stmt);
+	  gcc_assert (TREE_CODE (adj->base) == PARM_DECL);
+	  if (vexpr)
+	    def_temp = gimple_build_debug_bind (copy, vexpr, NULL);
+	  else
+	    def_temp = gimple_build_debug_source_bind (copy, adj->base,
+						       NULL);
+	  gsi_insert_before (gsip, def_temp, GSI_SAME_STMT);
 	}
     }
 }
--- gcc/var-tracking.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/var-tracking.c	2011-06-08 09:38:11.000000000 +0200
@@ -5810,6 +5810,29 @@ prepare_call_arguments (basic_block bb, 
 	  }
       }
 
+  /* Add debug arguments.  */
+  if (fndecl
+      && TREE_CODE (fndecl) == FUNCTION_DECL
+      && DECL_HAS_DEBUG_ARGS_P (fndecl))
+    {
+      VEC(tree, gc) **debug_args = decl_debug_args_lookup (fndecl);
+      if (debug_args)
+	{
+	  unsigned int ix;
+	  tree param;
+	  for (ix = 0; VEC_iterate (tree, *debug_args, ix, param); ix += 2)
+	    {
+	      rtx item;
+	      tree dtemp = VEC_index (tree, *debug_args, ix + 1);
+	      enum machine_mode mode = DECL_MODE (dtemp);
+	      item = gen_rtx_DEBUG_PARAMETER_REF (mode, param);
+	      item = gen_rtx_CONCAT (mode, item, DECL_RTL (dtemp));
+	      call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+						  call_arguments);
+	    }
+	}
+    }
+
   /* Reverse call_arguments chain.  */
   prev = NULL_RTX;
   for (cur = call_arguments; cur; cur = next)
--- gcc/tree-inline.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/tree-inline.c	2011-06-08 09:38:11.000000000 +0200
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -188,6 +188,33 @@ remap_ssa_name (tree name, copy_body_dat
 
   if (processing_debug_stmt)
     {
+      if (TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
+	  && SSA_NAME_IS_DEFAULT_DEF (name)
+	  && id->entry_bb == NULL
+	  && single_succ_p (ENTRY_BLOCK_PTR))
+	{
+	  tree vexpr = make_node (DEBUG_EXPR_DECL);
+	  gimple def_temp;
+	  gimple_stmt_iterator gsi;
+	  tree val = SSA_NAME_VAR (name);
+
+	  n = (tree *) pointer_map_contains (id->decl_map, val);
+	  if (n != NULL)
+	    val = *n;
+	  if (TREE_CODE (val) != PARM_DECL)
+	    {
+	      processing_debug_stmt = -1;
+	      return name;
+	    }
+	  def_temp = gimple_build_debug_source_bind (vexpr, val, NULL);
+	  DECL_ARTIFICIAL (vexpr) = 1;
+	  TREE_TYPE (vexpr) = TREE_TYPE (name);
+	  DECL_MODE (vexpr) = DECL_MODE (SSA_NAME_VAR (name));
+	  gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+	  gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+	  return vexpr;
+	}
+
       processing_debug_stmt = -1;
       return name;
     }
@@ -1403,6 +1430,14 @@ remap_gimple_stmt (gimple stmt, copy_bod
 	  VEC_safe_push (gimple, heap, id->debug_stmts, copy);
 	  return copy;
 	}
+      if (gimple_debug_source_bind_p (stmt))
+	{
+	  copy = gimple_build_debug_source_bind
+		   (gimple_debug_source_bind_get_var (stmt),
+		    gimple_debug_source_bind_get_value (stmt), stmt);
+	  VEC_safe_push (gimple, heap, id->debug_stmts, copy);
+	  return copy;
+	}
 
       /* Create a new deep copy of the statement.  */
       copy = gimple_copy (stmt);
@@ -1478,7 +1513,7 @@ remap_gimple_stmt (gimple stmt, copy_bod
 
   gimple_set_block (copy, new_block);
 
-  if (gimple_debug_bind_p (copy))
+  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
     return copy;
 
   /* Remap all the operands in COPY.  */
@@ -2151,22 +2186,33 @@ maybe_move_debug_stmts_to_successors (co
 	    {
 	      si = ssi;
 	      gsi_prev (&ssi);
-	      if (!single_pred_p (e->dest))
+	      if (!single_pred_p (e->dest) && gimple_debug_bind_p (stmt))
 		gimple_debug_bind_reset_value (stmt);
 	      gsi_remove (&si, false);
 	      gsi_insert_before (&dsi, stmt, GSI_SAME_STMT);
 	      continue;
 	    }
 
-	  var = gimple_debug_bind_get_var (stmt);
-	  if (single_pred_p (e->dest))
+	  if (gimple_debug_bind_p (stmt))
+	    {
+	      var = gimple_debug_bind_get_var (stmt);
+	      if (single_pred_p (e->dest))
+		{
+		  value = gimple_debug_bind_get_value (stmt);
+		  value = unshare_expr (value);
+		}
+	      else
+		value = NULL_TREE;
+	      new_stmt = gimple_build_debug_bind (var, value, stmt);
+	    }
+	  else if (gimple_debug_source_bind_p (stmt))
 	    {
-	      value = gimple_debug_bind_get_value (stmt);
-	      value = unshare_expr (value);
+	      var = gimple_debug_source_bind_get_var (stmt);
+	      value = gimple_debug_source_bind_get_value (stmt);
+	      new_stmt = gimple_build_debug_source_bind (var, value, stmt);
 	    }
 	  else
-	    value = NULL_TREE;
-	  new_stmt = gimple_build_debug_bind (var, value, stmt);
+	    gcc_unreachable ();
 	  gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
 	  VEC_safe_push (gimple, heap, id->debug_stmts, new_stmt);
 	  gsi_prev (&ssi);
@@ -2317,7 +2363,6 @@ copy_debug_stmt (gimple stmt, copy_body_
   t = id->block;
   if (gimple_block (stmt))
     {
-      tree *n;
       n = (tree *) pointer_map_contains (id->decl_map, gimple_block (stmt));
       if (n)
 	t = *n;
@@ -2330,7 +2375,10 @@ copy_debug_stmt (gimple stmt, copy_body_
 
   processing_debug_stmt = 1;
 
-  t = gimple_debug_bind_get_var (stmt);
+  if (gimple_debug_source_bind_p (stmt))
+    t = gimple_debug_source_bind_get_var (stmt);
+  else
+    t = gimple_debug_bind_get_var (stmt);
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = (tree *) pointer_map_contains (id->debug_map, t)))
@@ -2347,15 +2395,24 @@ copy_debug_stmt (gimple stmt, copy_body_
   else
     walk_tree (&t, remap_gimple_op_r, &wi, NULL);
 
-  gimple_debug_bind_set_var (stmt, t);
+  if (gimple_debug_bind_p (stmt))
+    {
+      gimple_debug_bind_set_var (stmt, t);
+
+      if (gimple_debug_bind_has_value_p (stmt))
+	walk_tree (gimple_debug_bind_get_value_ptr (stmt),
+		   remap_gimple_op_r, &wi, NULL);
 
-  if (gimple_debug_bind_has_value_p (stmt))
-    walk_tree (gimple_debug_bind_get_value_ptr (stmt),
-	       remap_gimple_op_r, &wi, NULL);
-
-  /* Punt if any decl couldn't be remapped.  */
-  if (processing_debug_stmt < 0)
-    gimple_debug_bind_reset_value (stmt);
+      /* Punt if any decl couldn't be remapped.  */
+      if (processing_debug_stmt < 0)
+	gimple_debug_bind_reset_value (stmt);
+    }
+  else if (gimple_debug_source_bind_p (stmt))
+    {
+      gimple_debug_source_bind_set_var (stmt, t);
+      walk_tree (gimple_debug_source_bind_get_value_ptr (stmt),
+		 remap_gimple_op_r, &wi, NULL);
+    }
 
   processing_debug_stmt = 0;
 
@@ -4999,6 +5056,20 @@ tree_function_versioning (tree old_decl,
   new_version_node = cgraph_get_node (new_decl);
   gcc_checking_assert (new_version_node);
 
+  /* Copy over debug args.  */
+  if (DECL_HAS_DEBUG_ARGS_P (old_decl))
+    {
+      VEC(tree, gc) **new_debug_args, **old_debug_args;
+      gcc_checking_assert (decl_debug_args_lookup (new_decl) == NULL);
+      DECL_HAS_DEBUG_ARGS_P (new_decl) = 0;
+      old_debug_args = decl_debug_args_lookup (old_decl);
+      if (old_debug_args)
+	{
+	  new_debug_args = decl_debug_args_insert (new_decl);
+	  *new_debug_args = VEC_copy (tree, gc, *old_debug_args);
+	}
+    }
+
   /* Output the inlining info for this abstract function, since it has been
      inlined.  If we don't do this now, we can lose the information about the
      variables in the function when the blocks get blown away as soon as we
--- gcc/rtl.h.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/rtl.h	2011-06-08 09:38:11.000000000 +0200
@@ -941,6 +941,9 @@ extern const char * const reg_note_name[
 /* VAR_DECL/PARM_DECL DEBUG_IMPLICIT_PTR takes address of.  */
 #define DEBUG_IMPLICIT_PTR_DECL(RTX) XCTREE (RTX, 0, DEBUG_IMPLICIT_PTR)
 
+/* PARM_DECL DEBUG_PARAMETER_REF references.  */
+#define DEBUG_PARAMETER_REF_DECL(RTX) XCTREE (RTX, 0, DEBUG_PARAMETER_REF)
+
 /* Possible initialization status of a variable.   When requested
    by the user, this information is tracked and recorded in the DWARF
    debug information, along with the variable's location.  */
--- gcc/ipa-prop.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/ipa-prop.c	2011-06-08 09:59:48.000000000 +0200
@@ -1,5 +1,5 @@
 /* Interprocedural analyses.
-   Copyright (C) 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -2390,6 +2390,7 @@ ipa_modify_call_arguments (struct cgraph
 			   ipa_parm_adjustment_vec adjustments)
 {
   VEC(tree, heap) *vargs;
+  VEC(tree, gc) **debug_args = NULL;
   gimple new_stmt;
   gimple_stmt_iterator gsi;
   tree callee_decl;
@@ -2397,6 +2398,7 @@ ipa_modify_call_arguments (struct cgraph
 
   len = VEC_length (ipa_parm_adjustment_t, adjustments);
   vargs = VEC_alloc (tree, heap, len);
+  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
 
   gsi = gsi_for_stmt (stmt);
   for (i = 0; i < len; i++)
@@ -2487,6 +2489,42 @@ ipa_modify_call_arguments (struct cgraph
 					   NULL, true, GSI_SAME_STMT);
 	  VEC_quick_push (tree, vargs, expr);
 	}
+      if (!adj->copy_param && MAY_HAVE_DEBUG_STMTS)
+	{
+	  unsigned int ix;
+	  tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
+	  gimple def_temp;
+
+	  arg = gimple_call_arg (stmt, adj->base_index);
+	  if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg)))
+	    {
+	      if (!fold_convertible_p (TREE_TYPE (origin), arg))
+		continue;
+	      arg = fold_convert_loc (gimple_location (stmt),
+				      TREE_TYPE (origin), arg);
+	    }
+	  if (debug_args == NULL)
+	    debug_args = decl_debug_args_insert (callee_decl);
+	  for (ix = 0; VEC_iterate (tree, *debug_args, ix, ddecl); ix += 2)
+	    if (ddecl == origin)
+	      {
+		ddecl = VEC_index (tree, *debug_args, ix + 1);
+		break;
+	      }
+	  if (ddecl == NULL)
+	    {
+	      ddecl = make_node (DEBUG_EXPR_DECL);
+	      DECL_ARTIFICIAL (ddecl) = 1;
+	      TREE_TYPE (ddecl) = TREE_TYPE (origin);
+	      DECL_MODE (ddecl) = DECL_MODE (origin);
+
+	      VEC_safe_push (tree, gc, *debug_args, origin);
+	      VEC_safe_push (tree, gc, *debug_args, ddecl);
+	    }
+	  def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg),
+					      stmt);
+	  gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+	}
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2495,7 +2533,6 @@ ipa_modify_call_arguments (struct cgraph
       print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0);
     }
 
-  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
   new_stmt = gimple_build_call_vec (callee_decl, vargs);
   VEC_free (tree, heap, vargs);
   if (gimple_call_lhs (stmt))
--- gcc/tree.h.jj	2011-06-08 08:53:15.000000000 +0200
+++ gcc/tree.h	2011-06-08 09:38:11.000000000 +0200
@@ -3426,6 +3426,13 @@ struct GTY(())
 #define DECL_DISREGARD_INLINE_LIMITS(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.disregard_inline_limits)
 
+extern VEC(tree, gc) **decl_debug_args_lookup (tree);
+extern VEC(tree, gc) **decl_debug_args_insert (tree);
+
+/* Nonzero if a FUNCTION_DECL has DEBUG arguments attached to it.  */
+#define DECL_HAS_DEBUG_ARGS_P(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.has_debug_args_flag)
+
 /* For FUNCTION_DECL, this holds a pointer to a structure ("struct function")
    that describes the status of this function.  */
 #define DECL_STRUCT_FUNCTION(NODE) \
@@ -3491,16 +3498,16 @@ struct GTY(()) tree_function_decl {
   unsigned operator_new_flag : 1;
   unsigned declared_inline_flag : 1;
   unsigned regdecl_flag : 1;
-
   unsigned no_inline_warning_flag : 1;
+
   unsigned no_instrument_function_entry_exit : 1;
   unsigned no_limit_stack : 1;
   unsigned disregard_inline_limits : 1;
   unsigned pure_flag : 1;
   unsigned looping_const_or_pure_flag : 1;
+  unsigned has_debug_args_flag : 1;
 
-
-  /* 3 bits left */
+  /* 2 bits left */
 };
 
 /* The source language of the translation-unit.  */
@@ -5695,6 +5702,17 @@ struct GTY(()) tree_priority_map {
 #define tree_priority_map_hash tree_map_base_hash
 #define tree_priority_map_marked_p tree_map_base_marked_p
 
+/* Map from a decl tree to a tree vector.  */
+
+struct GTY(()) tree_vec_map {
+  struct tree_map_base base;
+  VEC(tree,gc) *to;
+};
+
+#define tree_vec_map_eq tree_map_base_eq
+#define tree_vec_map_hash tree_decl_map_hash
+#define tree_vec_map_marked_p tree_map_base_marked_p
+
 /* In tree-ssa.c */
 
 tree target_for_debug_bind (tree);
--- gcc/tree-ssa-dce.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/tree-ssa-dce.c	2011-06-08 09:38:11.000000000 +0200
@@ -316,7 +316,8 @@ mark_stmt_if_obviously_necessary (gimple
 	 easily locate the debug temp bind stmt for a use thereof,
 	 would could refrain from marking all debug temps here, and
 	 mark them only if they're used.  */
-      if (gimple_debug_bind_has_value_p (stmt)
+      if (!gimple_debug_bind_p (stmt)
+	  || gimple_debug_bind_has_value_p (stmt)
 	  || TREE_CODE (gimple_debug_bind_get_var (stmt)) != DEBUG_EXPR_DECL)
 	mark_stmt_necessary (stmt, false);
       return;
--- gcc/cfgexpand.c.jj	2011-06-08 08:53:11.000000000 +0200
+++ gcc/cfgexpand.c	2011-06-08 09:38:11.000000000 +0200
@@ -57,6 +57,8 @@ struct ssaexpand SA;
    of comminucating the profile info to the builtin expanders.  */
 gimple currently_expanding_gimple_stmt;
 
+static rtx expand_debug_expr (tree);
+
 /* Return an expression tree corresponding to the RHS of GIMPLE
    statement STMT.  */
 
@@ -1859,6 +1861,21 @@ expand_call_stmt (gimple stmt)
   SET_EXPR_LOCATION (exp, gimple_location (stmt));
   TREE_BLOCK (exp) = gimple_block (stmt);
 
+  /* Ensure RTL is created for debug args.  */
+  if (decl && DECL_HAS_DEBUG_ARGS_P (decl))
+    {
+      VEC(tree, gc) **debug_args = decl_debug_args_lookup (decl);
+      unsigned int ix;
+      tree dtemp;
+
+      if (debug_args)
+	for (ix = 1; VEC_iterate (tree, *debug_args, ix, dtemp); ix += 2)
+	  {
+	    gcc_assert (TREE_CODE (dtemp) == DEBUG_EXPR_DECL);
+	    expand_debug_expr (dtemp);
+	  }
+    }
+
   lhs = gimple_call_lhs (stmt);
   if (lhs)
     expand_assignment (lhs, exp, false);
@@ -3293,6 +3310,120 @@ expand_debug_expr (tree exp)
     }
 }
 
+/* Return an RTX equivalent to the source bind value of the tree expression
+   EXP.  */
+
+static rtx
+expand_debug_source_expr (tree exp)
+{
+  rtx op0 = NULL_RTX;
+  enum machine_mode mode = VOIDmode, inner_mode;
+
+  switch (TREE_CODE (exp))
+    {
+    case PARM_DECL:
+      {
+	rtx incoming = DECL_INCOMING_RTL (exp);
+	mode = DECL_MODE (exp);
+	if (incoming
+	    && GET_MODE (incoming) != BLKmode
+	    && ((REG_P (incoming) && HARD_REGISTER_P (incoming))
+		|| (MEM_P (incoming)
+		    && REG_P (XEXP (incoming, 0))
+		    && HARD_REGISTER_P (XEXP (incoming, 0)))))
+	  {
+	    op0 = gen_rtx_ENTRY_VALUE (GET_MODE (incoming));
+	    ENTRY_VALUE_EXP (op0) = incoming;
+	    break;
+	  }
+	if (incoming
+	    && MEM_P (incoming)
+	    && !TREE_ADDRESSABLE (exp)
+	    && GET_MODE (incoming) != BLKmode
+	    && (XEXP (incoming, 0) == virtual_incoming_args_rtx
+		|| (GET_CODE (XEXP (incoming, 0)) == PLUS
+		    && XEXP (XEXP (incoming, 0), 0)
+		       == virtual_incoming_args_rtx
+		    && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+	  {
+	    op0 = incoming;
+	    break;
+	  }
+	/* See if this isn't an argument that has been completely
+	   optimized out.  */
+	if (!DECL_RTL_SET_P (exp)
+	    && incoming == NULL_RTX
+	    && DECL_ABSTRACT_ORIGIN (current_function_decl))
+	  {
+	    tree aexp = exp;
+	    if (DECL_ABSTRACT_ORIGIN (exp))
+	      aexp = DECL_ABSTRACT_ORIGIN (exp);
+	    if (DECL_CONTEXT (aexp)
+		== DECL_ABSTRACT_ORIGIN (current_function_decl))
+	      {
+		VEC(tree, gc) **debug_args;
+		unsigned int ix;
+		tree ddecl;
+#ifdef ENABLE_CHECKING
+		tree parm;
+		for (parm = DECL_ARGUMENTS (current_function_decl);
+		     parm; parm = DECL_CHAIN (parm))
+		  gcc_assert (parm != exp
+			      && DECL_ABSTRACT_ORIGIN (parm) != aexp);
+#endif
+		debug_args = decl_debug_args_lookup (current_function_decl);
+		if (debug_args != NULL)
+		  {
+		    for (ix = 0; VEC_iterate (tree, *debug_args, ix, ddecl);
+			 ix += 2)
+		      if (ddecl == aexp)
+			return gen_rtx_DEBUG_PARAMETER_REF (mode, aexp);
+		  }
+	      }
+	  }
+	break;
+      }
+    default:
+      break;
+    }
+
+  if (op0 == NULL_RTX)
+    return NULL_RTX;
+
+  inner_mode = GET_MODE (op0);
+  if (mode == inner_mode)
+    return op0;
+
+  if (FLOAT_MODE_P (mode) && FLOAT_MODE_P (inner_mode))
+    {
+      if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (inner_mode))
+	op0 = simplify_gen_subreg (mode, op0, inner_mode, 0);
+      else if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (inner_mode))
+	op0 = simplify_gen_unary (FLOAT_TRUNCATE, mode, op0, inner_mode);
+      else
+	op0 = simplify_gen_unary (FLOAT_EXTEND, mode, op0, inner_mode);
+    }
+  else if (FLOAT_MODE_P (mode))
+    gcc_unreachable ();
+  else if (FLOAT_MODE_P (inner_mode))
+    {
+      if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+	op0 = simplify_gen_unary (UNSIGNED_FIX, mode, op0, inner_mode);
+      else
+	op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
+    }
+  else if (CONSTANT_P (op0)
+	   || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (inner_mode))
+    op0 = simplify_gen_subreg (mode, op0, inner_mode,
+			       subreg_lowpart_offset (mode, inner_mode));
+  else if (TYPE_UNSIGNED (TREE_TYPE (exp)))
+    op0 = simplify_gen_unary (ZERO_EXTEND, mode, op0, inner_mode);
+  else
+    op0 = simplify_gen_unary (SIGN_EXTEND, mode, op0, inner_mode);
+
+  return op0;
+}
+
 /* Expand the _LOCs in debug insns.  We run this after expanding all
    regular insns, so that any variables referenced in the function
    will have their DECL_RTLs set.  */
@@ -3320,7 +3451,11 @@ expand_debug_locations (void)
 	  val = NULL_RTX;
 	else
 	  {
-	    val = expand_debug_expr (value);
+	    if (INSN_VAR_LOCATION_STATUS (insn)
+		== VAR_INIT_STATUS_UNINITIALIZED)
+	      val = expand_debug_source_expr (value);
+	    else
+	      val = expand_debug_expr (value);
 	    gcc_assert (last == get_last_insn ());
 	  }
 
@@ -3602,6 +3737,39 @@ expand_gimple_basic_block (basic_block b
 	  set_curr_insn_source_location (sloc);
 	  set_curr_insn_block (sblock);
 	}
+      else if (gimple_debug_source_bind_p (stmt))
+	{
+	  location_t sloc = get_curr_insn_source_location ();
+	  tree sblock = get_curr_insn_block ();
+	  tree var = gimple_debug_source_bind_get_var (stmt);
+	  tree value = gimple_debug_source_bind_get_value (stmt);
+	  rtx val;
+	  enum machine_mode mode;
+
+	  last = get_last_insn ();
+
+	  set_curr_insn_source_location (gimple_location (stmt));
+	  set_curr_insn_block (gimple_block (stmt));
+
+	  mode = DECL_MODE (var);
+
+	  val = gen_rtx_VAR_LOCATION (mode, var, (rtx)value,
+				      VAR_INIT_STATUS_UNINITIALIZED);
+
+	  emit_debug_insn (val);
+
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      /* We can't dump the insn with a TREE where an RTX
+		 is expected.  */
+	      PAT_VAR_LOCATION_LOC (val) = const0_rtx;
+	      maybe_dump_rtl_for_gimple_stmt (stmt, last);
+	      PAT_VAR_LOCATION_LOC (val) = (rtx)value;
+	    }
+
+	  set_curr_insn_source_location (sloc);
+	  set_curr_insn_block (sblock);
+	}
       else
 	{
 	  if (is_gimple_call (stmt) && gimple_call_tail_p (stmt))
--- gcc/tree-parloops.c.jj	2011-01-31 14:11:30.000000000 +0100
+++ gcc/tree-parloops.c	2011-06-08 10:58:33.000000000 +0200
@@ -1,5 +1,5 @@
 /* Loop autoparallelization.
-   Copyright (C) 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Sebastian Pop <pop@cri.ensmp.fr> and
    Zdenek Dvorak <dvorakz@suse.cz>.
@@ -716,8 +716,11 @@ eliminate_local_variables (edge entry, e
   FOR_EACH_VEC_ELT (basic_block, body, i, bb)
     if (bb != entry_bb && bb != exit_bb)
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-	if (gimple_debug_bind_p (gsi_stmt (gsi)))
-	  has_debug_stmt = true;
+	if (is_gimple_debug (gsi_stmt (gsi)))
+	  {
+	    if (gimple_debug_bind_p (gsi_stmt (gsi)))
+	      has_debug_stmt = true;
+	  }
 	else
 	  eliminate_local_variables_stmt (entry, &gsi, decl_address);
 
@@ -883,8 +886,8 @@ separate_decls_in_region_stmt (edge entr
    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)
+separate_decls_in_region_debug (gimple stmt, htab_t name_copies,
+				htab_t decl_copies)
 {
   use_operand_p use;
   ssa_op_iter oi;
@@ -893,7 +896,12 @@ separate_decls_in_region_debug_bind (gim
   struct name_to_copy_elt elt;
   void **slot, **dslot;
 
-  var = gimple_debug_bind_get_var (stmt);
+  if (gimple_debug_bind_p (stmt))
+    var = gimple_debug_bind_get_var (stmt);
+  else if (gimple_debug_source_bind_p (stmt))
+    var = gimple_debug_source_bind_get_var (stmt);
+  else
+    return true;
   if (TREE_CODE (var) == DEBUG_EXPR_DECL)
     return true;
   gcc_assert (DECL_P (var) && SSA_VAR_P (var));
@@ -901,7 +909,10 @@ separate_decls_in_region_debug_bind (gim
   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);
+  if (gimple_debug_bind_p (stmt))
+    gimple_debug_bind_set_var (stmt, ((struct int_tree_map *) *dslot)->to);
+  else if (gimple_debug_source_bind_p (stmt))
+    gimple_debug_source_bind_set_var (stmt, ((struct int_tree_map *) *dslot)->to);
 
   FOR_EACH_PHI_OR_STMT_USE (use, stmt, oi, SSA_OP_USE)
   {
@@ -1295,11 +1306,10 @@ separate_decls_in_region (edge entry, ed
 	    {
 	      gimple stmt = gsi_stmt (gsi);
 
-	      if (gimple_debug_bind_p (stmt))
+	      if (is_gimple_debug (stmt))
 		{
-		  if (separate_decls_in_region_debug_bind (stmt,
-							   name_copies,
-							   decl_copies))
+		  if (separate_decls_in_region_debug (stmt, name_copies,
+						      decl_copies))
 		    {
 		      gsi_remove (&gsi, true);
 		      continue;
--- include/dwarf2.h.jj	2011-06-06 10:24:07.000000000 +0200
+++ include/dwarf2.h	2011-06-07 08:56:43.000000000 +0200
@@ -563,6 +563,8 @@ enum dwarf_location_atom
     DW_OP_GNU_deref_type = 0xf6,
     DW_OP_GNU_convert = 0xf7,
     DW_OP_GNU_reinterpret = 0xf9,
+    /* The GNU parameter ref extension.  */
+    DW_OP_GNU_parameter_ref = 0xfa,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,

	Jakub

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-06-08 14:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-08 14:19 [PATCH] Improve debug info for IPA-SRA optimized code - add DW_OP_GNU_parameter_ref support (PR debug/47858) Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).