Hi,
Tree if-conv has below code checking on virtual PHI nodes in 
if_convertible__phi_p:

  if (any_mask_load_store)
    return true;

  /* When there were no if-convertible stores, check
     that there are no memory writes in the branches of the loop to be
     if-converted.  */
  if (virtual_operand_p (gimple_phi_result (phi)))
    {
      imm_use_iterator imm_iter;
      use_operand_p use_p;

      if (bb != loop->header)
        {
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "Virtual phi not on loop->header.\n");
          return false;
        }

      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (phi))
        {
          if (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI
              && USE_STMT (use_p) != phi)
            {
              if (dump_file && (dump_flags & TDF_DETAILS))
                fprintf (dump_file, "Difficult to handle this virtual phi.\n");
              return false;
            }
        }
    }

After investigation, I think it's to bypass code in the form of:

<bb header>
  .MEM_2232 = PHI <.MEM_574(179), .MEM_1247(183)>     // <----PHI_1
  ...
  if (cond)
    goto <bb 1>
  else
    goto <bb2>

<bb 1>:  //empty
<bb2>:
  .MEM_1247 = PHI <.MEM_2232(180), .MEM_2232(181)>     // <----PHI_2
  if (cond2)
    goto <bb exit>
  else
    goto <bb latch>

<bb latch>:
  goto <bb header>

Here PHI_2 can be degenerated and deleted.  Furthermore, after propagating 
.MEM_2232 to .MEM_1247's uses, PHI_1 can also be degenerated and deleted in 
this case.  These cases are bypassed because tree if-conv doesn't handle 
virtual PHI nodes during loop conversion (it only predicates scalar PHI nodes). 
 Of course this results in loops not converted, and not vectorized.
This patch firstly deletes the aforementioned checking code, then adds code 
handling such virtual PHIs during conversion.  The use of `any_mask_load_store' 
now is less ambiguous with this change, which allows further cleanups and 
patches fixing PR56541.
BTW, I think the newly fix at PR70725 on PHI nodes with only one argument is a 
special case covered by this change too.  Unfortunately I can't use 
replace_uses_by because I need to handle PHIs at use point after replacing too. 
 This doesn't really matter since we only care about virtual PHI, it's not 
possible to be used by anything other than IR itself.
Bootstrap and test on x86_64 and AArch64, is it OK if no regressions?

Thanks,
bin

2016-04-22  Bin Cheng  <bin.ch...@arm.com>

        * tree-if-conv.c (if_convertible_phi_p): Remove check on special
        virtual PHI nodes.  Delete parameter.
        (if_convertible_loop_p_1): Delete argument to above function.
        (degenerate_virtual_phi): New function.
        (predicate_all_scalar_phis): Rename to ...
        (process_all_phis): ... here.  Call degenerate_virtual_phi to
        handle virtual PHIs.
        (combine_blocks): Call renamed function.

Index: gcc/tree-if-conv.c
===================================================================
--- gcc/tree-if-conv.c  (revision 235359)
+++ gcc/tree-if-conv.c  (working copy)
@@ -640,16 +640,11 @@ phi_convertible_by_degenerating_args (gphi *phi)
    PHI is not if-convertible if:
    - it has more than 2 arguments.
 
-   When we didn't see if-convertible stores, PHI is not
-   if-convertible if:
-   - a virtual PHI is immediately used in another PHI node,
-   - there is a virtual PHI in a BB other than the loop->header.
    When the aggressive_if_conv is set, PHI can have more than
    two arguments.  */
 
 static bool
-if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi,
-                     bool any_mask_load_store)
+if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -669,36 +664,6 @@ static bool
         }
     }
 
-  if (any_mask_load_store)
-    return true;
-
-  /* When there were no if-convertible stores, check
-     that there are no memory writes in the branches of the loop to be
-     if-converted.  */
-  if (virtual_operand_p (gimple_phi_result (phi)))
-    {
-      imm_use_iterator imm_iter;
-      use_operand_p use_p;
-
-      if (bb != loop->header)
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "Virtual phi not on loop->header.\n");
-         return false;
-       }
-
-      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (phi))
-       {
-         if (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI
-             && USE_STMT (use_p) != phi)
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "Difficult to handle this virtual phi.\n");
-             return false;
-           }
-       }
-    }
-
   return true;
 }
 
@@ -1405,8 +1370,7 @@ if_convertible_loop_p_1 (struct loop *loop,
       gphi_iterator itr;
 
       for (itr = gsi_start_phis (bb); !gsi_end_p (itr); gsi_next (&itr))
-       if (!if_convertible_phi_p (loop, bb, itr.phi (),
-                                  *any_mask_load_store))
+       if (!if_convertible_phi_p (loop, bb, itr.phi ()))
          return false;
     }
 
@@ -1682,6 +1646,58 @@ gen_phi_arg_condition (gphi *phi, vec<int> *occur,
   return cond;
 }
 
+/* Degenerate virtual PHI node by propagating its operand to all uses
+   of its def.  After degeneration, the PHI node becomes dead and is
+   removed.  This function also tries to degenerate other virtual phi
+   nodes in LOOP after propagation.  */
+
+static void
+degenerate_virtual_phi (struct loop *loop, gphi *phi)
+{
+  auto_vec<gphi *, 4> worklist;
+
+  worklist.safe_push (phi);
+  while (worklist.length () > 0)
+    {
+      tree vop, vdef;
+      gimple *use_stmt;
+      imm_use_iterator iter;
+      gimple_stmt_iterator gsi;
+
+      phi = worklist.pop ();
+      vop = degenerate_phi_result (phi);
+      gcc_assert (vop != NULL);
+
+      /* Degenerate PHI by replacing def with op.  */
+      vdef = gimple_phi_result (phi);
+      FOR_EACH_IMM_USE_STMT (use_stmt, iter, vdef)
+       {
+         use_operand_p use_p;
+         gphi *use_phi = dyn_cast <gphi *> (use_stmt);
+
+         /* Skip use in itself.  */
+         if (use_phi == phi)
+           continue;
+
+         FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+           SET_USE (use_p, vop);
+
+         update_stmt(use_stmt);
+         /* Check if new PHI node can be degenerated or not.  */
+         if (use_phi
+             && virtual_operand_p (gimple_phi_result (use_phi))
+             && flow_bb_inside_loop_p (loop, gimple_bb (use_phi))
+             && degenerate_phi_result (use_phi))
+           worklist.safe_push (use_phi);
+       }
+      gsi = gsi_for_stmt (phi);
+      remove_phi_node (&gsi, true);
+      if (TREE_CODE (vop) == SSA_NAME
+         && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vdef))
+       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vop) = 1;
+    }
+}
+
 /* Replace a scalar PHI node with a COND_EXPR using COND as condition.
    This routine can handle PHI nodes with more than two arguments.
 
@@ -1895,7 +1911,7 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_itera
    LOOP->header block with conditional modify expressions.  */
 
 static void
-predicate_all_scalar_phis (struct loop *loop)
+process_all_phis (struct loop *loop)
 {
   basic_block bb;
   unsigned int orig_loop_num_nodes = loop->num_nodes;
@@ -1915,27 +1931,19 @@ static void
       if (gsi_end_p (phi_gsi))
        continue;
 
-      if (EDGE_COUNT (bb->preds) == 1)
+      gsi = gsi_after_labels (bb);
+      while (!gsi_end_p (phi_gsi))
        {
-         /* Propagate degenerate PHIs.  */
-         for (phi_gsi = gsi_start_phis (bb); !gsi_end_p (phi_gsi);
-              gsi_next (&phi_gsi))
+         phi = phi_gsi.phi ();
+         if (virtual_operand_p (gimple_phi_result (phi))
+             && degenerate_phi_result (phi) != NULL)
+           degenerate_virtual_phi (loop, phi);
+         else
            {
-             gphi *phi = phi_gsi.phi ();
-             replace_uses_by (gimple_phi_result (phi),
-                              gimple_phi_arg_def (phi, 0));
-           }
-       }
-      else
-       {
-         gsi = gsi_after_labels (bb);
-         while (!gsi_end_p (phi_gsi))
-           {
-             phi = phi_gsi.phi ();
              predicate_scalar_phi (phi, &gsi);
              release_phi_node (phi);
-             gsi_next (&phi_gsi);
            }
+         gsi_next (&phi_gsi);
        }
 
       set_phi_nodes (bb, NULL);
@@ -2289,7 +2297,7 @@ combine_blocks (struct loop *loop, bool any_mask_l
   predicate_bbs (loop);
   remove_conditions_and_labels (loop);
   insert_gimplified_predicates (loop, any_mask_load_store);
-  predicate_all_scalar_phis (loop);
+  process_all_phis (loop);
 
   if (any_mask_load_store)
     predicate_mem_writes (loop);

Reply via email to