On Wed, Dec 16, 2015 at 08:15:12PM +0100, Jan Hubicka wrote:
> just to summarize a discussion on IRC. The problem is that we produce debug
> statements for eliminated arguments only in ipa-sra and ipa-split, while we
> don't do anything for cgraph clones. This is a problem on release branches,
> too.
> 
> It seems we have all the necessary logic, but the callee modification code 
> from
> ipa-split should be moved to tree_function_versioning (which is used by both
> ipa-split and cgraph clone mechanizm) and caller modifcation copied to
> cgraph_edge::redirect_call_stmt_to_callee.
> 
> I am trying to do that. It seems bit difficult as the caller and callee
> modifications are tied together and I do not know how chaining of
> transfomraitons is going to work. 

Ok, so here is a WIP patch changing the functions you wanted, untested so
far.

I've been looking at 3 testcases (attached), -1.c and -3.c with -g -O2,
and -2.c with -g -O3.
The -3.c one is a copy of the test we have for the ipa-split debug info
stuff, before/after the patch we generate the same stuff.
-2.c testcase is for the (new or now much more often taken patch) of
ipa-cp, the patch arranges for proper debug info in that case
(but, I'm really surprised why when the function is already cloned, nothing
figures out that the clone is always called with the same constant
passed to the arg8 and the argument isn't removed and replaced by constant.
-1.c is a testcase for the IPA-SRA path, where we unfortunately end up with
-a slight regression (on the IL size, in the end we generate the same
assembly):
+  # DEBUG D#8 s=> arg8
+  # DEBUG arg8 => D#8
   # DEBUG arg8 => 7
with the patch.  On that testcase, arg8 is used, but it is always passed
value 7 (similarly to -2.c testcase) and in that case we really don't
need/want the decl_debug_args stuff, it is unnecessary, it is enough to say
in the callee that arg8 is 7.  Nothing on the caller side sets the magic
corresponding D# debug expr decl anyway.
Either tree_versioning is too low-level for the debug info addition, or
we need to figure out how to tell it if a constant will be always passed
to some argument and what that constant will be, so that we'd emit
always the # DEBUG arg8 => constant in that case instead of the source bind
stuff (but then figure out what has added that and avoid duplication too).

And then there is another thing, but best to be handled somewhere in
dwarf2out.c or in the debugger.  The arguments are printed in pretty random
order:
#0  foo (arg7=arg7@entry=30, arg8=arg8@entry=7, arg6=6, arg5=5, arg4=4, arg3=3, 
arg2=2, arg1=1) at pr68860-2.c:15
So, either the debugger for functions with abstract origins should look at
the order of arguments in the abstract origin and ignore order in the
particular instantiation, or dwarf2out.c should sort the
DW_TAG_formal_parameter such that it if at all possible matches the order
specified in the source.

--- gcc/ipa-split.c.jj  2015-12-10 11:14:00.000000000 +0100
+++ gcc/ipa-split.c     2015-12-17 18:21:39.402036180 +0100
@@ -1209,7 +1209,6 @@ split_function (basic_block return_bb, s
   gimple *last_stmt = NULL;
   unsigned int i;
   tree arg, ddef;
-  vec<tree, va_gc> **debug_args = NULL;
 
   if (dump_file)
     {
@@ -1432,73 +1431,38 @@ split_function (basic_block return_bb, s
      vector to say for debug info that if parameter parm had been passed,
      it would have value parm_Y(D).  */
   if (args_to_skip)
-    for (parm = DECL_ARGUMENTS (current_function_decl), num = 0;
-        parm; parm = DECL_CHAIN (parm), num++)
-      if (bitmap_bit_p (args_to_skip, num)
-         && is_gimple_reg (parm))
-       {
-         tree ddecl;
-         gimple *def_temp;
-
-         /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
-            otherwise if it didn't exist before, we'd end up with
-            different SSA_NAME_VERSIONs between -g and -g0.  */
-         arg = get_or_create_ssa_default_def (cfun, parm);
-         if (!MAY_HAVE_DEBUG_STMTS)
-           continue;
-
-         if (debug_args == NULL)
-           debug_args = decl_debug_args_insert (node->decl);
-         ddecl = make_node (DEBUG_EXPR_DECL);
-         DECL_ARTIFICIAL (ddecl) = 1;
-         TREE_TYPE (ddecl) = TREE_TYPE (parm);
-         DECL_MODE (ddecl) = DECL_MODE (parm);
-         vec_safe_push (*debug_args, DECL_ORIGIN (parm));
-         vec_safe_push (*debug_args, ddecl);
-         def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg),
-                                             call);
-         gsi_insert_after (&gsi, def_temp, GSI_NEW_STMT);
-       }
-  /* And on the callee side, add
-     DEBUG D#Y s=> parm
-     DEBUG var => D#Y
-     stmts to the first bb where var is a VAR_DECL created for the
-     optimized away parameter in DECL_INITIAL block.  This hints
-     in the debug info that var (whole DECL_ORIGIN is the parm PARM_DECL)
-     is optimized away, but could be looked up at the call site
-     as value of D#X there.  */
-  if (debug_args != NULL)
     {
-      unsigned int i;
-      tree var, vexpr;
-      gimple_stmt_iterator cgsi;
-      gimple *def_temp;
-
-      push_cfun (DECL_STRUCT_FUNCTION (node->decl));
-      var = BLOCK_VARS (DECL_INITIAL (node->decl));
-      i = vec_safe_length (*debug_args);
-      cgsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
-      do
+      vec<tree, va_gc> **debug_args = NULL;
+      unsigned i = 0, len = 0;
+      if (MAY_HAVE_DEBUG_STMTS)
        {
-         i -= 2;
-         while (var != NULL_TREE
-                && DECL_ABSTRACT_ORIGIN (var) != (**debug_args)[i])
-           var = TREE_CHAIN (var);
-         if (var == NULL_TREE)
-           break;
-         vexpr = make_node (DEBUG_EXPR_DECL);
-         parm = (**debug_args)[i];
-         DECL_ARTIFICIAL (vexpr) = 1;
-         TREE_TYPE (vexpr) = TREE_TYPE (parm);
-         DECL_MODE (vexpr) = DECL_MODE (parm);
-         def_temp = gimple_build_debug_source_bind (vexpr, parm,
-                                                    NULL);
-         gsi_insert_before (&cgsi, def_temp, GSI_SAME_STMT);
-         def_temp = gimple_build_debug_bind (var, vexpr, NULL);
-         gsi_insert_before (&cgsi, def_temp, GSI_SAME_STMT);
+         debug_args = decl_debug_args_lookup (node->decl);
+         if (debug_args)
+           len = vec_safe_length (*debug_args);
        }
-      while (i);
-      pop_cfun ();
+      for (parm = DECL_ARGUMENTS (current_function_decl), num = 0;
+          parm; parm = DECL_CHAIN (parm), num++)
+       if (bitmap_bit_p (args_to_skip, num) && is_gimple_reg (parm))
+         {
+           tree ddecl;
+           gimple *def_temp;
+
+           /* This needs to be done even without MAY_HAVE_DEBUG_STMTS,
+              otherwise if it didn't exist before, we'd end up with
+              different SSA_NAME_VERSIONs between -g and -g0.  */
+           arg = get_or_create_ssa_default_def (cfun, parm);
+           if (!MAY_HAVE_DEBUG_STMTS || debug_args == NULL)
+             continue;
+
+           while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
+             i += 2;
+           if (i >= len)
+             continue;
+           ddecl = (**debug_args)[i + 1];
+           def_temp
+             = gimple_build_debug_bind (ddecl, unshare_expr (arg), call);
+           gsi_insert_after (&gsi, def_temp, GSI_NEW_STMT);
+         }
     }
 
   /* We avoid address being taken on any variable used by split part,
--- gcc/cgraph.c.jj     2015-12-16 09:02:11.000000000 +0100
+++ gcc/cgraph.c        2015-12-17 18:34:50.609062057 +0100
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3.
 #include "params.h"
 #include "tree-chkp.h"
 #include "context.h"
+#include "gimplify.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  
*/
 #include "tree-pass.h"
@@ -1420,6 +1421,51 @@ cgraph_edge::redirect_call_stmt_to_calle
        SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
 
       gsi = gsi_for_stmt (e->call_stmt);
+
+      /* For optimized away parameters, add on the caller side
+        before the call
+        DEBUG D#X => parm_Y(D)
+        stmts and associate D#X with parm in decl_debug_args_lookup
+        vector to say for debug info that if parameter parm had been passed,
+        it would have value parm_Y(D).  */
+      if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_STMTS)
+       {
+         vec<tree, va_gc> **debug_args
+           = decl_debug_args_lookup (e->callee->decl);
+         if (debug_args)
+           {
+             tree parm;
+             unsigned i = 0, num;
+             unsigned len = vec_safe_length (*debug_args);
+             for (parm = DECL_ARGUMENTS (decl), num = 0;
+                  parm; parm = DECL_CHAIN (parm), num++)
+               if (bitmap_bit_p (e->callee->clone.combined_args_to_skip, num)
+                   && is_gimple_reg (parm))
+                 {
+                   gimple *def_temp;
+                   unsigned last = i;
+
+                   while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
+                     i += 2;
+                   if (i >= len)
+                     {
+                       i = 0;
+                       while (i < last && (**debug_args)[i]
+                              != DECL_ORIGIN (parm))
+                         i += 2;
+                       if (i >= last)
+                         continue;
+                     }
+                   tree ddecl = (**debug_args)[i + 1];
+                   tree arg = gimple_call_arg (e->call_stmt, num);
+                   def_temp
+                     = gimple_build_debug_bind (ddecl, unshare_expr (arg),
+                                                e->call_stmt);
+                   gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+                 }
+           }
+       }
+
       gsi_replace (&gsi, new_stmt, false);
       /* We need to defer cleaning EH info on the new statement to
          fixup-cfg.  We may not have dominator information at this point
--- gcc/tree-inline.c.jj        2015-12-10 16:56:26.000000000 +0100
+++ gcc/tree-inline.c   2015-12-17 18:56:18.667166746 +0100
@@ -5740,9 +5740,8 @@ tree_function_versioning (tree old_decl,
   /* Copy the function's static chain.  */
   p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl;
   if (p)
-    DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl =
-      copy_static_chain (DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl,
-                        &id);
+    DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl
+      = copy_static_chain (p, &id);
 
   /* If there's a tree_map, prepare for substitution.  */
   if (tree_map)
@@ -5797,9 +5796,9 @@ tree_function_versioning (tree old_decl,
       }
   /* Copy the function's arguments.  */
   if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
-    DECL_ARGUMENTS (new_decl) =
-      copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
-                                    args_to_skip, &vars);
+    DECL_ARGUMENTS (new_decl)
+      = copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
+                                      args_to_skip, &vars);
 
   DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
   BLOCK_SUPERCONTEXT (DECL_INITIAL (new_decl)) = new_decl;
@@ -5914,6 +5913,67 @@ tree_function_versioning (tree old_decl,
        }
     }
 
+  if (args_to_skip && MAY_HAVE_DEBUG_STMTS)
+    {
+      tree parm;
+      vec<tree, va_gc> **debug_args = NULL;
+      unsigned int len = 0;
+      for (parm = DECL_ARGUMENTS (old_decl), i = 0;
+          parm; parm = DECL_CHAIN (parm), i++)
+       if (bitmap_bit_p (args_to_skip, i) && is_gimple_reg (parm))
+         {
+           tree ddecl;
+
+           if (debug_args == NULL)
+             {
+               debug_args = decl_debug_args_insert (new_decl);
+               len = vec_safe_length (*debug_args);
+             }
+           ddecl = make_node (DEBUG_EXPR_DECL);
+           DECL_ARTIFICIAL (ddecl) = 1;
+           TREE_TYPE (ddecl) = TREE_TYPE (parm);
+           DECL_MODE (ddecl) = DECL_MODE (parm);
+           vec_safe_push (*debug_args, DECL_ORIGIN (parm));
+           vec_safe_push (*debug_args, ddecl);
+         }
+      if (debug_args != NULL)
+       {
+         /* On the callee side, add
+            DEBUG D#Y s=> parm
+            DEBUG var => D#Y
+            stmts to the first bb where var is a VAR_DECL created for the
+            optimized away parameter in DECL_INITIAL block.  This hints
+            in the debug info that var (whole DECL_ORIGIN is the parm
+            PARM_DECL) is optimized away, but could be looked up at the
+            call site as value of D#X there.  */
+         tree var = vars, vexpr;
+         gimple_stmt_iterator cgsi
+           = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+         gimple *def_temp;
+         var = vars;
+         i = vec_safe_length (*debug_args);
+         do
+           {
+             i -= 2;
+             while (var != NULL_TREE
+                    && DECL_ABSTRACT_ORIGIN (var) != (**debug_args)[i])
+               var = TREE_CHAIN (var);
+             if (var == NULL_TREE)
+               break;
+             vexpr = make_node (DEBUG_EXPR_DECL);
+             parm = (**debug_args)[i];
+             DECL_ARTIFICIAL (vexpr) = 1;
+             TREE_TYPE (vexpr) = TREE_TYPE (parm);
+             DECL_MODE (vexpr) = DECL_MODE (parm);
+             def_temp = gimple_build_debug_bind (var, vexpr, NULL);
+             gsi_insert_before (&cgsi, def_temp, GSI_NEW_STMT);
+             def_temp = gimple_build_debug_source_bind (vexpr, parm, NULL);
+             gsi_insert_before (&cgsi, def_temp, GSI_NEW_STMT);
+           }
+         while (i > len);
+       }
+    }
+
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 


        Jakub
/* PR debug/36728 */
/* { dg-do run } */
/* { dg-options "-g" } */

#define NOP "nop"

static int __attribute__((noinline))
foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int 
arg8)
{
  char *x = __builtin_alloca (arg7);
  int __attribute__ ((aligned(32))) y;

  y = 2;
  asm (NOP : "=m" (y) : "m" (y));
  x[0] = 25 + arg8;
  asm volatile (NOP : "=m" (x[0]) : "m" (x[0]));
  return y;
}

/* On s390(x) r2 and r3 are (depending on the optimization level) used
   when adjusting the addresses in order to meet the alignment
   requirements above.  They usually hold the function arguments arg1
   and arg2.  So it is expected that these values are unavailable in
   some of these tests.  */

/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 14 "arg3" "3" } } */
/* { dg-final { gdb-test 14 "arg4" "4" } } */
/* { dg-final { gdb-test 14 "arg5" "5" } } */
/* { dg-final { gdb-test 14 "arg6" "6" } } */
/* { dg-final { gdb-test 14 "arg7" "30" } } */
/* { dg-final { gdb-test 14 "y" "2" } } */
/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 16 "arg3" "3" } } */
/* { dg-final { gdb-test 16 "arg4" "4" } } */
/* { dg-final { gdb-test 16 "arg5" "5" } } */
/* { dg-final { gdb-test 16 "arg6" "6" } } */
/* { dg-final { gdb-test 16 "arg7" "30" } } */
/* { dg-final { gdb-test 16 "*x" "(char) 25" } } */
/* { dg-final { gdb-test 16 "y" "2" } } */

int q;

int
main ()
{
  int l = 0;
  asm ("" : "=r" (l) : "0" (l));
  foo (l + 1, l + 2, l + 3, l + 4, l + 5, l + 6, l + 30, 7);
  asm volatile ("" :: "r" (l));
  return 0;
}
/* PR debug/36728 */
/* { dg-do run } */
/* { dg-options "-g" } */

#define NOP "nop"

int __attribute__((noinline))
foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int 
arg8)
{
  char *x = __builtin_alloca (arg7);
  int __attribute__ ((aligned(32))) y;

  y = 2;
  asm (NOP : "=m" (y) : "m" (y));
  x[0] = 25 + arg8;
  asm volatile (NOP : "=m" (x[0]) : "m" (x[0]));
  return y;
}

/* On s390(x) r2 and r3 are (depending on the optimization level) used
   when adjusting the addresses in order to meet the alignment
   requirements above.  They usually hold the function arguments arg1
   and arg2.  So it is expected that these values are unavailable in
   some of these tests.  */

/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 14 "arg3" "3" } } */
/* { dg-final { gdb-test 14 "arg4" "4" } } */
/* { dg-final { gdb-test 14 "arg5" "5" } } */
/* { dg-final { gdb-test 14 "arg6" "6" } } */
/* { dg-final { gdb-test 14 "arg7" "30" } } */
/* { dg-final { gdb-test 14 "y" "2" } } */
/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
/* { dg-final { gdb-test 16 "arg3" "3" } } */
/* { dg-final { gdb-test 16 "arg4" "4" } } */
/* { dg-final { gdb-test 16 "arg5" "5" } } */
/* { dg-final { gdb-test 16 "arg6" "6" } } */
/* { dg-final { gdb-test 16 "arg7" "30" } } */
/* { dg-final { gdb-test 16 "*x" "(char) 25" } } */
/* { dg-final { gdb-test 16 "y" "2" } } */

int q;

int
main ()
{
  int l = 0;
  asm ("" : "=r" (l) : "0" (l));
  foo (l + 1, l + 2, l + 3, l + 4, l + 5, l + 6, l + 30, 7);
  asm volatile ("" :: "r" (l));
  return 0;
}
/* PR debug/54519 */
/* { dg-do run } */
/* { dg-options "-g" } */

__attribute__((noinline, noclone)) void
fn1 (int x)
{
  __asm volatile ("" : "+r" (x) : : "memory");
}

static int
fn2 (int x, int y, int z)
{
  int a = 8;
  if (x != z)
    {
      fn1 (x);
      fn1 (x);          /* { dg-final { gdb-test 20 "x" "36" } } */
      if (x == 36)      /* { dg-final { gdb-test 20 "y" "25" } } */
        fn1 (x);        /* { dg-final { gdb-test 20 "z" "6" } } */
      fn1 (x);          /* { dg-final { gdb-test 23 "x" "98" } } */
      if (x == 98)      /* { dg-final { gdb-test 23 "y" "117" } } */
        fn1 (x);        /* { dg-final { gdb-test 23 "z" "8" } } */
      fn1 (x);
      fn1 (x + a);
    }
  return y;
}

__attribute__((noinline, noclone)) int
fn3 (int x, int y)
{
  return fn2 (x, y, 6);
}

__attribute__((noinline, noclone)) int
fn4 (int x, int y)
{
  return fn2 (x, y, 8);
}

int
main ()
{
  fn3 (36, 25);
  fn4 (98, 117);
  return 0;
}

Reply via email to