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);

Reply via email to