optabs.c (expand_vec_perm): Use the correct mode for scaling the selector.

* optabs.c (expand_vec_perm): Use the correct mode for scaling the
        selector.  Save the qimode constant selector for later use by the
        qimode vec_perm pattern.

From-SVN: r180567
This commit is contained in:
Richard Henderson 2011-10-27 09:23:25 -07:00 committed by Richard Henderson
parent ed80f8590c
commit 4cb110fbcb
2 changed files with 58 additions and 46 deletions

View File

@ -1,3 +1,9 @@
2011-10-27 Richard Henderson <rth@redhat.com>
* optabs.c (expand_vec_perm): Use the correct mode for scaling the
selector. Save the qimode constant selector for later use by the
qimode vec_perm pattern.
2011-10-27 Bernd Schmidt <bernds@codesourcery.com>
* config/c6x/c6x.c (unit_req_imbalance, res_mii): Cast the first arg

View File

@ -6912,7 +6912,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
enum insn_code icode;
enum machine_mode qimode;
unsigned int i, w, e, u;
rtx tmp, sel_qi;
rtx tmp, sel_qi = NULL;
rtvec vec;
if (!target || GET_MODE (target) != mode)
@ -6946,23 +6946,23 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
/* Fall back to a constant byte-based permutation. */
if (qimode != VOIDmode)
{
vec = rtvec_alloc (w);
for (i = 0; i < e; ++i)
{
unsigned int j, this_e;
this_e = INTVAL (XVECEXP (sel, 0, i));
this_e &= 2 * e - 1;
this_e *= u;
for (j = 0; j < u; ++j)
RTVEC_ELT (vec, i * u + j) = GEN_INT (this_e + j);
}
sel_qi = gen_rtx_CONST_VECTOR (qimode, vec);
icode = direct_optab_handler (vec_perm_const_optab, qimode);
if (icode != CODE_FOR_nothing)
{
vec = rtvec_alloc (w);
for (i = 0; i < e; ++i)
{
unsigned int j, this_e;
this_e = INTVAL (XVECEXP (sel, 0, i));
this_e &= 2 * e - 1;
this_e *= u;
for (j = 0; j < u; ++j)
RTVEC_ELT (vec, i * u + j) = GEN_INT (this_e + j);
}
sel_qi = gen_rtx_CONST_VECTOR (qimode, vec);
tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
gen_lowpart (qimode, v0),
gen_lowpart (qimode, v1), sel_qi);
@ -6989,47 +6989,53 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
if (icode == CODE_FOR_nothing)
return NULL_RTX;
/* Multiply each element by its byte size. */
if (u == 2)
sel = expand_simple_binop (mode, PLUS, sel, sel, sel, 0, OPTAB_DIRECT);
else
sel = expand_simple_binop (mode, ASHIFT, sel, GEN_INT (exact_log2 (u)),
sel, 0, OPTAB_DIRECT);
gcc_assert (sel != NULL);
/* Broadcast the low byte each element into each of its bytes. */
vec = rtvec_alloc (w);
for (i = 0; i < w; ++i)
if (sel_qi == NULL)
{
int this_e = i / u * u;
if (BYTES_BIG_ENDIAN)
this_e += u - 1;
RTVEC_ELT (vec, i) = GEN_INT (this_e);
}
tmp = gen_rtx_CONST_VECTOR (qimode, vec);
sel = gen_lowpart (qimode, sel);
sel = expand_vec_perm (qimode, sel, sel, tmp, NULL);
gcc_assert (sel != NULL);
/* Multiply each element by its byte size. */
enum machine_mode selmode = GET_MODE (sel);
if (u == 2)
sel = expand_simple_binop (selmode, PLUS, sel, sel,
sel, 0, OPTAB_DIRECT);
else
sel = expand_simple_binop (selmode, ASHIFT, sel,
GEN_INT (exact_log2 (u)),
sel, 0, OPTAB_DIRECT);
gcc_assert (sel != NULL);
/* Add the byte offset to each byte element. */
/* Note that the definition of the indicies here is memory ordering,
so there should be no difference between big and little endian. */
vec = rtvec_alloc (w);
for (i = 0; i < w; ++i)
RTVEC_ELT (vec, i) = GEN_INT (i % u);
tmp = gen_rtx_CONST_VECTOR (qimode, vec);
sel = expand_simple_binop (qimode, PLUS, sel, tmp, sel, 0, OPTAB_DIRECT);
gcc_assert (sel != NULL);
/* Broadcast the low byte each element into each of its bytes. */
vec = rtvec_alloc (w);
for (i = 0; i < w; ++i)
{
int this_e = i / u * u;
if (BYTES_BIG_ENDIAN)
this_e += u - 1;
RTVEC_ELT (vec, i) = GEN_INT (this_e);
}
tmp = gen_rtx_CONST_VECTOR (qimode, vec);
sel = gen_lowpart (qimode, sel);
sel = expand_vec_perm (qimode, sel, sel, tmp, NULL);
gcc_assert (sel != NULL);
/* Add the byte offset to each byte element. */
/* Note that the definition of the indicies here is memory ordering,
so there should be no difference between big and little endian. */
vec = rtvec_alloc (w);
for (i = 0; i < w; ++i)
RTVEC_ELT (vec, i) = GEN_INT (i % u);
tmp = gen_rtx_CONST_VECTOR (qimode, vec);
sel_qi = expand_simple_binop (qimode, PLUS, sel, tmp,
sel, 0, OPTAB_DIRECT);
gcc_assert (sel_qi != NULL);
}
tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
gen_lowpart (qimode, v0),
gen_lowpart (qimode, v1), sel);
gen_lowpart (qimode, v1), sel_qi);
if (tmp)
tmp = gen_lowpart (mode, tmp);
return tmp;
}
/* Return insn code for a conditional operator with a comparison in
mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE. */