Currently we reject most commonalization of loads in factor_out_conditional_load
before the vectorizer.  This was done as the easiest and simpliest herustics at
the time I was writing the code.  We can do better than that.  This inproves
the heurstics by allowing pointers which don't analyize via scalar evolution.
This means loads which are from other loads can be factored out earlier than
the loop optimizers.

This changes 2 testcases which are now factored out in phiopt2 and one
testcase where we don't want the factoring out before the vectorizer as
we want to be able to vectorize the code (derived from eembc's
telecom/viterb00data_1 benchmark).

Bootstrapped and tested on x86_64-linux-gnu.

        PR tree-optimization/125945

gcc/ChangeLog:

        * tree-ssa-phiopt.cc (induction_based): New function.
        (factor_out_conditional_load): Allow some factoring out
        with early and/or before_vect.
        (factor_out_all): Set before_vect to false when not vectorizing.
        (pass_phiopt::execute): Initialize scev in some cases.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/scc-diamond-1.c:
        * gcc.dg/tree-ssa/scc-diamond-3.c:
        * gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c: New test.

Signed-off-by: Andrea Pinski <[email protected]>
---
 .../tree-ssa/factor_op_phi-load-vect-1.c      | 64 ++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c |  4 +-
 gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c |  4 +-
 gcc/tree-ssa-phiopt.cc                        | 66 ++++++++++++++++---
 4 files changed, 124 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c
new file mode 100644
index 00000000000..c26ea907f2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-vect-1.c
@@ -0,0 +1,64 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-aliasing -fdump-tree-phiopt-details" } */
+/* PR tree-optimization/125945 */
+/* These factoring out of loads should happen only after the vectorizer for 
this code. */
+typedef short s16;
+struct S { s16 tag; s16 key; };
+void f(s16 *dst, const struct S *a, const struct S *b, int n)
+{
+    for (int i = 0; i < n; i++) {
+        s16 ka = a[i].key;
+        s16 kb = b[i].key;
+        if (ka >= kb)
+            dst[i] = a[i].tag;
+        else
+            dst[i] = b[i].tag;
+    }
+}
+void f1(s16 *dst, const struct S *a, const struct S *b, int n)
+{
+    for (int i = 0; i < n; i++) {
+        s16 ka = a[i].key;
+        s16 kb = b[i].key;
+        s16 t;
+        if (ka >= kb)
+            t = a[i].tag;
+        else
+            t = b[i].tag;
+        dst[i] = t;
+    }
+}
+void f2(s16 *dst, const struct S *a, const struct S *b, int n)
+{
+    for (int i = 0; i < n; i++) {
+        s16 ka = a[i].key;
+        s16 kb = b[i].key;
+        s16 t;
+        const struct S *tt = &a[i];
+        const struct S *tt1 = &b[i];
+        if (ka >= kb)
+            t = tt->tag;
+        else
+            t = tt1->tag;
+        dst[i] = t;
+    }
+}
+void f3(s16 *dst, const struct S *a, const struct S *b, int n)
+{
+    for (int i = 0; i < n; i++) {
+        s16 ka = a[i].key;
+        s16 kb = b[i].key;
+        s16 t;
+        const s16 *tt = &a[i].tag;
+        const s16 *tt1 = &b[i].tag;
+        if (ka >= kb)
+            t = *tt;
+        else
+            t = *tt1;
+        dst[i] = t;
+    }
+}
+
+/* { dg-final { scan-tree-dump-not "changed to factor out load from" "phiopt3" 
} } */
+/* { dg-final { scan-tree-dump-not "changed to factor out load from" "phiopt2" 
} } */
+/* { dg-final { scan-tree-dump-times "changed to factor out load from" 4 
"phiopt4" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
index de4f003bcf3..f6206273d14 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-1.c
@@ -35,6 +35,6 @@ advance (const uint8_t *ip, size_t tag, const uint8_t *end)
 }
 
 /* The diamond is if-converted (branchless): one selected-offset load remains. 
 */
-/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
"phiopt4" } } */
-/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 1 
"phiopt4" } } */
+/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
"phiopt2" } } */
+/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 1 
"phiopt2" } } */
 /* { dg-final { scan-tree-dump-times "changed to factor operation out from" 2 
"phiopt1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
index 8f9f6a4dead..00c8dd278bc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scc-diamond-3.c
@@ -46,6 +46,6 @@ advance (const uint8_t *ip, size_t tag, const uint8_t *end)
 
 /* The mismatched alias types are merged to the alias-everything type, so the
    loads are commoned and the diamond is if-converted.  */
-/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
"phiopt4" } } */
-/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 1 
"phiopt4" } } */
+/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
"phiopt2" } } */
+/* { dg-final { scan-tree-dump-times "changed to factor operation out from" 1 
"phiopt2" } } */
 /* { dg-final { scan-tree-dump-times "changed to factor operation out from" 2 
"phiopt1" } } */
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index fbb4ec545e6..84a7949583d 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -4063,6 +4063,22 @@ cond_if_else_store_replacement (basic_block then_bb, 
basic_block else_bb,
   return ok;
 }
 
+/* Returns true when P is based on an induction variable
+   inside MERGE's inner most loop.  */
+static bool
+induction_based (tree p, basic_block merge)
+{
+  if (TREE_CODE (p) != SSA_NAME)
+    return false;
+  tree ev = analyze_scalar_evolution (merge->loop_father, p);
+  if (chrec_contains_undetermined (ev)
+      || chrec_contains_symbols_defined_in_loop (ev, merge->loop_father->num))
+    return false;
+  if (tree_does_not_contain_chrecs (ev))
+    return false;
+  return true;
+}
+
 /* If PHI at MERGE is a "load PHI", PHI <*P, *Q> whose two arguments are
    single-use, non-volatile scalar MEM_REF loads reading the same memory state
    (same VUSE), factor the load out: introduce P' = PHI <P, Q> and a single
@@ -4078,15 +4094,6 @@ static bool
 factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi,
                             bool early_p, bool before_vect)
 {
-  /* Factoring out a load during the first phi means we can't
-     trust if this is inside a loop or not; due to before inlining.  */
-  if (early_p)
-    return false;
-
-  /* Before vectorization, we don't want to factor out loads unless not inside 
a loop.  */
-  if (before_vect && bb_loop_depth (merge) != 0)
-    return false;
-
   /* Not a virtual operand. */
   if (virtual_operand_p (gimple_phi_result (phi))
       /* can only handle the merge bb having 2 predecessors.  */
@@ -4204,6 +4211,23 @@ factor_out_conditional_load (edge e0, edge e1, 
basic_block merge, gphi *phi,
   gimple_stmt_iterator gsi;
   gsi = gsi_after_labels (merge);
 
+  // factoring of the same pointer should be allowed
+  // irrespect to loops.
+  if (p0 == p1 && operand_equal_p (index0, index1))
+    ;
+  // Before inlining, we can't tell if different
+  // pointers are going to be induction variable based
+  // or not.
+  else if (early_p)
+    return false;
+  // Before vectorization, don't factor out
+  // pointers which are based on induction variables.
+  else if (before_vect
+          && bb_loop_depth (merge) != 0
+          && (induction_based (p0, merge)
+              || induction_based (p1, merge)))
+    return false;
+
   /* Try to handle different indices.  */
   if (operand_equal_p (index0, index1))
     newindex = fold_convert (atype, index0);
@@ -4354,6 +4378,11 @@ factor_out_all (edge e1, edge e2, basic_block merge,
 {
   bool changed = false;
   bool do_over;
+  bool before_vect = !fold_before_rtl_expansion_p ();
+  // If vectorization is disable, then we are never before the vectorizer.
+  if (!flag_tree_loop_vectorize
+      && !merge->loop_father->force_vectorize)
+    before_vect = false;
   basic_block bb1 = e1->src;
   basic_block bb2 = e2->src;
   do
@@ -4385,7 +4414,7 @@ factor_out_all (edge e1, edge e2, basic_block merge,
          /* Conditional load elimination can only be on a diamond.  */
          if ((diamond_p
               && factor_out_conditional_load (e1, e2, merge, phi, early_p,
-                                              !fold_before_rtl_expansion_p ()))
+                                              before_vect))
              || factor_out_conditional_operation (e1, e2, merge, phi,
                                                   cond_stmt, early_p))
            {
@@ -4973,6 +5002,18 @@ pass_phiopt::execute (function *)
 {
   bool do_hoist_loads = !early_p ? gate_hoist_loads () : false;
   bool cfgchanged = false;
+  bool need_loop_finalize = false;
+
+  if (!early_p
+      && !fold_before_rtl_expansion_p ()
+      && (flag_tree_loop_vectorize
+         || cfun->has_force_vectorize_loops)
+      && number_of_loops (cfun) > 1)
+  {
+    loop_optimizer_init (LOOPS_NORMAL);
+    scev_initialize ();
+    need_loop_finalize = true;
+  }
 
   calculate_dominance_info (CDI_DOMINATORS);
   mark_ssa_maybe_undefs ();
@@ -5063,6 +5104,11 @@ pass_phiopt::execute (function *)
 
   execute_over_cond_phis (phiopt_exec);
 
+  if (need_loop_finalize)
+    {
+      loop_optimizer_finalize ();
+      scev_finalize ();
+    }
   if (replicate_conds_over_phis ())
     {
       free_dominance_info (CDI_DOMINATORS);
-- 
2.43.0

Reply via email to