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]

[RFC/RFA] Const variable initializer folding


Hi.
at various places we need to fold const static variable via knowledge of its
initializer.  The precise conditions when we do so hoever vary. For example

const int a=5;
const int b[2]={0,1};
main()
{
  return a+b[0];
}

compiled with -O2 -fpic gets a folded to 5, but b[0] is not folded to 0.

In order to fix darwin WHOPR partitioning I need variables with extern linkage
but known initializer.  Even this is supported for scalars, but not for arrays,
see i.e. g++.dg/opt/static3.C but not for arrays or structures.

I am quite convinced that with WHOPR partitioning, we can't derive the fact
from current DECL flags. 

static const int a;

Allows folding referenced of A to 0. However with partitioning it might become:
__attribute__ ((visibility ("hidden"))) extern const int a;
... and we would lose knowledge that A is 0.

For this reason patch adds const_value_known into varpool structure and makes
existing folders to use it.  Note that there is other place folding initialiers
in expand.c I would like to remove (tree optimizers can do the same) but that
would need some extra work.

There is one failure with the patch, gfortran.dg/cray_pointers_5.f90.  It is
because fortran adds into varpool variable that is !TREE_STATIC &&
!DECL_EXTERNAL that seems like a bug to me, but I am not familiar enough with
this area of FE to know what it is supposed to do.

Does this seem to make sense?  Patch was bootstrapped/regtested x86_64-linux and
darwin.

Honza

	* cgraph.h (struct varpool_node): Add const_value_known.
	(varpool_decide_const_value_known): Declare.
	* tree-ssa-ccp.c (fold_const_aggregate_ref): Update initializer folding.
	* lto-cgraph.c (lto_output_varpool_node): Store const_value_known.
	(input_varpool_node): Restore const_value_known.
	* tree-ssa-loop-ivcanon (constant_after_peeling): Check varpool for
	initializer folding.
	* ipa.c (ipa_discover_readonly_nonaddressable_var,
	function_and_variable_visibility): Compute const_value_known.
	* gimple-fold.c (get_symbol_constant_value): Use varpool for initializer
	folding.
	* varpool.c (varpool_decide_const_value_known): New function.
Index: gcc/cgraph.h
===================================================================
--- gcc/cgraph.h	(revision 163636)
+++ gcc/cgraph.h	(working copy)
@@ -503,6 +503,8 @@ struct GTY((chain_next ("%h.next"), chai
      During WPA output it is used to mark nodes that are present in
      multiple partitions.  */
   unsigned in_other_partition : 1;
+  /* True when variable is constant and its value is known.  */
+  unsigned int const_value_known : 1;
 };
 
 /* Every top level asm statement is put into a cgraph_asm_node.  */
@@ -726,6 +728,7 @@ void varpool_empty_needed_queue (void);
 bool varpool_extra_name_alias (tree, tree);
 const char * varpool_node_name (struct varpool_node *node);
 void varpool_reset_queue (void);
+bool varpool_decide_const_value_known (struct varpool_node *node);
 
 /* Walk all reachable static variables.  */
 #define FOR_EACH_STATIC_VARIABLE(node) \
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c	(revision 163636)
+++ gcc/tree-ssa-ccp.c	(working copy)
@@ -1348,7 +1348,8 @@ fold_const_aggregate_ref (tree t)
 	case VAR_DECL:
 	  if (!TREE_READONLY (base)
 	      || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
-	      || !targetm.binds_local_p (base))
+	      || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
+		  && !varpool_get_node (base)->const_value_known))
 	    return NULL_TREE;
 
 	  ctor = DECL_INITIAL (base);
@@ -1435,7 +1436,8 @@ fold_const_aggregate_ref (tree t)
 	case VAR_DECL:
 	  if (!TREE_READONLY (base)
 	      || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
-	      || !targetm.binds_local_p (base))
+	      || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
+		  && !varpool_get_node (base)->const_value_known))
 	    return NULL_TREE;
 
 	  ctor = DECL_INITIAL (base);
@@ -1509,7 +1511,8 @@ fold_const_aggregate_ref (tree t)
 
 	  if (!TREE_READONLY (base)
 	      || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
-	      || !targetm.binds_local_p (base))
+	      || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
+		  && !varpool_get_node (base)->const_value_known))
 	    return NULL_TREE;
 
 	  ctor = DECL_INITIAL (base);
Index: gcc/lto-cgraph.c
===================================================================
--- gcc/lto-cgraph.c	(revision 163636)
+++ gcc/lto-cgraph.c	(working copy)
@@ -575,6 +575,7 @@ lto_output_varpool_node (struct lto_simp
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->finalized, 1);
   bp_pack_value (&bp, node->alias, 1);
+  bp_pack_value (&bp, node->const_value_known, 1);
   gcc_assert (!node->alias || !node->extra_name);
   gcc_assert (node->finalized || !node->analyzed);
   gcc_assert (node->needed);
@@ -1106,9 +1112,10 @@ input_varpool_node (struct lto_file_decl
   node->force_output = bp_unpack_value (&bp, 1);
   node->finalized = bp_unpack_value (&bp, 1);
   node->alias = bp_unpack_value (&bp, 1);
+  node->const_value_known = bp_unpack_value (&bp, 1);
   node->analyzed = node->finalized; 
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
   aliases_p = bp_unpack_value (&bp, 1);
   if (node->finalized)
     varpool_mark_needed_node (node);
Index: gcc/tree-ssa-loop-ivcanon.c
===================================================================
--- gcc/tree-ssa-loop-ivcanon.c	(revision 163636)
+++ gcc/tree-ssa-loop-ivcanon.c	(working copy)
@@ -165,9 +165,7 @@ constant_after_peeling (tree op, gimple 
       if ((DECL_P (base)
       	   && TREE_STATIC (base)
 	   && TREE_READONLY (base)
-           && (DECL_INITIAL (base)
-	       || (!DECL_EXTERNAL (base)
-		   && targetm.binds_local_p (base))))
+	   && varpool_get_node (base)->const_value_known)
 	  || CONSTANT_CLASS_P (base))
 	{
 	  /* If so, see if we understand all the indices.  */
Index: gcc/ipa.c
===================================================================
--- gcc/ipa.c	(revision 163636)
+++ gcc/ipa.c	(working copy)
@@ -561,6 +561,7 @@ ipa_discover_readonly_nonaddressable_var
 	    if (dump_file)
 	      fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode));
 	    TREE_READONLY (vnode->decl) = 1;
+	    vnode->const_value_known |= varpool_decide_const_value_known (vnode);
 	  }
       }
   if (dump_file)
@@ -767,6 +768,9 @@ function_and_variable_visibility (bool w
 	      || ! (ADDR_SPACE_GENERIC_P
 		    (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
 	DECL_COMMON (vnode->decl) = 0;
+     /* Even extern variables might have initializers known.
+	See, for example testsuite/g++.dg/opt/static3.C  */
+     vnode->const_value_known |= varpool_decide_const_value_known (vnode);
     }
   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
     {
@@ -801,6 +805,7 @@ function_and_variable_visibility (bool w
 	  gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl));
 	  cgraph_make_decl_local (vnode->decl);
 	}
+     vnode->const_value_known |= varpool_decide_const_value_known (vnode);
      gcc_assert (TREE_STATIC (vnode->decl));
     }
   pointer_set_destroy (aliased_nodes);
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 163636)
+++ gcc/gimple-fold.c	(working copy)
@@ -38,9 +38,9 @@ along with GCC; see the file COPYING3.  
 tree
 get_symbol_constant_value (tree sym)
 {
-  if (TREE_STATIC (sym)
-      && (TREE_READONLY (sym)
-	  || TREE_CODE (sym) == CONST_DECL))
+  if ((TREE_STATIC (sym) || DECL_EXTERNAL (sym))
+      && (TREE_CODE (sym) == CONST_DECL
+	  || varpool_get_node (sym)->const_value_known))
     {
       tree val = DECL_INITIAL (sym);
       if (val)
@@ -65,8 +65,6 @@ get_symbol_constant_value (tree sym)
 	 have zero as the initializer if they may not be
 	 overridden at link or run time.  */
       if (!val
-	  && !DECL_EXTERNAL (sym)
-	  && targetm.binds_local_p (sym)
           && (INTEGRAL_TYPE_P (TREE_TYPE (sym))
 	       || SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym))))
 	return fold_convert (TREE_TYPE (sym), integer_zero_node);
Index: gcc/varpool.c
===================================================================
--- gcc/varpool.c	(revision 163636)
+++ gcc/varpool.c	(working copy)
@@ -357,6 +357,37 @@ decide_is_variable_needed (struct varpoo
   return true;
 }
 
+/* Return if NODE is constant and its initial value is known (so we can do
+   constant folding).  The decision depends on whole program decisions
+   and can not be recomputed at ltrans stage for variables from other
+   partitions.  For this reason the new value should be always combined
+   with the previous knowledge.  */
+
+bool
+varpool_decide_const_value_known (struct varpool_node *node)
+{
+  tree decl = node->decl;
+
+  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
+  gcc_assert (TREE_CODE (decl) == VAR_DECL);
+  if (!TREE_READONLY (decl))
+    return false;
+  /* Variables declared 'const' without an initializer
+     have zero as the initializer if they may not be
+     overridden at link or run time.  */
+  if (!DECL_INITIAL (decl)
+      && (DECL_EXTERNAL (decl)
+	  || DECL_REPLACEABLE_P (decl)))
+    return false;
+
+  /* Variables declared `const' with an initializer are considered
+     to not be overwritable with different initializer by default. 
+
+     ??? Previously we behaved so for scalar variables but not for array
+     accesses.  */
+  return true;
+}
+
 /* Mark DECL as finalized.  By finalizing the declaration, frontend instruct the
    middle end to output the variable to asm file, if needed or externally
    visible.  */


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