From da694a7701bc6c2defe09cc590166de096dd26da Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 3 Apr 2013 11:44:28 +0200 Subject: [PATCH] simplify-rtx.c (simplify_binary_operation_1): Handle VEC_MERGE. 2013-04-03 Marc Glisse gcc/ * simplify-rtx.c (simplify_binary_operation_1) : Handle VEC_MERGE. (simplify_ternary_operation) : 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 --- gcc/ChangeLog | 8 ++ gcc/simplify-rtx.c | 94 ++++++++++++++++--- gcc/testsuite/ChangeLog | 5 + .../gcc.target/i386/avx2-vpblendd128-1.c | 3 +- gcc/testsuite/gcc.target/i386/merge-1.c | 22 +++++ 5 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/merge-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1d14dd478e6..33773594e29 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2013-04-03 Marc Glisse + + * simplify-rtx.c (simplify_binary_operation_1) : + Handle VEC_MERGE. + (simplify_ternary_operation) : Use unsigned HOST_WIDE_INT + for masks. Test for side effects. Handle nested VEC_MERGE. Handle + equal arguments. + 2013-04-03 Jakub Jelinek PR c/19449 diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index c320bcf5807..791f91a34a8 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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)); + 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: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c7265259070..9ce315c5cf4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-04-03 Marc Glisse + + * gcc.target/i386/merge-1.c: New testcase. + * gcc.target/i386/avx2-vpblendd128-1.c: Make it non-trivial. + 2013-04-03 Jakub Jelinek PR c/19449 diff --git a/gcc/testsuite/gcc.target/i386/avx2-vpblendd128-1.c b/gcc/testsuite/gcc.target/i386/avx2-vpblendd128-1.c index 92f7e1b8e23..a3fea9554e1 100644 --- a/gcc/testsuite/gcc.target/i386/avx2-vpblendd128-1.c +++ b/gcc/testsuite/gcc.target/i386/avx2-vpblendd128-1.c @@ -5,9 +5,10 @@ #include __m128i x; +__m128i y; void extern avx2_test (void) { - x = _mm_blend_epi32 (x, x, 13); + x = _mm_blend_epi32 (x, y, 13); } diff --git a/gcc/testsuite/gcc.target/i386/merge-1.c b/gcc/testsuite/gcc.target/i386/merge-1.c new file mode 100644 index 00000000000..d5256851096 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/merge-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -msse2" } */ + +#include + +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 } } */ -- 2.30.2