I kept seeing the same patterns over and over in all this re-factoring:
1. extract value_range constants into pairs of wide ints
2. mimic symbolics as [-MIN, +MAX] (most of the time :))
3. perform some wide int operation on the wide int range
4. convert back to a value range
So I've decided to clean this up even more. Instead of passing a pair
of wide ints plus sign, precision, and god knows what to every
wide_int_range_* function, I've implemented a lighweight class
(wi_range) for a pair of wide ints. It is not meant for long term
storage, but even so its footprint is minimal.
The only extra bits are another 64-bit word per pair for keeping
attributes such as precision, sign, overflow_wraps, and a few other
things we'll need shortly. In reality we only need one set of
attributes for both sets of pairs, so we waste one 64-bit word. I don't
care. They're short lived, and the resulting code looks an awful lot
nicer. For example, the shift code gets rewritten from this:
if (range_int_cst_p (&vr1)
&& !vrp_shift_undefined_p (vr1, prec))
{
if (code == RSHIFT_EXPR)
{
if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
{
vr0.type = type = VR_RANGE;
vr0.min = vrp_val_min (expr_type);
vr0.max = vrp_val_max (expr_type);
}
extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
return;
}
else if (code == LSHIFT_EXPR
&& range_int_cst_p (&vr0))
{
wide_int res_lb, res_ub;
if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
wi::to_wide (vr0.min),
wi::to_wide (vr0.max),
wi::to_wide (vr1.min),
wi::to_wide (vr1.max),
TYPE_OVERFLOW_UNDEFINED (expr_type),
TYPE_OVERFLOW_WRAPS (expr_type)))
{
min = wide_int_to_tree (expr_type, res_lb);
max = wide_int_to_tree (expr_type, res_ub);
set_and_canonicalize_value_range (vr, VR_RANGE,
min, max, NULL);
return;
}
}
}
set_value_range_to_varying (vr);
into this:
wi_range w0 (&vr0, expr_type);
wi_range w1 (&vr1, expr_type);
if (!range_int_cst_p (&vr1)
|| wi_range_shift_undefined_p (w1)
|| (code == LSHIFT_EXPR
&& !range_int_cst_p (&vr0)))
{
vr->set_varying ();
return;
}
bool success;
if (code == RSHIFT_EXPR)
success = wi_range_multiplicative_op (res, code, w0, w1);
else
success = wi_range_lshift (res, w0, w1);
if (success)
vr->set_and_canonicalize (res, expr_type);
else
vr->set_varying ();
return;
I also munged together the maybe/mustbe nonzero_bits into one structure.
Finally, I've pontificated that wide_int_range_blah is too much typing.
Everyone's RSI will thank me for rewriting the methods as wi_range_blah.
I've tried to keep the functionality changes to a minimum. However,
there are some slight changes where I treat symbolics and VR_VARYING as
[MIN, MAX] and let the constant code do its thing. It is considerably
easier to read.
I am finally happy with the overall direction of this. If this and the
last one are acceptable, I think I only need to clean MIN/MAX_EXPR and
ABS_EXPR and I'm basically done with what I need going forward.
Phew...
How does this look?
Aldy
gcc/
* tree-vrp.c (set_value_range_to_undefined): Remove static inline.
(vrp_set_zero_nonzero_bits): Pass nonzero bits as a structure.
(vrp_shift_undefined_p): Remove.
(extract_range_from_multiplicative_op): Use wi_range class.
(vrp_can_optimize_bit_op): Rename
wide_int_range_can_optimize_bit_op to
wi_range_can_optimize_bit_op.
(extract_range_from_binary_expr_1): Use wi_range class throughout.
Rename uses of wide_int_range_* to wi_range_*.
(wi_range::dump): New.
* tree-vrp.h (struct value_range): Add set, set_and_canonicalize,
set_undefined, and set_varying.
(struct wi_range): New.
(struct maybe_nonzero_bits): New.
* vr-values.c (simplify_bit_ops_using_ranges): Pass nonzero bits
to vrp_set_zero_nonzero_bits in a structure.
* wide-int-range.cc (wi_range_set_zero_nonzero_bits): Rename from
wide_int_range_*. Pass nonzero bits as a structure. Use wi_range
for arguments and adjust.
(wi_range_min_max): Same.
(wi_range_cross_product): Same.
(wi_range_mult_wrapping): Same.
(wi_range_multiplicative_op): Same.
(wi_range_lshift): Same.
(wi_range_can_optimize_bit_op): Same.
(wi_range_bit_xor): Same.
(wi_range_bit_ior): Same.
(wi_range_bit_and): Same.
(wi_range_trunc_mod): Same.
* wide-int-range.h: Rename all wide_int_range_* to wi_range_*.
(wi_range_shift_undefined_p): Adjust for wi_range.
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index d553a254878..7fe68177704 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -246,7 +246,7 @@ intersect_range_with_nonzero_bits (enum value_range_type vr_type,
/* Set value range VR to VR_UNDEFINED. */
-static inline void
+void
set_value_range_to_undefined (value_range *vr)
{
vr->type = VR_UNDEFINED;
@@ -957,9 +957,9 @@ value_range_constant_singleton (value_range *vr)
return NULL_TREE;
}
-/* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
+/* Value range wrapper for wi_range_set_zero_nonzero_bits.
- Compute MAY_BE_NONZERO and MUST_BE_NONZERO bit masks for range in VR.
+ Compute maybe_nonzero_bits for range in VR.
Return TRUE if VR was a constant range and we were able to compute
the bit masks. */
@@ -967,19 +967,16 @@ value_range_constant_singleton (value_range *vr)
bool
vrp_set_zero_nonzero_bits (const tree expr_type,
value_range *vr,
- wide_int *may_be_nonzero,
- wide_int *must_be_nonzero)
+ maybe_nonzero_bits *nonzero)
{
if (!range_int_cst_p (vr))
{
- *may_be_nonzero = wi::minus_one (TYPE_PRECISION (expr_type));
- *must_be_nonzero = wi::zero (TYPE_PRECISION (expr_type));
+ nonzero->may_be = wi::minus_one (TYPE_PRECISION (expr_type));
+ nonzero->must_be = wi::zero (TYPE_PRECISION (expr_type));
return false;
}
- wide_int_range_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
- wi::to_wide (vr->min),
- wi::to_wide (vr->max),
- *may_be_nonzero, *must_be_nonzero);
+ wi_range r (vr, expr_type);
+ wi_range_set_zero_nonzero_bits (r, nonzero);
return true;
}
@@ -1048,17 +1045,6 @@ extract_range_into_wide_ints (value_range *vr,
}
}
-/* Value range wrapper for wide_int_range_shift_undefined_p. */
-
-static inline bool
-vrp_shift_undefined_p (const value_range &shifter, unsigned prec)
-{
- tree type = TREE_TYPE (shifter.min);
- return wide_int_range_shift_undefined_p (TYPE_SIGN (type), prec,
- wi::to_wide (shifter.min),
- wi::to_wide (shifter.max));
-}
-
/* Value range wrapper for wide_int_range_multiplicative_op:
*VR = *VR0 .CODE. *VR1. */
@@ -1079,24 +1065,13 @@ extract_range_from_multiplicative_op (value_range *vr,
gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
tree type = TREE_TYPE (vr0->min);
- wide_int res_lb, res_ub;
- wide_int vr0_lb = wi::to_wide (vr0->min);
- wide_int vr0_ub = wi::to_wide (vr0->max);
- wide_int vr1_lb = wi::to_wide (vr1->min);
- wide_int vr1_ub = wi::to_wide (vr1->max);
- bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
- bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
- unsigned prec = TYPE_PRECISION (type);
-
- if (wide_int_range_multiplicative_op (res_lb, res_ub,
- code, TYPE_SIGN (type), prec,
- vr0_lb, vr0_ub, vr1_lb, vr1_ub,
- overflow_undefined, overflow_wraps))
- set_and_canonicalize_value_range (vr, VR_RANGE,
- wide_int_to_tree (type, res_lb),
- wide_int_to_tree (type, res_ub), NULL);
+ wi_range res;
+ wi_range w0 (vr0, type);
+ wi_range w1 (vr1, type);
+ if (wi_range_multiplicative_op (res, code, w0, w1))
+ vr->set_and_canonicalize (res, type);
else
- set_value_range_to_varying (vr);
+ vr->set_varying ();
}
/* Value range wrapper for wide_int_range_can_optimize_bit_op.
@@ -1129,10 +1104,10 @@ vrp_can_optimize_bit_op (value_range *vr, enum tree_code code,
}
else
return false;
- if (wide_int_range_can_optimize_bit_op (code,
- wi::to_wide (lower_bound),
- wi::to_wide (upper_bound),
- wi::to_wide (mask)))
+ if (wi_range_can_optimize_bit_op (code,
+ wi::to_wide (lower_bound),
+ wi::to_wide (upper_bound),
+ wi::to_wide (mask)))
{
tree min = int_const_binop (code, lower_bound, mask);
tree max = int_const_binop (code, upper_bound, mask);
@@ -1317,13 +1292,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
enum tree_code code, tree expr_type,
value_range *vr0_, value_range *vr1_)
{
- signop sign = TYPE_SIGN (expr_type);
- unsigned int prec = TYPE_PRECISION (expr_type);
value_range vr0 = *vr0_, vr1 = *vr1_;
value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
enum value_range_type type;
tree min = NULL_TREE, max = NULL_TREE;
int cmp;
+ wi_range res;
if (!INTEGRAL_TYPE_P (expr_type)
&& !POINTER_TYPE_P (expr_type))
@@ -1636,56 +1610,49 @@ extract_range_from_binary_expr_1 (value_range *vr,
}
else if (code == MULT_EXPR)
{
- if (!range_int_cst_p (&vr0)
- || !range_int_cst_p (&vr1))
+ if (!range_int_cst_p (&vr0) || !range_int_cst_p (&vr1))
{
- set_value_range_to_varying (vr);
+ vr->set_varying ();
return;
}
- extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
+ wi_range w0 (&vr0, expr_type);
+ wi_range w1 (&vr1, expr_type);
+ if (wi_range_multiplicative_op (res, code, w0, w1))
+ vr->set_and_canonicalize (res, expr_type);
+ else
+ vr->set_varying ();
return;
}
else if (code == RSHIFT_EXPR
|| code == LSHIFT_EXPR)
{
- if (range_int_cst_p (&vr1)
- && !vrp_shift_undefined_p (vr1, prec))
+ /* Avoid calculating the obviously impossible stuff.
+
+ However, we allow right shifting an unknown vr0 if the shift
+ count is known, because we may still calculate a useful
+ range. For example:
+
+ x >> 63 for signed 64-bit x is always [-1, 0]. */
+ wi_range w0 (&vr0, expr_type);
+ wi_range w1 (&vr1, expr_type);
+ if (!range_int_cst_p (&vr1)
+ || wi_range_shift_undefined_p (w1)
+ || (code == LSHIFT_EXPR
+ && !range_int_cst_p (&vr0)))
{
- if (code == RSHIFT_EXPR)
- {
- /* Even if vr0 is VARYING or otherwise not usable, we can derive
- useful ranges just from the shift count. E.g.
- x >> 63 for signed 64-bit x is always [-1, 0]. */
- if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
- {
- vr0.type = type = VR_RANGE;
- vr0.min = vrp_val_min (expr_type);
- vr0.max = vrp_val_max (expr_type);
- }
- extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
- return;
- }
- else if (code == LSHIFT_EXPR
- && range_int_cst_p (&vr0))
- {
- wide_int res_lb, res_ub;
- if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
- wi::to_wide (vr0.min),
- wi::to_wide (vr0.max),
- wi::to_wide (vr1.min),
- wi::to_wide (vr1.max),
- TYPE_OVERFLOW_UNDEFINED (expr_type),
- TYPE_OVERFLOW_WRAPS (expr_type)))
- {
- min = wide_int_to_tree (expr_type, res_lb);
- max = wide_int_to_tree (expr_type, res_ub);
- set_and_canonicalize_value_range (vr, VR_RANGE,
- min, max, NULL);
- return;
- }
- }
+ vr->set_varying ();
+ return;
}
- set_value_range_to_varying (vr);
+ bool success;
+ if (code == RSHIFT_EXPR)
+ success = wi_range_multiplicative_op (res, code, w0, w1);
+ else
+ success = wi_range_lshift (res, w0, w1);
+
+ if (success)
+ vr->set_and_canonicalize (res, expr_type);
+ else
+ vr->set_varying ();
return;
}
else if (code == TRUNC_DIV_EXPR
@@ -1800,20 +1767,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
}
else if (code == TRUNC_MOD_EXPR)
{
- if (range_is_null (&vr1))
- {
- set_value_range_to_undefined (vr);
- return;
- }
- wide_int wmin, wmax, tmp;
- wide_int vr0_min, vr0_max, vr1_min, vr1_max;
- extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
- extract_range_into_wide_ints (&vr1, sign, prec, &vr1_min, &vr1_max);
- wide_int_range_trunc_mod (wmin, wmax, sign, prec,
- vr0_min, vr0_max, vr1_min, vr1_max);
- min = wide_int_to_tree (expr_type, wmin);
- max = wide_int_to_tree (expr_type, wmax);
- set_value_range (vr, VR_RANGE, min, max, NULL);
+ wi_range w0 (&vr0, expr_type);
+ wi_range w1 (&vr1, expr_type);
+ if (wi_range_trunc_mod (res, w0, w1))
+ vr->set (res, expr_type);
+ else
+ vr->set_undefined ();
return;
}
else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
@@ -1821,68 +1780,30 @@ extract_range_from_binary_expr_1 (value_range *vr,
if (vrp_can_optimize_bit_op (vr, code, &vr0, &vr1))
return;
- wide_int may_be_nonzero0, may_be_nonzero1;
- wide_int must_be_nonzero0, must_be_nonzero1;
- wide_int wmin, wmax;
- wide_int vr0_min, vr0_max, vr1_min, vr1_max;
- vrp_set_zero_nonzero_bits (expr_type, &vr0,
- &may_be_nonzero0, &must_be_nonzero0);
- vrp_set_zero_nonzero_bits (expr_type, &vr1,
- &may_be_nonzero1, &must_be_nonzero1);
- extract_range_into_wide_ints (&vr0, sign, prec, &vr0_min, &vr0_max);
- extract_range_into_wide_ints (&vr1, sign, prec, &vr1_min, &vr1_max);
+ wi_range w0 (&vr0, expr_type);
+ wi_range w1 (&vr1, expr_type);
+ maybe_nonzero_bits nonzero0, nonzero1;
+ /* ?? Previously we were calling vrp_set_zero_nonzero_bits,
+ which would immediately set the masks if the range was not a
+ constant. Let's avoid this special casing for maximum
+ share-ability. */
+ wi_range_set_zero_nonzero_bits (w0, &nonzero0);
+ wi_range_set_zero_nonzero_bits (w1, &nonzero1);
+ bool success;
if (code == BIT_AND_EXPR)
- {
- if (wide_int_range_bit_and (wmin, wmax, sign, prec,
- vr0_min, vr0_max,
- vr1_min, vr1_max,
- must_be_nonzero0,
- may_be_nonzero0,
- must_be_nonzero1,
- may_be_nonzero1))
- {
- min = wide_int_to_tree (expr_type, wmin);
- max = wide_int_to_tree (expr_type, wmax);
- set_value_range (vr, VR_RANGE, min, max, NULL);
- }
- else
- set_value_range_to_varying (vr);
- return;
- }
+ success = wi_range_bit_and (res, w0, w1, nonzero0, nonzero1);
else if (code == BIT_IOR_EXPR)
- {
- if (wide_int_range_bit_ior (wmin, wmax, sign,
- vr0_min, vr0_max,
- vr1_min, vr1_max,
- must_be_nonzero0,
- may_be_nonzero0,
- must_be_nonzero1,
- may_be_nonzero1))
- {
- min = wide_int_to_tree (expr_type, wmin);
- max = wide_int_to_tree (expr_type, wmax);
- set_value_range (vr, VR_RANGE, min, max, NULL);
- }
- else
- set_value_range_to_varying (vr);
- return;
- }
+ success = wi_range_bit_ior (res, w0, w1, nonzero0, nonzero1);
else if (code == BIT_XOR_EXPR)
- {
- if (wide_int_range_bit_xor (wmin, wmax, sign, prec,
- must_be_nonzero0,
- may_be_nonzero0,
- must_be_nonzero1,
- may_be_nonzero1))
- {
- min = wide_int_to_tree (expr_type, wmin);
- max = wide_int_to_tree (expr_type, wmax);
- set_value_range (vr, VR_RANGE, min, max, NULL);
- }
- else
- set_value_range_to_varying (vr);
- return;
- }
+ success = wi_range_bit_xor (res, w0, w1, nonzero0, nonzero1);
+ else
+ gcc_unreachable ();
+
+ if (success)
+ vr->set (res, expr_type);
+ else
+ vr->set_varying ();
+ return;
}
else
gcc_unreachable ();
@@ -2215,6 +2136,14 @@ value_range::dump ()
debug_value_range (this);
}
+void
+wi_range::dump ()
+{
+ fprintf (stderr, "[");
+ min.dump ();
+ max.dump ();
+ fprintf (stderr, "], precision = %d\n", precision);
+}
/* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,
create a new SSA name N and return the assertion assignment
diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 0c1fb3637cf..ca873be6843 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
enum value_range_type { VR_UNDEFINED, VR_RANGE,
VR_ANTI_RANGE, VR_VARYING, VR_LAST };
+struct wi_range;
+
/* Range of values that can be associated with an SSA_NAME after VRP
has executed. */
struct GTY((for_user)) value_range
@@ -52,6 +54,58 @@ struct GTY((for_user)) value_range
/* Dump value range to stderr. */
void dump ();
+
+ void set (const wi_range &r, tree type);
+ void set_and_canonicalize (const wi_range &r, tree type);
+ void set_undefined ();
+ void set_varying ();
+};
+
+/* Similar to value_range, but only for straight up VR_RANGEs held as
+ a pair of wide ints. This is used internally to pass wide int
+ ranges to wi_range_* supporting routines, and is not meant for long
+ term storage. */
+
+struct wi_range
+{
+ wide_int min;
+ wide_int max;
+ /* This structure takes one additional 64-bit word apart from the
+ min/max bounds above. It is laid out so that PRECISION and SIGN
+ can be accessed without any bit twiddling, since they're the most
+ commonly accessed fields. */
+ unsigned short precision;
+ bool empty_p:1;
+ bool pointer_type_p:1;
+ bool overflow_wraps:1;
+ bool overflow_undefined:1;
+ signop sign;
+
+ wi_range () { empty_p = false; }
+ /* Construct a new range from the contents of a value_range. */
+ wi_range (value_range *vr, tree type);
+ /* Initialize a range with [MIN_, MAX_], but using the attributes
+ (precision, sign, etc) from SRC. */
+ void set (const wi_range &src, const wide_int &min_, const wide_int &max_);
+ /* Return TRUE if range is a singleton zero. */
+ bool zero_p () const { return (wi::eq_p (min, max)
+ && wi::eq_p (min, wi::zero (precision))); }
+ /* We all need a little help sometimes. */
+ void dump ();
+};
+
+/* A structure to pass maybe and mustbe nonzero bitmasks. This is for
+ use in wi_range_set_zero_nonzero_bits and friends. */
+
+struct maybe_nonzero_bits
+{
+ /* If some bit is unset, it means that for all numbers in the range
+ the bit is 0, otherwise it might be 0 or 1. */
+ wide_int may_be;
+
+ /* If some bit is set, it means that for all numbers in the range
+ the bit is 1, otherwise it might be 0 or 1. */
+ wide_int must_be;
};
extern void vrp_intersect_ranges (value_range *vr0, value_range *vr1);
@@ -86,6 +140,7 @@ extern void register_edge_assert_for (tree, edge, enum tree_code,
tree, tree, vec<assert_info> &);
extern bool stmt_interesting_for_vrp (gimple *);
extern void set_value_range_to_varying (value_range *);
+extern void set_value_range_to_undefined (value_range *);
extern int range_includes_zero_p (tree, tree);
extern bool infer_value_range (gimple *, tree, tree_code *, tree *);
@@ -116,7 +171,7 @@ 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 bool vrp_set_zero_nonzero_bits (const tree, value_range *,
- wide_int *, wide_int *);
+ maybe_nonzero_bits *);
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);
@@ -132,4 +187,82 @@ struct switch_update {
extern vec<edge> to_remove_edges;
extern vec<switch_update> to_update_switch_stmts;
+/* Construct a new range from the contents of a value_range. Varying
+ or symbolic ranges are normalized to the entire possible range. */
+
+inline
+wi_range::wi_range (value_range *vr, tree type)
+{
+ precision = TYPE_PRECISION (type);
+ pointer_type_p = POINTER_TYPE_P (type);
+ overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
+ overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
+ sign = TYPE_SIGN (type);
+ empty_p = false;
+ if (vr->type == VR_VARYING || symbolic_range_p (vr))
+ {
+ min = wi::min_value (precision, sign);
+ max = wi::max_value (precision, sign);
+ }
+ else if (vr->type == VR_RANGE)
+ {
+ min = wi::to_wide (vr->min);
+ max = wi::to_wide (vr->max);
+ }
+ else
+ gcc_unreachable ();
+}
+
+/* Set current wi_range to [MIN_, MAX_] but with the attributes from
+ SRC. */
+
+inline void
+wi_range::set (const wi_range &src, const wide_int &min_, const wide_int &max_)
+{
+ min = min_;
+ max = max_;
+ precision = src.precision;
+ empty_p = src.empty_p;
+ pointer_type_p = src.pointer_type_p;
+ overflow_wraps = src.overflow_wraps;
+ overflow_undefined = src.overflow_undefined;
+ sign = src.sign;
+}
+
+/* Set current value_range to the range in R. */
+
+inline void
+value_range::set (const wi_range &r, tree type)
+{
+ set_value_range (this, VR_RANGE,
+ wide_int_to_tree (type, r.min),
+ wide_int_to_tree (type, r.max), NULL);
+}
+
+/* Set and canonicalize current value_range to the range in R. */
+
+inline void
+value_range::set_and_canonicalize (const wi_range &r, tree type)
+{
+ set_and_canonicalize_value_range (this, VR_RANGE,
+ wide_int_to_tree (type, r.min),
+ wide_int_to_tree (type, r.max), NULL);
+}
+
+/* Set current value range to VR_UNDEFINED. */
+
+inline void
+value_range::set_undefined ()
+{
+ set_value_range_to_undefined (this);
+}
+
+/* Set current value range to VR_VARYING. */
+
+inline void
+value_range::set_varying ()
+{
+ set_value_range_to_varying (this);
+}
+
#endif /* GCC_TREE_VRP_H */
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 33335f3da31..f8b849a2b94 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -3300,23 +3300,22 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
else
return false;
- if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op0), &vr0, &may_be_nonzero0,
- &must_be_nonzero0))
+ maybe_nonzero_bits nz0, nz1;
+ if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op0), &vr0, &nz0))
return false;
- if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op1), &vr1, &may_be_nonzero1,
- &must_be_nonzero1))
+ if (!vrp_set_zero_nonzero_bits (TREE_TYPE (op1), &vr1, &nz1))
return false;
switch (gimple_assign_rhs_code (stmt))
{
case BIT_AND_EXPR:
- mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
+ mask = wi::bit_and_not (nz0.may_be, nz1.must_be);
if (mask == 0)
{
op = op0;
break;
}
- mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
+ mask = wi::bit_and_not (nz1.may_be, nz0.must_be);
if (mask == 0)
{
op = op1;
@@ -3324,13 +3323,13 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi,
}
break;
case BIT_IOR_EXPR:
- mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
+ mask = wi::bit_and_not (nz0.may_be, nz1.must_be);
if (mask == 0)
{
op = op1;
break;
}
- mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
+ mask = wi::bit_and_not (nz1.may_be, nz0.must_be);
if (mask == 0)
{
op = op0;
diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc
index 3491d89664d..401bee4c946 100644
--- a/gcc/wide-int-range.cc
+++ b/gcc/wide-int-range.cc
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tree.h"
#include "fold-const.h"
+#include "options.h"
+#include "tree-vrp.h"
#include "wide-int-range.h"
/* Wrapper around wide_int_binop that adjusts for overflow.
@@ -76,53 +78,46 @@ wide_int_binop_overflow (wide_int &res,
return !overflow;
}
-/* For range [LB, UB] compute two wide_int bit masks.
-
- In the MAY_BE_NONZERO bit mask, if some bit is unset, it means that
- for all numbers in the range the bit is 0, otherwise it might be 0
- or 1.
-
- In the MUST_BE_NONZERO bit mask, if some bit is set, it means that
- for all numbers in the range the bit is 1, otherwise it might be 0
- or 1. */
+/* For range R compute the maybe and mustbe nonzero bits as described
+ in the MAYBE_NONZERO_BITS structure. */
void
-wide_int_range_set_zero_nonzero_bits (signop sign,
- const wide_int &lb, const wide_int &ub,
- wide_int &may_be_nonzero,
- wide_int &must_be_nonzero)
+wi_range_set_zero_nonzero_bits (const wi_range &r,
+ maybe_nonzero_bits *nonzero)
{
- may_be_nonzero = wi::minus_one (lb.get_precision ());
- must_be_nonzero = wi::zero (lb.get_precision ());
+ signop sign = r.sign;
+ nonzero->may_be = wi::minus_one (r.min.get_precision ());
+ nonzero->must_be = wi::zero (r.min.get_precision ());
- if (wi::eq_p (lb, ub))
+ if (wi::eq_p (r.min, r.max))
{
- may_be_nonzero = lb;
- must_be_nonzero = may_be_nonzero;
+ nonzero->may_be = r.min;
+ nonzero->must_be = r.min;
}
- else if (wi::ge_p (lb, 0, sign) || wi::lt_p (ub, 0, sign))
+ else if (wi::ge_p (r.min, 0, sign) || wi::lt_p (r.max, 0, sign))
{
- wide_int xor_mask = lb ^ ub;
- may_be_nonzero = lb | ub;
- must_be_nonzero = lb & ub;
+ wide_int xor_mask = r.min ^ r.max;
+ nonzero->may_be = r.min | r.max;
+ nonzero->must_be = r.min & r.max;
if (xor_mask != 0)
{
wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false,
- may_be_nonzero.get_precision ());
- may_be_nonzero = may_be_nonzero | mask;
- must_be_nonzero = wi::bit_and_not (must_be_nonzero, mask);
+ nonzero->may_be.get_precision ());
+ nonzero->may_be = nonzero->may_be | mask;
+ nonzero->must_be = wi::bit_and_not (nonzero->must_be, mask);
}
}
}
-/* Order 2 sets of wide int ranges (w0/w1, w2/w3) and set MIN/MAX
- accordingly. */
+/* Order 2 sets of wide int ranges (w0/w1, w2/w3) and set the
+ resulting [MIN, MAX] in RES. */
static void
-wide_int_range_min_max (wide_int &min, wide_int &max,
- wide_int &w0, wide_int &w1, wide_int &w2, wide_int &w3,
- signop sign)
+wi_range_min_max (wi_range &res,
+ wide_int &w0, wide_int &w1, wide_int &w2, wide_int &w3,
+ const wi_range &vr0)
{
+ signop sign = vr0.sign;
/* Order pairs w0,w1 and w2,w3. */
if (wi::gt_p (w0, w1, sign))
std::swap (w0, w1);
@@ -130,60 +125,55 @@ wide_int_range_min_max (wide_int &min, wide_int &max,
std::swap (w2, w3);
/* Choose min and max from the ordered pairs. */
- min = wi::min (w0, w2, sign);
- max = wi::max (w1, w3, sign);
+ res.set (vr0, wi::min (w0, w2, sign), wi::max (w1, w3, sign));
}
/* Calculate the cross product of two sets of ranges (VR0 and VR1) and
- store the result in [RES_LB, RES_UB].
-
- CODE is the operation to perform with sign SIGN.
-
- OVERFLOW_UNDEFINED is set if overflow is undefined for the operation type.
+ store the result in RES.
Return TRUE if we were able to calculate the cross product. */
bool
-wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
- enum tree_code code, signop sign,
- const wide_int &vr0_lb, const wide_int &vr0_ub,
- const wide_int &vr1_lb, const wide_int &vr1_ub,
- bool overflow_undefined)
+wi_range_cross_product (wi_range &res,
+ enum tree_code code,
+ const wi_range &vr0, const wi_range &vr1)
{
+ bool overflow_undefined = vr0.overflow_undefined;
+ signop sign = vr0.sign;
wide_int cp1, cp2, cp3, cp4;
/* Compute the 4 cross operations, bailing if we get an overflow we
can't handle. */
- if (!wide_int_binop_overflow (cp1, code, vr0_lb, vr1_lb, sign,
+ if (!wide_int_binop_overflow (cp1, code, vr0.min, vr1.min, sign,
overflow_undefined))
return false;
- if (wi::eq_p (vr0_lb, vr0_ub))
+ if (wi::eq_p (vr0.min, vr0.max))
cp3 = cp1;
- else if (!wide_int_binop_overflow (cp3, code, vr0_ub, vr1_lb, sign,
+ else if (!wide_int_binop_overflow (cp3, code, vr0.max, vr1.min, sign,
overflow_undefined))
return false;
- if (wi::eq_p (vr1_lb, vr1_ub))
+ if (wi::eq_p (vr1.min, vr1.max))
cp2 = cp1;
- else if (!wide_int_binop_overflow (cp2, code, vr0_lb, vr1_ub, sign,
- overflow_undefined))
+ else if (!wide_int_binop_overflow (cp2, code, vr0.min, vr1.max,
+ sign, overflow_undefined))
return false;
- if (wi::eq_p (vr0_lb, vr0_ub))
+ if (wi::eq_p (vr0.min, vr0.max))
cp4 = cp2;
- else if (!wide_int_binop_overflow (cp4, code, vr0_ub, vr1_ub, sign,
+ else if (!wide_int_binop_overflow (cp4, code, vr0.max, vr1.max, sign,
overflow_undefined))
return false;
- wide_int_range_min_max (res_lb, res_ub, cp1, cp2, cp3, cp4, sign);
+ wi_range_min_max (res, cp1, cp2, cp3, cp4, vr0);
return true;
}
/* Multiply two ranges when TYPE_OVERFLOW_WRAPS:
- [RES_LB, RES_UB] = [MIN0, MAX0] * [MIN1, MAX1]
+ RES = VR0 * VR1
This is basically fancy code so we don't drop to varying with an
unsigned [-3,-1]*[-3,-1].
@@ -191,24 +181,20 @@ wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
Return TRUE if we were able to perform the operation. */
bool
-wide_int_range_mult_wrapping (wide_int &res_lb,
- wide_int &res_ub,
- signop sign,
- unsigned prec,
- const wide_int &min0_,
- const wide_int &max0_,
- const wide_int &min1_,
- const wide_int &max1_)
+wi_range_mult_wrapping (wi_range &res,
+ const wi_range &vr0, const wi_range &vr1)
{
+ signop sign = vr0.sign;
+ unsigned prec = vr0.precision;
/* This test requires 2*prec bits if both operands are signed and
2*prec + 2 bits if either is not. Therefore, extend the values
using the sign of the result to PREC2. From here on out,
everthing is just signed math no matter what the input types
were. */
- widest2_int min0 = widest2_int::from (min0_, sign);
- widest2_int max0 = widest2_int::from (max0_, sign);
- widest2_int min1 = widest2_int::from (min1_, sign);
- widest2_int max1 = widest2_int::from (max1_, sign);
+ widest2_int min0 = widest2_int::from (vr0.min, sign);
+ widest2_int max0 = widest2_int::from (vr0.max, sign);
+ widest2_int min1 = widest2_int::from (vr1.min, sign);
+ widest2_int max1 = widest2_int::from (vr1.max, sign);
widest2_int sizem1 = wi::mask <widest2_int> (prec, false);
widest2_int size = sizem1 + 1;
@@ -255,14 +241,15 @@ wide_int_range_mult_wrapping (wide_int &res_lb,
/* The range covers all values. */
return false;
- res_lb = wide_int::from (prod0, prec, sign);
- res_ub = wide_int::from (prod3, prec, sign);
+ res = vr0;
+ res.min = wide_int::from (prod0, prec, sign);
+ res.max = wide_int::from (prod3, prec, sign);
return true;
}
/* Perform multiplicative operation CODE on two ranges:
- [RES_LB, RES_UB] = [VR0_LB, VR0_UB] .CODE. [VR1_LB, VR1_LB]
+ RES = VR0 .CODE. VR1
Return TRUE if we were able to perform the operation.
@@ -271,16 +258,8 @@ wide_int_range_mult_wrapping (wide_int &res_lb,
may be swapped. */
bool
-wide_int_range_multiplicative_op (wide_int &res_lb, wide_int &res_ub,
- enum tree_code code,
- signop sign,
- unsigned prec,
- const wide_int &vr0_lb,
- const wide_int &vr0_ub,
- const wide_int &vr1_lb,
- const wide_int &vr1_ub,
- bool overflow_undefined,
- bool overflow_wraps)
+wi_range_multiplicative_op (wi_range &res, enum tree_code code,
+ const wi_range &vr0, const wi_range &vr1)
{
/* Multiplications, divisions and shifts are a bit tricky to handle,
depending on the mix of signs we have in the two ranges, we
@@ -294,19 +273,15 @@ wide_int_range_multiplicative_op (wide_int &res_lb, wide_int &res_ub,
(MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
MAX1) and then figure the smallest and largest values to form
the new range. */
- if (code == MULT_EXPR && overflow_wraps)
- return wide_int_range_mult_wrapping (res_lb, res_ub,
- sign, prec,
- vr0_lb, vr0_ub, vr1_lb, vr1_ub);
- return wide_int_range_cross_product (res_lb, res_ub,
- code, sign,
- vr0_lb, vr0_ub, vr1_lb, vr1_ub,
- overflow_undefined);
+ /* ?? Document that overflow wraps comes from vr1. */
+ if (code == MULT_EXPR && vr1.overflow_wraps)
+ return wi_range_mult_wrapping (res, vr0, vr1);
+ return wi_range_cross_product (res, code, vr0, vr1);
}
/* Perform a left shift operation on two ranges:
- [RES_LB, RES_UB] = [VR0_LB, VR0_UB] << [VR1_LB, VR1_LB]
+ RES = VR0 << VR1
Return TRUE if we were able to perform the operation.
@@ -314,28 +289,27 @@ wide_int_range_multiplicative_op (wide_int &res_lb, wide_int &res_ub,
because its contents components may be swapped. */
bool
-wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
- signop sign, unsigned prec,
- const wide_int &vr0_lb, const wide_int &vr0_ub,
- const wide_int &vr1_lb, const wide_int &vr1_ub,
- bool overflow_undefined, bool overflow_wraps)
+wi_range_lshift (wi_range &res, const wi_range &vr0, const wi_range &vr1)
{
+ unsigned prec = vr0.precision;
+ signop sign = vr0.sign;
+
/* Transform left shifts by constants into multiplies. */
- if (wi::eq_p (vr1_lb, vr1_ub))
+ if (wi::eq_p (vr1.min, vr1.max))
{
- int shift = wi::extract_uhwi (vr1_ub, 0, vr1_ub.get_precision ());
- wide_int tmp = wi::set_bit_in_zero (shift, prec);
- return wide_int_range_multiplicative_op (res_lb, res_ub,
- MULT_EXPR, sign, prec,
- vr0_lb, vr0_ub, tmp, tmp,
- overflow_undefined,
- /*overflow_wraps=*/true);
+ int shift = wi::extract_uhwi (vr1.max, 0, vr1.min.get_precision ());
+ wide_int tmp = wi::set_bit_in_zero (shift, vr0.precision);
+ wi_range tmp_range = vr0;
+ tmp_range.min = tmp;
+ tmp_range.max = tmp;
+ tmp_range.overflow_wraps = true;
+ return wi_range_multiplicative_op (res, MULT_EXPR, vr0, tmp_range);
}
int overflow_pos = prec;
if (sign == SIGNED)
overflow_pos -= 1;
- int bound_shift = overflow_pos - vr1_ub.to_shwi ();
+ int bound_shift = overflow_pos - vr1.max.to_shwi ();
/* If bound_shift == HOST_BITS_PER_WIDE_INT, the llshift can
overflow. However, for that to happen, vr1.max needs to be
zero, which means vr1 is a singleton range of zero, which
@@ -349,14 +323,14 @@ wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
{
low_bound = bound;
high_bound = complement;
- if (wi::ltu_p (vr0_ub, low_bound))
+ if (wi::ltu_p (vr0.max, low_bound))
{
/* [5, 6] << [1, 2] == [10, 24]. */
/* We're shifting out only zeroes, the value increases
monotonically. */
in_bounds = true;
}
- else if (wi::ltu_p (high_bound, vr0_lb))
+ else if (wi::ltu_p (high_bound, vr0.min))
{
/* [0xffffff00, 0xffffffff] << [1, 2]
== [0xfffffc00, 0xfffffffe]. */
@@ -370,8 +344,8 @@ wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
/* [-1, 1] << [1, 2] == [-4, 4]. */
low_bound = complement;
high_bound = bound;
- if (wi::lts_p (vr0_ub, high_bound)
- && wi::lts_p (low_bound, vr0_lb))
+ if (wi::lts_p (vr0.max, high_bound)
+ && wi::lts_p (low_bound, vr0.min))
{
/* For non-negative numbers, we're shifting out only
zeroes, the value increases monotonically.
@@ -381,12 +355,7 @@ wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
}
}
if (in_bounds)
- return wide_int_range_multiplicative_op (res_lb, res_ub,
- LSHIFT_EXPR, sign, prec,
- vr0_lb, vr0_ub,
- vr1_lb, vr1_ub,
- overflow_undefined,
- overflow_wraps);
+ return wi_range_multiplicative_op (res, LSHIFT_EXPR, vr0, vr1);
return false;
}
@@ -402,9 +371,9 @@ wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
It is up to the caller to perform the actual folding above. */
bool
-wide_int_range_can_optimize_bit_op (tree_code code,
- const wide_int &lb, const wide_int &ub,
- const wide_int &mask)
+wi_range_can_optimize_bit_op (tree_code code,
+ const wide_int &lb, const wide_int &ub,
+ const wide_int &mask)
{
if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR)
@@ -441,167 +410,157 @@ wide_int_range_can_optimize_bit_op (tree_code code,
return false;
}
-/* Calculate the XOR of two ranges and store the result in [WMIN,WMAX].
- The two input ranges are described by their MUST_BE_NONZERO and
- MAY_BE_NONZERO bit masks.
+/* Calculate the XOR of two ranges and store the result in RES. The
+ two input ranges are described by their MUST_BE and MAY_BE nonzero
+ bit masks.
Return TRUE if we were able to successfully calculate the new range. */
bool
-wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1)
+wi_range_bit_xor (wi_range &res,
+ const wi_range &vr0,
+ const wi_range &vr1 ATTRIBUTE_UNUSED,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1)
{
- wide_int result_zero_bits = ((must_be_nonzero0 & must_be_nonzero1)
- | ~(may_be_nonzero0 | may_be_nonzero1));
+ unsigned prec = vr0.precision;
+ signop sign = vr0.sign;
+ wide_int result_zero_bits = ((nz0.must_be & nz1.must_be)
+ | ~(nz0.may_be | nz1.may_be));
wide_int result_one_bits
- = (wi::bit_and_not (must_be_nonzero0, may_be_nonzero1)
- | wi::bit_and_not (must_be_nonzero1, may_be_nonzero0));
- wmax = ~result_zero_bits;
- wmin = result_one_bits;
+ = (wi::bit_and_not (nz0.must_be, nz1.may_be)
+ | wi::bit_and_not (nz1.must_be, nz0.may_be));
+ res.set (vr0, result_one_bits, ~result_zero_bits);
/* If the range has all positive or all negative values, the result
is better than VARYING. */
- if (wi::lt_p (wmin, 0, sign) || wi::ge_p (wmax, 0, sign))
+ if (wi::lt_p (res.min, 0, sign) || wi::ge_p (res.max, 0, sign))
return true;
- wmin = wi::min_value (prec, sign);
- wmax = wi::max_value (prec, sign);
+ res.min = wi::min_value (prec, sign);
+ res.max = wi::max_value (prec, sign);
return false;
}
-/* Calculate the IOR of two ranges and store the result in [WMIN,WMAX].
+/* Calculate the IOR of two ranges and store the result in RES.
Return TRUE if we were able to successfully calculate the new range. */
bool
-wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax,
- signop sign,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1)
+wi_range_bit_ior (wi_range &res,
+ const wi_range &vr0, const wi_range &vr1,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1)
{
- wmin = must_be_nonzero0 | must_be_nonzero1;
- wmax = may_be_nonzero0 | may_be_nonzero1;
+ signop sign = vr0.sign;
+ res.set (vr0, nz0.must_be | nz1.must_be, nz0.may_be | nz1.may_be);
/* If the input ranges contain only positive values we can
truncate the minimum of the result range to the maximum
of the input range minima. */
- if (wi::ge_p (vr0_min, 0, sign)
- && wi::ge_p (vr1_min, 0, sign))
+ if (wi::ge_p (vr0.min, 0, sign)
+ && wi::ge_p (vr1.min, 0, sign))
{
- wmin = wi::max (wmin, vr0_min, sign);
- wmin = wi::max (wmin, vr1_min, sign);
+ res.min = wi::max (res.min, vr0.min, sign);
+ res.min = wi::max (res.min, vr1.min, sign);
}
/* If either input range contains only negative values
we can truncate the minimum of the result range to the
respective minimum range. */
- if (wi::lt_p (vr0_max, 0, sign))
- wmin = wi::max (wmin, vr0_min, sign);
- if (wi::lt_p (vr1_max, 0, sign))
- wmin = wi::max (wmin, vr1_min, sign);
+ if (wi::lt_p (vr0.max, 0, sign))
+ res.min = wi::max (res.min, vr0.min, sign);
+ if (wi::lt_p (vr1.max, 0, sign))
+ res.min = wi::max (res.min, vr1.min, sign);
/* If the limits got swapped around, indicate error so we can adjust
the range to VARYING. */
- if (wi::gt_p (wmin, wmax,sign))
+ if (wi::gt_p (res.min, res.max, sign))
return false;
return true;
}
-/* Calculate the bitwise AND of two ranges and store the result in [WMIN,WMAX].
+/* Calculate the bitwise AND of two ranges and store the result in RES.
Return TRUE if we were able to successfully calculate the new range. */
bool
-wide_int_range_bit_and (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1)
+wi_range_bit_and (wi_range &res,
+ const wi_range &vr0, const wi_range &vr1,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1)
{
- wmin = must_be_nonzero0 & must_be_nonzero1;
- wmax = may_be_nonzero0 & may_be_nonzero1;
+ signop sign = vr0.sign;
+ res.set (vr0, nz0.must_be & nz1.must_be, nz0.may_be & nz1.may_be);
/* If both input ranges contain only negative values we can
truncate the result range maximum to the minimum of the
input range maxima. */
- if (wi::lt_p (vr0_max, 0, sign) && wi::lt_p (vr1_max, 0, sign))
+ if (wi::lt_p (vr0.max, 0, sign) && wi::lt_p (vr1.max, 0, sign))
{
- wmax = wi::min (wmax, vr0_max, sign);
- wmax = wi::min (wmax, vr1_max, sign);
+ res.max = wi::min (res.max, vr0.max, sign);
+ res.max = wi::min (res.max, vr1.max, sign);
}
/* If either input range contains only non-negative values
we can truncate the result range maximum to the respective
maximum of the input range. */
- if (wi::ge_p (vr0_min, 0, sign))
- wmax = wi::min (wmax, vr0_max, sign);
- if (wi::ge_p (vr1_min, 0, sign))
- wmax = wi::min (wmax, vr1_max, sign);
+ if (wi::ge_p (vr0.min, 0, sign))
+ res.max = wi::min (res.max, vr0.max, sign);
+ if (wi::ge_p (vr1.min, 0, sign))
+ res.max = wi::min (res.max, vr1.max, sign);
/* PR68217: In case of signed & sign-bit-CST should
result in [-INF, 0] instead of [-INF, INF]. */
- if (wi::gt_p (wmin, wmax, sign))
+ if (wi::gt_p (res.min, res.max, sign))
{
+ unsigned prec = vr0.precision;
wide_int sign_bit = wi::set_bit_in_zero (prec - 1, prec);
if (sign == SIGNED
- && ((wi::eq_p (vr0_min, vr0_max)
- && !wi::cmps (vr0_min, sign_bit))
- || (wi::eq_p (vr1_min, vr1_max)
- && !wi::cmps (vr1_min, sign_bit))))
+ && ((wi::eq_p (vr0.min, vr0.max)
+ && !wi::cmps (vr0.min, sign_bit))
+ || (wi::eq_p (vr1.min, vr1.max)
+ && !wi::cmps (vr1.min, sign_bit))))
{
- wmin = wi::min_value (prec, sign);
- wmax = wi::zero (prec);
+ res.min = wi::min_value (prec, sign);
+ res.max = wi::zero (prec);
}
}
/* If the limits got swapped around, indicate error so we can adjust
the range to VARYING. */
- if (wi::gt_p (wmin, wmax,sign))
+ if (wi::gt_p (res.min, res.max, sign))
return false;
return true;
}
-/* Calculate TRUNC_MOD_EXPR on two ranges and store the result in
- [WMIN,WMAX]. */
+/* Calculate TRUNC_MOD_EXPR on two ranges and store the result in RES.
+ Return TRUE if operation succeeded. */
-void
-wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max)
+bool
+wi_range_trunc_mod (wi_range &res, const wi_range &vr0, const wi_range &vr1)
{
wide_int tmp;
+ signop sign = vr0.sign;
+ unsigned prec = vr0.precision;
+
+ if (vr1.zero_p ())
+ return false;
+
+ /* Copy vr0'0 sign, precision, etc attributes into a fresh result. */
+ res = vr0;
/* ABS (A % B) < ABS (B) and either
0 <= A % B <= A or A <= A % B <= 0. */
- wmax = vr1_max - 1;
+ res.max = vr1.max - 1;
if (sign == SIGNED)
{
- tmp = -1 - vr1_min;
- wmax = wi::smax (wmax, tmp);
+ tmp = -1 - vr1.min;
+ res.max = wi::smax (res.max, tmp);
}
if (sign == UNSIGNED)
- wmin = wi::zero (prec);
+ res.min = wi::zero (prec);
else
{
- wmin = -wmax;
- tmp = vr0_min;
+ res.min = -res.max;
+ tmp = vr0.min;
if (wi::gts_p (tmp, 0))
tmp = wi::zero (prec);
- wmin = wi::smax (wmin, tmp);
+ res.min = wi::smax (res.min, tmp);
}
- tmp = vr0_max;
+ tmp = vr0.max;
if (sign == SIGNED && wi::neg_p (tmp))
tmp = wi::zero (prec);
- wmax = wi::min (wmax, tmp, sign);
+ res.max = wi::min (res.max, tmp, sign);
+ return true;
}
diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h
index 4421bc8aeca..987352b7d6e 100644
--- a/gcc/wide-int-range.h
+++ b/gcc/wide-int-range.h
@@ -20,86 +20,47 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_WIDE_INT_RANGE_H
#define GCC_WIDE_INT_RANGE_H
-extern bool wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub,
- enum tree_code code, signop sign,
- const wide_int &, const wide_int &,
- const wide_int &, const wide_int &,
- bool overflow_undefined);
-extern bool wide_int_range_mult_wrapping (wide_int &res_lb,
- wide_int &res_ub,
- signop sign,
- unsigned prec,
- const wide_int &min0_,
- const wide_int &max0_,
- const wide_int &min1_,
- const wide_int &max1_);
-extern bool wide_int_range_multiplicative_op (wide_int &res_lb,
- wide_int &res_ub,
- enum tree_code code,
- signop sign,
- unsigned prec,
- const wide_int &vr0_lb,
- const wide_int &vr0_ub,
- const wide_int &vr1_lb,
- const wide_int &vr1_ub,
- bool overflow_undefined,
- bool overflow_wraps);
-extern bool wide_int_range_lshift (wide_int &res_lb, wide_int &res_ub,
- signop sign, unsigned prec,
- const wide_int &, const wide_int &,
- const wide_int &, const wide_int &,
- bool overflow_undefined,
- bool overflow_wraps);
-extern void wide_int_range_set_zero_nonzero_bits (signop,
- const wide_int &lb,
- const wide_int &ub,
- wide_int &may_be_nonzero,
- wide_int &must_be_nonzero);
-extern bool wide_int_range_can_optimize_bit_op (tree_code,
- const wide_int &lb,
- const wide_int &ub,
- const wide_int &mask);
-extern bool wide_int_range_bit_xor (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1);
-extern bool wide_int_range_bit_ior (wide_int &wmin, wide_int &wmax,
- signop sign,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1);
-extern bool wide_int_range_bit_and (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max,
- const wide_int &must_be_nonzero0,
- const wide_int &may_be_nonzero0,
- const wide_int &must_be_nonzero1,
- const wide_int &may_be_nonzero1);
-extern void wide_int_range_trunc_mod (wide_int &wmin, wide_int &wmax,
- signop sign,
- unsigned prec,
- const wide_int &vr0_min,
- const wide_int &vr0_max,
- const wide_int &vr1_min,
- const wide_int &vr1_max);
+extern bool wi_range_cross_product (wi_range &res,
+ enum tree_code code,
+ const wi_range &vr0,
+ const wi_range &vr1);
+extern bool wi_range_mult_wrapping (wi_range &res,
+ const wi_range &vr0,
+ const wi_range &vr1);
+extern bool wi_range_multiplicative_op (wi_range &res,
+ enum tree_code code,
+ const wi_range &vr0,
+ const wi_range &vr1);
+extern bool wi_range_lshift (wi_range &res,
+ const wi_range &vr0, const wi_range &vr1);
+extern void wi_range_set_zero_nonzero_bits (const wi_range &r,
+ maybe_nonzero_bits *nonzero);
+extern bool wi_range_can_optimize_bit_op (tree_code,
+ const wide_int &lb,
+ const wide_int &ub,
+ const wide_int &mask);
+extern bool wi_range_bit_xor (wi_range &res,
+ const wi_range &vr0,
+ const wi_range &vr1,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1);
+extern bool wi_range_bit_ior (wi_range &res,
+ const wi_range &vr0,
+ const wi_range &vr1,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1);
+extern bool wi_range_bit_and (wi_range &res,
+ const wi_range &vr0,
+ const wi_range &vr1,
+ const maybe_nonzero_bits &nz0,
+ const maybe_nonzero_bits &nz1);
+extern bool wi_range_trunc_mod (wi_range &res,
+ const wi_range &vr0, const wi_range &vr1);
/* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */
inline bool
-wide_int_range_shift_undefined_p (signop sign, unsigned prec,
- const wide_int &min, const wide_int &max)
+wi_range_shift_undefined_p (const wi_range &shifter)
{
/* ?? Note: The original comment said this only applied to
RSHIFT_EXPR, but it was being applied to both left and right
@@ -109,7 +70,9 @@ wide_int_range_shift_undefined_p (signop sign, unsigned prec,
behavior from the shift operation. We cannot even trust
SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
shifts, and the operation at the tree level may be widened. */
- return wi::lt_p (min, 0, sign) || wi::ge_p (max, prec, sign);
+ signop sign = shifter.sign;
+ unsigned prec = shifter.precision;
+ return wi::lt_p (shifter.min, 0, sign) || wi::ge_p (shifter.max, prec, sign);
}
#endif /* GCC_WIDE_INT_RANGE_H */