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