Commit 4cb110fb by Richard Henderson Committed by Richard Henderson

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
parent ed80f859
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> 2011-10-27 Bernd Schmidt <bernds@codesourcery.com>
* config/c6x/c6x.c (unit_req_imbalance, res_mii): Cast the first arg * config/c6x/c6x.c (unit_req_imbalance, res_mii): Cast the first arg
...@@ -6912,7 +6912,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target) ...@@ -6912,7 +6912,7 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
enum insn_code icode; enum insn_code icode;
enum machine_mode qimode; enum machine_mode qimode;
unsigned int i, w, e, u; unsigned int i, w, e, u;
rtx tmp, sel_qi; rtx tmp, sel_qi = NULL;
rtvec vec; rtvec vec;
if (!target || GET_MODE (target) != mode) 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) ...@@ -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. */ /* Fall back to a constant byte-based permutation. */
if (qimode != VOIDmode) if (qimode != VOIDmode)
{ {
icode = direct_optab_handler (vec_perm_const_optab, qimode); vec = rtvec_alloc (w);
if (icode != CODE_FOR_nothing) for (i = 0; i < e; ++i)
{ {
vec = rtvec_alloc (w); unsigned int j, this_e;
for (i = 0; i < e; ++i)
{
unsigned int j, this_e;
this_e = INTVAL (XVECEXP (sel, 0, i)); this_e = INTVAL (XVECEXP (sel, 0, i));
this_e &= 2 * e - 1; this_e &= 2 * e - 1;
this_e *= u; this_e *= u;
for (j = 0; j < u; ++j) for (j = 0; j < u; ++j)
RTVEC_ELT (vec, i * u + j) = GEN_INT (this_e + j); RTVEC_ELT (vec, i * u + j) = GEN_INT (this_e + j);
} }
sel_qi = gen_rtx_CONST_VECTOR (qimode, vec); sel_qi = gen_rtx_CONST_VECTOR (qimode, vec);
icode = direct_optab_handler (vec_perm_const_optab, qimode);
if (icode != CODE_FOR_nothing)
{
tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target), tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
gen_lowpart (qimode, v0), gen_lowpart (qimode, v0),
gen_lowpart (qimode, v1), sel_qi); 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) ...@@ -6989,47 +6989,53 @@ expand_vec_perm (enum machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target)
if (icode == CODE_FOR_nothing) if (icode == CODE_FOR_nothing)
return NULL_RTX; return NULL_RTX;
/* Multiply each element by its byte size. */ if (sel_qi == NULL)
if (u == 2) {
sel = expand_simple_binop (mode, PLUS, sel, sel, sel, 0, OPTAB_DIRECT); /* Multiply each element by its byte size. */
else enum machine_mode selmode = GET_MODE (sel);
sel = expand_simple_binop (mode, ASHIFT, sel, GEN_INT (exact_log2 (u)), if (u == 2)
sel, 0, OPTAB_DIRECT); sel = expand_simple_binop (selmode, PLUS, sel, sel,
gcc_assert (sel != NULL); sel, 0, OPTAB_DIRECT);
else
/* Broadcast the low byte each element into each of its bytes. */ sel = expand_simple_binop (selmode, ASHIFT, sel,
vec = rtvec_alloc (w); GEN_INT (exact_log2 (u)),
for (i = 0; i < w; ++i) sel, 0, OPTAB_DIRECT);
{ gcc_assert (sel != NULL);
int this_e = i / u * u;
if (BYTES_BIG_ENDIAN) /* Broadcast the low byte each element into each of its bytes. */
this_e += u - 1; vec = rtvec_alloc (w);
RTVEC_ELT (vec, i) = GEN_INT (this_e); for (i = 0; i < w; ++i)
} {
tmp = gen_rtx_CONST_VECTOR (qimode, vec); int this_e = i / u * u;
sel = gen_lowpart (qimode, sel); if (BYTES_BIG_ENDIAN)
sel = expand_vec_perm (qimode, sel, sel, tmp, NULL); this_e += u - 1;
gcc_assert (sel != NULL); RTVEC_ELT (vec, i) = GEN_INT (this_e);
}
/* Add the byte offset to each byte element. */ tmp = gen_rtx_CONST_VECTOR (qimode, vec);
/* Note that the definition of the indicies here is memory ordering, sel = gen_lowpart (qimode, sel);
so there should be no difference between big and little endian. */ sel = expand_vec_perm (qimode, sel, sel, tmp, NULL);
vec = rtvec_alloc (w); gcc_assert (sel != NULL);
for (i = 0; i < w; ++i)
RTVEC_ELT (vec, i) = GEN_INT (i % u); /* Add the byte offset to each byte element. */
tmp = gen_rtx_CONST_VECTOR (qimode, vec); /* Note that the definition of the indicies here is memory ordering,
sel = expand_simple_binop (qimode, PLUS, sel, tmp, sel, 0, OPTAB_DIRECT); so there should be no difference between big and little endian. */
gcc_assert (sel != NULL); 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), tmp = expand_vec_perm_1 (icode, gen_lowpart (qimode, target),
gen_lowpart (qimode, v0), gen_lowpart (qimode, v0),
gen_lowpart (qimode, v1), sel); gen_lowpart (qimode, v1), sel_qi);
if (tmp) if (tmp)
tmp = gen_lowpart (mode, tmp); tmp = gen_lowpart (mode, tmp);
return tmp; return tmp;
} }
/* Return insn code for a conditional operator with a comparison in /* 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. */ mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment