re PR tree-optimization/56541 (vectorizaton fails in conditional assignment of a...
authorBin Cheng <bin.cheng@arm.com>
Tue, 3 May 2016 09:04:46 +0000 (09:04 +0000)
committerBin Cheng <amker@gcc.gnu.org>
Tue, 3 May 2016 09:04:46 +0000 (09:04 +0000)
PR tree-optimization/56541
* doc/invoke.texi (@item max-tree-if-conversion-phi-args): New item.
* params.def (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS): new param.
* tree-if-conv.c (MAX_PHI_ARG_NUM): new macro.
(any_complicated_phi): new static variable.
(aggressive_if_conv): delete.
(if_convertible_phi_p): support phis with more than two arguments.
(if_convertible_bb_p): remvoe check on aggressive_if_conv and
critical pred edges.
(ifcvt_split_critical_edges): support phis with more than two
arguments by checking new parameter.  only split critical edges
if needed.
(tree_if_conversion): handle simd pragma marked loop using new
local variable aggressive_if_conv.  check any_complicated_phi.

gcc/testsuite
PR tree-optimization/56541
* gcc.dg/tree-ssa/ifc-pr56541.c: new test.
* gcc.dg/vect/pr56541.c: new test.

From-SVN: r235808

gcc/ChangeLog
gcc/doc/invoke.texi
gcc/params.def
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/vect/pr56541.c [new file with mode: 0644]
gcc/tree-if-conv.c

index 45670bc2000a4f4aca0182af056b20471dd645e3..ffe45b718a5bc1fca6cb3683c07f12d7f1f08116 100644 (file)
@@ -1,3 +1,20 @@
+2016-05-03  bin cheng  <bin.cheng@arm.com>
+
+       PR tree-optimization/56541
+       * doc/invoke.texi (@item max-tree-if-conversion-phi-args): New item.
+       * params.def (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS): new param.
+       * tree-if-conv.c (MAX_PHI_ARG_NUM): new macro.
+       (any_complicated_phi): new static variable.
+       (aggressive_if_conv): delete.
+       (if_convertible_phi_p): support phis with more than two arguments.
+       (if_convertible_bb_p): remvoe check on aggressive_if_conv and
+       critical pred edges.
+       (ifcvt_split_critical_edges): support phis with more than two
+       arguments by checking new parameter.  only split critical edges
+       if needed.
+       (tree_if_conversion): handle simd pragma marked loop using new
+       local variable aggressive_if_conv.  check any_complicated_phi.
+
 2016-05-03  Bin Cheng  <bin.cheng@arm.com>
 
        * tree-ssa-loop-ivopts.c (get_computation_cost_at): Check depends_on
index 515d948ce710a2fba98c586ea2efa05d4cf60979..f5413faf11615ae982aee1bea50720b62be37ecb 100644 (file)
@@ -9020,6 +9020,10 @@ Large expressions slow the analyzer.
 Bound on the complexity of the expressions in the scalar evolutions analyzer.
 Complex expressions slow the analyzer.
 
+@item max-tree-if-conversion-phi-args
+Maximum number of arguments in a PHI supported by TREE if conversion
+unless the loop is marked with simd pragma.
+
 @item vect-max-version-for-alignment-checks
 The maximum number of run-time checks that can be performed when
 doing loop versioning for alignment in the vectorizer.
index 9e05401f028ca0e54561c52e6541da10f4e60cf9..62a1e404a1aac763ae1187b98027d073bcd6f712 100644 (file)
@@ -530,6 +530,12 @@ DEFPARAM(PARAM_SCEV_MAX_EXPR_COMPLEXITY,
         "Bound on the complexity of the expressions in the scalar evolutions analyzer.",
         10, 0, 0)
 
+DEFPARAM (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS,
+         "max-tree-if-conversion-phi-args",
+         "Maximum number of arguments in a PHI supported by TREE if-conversion "
+         "unless the loop is marked with simd pragma.",
+         4, 2, 0)
+
 DEFPARAM(PARAM_VECT_MAX_VERSION_FOR_ALIGNMENT_CHECKS,
          "vect-max-version-for-alignment-checks",
          "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check.",
index 0f91bdf762893067524efbb4487d904a378990a6..6ce2c7e916c30fefddc4351a37b9d0ce49538e55 100644 (file)
@@ -1,3 +1,9 @@
+2016-05-03  bin cheng  <bin.cheng@arm.com>
+
+       PR tree-optimization/56541
+       * gcc.dg/tree-ssa/ifc-pr56541.c: new test.
+       * gcc.dg/vect/pr56541.c: new test.
+
 2016-05-02  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        * gcc.target/powerpc/float128-complex-1.c: New tests for complex
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c b/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c
new file mode 100644 (file)
index 0000000..a52baca
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-ifcvt-stats" } */
+
+float a,b,c,d;
+
+float z[1024]; int ok[1024];
+const float rBig = 150.;
+
+void foo()
+{
+  int i;
+
+  for (i=0; i!=1024; ++i)
+    {
+      float rR = a*z[i];
+      float rL = b*z[i];
+      float rMin = (rR<rL) ? rR : rL;
+      float rMax = (rR<rL) ? rL : rR;
+      rMin = (rMax>0) ? rMin : rBig;
+      rMin = (rMin>0) ? rMin : rMax;
+      ok[i] = rMin-c<rMax+d;
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr56541.c b/gcc/testsuite/gcc.dg/vect/pr56541.c
new file mode 100644 (file)
index 0000000..16b8d7c
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-require-effective-target vect_condition } */
+
+float a,b,c,d;
+
+float z[1024]; int ok[1024];
+const float rBig = 150.;
+
+void foo()
+{
+  int i;
+
+  for (i=0; i!=1024; ++i)
+    {
+      float rR = a*z[i];
+      float rL = b*z[i];
+      float rMin = (rR<rL) ? rR : rL;
+      float rMax = (rR<rL) ? rL : rR;
+      rMin = (rMax>0) ? rMin : rBig;
+      rMin = (rMin>0) ? rMin : rMax;
+      ok[i] = rMin-c<rMax+d;
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
index 32ced164081c34f268be740a15153987fa76b81d..97b62b7a79e94883b319f12a946729ac55f6f840 100644 (file)
@@ -113,11 +113,22 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "builtins.h"
 #include "params.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))
+
 /* Indicate if new load/store that needs to be predicated is introduced
    during if conversion.  */
 static bool any_pred_load_store;
 
+/* Indicate if there are any complicated PHIs that need to be handled in
+   if-conversion.  Complicated PHI has more than two arguments and can't
+   be degenerated to two arguments PHI.  See more information in comment
+   before phi_convertible_by_degenerating_args.  */
+static bool any_complicated_phi;
+
 /* Hash for struct innermost_loop_behavior.  It depends on the user to
    free the memory.  */
 
@@ -172,9 +183,6 @@ innermost_loop_behavior_hash::equal (const value_type &e1,
 /* List of basic blocks in if-conversion-suitable order.  */
 static basic_block *ifc_bbs;
 
-/* Apply more aggressive (extended) if-conversion if true.  */
-static bool aggressive_if_conv;
-
 /* Hash table to store <DR's innermost loop behavior, DR> pairs.  */
 static hash_map<innermost_loop_behavior_hash,
                data_reference_p> *innermost_DR_map;
@@ -639,13 +647,9 @@ phi_convertible_by_degenerating_args (gphi *phi)
 }
 
 /* Return true when PHI is if-convertible.  PHI is part of loop LOOP
-   and it belongs to basic block BB.
-
-   PHI is not if-convertible if:
-   - it has more than 2 arguments.
-
-   When the aggressive_if_conv is set, PHI can have more than
-   two arguments.  */
+   and it belongs to basic block BB.  Note at this point, it is sure
+   that PHI is if-convertible.  This function updates global variable
+   ANY_COMPLICATED_PHI if PHI is complicated.  */
 
 static bool
 if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
@@ -656,17 +660,10 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
       print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
     }
 
-  if (bb != loop->header)
-    {
-      if (gimple_phi_num_args (phi) > 2
-         && !aggressive_if_conv
-         && !phi_convertible_by_degenerating_args (phi))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "Phi can't be predicated by single cond.\n");
-         return false;
-        }
-    }
+  if (bb != loop->header
+      && gimple_phi_num_args (phi) > 2
+      && !phi_convertible_by_degenerating_args (phi))
+    any_complicated_phi = true;
 
   return true;
 }
@@ -1012,8 +1009,6 @@ has_pred_critical_p (basic_block bb)
    - it is after the exit block but before the latch,
    - its edges are not normal.
 
-   Last restriction is valid if aggressive_if_conv is false.
-
    EXIT_BB is the basic block containing the exit of the LOOP.  BB is
    inside LOOP.  */
 
@@ -1062,19 +1057,6 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
        return false;
       }
 
-  /* At least one incoming edge has to be non-critical as otherwise edge
-     predicates are not equal to basic-block predicates of the edge
-     source.  This check is skipped if aggressive_if_conv is true.  */
-  if (!aggressive_if_conv
-      && EDGE_COUNT (bb->preds) > 1
-      && bb != loop->header
-      && all_preds_critical_p (bb))
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       fprintf (dump_file, "only critical predecessors\n");
-      return false;
-    }
-
   return true;
 }
 
@@ -2380,11 +2362,16 @@ version_loop_for_if_conversion (struct loop *loop)
   return true;
 }
 
-/* Performs splitting of critical edges if aggressive_if_conv is true.
-   Returns false if loop won't be if converted and true otherwise.  */
+/* Performs splitting of critical edges.  Skip splitting and return false
+   if LOOP will not be converted because:
+
+     - LOOP is not well formed.
+     - LOOP has PHI with more than MAX_PHI_ARG_NUM arguments.
+
+   Last restriction is valid only if AGGRESSIVE_IF_CONV is false.  */
 
 static bool
-ifcvt_split_critical_edges (struct loop *loop)
+ifcvt_split_critical_edges (struct loop *loop, bool aggressive_if_conv)
 {
   basic_block *body;
   basic_block bb;
@@ -2393,30 +2380,51 @@ ifcvt_split_critical_edges (struct loop *loop)
   gimple *stmt;
   edge e;
   edge_iterator ei;
+  vec<edge> critical_edges = vNULL;
 
-  if (num <= 2)
-    return false;
-  if (loop->inner)
-    return false;
-  if (!single_exit (loop))
+  /* Loop is not well formed.  */
+  if (num <= 2 || loop->inner || !single_exit (loop))
     return false;
 
   body = get_loop_body (loop);
   for (i = 0; i < num; i++)
     {
       bb = body[i];
-      if (bb == loop->latch
-         || bb_with_exit_edge_p (loop, bb))
+      if (!aggressive_if_conv
+         && phi_nodes (bb)
+         && EDGE_COUNT (bb->preds) > MAX_PHI_ARG_NUM)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file,
+                    "BB %d has complicated PHI with more than %u args.\n",
+                    bb->index, MAX_PHI_ARG_NUM);
+
+         free (body);
+         critical_edges.release ();
+         return false;
+       }
+      if (bb == loop->latch || bb_with_exit_edge_p (loop, bb))
        continue;
+
       stmt = last_stmt (bb);
       /* Skip basic blocks not ending with conditional branch.  */
-      if (!(stmt && gimple_code (stmt) == GIMPLE_COND))
+      if (!stmt || gimple_code (stmt) != GIMPLE_COND)
        continue;
+
       FOR_EACH_EDGE (e, ei, bb->succs)
        if (EDGE_CRITICAL_P (e) && e->dest->loop_father == loop)
-         split_edge (e);
+         critical_edges.safe_push (e);
     }
   free (body);
+
+  while (critical_edges.length () > 0)
+    {
+      e = critical_edges.pop ();
+      /* Don't split if bb can be predicated along non-critical edge.  */
+      if (EDGE_COUNT (e->dest->preds) > 2 || all_preds_critical_p (e->dest))
+       split_edge (e);
+    }
+
   return true;
 }
 
@@ -2713,12 +2721,16 @@ static unsigned int
 tree_if_conversion (struct loop *loop)
 {
   unsigned int todo = 0;
+  bool aggressive_if_conv;
+
   ifc_bbs = NULL;
   any_pred_load_store = false;
+  any_complicated_phi = false;
 
-  /* Set up aggressive if-conversion for loops marked with simd pragma.  */
+  /* Apply more aggressive if-conversion when loop or its outer loop were
+     marked with simd pragma.  When that's the case, we try to if-convert
+     loop containing PHIs with more than MAX_PHI_ARG_NUM arguments.  */
   aggressive_if_conv = loop->force_vectorize;
-  /* Check either outer loop was marked with simd pragma.  */
   if (!aggressive_if_conv)
     {
       struct loop *outer_loop = loop_outer (loop);
@@ -2726,20 +2738,20 @@ tree_if_conversion (struct loop *loop)
        aggressive_if_conv = true;
     }
 
-  if (aggressive_if_conv)
-    if (!ifcvt_split_critical_edges (loop))
-      goto cleanup;
+  if (!ifcvt_split_critical_edges (loop, aggressive_if_conv))
+    goto cleanup;
 
   if (!if_convertible_loop_p (loop)
       || !dbg_cnt (if_conversion_tree))
     goto cleanup;
 
-  if (any_pred_load_store
+  if ((any_pred_load_store || any_complicated_phi)
       && ((!flag_tree_loop_vectorize && !loop->force_vectorize)
          || loop->dont_vectorize))
     goto cleanup;
 
-  if (any_pred_load_store && !version_loop_for_if_conversion (loop))
+  if ((any_pred_load_store || any_complicated_phi)
+      && !version_loop_for_if_conversion (loop))
     goto cleanup;
 
   /* Now all statements are if-convertible.  Combine all the basic
@@ -2749,11 +2761,8 @@ tree_if_conversion (struct loop *loop)
 
   /* Delete dead predicate computations and repair tree correspondent
      to bool pattern to delete multiple uses of predicates.  */
-  if (aggressive_if_conv)
-    {
-      ifcvt_local_dce (loop->header);
-      ifcvt_repair_bool_pattern (loop->header);
-    }
+  ifcvt_local_dce (loop->header);
+  ifcvt_repair_bool_pattern (loop->header);
 
   todo |= TODO_cleanup_cfg;
   mark_virtual_operands_for_renaming (cfun);