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]

[PATCH] Fix debug info handling in prepare_shrink_wrap (PR debug/65779)


Hi!

On the following testcase with -mrelocatable on ppc32 we get assembly that
contains undefined reference to a local .LC* symbol.
The problem is that prepare_shrink_wrap attempts to schedule some
instructions from the entry block to later basic blocks, if they set a
register that is only used in one of the paths, but the debug infos are kept
where they used to appear (that is correct thing to do), but nothing adjusts
them or resets them); on most targets we get away just with wrong debug
info, but on ppc32 -mrelocatable something in the prologue sets the hard
registers used by some debug insns to subtraction of two magic labels, which
are later removed as unneeded, but kept in the debug info.

Fixed by using the infrastructure we have for this in valtrack.c, that is
used by DCE and DF note problem computation.

E.g. on ppc32, we used to have:
(insn 34 38 35 2 (set (reg/v:SI 6 6 [orig:238 s1 ] [238])
        (and:SI (reg/v:SI 3 3 [orig:264 adler ] [264])
            (const_int 65535 [0xffff]))) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/../../../powerpc/sha
     (nil))
(debug_insn 35 34 36 2 (var_location:SI s1 (reg/v:SI 6 6 [orig:238 s1 ] [238])) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_
     (nil))
(insn 36 35 37 2 (set (reg/v:SI 0 0 [orig:239 s2 ] [239])
        (lshiftrt:SI (reg/v:SI 3 3 [orig:264 adler ] [264])
            (const_int 16 [0x10]))) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/../../../powerpc/shared/b
     (nil))
(debug_insn 37 36 39 2 (var_location:SI s2 (reg/v:SI 0 0 [orig:239 s2 ] [239])) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_
     (nil))
in bb2 and decide to move insn 34 and 36 to the start of bb3,
before the patch we'd keep the debug insns untouched, while with the
patch we get:
(debug_insn 365 38 35 2 (var_location:SI D#38 (and:SI (reg/v:SI 3 3 [orig:264 adler ] [264])
        (const_int 65535 [0xffff]))) -1
     (nil))
(debug_insn 35 365 363 2 (var_location:SI s1 (debug_expr:SI D#38)) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootl
     (nil))
(debug_insn 363 35 37 2 (var_location:SI D#37 (lshiftrt:SI (reg/v:SI 3 3 [orig:264 adler ] [264])
        (const_int 16 [0x10]))) -1
     (nil))
(debug_insn 37 363 39 2 (var_location:SI s2 (debug_expr:SI D#37)) ../../../../../../../../../rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/bootlo
     (nil))
in bb2.  Even on x86_64-linux I saw even on this testcase improvement
in debug info coverage (it didn't end up being wrong debug there, but
one of the variables used to be <optimized out> without the patch in
certain range.

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

2016-01-19  Jakub Jelinek  <jakub@redhat.com>

	PR debug/65779
	* shrink-wrap.c: Include valtrack.h.
	(move_insn_for_shrink_wrap): Add DEBUG argument.  If
	MAY_HAVE_DEBUG_INSNS, call dead_debug_add on DEBUG_INSNs
	in between insn and where it will be moved to.  Call
	dead_debug_insert_temp.
	(prepare_shrink_wrap): Adjust caller.  Call dead_debug_local_init
	first and dead_debug_local_finish at the end.
	For uses and defs bitmap, handle all regs in between REGNO and
	END_REGNO, not just the first one.

	* gcc.dg/pr65779.c: New test.

--- gcc/shrink-wrap.c.jj	2016-01-08 07:31:10.000000000 +0100
+++ gcc/shrink-wrap.c	2016-01-18 20:06:53.029487254 +0100
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.
 #include "shrink-wrap.h"
 #include "regcprop.h"
 #include "rtl-iter.h"
+#include "valtrack.h"
 
 
 /* Return true if INSN requires the stack frame to be set up.
@@ -149,7 +150,8 @@ static bool
 move_insn_for_shrink_wrap (basic_block bb, rtx_insn *insn,
 			   const HARD_REG_SET uses,
 			   const HARD_REG_SET defs,
-			   bool *split_p)
+			   bool *split_p,
+			   struct dead_debug_local *debug)
 {
   rtx set, src, dest;
   bitmap live_out, live_in, bb_uses, bb_defs;
@@ -158,6 +160,8 @@ move_insn_for_shrink_wrap (basic_block b
   unsigned int end_sregno = FIRST_PSEUDO_REGISTER;
   basic_block next_block;
   edge live_edge;
+  rtx_insn *dinsn;
+  df_ref def;
 
   /* Look for a simple register assignment.  We don't use single_set here
      because we can't deal with any CLOBBERs, USEs, or REG_UNUSED secondary
@@ -298,6 +302,19 @@ move_insn_for_shrink_wrap (basic_block b
       *split_p = true;
     }
 
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      for (dinsn = BB_END (bb); dinsn != insn; dinsn = PREV_INSN (dinsn))
+	if (DEBUG_INSN_P (dinsn))
+	  {
+	    df_ref use;
+	    FOR_EACH_INSN_USE (use, dinsn)
+	      if (refers_to_regno_p (dregno, end_dregno,
+				     DF_REF_REG (use), (rtx *) NULL))
+		dead_debug_add (debug, use, DF_REF_REGNO (use));
+	  }
+    }
+
   /* At this point we are committed to moving INSN, but let's try to
      move it as far as we can.  */
   do
@@ -363,6 +380,18 @@ move_insn_for_shrink_wrap (basic_block b
 	  if (!live_edge || EDGE_COUNT (live_edge->dest->preds) > 1)
 	    break;
 	  next_block = live_edge->dest;
+	  if (MAY_HAVE_DEBUG_INSNS)
+	    {
+	      FOR_BB_INSNS_REVERSE (bb, dinsn)
+		if (DEBUG_INSN_P (dinsn))
+		  {
+		    df_ref use;
+		    FOR_EACH_INSN_USE (use, dinsn)
+		      if (refers_to_regno_p (dregno, end_dregno,
+					     DF_REF_REG (use), (rtx *) NULL))
+			dead_debug_add (debug, use, DF_REF_REGNO (use));
+		  }
+	    }
 	}
     }
   while (next_block);
@@ -384,6 +413,12 @@ move_insn_for_shrink_wrap (basic_block b
 	SET_REGNO_REG_SET (bb_uses, i);
     }
 
+  /* Insert debug temps for dead REGs used in subsequent debug insns.  */
+  if (debug->used && !bitmap_empty_p (debug->used))
+    FOR_EACH_INSN_DEF (def, insn)
+      dead_debug_insert_temp (debug, DF_REF_REGNO (def), insn,
+			      DEBUG_TEMP_BEFORE_WITH_VALUE);
+
   emit_insn_after (PATTERN (insn), bb_note (bb));
   delete_insn (insn);
   return true;
@@ -404,6 +439,8 @@ prepare_shrink_wrap (basic_block entry_b
   HARD_REG_SET uses, defs;
   df_ref def, use;
   bool split_p = false;
+  unsigned int i;
+  struct dead_debug_local debug;
 
   if (JUMP_P (BB_END (entry_block)))
     {
@@ -414,19 +451,22 @@ prepare_shrink_wrap (basic_block entry_b
       copyprop_hardreg_forward_bb_without_debug_insn (entry_block);
     }
 
+  dead_debug_local_init (&debug, NULL, NULL);
   CLEAR_HARD_REG_SET (uses);
   CLEAR_HARD_REG_SET (defs);
+
   FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr)
     if (NONDEBUG_INSN_P (insn)
 	&& !move_insn_for_shrink_wrap (entry_block, insn, uses, defs,
-				       &split_p))
+				       &split_p, &debug))
       {
 	/* Add all defined registers to DEFs.  */
 	FOR_EACH_INSN_DEF (def, insn)
 	  {
 	    x = DF_REF_REG (def);
 	    if (REG_P (x) && HARD_REGISTER_P (x))
-	      SET_HARD_REG_BIT (defs, REGNO (x));
+	      for (i = REGNO (x); i < END_REGNO (x); i++)
+		SET_HARD_REG_BIT (defs, i);
 	  }
 
 	/* Add all used registers to USESs.  */
@@ -434,9 +474,12 @@ prepare_shrink_wrap (basic_block entry_b
 	  {
 	    x = DF_REF_REG (use);
 	    if (REG_P (x) && HARD_REGISTER_P (x))
-	      SET_HARD_REG_BIT (uses, REGNO (x));
+	      for (i = REGNO (x); i < END_REGNO (x); i++)
+		SET_HARD_REG_BIT (uses, i);
 	  }
       }
+
+  dead_debug_local_finish (&debug, NULL);
 }
 
 /* Return whether basic block PRO can get the prologue.  It can not if it
--- gcc/testsuite/gcc.dg/pr65779.c.jj	2016-01-18 20:27:48.906187675 +0100
+++ gcc/testsuite/gcc.dg/pr65779.c	2016-01-18 20:20:02.000000000 +0100
@@ -0,0 +1,42 @@
+/* PR debug/65779 */
+/* { dg-do assemble } */
+/* { dg-options "-O2 -fcompare-debug" } */
+
+unsigned long
+foo (unsigned long x, unsigned char *y, unsigned int z)
+{
+  unsigned long a = x & 0xffff;
+  unsigned long b = (x >> 16) & 0xffff;
+  int k;
+  if (y == 0) return 1L;
+  while (z > 0)
+    {
+      k = z < 5552 ? z : 5552;
+      z -= k;
+      while (k >= 16)
+	{
+          a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  a += *y++; b += a;
+	  k -= 16;
+        }
+      if (k != 0)
+	do { a += *y++; b += a; } while (--k);
+      a %= 65521L;
+      b %= 65521L;
+    }
+  return (b << 16) | a;
+}

	Jakub


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