diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 584c9714d42..cde57345880 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,31 @@ 1999-04-30 Mark Mitchell + * class.c (build_vtable): Use build_lang_decl when building + vtables, not just build_decl. + (prepare_fresh_vtable): Likewise. + * decl.c (wrapup_globals_for_namespace): Mark vtables as + DECL_EXTERNAL when calling wrapup_global_declarations. + * decl2.c (priority_info_s): Add initializations_p and + destructions_p members. + (finish_vtable_vardecl): Use TREE_SYMBOL_REFERENCED, not TREE_USED, + when deciding what vtables to write out. + (ssdf_decls): New variable. + (ssdf_decls_used): Likewise. + (start_static_storage_duration_function): Deal with being called + multiple times. Avoid inlining this function. + (generate_inits_for_priority): Deal with reuse of priority map. + (get_priority_info): Clear initializations_p and destructions_p. + (do_static_initialization): Tweak comment. + (do_static_destruction): Likewise. Fix condition on sentries for + destruction. + (generate_ctor_or_dtor_function): Call all of the static storage + duration functions. + (generate_ctor_or_dtor_function_for_priority): Check + initializations_p and destructions_p to see what priorities need + initialization functions. + (finish_file): Rework to generate multiple static storage duration + functions, rather than just one. + * typeck.c (build_const_cast): Tweak last change to handle templates correctly. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 9a20b5b093f..d3d544f05e5 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -712,7 +712,7 @@ build_vtable (binfo, type) tree offset; virtuals = copy_list (BINFO_VIRTUALS (binfo)); - decl = build_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo))); + decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo))); /* Now do rtti stuff. */ offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE); @@ -722,7 +722,7 @@ build_vtable (binfo, type) else { virtuals = NULL_TREE; - decl = build_decl (VAR_DECL, name, void_type_node); + decl = build_lang_decl (VAR_DECL, name, void_type_node); } #ifdef GATHER_STATISTICS @@ -872,7 +872,7 @@ prepare_fresh_vtable (binfo, for_type) buf2 = new_buf2; } - new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); + new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); /* Remember which class this vtable is really for. */ DECL_CONTEXT (new_decl) = for_type; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 05ee40863ca..b37dbc8e6bc 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1988,6 +1988,7 @@ wrapup_globals_for_namespace (namespace, data) int len = list_length (globals); tree *vec = (tree *) alloca (sizeof (tree) * len); int i; + int result; tree decl; int last_time = (data != 0); @@ -2001,11 +2002,35 @@ wrapup_globals_for_namespace (namespace, data) for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) vec[len - i - 1] = decl; - if (!last_time) - return wrapup_global_declarations (vec, len); + if (last_time) + { + check_global_declarations (vec, len); + return 0; + } - check_global_declarations (vec, len); - return 0; + /* Temporarily mark vtables as external. That prevents + wrapup_global_declarations from writing them out; we must process + them ourselves in finish_vtable_vardecl. */ + for (i = 0; i < len; ++i) + if (vtable_decl_p (vec[i], /*data=*/0)) + { + DECL_NOT_REALLY_EXTERN (vec[i]) = 1; + DECL_EXTERNAL (vec[i]) = 1; + } + + /* Write out any globals that need to be output. */ + result = wrapup_global_declarations (vec, len); + + /* Undo the hack to DECL_EXTERNAL above. */ + for (i = 0; i < len; ++i) + if (vtable_decl_p (vec[i], /*data=*/0) + && DECL_NOT_REALLY_EXTERN (vec[i])) + { + DECL_NOT_REALLY_EXTERN (vec[i]) = 0; + DECL_EXTERNAL (vec[i]) = 0; + } + + return result; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 68f4f134889..79261a0f7f1 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -59,6 +59,12 @@ typedef struct priority_info_s { /* A label indicating where we should generate the next destruction with this priority. */ rtx destruction_sequence; + /* Non-zero if there have been any initializations at this priority + throughout the translation unit. */ + int initializations_p; + /* Non-zero if there have been any destructions at this priority + throughout the translation unit. */ + int destructions_p; } *priority_info; static tree get_sentry PROTO((tree)); @@ -2655,7 +2661,9 @@ finish_vtable_vardecl (t, data) import_export_vtable (vars, ctype, 1); if (! DECL_EXTERNAL (vars) - && (DECL_INTERFACE_KNOWN (vars) || TREE_USED (vars)) + && (DECL_INTERFACE_KNOWN (vars) + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)) + || (hack_decl_function_context (vars) && TREE_USED (vars))) && ! TREE_ASM_WRITTEN (vars)) { /* Write it out. */ @@ -2700,7 +2708,7 @@ finish_vtable_vardecl (t, data) return 1; } - else if (! TREE_USED (vars)) + else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars))) /* We don't know what to do with this one yet. */ return 0; @@ -2973,6 +2981,11 @@ static tree priority_decl; /* The declaration for the static storage duration function. */ static tree ssdf_decl; +/* All the static storage duration functions created in this + translation unit. */ +static varray_type ssdf_decls; +static size_t ssdf_decls_used; + /* A map from priority levels to information about that priority level. There may be many such levels, so efficient lookup is important. */ @@ -2993,8 +3006,22 @@ static splay_tree priority_info_map; static void start_static_storage_duration_function () { + static unsigned ssdf_number; + tree parm_types; tree type; + char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; + + /* Create the identifier for this function. It will be of the form + SSDF_IDENTIFIER_. */ + sprintf (id, "%s_%u", SSDF_IDENTIFIER, ssdf_number++); + if (ssdf_number == 0) + { + /* Overflow occurred. That means there are at least 4 billion + initialization functions. */ + sorry ("too many initialization functions required"); + my_friendly_abort (19990430); + } /* Create the parameters. */ parm_types = void_list_node; @@ -3004,11 +3031,35 @@ start_static_storage_duration_function () /* Create the FUNCTION_DECL itself. */ ssdf_decl = build_lang_decl (FUNCTION_DECL, - get_identifier (SSDF_IDENTIFIER), + get_identifier (id), type); TREE_PUBLIC (ssdf_decl) = 0; DECL_ARTIFICIAL (ssdf_decl) = 1; - DECL_INLINE (ssdf_decl) = 1; + + /* Put this function in the list of functions to be called from the + static constructors and destructors. */ + if (!ssdf_decls) + { + VARRAY_TREE_INIT (ssdf_decls, 32, "ssdf_decls"); + + /* Take this opportunity to initialize the map from priority + numbers to information about that priority level. */ + priority_info_map = splay_tree_new (splay_tree_compare_ints, + /*delete_key_fn=*/0, + /*delete_value_fn=*/ + (splay_tree_delete_value_fn) &free); + + /* We always need to generate functions for the + DEFAULT_INIT_PRIORITY so enter it now. That way when we walk + priorities later, we'll be sure to find the + DEFAULT_INIT_PRIORITY. */ + get_priority_info (DEFAULT_INIT_PRIORITY); + } + + if (ssdf_decls_used == ssdf_decls->num_elements) + VARRAY_GROW (ssdf_decls, 2 * ssdf_decls_used); + VARRAY_TREE (ssdf_decls, ssdf_decls_used) = ssdf_decl; + ++ssdf_decls_used; /* Create the argument list. */ initialize_p_decl = build_decl (PARM_DECL, @@ -3045,12 +3096,10 @@ start_static_storage_duration_function () push_momentary (); expand_start_bindings (0); - /* Initialize the map from priority numbers to information about - that priority level. */ - priority_info_map = splay_tree_new (splay_tree_compare_ints, - /*delete_key_fn=*/0, - /*delete_value_fn=*/ - (splay_tree_delete_value_fn) &free); + /* This function must not be deferred because we are depending on + its compilation to tell us what is TREE_SYMBOL_REFERENCED. */ + current_function_cannot_inline + = "static storage duration functions cannot be inlined"; } /* Generate the initialization code for the priority indicated in N. */ @@ -3093,6 +3142,8 @@ generate_inits_for_priority (n, data) end_sequence (); emit_insn (insns); + pi->initialization_sequence = NULL_RTX; + pi->initializations_p = 1; } /* Do the destructions. */ @@ -3106,6 +3157,8 @@ generate_inits_for_priority (n, data) end_sequence (); emit_insn (insns); + pi->destruction_sequence = NULL_RTX; + pi->destructions_p = 1; } /* Close out the conditionals. */ @@ -3154,6 +3207,8 @@ get_priority_info (priority) pi = (priority_info) xmalloc (sizeof (struct priority_info_s)); pi->initialization_sequence = NULL_RTX; pi->destruction_sequence = NULL_RTX; + pi->initializations_p = 0; + pi->destructions_p = 0; splay_tree_insert (priority_info_map, (splay_tree_key) priority, (splay_tree_value) pi); @@ -3221,7 +3276,7 @@ do_static_initialization (decl, init, sentry, priority) expand_end_target_temps (); /* Cleanup any deferred pops from function calls. This would be done - by expand_end_cond, but we also need it when !sentry, since we are + by expand_end_cond, but we also need it when !SENTRY, since we are constructing these sequences by parts. */ do_pending_stack_adjust (); @@ -3266,21 +3321,21 @@ do_static_destruction (decl, sentry, priority) variable in question. */ emit_note (input_filename, lineno); - /* If there's a SENTRY, we only do the initialization if it is - one, i.e., if we are the last to initialize it. */ + /* If there's a SENTRY, we only do the destruction if it is one, + i.e., if we are the last to destroy it. */ if (sentry) expand_start_cond (build_binary_op (EQ_EXPR, build_unary_op (PREDECREMENT_EXPR, sentry, /*nonconvert=*/1), - integer_one_node), + integer_zero_node), /*exit_flag=*/0); /* Actually to the destruction. */ expand_expr_stmt (build_cleanup (decl)); /* Cleanup any deferred pops from function calls. This would be done - by expand_end_cond, but we also need it when !sentry, since we are + by expand_end_cond, but we also need it when !SENTRY, since we are constructing these sequences by parts. */ do_pending_stack_adjust (); @@ -3390,6 +3445,7 @@ generate_ctor_or_dtor_function (constructor_p, priority) { char function_key; tree arguments; + size_t i; /* We use `I' to indicate initialization and `D' to indicate destruction. */ @@ -3403,11 +3459,15 @@ generate_ctor_or_dtor_function (constructor_p, priority) /* Call the static storage duration function with appropriate arguments. */ - arguments = tree_cons (NULL_TREE, build_int_2 (priority, 0), - NULL_TREE); - arguments = tree_cons (NULL_TREE, build_int_2 (constructor_p, 0), - arguments); - expand_expr_stmt (build_function_call (ssdf_decl, arguments)); + for (i = 0; i < ssdf_decls_used; ++i) + { + arguments = tree_cons (NULL_TREE, build_int_2 (priority, 0), + NULL_TREE); + arguments = tree_cons (NULL_TREE, build_int_2 (constructor_p, 0), + arguments); + expand_expr_stmt (build_function_call (VARRAY_TREE (ssdf_decls, i), + arguments)); + } /* If we're generating code for the DEFAULT_INIT_PRIORITY, throw in calls to any functions marked with attributes indicating that @@ -3427,28 +3487,23 @@ generate_ctor_or_dtor_function (constructor_p, priority) } /* Generate constructor and destructor functions for the priority - indicated by N. DATA is really an `int*', and it set to `1' if we - process the DEFAULT_INIT_PRIORITY. */ + indicated by N. */ static int generate_ctor_and_dtor_functions_for_priority (n, data) splay_tree_node n; - void *data; + void *data ATTRIBUTE_UNUSED; { int priority = (int) n->key; priority_info pi = (priority_info) n->value; - int *did_default_priority_p = (int*) data; - - if (priority == DEFAULT_INIT_PRIORITY) - *did_default_priority_p = 1; /* Generate the functions themselves, but only if they are really needed. */ - if (pi->initialization_sequence + if (pi->initializations_p || (priority == DEFAULT_INIT_PRIORITY && static_ctors)) generate_ctor_or_dtor_function (/*constructor_p=*/1, priority); - if (pi->destruction_sequence + if (pi->destructions_p || (priority == DEFAULT_INIT_PRIORITY && static_dtors)) generate_ctor_or_dtor_function (/*constructor_p=*/0, priority); @@ -3467,7 +3522,6 @@ finish_file () { extern int lineno; int start_time, this_time; - int did_default_priority_p = 0; tree vars; int reconsider; size_t i; @@ -3509,18 +3563,18 @@ finish_file () start_time = get_run_time (); permanent_allocation (1); - /* Create the function that will contain all initializations and - destructions for objects with static storage duration. We cannot - conclude that because a symbol is not TREE_SYMBOL_REFERENCED the - corresponding entity is not used until we call finish_function - for the static storage duration function. We give C linkage to - static constructors and destructors. */ - push_lang_context (lang_name_c); - start_static_storage_duration_function (); - push_to_top_level (); - do { + /* We need to start a new initialization function each time + through the loop. That's because we need to know which + vtables have been referenced, and TREE_SYMBOL_REFERENCED + isn't computed until a function is finished, and written out. + That's a deficiency in the back-end. When this is fixed, + these initialization functions could all become inline, with + resulting performance improvements. */ + start_static_storage_duration_function (); + push_to_top_level (); + reconsider = 0; /* If there are templates that we've put off instantiating, do @@ -3560,8 +3614,11 @@ finish_file () reconsider = 1; vars = TREE_CHAIN (vars); } - push_to_top_level (); + /* Finish up the static storage duration function for this + round. */ + finish_static_storage_duration_function (); + /* Go through the various inline functions, and see if any need synthesizing. */ for (i = 0; i < saved_inlines_used; ++i) @@ -3586,81 +3643,24 @@ finish_file () reconsider = 1; } } - } - while (reconsider); - /* Finish up the static storage duration function, now that we now - there can be no more things in need of initialization or - destruction. */ - pop_from_top_level (); - finish_static_storage_duration_function (); + /* Mark all functions that might deal with exception-handling as + referenced. */ + mark_all_runtime_matches (); - /* Generate initialization and destruction functions for all - priorities for which they are required. */ - if (priority_info_map) - splay_tree_foreach (priority_info_map, - generate_ctor_and_dtor_functions_for_priority, - &did_default_priority_p); - - if (!did_default_priority_p) - { - /* Even if there were no explicit initializations or - destructions required, we may still have to handle the - default priority if there functions declared as constructors - or destructors via attributes. */ - if (static_ctors) - generate_ctor_or_dtor_function (/*constructor_p=*/1, - DEFAULT_INIT_PRIORITY); - if (static_dtors) - generate_ctor_or_dtor_function (/*constructor_p=*/0, - DEFAULT_INIT_PRIORITY); - } - - /* We're done with the splay-tree now. */ - if (priority_info_map) - splay_tree_delete (priority_info_map); - - /* We're done with static constructors, so we can go back to "C++" - linkage now. */ - pop_lang_context (); - - /* Mark all functions that might deal with exception-handling as - referenced. */ - mark_all_runtime_matches (); - - /* Now delete from the chain of variables all virtual function tables. - We output them all ourselves, because each will be treated - specially. */ - walk_globals (vtable_decl_p, prune_vtable_vardecl, /*data=*/0); - - /* We'll let wrapup_global_declarations handle the inline functions, - but it will be fooled by DECL_NOT_REALL_EXTERN funtions, so we - fix them up here. */ - for (i = 0; i < saved_inlines_used; ++i) - { - tree decl = VARRAY_TREE (saved_inlines, i); - - if (DECL_NOT_REALLY_EXTERN (decl) && !DECL_COMDAT (decl) - && DECL_INITIAL (decl)) - DECL_EXTERNAL (decl) = 0; - } - - /* We haven't handled non-local objects that don't need dynamic - initialization. Do that now. */ - do - { - reconsider = 0; - - /* Above, we hung back on weak functions; they will be defined - where they are needed. But, here we loop again, so that we - output the things that *are* needed. */ + /* We lie to the back-end, pretending that some functions are + not defined when they really are. This keeps these functions + from being put out unncessarily. But, we must stop lying + when the functions are referenced, or if they are not comdat + since they need to be put out now. */ for (i = 0; i < saved_inlines_used; ++i) { tree decl = VARRAY_TREE (saved_inlines, i); if (DECL_NOT_REALLY_EXTERN (decl) && DECL_INITIAL (decl) - && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + && (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + || !DECL_COMDAT (decl))) DECL_EXTERNAL (decl) = 0; } @@ -3668,7 +3668,6 @@ finish_file () && wrapup_global_declarations (&VARRAY_TREE (saved_inlines, 0), saved_inlines_used)) reconsider = 1; - if (walk_namespaces (wrapup_globals_for_namespace, /*data=*/0)) reconsider = 1; @@ -3686,9 +3685,32 @@ finish_file () && wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0), pending_statics_used)) reconsider = 1; - } + } while (reconsider); + /* We give C linkage to static constructors and destructors. */ + push_lang_context (lang_name_c); + + /* Generate initialization and destruction functions for all + priorities for which they are required. */ + if (priority_info_map) + splay_tree_foreach (priority_info_map, + generate_ctor_and_dtor_functions_for_priority, + /*data=*/0); + + /* We're done with the splay-tree now. */ + if (priority_info_map) + splay_tree_delete (priority_info_map); + + /* We're done with static constructors, so we can go back to "C++" + linkage now. */ + pop_lang_context (); + + /* Now delete from the chain of variables all virtual function tables. + We output them all ourselves, because each will be treated + specially. */ + walk_globals (vtable_decl_p, prune_vtable_vardecl, /*data=*/0); + /* Now, issue warnings about static, but not defined, functions, etc. */ walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider);