This PR shows that when SRA creates DECL_DEBUG_EXPRs with locations
(and blocks) this does not work with inlining.  The reason is that
the inliner does not bother to copy vars used only in lhs of
debug-stmts (eek) and thus ends up sharing DECL_DEBUG_EXPRs
(and not re-mapping them and their location blocks).  Maybe
a recipie for further desaster ... (who knows).  I didn't manage
to get it to "properly" copy things, but basically

  else if (TREE_CODE (t) == VAR_DECL
           && !is_global_var (t)
           && !pointer_map_contains (id->decl_map, t))
    /* T is a non-localized variable.  */;

doesn't work - vars can be not in local-decls (which we all remap)
due to remove-unused-locals.  Thus we end up not remapping the
debug var (and refer to the other functions DECL_DEBUG_EXPR).

The following avoids the DECL_DEBUG_EXPR issue by clearing
all location information from it (it's unused anyway).
The above code should nevertheless be inspected ...

I took the liberty to sync the MEM_REF code from the two nearly
identical tree copying routines (eh ...), it was my first guess
as to what goes wrong.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

For 4.9 we'd want a verify_no_location eventually which we can
use to recurse here.

Any comments about the above code?

Thanks,
Richard.

2013-03-08  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/56570
        * tree-cfg.c (verify_expr_location_1): Verify locations for
        DECL_DEBUG_EXPR.
        * tree-sra.c (create_access_replacement): Strip locations
        from DECL_DEBUG_EXPRs.
        * tree-inline.c (copy_tree_body_r): Sync MEM_REF code from ...
        remap_gimple_op_r.

Index: gcc/tree-cfg.c
===================================================================
*** gcc/tree-cfg.c      (revision 196542)
--- gcc/tree-cfg.c      (working copy)
*************** verify_expr_location_1 (tree *tp, int *w
*** 4523,4528 ****
--- 4523,4537 ----
  {
    struct pointer_set_t *blocks = (struct pointer_set_t *) data;
  
+   if (TREE_CODE (*tp) == VAR_DECL
+       && DECL_DEBUG_EXPR_IS_FROM (*tp))
+     {
+       tree t = DECL_DEBUG_EXPR (*tp);
+       tree addr = walk_tree (&t, verify_expr_location_1, blocks, NULL);
+       if (addr)
+       return addr;
+     }
+ 
    if (!EXPR_P (*tp))
      {
        *walk_subtrees = false;
Index: gcc/tree-sra.c
===================================================================
*** gcc/tree-sra.c      (revision 196541)
--- gcc/tree-sra.c      (working copy)
*************** create_access_replacement (struct access
*** 1917,1923 ****
        && !DECL_ARTIFICIAL (access->base))
      {
        char *pretty_name = make_fancy_name (access->expr);
!       tree debug_expr = unshare_expr (access->expr), d;
        bool fail = false;
  
        DECL_NAME (repl) = get_identifier (pretty_name);
--- 1917,1923 ----
        && !DECL_ARTIFICIAL (access->base))
      {
        char *pretty_name = make_fancy_name (access->expr);
!       tree debug_expr = unshare_expr_without_location (access->expr), d;
        bool fail = false;
  
        DECL_NAME (repl) = get_identifier (pretty_name);
Index: gcc/tree-inline.c
===================================================================
*** gcc/tree-inline.c   (revision 196542)
--- gcc/tree-inline.c   (working copy)
*************** copy_tree_body_r (tree *tp, int *walk_su
*** 1092,1113 ****
        }
        else if (TREE_CODE (*tp) == MEM_REF)
        {
!         /* We need to re-canonicalize MEM_REFs from inline substitutions
!            that can happen when a pointer argument is an ADDR_EXPR.  */
!         tree decl = TREE_OPERAND (*tp, 0);
!         tree *n;
  
!         n = (tree *) pointer_map_contains (id->decl_map, decl);
!         if (n)
!           {
!             tree old = *tp;
!             *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
!                                unshare_expr (*n), TREE_OPERAND (*tp, 1));
!             TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
!             TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
!             *walk_subtrees = 0;
!             return NULL;
!           }
        }
  
        /* Here is the "usual case".  Copy this tree node, and then
--- 1092,1113 ----
        }
        else if (TREE_CODE (*tp) == MEM_REF)
        {
!         tree ptr = TREE_OPERAND (*tp, 0);
!         tree type = remap_type (TREE_TYPE (*tp), id);
!         tree old = *tp;
  
!         /* We need to re-canonicalize MEM_REFs from inline substitutions
!            that can happen when a pointer argument is an ADDR_EXPR.
!            Recurse here manually to allow that.  */
!         walk_tree (&ptr, copy_tree_body_r, data, NULL);
!         *tp = fold_build2 (MEM_REF, type,
!                            ptr, TREE_OPERAND (*tp, 1));
!         TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old);
!         TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
!         TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
!         TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
!         *walk_subtrees = 0;
!         return NULL;
        }
  
        /* Here is the "usual case".  Copy this tree node, and then

Reply via email to