d: Force TYPE_MODE of classes and non-POD structs as BLKmode
[gcc.git] / gcc / ipa-icf.c
index 8cae076b3cef806008c280d061dca483c003b6b3..5bbbec6c806fac05054010fea795a91f73020f5e 100644 (file)
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coverage.h"
 #include "gimple-pretty-print.h"
 #include "data-streamer.h"
+#include "tree-streamer.h"
 #include "fold-const.h"
 #include "calls.h"
 #include "varasm.h"
@@ -78,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "print-tree.h"
 #include "ipa-utils.h"
+#include "tree-ssa-alias-compare.h"
 #include "ipa-icf-gimple.h"
 #include "fibonacci_heap.h"
 #include "ipa-icf.h"
@@ -85,6 +87,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-vector-builder.h"
 #include "symtab-thunks.h"
+#include "alias.h"
 
 using namespace ipa_icf_gimple;
 
@@ -226,14 +229,16 @@ hash_map<const_tree, hashval_t> sem_item::m_type_hash_cache;
 /* Semantic function constructor that uses STACK as bitmap memory stack.  */
 
 sem_function::sem_function (bitmap_obstack *stack)
-: sem_item (FUNC, stack), m_checker (NULL), m_compared_func (NULL)
+  : sem_item (FUNC, stack), memory_access_types (), m_alias_sets_hash (0),
+    m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
 }
 
 sem_function::sem_function (cgraph_node *node, bitmap_obstack *stack)
-: sem_item (FUNC, node, stack), m_checker (NULL), m_compared_func (NULL)
+  : sem_item (FUNC, node, stack), memory_access_types (),
+    m_alias_sets_hash (0), m_checker (NULL), m_compared_func (NULL)
 {
   bb_sizes.create (0);
   bb_sorted.create (0);
@@ -570,6 +575,7 @@ sem_function::equals_wpa (sem_item *item,
      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)
+      && opt_for_fn (decl, flag_devirtualize)
       && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
     {
       if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
@@ -843,6 +849,8 @@ sem_function::equals_private (sem_item *item)
 
   m_checker = new func_checker (decl, m_compared_func->decl,
                                false,
+                               opt_for_fn (m_compared_func->decl,
+                                           flag_strict_aliasing),
                                &refs_set,
                                &m_compared_func->refs_set);
   arg1 = DECL_ARGUMENTS (decl);
@@ -1419,33 +1427,53 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
     {
     case GIMPLE_SWITCH:
       m_checker->hash_operand (gimple_switch_index (as_a <gswitch *> (stmt)),
-                            hstate, 0);
+                              hstate, 0, func_checker::OP_NORMAL);
       break;
     case GIMPLE_ASSIGN:
       hstate.add_int (gimple_assign_rhs_code (stmt));
-      if (commutative_tree_code (gimple_assign_rhs_code (stmt))
-         || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
-       {
-         m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0);
-         m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0);
-         if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
-           m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0);
-         m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0);
-       }
       /* fall through */
     case GIMPLE_CALL:
     case GIMPLE_ASM:
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     case GIMPLE_RETURN:
-      /* All these statements are equivalent if their operands are.  */
-      for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
-       m_checker->hash_operand (gimple_op (stmt, i), hstate, 0);
-      /* Consider nocf_check attribute in hash as it affects code
-        generation.  */
-      if (code == GIMPLE_CALL
-         && flag_cf_protection & CF_BRANCH)
-       hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
+      {
+       func_checker::operand_access_type_map map (5);
+       func_checker::classify_operands (stmt, &map);
+
+       /* All these statements are equivalent if their operands are.  */
+       for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
+         {
+           func_checker::operand_access_type
+               access_type = func_checker::get_operand_access_type
+                                         (&map, gimple_op (stmt, i));
+           m_checker->hash_operand (gimple_op (stmt, i), hstate, 0,
+                                    access_type);
+           /* For memory accesses when hasing for LTO stremaing record
+              base and ref alias ptr types so we can compare them at WPA
+              time without having to read actual function body.  */
+           if (access_type == func_checker::OP_MEMORY
+               && lto_streaming_expected_p ()
+               && flag_strict_aliasing)
+             {
+               ao_ref ref;
+
+               ao_ref_init (&ref, gimple_op (stmt, i));
+               tree t = ao_ref_alias_ptr_type (&ref);
+               if (!variably_modified_type_p (t, NULL_TREE))
+                 memory_access_types.safe_push (t);
+               t = ao_ref_base_alias_ptr_type (&ref);
+               if (!variably_modified_type_p (t, NULL_TREE))
+                 memory_access_types.safe_push (t);
+             }
+         }
+       /* Consider nocf_check attribute in hash as it affects code
+          generation.  */
+       if (code == GIMPLE_CALL
+           && flag_cf_protection & CF_BRANCH)
+         hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
+      }
+      break;
     default:
       break;
     }
@@ -1534,7 +1562,8 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
       tree phi_result1 = gimple_phi_result (phi1);
       tree phi_result2 = gimple_phi_result (phi2);
 
-      if (!m_checker->compare_operand (phi_result1, phi_result2))
+      if (!m_checker->compare_operand (phi_result1, phi_result2,
+                                      func_checker::OP_NORMAL))
        return return_false_with_msg ("PHI results are different");
 
       size1 = gimple_phi_num_args (phi1);
@@ -1548,7 +1577,7 @@ sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
          t1 = gimple_phi_arg (phi1, i)->def;
          t2 = gimple_phi_arg (phi2, i)->def;
 
-         if (!m_checker->compare_operand (t1, t2))
+         if (!m_checker->compare_operand (t1, t2, func_checker::OP_NORMAL))
            return return_false ();
 
          e1 = gimple_phi_arg_edge (phi1, i);
@@ -2126,6 +2155,14 @@ sem_item_optimizer::write_summary (void)
          streamer_write_uhwi_stream (ob->main_stream, node_ref);
 
          streamer_write_uhwi (ob, (*item)->get_hash ());
+
+         if ((*item)->type == FUNC)
+           {
+             sem_function *fn = static_cast<sem_function *> (*item);
+             streamer_write_uhwi (ob, fn->memory_access_types.length ());
+             for (unsigned i = 0; i < fn->memory_access_types.length (); i++)
+               stream_write_tree (ob, fn->memory_access_types[i], true);
+           }
        }
     }
 
@@ -2177,6 +2214,18 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
          cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
 
          sem_function *fn = new sem_function (cnode, &m_bmstack);
+         unsigned count = streamer_read_uhwi (&ib_main);
+         inchash::hash hstate (0);
+         if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+           fn->memory_access_types.reserve_exact (count);
+         for (unsigned i = 0; i < count; i++)
+           {
+             tree type = stream_read_tree (&ib_main, data_in);
+             hstate.add_int (get_deref_alias_set (type));
+             if (flag_incremental_link == INCREMENTAL_LINK_LTO)
+               fn->memory_access_types.quick_push (type);
+           }
+         fn->m_alias_sets_hash = hstate.end ();
          fn->set_hash (hash);
          m_items.safe_push (fn);
        }
@@ -2373,6 +2422,7 @@ sem_item_optimizer::execute (void)
 
   build_graph ();
   update_hash_by_addr_refs ();
+  update_hash_by_memory_access_type ();
   build_hash_based_classes ();
 
   if (dump_file)
@@ -2487,11 +2537,24 @@ sem_item_optimizer::update_hash_by_addr_refs ()
                  = TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl));
                inchash::hash hstate (m_items[i]->get_hash ());
 
+               /* Hash ODR types by mangled name if it is defined.
+                  If not we know that type is anonymous of free_lang_data
+                  was not run and in that case type main variants are
+                  unique.  */
                if (TYPE_NAME (class_type)
-                    && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
+                    && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type))
+                    && !type_in_anonymous_namespace_p
+                                (class_type))
                  hstate.add_hwi
                    (IDENTIFIER_HASH_VALUE
                       (DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
+               else
+                 {
+                   gcc_checking_assert
+                        (!in_lto_p
+                         || type_in_anonymous_namespace_p (class_type));
+                   hstate.add_hwi (TYPE_UID (TYPE_MAIN_VARIANT (class_type)));
+                 }
 
                m_items[i]->set_hash (hstate.end ());
             }
@@ -2510,6 +2573,21 @@ sem_item_optimizer::update_hash_by_addr_refs ()
     m_items[i]->set_hash (m_items[i]->global_hash);
 }
 
+void
+sem_item_optimizer::update_hash_by_memory_access_type ()
+{
+  for (unsigned i = 0; i < m_items.length (); i++)
+    {
+      if (m_items[i]->type == FUNC)
+       {
+         sem_function *fn = static_cast<sem_function *> (m_items[i]);
+         inchash::hash hstate (fn->get_hash ());
+         hstate.add_int (fn->m_alias_sets_hash);
+         fn->set_hash (hstate.end ());
+       }
+    }
+}
+
 /* Congruence classes are built by hash value.  */
 
 void