fold-const.c (fold_ternary_loc): Detect identity permutations.
authorMarc Glisse <marc.glisse@inria.fr>
Tue, 21 Aug 2012 13:27:00 +0000 (15:27 +0200)
committerMarc Glisse <glisse@gcc.gnu.org>
Tue, 21 Aug 2012 13:27:00 +0000 (13:27 +0000)
2012-08-21  Marc Glisse  <marc.glisse@inria.fr>

gcc/
* fold-const.c (fold_ternary_loc): Detect identity permutations.
Canonicalize permutations more.
* tree-ssa-forwprop.c (is_combined_permutation_identity): New function.
(simplify_permutation): Likewise.
(ssa_forward_propagate_and_combine): Call it.

gcc/testsuite/
* gcc.dg/tree-ssa/forwprop-19.c: New testcase.
* gcc.dg/fold-perm.c: Likewise.

From-SVN: r190561

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/fold-perm.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c [new file with mode: 0644]
gcc/tree-ssa-forwprop.c

index 5aa1ec81734f68014c8a0af728a4bd0aca500bc9..a271fe5258fe85805ee7b7821c55122bcb0d4630 100644 (file)
@@ -1,3 +1,11 @@
+2012-08-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * fold-const.c (fold_ternary_loc): Detect identity permutations.
+       Canonicalize permutations more.
+       * tree-ssa-forwprop.c (is_combined_permutation_identity): New function.
+       (simplify_permutation): Likewise.
+       (ssa_forward_propagate_and_combine): Call it.
+
 2012-08-21  Richard Guenther  <rguenther@suse.de>
 
        * tree-ssa-loop-im.c (tree_ssa_lim_finalize): Properly free
index 3bfd203bea8794a65747f852d62bc5404c8c7f36..b386bb2c6060275e6fc4b21dd0a469d4c62eb1e6 100644 (file)
@@ -14155,11 +14155,17 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
     case VEC_PERM_EXPR:
       if (TREE_CODE (arg2) == VECTOR_CST)
        {
-         unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+         unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i, mask;
          unsigned char *sel = XALLOCAVEC (unsigned char, nelts);
          tree t;
          bool need_mask_canon = false;
+         bool all_in_vec0 = true;
+         bool all_in_vec1 = true;
+         bool maybe_identity = true;
+         bool single_arg = (op0 == op1);
+         bool changed = false;
 
+         mask = single_arg ? (nelts - 1) : (2 * nelts - 1);
          gcc_assert (nelts == VECTOR_CST_NELTS (arg2));
          for (i = 0; i < nelts; i++)
            {
@@ -14167,11 +14173,27 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
              if (TREE_CODE (val) != INTEGER_CST)
                return NULL_TREE;
 
-             sel[i] = TREE_INT_CST_LOW (val) & (2 * nelts - 1);
+             sel[i] = TREE_INT_CST_LOW (val) & mask;
              if (TREE_INT_CST_HIGH (val)
                  || ((unsigned HOST_WIDE_INT)
                      TREE_INT_CST_LOW (val) != sel[i]))
                need_mask_canon = true;
+
+             if (sel[i] < nelts)
+               all_in_vec1 = false;
+             else
+               all_in_vec0 = false;
+
+             if ((sel[i] & (nelts-1)) != i)
+               maybe_identity = false;
+           }
+
+         if (maybe_identity)
+           {
+             if (all_in_vec0)
+               return op0;
+             if (all_in_vec1)
+               return op1;
            }
 
          if ((TREE_CODE (arg0) == VECTOR_CST
@@ -14184,15 +14206,31 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
                return t;
            }
 
+         if (all_in_vec0)
+           op1 = op0;
+         else if (all_in_vec1)
+           {
+             op0 = op1;
+             for (i = 0; i < nelts; i++)
+               sel[i] -= nelts;
+             need_mask_canon = true;
+           }
+
+         if (op0 == op1 && !single_arg)
+           changed = true;
+
          if (need_mask_canon && arg2 == op2)
            {
              tree *tsel = XALLOCAVEC (tree, nelts);
              tree eltype = TREE_TYPE (TREE_TYPE (arg2));
              for (i = 0; i < nelts; i++)
                tsel[i] = build_int_cst (eltype, sel[i]);
-             t = build_vector (TREE_TYPE (arg2), tsel);
-             return build3_loc (loc, VEC_PERM_EXPR, type, op0, op1, t);
+             op2 = build_vector (TREE_TYPE (arg2), tsel);
+             changed = true;
            }
+
+         if (changed)
+           return build3_loc (loc, VEC_PERM_EXPR, type, op0, op1, op2);
        }
       return NULL_TREE;
 
index f6151fcca7b162fd91d6f80f3b635203861c7cac..9bdd4f8c78784cb0678a7519378a127f3c6f6e31 100644 (file)
@@ -1,3 +1,8 @@
+2012-08-21  Marc Glisse  <marc.glisse@inria.fr>
+
+       * gcc.dg/tree-ssa/forwprop-19.c: New testcase.
+       * gcc.dg/fold-perm.c: Likewise.
+
 2012-08-20  Jan Hubicka  <jh@suse.cz>
 
        PR fortran/48636
diff --git a/gcc/testsuite/gcc.dg/fold-perm.c b/gcc/testsuite/gcc.dg/fold-perm.c
new file mode 100644 (file)
index 0000000..7396c1d
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-ccp1" } */
+
+typedef int veci __attribute__ ((vector_size (4 * sizeof (int))));
+
+void fun (veci *f, veci *g, veci *h)
+{
+  veci m = { 7, 7, 4, 6 };
+  veci n = { 0, 1, 2, 3 };
+  veci p = { 1, 1, 7, 6 };
+  *h = __builtin_shuffle (*h, *h, p);
+  *g = __builtin_shuffle (*f, *g, m);
+  *f = __builtin_shuffle (*f, *g, n);
+}
+
+/* { dg-final { scan-tree-dump "VEC_PERM_EXPR.*{ 3, 3, 0, 2 }" "ccp1" } } */
+/* { dg-final { scan-tree-dump "VEC_PERM_EXPR.*{ 1, 1, 3, 2 }" "ccp1" } } */
+/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 2 "ccp1" } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c
new file mode 100644 (file)
index 0000000..6d25c1b
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-forwprop2" } */
+
+typedef int vec __attribute__((vector_size (4 * sizeof (int))));
+void f (vec *x1, vec *x2)
+{
+  vec m = { 1, 2, 3, 0 };
+  vec n = { 3, 0, 1, 2 };
+  vec y = __builtin_shuffle (*x1, *x2, n);
+  vec z = __builtin_shuffle (y, m);
+  *x1 = z;
+}
+
+/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "forwprop2" } } */
+/* { dg-final { cleanup-tree-dump "forwprop2" } } */
index bd9b72b9ea5fb4ec151ea7db84c35f6cbe731b0c..532b9c5c688c9ba144ce7127b4eacdcd2bf66c47 100644 (file)
@@ -2577,6 +2577,95 @@ combine_conversions (gimple_stmt_iterator *gsi)
   return 0;
 }
 
+/* Determine whether applying the 2 permutations (mask1 then mask2)
+   gives back one of the input.  */
+
+static int
+is_combined_permutation_identity (tree mask1, tree mask2)
+{
+  tree mask;
+  unsigned int nelts, i, j;
+  bool maybe_identity1 = true;
+  bool maybe_identity2 = true;
+
+  gcc_checking_assert (TREE_CODE (mask1) == VECTOR_CST
+                      && TREE_CODE (mask2) == VECTOR_CST);
+  mask = fold_ternary (VEC_PERM_EXPR, TREE_TYPE (mask1), mask1, mask1, mask2);
+  gcc_assert (TREE_CODE (mask) == VECTOR_CST);
+
+  nelts = VECTOR_CST_NELTS (mask);
+  for (i = 0; i < nelts; i++)
+    {
+      tree val = VECTOR_CST_ELT (mask, i);
+      gcc_assert (TREE_CODE (val) == INTEGER_CST);
+      j = TREE_INT_CST_LOW (val) & (2 * nelts - 1);
+      if (j == i)
+       maybe_identity2 = false;
+      else if (j == i + nelts)
+       maybe_identity1 = false;
+      else
+       return 0;
+    }
+  return maybe_identity1 ? 1 : maybe_identity2 ? 2 : 0;
+}
+
+/* Combine two shuffles in a row.  Returns 1 if there were any changes
+   made, 2 if cfg-cleanup needs to run.  Else it returns 0.  */
+static int
+simplify_permutation (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt;
+  tree op0, op1, op2, op3;
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  enum tree_code code2;
+
+  gcc_checking_assert (code == VEC_PERM_EXPR);
+
+  op0 = gimple_assign_rhs1 (stmt);
+  op1 = gimple_assign_rhs2 (stmt);
+  op2 = gimple_assign_rhs3 (stmt);
+
+  if (TREE_CODE (op0) != SSA_NAME)
+    return 0;
+
+  if (TREE_CODE (op2) != VECTOR_CST)
+    return 0;
+
+  if (op0 != op1)
+    return 0;
+
+  def_stmt = SSA_NAME_DEF_STMT (op0);
+  if (!def_stmt || !is_gimple_assign (def_stmt)
+      || !can_propagate_from (def_stmt))
+    return 0;
+
+  code2 = gimple_assign_rhs_code (def_stmt);
+
+  /* Two consecutive shuffles.  */
+  if (code2 == VEC_PERM_EXPR)
+    {
+      tree orig;
+      int ident;
+      op3 = gimple_assign_rhs3 (def_stmt);
+      if (TREE_CODE (op3) != VECTOR_CST)
+       return 0;
+      ident = is_combined_permutation_identity (op3, op2);
+      if (!ident)
+       return 0;
+      orig = (ident == 1) ? gimple_assign_rhs1 (def_stmt)
+                         : gimple_assign_rhs2 (def_stmt);
+      gimple_assign_set_rhs1 (stmt, unshare_expr (orig));
+      gimple_assign_set_rhs_code (stmt, TREE_CODE (orig));
+      gimple_set_num_ops (stmt, 2);
+      update_stmt (stmt);
+      return remove_prop_source_from_use (op0) ? 2 : 1;
+    }
+
+  return false;
+}
+
 /* Main entry point for the forward propagation and statement combine
    optimizer.  */
 
@@ -2739,6 +2828,13 @@ ssa_forward_propagate_and_combine (void)
                      cfg_changed = true;
                    changed = did_something != 0;
                  }
+               else if (code == VEC_PERM_EXPR)
+                 {
+                   int did_something = simplify_permutation (&gsi);
+                   if (did_something == 2)
+                     cfg_changed = true;
+                   changed = did_something != 0;
+                 }
                break;
              }