Commit 5f9d2c58 by Aldy Hernandez Committed by Aldy Hernandez

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
parent 5933c685
2018-07-16 Aldy Hernandez <aldyh@redhat.com>
* fold-const.c (int_const_binop_1): Abstract...
(wide_int_binop): ...wide int code here.
(poly_int_binop): ...poly int code here.
Abstract the rest of int_const_binop_1 into int_const_binop.
* 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.
2018-07-15 Jeff Law <law@redhat.com> 2018-07-15 Jeff Law <law@redhat.com>
PR target/85993 PR target/85993
......
...@@ -966,21 +966,17 @@ int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2 ...@@ -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); && 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 bool
int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2, wide_int_binop (wide_int &res,
int overflowable) enum tree_code code, const wide_int &arg1, const wide_int &arg2,
signop sign, wi::overflow_type *overflow)
{ {
wide_int res; wide_int tmp;
tree t; *overflow = wi::OVF_NONE;
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));
switch (code) switch (code)
{ {
case BIT_IOR_EXPR: case BIT_IOR_EXPR:
...@@ -999,49 +995,53 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2, ...@@ -999,49 +995,53 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
case LSHIFT_EXPR: case LSHIFT_EXPR:
if (wi::neg_p (arg2)) if (wi::neg_p (arg2))
{ {
arg2 = -arg2; tmp = -arg2;
if (code == RSHIFT_EXPR) if (code == RSHIFT_EXPR)
code = LSHIFT_EXPR; code = LSHIFT_EXPR;
else else
code = RSHIFT_EXPR; code = RSHIFT_EXPR;
} }
else
tmp = arg2;
if (code == RSHIFT_EXPR) if (code == RSHIFT_EXPR)
/* It's unclear from the C standard whether shifts can overflow. /* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */ interpretation ruling is needed. */
res = wi::rshift (arg1, arg2, sign); res = wi::rshift (arg1, tmp, sign);
else else
res = wi::lshift (arg1, arg2); res = wi::lshift (arg1, tmp);
break; break;
case RROTATE_EXPR: case RROTATE_EXPR:
case LROTATE_EXPR: case LROTATE_EXPR:
if (wi::neg_p (arg2)) if (wi::neg_p (arg2))
{ {
arg2 = -arg2; tmp = -arg2;
if (code == RROTATE_EXPR) if (code == RROTATE_EXPR)
code = LROTATE_EXPR; code = LROTATE_EXPR;
else else
code = RROTATE_EXPR; code = RROTATE_EXPR;
} }
else
tmp = arg2;
if (code == RROTATE_EXPR) if (code == RROTATE_EXPR)
res = wi::rrotate (arg1, arg2); res = wi::rrotate (arg1, tmp);
else else
res = wi::lrotate (arg1, arg2); res = wi::lrotate (arg1, tmp);
break; break;
case PLUS_EXPR: case PLUS_EXPR:
res = wi::add (arg1, arg2, sign, &overflow); res = wi::add (arg1, arg2, sign, overflow);
break; break;
case MINUS_EXPR: case MINUS_EXPR:
res = wi::sub (arg1, arg2, sign, &overflow); res = wi::sub (arg1, arg2, sign, overflow);
break; break;
case MULT_EXPR: case MULT_EXPR:
res = wi::mul (arg1, arg2, sign, &overflow); res = wi::mul (arg1, arg2, sign, overflow);
break; break;
case MULT_HIGHPART_EXPR: case MULT_HIGHPART_EXPR:
...@@ -1051,50 +1051,50 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2, ...@@ -1051,50 +1051,50 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
case TRUNC_DIV_EXPR: case TRUNC_DIV_EXPR:
case EXACT_DIV_EXPR: case EXACT_DIV_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::div_trunc (arg1, arg2, sign, &overflow); res = wi::div_trunc (arg1, arg2, sign, overflow);
break; break;
case FLOOR_DIV_EXPR: case FLOOR_DIV_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::div_floor (arg1, arg2, sign, &overflow); res = wi::div_floor (arg1, arg2, sign, overflow);
break; break;
case CEIL_DIV_EXPR: case CEIL_DIV_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::div_ceil (arg1, arg2, sign, &overflow); res = wi::div_ceil (arg1, arg2, sign, overflow);
break; break;
case ROUND_DIV_EXPR: case ROUND_DIV_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::div_round (arg1, arg2, sign, &overflow); res = wi::div_round (arg1, arg2, sign, overflow);
break; break;
case TRUNC_MOD_EXPR: case TRUNC_MOD_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::mod_trunc (arg1, arg2, sign, &overflow); res = wi::mod_trunc (arg1, arg2, sign, overflow);
break; break;
case FLOOR_MOD_EXPR: case FLOOR_MOD_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::mod_floor (arg1, arg2, sign, &overflow); res = wi::mod_floor (arg1, arg2, sign, overflow);
break; break;
case CEIL_MOD_EXPR: case CEIL_MOD_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::mod_ceil (arg1, arg2, sign, &overflow); res = wi::mod_ceil (arg1, arg2, sign, overflow);
break; break;
case ROUND_MOD_EXPR: case ROUND_MOD_EXPR:
if (arg2 == 0) if (arg2 == 0)
return NULL_TREE; return false;
res = wi::mod_round (arg1, arg2, sign, &overflow); res = wi::mod_round (arg1, arg2, sign, overflow);
break; break;
case MIN_EXPR: case MIN_EXPR:
...@@ -1106,55 +1106,41 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2, ...@@ -1106,55 +1106,41 @@ int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2,
break; break;
default: default:
return NULL_TREE; return false;
} }
return true;
t = force_fit_type (type, res, overflowable,
(((sign == SIGNED || overflowable == -1)
&& overflow)
| TREE_OVERFLOW (parg1) | TREE_OVERFLOW (parg2)));
return t;
} }
/* Combine two integer constants PARG1 and PARG2 under operation CODE /* Combine two poly int's ARG1 and ARG2 under operation CODE to
to produce a new constant. Return NULL_TREE if we don't know how produce a new constant in RES. Return FALSE if we don't know how
to evaluate CODE at compile-time. */ to evaluate CODE at compile-time. */
static tree static bool
int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2, poly_int_binop (poly_wide_int &res, enum tree_code code,
int overflowable) 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); gcc_assert (NUM_POLY_INT_COEFFS != 1);
gcc_assert (poly_int_tree_p (arg1) && poly_int_tree_p (arg2));
if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2))
{
poly_wide_int res;
wi::overflow_type overflow;
tree type = TREE_TYPE (arg1);
signop sign = TYPE_SIGN (type);
switch (code) switch (code)
{ {
case PLUS_EXPR: case PLUS_EXPR:
res = wi::add (wi::to_poly_wide (arg1), res = wi::add (wi::to_poly_wide (arg1),
wi::to_poly_wide (arg2), sign, &overflow); wi::to_poly_wide (arg2), sign, overflow);
break; break;
case MINUS_EXPR: case MINUS_EXPR:
res = wi::sub (wi::to_poly_wide (arg1), res = wi::sub (wi::to_poly_wide (arg1),
wi::to_poly_wide (arg2), sign, &overflow); wi::to_poly_wide (arg2), sign, overflow);
break; break;
case MULT_EXPR: case MULT_EXPR:
if (TREE_CODE (arg2) == INTEGER_CST) if (TREE_CODE (arg2) == INTEGER_CST)
res = wi::mul (wi::to_poly_wide (arg1), res = wi::mul (wi::to_poly_wide (arg1),
wi::to_wide (arg2), sign, &overflow); wi::to_wide (arg2), sign, overflow);
else if (TREE_CODE (arg1) == INTEGER_CST) else if (TREE_CODE (arg1) == INTEGER_CST)
res = wi::mul (wi::to_poly_wide (arg2), res = wi::mul (wi::to_poly_wide (arg2),
wi::to_wide (arg1), sign, &overflow); wi::to_wide (arg1), sign, overflow);
else else
return NULL_TREE; return NULL_TREE;
break; break;
...@@ -1163,32 +1149,51 @@ int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2, ...@@ -1163,32 +1149,51 @@ int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2,
if (TREE_CODE (arg2) == INTEGER_CST) if (TREE_CODE (arg2) == INTEGER_CST)
res = wi::to_poly_wide (arg1) << wi::to_wide (arg2); res = wi::to_poly_wide (arg1) << wi::to_wide (arg2);
else else
return NULL_TREE; return false;
break; break;
case BIT_IOR_EXPR: case BIT_IOR_EXPR:
if (TREE_CODE (arg2) != INTEGER_CST if (TREE_CODE (arg2) != INTEGER_CST
|| !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2), || !can_ior_p (wi::to_poly_wide (arg1), wi::to_wide (arg2),
&res)) &res))
return NULL_TREE; return false;
break; break;
default: default:
return NULL_TREE; return false;
}
return force_fit_type (type, res, overflowable,
(((sign == SIGNED || overflowable == -1)
&& overflow)
| TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)));
} }
return true;
return NULL_TREE;
} }
/* 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 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 /* 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) ...@@ -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 /* Handle general case of two integer constants. For sizetype
constant calculations we always want to know about overflow, constant calculations we always want to know about overflow,
even in the unsigned case. */ 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) if (res != NULL_TREE)
return res; return res;
} }
......
...@@ -100,7 +100,10 @@ extern tree fold_bit_and_mask (tree, tree, enum tree_code, ...@@ -100,7 +100,10 @@ extern tree fold_bit_and_mask (tree, tree, enum tree_code,
tree, enum tree_code, tree, tree, tree, enum tree_code, tree, tree,
tree, enum tree_code, tree, tree, tree *); tree, enum tree_code, tree, tree, tree *);
extern tree fold_read_from_constant_string (tree); extern tree fold_read_from_constant_string (tree);
extern tree int_const_binop (enum tree_code, const_tree, const_tree); extern bool wide_int_binop (wide_int &res, enum tree_code,
const wide_int &arg1, const wide_int &arg2,
signop, wi::overflow_type *);
extern tree int_const_binop (enum tree_code, const_tree, const_tree, int = 1);
#define build_fold_addr_expr(T)\ #define build_fold_addr_expr(T)\
build_fold_addr_expr_loc (UNKNOWN_LOCATION, (T)) build_fold_addr_expr_loc (UNKNOWN_LOCATION, (T))
extern tree build_fold_addr_expr_loc (location_t, tree); extern tree build_fold_addr_expr_loc (location_t, tree);
......
...@@ -112,8 +112,14 @@ extern bool range_int_cst_p (value_range *); ...@@ -112,8 +112,14 @@ extern bool range_int_cst_p (value_range *);
extern int operand_less_p (tree, tree); extern int operand_less_p (tree, tree);
extern bool find_case_label_range (gswitch *, tree, tree, size_t *, size_t *); extern bool find_case_label_range (gswitch *, tree, tree, size_t *, size_t *);
extern bool find_case_label_index (gswitch *, size_t, tree, size_t *); extern bool find_case_label_index (gswitch *, size_t, tree, size_t *);
extern void zero_nonzero_bits_from_bounds (signop, const wide_int&,
const wide_int&, wide_int *,
wide_int *);
extern bool zero_nonzero_bits_from_vr (const tree, value_range *, extern bool zero_nonzero_bits_from_vr (const tree, value_range *,
wide_int *, wide_int *); wide_int *, wide_int *);
extern bool range_easy_mask_min_max (tree_code,
const wide_int &lb, const wide_int &ub,
const wide_int &mask);
extern bool overflow_comparison_p (tree_code, tree, tree, bool, tree *); extern bool overflow_comparison_p (tree_code, tree, tree, bool, tree *);
extern bool range_int_cst_singleton_p (value_range *); extern bool range_int_cst_singleton_p (value_range *);
extern int value_inside_range (tree, tree, tree); extern int value_inside_range (tree, tree, tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment