* cgraph.h (struct cgraph_node): Add same_comdat_group field.
* cgraph.c (cgraph_remove_node): Unchain node from same_comdat_group
circular list.
(cgraph_node_can_be_local_p): Return false for DECL_COMDAT with
node->same_comdat_group.
* ipa.c (cgraph_remove_unreachable_nodes): For any reachable node
mark all its same_comdat_group nodes as also reachable.
(cgraph_externally_visible_p): Return true even if any of
same_comdat_group nodes has address taken.
* lto-cgraph.c (lto_output_node): Stream out same_comdat_group.
(output_cgraph): Ensure other same_comdat_group nodes are also
included.
(input_node): Stream in same_comdat_group.
(input_cgraph_1): Fix up same_comdat_group fields from references
to pointers.
* cgraphunit.c (cgraph_analyze_functions): Mark all other
same_comdat_group nodes as reachable.
(cgraph_mark_functions_to_output): For each node->process process
also other same_comdat_group nodes.
* ipa-inline.c (cgraph_clone_inlined_nodes): Don't reuse nodes
with same_comdat_group non-NULL.
(cgraph_mark_inline_edge): Likewise.
* decl2.c (cp_write_global_declarations): Clear DECL_EXTERNAL
also on all other functions in the same comdat group.
* optimize.c (maybe_clone_body): Also optimize virtual implicit
dtors. For virtual comdat dtors tell cgraph that base and deleting
dtor are in the same comdat group.
* config/abi/pre/gnu.ver: Don't export certain base dtors that
weren't previously exported.
* g++.dg/opt/dtor2.C: New test.
* g++.dg/opt/dtor2.h: New file.
* g++.dg/opt/dtor2-aux.cc: New file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155143
138bc75d-0d04-0410-961f-
82ee72b054a4
+2009-12-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/42317
+ * cgraph.h (struct cgraph_node): Add same_comdat_group field.
+ * cgraph.c (cgraph_remove_node): Unchain node from same_comdat_group
+ circular list.
+ (cgraph_node_can_be_local_p): Return false for DECL_COMDAT with
+ node->same_comdat_group.
+ * ipa.c (cgraph_remove_unreachable_nodes): For any reachable node
+ mark all its same_comdat_group nodes as also reachable.
+ (cgraph_externally_visible_p): Return true even if any of
+ same_comdat_group nodes has address taken.
+ * lto-cgraph.c (lto_output_node): Stream out same_comdat_group.
+ (output_cgraph): Ensure other same_comdat_group nodes are also
+ included.
+ (input_node): Stream in same_comdat_group.
+ (input_cgraph_1): Fix up same_comdat_group fields from references
+ to pointers.
+ * cgraphunit.c (cgraph_analyze_functions): Mark all other
+ same_comdat_group nodes as reachable.
+ (cgraph_mark_functions_to_output): For each node->process process
+ also other same_comdat_group nodes.
+ * ipa-inline.c (cgraph_clone_inlined_nodes): Don't reuse nodes
+ with same_comdat_group non-NULL.
+ (cgraph_mark_inline_edge): Likewise.
+
2009-12-10 Jan Hubicka <jh@suse.cz>
PR middle-end/42228
while (node->same_body)
cgraph_remove_same_body_alias (node->same_body);
+ if (node->same_comdat_group)
+ {
+ struct cgraph_node *prev;
+ for (prev = node->same_comdat_group;
+ prev->same_comdat_group != node;
+ prev = prev->same_comdat_group)
+ ;
+ if (node->same_comdat_group == prev)
+ prev->same_comdat_group = NULL;
+ else
+ prev->same_comdat_group = node->same_comdat_group;
+ node->same_comdat_group = NULL;
+ }
+
/* While all the clones are removed after being proceeded, the function
itself is kept in the cgraph even after it is compiled. Check whether
we are done with this body and reclaim it proactively if this is the case.
cgraph_node_can_be_local_p (struct cgraph_node *node)
{
return (!node->needed
- && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
+ && ((DECL_COMDAT (node->decl) && !node->same_comdat_group)
+ || !node->local.externally_visible));
}
/* Bring NODE local. */
/* For normal nodes pointer to the list of alias and thunk nodes,
in alias/thunk nodes pointer to the normal node. */
struct cgraph_node *same_body;
+ /* Circular list of nodes in the same comdat group if non-NULL. */
+ struct cgraph_node *same_comdat_group;
/* For functions with many calls sites it holds map from call expression
to the edge to speed up cgraph_edge function. */
htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
if (!edge->callee->reachable)
cgraph_mark_reachable_node (edge->callee);
+ if (node->same_comdat_group)
+ {
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ cgraph_mark_reachable_node (next);
+ }
+
/* If decl is a clone of an abstract function, mark that abstract
function so that we don't release its body. The DECL_INITIAL() of that
abstract function declaration will be later needed to output debug info. */
cgraph_mark_functions_to_output (void)
{
struct cgraph_node *node;
+#ifdef ENABLE_CHECKING
+ bool check_same_comdat_groups = false;
+
+ for (node = cgraph_nodes; node; node = node->next)
+ gcc_assert (!node->process);
+#endif
for (node = cgraph_nodes; node; node = node->next)
{
tree decl = node->decl;
struct cgraph_edge *e;
- gcc_assert (!node->process);
+ gcc_assert (!node->process || node->same_comdat_group);
+ if (node->process)
+ continue;
for (e = node->callers; e; e = e->next_caller)
if (e->inline_failed)
|| (e && node->reachable))
&& !TREE_ASM_WRITTEN (decl)
&& !DECL_EXTERNAL (decl))
- node->process = 1;
+ {
+ node->process = 1;
+ if (node->same_comdat_group)
+ {
+ struct cgraph_node *next;
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ next->process = 1;
+ }
+ }
+ else if (node->same_comdat_group)
+ {
+#ifdef ENABLE_CHECKING
+ check_same_comdat_groups = true;
+#endif
+ }
else
{
/* We should've reclaimed all functions that are not needed. */
}
}
+#ifdef ENABLE_CHECKING
+ if (check_same_comdat_groups)
+ for (node = cgraph_nodes; node; node = node->next)
+ if (node->same_comdat_group && !node->process)
+ {
+ tree decl = node->decl;
+ if (!node->global.inlined_to
+ && gimple_has_body_p (decl)
+ && !DECL_EXTERNAL (decl))
+ {
+ dump_cgraph_node (stderr, node);
+ internal_error ("failed to reclaim unneeded function");
+ }
+ }
+#endif
}
/* DECL is FUNCTION_DECL. Initialize datastructures so DECL is a function
+2009-12-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/42317
+ * decl2.c (cp_write_global_declarations): Clear DECL_EXTERNAL
+ also on all other functions in the same comdat group.
+ * optimize.c (maybe_clone_body): Also optimize virtual implicit
+ dtors. For virtual comdat dtors tell cgraph that base and deleting
+ dtor are in the same comdat group.
+
2009-12-04 Jason Merrill <jason@redhat.com>
PR c++/42010
&& DECL_INITIAL (decl)
&& decl_needed_p (decl))
{
- struct cgraph_node *node = cgraph_get_node (decl), *alias;
+ struct cgraph_node *node = cgraph_get_node (decl), *alias, *next;
DECL_EXTERNAL (decl) = 0;
/* If we mark !DECL_EXTERNAL one of the same body aliases,
for (alias = node->same_body; alias; alias = alias->next)
DECL_EXTERNAL (alias->decl) = 0;
}
+ /* If we mark !DECL_EXTERNAL one of the symbols in some comdat
+ group, we need to mark all symbols in the same comdat group
+ that way. */
+ if (node->same_comdat_group)
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ {
+ DECL_EXTERNAL (next->decl) = 0;
+ if (next->same_body)
+ {
+ for (alias = next->same_body;
+ alias;
+ alias = alias->next)
+ DECL_EXTERNAL (alias->decl) = 0;
+ }
+ }
}
/* If we're going to need to write this function out, and
&& (SUPPORTS_ONE_ONLY || !DECL_WEAK (fns[0]))
&& (!DECL_ONE_ONLY (fns[0])
|| (HAVE_COMDAT_GROUP
- && DECL_WEAK (fns[0])
- /* Don't optimize synthetized virtual dtors, because then
- the deleting and other dtors are emitted when needed
- and so it is not certain we would emit both
- deleting and complete/base dtors in the comdat group. */
- && (fns[2] == NULL || !DECL_ARTIFICIAL (fn))))
+ && DECL_WEAK (fns[0])))
&& cgraph_same_body_alias (clone, fns[0]))
{
alias = true;
{
DECL_COMDAT_GROUP (fns[1]) = comdat_group;
if (fns[2])
- /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
- virtual, it goes into the same comdat group as well. */
- DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+ {
+ struct cgraph_node *base_dtor_node, *deleting_dtor_node;
+ /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is
+ virtual, it goes into the same comdat group as well. */
+ DECL_COMDAT_GROUP (fns[2]) = comdat_group;
+ base_dtor_node = cgraph_node (fns[0]);
+ deleting_dtor_node = cgraph_node (fns[2]);
+ gcc_assert (base_dtor_node->same_comdat_group == NULL);
+ gcc_assert (deleting_dtor_node->same_comdat_group == NULL);
+ base_dtor_node->same_comdat_group = deleting_dtor_node;
+ deleting_dtor_node->same_comdat_group = base_dtor_node;
+ }
}
/* We don't need to process the original function any further. */
In that case just go ahead and re-use it. */
if (!e->callee->callers->next_caller
&& cgraph_can_remove_if_no_direct_calls_p (e->callee)
+ /* Don't reuse if more than one function shares a comdat group.
+ If the other function(s) are needed, we need to emit even
+ this function out of line. */
+ && !e->callee->same_comdat_group
&& !cgraph_new_nodes)
{
gcc_assert (!e->callee->global.inlined_to);
e->callee->global.inlined = true;
if (e->callee->callers->next_caller
- || !cgraph_can_remove_if_no_direct_calls_p (e->callee))
+ || !cgraph_can_remove_if_no_direct_calls_p (e->callee)
+ || e->callee->same_comdat_group)
duplicate = true;
cgraph_clone_inlined_nodes (e, true, update_original);
/* Basic IPA optimizations and utilities.
- Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
+ Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
Inc.
This file is part of GCC.
first = e->callee;
}
}
-
+
+ /* If any function in a comdat group is reachable, force
+ all other functions in the same comdat group to be
+ also reachable. */
+ if (node->same_comdat_group
+ && node->reachable
+ && !node->global.inlined_to)
+ {
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ if (!next->reachable)
+ {
+ next->aux = first;
+ first = next;
+ next->reachable = true;
+ }
+ }
+
/* We can freely remove inline clones even if they are cloned, however if
function is clone of real clone, we must keep it around in order to
make materialize_clones produce function body with the changes
/* COMDAT functions must be shared only if they have address taken,
otherwise we can produce our own private implementation with
-fwhole-program. */
- if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed))
- return true;
+ if (DECL_COMDAT (node->decl))
+ {
+ if (node->address_taken || !node->analyzed)
+ return true;
+ if (node->same_comdat_group)
+ {
+ struct cgraph_node *next;
+
+ /* If more than one function is in the same COMDAT group, it must
+ be shared even if just one function in the comdat group has
+ address taken. */
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ if (next->address_taken || !next->analyzed)
+ return true;
+ }
+ }
if (MAIN_NAME_P (DECL_NAME (node->decl)))
return true;
if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
lto_output_sleb128_stream (ob->main_stream,
node->global.estimated_growth);
lto_output_uleb128_stream (ob->main_stream, node->global.inlined);
+ if (node->same_comdat_group)
+ {
+ ref = lto_cgraph_encoder_lookup (encoder, node->same_comdat_group);
+ gcc_assert (ref != LCC_NOT_FOUND);
+ }
+ else
+ ref = LCC_NOT_FOUND;
+ lto_output_sleb128_stream (ob->main_stream, ref);
+
if (node->same_body)
{
struct cgraph_node *alias;
/* We should have moved all the inlines. */
gcc_assert (!callee->global.inlined_to);
lto_cgraph_encoder_encode (encoder, callee);
+ /* Also with each included function include all other functions
+ in the same comdat group. */
+ if (callee->same_comdat_group)
+ {
+ struct cgraph_node *next;
+ for (next = callee->same_comdat_group;
+ next != callee;
+ next = next->same_comdat_group)
+ if (!cgraph_node_in_set_p (next, set))
+ lto_cgraph_encoder_encode (encoder, next);
+ }
}
}
+ /* Also with each included function include all other functions
+ in the same comdat group. */
+ if (node->same_comdat_group)
+ {
+ struct cgraph_node *next;
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ if (!cgraph_node_in_set_p (next, set))
+ lto_cgraph_encoder_encode (encoder, next);
+ }
}
/* Write out the nodes. */
bool clone_p;
int estimated_stack_size = 0;
int stack_frame_offset = 0;
- int ref = LCC_NOT_FOUND;
+ int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND;
int estimated_growth = 0;
int time = 0;
int size = 0;
size = lto_input_sleb128 (ib);
estimated_growth = lto_input_sleb128 (ib);
inlined = lto_input_uleb128 (ib);
+ ref2 = lto_input_sleb128 (ib);
same_body_count = lto_input_uleb128 (ib);
/* Make sure that we have not read this node before. Nodes that
node->global.estimated_growth = estimated_growth;
node->global.inlined = inlined;
+ /* Store a reference for now, and fix up later to be a pointer. */
+ node->same_comdat_group = (cgraph_node_ptr) (intptr_t) ref2;
+
while (same_body_count-- > 0)
{
tree alias_decl;
for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
{
- const int ref = (int) (intptr_t) node->global.inlined_to;
+ int ref = (int) (intptr_t) node->global.inlined_to;
/* Fixup inlined_to from reference to pointer. */
if (ref != LCC_NOT_FOUND)
node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref);
else
node->global.inlined_to = NULL;
+
+ ref = (int) (intptr_t) node->same_comdat_group;
+
+ /* Fixup same_comdat_group from reference to pointer. */
+ if (ref != LCC_NOT_FOUND)
+ node->same_comdat_group = VEC_index (cgraph_node_ptr, nodes, ref);
+ else
+ node->same_comdat_group = NULL;
}
VEC_free (cgraph_node_ptr, heap, nodes);
+2009-12-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/42317
+ * g++.dg/opt/dtor2.C: New test.
+ * g++.dg/opt/dtor2.h: New file.
+ * g++.dg/opt/dtor2-aux.cc: New file.
+
2009-12-10 Daniel Franke <franke.daniel@gmail.com>
PR fortran/41369
--- /dev/null
+// { dg-do compile }
+// { dg-options "" }
+
+#include "dtor2.h"
+
+A::A () {}
+A::~A () {}
+
+void B::mb () {}
+B::B (int) {}
+B::~B () {}
+
+void C::mc () {}
+C::C (int x) : B (x) {}
+
+D::~D () {}
--- /dev/null
+// PR c++/42317
+// { dg-do link }
+// { dg-options "-O0" }
+// { dg-additional-sources "dtor2-aux.cc" }
+
+#include "dtor2.h"
+
+D::D (int x) : C (x) {}
+
+int
+main ()
+{
+}
--- /dev/null
+struct A
+{
+ A ();
+ ~A ();
+};
+
+struct B
+{
+ A b;
+ virtual void mb ();
+ B (int);
+ virtual ~B ();
+};
+
+struct C : public B
+{
+ virtual void mc ();
+ C (int);
+ ~C ();
+};
+
+inline C::~C () {}
+
+struct D : public C
+{
+ A d;
+ D (int);
+ ~D ();
+};
+2009-12-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/42317
+ * config/abi/pre/gnu.ver: Don't export certain base dtors that
+ weren't previously exported.
+
2009-12-10 Paolo Carlini <paolo.carlini@oracle.com>
PR libstdc++/42261 (take 2)
std::c[v-z]*;
# std::[d-g]*;
std::d[a-d]*;
- std::d[f-z]*;
+ std::d[f-n]*;
+ std::domain_error::d*;
+# std::domain_error::~d*;
+ std::d[p-z]*;
std::e[a-q]*;
std::error[^_]*;
std::e[s-z]*;
std::gslice*;
std::h[^a]*;
- std::i[a-n]*;
+ std::i[a-m]*;
+ std::invalid_argument::i*;
+# std::invalid_argument::~i*;
# std::ios_base::[A-Ha-z]*;
std::ios_base::[A-Ha-f]*;
std::ios_base::goodbit;
std::istrstream*;
std::i[t-z]*;
std::[A-Zj-k]*;
- std::length_error*;
+ std::length_error::l*;
+# std::length_error::~l*;
std::logic_error*;
std::locale::[A-Za-e]*;
std::locale::facet::[A-Za-z]*;
std::nu[^m]*;
std::num[^e]*;
std::ostrstream*;
- std::out_of_range*;
- std::overflow_error*;
+ std::out_of_range::o*;
+# std::out_of_range::~o*;
+ std::overflow_error::o*;
+# std::overflow_error::~o*;
# std::[p-q]*;
- std::r[^e]*;
+ std::r[^ae]*;
+ std::range_error::r*;
+# std::range_error::~r*;
std::re[^t]*;
# std::rethrow_exception
std::set_new_handler*;
std::tr1::h[^a]*;
std::t[s-z]*;
# std::[A-Zu-z]*;
- std::underflow_error*;
+ std::underflow_error::u*;
+# std::underflow_error::~u*;
std::uncaught_exception*;
std::unexpected*;
std::[A-Zv-z]*;
_ZNSt15basic_streambufI[cw]St11char_traitsI[cw]EEaSERKS2_;
# std::basic_stringbuf
- _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[CD]*;
+ _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EEC*;
+ _ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EED[^2]*;
_ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9][a-r]*;
_ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9]seek*;
_ZNSt15basic_stringbufI[cw]St11char_traitsI[cw]ESaI[cw]EE[0-9]set*;
_ZGVNSt[^1]*;
_ZGVNSt1[^7]*;
+ # complete and deleting destructors where base destructors should not
+ # be exported.
+ _ZNSt11range_errorD[01]Ev;
+ _ZNSt12domain_errorD[01]Ev;
+ _ZNSt12length_errorD[01]Ev;
+ _ZNSt12out_of_rangeD[01]Ev;
+ _ZNSt14overflow_errorD[01]Ev;
+ _ZNSt15underflow_errorD[01]Ev;
+ _ZNSt16invalid_argumentD[01]Ev;
+
# virtual function thunks
_ZThn8_NS*;
_ZThn16_NS*;
_ZNSt15basic_streambufI[cw]St11char_traitsI[cw]EE6stosscEv;
_ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE4syncEv;
- _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE[5-9CD]*;
+ _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EE[5-9C]*;
+ _ZN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EED[^2]*;
} GLIBCXX_3.4.9;