public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* PATCH: Speed up G++
@ 2004-07-08  5:43 Mark Mitchell
  2004-07-08 11:00 ` Nathan Sidwell
  0 siblings, 1 reply; 7+ messages in thread
From: Mark Mitchell @ 2004-07-08  5:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: nathan


This patch improves the compile-time performance of G++ substantially
on some input test cases.  On the test case I was examining, comptypes
was at the top of the profile, with 12.7M calls; after this patch,
that figure is 1.7M -- i.e., an 80%+ reduction.  The number of calls to
ggc_alloc_stat dropped by about 8%.  That's worth about 10% of compile
time on the particular test case I was using.  I'd be interested in
hearing what kinds of effects people see on other code.

We maintain a cache of class-level bindings so that if we re-enter the
class we just left we can do so quickly.  Unfortunately, restoring the
cache was much more expensive than it should have been.

Nathan, I broke the vector abstraction barrier in push_binding, where
I calculate "need_fixup".  You will want to go back and adjust that
code after you add the additional vector API function we dicussed
today.

Tested on i866-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-07-07  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (saved_scope): Remove x_previous_class_type and
	x_previous_class_values; add x_previous_class_level.
	(previous_class_type): Remove.
	(previous_class_values): Remove.
	(previous_class_level): New macro.
	* class.c (pushclass): Restore the identifier cache more
	expeditiously.
	(invalidate_class_lookup_cache): Use vector for class_shadowed and
	previous_class_values.
	* decl.c (poplevel): Likewise.
	* name-lookup.c (cxx_binding_init): New function.
	(cxx_binding_make): Use it.
	(push_binding): For a binding in a class level, use a vector of
	cp_class_binding nodes.
	(push_binding_level): New function.
	(begin_scope): Use it.
	(leave_scope): Do not put class binding levels on the free list.
	(print_binding_level): Adjust for the fact that class_shadowed is
	a vector.
	(poplevel_class): Likewise.
	(clear_identifier_class_values): Likewise.
	(push_class_level_binding): Likewise.
	(set_class_shadows): Remove.
	(store_binding): New function.
	(store_class_bindings): New function.
	(push_to_top_level): Use store_class_bindings as appropriate.
	(pop_from_top_level): Use previous_class_level, not
	previous_class_type.
	* name-lookup.h (cp_class_binding): New type.
	(cp_binding_level): Use a vector object for class_shadowed.
	(push_binding_level): Declare.
	(set_class_shadows): Remove.

Index: class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.624
diff -c -5 -p -r1.624 class.c
*** class.c	7 Jul 2004 10:20:20 -0000	1.624
--- class.c	8 Jul 2004 04:31:10 -0000
*************** pushclass (tree type)
*** 5484,5496 ****
       structures or unions are public.  */
    current_access_specifier = (CLASSTYPE_DECLARED_CLASS (type) 
  			      ? access_private_node 
  			      : access_public_node);
  
!   if (previous_class_type != NULL_TREE
!       && (type != previous_class_type 
! 	  || !COMPLETE_TYPE_P (previous_class_type))
        && current_class_depth == 1)
      {
        /* Forcibly remove any old class remnants.  */
        invalidate_class_lookup_cache ();
      }
--- 5484,5495 ----
       structures or unions are public.  */
    current_access_specifier = (CLASSTYPE_DECLARED_CLASS (type) 
  			      ? access_private_node 
  			      : access_public_node);
  
!   if (previous_class_level
!       && type != previous_class_level->this_entity
        && current_class_depth == 1)
      {
        /* Forcibly remove any old class remnants.  */
        invalidate_class_lookup_cache ();
      }
*************** pushclass (tree type)
*** 5498,5511 ****
    /* If we're about to enter a nested class, clear
       IDENTIFIER_CLASS_VALUE for the enclosing classes.  */
    if (current_class_depth > 1)
      clear_identifier_class_values ();
  
!   pushlevel_class ();
! 
!   if (type != previous_class_type || current_class_depth > 1)
      {
        push_class_decls (type);
        if (CLASSTYPE_TEMPLATE_INFO (type) && !CLASSTYPE_USE_TEMPLATE (type))
  	{
  	  /* If we are entering the scope of a template declaration (not a
  	     specialization), we need to push all the using decls with
--- 5497,5511 ----
    /* If we're about to enter a nested class, clear
       IDENTIFIER_CLASS_VALUE for the enclosing classes.  */
    if (current_class_depth > 1)
      clear_identifier_class_values ();
  
!   if (!previous_class_level 
!       || type != previous_class_level->this_entity
!       || current_class_depth > 1)
      {
+       pushlevel_class ();
        push_class_decls (type);
        if (CLASSTYPE_TEMPLATE_INFO (type) && !CLASSTYPE_USE_TEMPLATE (type))
  	{
  	  /* If we are entering the scope of a template declaration (not a
  	     specialization), we need to push all the using decls with
*************** pushclass (tree type)
*** 5518,5543 ****
  	      pushdecl_class_level (fields);
  	}
      }
    else
      {
!       tree item;
  
        /* We are re-entering the same class we just left, so we don't
  	 have to search the whole inheritance matrix to find all the
  	 decls to bind again.  Instead, we install the cached
  	 class_shadowed list, and walk through it binding names and
  	 setting up IDENTIFIER_TYPE_VALUEs.  */
!       set_class_shadows (previous_class_values);
!       for (item = previous_class_values; item; item = TREE_CHAIN (item))
! 	{
! 	  tree id = TREE_PURPOSE (item);
! 	  tree decl = TREE_TYPE (item);
! 	  
! 	  push_class_binding (id, decl);
! 	  if (TREE_CODE (decl) == TYPE_DECL)
! 	    set_identifier_type_value (id, decl);
  	}
        unuse_fields (type);
      }
    
    cxx_remember_type_decls (CLASSTYPE_NESTED_UTDS (type));
--- 5518,5554 ----
  	      pushdecl_class_level (fields);
  	}
      }
    else
      {
!       cp_class_binding *cb;
!       size_t i;
  
        /* We are re-entering the same class we just left, so we don't
  	 have to search the whole inheritance matrix to find all the
  	 decls to bind again.  Instead, we install the cached
  	 class_shadowed list, and walk through it binding names and
  	 setting up IDENTIFIER_TYPE_VALUEs.  */
!       push_binding_level (previous_class_level);
!       class_binding_level = previous_class_level;
!       for (i = 0; 
! 	   (cb = VEC_iterate (cp_class_binding, 
! 			      previous_class_level->class_shadowed,
! 			      i));
! 	   ++i)
! 	{
! 	  tree id;
! 	  tree type_decl;
! 
! 	  id = cb->identifier;
! 	  cb->base.previous = IDENTIFIER_BINDING (id);
! 	  IDENTIFIER_BINDING (id) = &cb->base;
! 	  type_decl = cb->base.value;
! 	  if (!type_decl || TREE_CODE (type_decl) != TYPE_DECL)
! 	    type_decl = cb->base.type;
! 	  if (type_decl && TREE_CODE (type_decl) == TYPE_DECL)
! 	    set_identifier_type_value (id, type_decl);
  	}
        unuse_fields (type);
      }
    
    cxx_remember_type_decls (CLASSTYPE_NESTED_UTDS (type));
*************** pushclass (tree type)
*** 5549,5566 ****
     must invalidate our cache.  */
  
  void
  invalidate_class_lookup_cache (void)
  {
!   tree t;
    
    /* The IDENTIFIER_CLASS_VALUEs are no longer valid.  */
!   for (t = previous_class_values; t; t = TREE_CHAIN (t))
!     IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
  
!   previous_class_values = NULL_TREE;
!   previous_class_type = NULL_TREE;
  }
   
  /* Get out of the current class scope. If we were in a class scope
     previously, that is the one popped to.  */
  
--- 5560,5580 ----
     must invalidate our cache.  */
  
  void
  invalidate_class_lookup_cache (void)
  {
!   size_t i;
!   cp_class_binding *cb;
    
    /* The IDENTIFIER_CLASS_VALUEs are no longer valid.  */
!   for (i = 0;
!        (cb = VEC_iterate (cp_class_binding, 
! 			  previous_class_level->class_shadowed, i));
!        ++i)
!     IDENTIFIER_CLASS_VALUE (cb->identifier) = NULL_TREE;
  
!   previous_class_level = NULL;
  }
   
  /* Get out of the current class scope. If we were in a class scope
     previously, that is the one popped to.  */
  
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.997
diff -c -5 -p -r1.997 cp-tree.h
*** cp-tree.h	7 Jul 2004 10:20:24 -0000	1.997
--- cp-tree.h	8 Jul 2004 04:31:10 -0000
*************** struct saved_scope GTY(())
*** 638,649 ****
    tree access_specifier;
    tree function_decl;
    varray_type lang_base;
    tree lang_name;
    tree template_parms;
!   tree x_previous_class_type;
!   tree x_previous_class_values;
    tree x_saved_tree;
  
    HOST_WIDE_INT x_processing_template_decl;
    int x_processing_specialization;
    bool x_processing_explicit_instantiation;
--- 638,648 ----
    tree access_specifier;
    tree function_decl;
    varray_type lang_base;
    tree lang_name;
    tree template_parms;
!   struct cp_binding_level *x_previous_class_level;
    tree x_saved_tree;
  
    HOST_WIDE_INT x_processing_template_decl;
    int x_processing_specialization;
    bool x_processing_explicit_instantiation;
*************** struct saved_scope GTY(())
*** 692,711 ****
  
  #define processing_template_decl scope_chain->x_processing_template_decl
  #define processing_specialization scope_chain->x_processing_specialization
  #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
  
! /* _TYPE: the previous type that was a class */
  
! #define previous_class_type scope_chain->x_previous_class_type
! 
! /* This is a copy of the class_shadowed list of the previous class
!    binding contour when at global scope.  It's used to reset
!    IDENTIFIER_CLASS_VALUEs when entering another class scope (i.e. a
!    cache miss).  */
! 
! #define previous_class_values scope_chain->x_previous_class_values
  
  /* A list of private types mentioned, for deferred access checking.  */
  
  extern GTY(()) struct saved_scope *scope_chain;
  
--- 691,704 ----
  
  #define processing_template_decl scope_chain->x_processing_template_decl
  #define processing_specialization scope_chain->x_processing_specialization
  #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
  
! /* The cached class binding level, from the most recently exited
!    class, or NULL if none.  */
  
! #define previous_class_level scope_chain->x_previous_class_level
  
  /* A list of private types mentioned, for deferred access checking.  */
  
  extern GTY(()) struct saved_scope *scope_chain;
  
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1239
diff -c -5 -p -r1.1239 decl.c
*** decl.c	7 Jul 2004 10:20:27 -0000	1.1239
--- decl.c	8 Jul 2004 04:31:10 -0000
*************** poplevel (int keep, int reverse, int fun
*** 441,451 ****
  
    real_functionbody = (current_binding_level->kind == sk_cleanup
  		       ? ((functionbody = 0), tmp) : functionbody);
    subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
  
!   my_friendly_assert (!current_binding_level->class_shadowed,
  		      19990414);
  
    /* We used to use KEEP == 2 to indicate that the new block should go
       at the beginning of the list of blocks at this binding level,
       rather than the end.  This hack is no longer used.  */
--- 441,452 ----
  
    real_functionbody = (current_binding_level->kind == sk_cleanup
  		       ? ((functionbody = 0), tmp) : functionbody);
    subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
  
!   my_friendly_assert (VEC_length(cp_class_binding, 
! 				 current_binding_level->class_shadowed) == 0,
  		      19990414);
  
    /* We used to use KEEP == 2 to indicate that the new block should go
       at the beginning of the list of blocks at this binding level,
       rather than the end.  This hack is no longer used.  */
Index: name-lookup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.66
diff -c -5 -p -r1.66 name-lookup.c
*** name-lookup.c	7 Jul 2004 10:20:37 -0000	1.66
--- name-lookup.c	8 Jul 2004 04:31:10 -0000
*************** binding_table_foreach (binding_table tab
*** 326,335 ****
--- 326,346 ----
  
  /* A free list of "cxx_binding"s, connected by their PREVIOUS.  */
  
  static GTY((deletable)) cxx_binding *free_bindings;
  
+ /* Initialize VALUE and TYPE field for BINDING, and set the PREVIOUS
+    field to NULL.  */
+ 
+ static inline void
+ cxx_binding_init (cxx_binding *binding, tree value, tree type)
+ {
+   binding->value = value;
+   binding->type = type;
+   binding->previous = NULL;
+ }
+ 
  /* (GC)-allocate a binding object with VALUE and TYPE member initialized.  */
  
  static cxx_binding *
  cxx_binding_make (tree value, tree type)
  {
*************** cxx_binding_make (tree value, tree type)
*** 340,352 ****
        free_bindings = binding->previous;
      }
    else
      binding = ggc_alloc (sizeof (cxx_binding));
  
!   binding->value = value;
!   binding->type = type;
!   binding->previous = NULL;
  
    return binding;
  }
  
  /* Put BINDING back on the free list.  */
--- 351,361 ----
        free_bindings = binding->previous;
      }
    else
      binding = ggc_alloc (sizeof (cxx_binding));
  
!   cxx_binding_init (binding, value, type);
  
    return binding;
  }
  
  /* Put BINDING back on the free list.  */
*************** cxx_binding_free (cxx_binding *binding)
*** 363,374 ****
     level at which this declaration is being bound.  */
  
  static void
  push_binding (tree id, tree decl, cxx_scope* level)
  {
!    cxx_binding *binding = cxx_binding_make (decl, NULL);
  
    /* Now, fill in the binding information.  */
    binding->previous = IDENTIFIER_BINDING (id);
    binding->scope = level;
    INHERITED_VALUE_BINDING_P (binding) = 0;
    LOCAL_BINDING_P (binding) = (level != class_binding_level);
--- 372,406 ----
     level at which this declaration is being bound.  */
  
  static void
  push_binding (tree id, tree decl, cxx_scope* level)
  {
!   cxx_binding *binding;
  
+   if (level != class_binding_level)
+     binding = cxx_binding_make (decl, NULL_TREE);
+   else
+     {
+       cp_class_binding *cb;
+       size_t length;
+       size_t i;
+       bool need_fixup;
+ 
+       length = VEC_length (cp_class_binding, level->class_shadowed);
+       need_fixup = (length && length == level->class_shadowed->alloc);
+       cb = VEC_safe_push (cp_class_binding, level->class_shadowed, NULL);
+       cb->identifier = id;
+       binding = &cb->base;
+       cxx_binding_init (binding, decl, NULL_TREE);
+       if (need_fixup)
+ 	for (i = 0; i < length; ++i)
+ 	  {
+ 	    cb = VEC_index (cp_class_binding, level->class_shadowed, i);
+ 	    IDENTIFIER_BINDING (cb->identifier) = &cb->base;
+ 	  }
+     }
+ 			      
    /* Now, fill in the binding information.  */
    binding->previous = IDENTIFIER_BINDING (id);
    binding->scope = level;
    INHERITED_VALUE_BINDING_P (binding) = 0;
    LOCAL_BINDING_P (binding) = (level != class_binding_level);
*************** namespace_scope_ht_size (tree ns)
*** 1259,1268 ****
--- 1291,1320 ----
  
  /* A chain of binding_level structures awaiting reuse.  */
  
  static GTY((deletable)) struct cp_binding_level *free_binding_level;
  
+ /* Insert SCOPE as the innermost binding level.  */
+ 
+ void
+ push_binding_level (struct cp_binding_level *scope)
+ {
+   /* Add it to the front of currently active scopes stack.  */
+   scope->level_chain = current_binding_level;
+   current_binding_level = scope;
+   keep_next_level_flag = false;
+ 
+   if (ENABLE_SCOPE_CHECKING)
+     {
+       scope->binding_depth = binding_depth;
+       indent (binding_depth);
+       cxx_scope_debug (scope, input_line, "push");
+       is_class_level = 0;
+       binding_depth++;
+     }
+ }
+ 
  /* Create a new KIND scope and make it the top of the active scopes stack.
     ENTITY is the scope of the associated C++ entity (namespace, class,
     function); it is NULL otherwise.  */
  
  cxx_scope *
*************** begin_scope (scope_kind kind, tree entit
*** 1317,1339 ****
        my_friendly_assert (false, 20030922);
        break;
      }
    scope->kind = kind;
  
!   /* Add it to the front of currently active scopes stack.  */
!   scope->level_chain = current_binding_level;
!   current_binding_level = scope;
!   keep_next_level_flag = false;
! 
!   if (ENABLE_SCOPE_CHECKING)
!     {
!       scope->binding_depth = binding_depth;
!       indent (binding_depth);
!       cxx_scope_debug (scope, input_line, "push");
!       is_class_level = 0;
!       binding_depth++;
!     }
  
    return scope;
  }
  
  /* We're about to leave current scope.  Pop the top of the stack of
--- 1369,1379 ----
        my_friendly_assert (false, 20030922);
        break;
      }
    scope->kind = kind;
  
!   push_binding_level (scope);
  
    return scope;
  }
  
  /* We're about to leave current scope.  Pop the top of the stack of
*************** leave_scope (void)
*** 1364,1378 ****
      }
  
    /* Move one nesting level up.  */
    current_binding_level = scope->level_chain;
  
!   /* Namespace-scopes are left most probably temporarily, not completely;
!      they can be reopen later, e.g. in namespace-extension or any name
!      binding activity that requires us to resume a namespace.  For other
       scopes, we just make the structure available for reuse.  */
!   if (scope->kind != sk_namespace)
      {
        scope->level_chain = free_binding_level;
        if (scope->kind == sk_class)
          scope->type_decls = NULL;
        else
--- 1404,1420 ----
      }
  
    /* Move one nesting level up.  */
    current_binding_level = scope->level_chain;
  
!   /* Namespace-scopes are left most probably temporarily, not
!      completely; they can be reopen later, e.g. in namespace-extension
!      or any name binding activity that requires us to resume a
!      namespace.  For classes, we cache some binding levels.  For other
       scopes, we just make the structure available for reuse.  */
!   if (scope->kind != sk_namespace
!       && scope->kind != sk_class)
      {
        scope->level_chain = free_binding_level;
        if (scope->kind == sk_class)
          scope->type_decls = NULL;
        else
*************** print_binding_level (struct cp_binding_l
*** 1626,1642 ****
        i = 0;
        binding_table_foreach (lvl->type_decls, bt_print_entry, &i);
        if (i)
  	fprintf (stderr, "\n");
      }
!   if (lvl->class_shadowed)
      {
        fprintf (stderr, " class-shadowed:");
!       for (t = lvl->class_shadowed; t; t = TREE_CHAIN (t))
! 	{
! 	  fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t)));
! 	}
        fprintf (stderr, "\n");
      }
    if (lvl->type_shadowed)
      {
        fprintf (stderr, " type-shadowed:");
--- 1668,1688 ----
        i = 0;
        binding_table_foreach (lvl->type_decls, bt_print_entry, &i);
        if (i)
  	fprintf (stderr, "\n");
      }
!   if (VEC_length (cp_class_binding, lvl->class_shadowed))
      {
+       size_t i;
+       cp_class_binding *b;
        fprintf (stderr, " class-shadowed:");
!       for (i = 0; 
! 	   (b = VEC_iterate(cp_class_binding, 
! 			    lvl->class_shadowed,
! 			    i));
! 	   ++i) 
! 	fprintf (stderr, " %s ", IDENTIFIER_POINTER (b->identifier));
        fprintf (stderr, "\n");
      }
    if (lvl->type_shadowed)
      {
        fprintf (stderr, " type-shadowed:");
*************** pushlevel_class (void)
*** 2574,2583 ****
--- 2620,2631 ----
  
  void
  poplevel_class (void)
  {
    struct cp_binding_level *level = class_binding_level;
+   cp_class_binding *cb;
+   size_t i;
    tree shadowed;
  
    timevar_push (TV_NAME_LOOKUP);
    my_friendly_assert (level != 0, 354);
  
*************** poplevel_class (void)
*** 2587,2642 ****
       if we don't touch it here, we're able to use the cache effect if the
       next time we're entering a class scope, it is the same class.  */
    if (current_class_depth != 1)
      {
        struct cp_binding_level* b;
  
        /* Clear out our IDENTIFIER_CLASS_VALUEs.  */
!       for (shadowed = level->class_shadowed;
! 	   shadowed;
! 	   shadowed = TREE_CHAIN (shadowed))
! 	IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed)) = NULL_TREE;
  
        /* Find the next enclosing class, and recreate
  	 IDENTIFIER_CLASS_VALUEs appropriate for that class.  */
        b = level->level_chain;
        while (b && b->kind != sk_class)
  	b = b->level_chain;
  
        if (b)
! 	for (shadowed = b->class_shadowed;
! 	     shadowed;
! 	     shadowed = TREE_CHAIN (shadowed))
  	  {
  	    cxx_binding *binding;
              
! 	    binding = IDENTIFIER_BINDING (TREE_PURPOSE (shadowed));
  	    while (binding && binding->scope != b)
  	      binding = binding->previous;
  
  	    if (binding)
! 	      IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (shadowed))
! 		= binding->value;
  	  }
      }
    else
      /* Remember to save what IDENTIFIER's were bound in this scope so we
         can recover from cache misses.  */
!     {
!       previous_class_type = current_class_type;
!       previous_class_values = class_binding_level->class_shadowed;
!     }
    for (shadowed = level->type_shadowed;
         shadowed;
         shadowed = TREE_CHAIN (shadowed))
      SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
  
    /* Remove the bindings for all of the class-level declarations.  */
!   for (shadowed = level->class_shadowed;
!        shadowed;
!        shadowed = TREE_CHAIN (shadowed))
!     pop_binding (TREE_PURPOSE (shadowed), TREE_TYPE (shadowed));
  
    /* Now, pop out of the binding level which we created up in the
       `pushlevel_class' routine.  */
    if (ENABLE_SCOPE_CHECKING)
      is_class_level = 1;
--- 2635,2687 ----
       if we don't touch it here, we're able to use the cache effect if the
       next time we're entering a class scope, it is the same class.  */
    if (current_class_depth != 1)
      {
        struct cp_binding_level* b;
+       cp_class_binding* cb;
+       size_t i;
  
        /* Clear out our IDENTIFIER_CLASS_VALUEs.  */
!       clear_identifier_class_values ();
  
        /* Find the next enclosing class, and recreate
  	 IDENTIFIER_CLASS_VALUEs appropriate for that class.  */
        b = level->level_chain;
        while (b && b->kind != sk_class)
  	b = b->level_chain;
  
        if (b)
! 	for (i = 0;
! 	     (cb = VEC_iterate (cp_class_binding, 
! 				b->class_shadowed, 
! 				i));
! 	     ++i)
  	  {
  	    cxx_binding *binding;
              
! 	    binding = IDENTIFIER_BINDING (cb->identifier);
  	    while (binding && binding->scope != b)
  	      binding = binding->previous;
  
  	    if (binding)
! 	      IDENTIFIER_CLASS_VALUE (cb->identifier) = binding->value;
  	  }
      }
    else
      /* Remember to save what IDENTIFIER's were bound in this scope so we
         can recover from cache misses.  */
!     previous_class_level = level;
    for (shadowed = level->type_shadowed;
         shadowed;
         shadowed = TREE_CHAIN (shadowed))
      SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
  
    /* Remove the bindings for all of the class-level declarations.  */
!   for (i = 0;
!        (cb = VEC_iterate (cp_class_binding, level->class_shadowed, i));
!        ++i)
!     IDENTIFIER_BINDING (cb->identifier) = cb->base.previous;
  
    /* Now, pop out of the binding level which we created up in the
       `pushlevel_class' routine.  */
    if (ENABLE_SCOPE_CHECKING)
      is_class_level = 1;
*************** push_class_binding (tree id, tree decl)
*** 2705,2723 ****
     for any names in enclosing classes.  */
  
  void
  clear_identifier_class_values (void)
  {
!   tree t;
! 
!   if (!class_binding_level)
!     return;
  
!   for (t = class_binding_level->class_shadowed;
!        t;
!        t = TREE_CHAIN (t))
!     IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
  }
  
  /* Make the declaration of X appear in CLASS scope.  */
  
  bool
--- 2750,2769 ----
     for any names in enclosing classes.  */
  
  void
  clear_identifier_class_values (void)
  {
!   size_t i;
!   cp_class_binding *cb;
  
!   if (class_binding_level)
!     for (i = 0;
! 	 (cb = VEC_iterate (cp_class_binding, 
! 			    class_binding_level->class_shadowed, 
! 			    i));
! 	 ++i)
!       IDENTIFIER_CLASS_VALUE (cb->identifier) = NULL_TREE;
  }
  
  /* Make the declaration of X appear in CLASS scope.  */
  
  bool
*************** push_class_level_binding (tree name, tre
*** 2857,2900 ****
  	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
        else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval))
  	old_decl = bval;
        else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x))
  	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
!       
        if (old_decl)
  	{
! 	  tree shadow;
! 	  
  	  /* Find the previous binding of name on the class-shadowed
               list, and update it.  */
! 	  for (shadow = class_binding_level->class_shadowed;
! 	       shadow;
! 	       shadow = TREE_CHAIN (shadow))
! 	    if (TREE_PURPOSE (shadow) == name
! 		&& TREE_TYPE (shadow) == old_decl)
  	      {
  		binding->value = x;
  		INHERITED_VALUE_BINDING_P (binding) = 0;
- 		TREE_TYPE (shadow) = x;
  		IDENTIFIER_CLASS_VALUE (name) = x;
  		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
  	      }
  	}
      }
  
    /* If we didn't replace an existing binding, put the binding on the
       stack of bindings for the identifier, and update the shadowed list.  */
    if (push_class_binding (name, x))
!     {
!       class_binding_level->class_shadowed
! 	= tree_cons (name, NULL,
! 		     class_binding_level->class_shadowed);
!       /* Record the value we are binding NAME to so that we can know
! 	 what to pop later.  */
!       TREE_TYPE (class_binding_level->class_shadowed) = x;
!       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
!     }
  
    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, false);
  }
  
  tree
--- 2903,2941 ----
  	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
        else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval))
  	old_decl = bval;
        else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x))
  	POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
! 
        if (old_decl)
  	{
! 	  cp_class_binding *cb;
! 	  size_t i;
! 
  	  /* Find the previous binding of name on the class-shadowed
               list, and update it.  */
! 	  for (i = 0; 
! 	       (cb = VEC_iterate (cp_class_binding,
! 				  class_binding_level->class_shadowed,
! 				  i));
! 	       ++i)
! 	    if (cb->identifier == name
! 		&& (cb->base.value == old_decl
! 		    || cb->base.type == old_decl))
  	      {
  		binding->value = x;
  		INHERITED_VALUE_BINDING_P (binding) = 0;
  		IDENTIFIER_CLASS_VALUE (name) = x;
  		POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
  	      }
  	}
      }
  
    /* If we didn't replace an existing binding, put the binding on the
       stack of bindings for the identifier, and update the shadowed list.  */
    if (push_class_binding (name, x))
!     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
  
    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, false);
  }
  
  tree
*************** do_class_using_decl (tree decl)
*** 2943,2957 ****
  	cp_emit_debug_info_for_using (r, scope);
      }
    return value;
  }
  
- void
- set_class_shadows (tree shadows)
- {
-   class_binding_level->class_shadowed = shadows;
- }
  \f
  /* Return the binding value for name in scope.  */
  
  tree
  namespace_binding (tree name, tree scope)
--- 2984,2993 ----
*************** struct cxx_saved_binding GTY(())
*** 4794,4848 ****
     local-value slots of all identifiers, so that only the global values
     are at all visible.  Simply setting current_binding_level to the global
     scope isn't enough, because more binding levels may be pushed.  */
  struct saved_scope *scope_chain;
  
  static cxx_saved_binding *
  store_bindings (tree names, cxx_saved_binding *old_bindings)
  {
    tree t;
    cxx_saved_binding *search_bindings = old_bindings;
  
    timevar_push (TV_NAME_LOOKUP);
    for (t = names; t; t = TREE_CHAIN (t))
      {
        tree id;
-       cxx_saved_binding *saved;
-       cxx_saved_binding *t1;
  
        if (TREE_CODE (t) == TREE_LIST)
  	id = TREE_PURPOSE (t);
        else
  	id = DECL_NAME (t);
  
!       if (!id
! 	  /* Note that we may have an IDENTIFIER_CLASS_VALUE even when
! 	     we have no IDENTIFIER_BINDING if we have left the class
! 	     scope, but cached the class-level declarations.  */
! 	  || !(IDENTIFIER_BINDING (id) || IDENTIFIER_CLASS_VALUE (id)))
! 	continue;
! 
!       for (t1 = search_bindings; t1; t1 = t1->previous)
! 	if (t1->identifier == id)
! 	  goto skip_it;
! 
!       my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
!       saved = cxx_saved_binding_make ();
!       saved->previous = old_bindings;
!       saved->identifier = id;
!       saved->binding = IDENTIFIER_BINDING (id);
!       saved->class_value = IDENTIFIER_CLASS_VALUE (id);;
!       saved->real_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
!       IDENTIFIER_BINDING (id) = NULL;
!       IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
!       old_bindings = saved;
!     skip_it:
!       ;
      }
    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, old_bindings);
  }
  
  void
  push_to_top_level (void)
  {
    struct saved_scope *s;
    struct cp_binding_level *b;
--- 4830,4916 ----
     local-value slots of all identifiers, so that only the global values
     are at all visible.  Simply setting current_binding_level to the global
     scope isn't enough, because more binding levels may be pushed.  */
  struct saved_scope *scope_chain;
  
+ /* If ID is not already in the SEARCH_BINDINGS, prepend its binding
+    information to OLD_BINDINGS.  Returns the new OLD_BINDINGS
+    list.  */
+ 
+ static cxx_saved_binding *
+ store_binding (tree id,
+ 	       cxx_saved_binding *old_bindings,
+ 	       cxx_saved_binding *search_bindings)
+ {
+   cxx_saved_binding *saved;
+   cxx_saved_binding *t1;
+ 
+   if (!id
+       /* Note that we may have an IDENTIFIER_CLASS_VALUE even when
+ 	 we have no IDENTIFIER_BINDING if we have left the class
+ 	 scope, but cached the class-level declarations.  */
+       || !(IDENTIFIER_BINDING (id) || IDENTIFIER_CLASS_VALUE (id)))
+      return old_bindings;
+ 
+   for (t1 = search_bindings; t1; t1 = t1->previous)
+     if (t1->identifier == id)
+      return old_bindings;
+ 
+   my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
+   saved = cxx_saved_binding_make ();
+   saved->previous = old_bindings;
+   saved->identifier = id;
+   saved->binding = IDENTIFIER_BINDING (id);
+   saved->class_value = IDENTIFIER_CLASS_VALUE (id);;
+   saved->real_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
+   IDENTIFIER_BINDING (id) = NULL;
+   IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
+   return saved;
+ }
+ 
  static cxx_saved_binding *
  store_bindings (tree names, cxx_saved_binding *old_bindings)
  {
    tree t;
    cxx_saved_binding *search_bindings = old_bindings;
  
    timevar_push (TV_NAME_LOOKUP);
    for (t = names; t; t = TREE_CHAIN (t))
      {
        tree id;
  
        if (TREE_CODE (t) == TREE_LIST)
  	id = TREE_PURPOSE (t);
        else
  	id = DECL_NAME (t);
  
!       old_bindings 
! 	= store_binding (id, old_bindings, search_bindings);
      }
    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, old_bindings);
  }
  
+ /* Like store_bindings, but NAMES is a vector of cp_class_binding
+    objects, rather than a TREE_LIST.  */
+ 
+ static cxx_saved_binding *
+ store_class_bindings (VEC(cp_class_binding) *names, 
+ 		      cxx_saved_binding *old_bindings)
+ {
+   size_t i;
+   cp_class_binding *cb;
+   cxx_saved_binding *search_bindings = old_bindings;
+ 
+   timevar_push (TV_NAME_LOOKUP);
+   for (i = 0; 
+        (cb = VEC_iterate(cp_class_binding, names, i));
+        ++i)
+     old_bindings 
+       = store_binding (cb->identifier, old_bindings, search_bindings);
+   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, old_bindings);
+ }
+ 
  void
  push_to_top_level (void)
  {
    struct saved_scope *s;
    struct cp_binding_level *b;
*************** push_to_top_level (void)
*** 4862,4873 ****
      }
    else
      need_pop = 0;
  
    old_bindings = NULL;
!   if (scope_chain && previous_class_type)
!     old_bindings = store_bindings (previous_class_values, old_bindings);
  
    /* Have to include the global scope, because class-scope decls
       aren't listed anywhere useful.  */
    for (; b; b = b->level_chain)
      {
--- 4930,4942 ----
      }
    else
      need_pop = 0;
  
    old_bindings = NULL;
!   if (scope_chain && previous_class_level)
!     old_bindings = store_class_bindings (previous_class_level->class_shadowed,
! 					 old_bindings);
  
    /* Have to include the global scope, because class-scope decls
       aren't listed anywhere useful.  */
    for (; b; b = b->level_chain)
      {
*************** push_to_top_level (void)
*** 4882,4892 ****
  
        old_bindings = store_bindings (b->names, old_bindings);
        /* We also need to check class_shadowed to save class-level type
  	 bindings, since pushclass doesn't fill in b->names.  */
        if (b->kind == sk_class)
! 	old_bindings = store_bindings (b->class_shadowed, old_bindings);
  
        /* Unwind type-value slots back to top level.  */
        for (t = b->type_shadowed; t; t = TREE_CHAIN (t))
  	SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t));
      }
--- 4951,4961 ----
  
        old_bindings = store_bindings (b->names, old_bindings);
        /* We also need to check class_shadowed to save class-level type
  	 bindings, since pushclass doesn't fill in b->names.  */
        if (b->kind == sk_class)
! 	old_bindings = store_class_bindings (b->class_shadowed, old_bindings);
  
        /* Unwind type-value slots back to top level.  */
        for (t = b->type_shadowed; t; t = TREE_CHAIN (t))
  	SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t));
      }
*************** pop_from_top_level (void)
*** 4910,4920 ****
    struct saved_scope *s = scope_chain;
    cxx_saved_binding *saved;
  
    timevar_push (TV_NAME_LOOKUP); 
    /* Clear out class-level bindings cache.  */
!   if (previous_class_type)
      invalidate_class_lookup_cache ();
  
    current_lang_base = 0;
  
    scope_chain = s->prev;
--- 4979,4989 ----
    struct saved_scope *s = scope_chain;
    cxx_saved_binding *saved;
  
    timevar_push (TV_NAME_LOOKUP); 
    /* Clear out class-level bindings cache.  */
!   if (previous_class_level)
      invalidate_class_lookup_cache ();
  
    current_lang_base = 0;
  
    scope_chain = s->prev;
Index: name-lookup.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.h,v
retrieving revision 1.21
diff -c -5 -p -r1.21 name-lookup.h
*** name-lookup.h	16 Jun 2004 01:21:31 -0000	1.21
--- name-lookup.h	8 Jul 2004 04:31:10 -0000
*************** typedef enum scope_kind {
*** 115,124 ****
--- 115,133 ----
  			specialization.  Since, by definition, an
  			explicit specialization is introduced by
  			"template <>", this scope is always empty.  */
  } scope_kind;
  
+ typedef struct cp_class_binding GTY(())
+ {
+   cxx_binding base;
+   /* The bound name.  */
+   tree identifier;
+ } cp_class_binding;
+ 
+ DEF_VEC_O(cp_class_binding);
+ 
  /* For each binding contour we allocate a binding_level structure
     which records the names defined in that contour.
     Contours include:
      0) the global one
      1) one for each function definition,
*************** struct cp_binding_level GTY(())
*** 173,183 ****
  
      /* If this binding level is the binding level for a class, then
         class_shadowed is a TREE_LIST.  The TREE_PURPOSE of each node
         is the name of an entity bound in the class.  The TREE_TYPE is
         the DECL bound by this name in the class.  */
!     tree class_shadowed;
  
      /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
         is used for all binding levels. In addition the TREE_VALUE is the
         IDENTIFIER_TYPE_VALUE before we entered the class.  */
      tree type_shadowed;
--- 182,192 ----
  
      /* If this binding level is the binding level for a class, then
         class_shadowed is a TREE_LIST.  The TREE_PURPOSE of each node
         is the name of an entity bound in the class.  The TREE_TYPE is
         the DECL bound by this name in the class.  */
!     VEC(cp_class_binding) *class_shadowed;
  
      /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
         is used for all binding levels. In addition the TREE_VALUE is the
         IDENTIFIER_TYPE_VALUE before we entered the class.  */
      tree type_shadowed;
*************** extern void pop_from_top_level (void);
*** 271,280 ****
--- 280,290 ----
  extern void pop_everything (void);
  extern void keep_next_level (bool);
  extern bool is_ancestor (tree, tree);
  extern bool push_scope (tree);
  extern void pop_scope (tree);
+ extern void push_binding_level (struct cp_binding_level *);
  \f
  extern void push_namespace (tree);
  extern void pop_namespace (void);
  extern void push_nested_namespace (tree);
  extern void pop_nested_namespace (tree);
*************** extern bool pushdecl_class_level (tree);
*** 297,307 ****
  extern tree pushdecl_namespace_level (tree);
  extern bool push_class_level_binding (tree, tree);
  extern void storetags (tree);
  extern tree getdecls (void);
  extern tree cp_namespace_decls (tree);
- extern void set_class_shadows (tree);
  extern void set_decl_namespace (tree, tree, bool);
  extern tree current_decl_namespace (void);
  extern void push_decl_namespace (tree);
  extern void pop_decl_namespace (void);
  extern void do_namespace_alias (tree, tree);
--- 307,316 ----

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
  2004-07-08  5:43 PATCH: Speed up G++ Mark Mitchell
@ 2004-07-08 11:00 ` Nathan Sidwell
  2004-07-08 15:21   ` Mark Mitchell
  0 siblings, 1 reply; 7+ messages in thread
From: Nathan Sidwell @ 2004-07-08 11:00 UTC (permalink / raw)
  To: mark; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 678 bytes --]

Mark Mitchell wrote:
> Nathan, I broke the vector abstraction barrier in push_binding, where
> I calculate "need_fixup".  You will want to go back and adjust that
> code after you add the additional vector API function we dicussed
> today.
Fixed & installed thusly.  The allocation functions now take a signed
value where >= 0 means exact and <0 means at least 1, but increae
exponentially. One exception is the default explicit allocator, for
which 0 also means default.

built & tested on i686-pc-linux-gnu.

nathan

-- 
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk


[-- Attachment #2: vec.patch --]
[-- Type: text/plain, Size: 17245 bytes --]

2004-07-08  Nathan Sidwell  <nathan@codesourcery.com>

	* vec.c (vec_p_reserve, vec_o_reserve): Allocation is signed.
	* vec.h (VEC_alloc, VEC_embedded_size, VEC_embedded_init):
	Allocation is signed.
	(VEC_reserve): Return flag, allocation is signed.

2004-07-08  Nathan Sidwell  <nathan@codesourcery.com>

	* name-lookup.c (push_binding): Use VEC_reserve.

Index: vec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/vec.c,v
retrieving revision 2.2
diff -c -3 -p -r2.2 vec.c
*** vec.c	6 Jul 2004 17:08:42 -0000	2.2
--- vec.c	8 Jul 2004 09:36:57 -0000
*************** struct vec_prefix 
*** 34,77 ****
    void *vec[1];
  };
  
! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
!    ~0u. If RESERVE == ~0u increase the current allocation
!    exponentially.  VEC can be NULL, to create a new vector.  */
  
  void *
! vec_p_reserve (void *vec, size_t reserve MEM_STAT_DECL)
  {
    return vec_o_reserve (vec, reserve,
  			offsetof (struct vec_prefix, vec), sizeof (void *)
  			PASS_MEM_STAT);
  }
  
! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
!    ~0u.  If RESERVE == ~0u, increase the current allocation
!    exponentially.  VEC can be NULL, in which case a new vector is
!    created.  The vector's trailing array is at VEC_OFFSET offset and
!    consistes of ELT_SIZE sized elements.  */
  
  void *
! vec_o_reserve (void *vec, size_t reserve, size_t vec_offset, size_t elt_size
  	       MEM_STAT_DECL)
  {
    struct vec_prefix *pfx = vec;
!   size_t alloc;
  
!   if (reserve + 1)
!     alloc = (pfx ? pfx->num : 0) + reserve;
    else
!     alloc = pfx ? pfx->alloc * 2 : 4;
    
!   if (!pfx || pfx->alloc < alloc)
!     {
!       vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size
! 			      PASS_MEM_STAT);
!       ((struct vec_prefix *)vec)->alloc = alloc;
!       if (!pfx)
! 	((struct vec_prefix *)vec)->num = 0;
!     }
    
    return vec;
  }
--- 34,78 ----
    void *vec[1];
  };
  
! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE >=
!    0.  If RESERVE < 0 increase the current allocation exponentially.
!    VEC can be NULL, to create a new vector.  */
  
  void *
! vec_p_reserve (void *vec, int reserve MEM_STAT_DECL)
  {
    return vec_o_reserve (vec, reserve,
  			offsetof (struct vec_prefix, vec), sizeof (void *)
  			PASS_MEM_STAT);
  }
  
! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE >=
!    0.  If RESERVE < 0, increase the current allocation exponentially.
!    VEC can be NULL, in which case a new vector is created.  The
!    vector's trailing array is at VEC_OFFSET offset and consistes of
!    ELT_SIZE sized elements.  */
  
  void *
! vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
  	       MEM_STAT_DECL)
  {
    struct vec_prefix *pfx = vec;
!   size_t alloc = pfx ? pfx->num : 0;
  
!   if (reserve >= 0)
!     alloc += reserve;
!   else if (alloc)
!     alloc *= 2;
    else
!     alloc = 4;
! 
!   if (pfx && pfx->alloc >= alloc)
!     abort ();
    
!   vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
!   ((struct vec_prefix *)vec)->alloc = alloc;
!   if (!pfx)
!     ((struct vec_prefix *)vec)->num = 0;
    
    return vec;
  }
Index: vec.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/vec.h,v
retrieving revision 2.5
diff -c -3 -p -r2.5 vec.h
*** vec.h	7 Jul 2004 08:25:04 -0000	2.5
--- vec.h	8 Jul 2004 09:36:58 -0000
*************** Software Foundation, 59 Temple Place - S
*** 58,64 ****
     vector, if needed.  Reallocation causes an exponential increase in
     vector size.  If you know you will be adding N elements, it would
     be more efficient to use the reserve operation before adding the
!    elements with the 'quick' operation.
  
     You should prefer the push and pop operations, as they append and
     remove from the end of the vector. If you need to remove several
--- 58,66 ----
     vector, if needed.  Reallocation causes an exponential increase in
     vector size.  If you know you will be adding N elements, it would
     be more efficient to use the reserve operation before adding the
!    elements with the 'quick' operation.  You may also use the reserve
!    operation with a -1 operand, to gain control over exactly when
!    reallocation occurs.
  
     You should prefer the push and pop operations, as they append and
     remove from the end of the vector. If you need to remove several
*************** Software Foundation, 59 Temple Place - S
*** 132,158 ****
  #define VEC_iterate(TDEF,V,I)		(VEC_OP(TDEF,iterate)(V,I))
  
  /* Allocate new vector.
!    VEC(T) *VEC_T_alloc(size_t reserve);
  
!    Allocate a new vector with space for RESERVE objects.  */
  #define VEC_alloc(TDEF,A)		(VEC_OP(TDEF,alloc)(A MEM_STAT_INFO))
  
  /* Use these to determine the required size and initialization of a
     vector embedded within another structure (as the final member).
     
!    size_t VEC_T_embedded_size(size_t reserve);
!    void VEC_T_embedded_init(VEC(T) *v, size_t reserve);
     
     These allow the caller to perform the memory allocation.  */
  #define VEC_embedded_size(TDEF,A) (VEC_OP(TDEF,embedded_size)(A))
  #define VEC_embedded_init(TDEF,O,A) (VEC_OP(TDEF,embedded_init)(O,A))
  
  /* Reserve space.
!    void VEC_T_reserve(VEC(T) *&v, size_t reserve);
  
!    Ensure that V has at least RESERVE slots available.  Note this can
!    cause V to be reallocated.  */
! #define VEC_reserve(TDEF,V,R)		(VEC_OP(TDEF,reserve)(&(V),R MEM_STAT_INFO))
  
  /* Push object with no reallocation
     T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
--- 134,166 ----
  #define VEC_iterate(TDEF,V,I)		(VEC_OP(TDEF,iterate)(V,I))
  
  /* Allocate new vector.
!    VEC(T) *VEC_T_alloc(int reserve);
  
!    Allocate a new vector with space for RESERVE objects.  If RESERVE
!    is <= 0, a default number of slots are created.  */
  #define VEC_alloc(TDEF,A)		(VEC_OP(TDEF,alloc)(A MEM_STAT_INFO))
  
  /* Use these to determine the required size and initialization of a
     vector embedded within another structure (as the final member).
     
!    size_t VEC_T_embedded_size(int reserve);
!    void VEC_T_embedded_init(VEC(T) *v, int reserve);
     
     These allow the caller to perform the memory allocation.  */
  #define VEC_embedded_size(TDEF,A) (VEC_OP(TDEF,embedded_size)(A))
  #define VEC_embedded_init(TDEF,O,A) (VEC_OP(TDEF,embedded_init)(O,A))
  
  /* Reserve space.
!    int VEC_T_reserve(VEC(T) *&v, int reserve);
  
!    Ensure that V has at least RESERVE slots available, if RESERVE is
!    >= 0.  If RESERVE < 0, ensure that there is at least one spare
!    slot.  These differ in their reallocation behaviour, the first will
!    not create additionsl headroom, but the second mechanism will
!    perform the usual exponential headroom increase.  Note this can
!    cause V to be reallocated.  Returns non-zero iff reallocation
!    actually occurred.  */
! #define VEC_reserve(TDEF,V,R)	(VEC_OP(TDEF,reserve)(&(V),R MEM_STAT_INFO))
  
  /* Push object with no reallocation
     T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
*************** Software Foundation, 59 Temple Place - S
*** 238,245 ****
  
  #if !IN_GENGTYPE
  /* Reallocate an array of elements with prefix.  */
! extern void *vec_p_reserve (void *, size_t MEM_STAT_DECL);
! extern void *vec_o_reserve (void *, size_t, size_t, size_t MEM_STAT_DECL);
  
  #if ENABLE_CHECKING
  extern void vec_assert_fail (const char *, const char *,
--- 246,253 ----
  
  #if !IN_GENGTYPE
  /* Reallocate an array of elements with prefix.  */
! extern void *vec_p_reserve (void *, int MEM_STAT_DECL);
! extern void *vec_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
  
  #if ENABLE_CHECKING
  extern void vec_assert_fail (const char *, const char *,
*************** static inline TDEF VEC_OP (TDEF,iterate)
*** 310,337 ****
  }									  \
  									  \
  static inline VEC (TDEF) *VEC_OP (TDEF,alloc MEM_STAT_DECL)		  \
!      (size_t alloc_)							  \
  {									  \
    return vec_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT);		  \
  }									  \
  									  \
  static inline size_t VEC_OP (TDEF,embedded_size)			  \
!      (size_t alloc_)							  \
  {									  \
    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
  }									  \
  									  \
  static inline void VEC_OP (TDEF,embedded_init)				  \
!      (VEC (TDEF) *vec_, size_t alloc_)					  \
  {									  \
    vec_->num = 0;							  \
    vec_->alloc = alloc_;							  \
  }									  \
  									  \
! static inline void VEC_OP (TDEF,reserve)	       			  \
!      (VEC (TDEF) **vec_, size_t alloc_ MEM_STAT_DECL)			  \
  {									  \
!   *vec_ = vec_p_reserve (*vec_, alloc_ PASS_MEM_STAT);			  \
  }									  \
  									  \
  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
--- 318,351 ----
  }									  \
  									  \
  static inline VEC (TDEF) *VEC_OP (TDEF,alloc MEM_STAT_DECL)		  \
!      (int alloc_)							  \
  {									  \
    return vec_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT);		  \
  }									  \
  									  \
  static inline size_t VEC_OP (TDEF,embedded_size)			  \
!      (int alloc_)							  \
  {									  \
    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
  }									  \
  									  \
  static inline void VEC_OP (TDEF,embedded_init)				  \
!      (VEC (TDEF) *vec_, int alloc_)					  \
  {									  \
    vec_->num = 0;							  \
    vec_->alloc = alloc_;							  \
  }									  \
  									  \
! static inline int VEC_OP (TDEF,reserve)	       				  \
!      (VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL)			  \
  {									  \
!   int extend = !*vec_ || ((*vec_)->alloc - (*vec_)->num			  \
! 			  < (size_t)(alloc_ < 0 ? 1 : alloc_));		  \
! 		  							  \
!   if (extend)	  							  \
!     *vec_ = vec_p_reserve (*vec_, alloc_ PASS_MEM_STAT);		  \
! 		  							  \
!   return extend;							  \
  }									  \
  									  \
  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
*************** static inline TDEF *VEC_OP (TDEF,quick_p
*** 349,356 ****
  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
       (VEC (TDEF) **vec_, TDEF obj_ MEM_STAT_DECL)			  \
  {									  \
!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
  									  \
    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
  }									  \
--- 363,369 ----
  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
       (VEC (TDEF) **vec_, TDEF obj_ MEM_STAT_DECL)			  \
  {									  \
!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
  									  \
    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
  }									  \
*************** static inline TDEF *VEC_OP (TDEF,quick_i
*** 402,409 ****
  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
       (VEC (TDEF) **vec_, size_t ix_, TDEF obj_ MEM_STAT_DECL)		  \
  {									  \
!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
  									  \
    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
  }									  \
--- 415,421 ----
  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
       (VEC (TDEF) **vec_, size_t ix_, TDEF obj_ MEM_STAT_DECL)		  \
  {									  \
!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
  									  \
    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
  }									  \
*************** static inline TDEF *VEC_OP (TDEF,iterate
*** 476,482 ****
  }									  \
  									  \
  static inline VEC (TDEF) *VEC_OP (TDEF,alloc)      			  \
!      (size_t alloc_ MEM_STAT_DECL)					  \
  {									  \
    return vec_o_reserve (NULL, alloc_ - !alloc_,				  \
  			offsetof (VEC(TDEF),vec), sizeof (TDEF)		  \
--- 488,494 ----
  }									  \
  									  \
  static inline VEC (TDEF) *VEC_OP (TDEF,alloc)      			  \
!      (int alloc_ MEM_STAT_DECL)						  \
  {									  \
    return vec_o_reserve (NULL, alloc_ - !alloc_,				  \
  			offsetof (VEC(TDEF),vec), sizeof (TDEF)		  \
*************** static inline VEC (TDEF) *VEC_OP (TDEF,a
*** 484,507 ****
  }									  \
  									  \
  static inline size_t VEC_OP (TDEF,embedded_size)			  \
!      (size_t alloc_)							  \
  {									  \
    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
  }									  \
  									  \
  static inline void VEC_OP (TDEF,embedded_init)				  \
!      (VEC (TDEF) *vec_, size_t alloc_)					  \
  {									  \
    vec_->num = 0;							  \
    vec_->alloc = alloc_;							  \
  }									  \
  									  \
! static inline void VEC_OP (TDEF,reserve)	       			  \
!      (VEC (TDEF) **vec_, size_t alloc_ MEM_STAT_DECL)			  \
  {									  \
!   *vec_ = vec_o_reserve (*vec_, alloc_,					  \
! 			 offsetof (VEC(TDEF),vec), sizeof (TDEF)	  \
! 			 PASS_MEM_STAT);				  \
  }									  \
  									  \
  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
--- 496,525 ----
  }									  \
  									  \
  static inline size_t VEC_OP (TDEF,embedded_size)			  \
!      (int alloc_)							  \
  {									  \
    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
  }									  \
  									  \
  static inline void VEC_OP (TDEF,embedded_init)				  \
!      (VEC (TDEF) *vec_, int alloc_)					  \
  {									  \
    vec_->num = 0;							  \
    vec_->alloc = alloc_;							  \
  }									  \
  									  \
! static inline int VEC_OP (TDEF,reserve)	   	    			  \
!      (VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL)			  \
  {									  \
!   int extend = !*vec_ || ((*vec_)->alloc - (*vec_)->num			  \
! 			  < (size_t)(alloc_ < 0 ? 1 : alloc_));		  \
! 									  \
!   if (extend)								  \
!     *vec_ = vec_o_reserve (*vec_, alloc_,				  \
! 			   offsetof (VEC(TDEF),vec), sizeof (TDEF)	  \
! 			   PASS_MEM_STAT);				  \
! 									  \
!   return extend;							  \
  }									  \
  									  \
  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
*************** static inline TDEF *VEC_OP (TDEF,quick_p
*** 520,527 ****
  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
       (VEC (TDEF) **vec_, const TDEF *obj_ MEM_STAT_DECL)		  \
  {									  \
!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
  									  \
    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
  }									  \
--- 538,544 ----
  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
       (VEC (TDEF) **vec_, const TDEF *obj_ MEM_STAT_DECL)		  \
  {									  \
!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
  									  \
    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
  }									  \
*************** static inline TDEF *VEC_OP (TDEF,quick_i
*** 571,578 ****
  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
       (VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_ MEM_STAT_DECL)	  \
  {									  \
!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
  									  \
    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
  }									  \
--- 588,594 ----
  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
       (VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_ MEM_STAT_DECL)	  \
  {									  \
!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
  									  \
    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
  }									  \
Index: cp/name-lookup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.67
diff -c -3 -p -r1.67 name-lookup.c
*** cp/name-lookup.c	8 Jul 2004 04:32:27 -0000	1.67
--- cp/name-lookup.c	8 Jul 2004 09:37:08 -0000
*************** push_binding (tree id, tree decl, cxx_sc
*** 381,402 ****
    else
      {
        cp_class_binding *cb;
-       size_t length;
-       size_t i;
-       bool need_fixup;
  
!       length = VEC_length (cp_class_binding, level->class_shadowed);
!       need_fixup = (length && length == level->class_shadowed->alloc);
!       cb = VEC_safe_push (cp_class_binding, level->class_shadowed, NULL);
        cb->identifier = id;
        binding = &cb->base;
        cxx_binding_init (binding, decl, NULL_TREE);
-       if (need_fixup)
- 	for (i = 0; i < length; ++i)
- 	  {
- 	    cb = VEC_index (cp_class_binding, level->class_shadowed, i);
- 	    IDENTIFIER_BINDING (cb->identifier) = &cb->base;
- 	  }
      }
  			      
    /* Now, fill in the binding information.  */
--- 381,402 ----
    else
      {
        cp_class_binding *cb;
  
!       if (VEC_reserve (cp_class_binding, level->class_shadowed, -1))
! 	{
! 	  /* Fixup the current bindings, as they might have moved.  */
! 	  size_t i;
! 	  
! 	  for (i = 0;
! 	       (cb = VEC_iterate (cp_class_binding, level->class_shadowed, i));
! 	       i++)
! 	    IDENTIFIER_BINDING (cb->identifier) = &cb->base;
! 	}
! 
!       cb = VEC_quick_push (cp_class_binding, level->class_shadowed, NULL);
        cb->identifier = id;
        binding = &cb->base;
        cxx_binding_init (binding, decl, NULL_TREE);
      }
  			      
    /* Now, fill in the binding information.  */

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
  2004-07-08 11:00 ` Nathan Sidwell
@ 2004-07-08 15:21   ` Mark Mitchell
  2004-07-08 15:35     ` Nathan Sidwell
  0 siblings, 1 reply; 7+ messages in thread
From: Mark Mitchell @ 2004-07-08 15:21 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches

Nathan Sidwell wrote:

> Mark Mitchell wrote:
>
>> Nathan, I broke the vector abstraction barrier in push_binding, where
>> I calculate "need_fixup".  You will want to go back and adjust that
>> code after you add the additional vector API function we dicussed
>> today.
>
> Fixed & installed thusly.  The allocation functions now take a signed
> value where >= 0 means exact and <0 means at least 1, but increae
> exponentially. One exception is the default explicit allocator, for
> which 0 also means default.
>
> built & tested on i686-pc-linux-gnu.
>
> nathan
>
>------------------------------------------------------------------------
>
>2004-07-08  Nathan Sidwell  <nathan@codesourcery.com>
>
>	* vec.c (vec_p_reserve, vec_o_reserve): Allocation is signed.
>	* vec.h (VEC_alloc, VEC_embedded_size, VEC_embedded_init):
>	Allocation is signed.
>	(VEC_reserve): Return flag, allocation is signed.
>
>2004-07-08  Nathan Sidwell  <nathan@codesourcery.com>
>
>	* name-lookup.c (push_binding): Use VEC_reserve.
>
>Index: vec.c
>===================================================================
>RCS file: /cvs/gcc/gcc/gcc/vec.c,v
>retrieving revision 2.2
>diff -c -3 -p -r2.2 vec.c
>*** vec.c	6 Jul 2004 17:08:42 -0000	2.2
>--- vec.c	8 Jul 2004 09:36:57 -0000
>*************** struct vec_prefix 
>*** 34,77 ****
>    void *vec[1];
>  };
>  
>! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
>!    ~0u. If RESERVE == ~0u increase the current allocation
>!    exponentially.  VEC can be NULL, to create a new vector.  */
>  
>  void *
>! vec_p_reserve (void *vec, size_t reserve MEM_STAT_DECL)
>  {
>    return vec_o_reserve (vec, reserve,
>  			offsetof (struct vec_prefix, vec), sizeof (void *)
>  			PASS_MEM_STAT);
>  }
>  
>! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE !=
>!    ~0u.  If RESERVE == ~0u, increase the current allocation
>!    exponentially.  VEC can be NULL, in which case a new vector is
>!    created.  The vector's trailing array is at VEC_OFFSET offset and
>!    consistes of ELT_SIZE sized elements.  */
>  
>  void *
>! vec_o_reserve (void *vec, size_t reserve, size_t vec_offset, size_t elt_size
>  	       MEM_STAT_DECL)
>  {
>    struct vec_prefix *pfx = vec;
>!   size_t alloc;
>  
>!   if (reserve + 1)
>!     alloc = (pfx ? pfx->num : 0) + reserve;
>    else
>!     alloc = pfx ? pfx->alloc * 2 : 4;
>    
>!   if (!pfx || pfx->alloc < alloc)
>!     {
>!       vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size
>! 			      PASS_MEM_STAT);
>!       ((struct vec_prefix *)vec)->alloc = alloc;
>!       if (!pfx)
>! 	((struct vec_prefix *)vec)->num = 0;
>!     }
>    
>    return vec;
>  }
>--- 34,78 ----
>    void *vec[1];
>  };
>  
>! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE >=
>!    0.  If RESERVE < 0 increase the current allocation exponentially.
>!    VEC can be NULL, to create a new vector.  */
>  
>  void *
>! vec_p_reserve (void *vec, int reserve MEM_STAT_DECL)
>  {
>    return vec_o_reserve (vec, reserve,
>  			offsetof (struct vec_prefix, vec), sizeof (void *)
>  			PASS_MEM_STAT);
>  }
>  
>! /* Ensure there are at least RESERVE free slots in VEC, if RESERVE >=
>!    0.  If RESERVE < 0, increase the current allocation exponentially.
>!    VEC can be NULL, in which case a new vector is created.  The
>!    vector's trailing array is at VEC_OFFSET offset and consistes of
>!    ELT_SIZE sized elements.  */
>  
>  void *
>! vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
>  	       MEM_STAT_DECL)
>  {
>    struct vec_prefix *pfx = vec;
>!   size_t alloc = pfx ? pfx->num : 0;
>  
>!   if (reserve >= 0)
>!     alloc += reserve;
>!   else if (alloc)
>!     alloc *= 2;
>    else
>!     alloc = 4;
>! 
>!   if (pfx && pfx->alloc >= alloc)
>!     abort ();
>    
>!   vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
>!   ((struct vec_prefix *)vec)->alloc = alloc;
>!   if (!pfx)
>!     ((struct vec_prefix *)vec)->num = 0;
>    
>    return vec;
>  }
>Index: vec.h
>===================================================================
>RCS file: /cvs/gcc/gcc/gcc/vec.h,v
>retrieving revision 2.5
>diff -c -3 -p -r2.5 vec.h
>*** vec.h	7 Jul 2004 08:25:04 -0000	2.5
>--- vec.h	8 Jul 2004 09:36:58 -0000
>*************** Software Foundation, 59 Temple Place - S
>*** 58,64 ****
>     vector, if needed.  Reallocation causes an exponential increase in
>     vector size.  If you know you will be adding N elements, it would
>     be more efficient to use the reserve operation before adding the
>!    elements with the 'quick' operation.
>  
>     You should prefer the push and pop operations, as they append and
>     remove from the end of the vector. If you need to remove several
>--- 58,66 ----
>     vector, if needed.  Reallocation causes an exponential increase in
>     vector size.  If you know you will be adding N elements, it would
>     be more efficient to use the reserve operation before adding the
>!    elements with the 'quick' operation.  You may also use the reserve
>!    operation with a -1 operand, to gain control over exactly when
>!    reallocation occurs.
>  
>     You should prefer the push and pop operations, as they append and
>     remove from the end of the vector. If you need to remove several
>*************** Software Foundation, 59 Temple Place - S
>*** 132,158 ****
>  #define VEC_iterate(TDEF,V,I)		(VEC_OP(TDEF,iterate)(V,I))
>  
>  /* Allocate new vector.
>!    VEC(T) *VEC_T_alloc(size_t reserve);
>  
>!    Allocate a new vector with space for RESERVE objects.  */
>  #define VEC_alloc(TDEF,A)		(VEC_OP(TDEF,alloc)(A MEM_STAT_INFO))
>  
>  /* Use these to determine the required size and initialization of a
>     vector embedded within another structure (as the final member).
>     
>!    size_t VEC_T_embedded_size(size_t reserve);
>!    void VEC_T_embedded_init(VEC(T) *v, size_t reserve);
>     
>     These allow the caller to perform the memory allocation.  */
>  #define VEC_embedded_size(TDEF,A) (VEC_OP(TDEF,embedded_size)(A))
>  #define VEC_embedded_init(TDEF,O,A) (VEC_OP(TDEF,embedded_init)(O,A))
>  
>  /* Reserve space.
>!    void VEC_T_reserve(VEC(T) *&v, size_t reserve);
>  
>!    Ensure that V has at least RESERVE slots available.  Note this can
>!    cause V to be reallocated.  */
>! #define VEC_reserve(TDEF,V,R)		(VEC_OP(TDEF,reserve)(&(V),R MEM_STAT_INFO))
>  
>  /* Push object with no reallocation
>     T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
>--- 134,166 ----
>  #define VEC_iterate(TDEF,V,I)		(VEC_OP(TDEF,iterate)(V,I))
>  
>  /* Allocate new vector.
>!    VEC(T) *VEC_T_alloc(int reserve);
>  
>!    Allocate a new vector with space for RESERVE objects.  If RESERVE
>!    is <= 0, a default number of slots are created.  */
>  #define VEC_alloc(TDEF,A)		(VEC_OP(TDEF,alloc)(A MEM_STAT_INFO))
>  
>  /* Use these to determine the required size and initialization of a
>     vector embedded within another structure (as the final member).
>     
>!    size_t VEC_T_embedded_size(int reserve);
>!    void VEC_T_embedded_init(VEC(T) *v, int reserve);
>     
>     These allow the caller to perform the memory allocation.  */
>  #define VEC_embedded_size(TDEF,A) (VEC_OP(TDEF,embedded_size)(A))
>  #define VEC_embedded_init(TDEF,O,A) (VEC_OP(TDEF,embedded_init)(O,A))
>  
>  /* Reserve space.
>!    int VEC_T_reserve(VEC(T) *&v, int reserve);
>  
>!    Ensure that V has at least RESERVE slots available, if RESERVE is
>!    >= 0.  If RESERVE < 0, ensure that there is at least one spare
>!    slot.  These differ in their reallocation behaviour, the first will
>!    not create additionsl headroom, but the second mechanism will
>!    perform the usual exponential headroom increase.  Note this can
>!    cause V to be reallocated.  Returns non-zero iff reallocation
>!    actually occurred.  */
>! #define VEC_reserve(TDEF,V,R)	(VEC_OP(TDEF,reserve)(&(V),R MEM_STAT_INFO))
>  
>  /* Push object with no reallocation
>     T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer
>*************** Software Foundation, 59 Temple Place - S
>*** 238,245 ****
>  
>  #if !IN_GENGTYPE
>  /* Reallocate an array of elements with prefix.  */
>! extern void *vec_p_reserve (void *, size_t MEM_STAT_DECL);
>! extern void *vec_o_reserve (void *, size_t, size_t, size_t MEM_STAT_DECL);
>  
>  #if ENABLE_CHECKING
>  extern void vec_assert_fail (const char *, const char *,
>--- 246,253 ----
>  
>  #if !IN_GENGTYPE
>  /* Reallocate an array of elements with prefix.  */
>! extern void *vec_p_reserve (void *, int MEM_STAT_DECL);
>! extern void *vec_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
>  
>  #if ENABLE_CHECKING
>  extern void vec_assert_fail (const char *, const char *,
>*************** static inline TDEF VEC_OP (TDEF,iterate)
>*** 310,337 ****
>  }									  \
>  									  \
>  static inline VEC (TDEF) *VEC_OP (TDEF,alloc MEM_STAT_DECL)		  \
>!      (size_t alloc_)							  \
>  {									  \
>    return vec_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT);		  \
>  }									  \
>  									  \
>  static inline size_t VEC_OP (TDEF,embedded_size)			  \
>!      (size_t alloc_)							  \
>  {									  \
>    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
>  }									  \
>  									  \
>  static inline void VEC_OP (TDEF,embedded_init)				  \
>!      (VEC (TDEF) *vec_, size_t alloc_)					  \
>  {									  \
>    vec_->num = 0;							  \
>    vec_->alloc = alloc_;							  \
>  }									  \
>  									  \
>! static inline void VEC_OP (TDEF,reserve)	       			  \
>!      (VEC (TDEF) **vec_, size_t alloc_ MEM_STAT_DECL)			  \
>  {									  \
>!   *vec_ = vec_p_reserve (*vec_, alloc_ PASS_MEM_STAT);			  \
>  }									  \
>  									  \
>  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
>--- 318,351 ----
>  }									  \
>  									  \
>  static inline VEC (TDEF) *VEC_OP (TDEF,alloc MEM_STAT_DECL)		  \
>!      (int alloc_)							  \
>  {									  \
>    return vec_p_reserve (NULL, alloc_ - !alloc_ PASS_MEM_STAT);		  \
>  }									  \
>  									  \
>  static inline size_t VEC_OP (TDEF,embedded_size)			  \
>!      (int alloc_)							  \
>  {									  \
>    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
>  }									  \
>  									  \
>  static inline void VEC_OP (TDEF,embedded_init)				  \
>!      (VEC (TDEF) *vec_, int alloc_)					  \
>  {									  \
>    vec_->num = 0;							  \
>    vec_->alloc = alloc_;							  \
>  }									  \
>  									  \
>! static inline int VEC_OP (TDEF,reserve)	       				  \
>!      (VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL)			  \
>  {									  \
>!   int extend = !*vec_ || ((*vec_)->alloc - (*vec_)->num			  \
>! 			  < (size_t)(alloc_ < 0 ? 1 : alloc_));		  \
>! 		  							  \
>!   if (extend)	  							  \
>!     *vec_ = vec_p_reserve (*vec_, alloc_ PASS_MEM_STAT);		  \
>! 		  							  \
>!   return extend;							  \
>  }									  \
>  									  \
>  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
>*************** static inline TDEF *VEC_OP (TDEF,quick_p
>*** 349,356 ****
>  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
>       (VEC (TDEF) **vec_, TDEF obj_ MEM_STAT_DECL)			  \
>  {									  \
>!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
>!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
>  									  \
>    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
>  }									  \
>--- 363,369 ----
>  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
>       (VEC (TDEF) **vec_, TDEF obj_ MEM_STAT_DECL)			  \
>  {									  \
>!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
>  									  \
>    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
>  }									  \
>*************** static inline TDEF *VEC_OP (TDEF,quick_i
>*** 402,409 ****
>  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
>       (VEC (TDEF) **vec_, size_t ix_, TDEF obj_ MEM_STAT_DECL)		  \
>  {									  \
>!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
>!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
>  									  \
>    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
>  }									  \
>--- 415,421 ----
>  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
>       (VEC (TDEF) **vec_, size_t ix_, TDEF obj_ MEM_STAT_DECL)		  \
>  {									  \
>!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
>  									  \
>    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
>  }									  \
>*************** static inline TDEF *VEC_OP (TDEF,iterate
>*** 476,482 ****
>  }									  \
>  									  \
>  static inline VEC (TDEF) *VEC_OP (TDEF,alloc)      			  \
>!      (size_t alloc_ MEM_STAT_DECL)					  \
>  {									  \
>    return vec_o_reserve (NULL, alloc_ - !alloc_,				  \
>  			offsetof (VEC(TDEF),vec), sizeof (TDEF)		  \
>--- 488,494 ----
>  }									  \
>  									  \
>  static inline VEC (TDEF) *VEC_OP (TDEF,alloc)      			  \
>!      (int alloc_ MEM_STAT_DECL)						  \
>  {									  \
>    return vec_o_reserve (NULL, alloc_ - !alloc_,				  \
>  			offsetof (VEC(TDEF),vec), sizeof (TDEF)		  \
>*************** static inline VEC (TDEF) *VEC_OP (TDEF,a
>*** 484,507 ****
>  }									  \
>  									  \
>  static inline size_t VEC_OP (TDEF,embedded_size)			  \
>!      (size_t alloc_)							  \
>  {									  \
>    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
>  }									  \
>  									  \
>  static inline void VEC_OP (TDEF,embedded_init)				  \
>!      (VEC (TDEF) *vec_, size_t alloc_)					  \
>  {									  \
>    vec_->num = 0;							  \
>    vec_->alloc = alloc_;							  \
>  }									  \
>  									  \
>! static inline void VEC_OP (TDEF,reserve)	       			  \
>!      (VEC (TDEF) **vec_, size_t alloc_ MEM_STAT_DECL)			  \
>  {									  \
>!   *vec_ = vec_o_reserve (*vec_, alloc_,					  \
>! 			 offsetof (VEC(TDEF),vec), sizeof (TDEF)	  \
>! 			 PASS_MEM_STAT);				  \
>  }									  \
>  									  \
>  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
>--- 496,525 ----
>  }									  \
>  									  \
>  static inline size_t VEC_OP (TDEF,embedded_size)			  \
>!      (int alloc_)							  \
>  {									  \
>    return offsetof (VEC(TDEF),vec) + alloc_ * sizeof(TDEF);		  \
>  }									  \
>  									  \
>  static inline void VEC_OP (TDEF,embedded_init)				  \
>!      (VEC (TDEF) *vec_, int alloc_)					  \
>  {									  \
>    vec_->num = 0;							  \
>    vec_->alloc = alloc_;							  \
>  }									  \
>  									  \
>! static inline int VEC_OP (TDEF,reserve)	   	    			  \
>!      (VEC (TDEF) **vec_, int alloc_ MEM_STAT_DECL)			  \
>  {									  \
>!   int extend = !*vec_ || ((*vec_)->alloc - (*vec_)->num			  \
>! 			  < (size_t)(alloc_ < 0 ? 1 : alloc_));		  \
>! 									  \
>!   if (extend)								  \
>!     *vec_ = vec_o_reserve (*vec_, alloc_,				  \
>! 			   offsetof (VEC(TDEF),vec), sizeof (TDEF)	  \
>! 			   PASS_MEM_STAT);				  \
>! 									  \
>!   return extend;							  \
>  }									  \
>  									  \
>  static inline TDEF *VEC_OP (TDEF,quick_push)				  \
>*************** static inline TDEF *VEC_OP (TDEF,quick_p
>*** 520,527 ****
>  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
>       (VEC (TDEF) **vec_, const TDEF *obj_ MEM_STAT_DECL)		  \
>  {									  \
>!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
>!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
>  									  \
>    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
>  }									  \
>--- 538,544 ----
>  static inline TDEF *VEC_OP (TDEF,safe_push)				  \
>       (VEC (TDEF) **vec_, const TDEF *obj_ MEM_STAT_DECL)		  \
>  {									  \
>!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
>  									  \
>    return VEC_OP (TDEF,quick_push) (*vec_, obj_);			  \
>  }									  \
>*************** static inline TDEF *VEC_OP (TDEF,quick_i
>*** 571,578 ****
>  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
>       (VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_ MEM_STAT_DECL)	  \
>  {									  \
>!   if (!*vec_ || (*vec_)->num == (*vec_)->alloc)				  \
>!     VEC_OP (TDEF,reserve) (vec_, ~(size_t)0 PASS_MEM_STAT);		  \
>  									  \
>    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
>  }									  \
>--- 588,594 ----
>  static inline TDEF *VEC_OP (TDEF,safe_insert)		     	  	  \
>       (VEC (TDEF) **vec_, size_t ix_, const TDEF *obj_ MEM_STAT_DECL)	  \
>  {									  \
>!   VEC_OP (TDEF,reserve) (vec_, -1 PASS_MEM_STAT);			  \
>  									  \
>    return VEC_OP (TDEF,quick_insert) (*vec_, ix_, obj_);			  \
>  }									  \
>Index: cp/name-lookup.c
>===================================================================
>RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
>retrieving revision 1.67
>diff -c -3 -p -r1.67 name-lookup.c
>*** cp/name-lookup.c	8 Jul 2004 04:32:27 -0000	1.67
>--- cp/name-lookup.c	8 Jul 2004 09:37:08 -0000
>*************** push_binding (tree id, tree decl, cxx_sc
>*** 381,402 ****
>    else
>      {
>        cp_class_binding *cb;
>-       size_t length;
>-       size_t i;
>-       bool need_fixup;
>  
>!       length = VEC_length (cp_class_binding, level->class_shadowed);
>!       need_fixup = (length && length == level->class_shadowed->alloc);
>!       cb = VEC_safe_push (cp_class_binding, level->class_shadowed, NULL);
>        cb->identifier = id;
>        binding = &cb->base;
>        cxx_binding_init (binding, decl, NULL_TREE);
>-       if (need_fixup)
>- 	for (i = 0; i < length; ++i)
>- 	  {
>- 	    cb = VEC_index (cp_class_binding, level->class_shadowed, i);
>- 	    IDENTIFIER_BINDING (cb->identifier) = &cb->base;
>- 	  }
>      }
>  			      
>    /* Now, fill in the binding information.  */
>--- 381,402 ----
>    else
>      {
>        cp_class_binding *cb;
>  
>!       if (VEC_reserve (cp_class_binding, level->class_shadowed, -1))
>! 	{
>! 	  /* Fixup the current bindings, as they might have moved.  */
>! 	  size_t i;
>! 	  
>! 	  for (i = 0;
>! 	       (cb = VEC_iterate (cp_class_binding, level->class_shadowed, i));
>! 	       i++)
>! 	    IDENTIFIER_BINDING (cb->identifier) = &cb->base;
>! 	}
>! 
>
Isn't this going to fixup too many things?  It looks like it will 
iterate over the *new* vector length, not the old length.  Am I confused?

-- 
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
  2004-07-08 15:21   ` Mark Mitchell
@ 2004-07-08 15:35     ` Nathan Sidwell
  2004-07-08 16:21       ` Mark Mitchell
  0 siblings, 1 reply; 7+ messages in thread
From: Nathan Sidwell @ 2004-07-08 15:35 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc-patches

Mark Mitchell wrote:
> Nathan Sidwell wrote:
> 
>>      {
>>        cp_class_binding *cb;
>>  
>> !       if (VEC_reserve (cp_class_binding, level->class_shadowed, -1))
>> !     {
>> !       /* Fixup the current bindings, as they might have moved.  */
>> !       size_t i;
>> !       !       for (i = 0;
>> !            (cb = VEC_iterate (cp_class_binding, 
>> level->class_shadowed, i));
>> !            i++)
>> !         IDENTIFIER_BINDING (cb->identifier) = &cb->base;
>> !     }
>> !
> 
> Isn't this going to fixup too many things?  It looks like it will 
> iterate over the *new* vector length, not the old length.  Am I confused?

you are confused :) VEC_reserve will increase the allocated space, but
not change the number of live elements.  VEC_iterate will iterate only over
the live elements.

nathan

-- 
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
  2004-07-08 15:35     ` Nathan Sidwell
@ 2004-07-08 16:21       ` Mark Mitchell
  0 siblings, 0 replies; 7+ messages in thread
From: Mark Mitchell @ 2004-07-08 16:21 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches

Nathan Sidwell wrote:

> Mark Mitchell wrote:
>
>> Nathan Sidwell wrote:
>>
>>>      {
>>>        cp_class_binding *cb;
>>>  
>>> !       if (VEC_reserve (cp_class_binding, level->class_shadowed, -1))
>>> !     {
>>> !       /* Fixup the current bindings, as they might have moved.  */
>>> !       size_t i;
>>> !       !       for (i = 0;
>>> !            (cb = VEC_iterate (cp_class_binding, 
>>> level->class_shadowed, i));
>>> !            i++)
>>> !         IDENTIFIER_BINDING (cb->identifier) = &cb->base;
>>> !     }
>>> !
>>
>>
>> Isn't this going to fixup too many things?  It looks like it will 
>> iterate over the *new* vector length, not the old length.  Am I 
>> confused?
>
>
> you are confused :) 

Cool.  Thanks!

-- 
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
  2004-07-08 12:28 Giovanni Bajo
@ 2004-07-08 15:06 ` Mark Mitchell
  0 siblings, 0 replies; 7+ messages in thread
From: Mark Mitchell @ 2004-07-08 15:06 UTC (permalink / raw)
  To: Giovanni Bajo; +Cc: gcc-patches

Giovanni Bajo wrote:

>The comment for class_shadowed is now invalid as far as I can tell. Would you
>please update it?
>  
>
Yes, I mean to do this before check-in, but completely spaced it.  
Thanks for reminding me!

-- 
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: PATCH: Speed up G++
@ 2004-07-08 12:28 Giovanni Bajo
  2004-07-08 15:06 ` Mark Mitchell
  0 siblings, 1 reply; 7+ messages in thread
From: Giovanni Bajo @ 2004-07-08 12:28 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc-patches

Mark,

*************** struct cp_binding_level GTY(())
*** 173,183 ****

      /* If this binding level is the binding level for a class, then
         class_shadowed is a TREE_LIST.  The TREE_PURPOSE of each node
         is the name of an entity bound in the class.  The TREE_TYPE is
         the DECL bound by this name in the class.  */
!     tree class_shadowed;

      /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
         is used for all binding levels. In addition the TREE_VALUE is the
         IDENTIFIER_TYPE_VALUE before we entered the class.  */
      tree type_shadowed;
--- 182,192 ----

      /* If this binding level is the binding level for a class, then
         class_shadowed is a TREE_LIST.  The TREE_PURPOSE of each node
         is the name of an entity bound in the class.  The TREE_TYPE is
         the DECL bound by this name in the class.  */
!     VEC(cp_class_binding) *class_shadowed;

      /* Similar to class_shadowed, but for IDENTIFIER_TYPE_VALUE, and
         is used for all binding levels. In addition the TREE_VALUE is the
         IDENTIFIER_TYPE_VALUE before we entered the class.  */
      tree type_shadowed;


The comment for class_shadowed is now invalid as far as I can tell. Would you
please update it?

Thanks,
Giovanni Bajo


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2004-07-08 15:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-07-08  5:43 PATCH: Speed up G++ Mark Mitchell
2004-07-08 11:00 ` Nathan Sidwell
2004-07-08 15:21   ` Mark Mitchell
2004-07-08 15:35     ` Nathan Sidwell
2004-07-08 16:21       ` Mark Mitchell
2004-07-08 12:28 Giovanni Bajo
2004-07-08 15:06 ` Mark Mitchell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).