diff gcc/tree-if-conv.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/tree-if-conv.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/tree-if-conv.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* If-conversion for vectorizer.
-   Copyright (C) 2004-2018 Free Software Foundation, Inc.
+   Copyright (C) 2004-2020 Free Software Foundation, Inc.
    Contributed by Devang Patel <dpatel@apple.com>
 
 This file is part of GCC.
@@ -114,15 +114,17 @@
 #include "tree-hash-traits.h"
 #include "varasm.h"
 #include "builtins.h"
-#include "params.h"
 #include "cfganal.h"
 #include "internal-fn.h"
 #include "fold-const.h"
+#include "tree-ssa-sccvn.h"
+#include "tree-cfgcleanup.h"
+#include "tree-ssa-dse.h"
 
 /* Only handle PHIs with no more arguments unless we are asked to by
    simd pragma.  */
 #define MAX_PHI_ARG_NUM \
-  ((unsigned) PARAM_VALUE (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS))
+  ((unsigned) param_max_tree_if_conversion_phi_args)
 
 /* True if we've converted a statement that was only executed when some
    condition C was true, and if for correctness we need to predicate the
@@ -434,7 +436,7 @@
 
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
-      tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
+      tree t = maybe_fold_or_comparisons (boolean_type_node, code1, op1a, op1b,
 					  code2, op2a, op2b);
       if (t)
 	return t;
@@ -500,7 +502,7 @@
    cd-equivalent if they are executed under the same condition.  */
 
 static inline void
-add_to_predicate_list (struct loop *loop, basic_block bb, tree nc)
+add_to_predicate_list (class loop *loop, basic_block bb, tree nc)
 {
   tree bc, *tp;
   basic_block dom_bb;
@@ -565,7 +567,7 @@
    the loop to be if-converted.  */
 
 static void
-add_to_dst_predicate_list (struct loop *loop, edge e,
+add_to_dst_predicate_list (class loop *loop, edge e,
 			   tree prev_cond, tree cond)
 {
   if (!flow_bb_inside_loop_p (loop, e->dest))
@@ -582,7 +584,7 @@
 /* Return true if one of the successor edges of BB exits LOOP.  */
 
 static bool
-bb_with_exit_edge_p (struct loop *loop, basic_block bb)
+bb_with_exit_edge_p (class loop *loop, basic_block bb)
 {
   edge e;
   edge_iterator ei;
@@ -659,7 +661,7 @@
    ANY_COMPLICATED_PHI if PHI is complicated.  */
 
 static bool
-if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
+if_convertible_phi_p (class loop *loop, basic_block bb, gphi *phi)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -754,7 +756,7 @@
   widest_int niter, valid_niter, delta, wi_step;
   tree ev, init, step;
   tree low, high;
-  struct loop *loop = (struct loop*) dta;
+  class loop *loop = (class loop*) dta;
 
   /* Only support within-bound access for array references.  */
   if (TREE_CODE (ref) != ARRAY_REF)
@@ -820,7 +822,7 @@
 static bool
 ref_within_array_bound (gimple *stmt, tree ref)
 {
-  struct loop *loop = loop_containing_stmt (stmt);
+  class loop *loop = loop_containing_stmt (stmt);
 
   gcc_assert (loop != NULL);
   return for_each_index (&ref, idx_within_array_bound, loop);
@@ -911,10 +913,10 @@
          to unconditionally.  */
       if (base_master_dr
 	  && DR_BASE_W_UNCONDITIONALLY (*base_master_dr))
-	return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
+	return flag_store_data_races;
       /* or the base is known to be not readonly.  */
       else if (base_object_writable (DR_REF (a)))
-	return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
+	return flag_store_data_races;
     }
 
   return false;
@@ -1126,7 +1128,7 @@
    inside LOOP.  */
 
 static bool
-if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
+if_convertible_bb_p (class loop *loop, basic_block bb, basic_block exit_bb)
 {
   edge e;
   edge_iterator ei;
@@ -1195,7 +1197,7 @@
    predecessors are already selected.  */
 
 static basic_block *
-get_loop_body_in_if_conv_order (const struct loop *loop)
+get_loop_body_in_if_conv_order (const class loop *loop)
 {
   basic_block *blocks, *blocks_in_bfs_order;
   basic_block bb;
@@ -1342,7 +1344,7 @@
 /* Build region by adding loop pre-header and post-header blocks.  */
 
 static vec<basic_block>
-build_region (struct loop *loop)
+build_region (class loop *loop)
 {
   vec<basic_block> region = vNULL;
   basic_block exit_bb = NULL;
@@ -1376,7 +1378,7 @@
    in if_convertible_loop_p.  */
 
 static bool
-if_convertible_loop_p_1 (struct loop *loop, vec<data_reference_p> *refs)
+if_convertible_loop_p_1 (class loop *loop, vec<data_reference_p> *refs)
 {
   unsigned int i;
   basic_block exit_bb = NULL;
@@ -1516,7 +1518,7 @@
    - if its basic blocks and phi nodes are if convertible.  */
 
 static bool
-if_convertible_loop_p (struct loop *loop)
+if_convertible_loop_p (class loop *loop)
 {
   edge e;
   edge_iterator ei;
@@ -1595,7 +1597,7 @@
   gimple *header_phi = NULL;
   enum tree_code reduction_op;
   basic_block bb = gimple_bb (phi);
-  struct loop *loop = bb->loop_father;
+  class loop *loop = bb->loop_father;
   edge latch_e = loop_latch_edge (loop);
   imm_use_iterator imm_iter;
   use_operand_p use_p;
@@ -2002,7 +2004,7 @@
    LOOP->header block with conditional modify expressions.  */
 
 static void
-predicate_all_scalar_phis (struct loop *loop)
+predicate_all_scalar_phis (class loop *loop)
 {
   basic_block bb;
   unsigned int orig_loop_num_nodes = loop->num_nodes;
@@ -2139,9 +2141,7 @@
       new_stmt
 	= gimple_build_call_internal (IFN_MASK_STORE, 4, addr, ptr,
 				      mask, rhs);
-      gimple_set_vuse (new_stmt, gimple_vuse (stmt));
-      gimple_set_vdef (new_stmt, gimple_vdef (stmt));
-      SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+      gimple_move_vops (new_stmt, stmt);
     }
   gimple_call_set_nothrow (new_stmt, true);
   return new_stmt;
@@ -2524,7 +2524,7 @@
    blocks.  Replace PHI nodes with conditional modify expressions.  */
 
 static void
-combine_blocks (struct loop *loop)
+combine_blocks (class loop *loop)
 {
   basic_block bb, exit_bb, merge_target_bb;
   unsigned int orig_loop_num_nodes = loop->num_nodes;
@@ -2624,6 +2624,11 @@
       vphi = get_virtual_phi (bb);
       if (vphi)
 	{
+	  /* When there's just loads inside the loop a stray virtual
+	     PHI merging the uses can appear, update last_vdef from
+	     it.  */
+	  if (!last_vdef)
+	    last_vdef = gimple_phi_arg_def (vphi, 0);
 	  imm_use_iterator iter;
 	  use_operand_p use_p;
 	  gimple *use_stmt;
@@ -2632,6 +2637,8 @@
 	      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
 		SET_USE (use_p, last_vdef);
 	    }
+	  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (vphi)))
+	    SSA_NAME_OCCURS_IN_ABNORMAL_PHI (last_vdef) = 1;
 	  gsi = gsi_for_stmt (vphi); 
 	  remove_phi_node (&gsi, true);
 	}
@@ -2653,6 +2660,10 @@
 	      if (gimple_vdef (stmt))
 		last_vdef = gimple_vdef (stmt);
 	    }
+	  else
+	    /* If this is the first load we arrive at update last_vdef
+	       so we handle stray PHIs correctly.  */
+	    last_vdef = gimple_vuse (stmt);
 	  if (predicated[i])
 	    {
 	      ssa_op_iter i;
@@ -2690,6 +2701,8 @@
 	      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
 		SET_USE (use_p, last_vdef);
 	    }
+	  if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (vphi)))
+	    SSA_NAME_OCCURS_IN_ABNORMAL_PHI (last_vdef) = 1;
 	  gimple_stmt_iterator gsi = gsi_for_stmt (vphi); 
 	  remove_phi_node (&gsi, true);
 	}
@@ -2713,12 +2726,12 @@
    out of LOOP_VECTORIZED must have 100% probability so the profile remains
    consistent after the condition is folded in the vectorizer.  */
 
-static struct loop *
-version_loop_for_if_conversion (struct loop *loop)
+static class loop *
+version_loop_for_if_conversion (class loop *loop, vec<gimple *> *preds)
 {
   basic_block cond_bb;
   tree cond = make_ssa_name (boolean_type_node);
-  struct loop *new_loop;
+  class loop *new_loop;
   gimple *g;
   gimple_stmt_iterator gsi;
   unsigned int save_length;
@@ -2754,6 +2767,8 @@
   new_loop->force_vectorize = false;
   gsi = gsi_last_bb (cond_bb);
   gimple_call_set_arg (g, 1, build_int_cst (integer_type_node, new_loop->num));
+  if (preds)
+    preds->safe_push (g);
   gsi_insert_before (&gsi, g, GSI_SAME_STMT);
   update_ssa (TODO_update_ssa);
   return new_loop;
@@ -2773,7 +2788,7 @@
       inner loop's exit block.  */
 
 static bool
-versionable_outer_loop_p (struct loop *loop)
+versionable_outer_loop_p (class loop *loop)
 {
   if (!loop_outer (loop)
       || loop->dont_vectorize
@@ -2807,7 +2822,7 @@
    Last restriction is valid only if AGGRESSIVE_IF_CONV is false.  */
 
 static bool
-ifcvt_split_critical_edges (struct loop *loop, bool aggressive_if_conv)
+ifcvt_split_critical_edges (class loop *loop, bool aggressive_if_conv)
 {
   basic_block *body;
   basic_block bb;
@@ -2867,7 +2882,7 @@
    loop vectorization.  */
 
 static void
-ifcvt_local_dce (basic_block bb)
+ifcvt_local_dce (class loop *loop)
 {
   gimple *stmt;
   gimple *stmt1;
@@ -2884,6 +2899,10 @@
     replace_uses_by (name_pair->first, name_pair->second);
   redundant_ssa_names.release ();
 
+  /* The loop has a single BB only.  */
+  basic_block bb = loop->header;
+  tree latch_vdef = NULL_TREE;
+
   worklist.create (64);
   /* Consider all phi as live statements.  */
   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -2891,6 +2910,8 @@
       phi = gsi_stmt (gsi);
       gimple_set_plf (phi, GF_PLF_2, true);
       worklist.safe_push (phi);
+      if (virtual_operand_p (gimple_phi_result (phi)))
+	latch_vdef = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (loop));
     }
   /* Consider load/store statements, CALL and COND as live.  */
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -2954,6 +2975,20 @@
   while (!gsi_end_p (gsi))
     {
       stmt = gsi_stmt (gsi);
+      if (gimple_store_p (stmt))
+	{
+	  tree lhs = gimple_get_lhs (stmt);
+	  ao_ref write;
+	  ao_ref_init (&write, lhs);
+
+	  if (dse_classify_store (&write, stmt, false, NULL, NULL, latch_vdef)
+	      == DSE_STORE_DEAD)
+	    delete_dead_or_redundant_assignment (&gsi, "dead");
+	  else
+	    gsi_next (&gsi);
+	  continue;
+	}
+
       if (gimple_plf (stmt, GF_PLF_2))
 	{
 	  gsi_next (&gsi);
@@ -2974,11 +3009,12 @@
    changed.  */
 
 unsigned int
-tree_if_conversion (struct loop *loop)
+tree_if_conversion (class loop *loop, vec<gimple *> *preds)
 {
   unsigned int todo = 0;
   bool aggressive_if_conv;
-  struct loop *rloop;
+  class loop *rloop;
+  bitmap exit_bbs;
 
  again:
   rloop = NULL;
@@ -2992,7 +3028,7 @@
   aggressive_if_conv = loop->force_vectorize;
   if (!aggressive_if_conv)
     {
-      struct loop *outer_loop = loop_outer (loop);
+      class loop *outer_loop = loop_outer (loop);
       if (outer_loop && outer_loop->force_vectorize)
 	aggressive_if_conv = true;
     }
@@ -3018,10 +3054,10 @@
       || any_complicated_phi
       || flag_tree_loop_if_convert != 1)
     {
-      struct loop *vloop
+      class loop *vloop
 	= (versionable_outer_loop_p (loop_outer (loop))
 	   ? loop_outer (loop) : loop);
-      struct loop *nloop = version_loop_for_if_conversion (vloop);
+      class loop *nloop = version_loop_for_if_conversion (vloop, preds);
       if (nloop == NULL)
 	goto cleanup;
       if (vloop != loop)
@@ -3053,8 +3089,18 @@
      on-the-fly.  */
   combine_blocks (loop);
 
+  /* Perform local CSE, this esp. helps the vectorizer analysis if loads
+     and stores are involved.  CSE only the loop body, not the entry
+     PHIs, those are to be kept in sync with the non-if-converted copy.
+     ???  We'll still keep dead stores though.  */
+  exit_bbs = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (exit_bbs, single_exit (loop)->dest->index);
+  bitmap_set_bit (exit_bbs, loop->latch->index);
+  todo |= do_rpo_vn (cfun, loop_preheader_edge (loop), exit_bbs);
+
   /* Delete dead predicate computations.  */
-  ifcvt_local_dce (loop->header);
+  ifcvt_local_dce (loop);
+  BITMAP_FREE (exit_bbs);
 
   todo |= TODO_cleanup_cfg;
 
@@ -3119,17 +3165,18 @@
 unsigned int
 pass_if_conversion::execute (function *fun)
 {
-  struct loop *loop;
+  class loop *loop;
   unsigned todo = 0;
 
   if (number_of_loops (fun) <= 1)
     return 0;
 
+  auto_vec<gimple *> preds;
   FOR_EACH_LOOP (loop, 0)
     if (flag_tree_loop_if_convert == 1
 	|| ((flag_tree_loop_vectorize || loop->force_vectorize)
 	    && !loop->dont_vectorize))
-      todo |= tree_if_conversion (loop);
+      todo |= tree_if_conversion (loop, &preds);
 
   if (todo)
     {
@@ -3144,7 +3191,32 @@
 	gcc_assert (!bb->aux);
     }
 
-  return todo;
+  /* Perform IL update now, it might elide some loops.  */
+  if (todo & TODO_cleanup_cfg)
+    {
+      cleanup_tree_cfg ();
+      if (need_ssa_update_p (fun))
+	todo |= TODO_update_ssa;
+    }
+  if (todo & TODO_update_ssa_any)
+    update_ssa (todo & TODO_update_ssa_any);
+
+  /* If if-conversion elided the loop fall back to the original one.  */
+  for (unsigned i = 0; i < preds.length (); ++i)
+    {
+      gimple *g = preds[i];
+      if (!gimple_bb (g))
+	continue;
+      unsigned ifcvt_loop = tree_to_uhwi (gimple_call_arg (g, 0));
+      if (!get_loop (fun, ifcvt_loop))
+	{
+	  if (dump_file)
+	    fprintf (dump_file, "If-converted loop vanished\n");
+	  fold_loop_internal_call (g, boolean_false_node);
+	}
+    }
+
+  return 0;
 }
 
 } // anon namespace