ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P and CXX_DESTURCTOR_P.
authorJan Hubicka <hubicka@ucw.cz>
Fri, 13 Mar 2015 06:30:04 +0000 (07:30 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 13 Mar 2015 06:30:04 +0000 (06:30 +0000)
* ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
and CXX_DESTURCTOR_P. For consutrctors match ODR type of class they
are building; for methods check ODR type of class they belong to if
they may lead to a polymorphic call.
(sem_function::compare_polymorphic_p): Be bit smarter about testing
when function may lead to a polymorphic call.
(sem_function::compare_type_list): Remove.
(sem_variable::equals): Update use of compatible_types_p.
(sem_variable::parse_tree_refs): Remove.
(sem_item_optimizer::filter_removed_items): Do not filter out CXX
cdtor.
* ipa-icf-gimple.c (func_checker::compare_decl): Do polymorphic
matching here.
(func_checker::compatible_polymorphic_types_p): Break out from ...
(unc_checker::compatible_types_p): ... here.
* ipa-icf-gimple.h (func_checker::compatible_polymorphic_types_p):
Declare.
(unc_checker::compatible_types_p): Update.
* ipa-icf.h (compare_type_list, parse_tree_refs, compare_sections):
Remove.

From-SVN: r221406

gcc/ChangeLog
gcc/ipa-icf-gimple.c
gcc/ipa-icf-gimple.h
gcc/ipa-icf.c
gcc/ipa-icf.h

index e5a0e9e6f1363e8f433c6228e35567bfb7193427..1cc9905f5548d888e14b07d82091a4e855a88a5a 100644 (file)
@@ -1,3 +1,26 @@
+2015-03-12  Jan Hubicka  <hubicka@ucw.cz>
+
+       * ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
+       and CXX_DESTURCTOR_P. For consutrctors match ODR type of class they
+       are building; for methods check ODR type of class they belong to if
+       they may lead to a polymorphic call.
+       (sem_function::compare_polymorphic_p): Be bit smarter about testing
+       when function may lead to a polymorphic call.
+       (sem_function::compare_type_list): Remove.
+       (sem_variable::equals): Update use of compatible_types_p.
+       (sem_variable::parse_tree_refs): Remove.
+       (sem_item_optimizer::filter_removed_items): Do not filter out CXX
+       cdtor.
+       * ipa-icf-gimple.c (func_checker::compare_decl): Do polymorphic
+       matching here.
+       (func_checker::compatible_polymorphic_types_p): Break out from ...
+       (unc_checker::compatible_types_p): ... here.
+       * ipa-icf-gimple.h (func_checker::compatible_polymorphic_types_p):
+       Declare.
+       (unc_checker::compatible_types_p): Update.
+       * ipa-icf.h (compare_type_list, parse_tree_refs, compare_sections):
+       Remove.
+
 2015-03-12  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        PR rtl-optimization/65235
index 4f1a8ce6e95307059a17da1ad498529d3b73225a..568407da2fdc218b9d553214c90db720836dd89b 100644 (file)
@@ -200,8 +200,22 @@ func_checker::compare_decl (tree t1, tree t2)
       && DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2))
     return return_false_with_msg ("DECL_BY_REFERENCE flags are different");
 
-  if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-                          m_compare_polymorphic))
+  if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return return_false ();
+
+  /* TODO: we are actually too strict here.  We only need to compare if
+     T1 can be used in polymorphic call.  */
+  if (TREE_ADDRESSABLE (t1)
+      && m_compare_polymorphic
+      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
+                                         false))
+    return return_false ();
+
+  if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL)
+      && DECL_BY_REFERENCE (t1)
+      && m_compare_polymorphic
+      && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
+                                         true))
     return return_false ();
 
   bool existed_p;
@@ -215,11 +229,41 @@ func_checker::compare_decl (tree t1, tree t2)
   return true;
 }
 
+/* Return true if T1 and T2 are same for purposes of ipa-polymorphic-call
+   analysis.  COMPARE_PTR indicates if types of pointers needs to be
+   considered.  */
+
+bool
+func_checker::compatible_polymorphic_types_p (tree t1, tree t2,
+                                             bool compare_ptr)
+{
+  gcc_assert (TREE_CODE (t1) != FUNCTION_TYPE && TREE_CODE (t1) != METHOD_TYPE);
+
+  /* Pointer types generally give no information.  */
+  if (POINTER_TYPE_P (t1))
+    {
+      if (!compare_ptr)
+       return true;
+      return func_checker::compatible_polymorphic_types_p (TREE_TYPE (t1),
+                                                          TREE_TYPE (t2),
+                                                          false);
+    }
+
+  /* If types contain a polymorphic types, match them.  */
+  bool c1 = contains_polymorphic_type_p (t1);
+  bool c2 = contains_polymorphic_type_p (t2);
+  if (!c1 && !c2)
+    return true;
+  if (!c1 || !c2)
+    return return_false_with_msg ("one type is not polymorphic");
+  if (!types_must_be_same_for_odr (t1, t2))
+    return return_false_with_msg ("types are not same for ODR");
+  return true;
+}
+
 /* Return true if types are compatible from perspective of ICF.  */
 bool
-func_checker::compatible_types_p (tree t1, tree t2,
-                                 bool compare_polymorphic,
-                                 bool first_argument)
+func_checker::compatible_types_p (tree t1, tree t2)
 {
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return return_false_with_msg ("different tree types");
@@ -233,23 +277,6 @@ func_checker::compatible_types_p (tree t1, tree t2,
   if (get_alias_set (t1) != get_alias_set (t2))
     return return_false_with_msg ("alias sets are different");
 
-  /* We call contains_polymorphic_type_p with this pointer type.  */
-  if (first_argument && TREE_CODE (t1) == POINTER_TYPE)
-    {
-      t1 = TREE_TYPE (t1);
-      t2 = TREE_TYPE (t2);
-    }
-
-  if (compare_polymorphic)
-    if (contains_polymorphic_type_p (t1) || contains_polymorphic_type_p (t2))
-      {
-       if (!contains_polymorphic_type_p (t1) || !contains_polymorphic_type_p (t2))
-         return return_false_with_msg ("one type is not polymorphic");
-
-       if (!types_must_be_same_for_odr (t1, t2))
-         return return_false_with_msg ("types are not same for ODR");
-      }
-
   return true;
 }
 
index a52f8c33c9ac98a38a34297fa9bc2f849c457274..53a1bfe3c14bae79031def239970b8f61ced8c7f 100644 (file)
@@ -226,12 +226,16 @@ public:
   /* Verifies that trees T1 and T2 do correspond.  */
   bool compare_variable_decl (tree t1, tree t2);
 
+  /* Return true if types are compatible for polymorphic call analysis.
+     COMPARE_PTR indicates if polymorphic type comparsion should be
+     done for pointers, too.  */
+  static bool compatible_polymorphic_types_p (tree t1, tree t2,
+                                             bool compare_ptr);
+
   /* Return true if types are compatible from perspective of ICF.
      FIRST_ARGUMENT indicates if the comparison is called for
      first parameter of a function.  */
-  static bool compatible_types_p (tree t1, tree t2,
-                                 bool compare_polymorphic = true,
-                                 bool first_argument = false);
+  static bool compatible_types_p (tree t1, tree t2);
 
 
 private:
index 1f51cc17c5f1af77e0b35edaf4b653b0e7a39b36..25b83062d3f48bdd4bdb9d01a49b55ae1e6e50f3 100644 (file)
@@ -429,9 +429,29 @@ sem_function::equals_wpa (sem_item *item,
   if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
     return return_false_with_msg ("no stack limit attributes are different");
 
+  if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl))
+    return return_false_with_msg ("DELC_CXX_CONSTRUCTOR mismatch");
+
+  if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
+    return return_false_with_msg ("DELC_CXX_DESTRUCTOR mismatch");
+
   if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
     return return_false_with_msg ("decl_or_type flags are different");
 
+  /* Do not match polymorphic constructors of different types.  They calls
+     type memory location for ipa-polymorphic-call and we do not want
+     it to get confused by wrong type.  */
+  if (DECL_CXX_CONSTRUCTOR_P (decl)
+      && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+    {
+      if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
+        return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
+      else if (!func_checker::compatible_polymorphic_types_p
+                (method_class_type (TREE_TYPE (decl)),
+                 method_class_type (TREE_TYPE (item->decl)), false))
+        return return_false_with_msg ("ctor polymorphic type mismatch");
+    }
+
   /* Checking function TARGET and OPTIMIZATION flags.  */
   cl_target_option *tar1 = target_opts_for_fn (decl);
   cl_target_option *tar2 = target_opts_for_fn (item->decl);
@@ -473,13 +493,8 @@ sem_function::equals_wpa (sem_item *item,
       if (!arg_types[i] || !m_compared_func->arg_types[i])
        return return_false_with_msg ("NULL argument type");
 
-      /* Polymorphic comparison is executed just for non-leaf functions.  */
-      bool is_not_leaf = get_node ()->callees != NULL
-                        || get_node ()->indirect_calls != NULL;
-
       if (!func_checker::compatible_types_p (arg_types[i],
-                                            m_compared_func->arg_types[i],
-                                            is_not_leaf, i == 0))
+                                            m_compared_func->arg_types[i]))
        return return_false_with_msg ("argument type is different");
       if (POINTER_TYPE_P (arg_types[i])
          && (TYPE_RESTRICT (arg_types[i])
@@ -494,6 +509,24 @@ sem_function::equals_wpa (sem_item *item,
                            TREE_TYPE (item->decl)) != 1)
     return return_false_with_msg ("different type attributes");
 
+  /* The type of THIS pointer type memory location for
+     ipa-polymorphic-call-analysis.  */
+  if (opt_for_fn (decl, flag_devirtualize)
+      && (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
+          || TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE)
+      && (!flag_ipa_cp
+         || ipa_is_param_used (IPA_NODE_REF (dyn_cast <cgraph_node *>(node)),
+                               0))
+      && compare_polymorphic_p ())
+    {
+      if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl)))
+       return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch");
+      if (!func_checker::compatible_polymorphic_types_p
+          (method_class_type (TREE_TYPE (decl)),
+           method_class_type (TREE_TYPE (item->decl)), false))
+       return return_false_with_msg ("THIS pointer ODR type mismatch");
+    }
+
   ipa_ref *ref = NULL, *ref2 = NULL;
   for (unsigned i = 0; node->iterate_reference (i, ref); i++)
     {
@@ -614,7 +647,6 @@ sem_function::equals_private (sem_item *item,
   if (decl1 != decl2)
     return return_false();
 
-
   for (arg1 = DECL_ARGUMENTS (decl),
        arg2 = DECL_ARGUMENTS (m_compared_func->decl);
        arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
@@ -1216,10 +1248,20 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
 bool
 sem_function::compare_polymorphic_p (void)
 {
-  return get_node ()->callees != NULL
-        || get_node ()->indirect_calls != NULL
-        || m_compared_func->get_node ()->callees != NULL
-        || m_compared_func->get_node ()->indirect_calls != NULL;
+  struct cgraph_edge *e;
+
+  if (!opt_for_fn (decl, flag_devirtualize))
+    return false;
+  if (get_node ()->indirect_calls != NULL
+      || m_compared_func->get_node ()->indirect_calls != NULL)
+    return true;
+  /* TODO: We can do simple propagation determining what calls may lead to
+     a polymorphic call.  */
+  for (e = m_compared_func->get_node ()->callees; e; e = e->next_callee)
+    if (e->callee->definition
+       && opt_for_fn (e->callee->decl, flag_devirtualize))
+      return true;
+  return false;
 }
 
 /* For a given call graph NODE, the function constructs new
@@ -1374,41 +1416,6 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
     return (*bb_dict)[source] == target;
 }
 
-/* Iterates all tree types in T1 and T2 and returns true if all types
-   are compatible. If COMPARE_POLYMORPHIC is set to true,
-   more strict comparison is executed.  */
-
-bool
-sem_function::compare_type_list (tree t1, tree t2, bool compare_polymorphic)
-{
-  tree tv1, tv2;
-  tree_code tc1, tc2;
-
-  if (!t1 && !t2)
-    return true;
-
-  while (t1 != NULL && t2 != NULL)
-    {
-      tv1 = TREE_VALUE (t1);
-      tv2 = TREE_VALUE (t2);
-
-      tc1 = TREE_CODE (tv1);
-      tc2 = TREE_CODE (tv2);
-
-      if (tc1 == NOP_EXPR && tc2 == NOP_EXPR)
-       {}
-      else if (tc1 == NOP_EXPR || tc2 == NOP_EXPR)
-       return false;
-      else if (!func_checker::compatible_types_p (tv1, tv2, compare_polymorphic))
-       return false;
-
-      t1 = TREE_CHAIN (t1);
-      t2 = TREE_CHAIN (t2);
-    }
-
-  return !(t1 || t2);
-}
-
 
 /* Semantic variable constructor that uses STACK as bitmap memory stack.  */
 
@@ -1586,8 +1593,7 @@ sem_variable::equals (tree t1, tree t2)
        tree y1 = TREE_OPERAND (t1, 1);
        tree y2 = TREE_OPERAND (t2, 1);
 
-       if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2),
-                                              true))
+       if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
          return return_false ();
 
        /* Type of the offset on MEM_REF does not matter.  */
@@ -1696,8 +1702,7 @@ sem_variable::equals (tree t1, tree t2)
 
     CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
-      if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
-                                            true))
+      if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
          return return_false ();
       return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
     case ERROR_MARK:
@@ -1874,40 +1879,6 @@ sem_variable::dump_to_file (FILE *file)
   fprintf (file, "\n\n");
 }
 
-/* Iterates though a constructor and identifies tree references
-   we are interested in semantic function equality.  */
-
-void
-sem_variable::parse_tree_refs (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case CONSTRUCTOR:
-      {
-       unsigned length = vec_safe_length (CONSTRUCTOR_ELTS (t));
-
-       for (unsigned i = 0; i < length; i++)
-         parse_tree_refs(CONSTRUCTOR_ELT (t, i)->value);
-
-       break;
-      }
-    case NOP_EXPR:
-    case ADDR_EXPR:
-      {
-       tree op = TREE_OPERAND (t, 0);
-       parse_tree_refs (op);
-       break;
-      }
-    case FUNCTION_DECL:
-      {
-       tree_refs.safe_push (t);
-       break;
-      }
-    default:
-      break;
-    }
-}
-
 unsigned int sem_item_optimizer::class_id = 0;
 
 sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0),
@@ -2185,10 +2156,7 @@ sem_item_optimizer::filter_removed_items (void)
         {
          cgraph_node *cnode = static_cast <sem_function *>(item)->get_node ();
 
-         bool no_body_function = in_lto_p && (cnode->alias || cnode->body_removed);
-         if (no_body_function || !opt_for_fn (item->decl, flag_ipa_icf_functions)
-             || DECL_CXX_CONSTRUCTOR_P (item->decl)
-             || DECL_CXX_DESTRUCTOR_P (item->decl))
+         if (in_lto_p && (cnode->alias || cnode->body_removed))
            remove_item (item);
          else
            filtered.safe_push (item);
index 148135338887b48a1504af7ef6e296e6088f585a..c51bb4a4299c3ab245bafa3f15e997ad4bdce207 100644 (file)
@@ -353,11 +353,6 @@ private:
      corresponds to TARGET.  */
   bool bb_dict_test (vec<int> *bb_dict, int source, int target);
 
-  /* Iterates all tree types in T1 and T2 and returns true if all types
-     are compatible. If COMPARE_POLYMORPHIC is set to true,
-     more strict comparison is executed.  */
-  bool compare_type_list (tree t1, tree t2, bool compare_polymorphic);
-
   /* If cgraph edges E1 and E2 are indirect calls, verify that
      ICF flags are the same.  */
   bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2);
@@ -415,15 +410,8 @@ public:
   static sem_variable *parse (varpool_node *node, bitmap_obstack *stack);
 
 private:
-  /* Iterates though a constructor and identifies tree references
-     we are interested in semantic function equality.  */
-  void parse_tree_refs (tree t);
-
   /* Compares trees T1 and T2 for semantic equality.  */
   static bool equals (tree t1, tree t2);
-
-  /* Compare that symbol sections are either NULL or have same name.  */
-  bool compare_sections (sem_variable *alias);
 }; // class sem_variable
 
 class sem_item_optimizer;