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]

[C++ PATCH] Inline even functions containing static variables (take 2)


Hi!

Here is a second attempt against today's trunk. I tried to incorporate
feedback into it. The main differences against Friday's patch:
Discriminator for VAR_DECLs is now stored in lang_decl_flag's (instead of
DECL_ACCESS) and only for discriminator 1 and above (ie. in most sources it
should take no memory past pop_cp_function_context, until then only one tree
for each identifier of static local variable is stored in a varray).
expand_static_init call has been moved from grok_reference_init to
cp_finish_decl (ie. after maybe_commonize_var).
And push_local_name is now called for all local static variables, because
Mark's changes from yesterday mangle everything.
Bootstrapped on i386-redhat-linux, no regressions.

2001-03-20  Jakub Jelinek  <jakub@redhat.com>

	* decl.c (local_names): Define.
	(push_local_name): New.
	(duplicate_decls): Copy DECL_DISCRIMINATOR for VAR_DECLs, otherwise
	DECL_ACCESS.
	(grok_reference_init): Return non-zero if successful.
	Move expand_static_init call to cp_finish_decl.
	(layout_var_decl): Call push_local_name.
	(maybe_commonize_var): Allow inlining functions even if they have
	static local variables, use comdat_linkage for them if flag_weak.
	(check_initializer): Clear DECL_INITIAL if grok_reference_init was
	not successful on static variable.
	(cp_finish_decl): Call expand_static_init for static variable of
	reference type not initialized by constant.
	(save_function_data): Clear x_local_names.
	(pop_cp_function_context): Free x_local_names.
	(mark_inlined_fns): Remove.
	(mark_lang_function): Mark x_local_names.
	(lang_mark_tree): Don't mark DECL_ACCESS for VAR_DECL.
	Mark inlined_fns as tree, remove call to mark_inlined_fns.
	* class.c (alter_access): Ensure DECL_ACCESS is never set for
	VAR_DECL.
	* cp-tree.h (cp_language_function): Add x_local_names.
	(lang_decl_flags): Add discriminator into u2.
	(lang_decl_inlined_fns): Remove.
	(lang_decl): inlined_fns is now a TREE_VEC.
	(DECL_DISCRIMINATOR): Define.
	* optimize.c (inlinable_function_p): DECL_INLINED_FNS is now a
	TREE_VEC, not a custom structure.
	(optimize_function): Likewise.
	* mangle.c (discriminator_for_local_entity): Discriminate among
	VAR_DECL local entities.
	* search.c (dfs_access_in_type): VAR_DECLs don't have DECL_ACCESS.

	* g++.old-deja/g++.other/mangle3.C: New test.

--- gcc/cp/decl.c.jj	Tue Mar 20 13:45:02 2001
+++ gcc/cp/decl.c	Tue Mar 20 15:47:37 2001
@@ -75,8 +75,9 @@ static tree store_bindings PARAMS ((tree
 static tree lookup_tag_reverse PARAMS ((tree, tree));
 static tree obscure_complex_init PARAMS ((tree, tree));
 static tree lookup_name_real PARAMS ((tree, int, int, int));
+static void push_local_name PARAMS ((tree));
 static void warn_extern_redeclared_static PARAMS ((tree, tree));
-static void grok_reference_init PARAMS ((tree, tree, tree));
+static int grok_reference_init PARAMS ((tree, tree, tree));
 static tree grokfndecl PARAMS ((tree, tree, tree, tree, int,
 			      enum overload_flags, tree,
 			      tree, int, int, int, int, int, int, tree));
@@ -130,7 +131,6 @@ static void mark_binding_level PARAMS ((
 static void mark_named_label_lists PARAMS ((void *, void *));
 static void mark_cp_function_context PARAMS ((struct function *));
 static void mark_saved_scope PARAMS ((void *));
-static void mark_inlined_fns PARAMS ((struct lang_decl_inlined_fns *));
 static void mark_lang_function PARAMS ((struct cp_language_function *));
 static void save_function_data PARAMS ((tree));
 static void check_function_type PARAMS ((tree, tree));
@@ -248,6 +248,8 @@ struct named_label_use_list
 
 #define named_label_uses cp_function_chain->x_named_label_uses
 
+#define local_names cp_function_chain->x_local_names
+
 /* A list of objects which have constructors or destructors
    which reside in the global scope.  The decl is stored in
    the TREE_VALUE slot and the initializer is stored
@@ -2751,6 +2753,41 @@ create_implicit_typedef (name, type)
   return decl;
 }
 
+/* Remember a local name for name-mangling purposes.  */
+
+static void
+push_local_name (decl)
+     tree decl;
+{
+  size_t i, nelts;
+  tree t, name;
+
+  if (!local_names)
+    VARRAY_TREE_INIT (local_names, 8, "local_names");
+
+  name = DECL_NAME (decl);
+
+  nelts = VARRAY_ACTIVE_SIZE (local_names);
+  for (i = 0; i < nelts; i++)
+    {
+      t = VARRAY_TREE (local_names, i);
+      if (DECL_NAME (t) == name)
+	{
+	  if (!DECL_LANG_SPECIFIC (decl))
+	    retrofit_lang_decl (decl);
+	  if (DECL_LANG_SPECIFIC (t))
+	    DECL_DISCRIMINATOR (decl) = DECL_DISCRIMINATOR (t) + 1;
+	  else
+	    DECL_DISCRIMINATOR (decl) = 1;
+
+	  VARRAY_TREE (local_names, i) = decl;
+	  return;
+	}
+    }
+
+  VARRAY_PUSH_TREE (local_names, decl);
+}
+
 /* Push a tag name NAME for struct/class/union/enum type TYPE.
    Normally put it into the inner-most non-tag-transparent scope,
    but if GLOBALIZE is true, put it in the inner-most non-class scope.
@@ -3575,7 +3612,10 @@ duplicate_decls (newdecl, olddecl)
       /* Don't really know how much of the language-specific
 	 values we should copy from old to new.  */
       DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
-      DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
+      if (TREE_CODE (newdecl) == VAR_DECL)
+	DECL_DISCRIMINATOR (newdecl) = DECL_DISCRIMINATOR (olddecl);
+      else
+	DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
       DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
       DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
       DECL_INITIALIZED_IN_CLASS_P (newdecl)
@@ -7267,7 +7307,7 @@ start_decl_1 (decl)
 
    Quotes on semantics can be found in ARM 8.4.3.  */
 
-static void
+static int
 grok_reference_init (decl, type, init)
      tree decl, type, init;
 {
@@ -7279,16 +7319,16 @@ grok_reference_init (decl, type, init)
 	   || DECL_IN_AGGR_P (decl) == 0)
 	  && ! DECL_THIS_EXTERN (decl))
 	cp_error ("`%D' declared as reference but not initialized", decl);
-      return;
+      return 0;
     }
 
   if (init == error_mark_node)
-    return;
+    return 0;
 
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
       cp_error ("ISO C++ forbids use of initializer list to initialize reference `%D'", decl);
-      return;
+      return 0;
     }
 
   if (TREE_CODE (init) == TREE_LIST)
@@ -7317,7 +7357,7 @@ grok_reference_init (decl, type, init)
      decl);
 
   if (tmp == error_mark_node)
-    return;
+    return 0;
   else if (tmp != NULL_TREE)
     {
       init = tmp;
@@ -7334,15 +7374,10 @@ grok_reference_init (decl, type, init)
   else
     {
       cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init));
-      return;
+      return 0;
     }
 
-  if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
-    {
-      expand_static_init (decl, DECL_INITIAL (decl));
-      DECL_INITIAL (decl) = NULL_TREE;
-    }
-  return;
+  return 1;
 }
 
 /* Fill in DECL_INITIAL with some magical value to prevent expand_decl from
@@ -7468,6 +7503,12 @@ layout_var_decl (decl)
       else
 	cp_error ("storage size of `%D' isn't constant", decl);
     }
+
+  if (TREE_STATIC (decl)
+      && !DECL_ARTIFICIAL (decl)
+      && current_function_decl
+      && DECL_CONTEXT (decl) == current_function_decl)
+    push_local_name (decl);
 }
 
 /* If a local static variable is declared in an inline function, or if
@@ -7489,12 +7530,6 @@ maybe_commonize_var (decl)
 	  || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
       && TREE_PUBLIC (current_function_decl))
     {
-      /* Rather than try to get this right with inlining, we suppress
-	 inlining of such functions.  */
-      current_function_cannot_inline
-	= "function with static variable cannot be inline";
-      DECL_UNINLINABLE (current_function_decl) = 1;
-
       /* If flag_weak, we don't need to mess with this, as we can just
 	 make the function weak, and let it refer to its unique local
 	 copy.  This works because we don't allow the function to be
@@ -7521,6 +7556,8 @@ maybe_commonize_var (decl)
 	      cp_warning_at ("  you can work around this by removing the initializer", decl);
 	    }
 	}
+      else
+	comdat_linkage (decl);
     }
   else if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
     /* Set it up again; we might have set DECL_INITIAL since the last
@@ -7607,7 +7644,10 @@ check_initializer (decl, init)
     }
   else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
     {
-      grok_reference_init (decl, type, init);
+      if (!grok_reference_init (decl, type, init)
+	  && TREE_STATIC (decl) && DECL_INITIAL (decl)
+	  && ! TREE_CONSTANT (DECL_INITIAL (decl)))
+	DECL_INITIAL (decl) = NULL_TREE;
       init = NULL_TREE;
     }
   else if (init)
@@ -8047,6 +8087,14 @@ cp_finish_decl (decl, init, asmspec_tree
       else
 	abstract_virtuals_error (decl, strip_array_types (type));
 
+      if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE
+	  && TREE_STATIC (decl) && DECL_INITIAL (decl)
+	  && !TREE_CONSTANT (DECL_INITIAL (decl)))
+	{
+	  expand_static_init (decl, DECL_INITIAL (decl));
+	  DECL_INITIAL (decl) = NULL_TREE;
+	}
+
       if (TREE_CODE (decl) == FUNCTION_DECL)
 	;
       else if (DECL_EXTERNAL (decl)
@@ -13670,6 +13718,7 @@ save_function_data (decl)
   f->base.x_stmt_tree.x_last_expr_type = NULL_TREE;
   f->x_named_label_uses = NULL;
   f->bindings = NULL;
+  f->x_local_names = NULL;
 
   /* When we get back here again, we will be expanding.  */
   f->x_expanding_p = 1;
@@ -14288,23 +14337,16 @@ pop_cp_function_context (f)
      struct function *f;
 {
   if (f->language)
-    free (f->language);
+    {
+      struct cp_language_function *cp =
+	(struct cp_language_function *) f->language;
+      if (cp->x_local_names)
+	VARRAY_FREE (cp->x_local_names);
+      free (f->language);
+    }
   f->language = 0;
 }
 
-/* Mark I for GC.  */
-
-static void
-mark_inlined_fns (i)
-     struct lang_decl_inlined_fns *i;
-{
-  int n;
-
-  for (n = i->num_fns - 1; n >= 0; n--)
-    ggc_mark_tree (i->fns [n]);
-  ggc_set_mark (i);
-}
-
 /* Mark P for GC.  */
 
 static void
@@ -14321,6 +14363,7 @@ mark_lang_function (p)
   ggc_mark_tree (p->x_current_class_ptr);
   ggc_mark_tree (p->x_current_class_ref);
   ggc_mark_tree (p->x_eh_spec_try_block);
+  ggc_mark_tree_varray (p->x_local_names);
 
   mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
   mark_binding_level (&p->bindings);
@@ -14378,7 +14421,8 @@ lang_mark_tree (t)
 	  c_mark_lang_decl (&ld->decl_flags.base);
 	  if (!DECL_GLOBAL_CTOR_P (t)
 	      && !DECL_GLOBAL_DTOR_P (t)
-	      && !DECL_THUNK_P (t))
+	      && !DECL_THUNK_P (t)
+	      && TREE_CODE (t) != VAR_DECL)
 	    ggc_mark_tree (ld->decl_flags.u2.access);
 	  else if (DECL_THUNK_P (t))
 	    ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
@@ -14391,8 +14435,7 @@ lang_mark_tree (t)
 	      ggc_mark_tree (ld->befriending_classes);
 	      ggc_mark_tree (ld->context);
 	      ggc_mark_tree (ld->cloned_function);
-	      if (ld->inlined_fns)
-		mark_inlined_fns (ld->inlined_fns);
+	      ggc_mark_tree (ld->inlined_fns);
 	      if (TREE_CODE (t) == TYPE_DECL)
 		ggc_mark_tree (ld->u.sorted_fields);
 	      else if (TREE_CODE (t) == FUNCTION_DECL
--- gcc/cp/class.c.jj	Tue Mar 20 13:44:55 2001
+++ gcc/cp/class.c	Tue Mar 20 13:56:42 2001
@@ -1455,6 +1455,9 @@ alter_access (t, fdecl, access)
 {
   tree elem;
 
+  if (TREE_CODE (fdecl) == VAR_DECL)
+    abort ();
+
   if (!DECL_LANG_SPECIFIC (fdecl))
     retrofit_lang_decl (fdecl);
 
--- gcc/cp/cp-tree.h.jj	Tue Mar 20 13:44:56 2001
+++ gcc/cp/cp-tree.h	Tue Mar 20 13:51:41 2001
@@ -889,6 +889,7 @@ struct cp_language_function
   struct named_label_use_list *x_named_label_uses;
   struct named_label_list *x_named_labels;
   struct binding_level *bindings;
+  varray_type x_local_names;
 
   const char *cannot_inline;
 };
@@ -1843,6 +1844,9 @@ struct lang_decl_flags
     /* This is DECL_ACCESS.  */
     tree access;
 
+    /* For VAR_DECL, this is DECL_DISCRIMINATOR.  */
+    int discriminator;
+
     /* In a namespace-scope FUNCTION_DECL, this is
        GLOBAL_INIT_PRIORITY.  */
     int init_priority;
@@ -1855,12 +1859,6 @@ struct lang_decl_flags
 
 struct unparsed_text;
 
-struct lang_decl_inlined_fns
-{
-  size_t num_fns;
-  tree fns[1];
-};
-
 struct lang_decl
 {
   struct lang_decl_flags decl_flags;
@@ -1874,8 +1872,9 @@ struct lang_decl
   /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */
   tree cloned_function;
 
-  /* In a FUNCTION_DECL, this is a list of trees inlined into its body.  */
-  struct lang_decl_inlined_fns *inlined_fns;
+  /* In a FUNCTION_DECL, these are function data which is to be kept
+     as long as FUNCTION_DECL is kept.  */
+  tree inlined_fns;
 
   union
   {
@@ -1991,6 +1990,10 @@ struct lang_decl
 /* List of FUNCION_DECLs inlined into this function's body.  */
 #define DECL_INLINED_FNS(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->inlined_fns)
+
+/* Discriminator for name mangling.  */
+#define DECL_DISCRIMINATOR(NODE) \
+  (DECL_LANG_SPECIFIC (NODE)->decl_flags.u2.discriminator)
 
 /* Non-zero if the VTT parm has been added to NODE.  */
 #define DECL_HAS_VTT_PARM_P(NODE) \
--- gcc/cp/optimize.c.jj	Tue Mar 20 13:45:15 2001
+++ gcc/cp/optimize.c	Tue Mar 20 13:51:41 2001
@@ -620,10 +620,11 @@ inlinable_function_p (fn, id)
 
       if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
 	{
-	  struct lang_decl_inlined_fns *ifn = DECL_INLINED_FNS (fn);
+	  int j;
+	  tree inlined_fns = DECL_INLINED_FNS (fn);
 
-	  for (i = 0; i < ifn->num_fns; ++i)
-	    if (ifn->fns [i] == VARRAY_TREE (id->fns, 0))
+	  for (j = 0; j < TREE_VEC_LENGTH (inlined_fns); ++j)
+	    if (TREE_VEC_ELT (inlined_fns, j) == VARRAY_TREE (id->fns, 0))
 	      return 0;
 	}
     }
@@ -912,14 +913,10 @@ optimize_function (fn)
       VARRAY_FREE (id.target_exprs);
       if (DECL_LANG_SPECIFIC (fn))
 	{
-	  struct lang_decl_inlined_fns *ifn;
+	  tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
 
-	  ifn = ggc_alloc (sizeof (struct lang_decl_inlined_fns)
-			   + (VARRAY_ACTIVE_SIZE (id.inlined_fns) - 1)
-			     * sizeof (tree));
-	  ifn->num_fns = VARRAY_ACTIVE_SIZE (id.inlined_fns);
-	  memcpy (&ifn->fns[0], &VARRAY_TREE (id.inlined_fns, 0),
-		  ifn->num_fns * sizeof (tree));
+	  memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+		  VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
 	  DECL_INLINED_FNS (fn) = ifn;
 	}
       VARRAY_FREE (id.inlined_fns);
--- gcc/cp/mangle.c.jj	Tue Mar 20 13:45:05 2001
+++ gcc/cp/mangle.c	Tue Mar 20 13:51:41 2001
@@ -1154,16 +1154,17 @@ discriminator_for_local_entity (entity)
   /* Assume this is the only local entity with this name.  */
   discriminator = 0;
 
-  /* For now, we don't discriminate amongst local variables.  */
-  if (TREE_CODE (entity) != TYPE_DECL)
-    return 0;
-
-  /* Scan the list of local classes.  */
-  entity = TREE_TYPE (entity);
-  for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
-    if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
-	&& TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
-      ++discriminator;
+  if (TREE_CODE (entity) == VAR_DECL && DECL_LANG_SPECIFIC (entity))
+    discriminator = DECL_DISCRIMINATOR (entity);
+  else if (TREE_CODE (entity) == TYPE_DECL)
+    {
+      /* Scan the list of local classes.  */
+      entity = TREE_TYPE (entity);
+      for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
+        if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
+            && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
+	  ++discriminator;
+    }  
 
   return discriminator;
 }
--- gcc/cp/search.c.jj	Tue Mar 20 13:45:15 2001
+++ gcc/cp/search.c	Tue Mar 20 13:59:26 2001
@@ -842,7 +842,7 @@ dfs_access_in_type (binfo, data)
 	 access to the DECL.  The CONST_DECL for an enumeration
 	 constant will not have DECL_LANG_SPECIFIC, and thus no
 	 DECL_ACCESS.  */
-      if (DECL_LANG_SPECIFIC (decl))
+      if (DECL_LANG_SPECIFIC (decl) && TREE_CODE (decl) != VAR_DECL)
 	{
 	  tree decl_access = purpose_member (type, DECL_ACCESS (decl));
 	  if (decl_access)
--- gcc/testsuite/g++.old-deja/g++.other/mangle3.C.jj	Thu Mar 15 18:20:51 2001
+++ gcc/testsuite/g++.old-deja/g++.other/mangle3.C	Thu Mar 15 18:19:19 2001
@@ -0,0 +1,41 @@
+struct foo {
+  static int bar ()
+  {
+    int i;
+    static int baz = 1;
+    {
+      static int baz = 2;
+      i = baz++;
+    }
+    {
+      struct baz {
+        static int m ()
+        {
+          static int n;
+          return n += 10;
+        }
+      };
+      baz a;
+      i += a.m ();
+    }
+    {
+      static int baz = 3;
+      i += baz;
+      baz += 30;
+    }
+    i += baz;
+    baz += 60;
+    return i;
+  }
+};
+
+int main ()
+{
+  foo x;
+
+  if (x.bar () != 16)
+    return 1;
+  if (x.bar() != 117)
+    return 1;
+  return 0;
+}

	Jakub


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