aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2018-07-16 06:49:39 +0000
committerAldy Hernandez <aldyh@gcc.gnu.org>2018-07-16 06:49:39 +0000
commit5f9d2c5870c0eaed8447efca0a2d453624cebe7a (patch)
tree4ab834e2c0791a891484a44e2e4d8ae246f635c7 /gcc/fold-const.c
parent5933c6856604f4c83d8e4fadcd4627c1e0e4e500 (diff)
downloadgcc-5f9d2c5870c0eaed8447efca0a2d453624cebe7a.zip
gcc-5f9d2c5870c0eaed8447efca0a2d453624cebe7a.tar.gz
gcc-5f9d2c5870c0eaed8447efca0a2d453624cebe7a.tar.bz2
fold-const.c (int_const_binop_1): Abstract...
* fold-const.c (int_const_binop_1): Abstract... (wide_int_binop): ...wide int code here. (poly_int_binop): ...poly int code here. (tree_binop): ...tree code here. * fold-const.h (wide_int_binop): New. * tree-vrp.c (vrp_int_const_binop): Call wide_int_binop. Remove useless PLUS/MINUS_EXPR case. (zero_nonzero_bits_from_vr): Move wide int code... (zero_nonzero_bits_from_bounds): ...here. (extract_range_from_binary_expr_1): Move mask optimization code... (range_easy_mask_min_max): ...here. * tree-vrp.h (zero_nonzero_bits_from_bounds): New. (range_easy_mask_min_max): New. From-SVN: r262676
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c213
1 files changed, 109 insertions, 104 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 1197d75..b318fc7 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -966,21 +966,17 @@ int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2
&& TYPE_MODE (type1) == TYPE_MODE (type2);
}
-/* Subroutine of int_const_binop_1 that handles two INTEGER_CSTs. */
+/* Combine two wide ints ARG1 and ARG2 under operation CODE to produce
+ a new constant in RES. Return FALSE if we don't know how to
+ evaluate CODE at compile-time. */
-static tree
-int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
- int overflowable)
+bool
+wide_int_binop (wide_int &res,
+ enum tree_code code, const wide_int &arg1, const wide_int &arg2,
+ signop sign, wi::overflow_type *overflow)
{
- wide_int res;
- tree t;
- tree type = TREE_TYPE (parg1);
- signop sign = TYPE_SIGN (type);
- wi::overflow_type overflow = wi::OVF_NONE;
-
- wi::tree_to_wide_ref arg1 = wi::to_wide (parg1);
- wide_int arg2 = wi::to_wide (parg2, TYPE_PRECISION (type));
-
+ wide_int tmp;
+ *overflow = wi::OVF_NONE;
switch (code)
{
case BIT_IOR_EXPR:
@@ -999,49 +995,53 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
case LSHIFT_EXPR:
if (wi::neg_p (arg2))
{
- arg2 = -arg2;
+ tmp = -arg2;
if (code == RSHIFT_EXPR)
code = LSHIFT_EXPR;
else
code = RSHIFT_EXPR;
}
+ else
+ tmp = arg2;
if (code == RSHIFT_EXPR)
/* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */
- res = wi::rshift (arg1, arg2, sign);
+ res = wi::rshift (arg1, tmp, sign);
else
- res = wi::lshift (arg1, arg2);
+ res = wi::lshift (arg1, tmp);
break;
case RROTATE_EXPR:
case LROTATE_EXPR:
if (wi::neg_p (arg2))
{
- arg2 = -arg2;
+ tmp = -arg2;
if (code == RROTATE_EXPR)
code = LROTATE_EXPR;
else
code = RROTATE_EXPR;
}
+ else
+ tmp = arg2;
if (code == RROTATE_EXPR)
- res = wi::rrotate (arg1, arg2);
+ res = wi::rrotate (arg1, tmp);
else
- res = wi::lrotate (arg1, arg2);
+ res = wi::lrotate (arg1, tmp);
break;
case PLUS_EXPR:
- res = wi::add (arg1, arg2, sign, &overflow);
+ res = wi::add (arg1, arg2, sign, overflow);
break;
case MINUS_EXPR:
- res = wi::sub (arg1, arg2, sign, &overflow);
+ res = wi::sub (arg1, arg2, sign, overflow);
break;
case MULT_EXPR:
- res = wi::mul (arg1, arg2, sign, &overflow);
+ res = wi::mul (arg1, arg2, sign, overflow);
break;
case MULT_HIGHPART_EXPR:
@@ -1051,50 +1051,50 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
case TRUNC_DIV_EXPR:
case EXACT_DIV_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::div_trunc (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::div_trunc (arg1, arg2, sign, overflow);
break;
case FLOOR_DIV_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::div_floor (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::div_floor (arg1, arg2, sign, overflow);
break;
case CEIL_DIV_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::div_ceil (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::div_ceil (arg1, arg2, sign, overflow);
break;
case ROUND_DIV_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::div_round (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::div_round (arg1, arg2, sign, overflow);
break;
case TRUNC_MOD_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::mod_trunc (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::mod_trunc (arg1, arg2, sign, overflow);
break;
case FLOOR_MOD_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::mod_floor (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::mod_floor (arg1, arg2, sign, overflow);
break;
case CEIL_MOD_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::mod_ceil (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::mod_ceil (arg1, arg2, sign, overflow);
break;
case ROUND_MOD_EXPR:
if (arg2 == 0)
- return NULL_TREE;
- res = wi::mod_round (arg1, arg2, sign, &overflow);
+ return false;
+ res = wi::mod_round (arg1, arg2, sign, overflow);
break;
case MIN_EXPR:
@@ -1106,89 +1106,94 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
break;
default:
- return NULL_TREE;
+ return false;
}
-
- t = force_fit_type (type, res, overflowable,
- (((sign == SIGNED || overflowable == -1)
- && overflow)
- | TREE_OVERFLOW (parg1) | TREE_OVERFLOW (parg2)));
-
- return t;
+ return true;
}
-/* Combine two integer constants PARG1 and PARG2 under operation CODE
- to produce a new constant. Return NULL_TREE if we don't know how
+/* Combine two poly int's ARG1 and ARG2 under operation CODE to
+ produce a new constant in RES. Return FALSE if we don't know how
to evaluate CODE at compile-time. */
-static tree
-int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2,
- int overflowable)
+static bool
+poly_int_binop (poly_wide_int &res, enum tree_code code,
+ const_tree arg1, const_tree arg2,
+ signop sign, wi::overflow_type *overflow)
{
- if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST)
- return int_const_binop_2 (code, arg1, arg2, overflowable);
-
gcc_assert (NUM_POLY_INT_COEFFS != 1);
-
- if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2))
+ gcc_assert (poly_int_tree_p (arg1) && poly_int_tree_p (arg2));
+ switch (code)
{
- poly_wide_int res;
- wi::overflow_type overflow;
- tree type = TREE_TYPE (arg1);
- signop sign = TYPE_SIGN (type);
- switch (code)
- {
- case PLUS_EXPR:
- res = wi::add (wi::to_poly_wide (arg1),
- wi::to_poly_wide (arg2), sign, &overflow);
- break;
+ case PLUS_EXPR:
+ res = wi::add (wi::to_poly_wide (arg1),
+ wi::to_poly_wide (arg2), sign, overflow);
+ break;
- case MINUS_EXPR:
- res = wi::sub (wi::to_poly_wide (arg1),
- wi::to_poly_wide (arg2), sign, &overflow);
- break;
+ case MINUS_EXPR:
+ res = wi::sub (wi::to_poly_wide (arg1),
+ wi::to_poly_wide (arg2), sign, overflow);
+ break;
- case MULT_EXPR:
- if (TREE_CODE (arg2) == INTEGER_CST)
- res = wi::mul (wi::to_poly_wide (arg1),
- wi::to_wide (arg2), sign, &overflow);
- else if (TREE_CODE (arg1) == INTEGER_CST)
- res = wi::mul (wi::to_poly_wide (arg2),
- wi::to_wide (arg1), sign, &overflow);
- else
- return NULL_TREE;
- break;
+ case MULT_EXPR:
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ res = wi::mul (wi::to_poly_wide (arg1),
+ wi::to_wide (arg2), sign, overflow);
+ else if (TREE_CODE (arg1) == INTEGER_CST)
+ res = wi::mul (wi::to_poly_wide (arg2),
+ wi::to_wide (arg1), sign, overflow);
+ else
+ return NULL_TREE;
+ break;
- case LSHIFT_EXPR:
- if (TREE_CODE (arg2) == INTEGER_CST)
- res = wi::to_poly_wide (arg1) << wi::to_wide (arg2);
- else
- return NULL_TREE;
- break;
+ case LSHIFT_EXPR:
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ res = wi::to_poly_wide (arg1) << wi::to_wide (arg2);
+ else
+ return false;
+ break;
- case BIT_IOR_EXPR:
- if (TREE_CODE (arg2) != INTEGER_CST
- || !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2),
- &res))
- return NULL_TREE;
- break;
+ case BIT_IOR_EXPR:
+ if (TREE_CODE (arg2) != INTEGER_CST
+ || !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2),
+ &res))
+ return false;
+ break;
- default:
- return NULL_TREE;
- }
- return force_fit_type (type, res, overflowable,
- (((sign == SIGNED || overflowable == -1)
- && overflow)
- | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)));
+ default:
+ return false;
}
-
- return NULL_TREE;
+ return true;
}
+/* Combine two integer constants ARG1 and ARG2 under operation CODE to
+ produce a new constant. Return NULL_TREE if we don't know how to
+ evaluate CODE at compile-time. */
+
tree
-int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2)
+int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2,
+ int overflowable)
{
- return int_const_binop_1 (code, arg1, arg2, 1);
+ bool success = false;
+ poly_wide_int poly_res;
+ tree type = TREE_TYPE (arg1);
+ signop sign = TYPE_SIGN (type);
+ wi::overflow_type overflow = wi::OVF_NONE;
+
+ if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST)
+ {
+ wide_int warg1 = wi::to_wide (arg1), res;
+ wide_int warg2 = wi::to_wide (arg2, TYPE_PRECISION (type));
+ success = wide_int_binop (res, code, warg1, warg2, sign, &overflow);
+ poly_res = res;
+ }
+ else if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2))
+ success = poly_int_binop (poly_res, code, arg1, arg2, sign, &overflow);
+ if (success)
+ return force_fit_type (type, poly_res, overflowable,
+ (((sign == SIGNED || overflowable == -1)
+ && overflow)
+ | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)));
+ return NULL_TREE;
}
/* Return true if binary operation OP distributes over addition in operand
@@ -1925,7 +1930,7 @@ size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1)
/* Handle general case of two integer constants. For sizetype
constant calculations we always want to know about overflow,
even in the unsigned case. */
- tree res = int_const_binop_1 (code, arg0, arg1, -1);
+ tree res = int_const_binop (code, arg0, arg1, -1);
if (res != NULL_TREE)
return res;
}