diff mbox series

[3/3] Fix debug info for LSM

Message ID mptblzhti71.fsf@arm.com
State New
Headers show
Series Improve debug info for addressable vars | expand

Commit Message

Richard Sandiford June 1, 2019, 3:54 p.m. UTC
This patch makes the into-SSA code handle LSM temporary variables
as though they had been assignments to the original variable.

In the end, the easiest place to record the link seemed to be
DECL_ABSTRACT_ORIGIN.  These sorts of nameless temporaries shouldn't
otherwise have debug info and so shouldn't be using DECL_ABSTRACT_ORIGIN
for anything else.


2019-06-01  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* gimple.h (gimple_assign_load_decl_p): New function.
	* tree-ssa.h (inherit_target_for_debug_bind): Declare.
	* tree-ssa.c (inherit_target_for_debug_bind): New function.
	(target_for_debug_bind): Honor calls to inherit_target_for_debug_bind.
	* tree-into-ssa.c (maybe_register_def): Don't emit "VAR => DEF"
	for "DEF = VAR".
	* tree-ssa-loop-im.c: Include tree-ssa.h.
	(execute_sm_if_changed): Explain why we don't insert any debug
	statements here.
	(execute_sm): Call inherit_target_for_debug_bind on the temporary
	variable.

gcc/testsuite/
	* lib/gcc-gdb-test.exp (gdb-test): Add a syntax for specifying
	the Nth hit of a breakpoint.
	* gcc.dg/guality/loop-2.c: New test.
	* gcc.dg/guality/loop-3.c: Likewise.
	* gcc.dg/guality/loop-4.c: Likewise.
diff mbox series

Patch

Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	2019-06-01 16:52:38.000000000 +0100
+++ gcc/gimple.h	2019-06-01 16:52:39.075271587 +0100
@@ -2782,6 +2782,18 @@  gimple_assign_load_p (const gimple *gs)
 }
 
 
+/* Return true if GS is an assignment that loads DECL into its lhs.  */
+
+static inline bool
+gimple_assign_load_decl_p (const gimple *gs, tree decl)
+{
+  const gassign *assign = dyn_cast <const gassign *> (gs);
+  return (assign
+	  && gimple_assign_single_p (assign)
+	  && get_base_address (gimple_assign_rhs1 (assign)) == decl);
+}
+
+
 /* Return true if S is a type-cast assignment.  */
 
 static inline bool
Index: gcc/tree-ssa.h
===================================================================
--- gcc/tree-ssa.h	2019-06-01 16:52:38.000000000 +0100
+++ gcc/tree-ssa.h	2019-06-01 16:52:39.079271578 +0100
@@ -39,6 +39,7 @@  extern void redirect_edge_var_map_empty
 extern edge ssa_redirect_edge (edge, basic_block);
 extern void flush_pending_stmts (edge);
 extern void gimple_replace_ssa_lhs (gimple *, tree);
+extern void inherit_target_for_debug_bind (tree, tree);
 extern tree target_for_debug_bind (tree);
 extern void insert_debug_temp_for_var_def (gimple_stmt_iterator *, tree);
 extern void insert_debug_temps_for_defs (gimple_stmt_iterator *);
Index: gcc/tree-ssa.c
===================================================================
--- gcc/tree-ssa.c	2019-06-01 16:52:38.000000000 +0100
+++ gcc/tree-ssa.c	2019-06-01 16:52:39.079271578 +0100
@@ -232,6 +232,25 @@  gimple_replace_ssa_lhs (gimple *stmt, tr
   gimple_set_lhs (stmt, nlhs);
 }
 
+/* Record that assignments to new temporary variable VAR should be treated
+   for debug purposes like an assignment to ORIGIN.  More specifically,
+   record that the value of target_for_debug_bind (VAR) should track the
+   value of target_for_debug_bind (ORIGIN).
+
+   This can be useful when replacing all references to ORIGIN with VAR
+   in a particular region of code.  */
+
+void
+inherit_target_for_debug_bind (tree var, tree origin)
+{
+  gcc_assert (VAR_P (var)
+	      && DECL_IGNORED_P (var)
+	      && DECL_ARTIFICIAL (var)
+	      && DECL_NAMELESS (var)
+	      && !DECL_ABSTRACT_ORIGIN (var));
+  if (target_for_debug_bind (origin))
+    DECL_ABSTRACT_ORIGIN (var) = origin;
+}
 
 /* Given a tree for an expression for which we might want to emit
    locations or values in debug information (generally a variable, but
@@ -252,6 +271,12 @@  target_for_debug_bind (tree var)
 	return NULL_TREE;
     }
 
+  /* Honor choices made through inherit_target_for_debug_bind.  */
+  if (VAR_P (var)
+      && DECL_IGNORED_P (var)
+      && !DECL_IGNORED_P (DECL_ORIGIN (var)))
+    var = DECL_ORIGIN (var);
+
   if ((!VAR_P (var) || VAR_DECL_IS_VIRTUAL_OPERAND (var))
       && TREE_CODE (var) != PARM_DECL)
     return NULL_TREE;
Index: gcc/tree-into-ssa.c
===================================================================
--- gcc/tree-into-ssa.c	2019-06-01 16:52:38.000000000 +0100
+++ gcc/tree-into-ssa.c	2019-06-01 16:52:39.079271578 +0100
@@ -1916,7 +1916,12 @@  maybe_register_def (def_operand_p def_p,
 	  SET_DEF (def_p, def);
 
 	  tree tracked_var = target_for_debug_bind (sym);
-	  if (tracked_var)
+	  /* Don't emit "VAR => DEF" for "DEF = VAR".  Although not
+	     semantically wrong, it leads to more resets when the load
+	     from VAR is (or might become) partly speculative.  */
+	  if (tracked_var
+	      && !(track_direct_refs_for_debug_p (tracked_var)
+		   && gimple_assign_load_decl_p (stmt, tracked_var)))
 	    {
 	      gimple *note = gimple_build_debug_bind (tracked_var, def, stmt);
 	      /* If stmt ends the bb, insert the debug stmt on the single
Index: gcc/tree-ssa-loop-im.c
===================================================================
--- gcc/tree-ssa-loop-im.c	2019-06-01 16:52:38.000000000 +0100
+++ gcc/tree-ssa-loop-im.c	2019-06-01 16:52:39.079271578 +0100
@@ -48,6 +48,7 @@  Free Software Foundation; either version
 #include "alias.h"
 #include "builtins.h"
 #include "tree-dfa.h"
+#include "tree-ssa.h"
 
 /* TODO:  Support for predicated code motion.  I.e.
 
@@ -1998,6 +1999,24 @@  execute_sm_if_changed (edge ex, tree mem
     orig_ex->aux = (void *) p;
   }
 
+  /* ??? As things stand, the value of MEM on entry to the join block
+     can be found at MEM's DECL_RTL.  It would therefore be accurate
+     to emit:
+
+         # DEBUG MEM s=> MEM
+
+     on entry to the block.  However, there's no guarantee that later
+     optimizations will keep things that way, and they can't reasonably
+     be expected to find and correct the statement.
+
+     E.g. if the store in THEN_BB is later deleted as dead, the debug
+     statement above would reestablish the connection between MEM and
+     its DECL_RTL even though the two are no longer the same.
+
+     We therefore leave things so that the debug location on entry
+     to the join block comes from MEM's DECL_RTL if the flag is set
+     and TMP_VAR otherwise.  */
+
   if (!loop_has_only_one_exit)
     for (gphi_iterator gpi = gsi_start_phis (old_dest);
 	 !gsi_end_p (gpi); gsi_next (&gpi))
@@ -2082,6 +2101,7 @@  execute_sm (struct loop *loop, vec<edge>
 
   tmp_var = create_tmp_reg (TREE_TYPE (ref->mem.ref),
 			    get_lsm_tmp_name (ref->mem.ref, ~0));
+  inherit_target_for_debug_bind (tmp_var, ref->mem.ref);
 
   fmt_data.loop = loop;
   fmt_data.orig_loop = loop;
Index: gcc/testsuite/lib/gcc-gdb-test.exp
===================================================================
--- gcc/testsuite/lib/gcc-gdb-test.exp	2019-06-01 16:52:38.000000000 +0100
+++ gcc/testsuite/lib/gcc-gdb-test.exp	2019-06-01 16:52:39.075271587 +0100
@@ -18,6 +18,7 @@ 
 # Call pass if variable has the desired value, otherwise fail.
 #
 # Argument 0 is the line number on which to put a breakpoint
+#   It can be suffixed by "*N" to test the Nth hit of the breakpoint.
 # Argument 1 is the name of the variable to be checked
 #   possibly prefixed with type: to get the type of the variable
 #   instead of the value of the variable (the default).
@@ -54,12 +55,18 @@  proc gdb-test { useline args } {
 	set var $arg1
     }
 
-    set line [lindex $args 0]
+    set line_pieces [split [lindex $args 0] "*"]
+    set line [lindex $line_pieces 0]
     if { [string range $line 0 0] == "@" } {
 	set line [string range $line 1 end]
     } else {
 	set line [get-absolute-line $useline $line]
     }
+    if { [llength $line_pieces] > 1 } {
+	set count [lindex $line_pieces 1]
+    } else {
+	set count 1
+    }
 
     set gdb_name $::env(GUALITY_GDB_NAME)
     set testname "$testcase line $line [lindex $args 1] == [lindex $args 2]"
@@ -69,6 +76,9 @@  proc gdb-test { useline args } {
     set fd [open $cmd_file "w"]
     puts $fd "break $line"
     puts $fd "run"
+    if { $count > 1 } {
+	puts $fd "continue [expr { $count - 1 }]"
+    }
     puts $fd "$command $var"
     if { $command == "print" } {
 	# For values, let gdb interpret them by printing them.
Index: gcc/testsuite/gcc.dg/guality/loop-2.c
===================================================================
--- /dev/null	2019-03-08 11:40:14.606883727 +0000
+++ gcc/testsuite/gcc.dg/guality/loop-2.c	2019-06-01 16:52:39.075271587 +0100
@@ -0,0 +1,41 @@ 
+/* { dg-do run } */
+/* Works without the --param except at -Os.  */
+/* { dg-options "-fno-tree-vectorize --param allow-store-data-races=1 -g" } */
+
+void __attribute__((noipa))
+get_start (int *x)
+{
+  *x = 42;
+}
+
+void __attribute__((noipa))
+consume (int *x)
+{
+  *x += 1;
+}
+
+void __attribute__((noipa))
+test (int *x, int *y, int n)
+{
+  int base;
+  get_start (&base);
+  base += 1; /* { dg-final { gdb-test . "base" "42" } } */
+  get_start (&base); /* { dg-final { gdb-test . "base" "43" } } */
+  for (int i = 0; i < n; ++i)
+    {
+      x[i] = base; /* { dg-final { gdb-test .*10 "base" "51" } } */
+      base += y[i];
+    }
+  y[0] = base; /* { dg-final { gdb-test . "base" "142" } } */
+  consume (&base); /* { dg-final { gdb-test . "base" "142" } } */
+  y[1] = 1; /* { dg-final { gdb-test . "base" "143" } } */
+}
+
+int
+main (void)
+{
+  int x[100], y[100];
+  for (int i = 0; i < 100; ++i)
+    y[i] = 1;
+  test (x, y, 100);
+}
Index: gcc/testsuite/gcc.dg/guality/loop-3.c
===================================================================
--- /dev/null	2019-03-08 11:40:14.606883727 +0000
+++ gcc/testsuite/gcc.dg/guality/loop-3.c	2019-06-01 16:52:39.075271587 +0100
@@ -0,0 +1,38 @@ 
+/* { dg-do run } */
+/* { dg-options "-fno-tree-vectorize -fno-unroll-loops -g" } */
+
+void __attribute__((noipa))
+get_start (int *x)
+{
+  *x = 42;
+}
+
+void __attribute__((noipa))
+consume (int *x)
+{
+  *x += 1;
+}
+
+void __attribute__((noipa))
+test (int *x, int *y)
+{
+  int base;
+  get_start (&base);
+  base += 1; /* { dg-final { gdb-test . "base" "42" } } */
+  get_start (&base); /* { dg-final { gdb-test . "base" "43" } } */
+  for (int i = 0; i < 100; ++i)
+    {
+      x[i] = base; /* { dg-final { gdb-test .*10 "base" "51" } } */
+      base += y[i];
+    }
+  y[0] = base; /* { dg-final { gdb-test . "base" "142" } } */
+}
+
+int
+main (void)
+{
+  int x[100], y[100];
+  for (int i = 0; i < 100; ++i)
+    y[i] = 1;
+  test (x, y);
+}
Index: gcc/testsuite/gcc.dg/guality/loop-4.c
===================================================================
--- /dev/null	2019-03-08 11:40:14.606883727 +0000
+++ gcc/testsuite/gcc.dg/guality/loop-4.c	2019-06-01 16:52:39.075271587 +0100
@@ -0,0 +1,34 @@ 
+/* { dg-do run } */
+/* { dg-options "-fno-tree-vectorize -fno-unroll-loops -g" } */
+
+void __attribute__((noipa))
+get_start (int *x)
+{
+  *x = 42;
+}
+
+void __attribute__((noipa))
+test (int *x, int *y)
+{
+  int base;
+  get_start (&base);
+  base += 1; /* { dg-final { gdb-test . "base" "42" } } */
+  get_start (&base);
+  for (int i = 0; i < 100; ++i)
+    {
+      x[i] = base; /* { dg-final { gdb-test .*10 "base" "51" } } */
+      base += y[i];
+    }
+  y[0] = base; /* { dg-final { gdb-test . "base" "142" } } */
+  base += 1;
+  y[1] = base; /* { dg-final { gdb-test . "base" "143" } } */
+}
+
+int
+main (void)
+{
+  int x[100], y[100];
+  for (int i = 0; i < 100; ++i)
+    y[i] = 1;
+  test (x, y);
+}