]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ipa-icf-gimple.c
rs6000: New iterator CCEITHER
[thirdparty/gcc.git] / gcc / ipa-icf-gimple.c
index 8f885b04c58b3e7d49aea30882f8108762bd6048..0713e125898718137b4c9e5a9b2fc436965e8dde 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural Identical Code Folding pass
-   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2014-2019 Free Software Foundation, Inc.
 
    Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
 
@@ -22,60 +22,24 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "options.h"
-#include "inchash.h"
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
-#include "fold-const.h"
-#include "predict.h"
-#include "tm.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
-#include "hashtab.h"
-#include "rtl.h"
-#include "flags.h"
-#include "statistics.h"
-#include "insn-config.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "gimple-iterator.h"
-#include "gimple-ssa.h"
-#include "tree-cfg.h"
-#include "stringpool.h"
-#include "tree-dfa.h"
 #include "tree-pass.h"
-#include "gimple-pretty-print.h"
-#include "cfgloop.h"
-#include "except.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
+#include "ssa.h"
 #include "cgraph.h"
 #include "data-streamer.h"
+#include "gimple-pretty-print.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
 #include "ipa-utils.h"
-#include <list>
-#include "tree-ssanames.h"
 #include "tree-eh.h"
 #include "builtins.h"
+#include "cfgloop.h"
 
 #include "ipa-icf-gimple.h"
-#include "ipa-icf.h"
 
 namespace ipa_icf_gimple {
 
@@ -269,7 +233,15 @@ func_checker::compatible_types_p (tree t1, tree t2)
   if (!types_compatible_p (t1, t2))
     return return_false_with_msg ("types are not compatible");
 
-  if (get_alias_set (t1) != get_alias_set (t2))
+  /* We do a lot of unnecesary matching of types that are not being
+     accessed and thus do not need to be compatible.  In longer term we should
+     remove these checks on all types which are not accessed as memory
+     locations.
+
+     For time being just avoid calling get_alias_set on types that are not
+     having alias sets defined at all.  */
+  if (type_with_alias_set_p (t1) && type_with_alias_set_p (t2)
+      && get_alias_set (t1) != get_alias_set (t2))
     return return_false_with_msg ("alias sets are different");
 
   return true;
@@ -390,10 +362,14 @@ func_checker::compare_cst_or_decl (tree t1, tree t2)
       }
     case LABEL_DECL:
       {
+       if (t1 == t2)
+         return true;
+
        int *bb1 = m_label_bb_map.get (t1);
        int *bb2 = m_label_bb_map.get (t2);
 
-       return return_with_debug (*bb1 == *bb2);
+       /* Labels can point to another function (non-local GOTOs).  */
+       return return_with_debug (bb1 != NULL && bb2 != NULL && *bb1 == *bb2);
       }
     case PARM_DECL:
     case RESULT_DECL:
@@ -435,8 +411,8 @@ func_checker::compare_operand (tree t1, tree t2)
     {
     case CONSTRUCTOR:
       {
-       unsigned length1 = vec_safe_length (CONSTRUCTOR_ELTS (t1));
-       unsigned length2 = vec_safe_length (CONSTRUCTOR_ELTS (t2));
+       unsigned length1 = CONSTRUCTOR_NELTS (t1);
+       unsigned length2 = CONSTRUCTOR_NELTS (t2);
 
        if (length1 != length2)
          return return_false ();
@@ -488,7 +464,7 @@ func_checker::compare_operand (tree t1, tree t2)
          return return_false_with_msg ("");
 
        /* Type of the offset on MEM_REF does not matter.  */
-       return wi::to_offset  (y1) == wi::to_offset  (y2);
+       return known_eq (wi::to_poly_offset (y1), wi::to_poly_offset (y2));
       }
     case COMPONENT_REF:
       {
@@ -568,11 +544,8 @@ func_checker::compare_operand (tree t1, tree t2)
     }
 }
 
-/* Compares two tree list operands T1 and T2 and returns true if these
-   two trees are semantically equivalent.  */
-
 bool
-func_checker::compare_tree_list_operand (tree t1, tree t2)
+func_checker::compare_asm_inputs_outputs (tree t1, tree t2)
 {
   gcc_assert (TREE_CODE (t1) == TREE_LIST);
   gcc_assert (TREE_CODE (t2) == TREE_LIST);
@@ -585,6 +558,16 @@ func_checker::compare_tree_list_operand (tree t1, tree t2)
       if (!compare_operand (TREE_VALUE (t1), TREE_VALUE (t2)))
        return return_false ();
 
+      tree p1 = TREE_PURPOSE (t1);
+      tree p2 = TREE_PURPOSE (t2);
+
+      gcc_assert (TREE_CODE (p1) == TREE_LIST);
+      gcc_assert (TREE_CODE (p2) == TREE_LIST);
+
+      if (strcmp (TREE_STRING_POINTER (TREE_VALUE (p1)),
+                 TREE_STRING_POINTER (TREE_VALUE (p2))) != 0)
+       return return_false ();
+
       t2 = TREE_CHAIN (t2);
     }
 
@@ -623,6 +606,40 @@ func_checker::compare_variable_decl (tree t1, tree t2)
   return return_with_debug (ret);
 }
 
+/* Compare loop information for basic blocks BB1 and BB2.  */
+
+bool
+func_checker::compare_loops (basic_block bb1, basic_block bb2)
+{
+  if ((bb1->loop_father == NULL) != (bb2->loop_father == NULL))
+    return return_false ();
+
+  struct loop *l1 = bb1->loop_father;
+  struct loop *l2 = bb2->loop_father;
+  if (l1 == NULL)
+    return true;
+
+  if ((bb1 == l1->header) != (bb2 == l2->header))
+    return return_false_with_msg ("header");
+  if ((bb1 == l1->latch) != (bb2 == l2->latch))
+    return return_false_with_msg ("latch");
+  if (l1->simdlen != l2->simdlen)
+    return return_false_with_msg ("simdlen");
+  if (l1->safelen != l2->safelen)
+    return return_false_with_msg ("safelen");
+  if (l1->can_be_parallel != l2->can_be_parallel)
+    return return_false_with_msg ("can_be_parallel");
+  if (l1->dont_vectorize != l2->dont_vectorize)
+    return return_false_with_msg ("dont_vectorize");
+  if (l1->force_vectorize != l2->force_vectorize)
+    return return_false_with_msg ("force_vectorize");
+  if (l1->unroll != l2->unroll)
+    return return_false_with_msg ("unroll");
+  if (!compare_variable_decl (l1->simduid, l2->simduid))
+    return return_false_with_msg ("simduid");
+
+  return true;
+}
 
 /* Function visits all gimple labels and creates corresponding
    mapping between basic blocks and labels.  */
@@ -633,7 +650,7 @@ func_checker::parse_labels (sem_bb *bb)
   for (gimple_stmt_iterator gsi = gsi_start_bb (bb->bb); !gsi_end_p (gsi);
        gsi_next (&gsi))
     {
-      gimple stmt = gsi_stmt (gsi);
+      gimple *stmt = gsi_stmt (gsi);
 
       if (glabel *label_stmt = dyn_cast <glabel *> (stmt))
        {
@@ -656,10 +673,10 @@ bool
 func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
 {
   gimple_stmt_iterator gsi1, gsi2;
-  gimple s1, s2;
+  gimple *s1, *s2;
 
-  gsi1 = gsi_start_bb_nondebug (bb1->bb);
-  gsi2 = gsi_start_bb_nondebug (bb2->bb);
+  gsi1 = gsi_start_nondebug_bb (bb1->bb);
+  gsi2 = gsi_start_nondebug_bb (bb2->bb);
 
   while (!gsi_end_p (gsi1))
     {
@@ -745,6 +762,9 @@ func_checker::compare_bb (sem_bb *bb1, sem_bb *bb2)
   if (!gsi_end_p (gsi2))
     return return_false ();
 
+  if (!compare_loops (bb1->bb, bb2->bb))
+    return return_false ();
+
   return true;
 }
 
@@ -772,8 +792,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
       || gimple_call_return_slot_opt_p (s1) != gimple_call_return_slot_opt_p (s2)
       || gimple_call_from_thunk_p (s1) != gimple_call_from_thunk_p (s2)
       || gimple_call_va_arg_pack_p (s1) != gimple_call_va_arg_pack_p (s2)
-      || gimple_call_alloca_for_var_p (s1) != gimple_call_alloca_for_var_p (s2)
-      || gimple_call_with_bounds_p (s1) != gimple_call_with_bounds_p (s2))
+      || gimple_call_alloca_for_var_p (s1) != gimple_call_alloca_for_var_p (s2))
     return false;
 
   if (gimple_call_internal_p (s1)
@@ -816,7 +835,7 @@ func_checker::compare_gimple_call (gcall *s1, gcall *s2)
    assignment statements are semantically equivalent.  */
 
 bool
-func_checker::compare_gimple_assign (gimple s1, gimple s2)
+func_checker::compare_gimple_assign (gimple *s1, gimple *s2)
 {
   tree arg1, arg2;
   tree_code code1, code2;
@@ -851,7 +870,7 @@ func_checker::compare_gimple_assign (gimple s1, gimple s2)
    condition statements are semantically equivalent.  */
 
 bool
-func_checker::compare_gimple_cond (gimple s1, gimple s2)
+func_checker::compare_gimple_cond (gimple *s1, gimple *s2)
 {
   tree t1, t2;
   tree_code code1, code2;
@@ -977,7 +996,7 @@ func_checker::compare_gimple_return (const greturn *g1, const greturn *g2)
    goto statements are semantically equivalent.  */
 
 bool
-func_checker::compare_gimple_goto (gimple g1, gimple g2)
+func_checker::compare_gimple_goto (gimple *g1, gimple *g2)
 {
   tree dest1, dest2;
 
@@ -1009,6 +1028,12 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
   if (gimple_asm_volatile_p (g1) != gimple_asm_volatile_p (g2))
     return false;
 
+  if (gimple_asm_input_p (g1) != gimple_asm_input_p (g2))
+    return false;
+
+  if (gimple_asm_inline_p (g1) != gimple_asm_inline_p (g2))
+    return false;
+
   if (gimple_asm_ninputs (g1) != gimple_asm_ninputs (g2))
     return false;
 
@@ -1030,7 +1055,7 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
       tree input1 = gimple_asm_input_op (g1, i);
       tree input2 = gimple_asm_input_op (g2, i);
 
-      if (!compare_tree_list_operand (input1, input2))
+      if (!compare_asm_inputs_outputs (input1, input2))
        return return_false_with_msg ("ASM input is different");
     }
 
@@ -1039,7 +1064,7 @@ func_checker::compare_gimple_asm (const gasm *g1, const gasm *g2)
       tree output1 = gimple_asm_output_op (g1, i);
       tree output2 = gimple_asm_output_op (g2, i);
 
-      if (!compare_tree_list_operand (output1, output2))
+      if (!compare_asm_inputs_outputs (output1, output2))
        return return_false_with_msg ("ASM output is different");
     }