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 remove_unused_locals (PR tree-optimization/33645)


Hi!

As the first testcase below shows, remove_unused_locals can purge
global (static) vars from unexpanded_var_list, even when they are actually
used by some used static var initializer.  The testcase doesn't fail
with -funit-at-a-time, because build_cgraph_edges already added the vars
into varpool and so even when they are not present in unexpanded_var_list,
they will be emitted if they are actually used.

Simply not purging is_global_var vars from unexpanded_var_list would cause
regression on attached pr33645-3.c, so this patch calls mark_all_vars_used
on DECL_INITIAL of in unexpanded_var_list present is_global_vars that are
known to be used (and does that recursively for newly such discovered vars).

Regtested on x86_64-linux, ok for trunk?

2007-10-11  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/33645
	* tree-ssa-live.c (mark_all_vars_used): Add data argument,
	pass it to walk_tree.
	(mark_all_vars_used_1): Pass data through to mark_all_vars_used.
	When calling set_is_used on a VAR_DECL, if data is not NULL and
	its DECL_UID is in the bitmap, call mark_all_vars_used on its
	DECL_INITIAL after clearing the bit in bitmap.
	(remove_unused_locals): Adjust mark_all_vars_used callers.
	Instead of removing unused global vars from unexpanded_var_list
	immediately record them in bitmap, call mark_all_vars_used on
	all used global vars from unexpanded_var_list and only purge
	global vars that weren't found used even during that step.

	* gcc.dg/pr33645-1.c: New test.
	* gcc.dg/pr33645-2.c: New test.
	* gcc.dg/pr33645-3.c: New test.
 
--- gcc/tree-ssa-live.c.jj	2007-10-03 21:33:54.000000000 +0200
+++ gcc/tree-ssa-live.c	2007-10-11 13:45:06.000000000 +0200
@@ -397,13 +397,13 @@ change_partition_var (var_map map, tree 
 }
 
 
-static inline void mark_all_vars_used (tree *);
+static inline void mark_all_vars_used (tree *, void *data);
 
 /* Helper function for mark_all_vars_used, called via walk_tree.  */
 
 static tree
 mark_all_vars_used_1 (tree *tp, int *walk_subtrees,
-		      void *data ATTRIBUTE_UNUSED)
+		      void *data)
 {
   tree t = *tp;
   enum tree_code_class c = TREE_CODE_CLASS (TREE_CODE (t));
@@ -420,9 +420,9 @@ mark_all_vars_used_1 (tree *tp, int *wal
      fields that do not contain vars.  */
   if (TREE_CODE (t) == TARGET_MEM_REF)
     {
-      mark_all_vars_used (&TMR_SYMBOL (t));
-      mark_all_vars_used (&TMR_BASE (t));
-      mark_all_vars_used (&TMR_INDEX (t));
+      mark_all_vars_used (&TMR_SYMBOL (t), data);
+      mark_all_vars_used (&TMR_BASE (t), data);
+      mark_all_vars_used (&TMR_INDEX (t), data);
       *walk_subtrees = 0;
       return NULL;
     }
@@ -430,7 +430,14 @@ mark_all_vars_used_1 (tree *tp, int *wal
   /* Only need to mark VAR_DECLS; parameters and return results are not
      eliminated as unused.  */
   if (TREE_CODE (t) == VAR_DECL)
-    set_is_used (t);
+    {
+      if (data != NULL && bitmap_bit_p ((bitmap) data, DECL_UID (t)))
+	{
+	  bitmap_clear_bit ((bitmap) data, DECL_UID (t));
+	  mark_all_vars_used (&DECL_INITIAL (t), data);
+	}
+      set_is_used (t);
+    }
 
   if (IS_TYPE_OR_DECL_P (t))
     *walk_subtrees = 0;
@@ -547,9 +554,9 @@ remove_unused_scope_block_p (tree scope)
    eliminated during the tree->rtl conversion process.  */
 
 static inline void
-mark_all_vars_used (tree *expr_p)
+mark_all_vars_used (tree *expr_p, void *data)
 {
-  walk_tree (expr_p, mark_all_vars_used_1, NULL, NULL);
+  walk_tree (expr_p, mark_all_vars_used_1, data, NULL);
 }
 
 
@@ -562,6 +569,7 @@ remove_unused_locals (void)
   tree t, *cell;
   referenced_var_iterator rvi;
   var_ann_t ann;
+  bitmap global_unused_vars = NULL;
 
   mark_scope_block_unused (DECL_INITIAL (current_function_decl));
   /* Assume all locals are unused.  */
@@ -576,7 +584,7 @@ remove_unused_locals (void)
 
       /* Walk the statements.  */
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-	mark_all_vars_used (bsi_stmt_ptr (bsi));
+	mark_all_vars_used (bsi_stmt_ptr (bsi), NULL);
 
       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
         {
@@ -588,17 +596,17 @@ remove_unused_locals (void)
 	    continue;
 
           def = PHI_RESULT (phi);
-          mark_all_vars_used (&def);
+	  mark_all_vars_used (&def, NULL);
 
           FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_ALL_USES)
             {
 	      tree arg = USE_FROM_PTR (arg_p);
-	      mark_all_vars_used (&arg);
+	      mark_all_vars_used (&arg, NULL);
             }
         }
     }
 
-  /* Remove unmarked vars and clear used flag.  */
+  /* Remove unmarked local vars from unexpanded_var_list.  */
   for (cell = &cfun->unexpanded_var_list; *cell; )
     {
       tree var = TREE_VALUE (*cell);
@@ -607,12 +615,49 @@ remove_unused_locals (void)
 	  && (!(ann = var_ann (var))
 	      || !ann->used))
 	{
-	  *cell = TREE_CHAIN (*cell);
-	  continue;
+	  if (is_global_var (var))
+	    {
+	      if (global_unused_vars == NULL)
+		global_unused_vars = BITMAP_ALLOC (NULL);
+	      bitmap_set_bit (global_unused_vars, DECL_UID (var));
+	    }
+	  else
+	    {
+	      *cell = TREE_CHAIN (*cell);
+	      continue;
+	    }
 	}
       cell = &TREE_CHAIN (*cell);
     }
 
+  /* Remove unmarked global vars from unexpanded_var_list.  */
+  if (global_unused_vars != NULL)
+    {
+      for (t = cfun->unexpanded_var_list; t; t = TREE_CHAIN (t))
+	{
+	  tree var = TREE_VALUE (t);
+
+	  if (TREE_CODE (var) == VAR_DECL
+	      && is_global_var (var)
+	      && (ann = var_ann (var)) != NULL
+	      && ann->used)
+	    mark_all_vars_used (&DECL_INITIAL (var), global_unused_vars);
+	}
+
+      for (cell = &cfun->unexpanded_var_list; *cell; )
+	{
+	  tree var = TREE_VALUE (*cell);
+
+	  if (TREE_CODE (var) == VAR_DECL
+	      && is_global_var (var)
+	      && bitmap_bit_p (global_unused_vars, DECL_UID (var)))
+	    *cell = TREE_CHAIN (*cell);
+	  else
+	    cell = &TREE_CHAIN (*cell);
+	}
+      BITMAP_FREE (global_unused_vars);
+    }
+
   /* Remove unused variables from REFERENCED_VARs.  As a special
      exception keep the variables that are believed to be aliased.
      Those can't be easily removed from the alias sets and operand
--- gcc/testsuite/gcc.dg/pr33645-1.c.jj	2007-10-11 13:52:00.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr33645-1.c	2007-10-11 13:51:27.000000000 +0200
@@ -0,0 +1,18 @@
+/* PR tree-optimization/33645 */
+/* { dg-do link } */
+/* { dg-options "-O2 -fno-unit-at-a-time" } */
+
+__attribute__((noinline)) int
+bar (int *x)
+{
+  return *x++;
+}
+
+int
+main ()
+{
+  static int var1_s;
+  static int *var1_t = &var1_s;
+
+  return bar (var1_t) != 0;
+}
--- gcc/testsuite/gcc.dg/pr33645-2.c.jj	2007-10-11 13:52:00.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr33645-2.c	2007-10-11 13:53:23.000000000 +0200
@@ -0,0 +1,20 @@
+/* PR tree-optimization/33645 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -funit-at-a-time" } */
+
+__attribute__((noinline)) int
+bar (int *x)
+{
+  return *x++;
+}
+
+int
+main ()
+{
+  static int var1_s;
+  static int *var1_t = &var1_s;
+
+  return bar (var1_t) != 0;
+}
+
+/* { dg-final { scan-assembler-not "var1_t" } } */
--- gcc/testsuite/gcc.dg/pr33645-3.c.jj	2007-10-11 13:52:00.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr33645-3.c	2007-10-11 13:53:47.000000000 +0200
@@ -0,0 +1,20 @@
+/* PR tree-optimization/33645 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-unit-at-a-time" } */
+
+__attribute__((noinline)) int
+bar (int *x)
+{
+  return *x++;
+}
+
+int
+main ()
+{
+  static int var1_s;
+  static int *const var1_t = &var1_s;
+
+  return bar (var1_t) != 0;
+}
+
+/* { dg-final { scan-assembler-not "var1_t" } } */

	Jakub


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