Mark Mitchell - C++ PATCH: Compile-time performance improvement (original) (raw)
This is the mail archive of the gcc-patches@gcc.gnu.orgmailing list for the GCC project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] |
- From: Mark Mitchell
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 26 Jan 2004 09:49:06 -0800
- Subject: C++ PATCH: Compile-time performance improvement
- Reply-to: mark at codesourcery dot com
This patch improves compile-time performance on the test case Richard Guenther sent me by about 11%.
The changes are:
(1) Do not call uses_template_parms when processing_template_decl will do.
(2) Reimplement uses_template_parms in terms of dependency-checking functions, which I finally convinced myself should actually be safe. (The worrisome cases are the ones where the "current instantiation" rules allow lookups through otherwise dependent typenames. If that does turn out to be a problem, the fix will be to call push_to_top_level before checking dependency.)
(3) Observe that cp_type_quals was a hot spot, being called a ton from comptypes, and avoid thh function call.
Tested on i686-pc-linux-gnu, applied on the mainline and on the branch.
-- Mark Mitchell CodeSourcery, LLC mark@codesourcery.com
2004-01-23 Mark Mitchell mark@codesourcery.com
* class.c (add_method): Just check processing_template_decl to
determine whether or not we are within a template.
* decl2.c (maybe_retrofit_in_chrg): Likewise.
* init.c (decl_constant_value): Check the type of the declaration,
not TREE_READONLY.
* name-lookup.c (maybe_push_to_top_level): Rename to ...
(push_to_top_level): ... this.
* name-lookup.h (maybe_push_to_top_level): Do not declare it.
* pt.c (push_template_decl_real): Reorder condition for speed.
(convert_template_argument): Use dependency-checking functions in
place of uses_template_parms.
(lookup_template_class): Avoid calling uses_template_parms more
than once.
(uses_template_parms): Reimplement, using dependency-checking
functions.
(instantiate_class_template): Use push_to_top_level, not
maybe_push_to_top_level.
(type_unification_real): Simplify.
(type_dependent_expression_p): Handle OFFSET_REFs and
TEMPLATE_DECLs.
(any_dependent_template_arguments_p): Handle multiple levels of
template argument.
* semantics.c (expand_or_defer_fn): Do not check
uses_template_parms for template instantiations.
* typeck.c (comptypes): Avoid calling cp_type_quals.Index: class.c
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.597
diff -c -5 -p -r1.597 class.c
*** class.c 21 Jan 2004 20:52:26 -0000 1.597
--- class.c 26 Jan 2004 17:36:44 -0000
*************** add_method (tree type, tree method, int
*** 864,874 ****
TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
}
}
}
! if (template_class_depth (type))
/* TYPE is a template class. Don't issue any errors now; wait
until instantiation time to complain. /
;
else
{
--- 864,874 ----
TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
}
}
}
! if (processing_template_decl)
/ TYPE is a template class. Don't issue any errors now; wait
until instantiation time to complain. */
;
else
{
Index: decl2.c
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.696
diff -c -5 -p -r1.696 decl2.c
*** decl2.c 21 Jan 2004 20:52:27 -0000 1.696
--- decl2.c 26 Jan 2004 17:36:45 -0000
*************** maybe_retrofit_in_chrg (tree fn)
*** 227,237 ****
if (DECL_HAS_IN_CHARGE_PARM_P (fn))
return;
/* When processing templates we can't know, in general, whether or
not we're going to have virtual baseclasses. /
! if (uses_template_parms (fn))
return;
/ We don't need an in-charge parameter for constructors that don't
have virtual bases. /
if (DECL_CONSTRUCTOR_P (fn)
--- 227,237 ----
if (DECL_HAS_IN_CHARGE_PARM_P (fn))
return;
/ When processing templates we can't know, in general, whether or
not we're going to have virtual baseclasses. /
! if (processing_template_decl)
return;
/ We don't need an in-charge parameter for constructors that don't
have virtual bases. */
if (DECL_CONSTRUCTOR_P (fn)
Index: init.c
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.358
diff -c -5 -p -r1.358 init.c
*** init.c 21 Jan 2004 20:52:27 -0000 1.358
--- init.c 26 Jan 2004 17:36:45 -0000
*************** decl_constant_value (tree decl)
*** 1608,1619 ****
return build (COND_EXPR,
TREE_TYPE (decl),
TREE_OPERAND (decl, 0), d1, d2);
}
! if (TREE_READONLY_DECL_P (decl)
! && ! TREE_THIS_VOLATILE (decl)
&& DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. /
--- 1608,1623 ----
return build (COND_EXPR,
TREE_TYPE (decl),
TREE_OPERAND (decl, 0), d1, d2);
}
! if (DECL_P (decl)
! && (/ Enumeration constants are constant. /
! TREE_CODE (decl) == CONST_DECL
! / And so are variables with a 'const' type -- unless they
! are also 'volatile'. /
! || CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))
&& DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/ This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. */
Index: name-lookup.c
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.c,v
retrieving revision 1.34
diff -c -5 -p -r1.34 name-lookup.c
*** name-lookup.c 15 Jan 2004 14:45:14 -0000 1.34
--- name-lookup.c 26 Jan 2004 17:36:45 -0000
*************** store_bindings (tree names, cxx_saved_bi
*** 4686,4696 ****
}
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, old_bindings);
}
void
! maybe_push_to_top_level (int pseudo)
{
struct saved_scope *s;
struct cp_binding_level *b;
cxx_saved_binding *old_bindings;
int need_pop;
--- 4686,4696 ----
}
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, old_bindings);
}
void
! push_to_top_level (void)
{
struct saved_scope *s;
struct cp_binding_level *b;
cxx_saved_binding old_bindings;
int need_pop;
*************** maybe_push_to_top_level (int pseudo)
*** 4721,4731 ****
/ Template IDs are inserted into the global level. If they were
inserted into namespace level, finish_file wouldn't find them
when doing pending instantiations. Therefore, don't stop at
namespace level, but continue until :: . /
! if (global_scope_p (b) || (pseudo && b->kind == sk_template_parms))
break;
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. /
--- 4721,4731 ----
/ Template IDs are inserted into the global level. If they were
inserted into namespace level, finish_file wouldn't find them
when doing pending instantiations. Therefore, don't stop at
namespace level, but continue until :: . /
! if (global_scope_p (b))
break;
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. */
*************** maybe_push_to_top_level (int pseudo)
*** 4747,4762 ****
current_function_decl = NULL_TREE;
VARRAY_TREE_INIT (current_lang_base, 10, "current_lang_base");
current_lang_name = lang_name_cplusplus;
current_namespace = global_namespace;
timevar_pop (TV_NAME_LOOKUP);
- }
- void
- push_to_top_level (void)
- {
- maybe_push_to_top_level (0); }
void pop_from_top_level (void) { --- 4747,4756 ---- Index: name-lookup.h
RCS file: /cvs/gcc/gcc/gcc/cp/name-lookup.h,v retrieving revision 1.15 diff -c -5 -p -r1.15 name-lookup.h *** name-lookup.h 15 Jan 2004 14:49:56 -0000 1.15 --- name-lookup.h 26 Jan 2004 17:36:45 -0000 *************** extern scope_kind innermost_scope_kind ( *** 262,272 **** extern cxx_scope *begin_scope (scope_kind, tree); extern void print_binding_stack (void); extern void print_binding_level (cxx_scope *); extern void push_to_top_level (void); extern void pop_from_top_level (void); - extern void maybe_push_to_top_level (int); extern void pop_everything (void); extern void keep_next_level (bool); extern bool is_ancestor (tree, tree); extern void push_scope (tree); extern void pop_scope (tree); --- 262,271 ---- Index: pt.c
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.818
diff -c -5 -p -r1.818 pt.c
*** pt.c 19 Jan 2004 20:33:21 -0000 1.818
--- pt.c 26 Jan 2004 17:36:46 -0000
*************** push_template_decl_real (tree decl, int
*** 2907,2920 ****
return decl;
}
else
tmpl = DECL_TI_TEMPLATE (decl);
! if (is_member_template (tmpl)
! && DECL_FUNCTION_TEMPLATE_P (tmpl)
&& DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl)
! && DECL_TEMPLATE_SPECIALIZATION (decl))
{
tree new_tmpl;
/* The declaration is a specialization of a member
template, declared outside the class. Therefore, the
--- 2907,2920 ----
return decl;
}
else
tmpl = DECL_TI_TEMPLATE (decl);
! if (DECL_FUNCTION_TEMPLATE_P (tmpl)
&& DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl)
! && DECL_TEMPLATE_SPECIALIZATION (decl)
! && is_member_template (tmpl))
{
tree new_tmpl;
/* The declaration is a specialization of a member
template, declared outside the class. Therefore, the
*************** lookup_template_class (tree d1,
*** 4273,4287 ****
= coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),
INNERMOST_TEMPLATE_ARGS (arglist),
template,
complain, /require_all_args=/1);
! if (arglist == error_mark_node
! || (!uses_template_parms (INNERMOST_TEMPLATE_ARGS (arglist))
! && check_instantiated_args (template,
! INNERMOST_TEMPLATE_ARGS (arglist),
! complain)))
/* We were unable to bind the arguments. /
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
/ In the scope of a template class, explicit references to the
template class refer to the type of the template, not any
--- 4273,4283 ----
= coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),
INNERMOST_TEMPLATE_ARGS (arglist),
template,
complain, /require_all_args=/1);
! if (arglist == error_mark_node)
/* We were unable to bind the arguments. /
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
/ In the scope of a template class, explicit references to the
template class refer to the type of the template, not any
*************** lookup_template_class (tree d1,
*** 4338,4347 ****
--- 4334,4351 ----
arguments still involve template parameters. Note that we set
IS_PARTIAL_INSTANTIATION for partial specializations as
well. /
is_partial_instantiation = uses_template_parms (arglist);
+ / If the deduced arguments are invalid, then the binding
+ failed. /
+ if (!is_partial_instantiation
+ && check_instantiated_args (template,
+ INNERMOST_TEMPLATE_ARGS (arglist),
+ complain))
+ POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
+
if (!is_partial_instantiation
&& !PRIMARY_TEMPLATE_P (template)
&& TREE_CODE (CP_DECL_CONTEXT (template)) == NAMESPACE_DECL)
{
found = xref_tag_from_type (TREE_TYPE (template),
*************** for_each_template_parm (tree t, tree_fn_
*** 4715,4725 ****
/ Returns true if T depends on any template parameter. /
int
uses_template_parms (tree t)
{
! return for_each_template_parm (t, 0, 0, NULL);
}
/ Returns true if T depends on any template parameter with level LEVEL. /
int
--- 4719,4756 ----
/ Returns true if T depends on any template parameter. /
int
uses_template_parms (tree t)
{
! bool dependent_p;
! int saved_processing_template_decl;
!
! saved_processing_template_decl = processing_template_decl;
! if (!saved_processing_template_decl)
! processing_template_decl = 1;
! if (TYPE_P (t))
! dependent_p = dependent_type_p (t);
! else if (TREE_CODE (t) == TREE_VEC)
! dependent_p = any_dependent_template_arguments_p (t);
! else if (TREE_CODE (t) == TREE_LIST)
! dependent_p = (uses_template_parms (TREE_VALUE (t))
! || uses_template_parms (TREE_CHAIN (t)));
! else if (DECL_P (t)
! || EXPR_P (t)
! || TREE_CODE (t) == TEMPLATE_PARM_INDEX
! || TREE_CODE (t) == OVERLOAD
! || TREE_CODE (t) == BASELINK
! || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
! dependent_p = (type_dependent_expression_p (t)
! || value_dependent_expression_p (t));
! else if (t == error_mark_node)
! dependent_p = false;
! else
! abort ();
! processing_template_decl = saved_processing_template_decl;
!
! return dependent_p;
}
/ Returns true if T depends on any template parameter with level LEVEL. /
int
*************** instantiate_class_template (tree type)
*** 5227,5237 ****
/ We may be in the middle of deferred access check. Disable
it now. /
push_deferring_access_checks (dk_no_deferred);
! maybe_push_to_top_level (uses_template_parms (type));
if (t)
{
/ This TYPE is actually an instantiation of a partial
specialization. We replace the innermost set of ARGS with
--- 5258,5268 ----
/* We may be in the middle of deferred access check. Disable
it now. /
push_deferring_access_checks (dk_no_deferred);
! push_to_top_level ();
if (t)
{
/ This TYPE is actually an instantiation of a partial
specialization. We replace the innermost set of ARGS with
*************** type_unification_real (tree tparms,
*** 8945,8965 ****
/* Conversions will be performed on a function argument that
corresponds with a function parameter that contains only
non-deducible template parameters and explicitly specified
template parameters. /
! if (! uses_template_parms (parm))
{
tree type;
if (!TYPE_P (arg))
type = TREE_TYPE (arg);
else
! {
! type = arg;
! arg = NULL_TREE;
! }
if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
{
if (same_type_p (parm, type))
continue;
--- 8976,8993 ----
/ Conversions will be performed on a function argument that
corresponds with a function parameter that contains only
non-deducible template parameters and explicitly specified
template parameters. /
! if (!uses_template_parms (parm))
{
tree type;
if (!TYPE_P (arg))
type = TREE_TYPE (arg);
else
! type = arg;
if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
{
if (same_type_p (parm, type))
continue;
*************** type_dependent_expression_p (tree expres
*** 11760,11774 ****
&& DECL_TEMPLATE_INFO (expression)
&& (any_dependent_template_arguments_p
(INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
return true;
if (TREE_TYPE (expression) == unknown_type_node)
{
if (TREE_CODE (expression) == ADDR_EXPR)
return type_dependent_expression_p (TREE_OPERAND (expression, 0));
! if (TREE_CODE (expression) == COMPONENT_REF)
{
if (type_dependent_expression_p (TREE_OPERAND (expression, 0)))
return true;
expression = TREE_OPERAND (expression, 1);
if (TREE_CODE (expression) == IDENTIFIER_NODE)
--- 11788,11807 ----
&& DECL_TEMPLATE_INFO (expression)
&& (any_dependent_template_arguments_p
(INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
return true;
+ if (TREE_CODE (expression) == TEMPLATE_DECL
+ && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression))
+ return false;
+
if (TREE_TYPE (expression) == unknown_type_node)
{
if (TREE_CODE (expression) == ADDR_EXPR)
return type_dependent_expression_p (TREE_OPERAND (expression, 0));
! if (TREE_CODE (expression) == COMPONENT_REF
! || TREE_CODE (expression) == OFFSET_REF)
{
if (type_dependent_expression_p (TREE_OPERAND (expression, 0)))
return true;
expression = TREE_OPERAND (expression, 1);
if (TREE_CODE (expression) == IDENTIFIER_NODE)
*************** dependent_template_arg_p (tree arg)
*** 11840,11856 ****
bool
any_dependent_template_arguments_p (tree args)
{
int i;
!
if (!args)
return false;
! for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
! if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
! return true;
return false;
}
/ Returns TRUE if the template TMPL is dependent. /
--- 11873,11894 ----
bool
any_dependent_template_arguments_p (tree args)
{
int i;
! int j;
!
if (!args)
return false;
! for (i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
! {
! tree level = TMPL_ARGS_LEVEL (args, i + 1);
! for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
! if (dependent_template_arg_p (TREE_VEC_ELT (level, j)))
! return true;
! }
return false;
}
/ Returns TRUE if the template TMPL is dependent. */
Index: semantics.c
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.382
diff -c -5 -p -r1.382 semantics.c
*** semantics.c 19 Jan 2004 20:33:22 -0000 1.382
--- semantics.c 26 Jan 2004 17:36:46 -0000
*************** expand_body (tree fn)
*** 2914,2931 ****
void
expand_or_defer_fn (tree fn)
{
/* When the parser calls us after finishing the body of a template
! function, we don't really want to expand the body. When we're
! processing an in-class definition of an inline function,
! PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
! to look at the function itself. /
! if (processing_template_decl
! || (DECL_LANG_SPECIFIC (fn)
! && DECL_TEMPLATE_INFO (fn)
! && uses_template_parms (DECL_TI_ARGS (fn))))
{
/ Normally, collection only occurs in rest_of_compilation. So,
if we don't collect here, we never collect junk generated
during the processing of templates until we hit a
non-template function. /
--- 2914,2925 ----
void
expand_or_defer_fn (tree fn)
{
/ When the parser calls us after finishing the body of a template
! function, we don't really want to expand the body. /
! if (processing_template_decl)
{
/ Normally, collection only occurs in rest_of_compilation. So,
if we don't collect here, we never collect junk generated
during the processing of templates until we hit a
non-template function. */
Index: typeck.c
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v retrieving revision 1.520 diff -c -5 -p -r1.520 typeck.c *** typeck.c 21 Jan 2004 20:52:28 -0000 1.520 --- typeck.c 26 Jan 2004 17:36:46 -0000 *************** comptypes (tree t1, tree t2, int strict) *** 961,981 ****
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
return false;! /* Qualifiers must match. */ ! if (cp_type_quals (t1) != cp_type_quals (t2)) return false; if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2)) return false;
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
qualifiers (just above). */! if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) return true;
if (!(*targetm.comp_type_attributes) (t1, t2))
return false;--- 961,984 ----
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
return false;! /* Qualifiers must match. For array types, we will check when we ! recur on the array element types. */ ! if (TREE_CODE (t1) != ARRAY_TYPE ! && TYPE_QUALS (t1) != TYPE_QUALS (t2)) return false; if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2)) return false;
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
qualifiers (just above). */! if (TREE_CODE (t1) != ARRAY_TYPE ! && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) return true;
if (!(*targetm.comp_type_attributes) (t1, t2))
return false;- Follow-Ups:
- Re: C++ PATCH: Compile-time performance improvement
* From: Gabriel Dos Reis - Re: C++ PATCH: Compile-time performance improvement
* From: Jason Merrill - Re: C++ PATCH: Compile-time performance improvement
* From: Jan Hubicka
- Re: C++ PATCH: Compile-time performance improvement
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |