]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-tail-merge.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / tree-ssa-tail-merge.c
index e95879fb8aa07a936be1d1c8b94aaff911c4971b..48f94217d16ede158d81ef2d3d556c6548a54e8c 100644 (file)
@@ -1,5 +1,5 @@
 /* Tail merging for gimple.
-   Copyright (C) 2011-2016 Free Software Foundation, Inc.
+   Copyright (C) 2011-2021 Free Software Foundation, Inc.
    Contributed by Tom de Vries (tom@codesourcery.com)
 
 This file is part of GCC.
@@ -201,9 +201,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
 #include "tree-into-ssa.h"
-#include "params.h"
 #include "tree-ssa-sccvn.h"
 #include "cfgloop.h"
+#include "tree-eh.h"
+#include "tree-cfgcleanup.h"
+
+const int ignore_edge_flags = EDGE_DFS_BACK | EDGE_EXECUTABLE;
 
 /* Describes a group of bbs with the same successors.  The successor bbs are
    cached in succs, and the successor edge flags are cached in succ_flags.
@@ -282,6 +285,21 @@ struct aux_bb_info
 #define BB_VOP_AT_EXIT(bb) (((struct aux_bb_info *)bb->aux)->vop_at_exit)
 #define BB_DEP_BB(bb) (((struct aux_bb_info *)bb->aux)->dep_bb)
 
+/* Valueization helper querying the VN lattice.  */
+
+static tree
+tail_merge_valueize (tree name)
+{
+  if (TREE_CODE (name) == SSA_NAME
+      && has_VN_INFO (name))
+    {
+      tree tem = VN_INFO (name)->valnum;
+      if (tem != VN_TOP)
+       return tem;
+    }
+  return name;
+}
+
 /* Returns true if the only effect a statement STMT has, is to define locally
    used SSA_NAMEs.  */
 
@@ -297,7 +315,15 @@ stmt_local_def (gimple *stmt)
   if (gimple_vdef (stmt) != NULL_TREE
       || gimple_has_side_effects (stmt)
       || gimple_could_trap_p_1 (stmt, false, false)
-      || gimple_vuse (stmt) != NULL_TREE)
+      || gimple_vuse (stmt) != NULL_TREE
+      /* Copied from tree-ssa-ifcombine.c:bb_no_side_effects_p():
+        const calls don't match any of the above, yet they could
+        still have some side-effects - they could contain
+        gimple_could_trap_p statements, like floating point
+        exceptions or integer division by zero.  See PR70586.
+        FIXME: perhaps gimple_has_side_effects or gimple_could_trap_p
+        should handle this.  */
+      || is_gimple_call (stmt))
     return false;
 
   def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
@@ -359,7 +385,7 @@ gvn_uses_equal (tree val1, tree val2)
   if (val1 == val2)
     return true;
 
-  if (vn_valueize (val1) != vn_valueize (val2))
+  if (tail_merge_valueize (val1) != tail_merge_valueize (val2))
     return false;
 
   return ((TREE_CODE (val1) == SSA_NAME || CONSTANT_CLASS_P (val1))
@@ -469,7 +495,7 @@ same_succ_hash (const same_succ *e)
       for (i = 0; i < gimple_call_num_args (stmt); i++)
        {
          arg = gimple_call_arg (stmt, i);
-         arg = vn_valueize (arg);
+         arg = tail_merge_valueize (arg);
          inchash::add_expr (arg, hstate);
        }
     }
@@ -477,6 +503,8 @@ same_succ_hash (const same_succ *e)
   hstate.add_int (size);
   BB_SIZE (bb) = size;
 
+  hstate.add_int (bb->loop_father->num);
+
   for (i = 0; i < e->succ_flags.length (); ++i)
     {
       flags = e->succ_flags[i];
@@ -538,6 +566,9 @@ same_succ::equal (const same_succ *e1, const same_succ *e2)
   gimple *s1, *s2;
   basic_block bb1, bb2;
 
+  if (e1 == e2)
+    return 1;
+
   if (e1->hashval != e2->hashval)
     return 0;
 
@@ -563,6 +594,9 @@ same_succ::equal (const same_succ *e1, const same_succ *e2)
   if (BB_SIZE (bb1) != BB_SIZE (bb2))
     return 0;
 
+  if (bb1->loop_father != bb2->loop_father)
+    return 0;
+
   gsi1 = gsi_start_nondebug_bb (bb1);
   gsi2 = gsi_start_nondebug_bb (bb2);
   gsi_advance_fw_nondebug_nonlocal (&gsi1);
@@ -690,22 +724,14 @@ find_same_succ_bb (basic_block bb, same_succ **same_p)
   edge_iterator ei;
   edge e;
 
-  if (bb == NULL
-      /* Be conservative with loop structure.  It's not evident that this test
-        is sufficient.  Before tail-merge, we've just called
-        loop_optimizer_finalize, and LOOPS_MAY_HAVE_MULTIPLE_LATCHES is now
-        set, so there's no guarantee that the loop->latch value is still valid.
-        But we assume that, since we've forced LOOPS_HAVE_SIMPLE_LATCHES at the
-        start of pre, we've kept that property intact throughout pre, and are
-        keeping it throughout tail-merge using this test.  */
-      || bb->loop_father->latch == bb)
+  if (bb == NULL)
     return;
   bitmap_set_bit (same->bbs, bb->index);
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
       int index = e->dest->index;
       bitmap_set_bit (same->succs, index);
-      same_succ_edge_flags[index] = e->flags;
+      same_succ_edge_flags[index] = (e->flags & ~ignore_edge_flags);
     }
   EXECUTE_IF_SET_IN_BITMAP (same->succs, 0, j, bj)
     same->succ_flags.safe_push (same_succ_edge_flags[j]);
@@ -804,6 +830,9 @@ static void
 same_succ_flush_bb (basic_block bb)
 {
   same_succ *same = BB_SAME_SUCC (bb);
+  if (! same)
+    return;
+
   BB_SAME_SUCC (bb) = NULL;
   if (bitmap_single_bit_set_p (same->bbs))
     same_succ_htab->remove_elt_with_hash (same, same->hashval);
@@ -1132,7 +1161,7 @@ gimple_equal_p (same_succ *same_succ, gimple *s1, gimple *s2)
       if (lhs1 == NULL_TREE || lhs2 == NULL_TREE)
        return false;
       if (TREE_CODE (lhs1) == SSA_NAME && TREE_CODE (lhs2) == SSA_NAME)
-       return vn_valueize (lhs1) == vn_valueize (lhs2);
+       return tail_merge_valueize (lhs1) == tail_merge_valueize (lhs2);
       return operand_equal_p (lhs1, lhs2, 0);
 
     case GIMPLE_ASSIGN:
@@ -1160,8 +1189,8 @@ gimple_equal_p (same_succ *same_succ, gimple *s1, gimple *s2)
       if (!gimple_operand_equal_value_p (t1, t2))
        return false;
 
-      code1 = gimple_expr_code (s1);
-      code2 = gimple_expr_code (s2);
+      code1 = gimple_cond_code (s1);
+      code2 = gimple_cond_code (s2);
       inv_cond = (bitmap_bit_p (same_succ->inverse, bb1->index)
                  != bitmap_bit_p (same_succ->inverse, bb2->index));
       if (inv_cond)
@@ -1219,6 +1248,10 @@ merge_stmts_p (gimple *stmt1, gimple *stmt2)
   if (is_tm_ending (stmt1))
     return false;
 
+  /* Verify EH landing pads.  */
+  if (lookup_stmt_eh_lp_fn (cfun, stmt1) != lookup_stmt_eh_lp_fn (cfun, stmt2))
+    return false;
+
   if (is_gimple_call (stmt1)
       && gimple_call_internal_p (stmt1))
     switch (gimple_call_internal_fn (stmt1))
@@ -1230,6 +1263,7 @@ merge_stmts_p (gimple *stmt1, gimple *stmt2)
       case IFN_UBSAN_CHECK_SUB:
       case IFN_UBSAN_CHECK_MUL:
       case IFN_UBSAN_OBJECT_SIZE:
+      case IFN_UBSAN_PTR:
       case IFN_ASAN_CHECK:
        /* For these internal functions, gimple_location is an implicit
           parameter, which will be used explicitly after expansion.
@@ -1262,6 +1296,10 @@ find_duplicate (same_succ *same_succ, basic_block bb1, basic_block bb2)
       gimple *stmt1 = gsi_stmt (gsi1);
       gimple *stmt2 = gsi_stmt (gsi2);
 
+      if (gimple_code (stmt1) == GIMPLE_LABEL
+         && gimple_code (stmt2) == GIMPLE_LABEL)
+       break;
+
       if (!gimple_equal_p (same_succ, stmt1, stmt2))
        return;
 
@@ -1274,6 +1312,20 @@ find_duplicate (same_succ *same_succ, basic_block bb1, basic_block bb2)
       gsi_advance_bw_nondebug_nonlocal (&gsi2, &vuse2, &vuse_escaped);
     }
 
+  while (!gsi_end_p (gsi1) && gimple_code (gsi_stmt (gsi1)) == GIMPLE_LABEL)
+    {
+      tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi1)));
+      if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
+       return;
+      gsi_prev (&gsi1);
+    }
+  while (!gsi_end_p (gsi2) && gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL)
+    {
+      tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)));
+      if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
+       return;
+      gsi_prev (&gsi2);
+    }
   if (!(gsi_end_p (gsi1) && gsi_end_p (gsi2)))
     return;
 
@@ -1377,11 +1429,11 @@ deps_ok_for_redirect_from_bb_to_bb (basic_block from, basic_block to)
   basic_block cd, dep_bb = BB_DEP_BB (to);
   edge_iterator ei;
   edge e;
-  bitmap from_preds = BITMAP_ALLOC (NULL);
 
   if (dep_bb == NULL)
     return true;
 
+  bitmap from_preds = BITMAP_ALLOC (NULL);
   FOR_EACH_EDGE (e, ei, from->preds)
     bitmap_set_bit (from_preds, e->src->index);
   cd = nearest_common_dominator_for_set (CDI_DOMINATORS, from_preds);
@@ -1416,7 +1468,7 @@ find_clusters_1 (same_succ *same_succ)
   unsigned int i, j;
   bitmap_iterator bi, bj;
   int nr_comparisons;
-  int max_comparisons = PARAM_VALUE (PARAM_MAX_TAIL_MERGE_COMPARISONS);
+  int max_comparisons = param_max_tail_merge_comparisons;
 
   EXECUTE_IF_SET_IN_BITMAP (same_succ->bbs, 0, i, bi)
     {
@@ -1425,7 +1477,8 @@ find_clusters_1 (same_succ *same_succ)
       /* TODO: handle blocks with phi-nodes.  We'll have to find corresponding
         phi-nodes in bb1 and bb2, with the same alternatives for the same
         preds.  */
-      if (bb_has_non_vop_phi (bb1))
+      if (bb_has_non_vop_phi (bb1) || bb_has_eh_pred (bb1)
+         || bb_has_abnormal_pred (bb1))
        continue;
 
       nr_comparisons = 0;
@@ -1433,7 +1486,8 @@ find_clusters_1 (same_succ *same_succ)
        {
          bb2 = BASIC_BLOCK_FOR_FN (cfun, j);
 
-         if (bb_has_non_vop_phi (bb2))
+         if (bb_has_non_vop_phi (bb2) || bb_has_eh_pred (bb2)
+             || bb_has_abnormal_pred (bb2))
            continue;
 
          if (BB_CLUSTER (bb1) != NULL && BB_CLUSTER (bb1) == BB_CLUSTER (bb2))
@@ -1500,8 +1554,6 @@ static void
 replace_block_by (basic_block bb1, basic_block bb2)
 {
   edge pred_edge;
-  edge e1, e2;
-  edge_iterator ei;
   unsigned int i;
   gphi *bb2_phi;
 
@@ -1528,28 +1580,40 @@ replace_block_by (basic_block bb1, basic_block bb2)
                   pred_edge, UNKNOWN_LOCATION);
     }
 
-  bb2->frequency += bb1->frequency;
-  if (bb2->frequency > BB_FREQ_MAX)
-    bb2->frequency = BB_FREQ_MAX;
 
+  /* Merge the outgoing edge counts from bb1 onto bb2.  */
+  edge e1, e2;
+  edge_iterator ei;
+
+  if (bb2->count.initialized_p ())
+    FOR_EACH_EDGE (e1, ei, bb1->succs)
+      {
+        e2 = find_edge (bb2, e1->dest);
+        gcc_assert (e2);
+
+       /* If probabilities are same, we are done.
+          If counts are nonzero we can distribute accordingly. In remaining
+          cases just avreage the values and hope for the best.  */
+       e2->probability = e1->probability.combine_with_count
+                            (bb1->count, e2->probability, bb2->count);
+      }
   bb2->count += bb1->count;
 
-  /* Merge the outgoing edge counts from bb1 onto bb2.  */
-  gcov_type out_sum = 0;
-  FOR_EACH_EDGE (e1, ei, bb1->succs)
-    {
-      e2 = find_edge (bb2, e1->dest);
-      gcc_assert (e2);
-      e2->count += e1->count;
-      out_sum += e2->count;
-    }
-  /* Recompute the edge probabilities from the new merged edge count.
-     Use the sum of the new merged edge counts computed above instead
-     of bb2's merged count, in case there are profile count insanities
-     making the bb count inconsistent with the edge weights.  */
-  FOR_EACH_EDGE (e2, ei, bb2->succs)
+  /* Move over any user labels from bb1 after the bb2 labels.  */
+  gimple_stmt_iterator gsi1 = gsi_start_bb (bb1);
+  if (!gsi_end_p (gsi1) && gimple_code (gsi_stmt (gsi1)) == GIMPLE_LABEL)
     {
-      e2->probability = GCOV_COMPUTE_SCALE (e2->count, out_sum);
+      gimple_stmt_iterator gsi2 = gsi_after_labels (bb2);
+      while (!gsi_end_p (gsi1)
+            && gimple_code (gsi_stmt (gsi1)) == GIMPLE_LABEL)
+       {
+         tree label = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi1)));
+         gcc_assert (!DECL_NONLOCAL (label) && !FORCED_LABEL (label));
+         if (DECL_ARTIFICIAL (label))
+           gsi_next (&gsi1);
+         else
+           gsi_move_before (&gsi1, &gsi2);
+       }
     }
 
   /* Clear range info from all stmts in BB2 -- this transformation
@@ -1666,7 +1730,7 @@ tail_merge_optimize (unsigned int todo)
   int nr_bbs_removed;
   bool loop_entered = false;
   int iteration_nr = 0;
-  int max_iterations = PARAM_VALUE (PARAM_MAX_TAIL_MERGE_ITERATIONS);
+  int max_iterations = param_max_tail_merge_iterations;
 
   if (!flag_tree_tail_merge
       || max_iterations == 0)
@@ -1674,6 +1738,16 @@ tail_merge_optimize (unsigned int todo)
 
   timevar_push (TV_TREE_TAIL_MERGE);
 
+  /* We enter from PRE which has critical edges split.  Elimination
+     does not process trivially dead code so cleanup the CFG if we
+     are told so.  And re-split critical edges then.  */
+  if (todo & TODO_cleanup_cfg)
+    {
+      cleanup_tree_cfg ();
+      todo &= ~TODO_cleanup_cfg;
+      split_edges_for_insertion ();
+    }
+
   if (!dom_info_available_p (CDI_DOMINATORS))
     {
       /* PRE can leave us with unreachable blocks, remove them now.  */
@@ -1722,7 +1796,7 @@ tail_merge_optimize (unsigned int todo)
 
   if (nr_bbs_removed_total > 0)
     {
-      if (MAY_HAVE_DEBUG_STMTS)
+      if (MAY_HAVE_DEBUG_BIND_STMTS)
        {
          calculate_dominance_info (CDI_DOMINATORS);
          update_debug_stmts ();