From a53e74714e8c41c838809e7304eed308d75a6a7c Mon Sep 17 00:00:00 2001 From: hubicka Date: Sat, 21 Aug 2010 12:36:19 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163443 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 24 ++++ gcc/cgraphunit.c | 242 --------------------------------------- gcc/ipa-prop.c | 3 +- gcc/ipa-pure-const.c | 6 +- gcc/ipa.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/passes.c | 1 + gcc/tree-pass.h | 1 + 7 files changed, 343 insertions(+), 246 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4f467ca..7b87da3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,29 @@ 2010-08-20 Jan Hubicka + * 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. + +2010-08-20 Jan Hubicka + PR c++/45307 PR c++/17736 * cgraph.h (cgraph_only_called_directly_p, diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 57b7a8d..024a3bc 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -147,174 +147,9 @@ static void cgraph_analyze_function (struct cgraph_node *); FILE *cgraph_dump_file; -/* A vector of FUNCTION_DECLs declared as static constructors. */ -static GTY (()) VEC(tree, gc) *static_ctors; -/* A vector of FUNCTION_DECLs declared as static destructors. */ -static GTY (()) VEC(tree, gc) *static_dtors; - /* Used for vtable lookup in thunk adjusting. */ static GTY (()) tree vtable_entry_type; -/* 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 (tree fndecl) -{ - struct cgraph_node *node; - if (targetm.have_ctors_dtors - || (!DECL_STATIC_CONSTRUCTOR (fndecl) - && !DECL_STATIC_DESTRUCTOR (fndecl))) - return; - - if (DECL_STATIC_CONSTRUCTOR (fndecl)) - { - VEC_safe_push (tree, gc, static_ctors, fndecl); - DECL_STATIC_CONSTRUCTOR (fndecl) = 0; - } - if (DECL_STATIC_DESTRUCTOR (fndecl)) - { - VEC_safe_push (tree, gc, static_dtors, fndecl); - DECL_STATIC_DESTRUCTOR (fndecl) = 0; - } - node = cgraph_node (fndecl); - node->local.disregard_inline_limits = 1; - cgraph_mark_reachable_node (node); -} - -/* 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; - - i = 0; - while (i < len) - { - tree body; - tree fn; - priority_type priority; - - priority = 0; - body = NULL_TREE; - /* 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 (!body) - priority = p; - else if (p != priority) - break; - call = build_call_expr (fn, 0); - 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. */ - return (const tree *)p1 - (const tree *)p2; -} - -/* 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 (const tree *)p1 - (const tree *)p2; -} - -/* 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 -cgraph_build_cdtor_fns (void) -{ - if (!VEC_empty (tree, static_ctors)) - { - gcc_assert (!targetm.have_ctors_dtors); - 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); - 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); - } -} - /* Determine if function DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury. */ @@ -519,7 +354,6 @@ cgraph_finalize_function (tree decl, bool nested) node->local.finalized = true; node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; node->finalized_by_frontend = true; - record_cdtor_fn (node->decl); if (cgraph_decide_is_function_needed (node, decl)) cgraph_mark_needed_node (node); @@ -1155,10 +989,6 @@ cgraph_finalize_compilation_unit (void) /* Emit size functions we didn't inline. */ finalize_size_functions (); - /* Call functions declared with the "constructor" or "destructor" - attribute. */ - cgraph_build_cdtor_fns (); - /* Mark alias targets necessary and emit diagnostics. */ finish_aliases_1 (); @@ -2007,78 +1837,6 @@ cgraph_optimize (void) #endif } - -/* 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); - cgraph_mark_needed_node (cgraph_node (decl)); - - set_cfun (NULL); - current_function_decl = NULL; -} - void init_cgraph (void) { diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 83fdeae..99e59b0 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -1541,11 +1541,12 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, struct cgraph_node *node, VEC (cgraph_edge_p, heap) **new_edges) { - struct ipa_edge_args *top = IPA_EDGE_REF (cs); + struct ipa_edge_args *top; struct cgraph_edge *ie, *next_ie, *new_direct_edge; bool res = false; ipa_check_create_edge_args (); + top = IPA_EDGE_REF (cs); for (ie = node->indirect_calls; ie; ie = next_ie) { diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 0e07e44..e1d2f7e 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -427,7 +427,7 @@ worse_state (enum pure_const_state_e *state, bool *looping, /* Recognize special cases of builtins that are by themself not pure or const but function using them is. */ static bool -special_builtlin_state (enum pure_const_state_e *state, bool *looping, +special_builtin_state (enum pure_const_state_e *state, bool *looping, tree callee) { if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL) @@ -510,7 +510,7 @@ check_call (funct_state local, gimple call, bool ipa) enum pure_const_state_e call_state; bool call_looping; - if (special_builtlin_state (&call_state, &call_looping, callee_t)) + if (special_builtin_state (&call_state, &call_looping, callee_t)) { worse_state (&local->pure_const_state, &local->looping, call_state, call_looping); @@ -1203,7 +1203,7 @@ propagate_pure_const (void) edge_looping = y_l->looping; } } - else if (special_builtlin_state (&edge_state, &edge_looping, + else if (special_builtin_state (&edge_state, &edge_looping, y->decl)) ; else diff --git a/gcc/ipa.c b/gcc/ipa.c index be5c4a3..021398b 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -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 */ +}; diff --git a/gcc/passes.c b/gcc/passes.c index 1b98e99..4823c63 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -811,6 +811,7 @@ init_optimization_passes (void) NEXT_PASS (pass_ipa_whole_program_visibility); NEXT_PASS (pass_ipa_profile); NEXT_PASS (pass_ipa_cp); + NEXT_PASS (pass_ipa_cdtor_merge); NEXT_PASS (pass_ipa_inline); NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_reference); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 84d4a88..0dd6dd1 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -468,6 +468,7 @@ extern struct simple_ipa_opt_pass pass_ipa_struct_reorg; extern struct ipa_opt_pass_d pass_ipa_lto_wpa_fixup; extern struct ipa_opt_pass_d pass_ipa_lto_finish_out; extern struct ipa_opt_pass_d pass_ipa_profile; +extern struct ipa_opt_pass_d pass_ipa_cdtor_merge; extern struct gimple_opt_pass pass_all_optimizations; extern struct gimple_opt_pass pass_cleanup_cfg_post_optimizing; -- 2.7.4