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>
PR target/85993
......
......@@ -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;
}
......
......@@ -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 *);
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)\
build_fold_addr_expr_loc (UNKNOWN_LOCATION, (T))
extern tree build_fold_addr_expr_loc (location_t, tree);
......
......@@ -112,8 +112,14 @@ extern bool range_int_cst_p (value_range *);
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_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 *,
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 range_int_cst_singleton_p (value_range *);
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