diff options
author | Jakub Jelinek <jakub@redhat.com> | 2011-11-11 20:55:23 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2011-11-11 20:55:23 +0100 |
commit | 22d8712ac4f4f04786d4a2428cde756b065b9f97 (patch) | |
tree | da6d861de02810601827aa20e1dd872a3b954e96 /gcc | |
parent | 0540978881f0e0de7d84c470628a1897b01b6831 (diff) | |
download | gcc-22d8712ac4f4f04786d4a2428cde756b065b9f97.zip gcc-22d8712ac4f4f04786d4a2428cde756b065b9f97.tar.gz gcc-22d8712ac4f4f04786d4a2428cde756b065b9f97.tar.bz2 |
re PR tree-optimization/51074 (No constant folding performed for VEC_PERM_EXPR, VEC_INTERLEAVE*EXPR, VEC_EXTRACT*EXPR)
PR tree-optimization/51074
* fold-const.c (vec_cst_ctor_to_array, fold_vec_perm): New functions.
(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.
* tree-ssa-propagate.c (valid_gimple_rhs_p): Handle ternary
expressions.
* tree-vect-generic.c (lower_vec_perm): Mask sel_int elements
to 0 .. 2 * elements - 1.
From-SVN: r181297
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/fold-const.c | 164 | ||||
-rw-r--r-- | gcc/tree-ssa-propagate.c | 10 | ||||
-rw-r--r-- | gcc/tree-vect-generic.c | 2 |
4 files changed, 189 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ef1453e..66e6f67 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2011-11-11 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/51074 + * fold-const.c (vec_cst_ctor_to_array, fold_vec_perm): New functions. + (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. + * tree-ssa-propagate.c (valid_gimple_rhs_p): Handle ternary + expressions. + * tree-vect-generic.c (lower_vec_perm): Mask sel_int elements + to 0 .. 2 * elements - 1. + 2011-11-11 Richard Henderson <rth@redhat.com> * gimple-pretty-print.c (dump_gimple_omp_atomic_load): Dump needed. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index e4c2589..167573b 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -9528,6 +9528,86 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue, return 1; } +/* Helper function for fold_vec_perm. Store elements of VECTOR_CST or + CONSTRUCTOR ARG into array ELTS and return true if successful. */ + +static bool +vec_cst_ctor_to_array (tree arg, tree *elts) +{ + unsigned int nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)), i; + + if (TREE_CODE (arg) == VECTOR_CST) + { + tree t; + + for (i = 0, t = TREE_VECTOR_CST_ELTS (arg); + i < nelts && t; i++, t = TREE_CHAIN (t)) + elts[i] = TREE_VALUE (t); + if (t) + return false; + } + else if (TREE_CODE (arg) == CONSTRUCTOR) + { + constructor_elt *elt; + + FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg), i, elt) + if (i >= nelts) + return false; + else + elts[i] = elt->value; + } + else + return false; + for (; i < nelts; i++) + elts[i] + = fold_convert (TREE_TYPE (TREE_TYPE (arg)), integer_zero_node); + return true; +} + +/* Attempt to fold vector permutation of ARG0 and ARG1 vectors using SEL + selector. Return the folded VECTOR_CST or CONSTRUCTOR if successful, + NULL_TREE otherwise. */ + +static tree +fold_vec_perm (tree type, tree arg0, tree arg1, const unsigned char *sel) +{ + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + tree *elts; + bool need_ctor = false; + + gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts + && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts); + if (TREE_TYPE (TREE_TYPE (arg0)) != TREE_TYPE (type) + || TREE_TYPE (TREE_TYPE (arg1)) != TREE_TYPE (type)) + return NULL_TREE; + + elts = XALLOCAVEC (tree, nelts * 3); + if (!vec_cst_ctor_to_array (arg0, elts) + || !vec_cst_ctor_to_array (arg1, elts + nelts)) + return NULL_TREE; + + for (i = 0; i < nelts; i++) + { + if (!CONSTANT_CLASS_P (elts[sel[i]])) + need_ctor = true; + elts[i + 2 * nelts] = unshare_expr (elts[sel[i]]); + } + + if (need_ctor) + { + VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, nelts); + for (i = 0; i < nelts; i++) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elts[2 * nelts + i]); + return build_constructor (type, v); + } + else + { + tree vals = NULL_TREE; + for (i = 0; i < nelts; i++) + vals = tree_cons (NULL_TREE, elts[3 * nelts - i - 1], vals); + return build_vector (type, vals); + } +} /* Fold a binary expression of code CODE and type TYPE with operands OP0 and OP1. LOC is the location of the resulting expression. @@ -13381,6 +13461,41 @@ 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)) + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + unsigned char *sel = XALLOCAVEC (unsigned char, nelts); + + for (i = 0; i < nelts; i++) + switch (code) + { + case VEC_EXTRACT_EVEN_EXPR: + sel[i] = i * 2; + break; + case VEC_EXTRACT_ODD_EXPR: + sel[i] = i * 2 + 1; + break; + case VEC_INTERLEAVE_HIGH_EXPR: + sel[i] = (i + nelts) / 2 + ((i & 1) ? nelts : 0); + break; + case VEC_INTERLEAVE_LOW_EXPR: + sel[i] = i / 2 + ((i & 1) ? nelts : 0); + break; + default: + gcc_unreachable (); + } + + return fold_vec_perm (type, arg0, arg1, sel); + } + return NULL_TREE; + default: return NULL_TREE; } /* switch (code) */ @@ -13767,6 +13882,55 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, return fold_fma (loc, type, arg0, arg1, arg2); + case VEC_PERM_EXPR: + if (TREE_CODE (arg2) == VECTOR_CST) + { + unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i; + unsigned char *sel = XALLOCAVEC (unsigned char, nelts); + tree t; + bool need_mask_canon = false; + + gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2))); + for (i = 0, t = TREE_VECTOR_CST_ELTS (arg2); + i < nelts && t; i++, t = TREE_CHAIN (t)) + { + if (TREE_CODE (TREE_VALUE (t)) != INTEGER_CST) + return NULL_TREE; + + sel[i] = TREE_INT_CST_LOW (TREE_VALUE (t)) & (2 * nelts - 1); + if (TREE_INT_CST_HIGH (TREE_VALUE (t)) + || ((unsigned HOST_WIDE_INT) + TREE_INT_CST_LOW (TREE_VALUE (t)) != sel[i])) + need_mask_canon = true; + } + if (t) + return NULL_TREE; + for (; i < nelts; i++) + sel[i] = 0; + + if ((TREE_CODE (arg0) == VECTOR_CST + || TREE_CODE (arg0) == CONSTRUCTOR) + && (TREE_CODE (arg1) == VECTOR_CST + || TREE_CODE (arg1) == CONSTRUCTOR)) + { + t = fold_vec_perm (type, arg0, arg1, sel); + if (t != NULL_TREE) + return t; + } + + if (need_mask_canon && arg2 == op2) + { + tree list = NULL_TREE, eltype = TREE_TYPE (TREE_TYPE (arg2)); + for (i = 0; i < nelts; i++) + list = tree_cons (NULL_TREE, + build_int_cst (eltype, sel[nelts - i - 1]), + list); + t = build_vector (TREE_TYPE (arg2), list); + return build3_loc (loc, VEC_PERM_EXPR, type, op0, op1, t); + } + } + return NULL_TREE; + default: return NULL_TREE; } /* switch (code) */ diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 05abaa5..80b33e1 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -602,6 +602,16 @@ valid_gimple_rhs_p (tree expr) break; default: + if (get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS) + { + if (((code == VEC_COND_EXPR || code == COND_EXPR) + ? !is_gimple_condexpr (TREE_OPERAND (expr, 0)) + : !is_gimple_val (TREE_OPERAND (expr, 0))) + || !is_gimple_val (TREE_OPERAND (expr, 1)) + || !is_gimple_val (TREE_OPERAND (expr, 2))) + return false; + break; + } return false; } break; diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 6555932..dc01ce7 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -649,7 +649,7 @@ lower_vec_perm (gimple_stmt_iterator *gsi) tree vals = TREE_VECTOR_CST_ELTS (mask); for (i = 0; i < elements; ++i, vals = TREE_CHAIN (vals)) - sel_int[i] = TREE_INT_CST_LOW (TREE_VALUE (vals)); + sel_int[i] = TREE_INT_CST_LOW (TREE_VALUE (vals)) & (2 * elements - 1); if (can_vec_perm_p (TYPE_MODE (vect_type), false, sel_int)) return; |