Hi,
I was asked by upstream to split the loop distribution patch into small ones.
It is hard because data structure and algorithm are closely coupled together.
Anyway, this is the patch series with smaller patches.  Basically I tried to
separate data structure and bug-fix changes apart with one as the main patch.
Note I only made necessary code refactoring in order to separate patch, apart
from that, there is no change against the last version.

This is the first patch introducing new internal function IFN_LOOP_DIST_ALIAS.
GCC will distribute loops under condition of this function call.

Bootstrap and test on x86_64 and AArch64.  Is it OK?

Thanks,
bin
2017-06-07  Bin Cheng  <bin.ch...@arm.com>

        * cfgloop.h (struct loop): New field ldist_alias_id.
        * cfgloopmanip.c (lv_adjust_loop_entry_edge): Comment change.
        * internal-fn.c (expand_LOOP_DIST_ALIAS): New function.
        * internal-fn.def (LOOP_DIST_ALIAS): New.
        * tree-vectorizer.c (vect_loop_dist_alias_call): New function.
        (fold_loop_dist_alias_call): New function.
        (vectorize_loops): Fold IFN_LOOP_DIST_ALIAS call depending on
        successful vectorization or not.
From 3598491598e0b425f1cfa4b7bb4c180886a08bef Mon Sep 17 00:00:00 2001
From: Bin Cheng <binch...@e108451-lin.cambridge.arm.com>
Date: Wed, 7 Jun 2017 13:04:03 +0100
Subject: [PATCH 01/14] ifn_loop_dist_alias-20170607.txt

---
 gcc/cfgloop.h         |  9 +++++++
 gcc/cfgloopmanip.c    |  3 ++-
 gcc/internal-fn.c     |  8 ++++++
 gcc/internal-fn.def   |  1 +
 gcc/tree-vectorizer.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index a8bec1d..be4187a 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -225,6 +225,15 @@ struct GTY ((chain_next ("%h.next"))) loop {
      builtins.  */
   tree simduid;
 
+  /* For loops generated by distribution with runtime alias checks, this
+     is a unique identifier of the original distributed loop.  Generally
+     it is the number of the original loop.  IFN_LOOP_DIST_ALIAS builtin
+     uses this id as its first argument.  Give a loop with an id, we can
+     look upward in dominance tree for the corresponding IFN_LOOP_DIST_ALIAS
+     buildin.  Note this id has no meanling after IFN_LOOP_DIST_ALIAS is
+     folded and eliminated.  */
+  int ldist_alias_id;
+
   /* Upper bound on number of iterations of a loop.  */
   struct nb_iter_bound *bounds;
 
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index d764ab9..adb2f65 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -1653,7 +1653,8 @@ force_single_succ_latches (void)
 
   THEN_PROB is the probability of then branch of the condition.
   ELSE_PROB is the probability of else branch. Note that they may be both
-  REG_BR_PROB_BASE when condition is IFN_LOOP_VECTORIZED.  */
+  REG_BR_PROB_BASE when condition is IFN_LOOP_VECTORIZED or
+  IFN_LOOP_DIST_ALIAS.  */
 
 static basic_block
 lv_adjust_loop_entry_edge (basic_block first_head, basic_block second_head,
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 75fe027..96e40cb 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2250,6 +2250,14 @@ expand_LOOP_VECTORIZED (internal_fn, gcall *)
   gcc_unreachable ();
 }
 
+/* This should get folded in tree-vectorizer.c.  */
+
+static void
+expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
 /* Expand MASK_LOAD call STMT using optab OPTAB.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index e162d81..79c19fb 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -158,6 +158,7 @@ DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF 
| ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_START, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_END, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (LOOP_VECTORIZED, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (LOOP_DIST_ALIAS, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ANNOTATE,  ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_BOUNDS, ECF_LEAF | ECF_NOTHROW, NULL)
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 1bef2e4..0d83d33 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -469,6 +469,63 @@ fold_loop_vectorized_call (gimple *g, tree value)
     }
 }
 
+/* If LOOP has been versioned during loop distribution, return the internal
+   call guarding it.  */
+
+static gimple *
+vect_loop_dist_alias_call (struct loop *loop)
+{
+  gimple_stmt_iterator gsi;
+  gimple *g;
+  basic_block bb = loop_preheader_edge (loop)->src;
+  struct loop *outer_loop = bb->loop_father;
+
+  /* Look upward in dominance tree.  */
+  for (; bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) && bb->loop_father == outer_loop;
+       bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+    {
+      g = last_stmt (bb);
+      if (g == NULL || gimple_code (g) != GIMPLE_COND)
+       continue;
+
+      gsi = gsi_for_stmt (g);
+      gsi_prev (&gsi);
+      if (gsi_end_p (gsi))
+       continue;
+
+      g = gsi_stmt (gsi);
+      /* The guarding internal function call must have the same distribution
+        alias id.  */
+      if (gimple_call_internal_p (g, IFN_LOOP_DIST_ALIAS)
+         && (tree_to_shwi (gimple_call_arg (g, 0)) == loop->ldist_alias_id))
+       return g;
+    }
+  return NULL;
+}
+
+/* Fold LOOP_DIST_ALIAS internal call stmt according to KEEP_P and update
+   any immediate uses of it's LHS.  Stmt is folded to its second argument
+   if KEEP_P is true, otherwise to boolean_false_node.  */
+
+static void
+fold_loop_dist_alias_call (gimple *g, bool keep_p)
+{
+  tree lhs = gimple_call_lhs (g);
+  use_operand_p use_p;
+  imm_use_iterator iter;
+  gimple *use_stmt;
+  gimple_stmt_iterator gsi = gsi_for_stmt (g);
+  tree folded_value = keep_p ? gimple_call_arg (g, 1) : boolean_false_node;
+
+  update_call_from_tree (&gsi, folded_value);
+  FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+    {
+      FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+       SET_USE (use_p, folded_value);
+      update_stmt (use_stmt);
+    }
+}
+
 /* Set the uids of all the statements in basic blocks inside loop
    represented by LOOP_VINFO. LOOP_VECTORIZED_CALL is the internal
    call guarding the loop which has been if converted.  */
@@ -595,7 +652,7 @@ vectorize_loops (void)
     else
       {
        loop_vec_info loop_vinfo, orig_loop_vinfo;
-       gimple *loop_vectorized_call;
+       gimple *loop_vectorized_call, *loop_dist_alias_call;
        try_vectorize:
        if (!((flag_tree_loop_vectorize
               && optimize_loop_nest_for_speed_p (loop))
@@ -603,6 +660,7 @@ vectorize_loops (void)
          continue;
        orig_loop_vinfo = NULL;
        loop_vectorized_call = vect_loop_vectorized_call (loop);
+       loop_dist_alias_call = vect_loop_dist_alias_call (loop);
        vectorize_epilogue:
        vect_location = find_loop_location (loop);
         if (LOCATION_LOCUS (vect_location) != UNKNOWN_LOCATION
@@ -710,6 +768,12 @@ vectorize_loops (void)
            loop_vectorized_call = NULL;
            ret |= TODO_cleanup_cfg;
          }
+       if (loop_dist_alias_call)
+         {
+           fold_loop_dist_alias_call (loop_dist_alias_call, true);
+           loop_dist_alias_call = NULL;
+           ret |= TODO_cleanup_cfg;
+         }
 
        if (new_loop)
          {
@@ -743,6 +807,15 @@ vectorize_loops (void)
              {
                fold_loop_vectorized_call (g, boolean_false_node);
                ret |= TODO_cleanup_cfg;
+               g = NULL;
+             }
+           else
+             g = vect_loop_dist_alias_call (loop);
+
+           if (g)
+             {
+               fold_loop_dist_alias_call (g, false);
+               ret |= TODO_cleanup_cfg;
              }
          }
       }
-- 
1.9.1

Reply via email to