diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2018-07-16 06:49:39 +0000 |
---|---|---|
committer | Aldy Hernandez <aldyh@gcc.gnu.org> | 2018-07-16 06:49:39 +0000 |
commit | 5f9d2c5870c0eaed8447efca0a2d453624cebe7a (patch) | |
tree | 4ab834e2c0791a891484a44e2e4d8ae246f635c7 /gcc/fold-const.c | |
parent | 5933c6856604f4c83d8e4fadcd4627c1e0e4e500 (diff) | |
download | gcc-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.c | 213 |
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; } |