C++ PATCH: Parser speedup

Mark Mitchell mark@codesourcery.com
Mon Dec 30 16:13:00 GMT 2002


This patch gets me about 17% on Paolo's first test case.

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

-- 
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2002-12-30  Mark Mitchell  <mark@codesourcery.com>

	* parser.c (cp_parser_context_free_list): New variable.
	(cp_parser_context_new): Use it.
	(cp_parser_error): Check return code from
	cp_parser_simulate_error.
	(cp_parser_simulate_error): Return a value.
	(cp_parser_id_expression): Optimize common case.
	(cp_parser_class_name): Likewise.
	(cp_parser_class_specifier): Adjust call to
	cp_parser_late_parsing_default_args.
	(cp_parser_lookup_name): Optimize common case.
	(cp_parser_late_parsing_for_member): Adjust call to
	cp_parser_late_parsing_default_args.
	(cp_parser_late_parsing_default_args): Add scope parameter.
	(cp_parser_require): Avoid creating the error message unless it's
	needed.
	(cp_parser_parse_definitely): Place free'd contexts on the free
	list.

Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.6
diff -c -p -r1.6 parser.c
*** parser.c	30 Dec 2002 20:18:38 -0000	1.6
--- parser.c	31 Dec 2002 00:02:37 -0000
*************** typedef struct cp_parser_context GTY (()
*** 1196,1201 ****
--- 1196,1205 ----
  static cp_parser_context *cp_parser_context_new
    PARAMS ((cp_parser_context *));
  
+ /* Class variables.  */
+ 
+ static GTY(()) cp_parser_context* cp_parser_context_free_list;
+ 
  /* Constructors and destructors.  */
  
  /* Construct a new context.  The context below this one on the stack
*************** cp_parser_context_new (next)
*** 1208,1215 ****
    cp_parser_context *context;
  
    /* Allocate the storage.  */
!   context = ((cp_parser_context *) 
! 	     ggc_alloc_cleared (sizeof (cp_parser_context)));
    /* No errors have occurred yet in this context.  */
    context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
    /* If this is not the bottomost context, copy information that we
--- 1212,1227 ----
    cp_parser_context *context;
  
    /* Allocate the storage.  */
!   if (cp_parser_context_free_list != NULL)
!     {
!       /* Pull the first entry from the free list.  */
!       context = cp_parser_context_free_list;
!       cp_parser_context_free_list = context->next;
!       memset ((char *)context, 0, sizeof (*context));
!     }
!   else
!     context = ((cp_parser_context *) 
! 	       ggc_alloc_cleared (sizeof (cp_parser_context)));
    /* No errors have occurred yet in this context.  */
    context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
    /* If this is not the bottomost context, copy information that we
*************** static tree cp_parser_functional_cast
*** 1704,1710 ****
  static void cp_parser_late_parsing_for_member
    PARAMS ((cp_parser *, tree));
  static void cp_parser_late_parsing_default_args
!   PARAMS ((cp_parser *, tree));
  static tree cp_parser_sizeof_operand
    PARAMS ((cp_parser *, enum rid));
  static bool cp_parser_declares_only_class_p
--- 1716,1722 ----
  static void cp_parser_late_parsing_for_member
    PARAMS ((cp_parser *, tree));
  static void cp_parser_late_parsing_default_args
!   (cp_parser *, tree, tree);
  static tree cp_parser_sizeof_operand
    PARAMS ((cp_parser *, enum rid));
  static bool cp_parser_declares_only_class_p
*************** static bool cp_parser_committed_to_tenta
*** 1741,1747 ****
    PARAMS ((cp_parser *));
  static void cp_parser_error
    PARAMS ((cp_parser *, const char *));
! static void cp_parser_simulate_error
    PARAMS ((cp_parser *));
  static void cp_parser_check_type_definition
    PARAMS ((cp_parser *));
--- 1753,1759 ----
    PARAMS ((cp_parser *));
  static void cp_parser_error
    PARAMS ((cp_parser *, const char *));
! static bool cp_parser_simulate_error
    PARAMS ((cp_parser *));
  static void cp_parser_check_type_definition
    PARAMS ((cp_parser *));
*************** cp_parser_error (parser, message)
*** 2213,2236 ****
       cp_parser *parser;
       const char *message;
  {
-   /* Remember that we have issued an error.  */
-   cp_parser_simulate_error (parser);
    /* Output the MESSAGE -- unless we're parsing tentatively.  */
!   if (!cp_parser_parsing_tentatively (parser) 
!       || cp_parser_committed_to_tentative_parse (parser))
      error (message);
  }
  
  /* If we are parsing tentatively, remember that an error has occurred
!    during this tentative parse.  */
  
! static void
  cp_parser_simulate_error (parser)
       cp_parser *parser;
  {
    if (cp_parser_parsing_tentatively (parser)
        && !cp_parser_committed_to_tentative_parse (parser))
!     parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
  }
  
  /* This function is called when a type is defined.  If type
--- 2225,2250 ----
       cp_parser *parser;
       const char *message;
  {
    /* Output the MESSAGE -- unless we're parsing tentatively.  */
!   if (!cp_parser_simulate_error (parser))
      error (message);
  }
  
  /* If we are parsing tentatively, remember that an error has occurred
!    during this tentative parse.  Returns true if the error was
!    simulated; false if a messgae should be issued by the caller.  */
  
! static bool
  cp_parser_simulate_error (parser)
       cp_parser *parser;
  {
    if (cp_parser_parsing_tentatively (parser)
        && !cp_parser_committed_to_tentative_parse (parser))
!     {
!       parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
!       return true;
!     }
!   return false;
  }
  
  /* This function is called when a type is defined.  If type
*************** cp_parser_id_expression (cp_parser *pars
*** 3117,3124 ****
        cp_token *token;
        tree id;
  
!       /* We don't know yet whether or not this will be a 
! 	 template-id.  */
        cp_parser_parse_tentatively (parser);
        /* Try a template-id.  */
        id = cp_parser_template_id (parser, 
--- 3131,3146 ----
        cp_token *token;
        tree id;
  
!       /* Peek at the next token.  */
!       token = cp_lexer_peek_token (parser->lexer);
! 
!       /* If it's an identifier, and the next token is not a "<", then
! 	 we can avoid the template-id case.  This is an optimization
! 	 for this common case.  */
!       if (token->type == CPP_NAME 
! 	  && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS)
! 	return cp_parser_identifier (parser);
! 
        cp_parser_parse_tentatively (parser);
        /* Try a template-id.  */
        id = cp_parser_template_id (parser, 
*************** cp_parser_id_expression (cp_parser *pars
*** 3128,3134 ****
        if (cp_parser_parse_definitely (parser))
  	return id;
  
!       /* Peek at the next token.  */
        token = cp_lexer_peek_token (parser->lexer);
  
        switch (token->type)
--- 3150,3157 ----
        if (cp_parser_parse_definitely (parser))
  	return id;
  
!       /* Peek at the next token.  (Changes in the token buffer may
! 	 have invalidated the pointer obtained above.)  */
        token = cp_lexer_peek_token (parser->lexer);
  
        switch (token->type)
*************** cp_parser_class_name (cp_parser *parser,
*** 11331,11337 ****
    tree decl;
    tree scope;
    bool typename_p;
!   
    /* PARSER->SCOPE can be cleared when parsing the template-arguments
       to a template-id, so we save it here.  */
    scope = parser->scope;
--- 11354,11369 ----
    tree decl;
    tree scope;
    bool typename_p;
!   cp_token *token;
! 
!   /* All class-names start with an identifier.  */
!   token = cp_lexer_peek_token (parser->lexer);
!   if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID)
!     {
!       cp_parser_error (parser, "expected class-name");
!       return error_mark_node;
!     }
!     
    /* PARSER->SCOPE can be cleared when parsing the template-arguments
       to a template-id, so we save it here.  */
    scope = parser->scope;
*************** cp_parser_class_name (cp_parser *parser,
*** 11339,11359 ****
       in a qualified name where the enclosing scope is type-dependent.  */
    typename_p = (typename_keyword_p && scope && TYPE_P (scope)
  		&& cp_parser_dependent_type_p (scope));
! 
!   /* We don't know whether what comes next is a template-id or 
!      not.  */
!   cp_parser_parse_tentatively (parser);
!   /* Try a template-id.  */
!   decl = cp_parser_template_id (parser, template_keyword_p,
! 				check_dependency_p);
!   if (cp_parser_parse_definitely (parser))
!     {
!       if (decl == error_mark_node)
! 	return error_mark_node;
!     }
!   else
      {
-       /* If it wasn't a template-id, try a simple identifier.  */
        tree identifier;
  
        /* Look for the identifier.  */
--- 11371,11381 ----
       in a qualified name where the enclosing scope is type-dependent.  */
    typename_p = (typename_keyword_p && scope && TYPE_P (scope)
  		&& cp_parser_dependent_type_p (scope));
!   /* Handle the common case (an identifier, but not a template-id)
!      efficiently.  */
!   if (token->type == CPP_NAME 
!       && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS)
      {
        tree identifier;
  
        /* Look for the identifier.  */
*************** cp_parser_class_name (cp_parser *parser,
*** 11385,11390 ****
--- 11407,11420 ----
  					check_dependency_p);
  	}
      }
+   else
+     {
+       /* Try a template-id.  */
+       decl = cp_parser_template_id (parser, template_keyword_p,
+ 				    check_dependency_p);
+       if (decl == error_mark_node)
+ 	return error_mark_node;
+     }
  
    decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
  
*************** cp_parser_class_specifier (parser)
*** 11515,11521 ****
  	   parser->default_arg_types;
  	   parser->default_arg_types = TREE_CHAIN (parser->default_arg_types))
  	cp_parser_late_parsing_default_args
! 	  (parser, TREE_PURPOSE (parser->default_arg_types));
        
        /* Reverse the queue, so that we process it in the order the
  	 functions were declared.  */
--- 11545,11551 ----
  	   parser->default_arg_types;
  	   parser->default_arg_types = TREE_CHAIN (parser->default_arg_types))
  	cp_parser_late_parsing_default_args
! 	  (parser, TREE_PURPOSE (parser->default_arg_types), NULL_TREE);
        
        /* Reverse the queue, so that we process it in the order the
  	 functions were declared.  */
*************** cp_parser_lookup_name (parser, name, che
*** 13392,13400 ****
      {
        /* The error message we have to print is too complicated for
  	 cp_parser_error, so we incorporate its actions directly.  */
!       cp_parser_simulate_error (parser);
!       if (!cp_parser_parsing_tentatively (parser)
! 	  || cp_parser_committed_to_tentative_parse (parser))
  	{
  	  error ("reference to `%D' is ambiguous", name);
  	  print_candidates (decl);
--- 13422,13428 ----
      {
        /* The error message we have to print is too complicated for
  	 cp_parser_error, so we incorporate its actions directly.  */
!       if (!cp_parser_simulate_error (parser))
  	{
  	  error ("reference to `%D' is ambiguous", name);
  	  print_candidates (decl);
*************** cp_parser_late_parsing_for_member (parse
*** 14216,14226 ****
  
    /* If there are default arguments that have not yet been processed,
       take care of them now.  */
!   if (DECL_FUNCTION_MEMBER_P (member_function))
!     push_nested_class (DECL_CONTEXT (member_function), 1);
!   cp_parser_late_parsing_default_args (parser, TREE_TYPE (member_function));
!   if (DECL_FUNCTION_MEMBER_P (member_function))
!     pop_nested_class ();
  
    /* If the body of the function has not yet been parsed, parse it
       now.  */
--- 14244,14253 ----
  
    /* If there are default arguments that have not yet been processed,
       take care of them now.  */
!   cp_parser_late_parsing_default_args (parser, TREE_TYPE (member_function),
! 				       DECL_FUNCTION_MEMBER_P (member_function)
! 				       ? DECL_CONTEXT (member_function)
! 				       : NULL_TREE);
  
    /* If the body of the function has not yet been parsed, parse it
       now.  */
*************** cp_parser_late_parsing_for_member (parse
*** 14276,14287 ****
  }
  
  /* TYPE is a FUNCTION_TYPE or METHOD_TYPE which contains a parameter
!    with an unparsed DEFAULT_ARG.  Parse those default args now.  */
  
  static void
! cp_parser_late_parsing_default_args (parser, type)
!      cp_parser *parser;
!      tree type;
  {
    cp_lexer *saved_lexer;
    cp_token_cache *tokens;
--- 14303,14314 ----
  }
  
  /* TYPE is a FUNCTION_TYPE or METHOD_TYPE which contains a parameter
!    with an unparsed DEFAULT_ARG.  If non-NULL, SCOPE is the class in
!    whose context name lookups in the default argument should occur.
!    Parse the default args now.  */
  
  static void
! cp_parser_late_parsing_default_args (cp_parser *parser, tree type, tree scope)
  {
    cp_lexer *saved_lexer;
    cp_token_cache *tokens;
*************** cp_parser_late_parsing_default_args (par
*** 14312,14318 ****
--- 14339,14349 ----
        saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
        parser->local_variables_forbidden_p = true;
         /* Parse the assignment-expression.  */
+       if (scope)
+ 	push_nested_class (scope, 1);
        TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser);
+       if (scope)
+ 	pop_nested_class ();
  
         /* Restore saved state.  */
        parser->lexer = saved_lexer;
*************** cp_parser_require (parser, type, token_d
*** 14450,14463 ****
      return cp_lexer_consume_token (parser->lexer);
    else
      {
!       dyn_string_t error_msg;
! 
!       /* Format the error message.  */
!       error_msg = dyn_string_new (0);
!       dyn_string_append_cstr (error_msg, "expected ");
!       dyn_string_append_cstr (error_msg, token_desc);
!       cp_parser_error (parser, error_msg->s);
!       dyn_string_delete (error_msg);
        return NULL;
      }
  }
--- 14481,14489 ----
      return cp_lexer_consume_token (parser->lexer);
    else
      {
!       /* Output the MESSAGE -- unless we're parsing tentatively.  */
!       if (!cp_parser_simulate_error (parser))
! 	error ("expected %s", token_desc);
        return NULL;
      }
  }
*************** cp_parser_parse_definitely (parser)
*** 14759,14773 ****
  	parser->context->deferred_access_checks 
  	  = chainon (parser->context->deferred_access_checks,
  		     context->deferred_access_checks);
-       return true;
      }
    /* Otherwise, if errors occurred, roll back our state so that things
       are just as they were before we began the tentative parse.  */
    else
!     {
!       cp_lexer_rollback_tokens (parser->lexer);
!       return false;
!     }
  }
  
  /* Returns non-zero if we are parsing tentatively.  */
--- 14785,14800 ----
  	parser->context->deferred_access_checks 
  	  = chainon (parser->context->deferred_access_checks,
  		     context->deferred_access_checks);
      }
    /* Otherwise, if errors occurred, roll back our state so that things
       are just as they were before we began the tentative parse.  */
    else
!     cp_lexer_rollback_tokens (parser->lexer);
!   /* Add the context to the front of the free list.  */
!   context->next = cp_parser_context_free_list;
!   cp_parser_context_free_list = context;
! 
!   return !error_occurred;
  }
  
  /* Returns non-zero if we are parsing tentatively.  */



More information about the Gcc-patches mailing list