Commit da694a77 by Marc Glisse Committed by Marc Glisse

simplify-rtx.c (simplify_binary_operation_1): Handle VEC_MERGE.

2013-04-03  Marc Glisse  <marc.glisse@inria.fr>

gcc/
	* simplify-rtx.c (simplify_binary_operation_1) <VEC_SELECT>:
	Handle VEC_MERGE.
	(simplify_ternary_operation) <VEC_MERGE>: Use unsigned HOST_WIDE_INT
	for masks. Test for side effects. Handle nested VEC_MERGE. Handle
	equal arguments.

gcc/testsuite/
	* gcc.target/i386/merge-1.c: New testcase.
	* gcc.target/i386/avx2-vpblendd128-1.c: Make it non-trivial.

From-SVN: r197394
parent 4e7d7b3d
2013-04-03 Marc Glisse <marc.glisse@inria.fr>
* simplify-rtx.c (simplify_binary_operation_1) <VEC_SELECT>:
Handle VEC_MERGE.
(simplify_ternary_operation) <VEC_MERGE>: Use unsigned HOST_WIDE_INT
for masks. Test for side effects. Handle nested VEC_MERGE. Handle
equal arguments.
2013-04-03 Jakub Jelinek <jakub@redhat.com>
PR c/19449
......
......@@ -3560,6 +3560,31 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
return vec;
}
/* If we select elements in a vec_merge that all come from the same
operand, select from that operand directly. */
if (GET_CODE (op0) == VEC_MERGE)
{
rtx trueop02 = avoid_constant_pool_reference (XEXP (op0, 2));
if (CONST_INT_P (trueop02))
{
unsigned HOST_WIDE_INT sel = UINTVAL (trueop02);
bool all_operand0 = true;
bool all_operand1 = true;
for (int i = 0; i < XVECLEN (trueop1, 0); i++)
{
rtx j = XVECEXP (trueop1, 0, i);
if (sel & (1 << UINTVAL (j)))
all_operand1 = false;
else
all_operand0 = false;
}
if (all_operand0 && !side_effects_p (XEXP (op0, 1)))
return simplify_gen_binary (VEC_SELECT, mode, XEXP (op0, 0), op1);
if (all_operand1 && !side_effects_p (XEXP (op0, 0)))
return simplify_gen_binary (VEC_SELECT, mode, XEXP (op0, 1), op1);
}
}
return 0;
case VEC_CONCAT:
{
......@@ -5224,7 +5249,7 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
{
unsigned int width = GET_MODE_PRECISION (mode);
bool any_change = false;
rtx tem;
rtx tem, trueop2;
/* VOIDmode means "infinite" precision. */
if (width == 0)
......@@ -5370,33 +5395,74 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
gcc_assert (GET_MODE (op0) == mode);
gcc_assert (GET_MODE (op1) == mode);
gcc_assert (VECTOR_MODE_P (mode));
op2 = avoid_constant_pool_reference (op2);
if (CONST_INT_P (op2))
trueop2 = avoid_constant_pool_reference (op2);
if (CONST_INT_P (trueop2))
{
int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
int mask = (1 << n_elts) - 1;
unsigned HOST_WIDE_INT sel = UINTVAL (trueop2);
unsigned HOST_WIDE_INT mask;
if (n_elts == HOST_BITS_PER_WIDE_INT)
mask = -1;
else
mask = ((unsigned HOST_WIDE_INT) 1 << n_elts) - 1;
if (!(INTVAL (op2) & mask))
if (!(sel & mask) && !side_effects_p (op0))
return op1;
if ((INTVAL (op2) & mask) == mask)
if ((sel & mask) == mask && !side_effects_p (op1))
return op0;
op0 = avoid_constant_pool_reference (op0);
op1 = avoid_constant_pool_reference (op1);
if (GET_CODE (op0) == CONST_VECTOR
&& GET_CODE (op1) == CONST_VECTOR)
rtx trueop0 = avoid_constant_pool_reference (op0);
rtx trueop1 = avoid_constant_pool_reference (op1);
if (GET_CODE (trueop0) == CONST_VECTOR
&& GET_CODE (trueop1) == CONST_VECTOR)
{
rtvec v = rtvec_alloc (n_elts);
unsigned int i;
for (i = 0; i < n_elts; i++)
RTVEC_ELT (v, i) = (INTVAL (op2) & (1 << i)
? CONST_VECTOR_ELT (op0, i)
: CONST_VECTOR_ELT (op1, i));
RTVEC_ELT (v, i) = ((sel & ((unsigned HOST_WIDE_INT) 1 << i))
? CONST_VECTOR_ELT (trueop0, i)
: CONST_VECTOR_ELT (trueop1, i));
return gen_rtx_CONST_VECTOR (mode, v);
}
/* Replace (vec_merge (vec_merge a b m) c n) with (vec_merge b c n)
if no element from a appears in the result. */
if (GET_CODE (op0) == VEC_MERGE)
{
tem = avoid_constant_pool_reference (XEXP (op0, 2));
if (CONST_INT_P (tem))
{
unsigned HOST_WIDE_INT sel0 = UINTVAL (tem);
if (!(sel & sel0 & mask) && !side_effects_p (XEXP (op0, 0)))
return simplify_gen_ternary (code, mode, mode,
XEXP (op0, 1), op1, op2);
if (!(sel & ~sel0 & mask) && !side_effects_p (XEXP (op0, 1)))
return simplify_gen_ternary (code, mode, mode,
XEXP (op0, 0), op1, op2);
}
}
if (GET_CODE (op1) == VEC_MERGE)
{
tem = avoid_constant_pool_reference (XEXP (op1, 2));
if (CONST_INT_P (tem))
{
unsigned HOST_WIDE_INT sel1 = UINTVAL (tem);
if (!(~sel & sel1 & mask) && !side_effects_p (XEXP (op1, 0)))
return simplify_gen_ternary (code, mode, mode,
op0, XEXP (op1, 1), op2);
if (!(~sel & ~sel1 & mask) && !side_effects_p (XEXP (op1, 1)))
return simplify_gen_ternary (code, mode, mode,
op0, XEXP (op1, 0), op2);
}
}
}
if (rtx_equal_p (op0, op1)
&& !side_effects_p (op2) && !side_effects_p (op1))
return op0;
break;
default:
......
2013-04-03 Marc Glisse <marc.glisse@inria.fr>
* gcc.target/i386/merge-1.c: New testcase.
* gcc.target/i386/avx2-vpblendd128-1.c: Make it non-trivial.
2013-04-03 Jakub Jelinek <jakub@redhat.com>
PR c/19449
......
......@@ -5,9 +5,10 @@
#include <immintrin.h>
__m128i x;
__m128i y;
void extern
avx2_test (void)
{
x = _mm_blend_epi32 (x, x, 13);
x = _mm_blend_epi32 (x, y, 13);
}
/* { dg-do compile } */
/* { dg-options "-O1 -msse2" } */
#include <x86intrin.h>
void
f (double *r, __m128d x, __m128d y, __m128d z)
{
__m128d t=_mm_move_sd(x,y);
__m128d u=_mm_move_sd(t,z);
*r = u[0];
}
__m128d
g(__m128d x, __m128d y, __m128d z)
{
__m128d t=_mm_move_sd(x,y);
__m128d u=_mm_move_sd(t,z);
return u;
}
/* { dg-final { scan-assembler-times "movsd" 1 } } */
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