PR tree-optimization/45605

Jan Hubicka hubicka@ucw.cz
Mon Sep 20 14:39:00 GMT 2010


Hi,
I've tested the other part of previous patch and comitted everything except
for the code introducing folding itself as they address other latent issues.

The problem with folders being called before cgraph&varpool are built is common
to issue I was addressing by my earlier string_constant patch that was refused
as too confusing.

Constant constructors are just special case of wider issue that with linker
plugin or WHOPR we do have more knowledge about what is locally bound than
in normal compilation.

After discussion with Richard on IRC, we got to conclusion that to address the
issue we probably should store resolution decisions into varpool and cgraph nodes.
Varpool's const_value_known and cgraph+varpool used_in_object_file flags can
then be turned into predicates looking into resolutions and DECL flags. Also
binds_local_p can be strenghtened to look up resolution info and take it into
account when dealing with weak, external and comdat decls.

I have patch for this change, but since it is tricky by itself (updates
binds_local_p logic, adds logic into lto-symtab to bookkeep what values come
from linker and what was decided in GCC, etc.) I decided to break those
changes.  This is patch that goes half way by introducing const_value_known_p
predicate while keeping current way of passing const_value_known flag from WPA
to LTRANS.

I updated the predicate to work on CONST_DECL, automatic vars, other decls and
vars w/o varpool entries allocated (yet), so it can be used more conveniently.
Now when one has non function/method DECL, it is possible use this predicate to
test whether it makes sense to look at DECL_INITIAL to get the constructor.
One no longer needs to special case constant pool, CONST_DECL, and check that
variable is static before attempting to do so.

This finally lets us to do the statement folding during gimplification without
ICEs.

Bootstrapped/regtested x86_64-linux, OK?

Honza

	* cgraph.h (const_value_known_p): Declare.
	(varpool_decide_const_value_known): Remove.
	* tree-ssa-ccp.c (get_base_constructor): Use it.
	* lto-cgraph.c (compute_ltrans_boundary): Likewise.
	* expr.c (string_constant): Likewise.
	* tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise.
	* ipa.c (ipa_discover_readonly_nonaddressable_var,
	function_and_variable_visibility): Likewise.
	* gimplify.c (gimplify_call_expr): Likewise.
	* gimple-fold.c (get_symbol_constant_value): Likewise.
	* varpool.c (varpool_decide_const_value_known): Replace by...
	(const_value_known_p): ... this one; handle other kinds of DECLs
	too and work for automatic vars.
	(varpool_finalize_decl): Use const_value_known_p.

	* lto.c (lto_promote_cross_file_statics): Use const_value_known_p.

	* g++.dg/tree-ssa/pr45605.C: New testcase.
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 164400)
+++ cgraph.h	(working copy)
@@ -728,7 +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);
+bool const_value_known_p (tree);
 
 /* Walk all reachable static variables.  */
 #define FOR_EACH_STATIC_VARIABLE(node) \
Index: testsuite/g++.dg/tree-ssa/pr45605.C
===================================================================
--- testsuite/g++.dg/tree-ssa/pr45605.C	(revision 0)
+++ testsuite/g++.dg/tree-ssa/pr45605.C	(revision 0)
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-ssa" } */
+extern "C" void abort(); 
+bool destructor_called = false; 
+
+struct B { 
+    virtual void Run(){}; 
+}; 
+
+struct D : public B { 
+    virtual void Run() 
+      { 
+        struct O { 
+            ~O() { destructor_called = true; }; 
+        } o; 
+
+        struct Raiser { 
+            Raiser()  throw( int ) {throw 1;}; 
+        } raiser; 
+      }; 
+}; 
+
+int main() { 
+    try { 
+      D d; 
+      static_cast<B&>(d).Run(); 
+    } catch (...) {} 
+
+    if (!destructor_called) 
+      abort (); 
+} 
+
+
+
+/* We should devirtualize call to D::Run */
+/* { dg-final { scan-tree-dump-times "D::Run (" 1 "ssa"} } */
+/* { dg-final { cleanup-tree-dump "ssa" } } */
Index: tree-ssa-ccp.c
===================================================================
--- tree-ssa-ccp.c	(revision 164400)
+++ tree-ssa-ccp.c	(working copy)
@@ -1342,9 +1342,7 @@ get_base_constructor (tree base, tree *o
   switch (TREE_CODE (base))
     {
     case VAR_DECL:
-      if (!TREE_READONLY (base)
-	  || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
-	      && !varpool_get_node (base)->const_value_known))
+      if (!const_value_known_p (base))
 	return NULL_TREE;
 
       /* Fallthru.  */
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 164400)
+++ lto-cgraph.c	(working copy)
@@ -813,8 +813,7 @@ compute_ltrans_boundary (struct lto_out_
       if (DECL_INITIAL (vnode->decl)
 	  && !lto_varpool_encoder_encode_initializer_p (varpool_encoder,
 						        vnode)
-	  && (DECL_IN_CONSTANT_POOL (vnode->decl)
-	      || vnode->const_value_known))
+	  && const_value_known_p (vnode->decl))
 	{
 	  lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
 	  add_references (encoder, varpool_encoder, &vnode->ref_list);
Index: expr.c
===================================================================
--- expr.c	(revision 164400)
+++ expr.c	(working copy)
@@ -9851,16 +9851,10 @@ string_constant (tree arg, tree *ptr_off
       int length;
 
       /* Variables initialized to string literals can be handled too.  */
-      if (DECL_INITIAL (array) == NULL_TREE
+      if (!const_value_known_p (array)
 	  || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
 	return 0;
 
-      /* If they are read-only, non-volatile and bind locally.  */
-      if (! TREE_READONLY (array)
-	  || TREE_SIDE_EFFECTS (array)
-	  || ! targetm.binds_local_p (array))
-	return 0;
-
       /* Avoid const char foo[4] = "abcde";  */
       if (DECL_SIZE_UNIT (array) == NULL_TREE
 	  || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
Index: tree-ssa-loop-ivcanon.c
===================================================================
--- tree-ssa-loop-ivcanon.c	(revision 164400)
+++ tree-ssa-loop-ivcanon.c	(working copy)
@@ -162,10 +162,8 @@ constant_after_peeling (tree op, gimple 
       /* First make fast look if we see constant array inside.  */
       while (handled_component_p (base))
 	base = TREE_OPERAND (base, 0);
-      if ((DECL_P (base)
-      	   && TREE_STATIC (base)
-	   && TREE_READONLY (base)
-	   && varpool_get_node (base)->const_value_known)
+      if ((DECL_P (base) == VAR_DECL
+	   && const_value_known_p (base))
 	  || CONSTANT_CLASS_P (base))
 	{
 	  /* If so, see if we understand all the indices.  */
Index: ipa.c
===================================================================
--- ipa.c	(revision 164400)
+++ ipa.c	(working copy)
@@ -565,7 +565,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);
+	    vnode->const_value_known |= const_value_known_p (vnode->decl);
 	  }
       }
   if (dump_file)
@@ -774,7 +774,7 @@ function_and_variable_visibility (bool w
 	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);
+     vnode->const_value_known |= const_value_known_p (vnode->decl);
     }
   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
     {
@@ -809,7 +809,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);
+     vnode->const_value_known |= const_value_known_p (vnode->decl);
      gcc_assert (TREE_STATIC (vnode->decl));
     }
   pointer_set_destroy (aliased_nodes);
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 164400)
+++ gimplify.c	(working copy)
@@ -2479,8 +2479,11 @@ gimplify_call_expr (tree *expr_p, gimple
     {
       /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
 	 have to do is replicate it as a GIMPLE_CALL tuple.  */
+      gimple_stmt_iterator gsi;
       call = gimple_build_call_from_tree (*expr_p);
       gimplify_seq_add_stmt (pre_p, call);
+      gsi = gsi_last (*pre_p);
+      fold_stmt (&gsi);
       *expr_p = NULL_TREE;
     }
 
Index: gimple-fold.c
===================================================================
--- gimple-fold.c	(revision 164402)
+++ gimple-fold.c	(working copy)
@@ -122,9 +122,7 @@ canonicalize_constructor_val (tree cval)
 tree
 get_symbol_constant_value (tree sym)
 {
-  if ((TREE_STATIC (sym) || DECL_EXTERNAL (sym))
-      && (TREE_CODE (sym) == CONST_DECL
-	  || varpool_get_node (sym)->const_value_known))
+  if (const_value_known_p (sym))
     {
       tree val = DECL_INITIAL (sym);
       if (val)
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 164400)
+++ lto/lto.c	(working copy)
@@ -1008,7 +1008,7 @@ lto_promote_cross_file_statics (void)
 	 from this partition that are not in this partition.
 	 This needs to be done recursively.  */
       for (vnode = varpool_nodes; vnode; vnode = vnode->next)
-	if ((vnode->const_value_known || DECL_IN_CONSTANT_POOL (vnode->decl))
+	if (const_value_known_p (vnode->decl)
 	    && DECL_INITIAL (vnode->decl)
 	    && !varpool_node_in_set_p (vnode, vset)
 	    && referenced_from_this_partition_p (&vnode->ref_list, set, vset)
Index: varpool.c
===================================================================
--- varpool.c	(revision 164400)
+++ varpool.c	(working copy)
@@ -359,21 +359,42 @@ 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.  */
+/* Return if DECL is constant and its initial value is known (so we can do
+   constant folding using DECL_INITIAL (decl)).  */
 
 bool
-varpool_decide_const_value_known (struct varpool_node *node)
+const_value_known_p (tree decl)
 {
-  tree decl = node->decl;
+  struct varpool_node *vnode;
+
+  if (TREE_CODE (decl) == PARM_DECL
+      || TREE_CODE (decl) == RESULT_DECL)
+    return false;
+
+  if (TREE_CODE (decl) == CONST_DECL
+      || DECL_IN_CONSTANT_POOL (decl))
+    return true;
 
-  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
   if (!TREE_READONLY (decl))
     return false;
+
+  /* Gimplifier takes away constructors of local vars  */
+  if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+    return DECL_INITIAL (decl) != NULL;
+
+  gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
+
+  /* In WHOPR mode we can put variable into one partition
+     and make it external in the other partition.  In this
+     case we still know the value, but it can't be determined
+     from DECL flags.  For this reason we keep const_value_known
+     flag in varpool nodes.  */
+  if ((vnode = varpool_get_node (decl))
+      && vnode->const_value_known)
+    return true;
+
   /* Variables declared 'const' without an initializer
      have zero as the initializer if they may not be
      overridden at link or run time.  */
@@ -423,7 +444,7 @@ varpool_finalize_decl (tree decl)
      there.  */
   else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
     varpool_mark_needed_node (node);
-  node->const_value_known |= varpool_decide_const_value_known (node);
+  node->const_value_known |= const_value_known_p (node->decl);
   if (cgraph_global_info_ready)
     varpool_assemble_pending_decls ();
 }



More information about the Gcc-patches mailing list