diff options
author | Jan Hubicka <jh@suse.cz> | 2010-08-21 14:36:19 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2010-08-21 12:36:19 +0000 |
commit | 9e97ff6183dd75e8d0cd2831e87646f01d3b4171 (patch) | |
tree | a5bb59f19d8d091599bf4239efb438a415ce4c98 /gcc/ipa.c | |
parent | 000eef232bb6480f70b68c48c7d689e958ee5059 (diff) | |
download | gcc-9e97ff6183dd75e8d0cd2831e87646f01d3b4171.zip gcc-9e97ff6183dd75e8d0cd2831e87646f01d3b4171.tar.gz gcc-9e97ff6183dd75e8d0cd2831e87646f01d3b4171.tar.bz2 |
tree-pass.h (pass_ipa_cdtor_merge): New function.
* tree-pass.h (pass_ipa_cdtor_merge): New function.
* cgraphunit.c (static_ctors, static_dtors): Move to ipa.c; make
heap allocated.
(record_cdtor_fn): Move to ipa.c; do not test for
have_ctors_dtors.
(build_cdtor): Move to ipa.c; add code avoiding construction
when target have ctors/dtors and there is only one ctor/dtor at given
priority.
(compare_ctor, compare_dtor): Move to ipa.c; use DECL_UID to stabilize sort;
reverse order of constructors.
(cgraph_build_cdtor_fns):Move to ipa.c; rename to build_cdtor_fns.
(cgraph_finalize_function): Do not call record_cdtor_fn.
(cgraph_finalize_compilation_unit): Do not call cgraph_build_cdtor_fns.
(cgraph_build_static_cdtor): Move to ipa.c.
* ipa.c: Include target.h and tree-iterator.h.
(cgraph_build_static_cdtor, static_ctors, static_dtors,
record_cdtor_fn, build_cdtor, compare_ctor, compare_dtor,
build_cdtor_fns, ipa_cdtor_merge, gate_ipa_cdtor_merge,
pass_ipa_cdtor_merge): New.
* passes.c (init_optimization_passes): Enqueue pass_ipa_cdtor_merge.
* ipa-prop.c (update_indirect_edges_after_inlining): Avoid out of bounds access.
From-SVN: r163443
Diffstat (limited to 'gcc/ipa.c')
-rw-r--r-- | gcc/ipa.c | 312 |
1 files changed, 312 insertions, 0 deletions
@@ -29,6 +29,8 @@ along with GCC; see the file COPYING3. If not see #include "ggc.h" #include "flags.h" #include "pointer-set.h" +#include "target.h" +#include "tree-iterator.h" /* Fill array order with all nodes with output flag set in the reverse topological order. */ @@ -1317,3 +1319,313 @@ struct ipa_opt_pass_d pass_ipa_profile = NULL, /* function_transform */ NULL /* variable_transform */ }; + +/* Generate and emit a static constructor or destructor. WHICH must + be one of 'I' (for a constructor) or 'D' (for a destructor). BODY + is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the + initialization priority for this constructor or destructor. */ + +void +cgraph_build_static_cdtor (char which, tree body, int priority) +{ + static int counter = 0; + char which_buf[16]; + tree decl, name, resdecl; + + /* The priority is encoded in the constructor or destructor name. + collect2 will sort the names and arrange that they are called at + program startup. */ + sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++); + name = get_file_function_name (which_buf); + + decl = build_decl (input_location, FUNCTION_DECL, name, + build_function_type_list (void_type_node, NULL_TREE)); + current_function_decl = decl; + + resdecl = build_decl (input_location, + RESULT_DECL, NULL_TREE, void_type_node); + DECL_ARTIFICIAL (resdecl) = 1; + DECL_RESULT (decl) = resdecl; + DECL_CONTEXT (resdecl) = decl; + + allocate_struct_function (decl, false); + + TREE_STATIC (decl) = 1; + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1; + DECL_SAVED_TREE (decl) = body; + if (!targetm.have_ctors_dtors) + { + TREE_PUBLIC (decl) = 1; + DECL_PRESERVE_P (decl) = 1; + } + DECL_UNINLINABLE (decl) = 1; + + DECL_INITIAL (decl) = make_node (BLOCK); + TREE_USED (DECL_INITIAL (decl)) = 1; + + DECL_SOURCE_LOCATION (decl) = input_location; + cfun->function_end_locus = input_location; + + switch (which) + { + case 'I': + DECL_STATIC_CONSTRUCTOR (decl) = 1; + decl_init_priority_insert (decl, priority); + break; + case 'D': + DECL_STATIC_DESTRUCTOR (decl) = 1; + decl_fini_priority_insert (decl, priority); + break; + default: + gcc_unreachable (); + } + + gimplify_function_tree (decl); + + cgraph_add_new_function (decl, false); + + set_cfun (NULL); + current_function_decl = NULL; +} + + +/* A vector of FUNCTION_DECLs declared as static constructors. */ +static VEC(tree, heap) *static_ctors; +/* A vector of FUNCTION_DECLs declared as static destructors. */ +static VEC(tree, heap) *static_dtors; + +/* When target does not have ctors and dtors, we call all constructor + and destructor by special initialization/destruction function + recognized by collect2. + + When we are going to build this function, collect all constructors and + destructors and turn them into normal functions. */ + +static void +record_cdtor_fn (struct cgraph_node *node) +{ + if (DECL_STATIC_CONSTRUCTOR (node->decl)) + VEC_safe_push (tree, heap, static_ctors, node->decl); + if (DECL_STATIC_DESTRUCTOR (node->decl)) + VEC_safe_push (tree, heap, static_dtors, node->decl); + node = cgraph_node (node->decl); + node->local.disregard_inline_limits = 1; +} + +/* Define global constructors/destructor functions for the CDTORS, of + which they are LEN. The CDTORS are sorted by initialization + priority. If CTOR_P is true, these are constructors; otherwise, + they are destructors. */ + +static void +build_cdtor (bool ctor_p, tree *cdtors, size_t len) +{ + size_t i,j; + + i = 0; + while (i < len) + { + tree body; + tree fn; + priority_type priority; + + priority = 0; + body = NULL_TREE; + j = i; + do + { + priority_type p; + fn = cdtors[i]; + p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn); + if (j == i) + priority = p; + else if (p != priority) + break; + j++; + } + while (j < len); + + /* When there is only once constructor and target supports them, do nothing. */ + if (j == i + 1 + && targetm.have_ctors_dtors) + { + i++; + continue; + } + /* Find the next batch of constructors/destructors with the same + initialization priority. */ + do + { + priority_type p; + tree call; + fn = cdtors[i]; + p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn); + if (p != priority) + break; + call = build_call_expr (fn, 0); + if (ctor_p) + DECL_STATIC_CONSTRUCTOR (fn) = 0; + else + DECL_STATIC_DESTRUCTOR (fn) = 0; + /* We do not want to optimize away pure/const calls here. + When optimizing, these should be already removed, when not + optimizing, we want user to be able to breakpoint in them. */ + TREE_SIDE_EFFECTS (call) = 1; + append_to_statement_list (call, &body); + ++i; + } + while (i < len); + gcc_assert (body != NULL_TREE); + /* Generate a function to call all the function of like + priority. */ + cgraph_build_static_cdtor (ctor_p ? 'I' : 'D', body, priority); + } +} + +/* Comparison function for qsort. P1 and P2 are actually of type + "tree *" and point to static constructors. DECL_INIT_PRIORITY is + used to determine the sort order. */ + +static int +compare_ctor (const void *p1, const void *p2) +{ + tree f1; + tree f2; + int priority1; + int priority2; + + f1 = *(const tree *)p1; + f2 = *(const tree *)p2; + priority1 = DECL_INIT_PRIORITY (f1); + priority2 = DECL_INIT_PRIORITY (f2); + + if (priority1 < priority2) + return -1; + else if (priority1 > priority2) + return 1; + else + /* Ensure a stable sort. Constructors are executed in backwarding + order to make LTO initialize braries first. */ + return DECL_UID (f2) - DECL_UID (f1); +} + +/* Comparison function for qsort. P1 and P2 are actually of type + "tree *" and point to static destructors. DECL_FINI_PRIORITY is + used to determine the sort order. */ + +static int +compare_dtor (const void *p1, const void *p2) +{ + tree f1; + tree f2; + int priority1; + int priority2; + + f1 = *(const tree *)p1; + f2 = *(const tree *)p2; + priority1 = DECL_FINI_PRIORITY (f1); + priority2 = DECL_FINI_PRIORITY (f2); + + if (priority1 < priority2) + return -1; + else if (priority1 > priority2) + return 1; + else + /* Ensure a stable sort. */ + return DECL_UID (f1) - DECL_UID (f2); +} + +/* Generate functions to call static constructors and destructors + for targets that do not support .ctors/.dtors sections. These + functions have magic names which are detected by collect2. */ + +static void +build_cdtor_fns (void) +{ + if (!VEC_empty (tree, static_ctors)) + { + gcc_assert (!targetm.have_ctors_dtors || in_lto_p); + qsort (VEC_address (tree, static_ctors), + VEC_length (tree, static_ctors), + sizeof (tree), + compare_ctor); + build_cdtor (/*ctor_p=*/true, + VEC_address (tree, static_ctors), + VEC_length (tree, static_ctors)); + VEC_truncate (tree, static_ctors, 0); + } + + if (!VEC_empty (tree, static_dtors)) + { + gcc_assert (!targetm.have_ctors_dtors || in_lto_p); + qsort (VEC_address (tree, static_dtors), + VEC_length (tree, static_dtors), + sizeof (tree), + compare_dtor); + build_cdtor (/*ctor_p=*/false, + VEC_address (tree, static_dtors), + VEC_length (tree, static_dtors)); + VEC_truncate (tree, static_dtors, 0); + } +} + +/* Look for constructors and destructors and produce function calling them. + This is needed for targets not supporting ctors or dtors, but we perform the + transformation also at linktime to merge possibly numberous + constructors/destructors into single function to improve code locality and + reduce size. */ + +static unsigned int +ipa_cdtor_merge (void) +{ + struct cgraph_node *node; + for (node = cgraph_nodes; node; node = node->next) + if (node->analyzed + && (DECL_STATIC_CONSTRUCTOR (node->decl) + || DECL_STATIC_DESTRUCTOR (node->decl))) + record_cdtor_fn (node); + build_cdtor_fns (); + VEC_free (tree, heap, static_ctors); + VEC_free (tree, heap, static_dtors); + return 0; +} + +/* Perform the pass when we have no ctors/dtors support + or at LTO time to merge multiple constructors into single + function. */ + +static bool +gate_ipa_cdtor_merge (void) +{ + return !targetm.have_ctors_dtors || (optimize && in_lto_p); +} + +struct ipa_opt_pass_d pass_ipa_cdtor_merge = +{ + { + IPA_PASS, + "cdtor", /* name */ + gate_ipa_cdtor_merge, /* gate */ + ipa_cdtor_merge, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_CGRAPHOPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + }, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL /* variable_transform */ +}; |