UNSPEC_VPERM);
else
{
- /* Invert selector. */
- rtx splat = gen_rtx_VEC_DUPLICATE (V16QImode,
- gen_rtx_CONST_INT (QImode, -1));
+ /* Invert selector. We prefer to generate VNAND on P8 so
+ that future fusion opportunities can kick in, but must
+ generate VNOR elsewhere. */
+ rtx notx = gen_rtx_NOT (V16QImode, force_reg (V16QImode, x));
+ rtx iorx = (TARGET_P8_VECTOR
+ ? gen_rtx_IOR (V16QImode, notx, notx)
+ : gen_rtx_AND (V16QImode, notx, notx));
rtx tmp = gen_reg_rtx (V16QImode);
- emit_move_insn (tmp, splat);
- x = gen_rtx_MINUS (V16QImode, tmp, force_reg (V16QImode, x));
- emit_move_insn (tmp, x);
+ emit_insn (gen_rtx_SET (VOIDmode, tmp, iorx));
/* Permute with operands reversed and adjusted selector. */
x = gen_rtx_UNSPEC (mode, gen_rtvec (3, reg, target, tmp),
/* Similarly to altivec_expand_vec_perm_const_le, we must adjust the
permute control vector. But here it's not a constant, so we must
- generate a vector splat/subtract to do the adjustment. */
+ generate a vector NAND or NOR to do the adjustment. */
void
altivec_expand_vec_perm_le (rtx operands[4])
{
- rtx splat, unspec;
+ rtx notx, iorx, unspec;
rtx target = operands[0];
rtx op0 = operands[1];
rtx op1 = operands[2];
rtx sel = operands[3];
rtx tmp = target;
- rtx splatreg = gen_reg_rtx (V16QImode);
+ rtx norreg = gen_reg_rtx (V16QImode);
enum machine_mode mode = GET_MODE (target);
/* Get everything in regs so the pattern matches. */
if (!REG_P (target))
tmp = gen_reg_rtx (mode);
- /* SEL = splat(31) - SEL. */
- /* We want to subtract from 31, but we can't vspltisb 31 since
- it's out of range. -1 works as well because only the low-order
- five bits of the permute control vector elements are used. */
- splat = gen_rtx_VEC_DUPLICATE (V16QImode,
- gen_rtx_CONST_INT (QImode, -1));
- emit_move_insn (splatreg, splat);
- sel = gen_rtx_MINUS (V16QImode, splatreg, sel);
- emit_move_insn (splatreg, sel);
+ /* Invert the selector with a VNAND if available, else a VNOR.
+ The VNAND is preferred for future fusion opportunities. */
+ notx = gen_rtx_NOT (V16QImode, sel);
+ iorx = (TARGET_P8_VECTOR
+ ? gen_rtx_IOR (V16QImode, notx, notx)
+ : gen_rtx_AND (V16QImode, notx, notx));
+ emit_insn (gen_rtx_SET (VOIDmode, norreg, iorx));
/* Permute with operands reversed and adjusted selector. */
- unspec = gen_rtx_UNSPEC (mode, gen_rtvec (3, op1, op0, splatreg), UNSPEC_VPERM);
+ unspec = gen_rtx_UNSPEC (mode, gen_rtvec (3, op1, op0, norreg),
+ UNSPEC_VPERM);
/* Copy into target, possibly by way of a register. */
if (!REG_P (target))