]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa.c
invoke.texi (-fvar-tracking-assignments): New.
[thirdparty/gcc.git] / gcc / tree-ssa.c
index 51b1689912115fb07297b28cc91ca70461ff36c7..db707fb35a9cfa64735add3a4ed8ba007d1bcd61 100644 (file)
@@ -243,6 +243,207 @@ flush_pending_stmts (edge e)
   redirect_edge_var_map_clear (e);
 }
 
+/* Given a tree for an expression for which we might want to emit
+   locations or values in debug information (generally a variable, but
+   we might deal with other kinds of trees in the future), return the
+   tree that should be used as the variable of a DEBUG_BIND STMT or
+   VAR_LOCATION INSN or NOTE.  Return NULL if VAR is not to be tracked.  */
+
+tree
+target_for_debug_bind (tree var)
+{
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return NULL_TREE;
+
+  if (TREE_CODE (var) != VAR_DECL
+      && TREE_CODE (var) != PARM_DECL)
+    return NULL_TREE;
+
+  if (DECL_HAS_VALUE_EXPR_P (var))
+    return target_for_debug_bind (DECL_VALUE_EXPR (var));
+
+  if (DECL_IGNORED_P (var))
+    return NULL_TREE;
+
+  if (!is_gimple_reg (var))
+    return NULL_TREE;
+
+  return var;
+}
+
+/* Called via walk_tree, look for SSA_NAMEs that have already been
+   released.  */
+
+static tree
+find_released_ssa_name (tree *tp, int *walk_subtrees, void *data_)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data_;
+
+  if (wi->is_lhs)
+    return NULL_TREE;
+
+  if (TREE_CODE (*tp) == SSA_NAME)
+    {
+      if (SSA_NAME_IN_FREE_LIST (*tp))
+       return *tp;
+
+      *walk_subtrees = 0;
+    }
+  else if (IS_TYPE_OR_DECL_P (*tp))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+/* Given a VAR whose definition STMT is to be moved to the iterator
+   position TOGSIP in the TOBB basic block, verify whether we're
+   moving it across any of the debug statements that use it, and
+   adjust them as needed.  If TOBB is NULL, then the definition is
+   understood as being removed, and TOGSIP is unused.  */
+void
+propagate_var_def_into_debug_stmts (tree var,
+                                   basic_block tobb,
+                                   const gimple_stmt_iterator *togsip)
+{
+  imm_use_iterator imm_iter;
+  gimple stmt;
+  use_operand_p use_p;
+  tree value = NULL;
+  bool no_value = false;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+    {
+      basic_block bb;
+      gimple_stmt_iterator si;
+
+      if (!is_gimple_debug (stmt))
+       continue;
+
+      if (tobb)
+       {
+         bb = gimple_bb (stmt);
+
+         if (bb != tobb)
+           {
+             gcc_assert (dom_info_available_p (CDI_DOMINATORS));
+             if (dominated_by_p (CDI_DOMINATORS, bb, tobb))
+               continue;
+           }
+         else
+           {
+             si = *togsip;
+
+             if (gsi_end_p (si))
+               continue;
+
+             do
+               {
+                 gsi_prev (&si);
+                 if (gsi_end_p (si))
+                   break;
+               }
+             while (gsi_stmt (si) != stmt);
+
+             if (gsi_end_p (si))
+               continue;
+           }
+       }
+
+      /* Here we compute (lazily) the value assigned to VAR, but we
+        remember if we tried before and failed, so that we don't try
+        again.  */
+      if (!value && !no_value)
+       {
+         gimple def_stmt = SSA_NAME_DEF_STMT (var);
+
+         if (is_gimple_assign (def_stmt))
+           {
+             if (!dom_info_available_p (CDI_DOMINATORS))
+               {
+                 struct walk_stmt_info wi;
+
+                 memset (&wi, 0, sizeof (wi));
+
+                 /* When removing blocks without following reverse
+                    dominance order, we may sometimes encounter SSA_NAMEs
+                    that have already been released, referenced in other
+                    SSA_DEFs that we're about to release.  Consider:
+
+                    <bb X>:
+                    v_1 = foo;
+
+                    <bb Y>:
+                    w_2 = v_1 + bar;
+                    # DEBUG w => w_2
+
+                    If we deleted BB X first, propagating the value of
+                    w_2 won't do us any good.  It's too late to recover
+                    their original definition of v_1: when it was
+                    deleted, it was only referenced in other DEFs, it
+                    couldn't possibly know it should have been retained,
+                    and propagating every single DEF just in case it
+                    might have to be propagated into a DEBUG STMT would
+                    probably be too wasteful.
+
+                    When dominator information is not readily
+                    available, we check for and accept some loss of
+                    debug information.  But if it is available,
+                    there's no excuse for us to remove blocks in the
+                    wrong order, so we don't even check for dead SSA
+                    NAMEs.  SSA verification shall catch any
+                    errors.  */
+                 if (!walk_gimple_op (def_stmt, find_released_ssa_name, &wi))
+                   no_value = true;
+               }
+
+             if (!no_value)
+               value = gimple_assign_rhs_to_tree (def_stmt);
+           }
+
+         if (!value)
+           no_value = true;
+       }
+
+      if (no_value)
+       gimple_debug_bind_reset_value (stmt);
+      else
+       FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+         SET_USE (use_p, unshare_expr (value));
+
+      update_stmt (stmt);
+    }
+}
+
+
+/* Given a STMT to be moved to the iterator position TOBSIP in the
+   TOBB basic block, verify whether we're moving it across any of the
+   debug statements that use it.  If TOBB is NULL, then the definition
+   is understood as being removed, and TOBSIP is unused.  */
+
+void
+propagate_defs_into_debug_stmts (gimple def, basic_block tobb,
+                                const gimple_stmt_iterator *togsip)
+{
+  ssa_op_iter op_iter;
+  def_operand_p def_p;
+
+  if (!MAY_HAVE_DEBUG_STMTS)
+    return;
+
+  FOR_EACH_SSA_DEF_OPERAND (def_p, def, op_iter, SSA_OP_DEF)
+    {
+      tree var = DEF_FROM_PTR (def_p);
+
+      if (TREE_CODE (var) != SSA_NAME)
+       continue;
+
+      propagate_var_def_into_debug_stmts (var, tobb, togsip);
+    }
+}
+
 /* Return true if SSA_NAME is malformed and mark it visited.
 
    IS_VIRTUAL is true if this SSA_NAME was found inside a virtual
@@ -636,6 +837,9 @@ verify_ssa (bool check_modified_stmt)
                  goto err;
                }
            }
+         else if (gimple_debug_bind_p (stmt)
+                  && !gimple_debug_bind_has_value_p (stmt))
+           continue;
 
          /* Verify the single virtual operand and its constraints.  */
          has_err = false;
@@ -1480,6 +1684,8 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
        {
          struct walk_stmt_info wi;
          data.stmt = gsi_stmt (gsi);
+         if (is_gimple_debug (data.stmt))
+           continue;
          memset (&wi, 0, sizeof (wi));
          wi.info = &data;
          walk_gimple_op (gsi_stmt (gsi), warn_uninitialized_var, &wi);