Hi,
during LTO we seem to give up on many valid devirtualization cases because
the types are not merged by type merging machinery. This is i.e. because their
declarations are different; one unit define a function, while in the other
unit it is just an external declaration.
It is my understanding that C++ standard enforces one definition rule for
types, too (to enable sane mangling?) and that we can basically match types
by their name and contextes (namespaces/outer classes)> Does the attaches
patch make sense?
It enables a lot more devirtualization to happen during Firefox build.
Honza
Index: gimple-fold.c
===================================================================
*** gimple-fold.c (revision 200063)
--- gimple-fold.c (working copy)
*************** gimple_extract_devirt_binfo_from_cst (tr
*** 1038,1044 ****
HOST_WIDE_INT pos, size;
tree fld;
! if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
break;
if (offset < 0)
return NULL_TREE;
--- 1038,1044 ----
HOST_WIDE_INT pos, size;
tree fld;
! if (types_same_for_odr (type, expected_type))
break;
if (offset < 0)
return NULL_TREE;
Index: tree.c
===================================================================
*** tree.c (revision 200063)
--- tree.c (working copy)
*************** lhd_gcc_personality (void)
*** 11618,11623 ****
--- 11618,11695 ----
return gcc_eh_personality_decl;
}
+ /* For languages with One Definition Rule, work out if
+ decls are actually the same even if the tree representation
+ differs. This handles only decls appearing in TYPE_NAME
+ and TYPE_CONTEXT. That is NAMESPACE_DECL, TYPE_DECL,
+ RECORD_TYPE and IDENTIFIER_NODE. */
+
+ static bool
+ decls_same_for_odr (tree decl1, tree decl2)
+ {
+ if (decl1 && TREE_CODE (decl1) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (decl1))
+ decl1 = DECL_ORIGINAL_TYPE (decl1);
+ if (decl2 && TREE_CODE (decl2) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (decl2))
+ decl2 = DECL_ORIGINAL_TYPE (decl2);
+ if (decl1 == decl2)
+ return true;
+ if (!decl1 || !decl2)
+ return false;
+ if (TREE_CODE (decl1) != TREE_CODE (decl2))
+ return false;
+ if (TREE_CODE (decl1) == TRANSLATION_UNIT_DECL)
+ return true;
+ if (TREE_CODE (decl1) != NAMESPACE_DECL
+ && TREE_CODE (decl1) != RECORD_TYPE
+ && TREE_CODE (decl1) != TYPE_DECL)
+ return false;
+ if (!DECL_NAME (decl1))
+ return false;
+ if (!decls_same_for_odr (DECL_NAME (decl1), DECL_NAME (decl2)))
+ return false;
+ return decls_same_for_odr (DECL_CONTEXT (decl1),
+ DECL_CONTEXT (decl2));
+ }
+
+ /* For languages with One Definition Rule, work out if
+ types are same even if the tree representation differs.
+ This is non-trivial for LTO where minnor differences in
+ the type representation may have prevented type merging
+ to merge two copies of otherwise equivalent type. */
+
+ bool
+ types_same_for_odr (tree type1, tree type2)
+ {
+ type1 = TYPE_MAIN_VARIANT (type1);
+ type2 = TYPE_MAIN_VARIANT (type2);
+ if (type1 == type2)
+ return true;
+ if (!type1 || !type2)
+ return false;
+
+ /* If types are not structuraly same, do not bother to contnue.
+ Match in the remainder of code would mean ODR violation. */
+ if (!types_compatible_p (type1, type2))
+ return false;
+
+ #ifndef ENABLE_CHECKING
+ if (!in_lto_p)
+ return false;
+ #endif
+
+ if (!TYPE_NAME (type1))
+ return false;
+ if (!decls_same_for_odr (TYPE_NAME (type1), TYPE_NAME (type2)))
+ return false;
+ if (!decls_same_for_odr (TYPE_CONTEXT (type1), TYPE_CONTEXT (type2)))
+ return false;
+ gcc_assert (in_lto_p);
+
+ return true;
+ }
+
/* Try to find a base info of BINFO that would have its field decl at offset
OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be
found, return, otherwise return NULL_TREE. */
*************** get_binfo_at_offset (tree binfo, HOST_WI
*** 11633,11639 ****
tree fld;
int i;
! if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
return binfo;
if (offset < 0)
return NULL_TREE;
--- 11705,11711 ----
tree fld;
int i;
! if (types_same_for_odr (type, expected_type))
return binfo;
if (offset < 0)
return NULL_TREE;
*************** get_binfo_at_offset (tree binfo, HOST_WI
*** 11663,11669 ****
{
tree base_binfo, found_binfo = NULL_TREE;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
! if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
{
found_binfo = base_binfo;
break;
--- 11735,11741 ----
{
tree base_binfo, found_binfo = NULL_TREE;
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
! if (types_same_for_odr (TREE_TYPE (base_binfo), TREE_TYPE (fld)))
{
found_binfo = base_binfo;
break;
Index: tree.h
===================================================================
*** tree.h (revision 200063)
--- tree.h (working copy)
*************** extern location_t tree_nonartificial_loc
*** 5973,5978 ****
--- 5973,5979 ----
extern tree block_ultimate_origin (const_tree);
extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
+ extern bool types_same_for_odr (tree, tree);
extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *);
extern bool contains_bitfld_component_ref_p (const_tree);