Targets like mips -mpaired-single which have support for V2SF vectors, but no support for V2SI vectors, will expand the V2SI constant parameter to VEC_PERM_EXPR in DImode. Which is absolutely not what we expect in expand_vec_perm, and is somewhat less than useful.
Tested on x86_64-linux (where it doesn't fire, of course), and lightly tested on mips64-elf. r~
commit d9198d8536af4470fffc9d1e70626d106d8a8ac7 Author: rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Sat Dec 10 20:43:03 2011 +0000 Force the creation of a CONST_VECTOR for expand_vec_perm. * expr.c (expand_expr_real_2) [VEC_PERM_EXPR]: Avoid passing a CONST_INT to expand_vec_perm as the selector. * optabs.c (expand_vec_perm): Assert the selector is of a proper mode. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@182192 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3490874..885f535 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2011-12-10 Richard Henderson <r...@redhat.com> + * expr.c (expand_expr_real_2) [VEC_PERM_EXPR]: Avoid passing a + CONST_INT to expand_vec_perm as the selector. + * optabs.c (expand_vec_perm): Assert the selector is of a proper mode. + +2011-12-10 Richard Henderson <r...@redhat.com> + * genmodes.c (struct mode_data): Remove wider_2x member. (blank_mode): Adjust initializer. (calc_wider_mode): Use XALLOCAVEC. diff --git a/gcc/expr.c b/gcc/expr.c index b2166bd..aa78468 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8716,6 +8716,23 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, case VEC_PERM_EXPR: expand_operands (treeop0, treeop1, target, &op0, &op1, EXPAND_NORMAL); op2 = expand_normal (treeop2); + + /* Careful here: if the target doesn't support integral vector modes, + a constant selection vector could wind up smooshed into a normal + integral constant. */ + if (CONSTANT_P (op2) && GET_CODE (op2) != CONST_VECTOR) + { + tree sel_type = TREE_TYPE (treeop2); + enum machine_mode vmode + = mode_for_vector (TYPE_MODE (TREE_TYPE (sel_type)), + TYPE_VECTOR_SUBPARTS (sel_type)); + gcc_assert (GET_MODE_CLASS (vmode) == MODE_VECTOR_INT); + op2 = simplify_subreg (vmode, op2, TYPE_MODE (sel_type), 0); + gcc_assert (op2 && GET_CODE (op2) == CONST_VECTOR); + } + else + gcc_assert (GET_MODE_CLASS (GET_MODE (op2)) == MODE_VECTOR_INT); + temp = expand_vec_perm (mode, op0, op1, op2, target); gcc_assert (temp); return temp; diff --git a/gcc/optabs.c b/gcc/optabs.c index 3f50177..2c3a640 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -7038,7 +7038,8 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target) } /* If the input is a constant, expand it specially. */ - if (CONSTANT_P (sel)) + gcc_assert (GET_MODE_CLASS (GET_MODE (sel)) == MODE_VECTOR_INT); + if (GET_CODE (sel) == CONST_VECTOR) { icode = direct_optab_handler (vec_perm_const_optab, mode); if (icode != CODE_FOR_nothing) @@ -7056,7 +7057,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target) { unsigned int j, this_e; - this_e = INTVAL (XVECEXP (sel, 0, i)); + this_e = INTVAL (CONST_VECTOR_ELT (sel, i)); this_e &= 2 * e - 1; this_e *= u;