summaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c91
1 files changed, 75 insertions, 16 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 905661cf7e6..59dbc034c4f 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -984,12 +984,22 @@ int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2,
break;
case MULT_HIGHPART_EXPR:
- /* ??? Need quad precision, or an additional shift operand
- to the multiply primitive, to handle very large highparts. */
if (TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT)
- return NULL_TREE;
- tmp = op1 - op2;
- res = tmp.rshift (TYPE_PRECISION (type), TYPE_PRECISION (type), !uns);
+ {
+ bool dummy_overflow;
+ if (TYPE_PRECISION (type) != 2 * HOST_BITS_PER_WIDE_INT)
+ return NULL_TREE;
+ op1.wide_mul_with_sign (op2, uns, &res, &dummy_overflow);
+ }
+ else
+ {
+ bool dummy_overflow;
+ /* MULT_HIGHPART_EXPR can't ever oveflow, as the multiplication
+ is performed in twice the precision of arguments. */
+ tmp = op1.mul_with_sign (op2, false, &dummy_overflow);
+ res = tmp.rshift (TYPE_PRECISION (type),
+ 2 * TYPE_PRECISION (type), !uns);
+ }
break;
case TRUNC_DIV_EXPR:
@@ -1342,21 +1352,44 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
if (TREE_CODE (arg1) == VECTOR_CST
&& TREE_CODE (arg2) == VECTOR_CST)
{
- tree type = TREE_TYPE(arg1);
+ tree type = TREE_TYPE (arg1);
int count = TYPE_VECTOR_SUBPARTS (type), i;
- tree *elts = XALLOCAVEC (tree, count);
+ tree *elts = XALLOCAVEC (tree, count);
for (i = 0; i < count; i++)
{
- tree elem1 = VECTOR_CST_ELT (arg1, i);
+ tree elem1 = VECTOR_CST_ELT (arg1, i);
tree elem2 = VECTOR_CST_ELT (arg2, i);
- elts[i] = const_binop (code, elem1, elem2);
+ elts[i] = const_binop (code, elem1, elem2);
+
+ /* It is possible that const_binop cannot handle the given
+ code and return NULL_TREE */
+ if (elts[i] == NULL_TREE)
+ return NULL_TREE;
+ }
+
+ return build_vector (type, elts);
+ }
+
+ /* Shifts allow a scalar offset for a vector. */
+ if (TREE_CODE (arg1) == VECTOR_CST
+ && TREE_CODE (arg2) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (arg1);
+ int count = TYPE_VECTOR_SUBPARTS (type), i;
+ tree *elts = XALLOCAVEC (tree, count);
+
+ for (i = 0; i < count; i++)
+ {
+ tree elem1 = VECTOR_CST_ELT (arg1, i);
- /* It is possible that const_binop cannot handle the given
- code and return NULL_TREE */
- if(elts[i] == NULL_TREE)
- return NULL_TREE;
+ elts[i] = const_binop (code, elem1, arg2);
+
+ /* It is possible that const_binop cannot handle the given
+ code and return NULL_TREE */
+ if (elts[i] == NULL_TREE)
+ return NULL_TREE;
}
return build_vector (type, elts);
@@ -5850,8 +5883,10 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
/* The last case is if we are a multiply. In that case, we can
apply the distributive law to commute the multiply and addition
- if the multiplication of the constants doesn't overflow. */
- if (code == MULT_EXPR)
+ if the multiplication of the constants doesn't overflow
+ and overflow is defined. With undefined overflow
+ op0 * c might overflow, while (op0 + orig_op1) * c doesn't. */
+ if (code == MULT_EXPR && TYPE_OVERFLOW_WRAPS (ctype))
return fold_build2 (tcode, ctype,
fold_build2 (code, ctype,
fold_convert (ctype, op0),
@@ -9857,7 +9892,8 @@ fold_binary_loc (location_t loc,
|| (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == FIXED_CST)
|| (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST)
- || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST))
+ || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+ || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == INTEGER_CST))
{
if (kind == tcc_binary)
{
@@ -13924,6 +13960,29 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
return pedantic_omit_one_operand_loc (loc, type, arg1, arg2);
if (integer_zerop (arg0))
return pedantic_omit_one_operand_loc (loc, type, arg2, arg1);
+
+ if ((TREE_CODE (arg1) == VECTOR_CST
+ || TREE_CODE (arg1) == CONSTRUCTOR)
+ && (TREE_CODE (arg2) == VECTOR_CST
+ || TREE_CODE (arg2) == CONSTRUCTOR))
+ {
+ unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+ unsigned char *sel = XALLOCAVEC (unsigned char, nelts);
+ gcc_assert (nelts == VECTOR_CST_NELTS (arg0));
+ for (i = 0; i < nelts; i++)
+ {
+ tree val = VECTOR_CST_ELT (arg0, i);
+ if (integer_all_onesp (val))
+ sel[i] = i;
+ else if (integer_zerop (val))
+ sel[i] = nelts + i;
+ else /* Currently unreachable. */
+ return NULL_TREE;
+ }
+ tree t = fold_vec_perm (type, arg1, arg2, sel);
+ if (t != NULL_TREE)
+ return t;
+ }
}
if (operand_equal_p (arg1, op2, 0))