summaryrefslogtreecommitdiff
path: root/gcc/simplify-rtx.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r--gcc/simplify-rtx.c94
1 files changed, 80 insertions, 14 deletions
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: