Hi!

This patch adds folding of the new VEC_PERM_EXPR as well as the older
more specialized permutation exprs.  For VEC_PERM_EXPR e.g.
__builtin_shuffle may be used with constant arguments, for the other
one the vectorizer sometimes creates it (though, admittedly, it should
try harder to figure it out).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2011-11-10  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/51074
        * fold-const.c (fold_binary_loc): Handle VEC_EXTRACT_EVEN_EXPR,
        VEC_EXTRACT_ODD_EXPR, VEC_INTERLEAVE_HIGH_EXPR and
        VEC_INTERLEAVE_LOW_EXPR with VECTOR_CST or CONSTRUCTOR operands.
        (fold_ternary_loc): Handle VEC_PERM_EXPR with VECTOR_CST or
        CONSTRUCTOR operands.

--- gcc/fold-const.c.jj 2011-10-24 12:21:14.000000000 +0200
+++ gcc/fold-const.c    2011-11-10 14:21:56.671487697 +0100
@@ -13381,6 +13381,102 @@ fold_binary_loc (location_t loc,
       /* An ASSERT_EXPR should never be passed to fold_binary.  */
       gcc_unreachable ();
 
+    case VEC_EXTRACT_EVEN_EXPR:
+    case VEC_EXTRACT_ODD_EXPR:
+    case VEC_INTERLEAVE_HIGH_EXPR:
+    case VEC_INTERLEAVE_LOW_EXPR:
+      if ((TREE_CODE (arg0) == VECTOR_CST
+          || TREE_CODE (arg0) == CONSTRUCTOR)
+         && (TREE_CODE (arg1) == VECTOR_CST
+             || TREE_CODE (arg1) == CONSTRUCTOR)
+         && TREE_TYPE (TREE_TYPE (arg0)) == TREE_TYPE (type)
+         && TREE_TYPE (TREE_TYPE (arg1)) == TREE_TYPE (type))
+       {
+         unsigned int nelements = TYPE_VECTOR_SUBPARTS (type), i;
+         tree *elements = XALLOCAVEC (tree, nelements * 3), t;
+         constructor_elt *elt;
+         bool need_ctor = false;
+
+         if (TREE_CODE (arg0) == VECTOR_CST)
+           {
+             for (i = 0, t = TREE_VECTOR_CST_ELTS (arg0);
+                  i < nelements && t; i++, t = TREE_CHAIN (t))
+               elements[i] = TREE_VALUE (t);
+             if (t)
+               return NULL_TREE;
+           }
+         else
+           FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg0), i, elt)
+             if (i >= nelements)
+               return NULL_TREE;
+             else
+               elements[i] = elt->value;
+         if (i < nelements)
+           return NULL_TREE;
+
+         if (TREE_CODE (arg0) == VECTOR_CST)
+           {
+             for (i = 0, t = TREE_VECTOR_CST_ELTS (arg1);
+                  i < nelements && t; i++, t = TREE_CHAIN (t))
+               elements[i + nelements] = TREE_VALUE (t);
+             if (t)
+               return NULL_TREE;
+           }
+         else
+           FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg1), i, elt)
+             if (i >= nelements)
+               return NULL_TREE;
+             else
+               elements[i + nelements] = elt->value;
+         if (i < nelements)
+           return NULL_TREE;
+
+         for (i = 0; i < nelements; i++)
+           {
+             unsigned int idx;
+             switch (code)
+               {
+               case VEC_EXTRACT_EVEN_EXPR:
+                 idx = i * 2;
+                 break;
+               case VEC_EXTRACT_ODD_EXPR:
+                 idx = i * 2 + 1;
+                 break;
+               case VEC_INTERLEAVE_HIGH_EXPR:
+                 idx = (i + nelements) / 2 + ((i & 1) ? nelements : 0);
+                 break;
+               case VEC_INTERLEAVE_LOW_EXPR:
+                 idx = i / 2 + ((i & 1) ? nelements : 0);
+                 break;
+               default:
+                 gcc_unreachable ();
+               }
+
+             if (!CONSTANT_CLASS_P (elements[idx]))
+               need_ctor = true;
+             elements[i + 2 * nelements] = elements[idx];
+           }
+
+         if (need_ctor)
+           {
+             VEC(constructor_elt,gc) *v
+               = VEC_alloc (constructor_elt, gc, nelements);
+             for (i = 0; i < nelements; i++)
+               CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
+                                       elements[2 * nelements + i]);
+             return build_constructor (type, v);
+           }
+         else
+           {
+             tree vals = NULL_TREE;
+             for (i = 0; i < nelements; i++)
+               vals = tree_cons (NULL_TREE,
+                                 elements[3 * nelements - i - 1], vals);
+             return build_vector (type, vals);
+           }
+       }
+      return NULL_TREE;
+
     default:
       return NULL_TREE;
     } /* switch (code) */
@@ -13767,6 +13863,90 @@ fold_ternary_loc (location_t loc, enum t
 
       return fold_fma (loc, type, arg0, arg1, arg2);
 
+    case VEC_PERM_EXPR:
+      if ((TREE_CODE (arg0) == VECTOR_CST
+          || TREE_CODE (arg0) == CONSTRUCTOR)
+         && (TREE_CODE (arg1) == VECTOR_CST
+             || TREE_CODE (arg1) == CONSTRUCTOR)
+         && TREE_CODE (arg2) == VECTOR_CST
+         && TREE_TYPE (TREE_TYPE (arg0)) == TREE_TYPE (type)
+         && TREE_TYPE (TREE_TYPE (arg1)) == TREE_TYPE (type))
+       {
+         unsigned int nelements = TYPE_VECTOR_SUBPARTS (type), i;
+         tree *elements = XALLOCAVEC (tree, nelements * 3), t;
+         constructor_elt *elt;
+         bool need_ctor = false;
+
+         if (TREE_CODE (arg0) == VECTOR_CST)
+           {
+             for (i = 0, t = TREE_VECTOR_CST_ELTS (arg0);
+                  i < nelements && t; i++, t = TREE_CHAIN (t))
+               elements[i] = TREE_VALUE (t);
+             if (t)
+               return NULL_TREE;
+           }
+         else
+           FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg0), i, elt)
+             if (i >= nelements)
+               return NULL_TREE;
+             else
+               elements[i] = elt->value;
+         if (i < nelements)
+           return NULL_TREE;
+
+         if (TREE_CODE (arg0) == VECTOR_CST)
+           {
+             for (i = 0, t = TREE_VECTOR_CST_ELTS (arg1);
+                  i < nelements && t; i++, t = TREE_CHAIN (t))
+               elements[i + nelements] = TREE_VALUE (t);
+             if (t)
+               return NULL_TREE;
+           }
+         else
+           FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg1), i, elt)
+             if (i >= nelements)
+               return NULL_TREE;
+             else
+               elements[i + nelements] = elt->value;
+         if (i < nelements)
+           return NULL_TREE;
+
+         for (i = 0, t = TREE_VECTOR_CST_ELTS (arg2);
+              i < nelements && t; i++, t = TREE_CHAIN (t))
+           {
+             unsigned HOST_WIDE_INT idx;
+             if (!host_integerp (TREE_VALUE (t), 1))
+               return NULL_TREE;
+             idx = tree_low_cst (TREE_VALUE (t), 1);
+             if (idx >= nelements * 2)
+               return NULL_TREE;
+             if (!CONSTANT_CLASS_P (elements[idx]))
+               need_ctor = true;
+             elements[i + 2 * nelements] = unshare_expr (elements[idx]);
+           }
+         if (i < nelements || t)
+           return NULL_TREE;
+
+         if (need_ctor)
+           {
+             VEC(constructor_elt,gc) *v
+               = VEC_alloc (constructor_elt, gc, nelements);
+             for (i = 0; i < nelements; i++)
+               CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
+                                       elements[2 * nelements + i]);
+             return build_constructor (type, v);
+           }
+         else
+           {
+             tree vals = NULL_TREE;
+             for (i = 0; i < nelements; i++)
+               vals = tree_cons (NULL_TREE,
+                                 elements[3 * nelements - i - 1], vals);
+             return build_vector (type, vals);
+           }
+       }
+      return NULL_TREE;
+
     default:
       return NULL_TREE;
     } /* switch (code) */

        Jakub

Reply via email to