diff options
author | Marc Glisse <marc.glisse@inria.fr> | 2013-04-03 11:44:28 +0200 |
---|---|---|
committer | Marc Glisse <glisse@gcc.gnu.org> | 2013-04-03 09:44:28 +0000 |
commit | da694a7701bc6c2defe09cc590166de096dd26da (patch) | |
tree | ece4f79c1b1627fac4524994f1ce7a3179e31280 /gcc/simplify-rtx.c | |
parent | 4e7d7b3d5d5cefd5e19a736a83c3077f7c95baad (diff) | |
download | gcc-da694a7701bc6c2defe09cc590166de096dd26da.zip gcc-da694a7701bc6c2defe09cc590166de096dd26da.tar.gz gcc-da694a7701bc6c2defe09cc590166de096dd26da.tar.bz2 |
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
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r-- | gcc/simplify-rtx.c | 94 |
1 files changed, 80 insertions, 14 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index c320bcf..791f91a 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: |