[PATCH 0/3] RFC: Keep debug values live for -Og

Richard Sandiford richard.sandiford@arm.com
Sun Jun 23 13:53:00 GMT 2019


This patch tries to make sure that, when optimising at -Og, the gimple
IL has appropriate debug information for the whole of a variable's scope.
It does the same for parameters in functions that always return (but still
misses cases in functions that don't return -- a TODO for later).

The idea is to emit a debug stmt that uses each gimple register "var"
when it goes out of scope.  With the new "tangible" debug stmts, this
forces SSA renaming of "var" for its entire lifetime, even after the
last real use.  This in turn means that we should enter rtl in a state
where, at any given point in a variable's scope, there is a single
dominating debug bind insn for it.

A side-effect of this is that a variable that is in-scope but
uninitialised and unused will give "0" rather than "<optimized out>"
(where the zero is guaranteed by init-regs).  E.g. for functions like:

static inline void
get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p,
					HARD_REG_SET *conflict_regs,
					HARD_REG_SET *start_profitable_regs)
{
  int i, nwords;
  ira_object_t obj;

  nwords = ALLOCNO_NUM_OBJECTS (a);
  for (i = 0; i < nwords; i++)
    {
      obj = ALLOCNO_OBJECT (a, i);
      COPY_HARD_REG_SET (conflict_regs[i],
			 OBJECT_TOTAL_CONFLICT_HARD_REGS (obj));
    }
  if (retry_p)
    {
      COPY_HARD_REG_SET (*start_profitable_regs,
			 reg_class_contents[ALLOCNO_CLASS (a)]);
      AND_COMPL_HARD_REG_SET (*start_profitable_regs,
			      ira_prohibited_class_mode_regs
			      [ALLOCNO_CLASS (a)][ALLOCNO_MODE (a)]);
    }
  else
    COPY_HARD_REG_SET (*start_profitable_regs,
		       ALLOCNO_COLOR_DATA (a)->profitable_hard_regs);
}

it is still possible to print "obj" after the loop.  If nwords is <= 0
(which it never is in practice), "obj" would print as zero.

IMO this isn't wrong debug info, because the value that we print for
"obj" is the value that a printf at that location would print, even in
the uninitialised/zero case.  And this kind of for loop is very common:
the program in practice guarantees that the loop executes at least once,
and thus guarantees that "obj" has a useful value, but the compiler
doesn't know that.

The patch uses debug insns of the form:

    # DEBUG NULL => var

to keep "var" live.  Binding to null seemed better than binding to "var",
which is about to go out of scope and doesn't actually change value here.
Binding to null also means that we can delete the stmt if no longer has
any SSA uses (e.g. due to fwprop).  Most of the patch is just adding
support for null debug bind vars.

Although this should ensure we have good-quality debug info for gimple
registers when entering rtl, it doesn't guarantee that the value bound
in a debug bind insn remains live for as long as the debug bind is in effect.
That's a separate patch.

It's also possible that rtl cfg manipulations could break the original
property of having one dominating debug bind at each point.  That too
is a separate patch.  It probably makes sense to fix both of these
problems immediately before IRA.

The patch fixes the referenced PRs.  In particular, the backtrace for
PR78685 is now:

  #0  call_debugger (x=x@entry=3) at pr78685.c:6
  #1  ... in apply_lambda (fun=fun@entry=1, args=args@entry=2, count=count@entry=3) at pr78685.c:14
  #2  ... in main (argc=1, argv=0x<addr>) at pr78685.c:22

instead of:

  #0  call_debugger (x=3) at pr78685.c:6
  #1  ... in apply_lambda (fun=1, args=2, count=<optimized out>) at pr78685.c:14
  #2  ... in main (argc=<optimized out>, argv=<optimized out>) at pr78685.c:22


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

gcc/
	PR debug/78685
	PR debug/88730
	* gimplify.c (gimplify_keep_decl_live): New function.
	(gimplify_bind_expr, gimplify_return_expr): Use it.
	* function.c (gimplify_parameters): Add debug stmts for parameters
	if flag_tangible_debug.
	* var-tracking.c (use_type): Drop debug binds with null variables.
	(delete_vta_debug_insn): Likewise.
	* gimple-low.c (lower_stmt): Allow debug binds too.
	* cfgexpand.c (expand_debug_locations): Handle null debug bind vars.
	(expand_gimple_basic_block): Likewise.
	* cfgrtl.c (duplicate_insn_chain): Likewise.
	* cse.c (insn_live_p): Likewise.
	* omp-simd-clone.c (ipa_simd_modify_function_body): Likewise.
	* print-rtl.c (rtx_writer::print_rtx, print_insn): Likewise.
	* tree-cfg.c (make_blocks_1, stmt_starts_bb_p): Handle tangible
	debug stmts like normal stmts.
	(make_blocks): Check for marker stmts rather than asserting for them.
	(gimple_duplicate_bb): Handle null debug bind vars.
	* tree-inline.c (maybe_move_debug_stmts_to_successors): Likewise.
	(copy_debug_stmt): Likewise.
	* tree-parloops.c (separate_decls_in_region_debug): Likewise.
	* tree-ssa-threadedge.c (propagate_threaded_block_debug_into):
	Likewise.
	* tree-ssa-dce.c (eliminate_unnecessary_stmts): Likewise.
	(mark_stmt_if_obviously_necessary): Likewise.  Allow debug binds
	with null variables to be deleted if they no longer have any
	SSA uses.

gcc/testsuite/
	* c-c++-common/guality/Og-keep-alive-1.c: New test.
	* c-c++-common/guality/Og-pr88730.c: Likewise.

Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c	2019-06-18 09:35:54.925869432 +0100
+++ gcc/gimplify.c	2019-06-23 14:48:55.226975633 +0100
@@ -1300,6 +1300,28 @@ asan_poison_variables (hash_set<tree> *v
     }
 }
 
+/* If DECL is a parameter or variable that we're going to rewrite into
+   SSA form, emit a "# DEBUG NULL => DECL" statement to make it live at
+   the end of SEQ, which is the point at which DECL dies.  This is only
+   valid for flag_tangible_debug.
+
+   Doing this ensures that we have an SSA name definition of DECL
+   throughout its lifetime, which as a side-effect ensures that a debug
+   binding for T is always available throughout its lifetime.  We can
+   then try to optimize away the SSA names, but only if doing so doesn't
+   compromise the debug bindings.  */
+
+static void
+gimplify_keep_decl_live (gimple_seq *seq, tree decl)
+{
+  gcc_assert (MAY_HAVE_DEBUG_BIND_STMTS && flag_tangible_debug);
+  if (is_gimple_reg (decl) && target_for_debug_bind (decl))
+    {
+      gdebug *debug = gimple_build_debug_bind (NULL_TREE, decl, NULL);
+      gimplify_seq_add_stmt (seq, debug);
+    }
+}
+
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
 
 static enum gimplify_status
@@ -1434,6 +1456,11 @@ gimplify_bind_expr (tree *expr_p, gimple
 	  && !is_global_var (t)
 	  && DECL_CONTEXT (t) == current_function_decl)
 	{
+	  if (MAY_HAVE_DEBUG_BIND_INSNS && flag_tangible_debug)
+	    /* Ensure that the variable's value is available for debug
+	       purposes throughout its lifetime.  */
+	    gimplify_keep_decl_live (&cleanup, t);
+
 	  if (!DECL_HARD_REGISTER (t)
 	      && !TREE_THIS_VOLATILE (t)
 	      && !DECL_HAS_VALUE_EXPR_P (t)
@@ -1629,6 +1656,14 @@ gimplify_return_expr (tree stmt, gimple_
 
   gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
 
+  if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tangible_debug)
+    /* If we're going to rewrite a parameter into SSA form, ensure that
+       the parameter's value is available for debug purposes throughout
+       its lifetime.  */
+    for (tree decl = DECL_ARGUMENTS (current_function_decl);
+	 decl; decl = DECL_CHAIN (decl))
+      gimplify_keep_decl_live (pre_p, decl);
+
   maybe_add_early_return_predict_stmt (pre_p);
   ret = gimple_build_return (result);
   gimple_set_no_warning (ret, TREE_NO_WARNING (stmt));
Index: gcc/function.c
===================================================================
--- gcc/function.c	2019-06-21 15:37:49.635878948 +0100
+++ gcc/function.c	2019-06-23 14:48:55.222975666 +0100
@@ -3906,6 +3906,17 @@ gimplify_parameters (gimple_seq *cleanup
 	      DECL_HAS_VALUE_EXPR_P (parm) = 1;
 	    }
 	}
+      if (flag_tangible_debug
+	  && is_gimple_reg (parm)
+	  && target_for_debug_bind (parm))
+	{
+	  /* This will be rewritten during SSA renaming to
+	     "# DEBUG parm => parm_N(D)".  In functions that return,
+	     the return statements have partnering "# DEBUG NULL => parm_M",
+	     statements.  */
+	  gdebug *debug = gimple_build_debug_bind (parm, parm, NULL);
+	  gimple_seq_add_stmt_without_update (&stmts, debug);
+	}
     }
 
   fnargs.release ();
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	2019-06-07 08:39:43.686343024 +0100
+++ gcc/var-tracking.c	2019-06-23 14:48:55.234975566 +0100
@@ -5508,7 +5508,10 @@ use_type (rtx loc, struct count_use_info
     {
       if (GET_CODE (loc) == VAR_LOCATION)
 	{
-	  if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
+	  /* The point of debug binds with no variable is to keep values
+	     live until this pass runs.  We can drop them here.  */
+	  if (PAT_VAR_LOCATION_DECL (loc)
+	      && track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
 	    {
 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
 	      if (! VAR_LOC_UNKNOWN_P (ploc))
@@ -10315,7 +10318,8 @@ delete_vta_debug_insn (rtx_insn *insn)
     }
 
   tree decl = INSN_VAR_LOCATION_DECL (insn);
-  if (TREE_CODE (decl) == LABEL_DECL
+  if (decl
+      && TREE_CODE (decl) == LABEL_DECL
       && DECL_NAME (decl)
       && !DECL_RTL_SET_P (decl))
     {
Index: gcc/gimple-low.c
===================================================================
--- gcc/gimple-low.c	2019-06-18 09:35:54.121876078 +0100
+++ gcc/gimple-low.c	2019-06-23 14:48:55.222975666 +0100
@@ -309,18 +309,25 @@ lower_stmt (gimple_stmt_iterator *gsi, s
       break;
 
     case GIMPLE_DEBUG:
-      gcc_checking_assert (cfun->debug_nonbind_markers);
-      /* We can't possibly have debug bind stmts before lowering, we
-	 first emit them when entering SSA.  */
-      gcc_checking_assert (gimple_debug_nonbind_marker_p (stmt));
-      /* Propagate fallthruness.  */
-      /* If the function (e.g. from PCH) had debug stmts, but they're
-	 disabled for this compilation, remove them.  */
-      if (!MAY_HAVE_DEBUG_MARKER_STMTS)
-	gsi_remove (gsi, true);
-      else
-	gsi_next (gsi);
-      return;
+      {
+	bool keep_p;
+	if (gimple_debug_nonbind_marker_p (stmt))
+	  {
+	    gcc_assert (cfun->debug_nonbind_markers);
+	    keep_p = MAY_HAVE_DEBUG_MARKER_STMTS;
+	  }
+	else if (gimple_debug_bind_p (stmt)
+		 || gimple_debug_source_bind_p (stmt))
+	  keep_p = MAY_HAVE_DEBUG_BIND_STMTS;
+	else
+	  gcc_unreachable ();
+
+	if (keep_p)
+	  gsi_next (gsi);
+	else
+	  gsi_remove (gsi, true);
+	return;
+      }
 
     case GIMPLE_NOP:
     case GIMPLE_ASM:
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	2019-06-23 14:48:44.491065092 +0100
+++ gcc/cfgexpand.c	2019-06-23 14:48:55.222975666 +0100
@@ -5455,6 +5455,7 @@ expand_debug_locations (void)
 	       being defined in this DEBUG_INSN.  */
 	    else if (deep_ter_debug_map && TREE_CODE (value) == SSA_NAME)
 	      {
+		gcc_assert (INSN_VAR_LOCATION_DECL (insn));
 		tree *slot = deep_ter_debug_map->get (value);
 		if (slot)
 		  {
@@ -5796,19 +5797,22 @@ expand_gimple_basic_block (basic_block b
 		    {
 		      var = gimple_debug_bind_get_var (stmt);
 
-		      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+		      if (var
+			  && TREE_CODE (var) != DEBUG_EXPR_DECL
 			  && TREE_CODE (var) != LABEL_DECL
 			  && !target_for_debug_bind (var))
 			goto delink_debug_stmt;
 
-		      if (DECL_P (var))
+		      if (gimple_debug_bind_has_value_p (stmt))
+			value = gimple_debug_bind_get_value (stmt);
+
+		      if (!var)
+			mode = TYPE_MODE (TREE_TYPE (value));
+		      else if (DECL_P (var))
 			mode = DECL_MODE (var);
 		      else
 			mode = TYPE_MODE (TREE_TYPE (var));
 
-		      if (gimple_debug_bind_has_value_p (stmt))
-			value = gimple_debug_bind_get_value (stmt);
-
 		      val = gen_rtx_VAR_LOCATION
 			(mode, var, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
 		    }
Index: gcc/cfgrtl.c
===================================================================
--- gcc/cfgrtl.c	2019-06-07 08:39:43.690343015 +0100
+++ gcc/cfgrtl.c	2019-06-23 14:48:55.222975666 +0100
@@ -4185,6 +4185,7 @@ duplicate_insn_chain (rtx_insn *from, rt
 	case DEBUG_INSN:
 	  /* Don't duplicate label debug insns.  */
 	  if (DEBUG_BIND_INSN_P (insn)
+	      && INSN_VAR_LOCATION_DECL (insn)
 	      && TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
 	    break;
 	  /* FALLTHRU */
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	2019-06-23 14:48:44.499065025 +0100
+++ gcc/cse.c	2019-06-23 14:48:55.222975666 +0100
@@ -7068,6 +7068,8 @@ insn_live_p (rtx_insn *insn, int *counts
 	   we want to keep the earlier debug insn.  */
 	else if (DEBUG_MARKER_INSN_P (next))
 	  return true;
+	else if (!INSN_VAR_LOCATION_DECL (insn))
+	  return true;
 	else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
 	  return false;
 
Index: gcc/omp-simd-clone.c
===================================================================
--- gcc/omp-simd-clone.c	2019-03-18 12:24:58.391436179 +0000
+++ gcc/omp-simd-clone.c	2019-06-23 14:48:55.226975633 +0100
@@ -1073,6 +1073,7 @@ ipa_simd_modify_function_body (struct cg
 		 vectorized loops doesn't work too well, so don't bother for
 		 now.  */
 	      if ((gimple_debug_bind_p (stmt)
+		   && gimple_debug_bind_get_var (stmt)
 		   && !DECL_P (gimple_debug_bind_get_var (stmt)))
 		  || (gimple_debug_source_bind_p (stmt)
 		      && !DECL_P (gimple_debug_source_bind_get_var (stmt))))
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	2019-06-07 08:39:59.000000000 +0100
+++ gcc/print-rtl.c	2019-06-23 14:48:55.226975633 +0100
@@ -861,7 +861,9 @@ rtx_writer::print_rtx (const_rtx in_rtx)
 #ifndef GENERATOR_FILE
       if (GET_CODE (in_rtx) == VAR_LOCATION)
 	{
-	  if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
+	  if (!PAT_VAR_LOCATION_DECL (in_rtx))
+	    fputs (" <none>", m_outfile);
+	  else if (TREE_CODE (PAT_VAR_LOCATION_DECL (in_rtx)) == STRING_CST)
 	    fputs (" <debug string placeholder>", m_outfile);
 	  else
 	    print_mem_expr (m_outfile, PAT_VAR_LOCATION_DECL (in_rtx));
@@ -1914,7 +1916,8 @@ print_insn (pretty_printer *pp, const rt
 	const char *name = "?";
 	char idbuf[32];
 
-	if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
+	if (INSN_VAR_LOCATION_DECL (x)
+	    && DECL_P (INSN_VAR_LOCATION_DECL (x)))
 	  {
 	    tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (x));
 	    if (id)
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	2019-06-23 14:48:44.511064925 +0100
+++ gcc/tree-cfg.c	2019-06-23 14:48:55.230975600 +0100
@@ -524,15 +524,15 @@ make_blocks_1 (gimple_seq seq, basic_blo
 
   while (!gsi_end_p (i))
     {
-      /* PREV_STMT should only be set to a debug stmt if the debug
-	 stmt is before nondebug stmts.  Once stmt reaches a nondebug
+      /* PREV_STMT should only be set to a shadow stmt if the shadow
+	 stmt is before tangible stmts.  Once stmt reaches a tangible
 	 nonlabel, prev_stmt will be set to it, so that
 	 stmt_starts_bb_p will know to start a new block if a label is
-	 found.  However, if stmt was a label after debug stmts only,
-	 keep the label in prev_stmt even if we find further debug
+	 found.  However, if stmt was a label after shadow stmts only,
+	 keep the label in prev_stmt even if we find further shadow
 	 stmts, for there may be other labels after them, and they
 	 should land in the same block.  */
-      if (!prev_stmt || !stmt || !is_gimple_debug (stmt))
+      if (!prev_stmt || !stmt || tangible_stmt_p (stmt))
 	prev_stmt = stmt;
       stmt = gsi_stmt (i);
 
@@ -633,9 +633,8 @@ make_blocks (gimple_seq seq)
 	    continue;
 
 	  /* Move the debug stmt at I after LABEL.  */
-	  if (is_gimple_debug (stmt))
+	  if (gimple_debug_nonbind_marker_p (stmt))
 	    {
-	      gcc_assert (gimple_debug_nonbind_marker_p (stmt));
 	      /* As STMT is removed, I advances to the stmt after
 		 STMT, so the gsi_prev in the for "increment"
 		 expression gets us to the stmt we're to visit after
@@ -2705,11 +2704,11 @@ stmt_starts_bb_p (gimple *stmt, gimple *
   if (stmt == NULL)
     return false;
 
-  /* PREV_STMT is only set to a debug stmt if the debug stmt is before
-     any nondebug stmts in the block.  We don't want to start another
-     block in this case: the debug stmt will already have started the
-     one STMT would start if we weren't outputting debug stmts.  */
-  if (prev_stmt && is_gimple_debug (prev_stmt))
+  /* PREV_STMT is only set to a shadow stmt if the shadow stmt is before
+     any tangible stmts in the block.  We don't want to start another
+     block in this case: the shadow stmt will already have started the
+     one STMT would start if we weren't outputting shadow stmts.  */
+  if (prev_stmt && !tangible_stmt_p (prev_stmt))
     return false;
 
   /* Labels start a new basic block only if the preceding statement
@@ -6196,6 +6195,7 @@ gimple_duplicate_bb (basic_block bb, cop
 
       /* Don't duplicate label debug stmts.  */
       if (gimple_debug_bind_p (stmt)
+	  && gimple_debug_bind_get_var (stmt)
 	  && TREE_CODE (gimple_debug_bind_get_var (stmt))
 	     == LABEL_DECL)
 	continue;
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c	2019-06-23 14:48:44.511064925 +0100
+++ gcc/tree-inline.c	2019-06-23 14:48:55.230975600 +0100
@@ -2760,8 +2760,10 @@ maybe_move_debug_stmts_to_successors (co
 		  value = unshare_expr (value);
 		  new_stmt = gimple_build_debug_bind (var, value, stmt);
 		}
-	      else
+	      else if (var)
 		new_stmt = gimple_build_debug_bind (var, NULL_TREE, NULL);
+	      else
+		continue;
 	    }
 	  else if (gimple_debug_source_bind_p (stmt))
 	    {
@@ -3060,16 +3062,19 @@ copy_debug_stmt (gdebug *stmt, copy_body
   else
     gcc_unreachable ();
 
-  if (TREE_CODE (t) == PARM_DECL && id->debug_map
-      && (n = id->debug_map->get (t)))
+  if (t)
     {
-      gcc_assert (VAR_P (*n));
-      t = *n;
+      if (TREE_CODE (t) == PARM_DECL && id->debug_map
+	  && (n = id->debug_map->get (t)))
+	{
+	  gcc_assert (VAR_P (*n));
+	  t = *n;
+	}
+      else if (VAR_P (t) && !is_global_var (t) && !id->decl_map->get (t))
+	/* T is a non-localized variable.  */;
+      else
+	walk_tree (&t, remap_gimple_op_r, &wi, NULL);
     }
-  else if (VAR_P (t) && !is_global_var (t) && !id->decl_map->get (t))
-    /* T is a non-localized variable.  */;
-  else
-    walk_tree (&t, remap_gimple_op_r, &wi, NULL);
 
   if (gimple_debug_bind_p (stmt))
     {
Index: gcc/tree-parloops.c
===================================================================
--- gcc/tree-parloops.c	2019-06-18 09:35:54.197875448 +0100
+++ gcc/tree-parloops.c	2019-06-23 14:48:55.230975600 +0100
@@ -950,23 +950,27 @@ separate_decls_in_region_debug (gimple *
   name_to_copy_elt **slot;
   int_tree_map *dslot;
 
+  /* FIXME */
   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 || TREE_CODE (var) == LABEL_DECL)
-    return true;
-  gcc_assert (DECL_P (var) && SSA_VAR_P (var));
-  ielt.uid = DECL_UID (var);
-  dslot = decl_copies->find_slot_with_hash (ielt, ielt.uid, NO_INSERT);
-  if (!dslot)
-    return true;
-  if (gimple_debug_bind_p (stmt))
-    gimple_debug_bind_set_var (stmt, dslot->to);
-  else if (gimple_debug_source_bind_p (stmt))
-    gimple_debug_source_bind_set_var (stmt, dslot->to);
+  if (var)
+    {
+      if (TREE_CODE (var) == DEBUG_EXPR_DECL || TREE_CODE (var) == LABEL_DECL)
+	return true;
+      gcc_assert (DECL_P (var) && SSA_VAR_P (var));
+      ielt.uid = DECL_UID (var);
+      dslot = decl_copies->find_slot_with_hash (ielt, ielt.uid, NO_INSERT);
+      if (!dslot)
+	return true;
+      if (gimple_debug_bind_p (stmt))
+	gimple_debug_bind_set_var (stmt, dslot->to);
+      else if (gimple_debug_source_bind_p (stmt))
+	gimple_debug_source_bind_set_var (stmt, dslot->to);
+    }
 
   FOR_EACH_PHI_OR_STMT_USE (use, stmt, oi, SSA_OP_USE)
   {
Index: gcc/tree-ssa-threadedge.c
===================================================================
--- gcc/tree-ssa-threadedge.c	2019-06-18 09:35:55.505864640 +0100
+++ gcc/tree-ssa-threadedge.c	2019-06-23 14:48:55.234975566 +0100
@@ -803,10 +803,13 @@ propagate_threaded_block_debug_into (bas
       else
 	gcc_unreachable ();
 
-      if (vars)
-	vars->add (var);
-      else
-	fewvars.quick_push (var);
+      if (var)
+	{
+	  if (vars)
+	    vars->add (var);
+	  else
+	    fewvars.quick_push (var);
+	}
     }
 
   basic_block bb = dest;
@@ -844,9 +847,9 @@ propagate_threaded_block_debug_into (bas
 	     not actually running the code that performed the binds at
 	     this point, we're just adding binds so that they survive
 	     the new confluence, so markers should not be copied.  */
-	  if (vars && vars->add (var))
+	  if (var && vars && vars->add (var))
 	    continue;
-	  else if (!vars)
+	  if (var && !vars)
 	    {
 	      int i = fewvars.length ();
 	      while (i--)
Index: gcc/tree-ssa-dce.c
===================================================================
--- gcc/tree-ssa-dce.c	2019-06-23 14:48:44.515064892 +0100
+++ gcc/tree-ssa-dce.c	2019-06-23 14:48:55.230975600 +0100
@@ -282,15 +282,26 @@ mark_stmt_if_obviously_necessary (gimple
       }
 
     case GIMPLE_DEBUG:
-      /* Debug temps without a value are not useful.  ??? If we could
-	 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_nonbind_marker_p (stmt)
-	  || !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, tangible_stmt_p (stmt));
+      if (gimple_debug_bind_p (stmt))
+	{
+	  tree var = gimple_debug_bind_get_var (stmt);
+
+	  /* Debug temps without a value are not useful.  ??? If we could
+	     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 (var
+	      && TREE_CODE (var) == DEBUG_EXPR_DECL
+	      && !gimple_debug_bind_has_value_p (stmt))
+	    return;
+
+	  /* "# DEBUG NULL => foo" only exists to keep foo live till this
+	     point (and initially to force SSA renaming).  Drop it if it
+	     no longer has any effect.  */
+	  if (!var && !gimple_use_ops (stmt))
+	    return;
+	}
+      mark_stmt_necessary (stmt, tangible_stmt_p (stmt));
       return;
 
     case GIMPLE_GOTO:
@@ -1399,7 +1410,8 @@ eliminate_unnecessary_stmts (void)
 	         non-DEBUG_EXPR_DECL variable in a series of
 		 debug-bind stmts.  */
 	      tree var = gimple_debug_bind_get_var (stmt);
-	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+	      if (var
+		  && TREE_CODE (var) != DEBUG_EXPR_DECL
 		  && !bitmap_set_bit (debug_seen, DECL_UID (var)))
 		remove_dead_stmt (&gsi, bb, to_remove_edges);
 	      continue;
Index: gcc/testsuite/c-c++-common/guality/Og-keep-alive-1.c
===================================================================
--- /dev/null	2019-06-14 15:59:19.298479944 +0100
+++ gcc/testsuite/c-c++-common/guality/Og-keep-alive-1.c	2019-06-23 14:48:55.226975633 +0100
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "../../gcc.dg/nop.h"
+
+int __attribute__ ((noipa))
+f (int a)
+{
+  int b, c;
+  if (a < 10)
+    {
+      b = 3;
+      c = b + a;
+    }
+  else
+    {
+      b = 2;
+      c = b - a;
+    }
+  asm volatile (NOP);	/* { dg-final { gdb-test . "a" "10" } } */
+			/* { dg-final { gdb-test .-1 "b" "2" } } */
+			/* { dg-final { gdb-test .-2 "c" "-8" } } */
+  return c;
+}
+
+int
+main (void)
+{
+  f (10);
+}
Index: gcc/testsuite/c-c++-common/guality/Og-pr88730.c
===================================================================
--- /dev/null	2019-06-14 15:59:19.298479944 +0100
+++ gcc/testsuite/c-c++-common/guality/Og-pr88730.c	2019-06-23 14:48:55.226975633 +0100
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "../../gcc.dg/nop.h"
+
+int a;
+int main() {
+  int b, j;
+  b = 0;
+  for (; b < 1; b++) {
+    j = 0;
+    for (; j < 5; j++)
+      ;
+  }
+  asm volatile (NOP); /* { dg-final { gdb-test . "j" "5" } } */
+}



More information about the Gcc-patches mailing list