commit e58c0f8b8a27fa91fe22f1f12d19f3d37cc729ae
Author: Aldy Hernandez <aldyh@redhat.com>
Date: Fri Jun 28 10:41:05 2019 +0200
Move set_value_range_with_overflow into wide-int-range.cc as
adjust_range_for_overflow.
Move the POINTER_PLUS_EXPR symbolics code into
handle_symbolics_in_pointer_plus_expr.
Move the PLUS/MINUS_EXPR handling code into extract_range_from_plus_expr.
@@ -1,3 +1,18 @@
+2019-07-01 Aldy Hernandez <aldyh@redhat.com>
+
+ * tree-vrp.h (value_range_kind): Move from here...
+ * coretypes.h (value_range_kind): ...to here.
+ * tree-vrp.c (extract_range_from_binary_expr): Abstract pointer
+ plus handling of symbolics to
+ handle_symbolics_in_pointer_plus_expr().
+ Abstract plus/minus handling code to
+ extract_range_from_plus_expr.
+ Move set_value_range_with_overflow to wide-int-range.cc.
+ (handle_symbolics_in_pointer_plus_expr): New.
+ (extract_range_from_plus_expr): New.
+ * wide-int-range.cc (adjust_range_for_overflow): New.
+ * wide-int-range.h (adjust_range_for_overflow): New.
+
2019-07-01 Aldy Hernandez <aldyh@redhat.com>
* tree-vrp.c (value_range_base::set_and_canonicalize): Rename to
@@ -202,6 +202,24 @@ enum profile_update {
PROFILE_UPDATE_PREFER_ATOMIC
};
+/* Types of ranges.
+
+ This is still prefixed with VR_*, even though it is more general
+ purpose, to avoid having to replace everything across the compiler.
+ Perhaps we should change it later. */
+enum value_range_kind {
+ /* Empty range. */
+ VR_UNDEFINED,
+ /* Range spans the entire domain. */
+ VR_VARYING,
+ /* Range is [MIN, MAX]. */
+ VR_RANGE,
+ /* Range is ~[MIN, MAX]. */
+ VR_ANTI_RANGE,
+ /* Range is a nice guy. */
+ VR_LAST
+};
+
/* Types of unwind/exception handling info that can be generated. */
enum unwind_info_type
@@ -1470,112 +1470,196 @@ combine_bound (enum tree_code code, wide_int &wi, wi::overflow_type &ovf,
wi = wi::shwi (0, prec);
}
-/* Given a range in [WMIN, WMAX], adjust it for possible overflow and
- put the result in VR.
+/* Fold two value range's of a POINTER_PLUS_EXPR into VR. Return TRUE
+ if successful. */
- TYPE is the type of the range.
+static bool
+handle_symbolics_in_pointer_plus_expr (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type,
+ const value_range_base *vr0,
+ const value_range_base *vr1)
+{
+ if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR)
+ {
+ /* For pointer types, we are really only interested in asserting
+ whether the expression evaluates to non-NULL.
+ With -fno-delete-null-pointer-checks we need to be more
+ conservative. As some object might reside at address 0,
+ then some offset could be added to it and the same offset
+ subtracted again and the result would be NULL.
+ E.g.
+ static int a[12]; where &a[0] is NULL and
+ ptr = &a[6];
+ ptr -= 6;
+ ptr will be NULL here, even when there is POINTER_PLUS_EXPR
+ where the first range doesn't include zero and the second one
+ doesn't either. As the second operand is sizetype (unsigned),
+ consider all ranges where the MSB could be set as possible
+ subtractions where the result might be NULL. */
+ if ((!range_includes_zero_p (vr0)
+ || !range_includes_zero_p (vr1))
+ && !TYPE_OVERFLOW_WRAPS (expr_type)
+ && (flag_delete_null_pointer_checks
+ || (range_int_cst_p (vr1)
+ && !tree_int_cst_sign_bit (vr1->max ()))))
+ vr->set_nonzero (expr_type);
+ else if (vr0->zero_p () && vr1->zero_p ())
+ vr->set_zero (expr_type);
+ else
+ vr->set_varying (expr_type);
+ return true;
+ }
+ return false;
+}
- MIN_OVF and MAX_OVF indicate what type of overflow, if any,
- occurred while originally calculating WMIN or WMAX. -1 indicates
- underflow. +1 indicates overflow. 0 indicates neither. */
+/* Extract range information from a PLUS_EXPR or MINUS_EXPR based on
+ the ranges of each of its operands *VR0 and *VR1 with resulting
+ type EXPR_TYPE. The resulting range is stored in *VR. */
static void
-set_value_range_with_overflow (value_range_kind &kind, tree &min, tree &max,
- tree type,
- const wide_int &wmin, const wide_int &wmax,
- wi::overflow_type min_ovf,
- wi::overflow_type max_ovf)
+extract_range_from_plus_expr (value_range_base *vr,
+ enum tree_code code, tree expr_type,
+ const value_range_base *vr0,
+ const value_range_base *vr1)
{
- const signop sgn = TYPE_SIGN (type);
- const unsigned int prec = TYPE_PRECISION (type);
-
- /* For one bit precision if max < min, then the swapped
- range covers all values. */
- if (prec == 1 && wi::lt_p (wmax, wmin, sgn))
+ gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR);
+ enum value_range_kind type;
+ tree min = NULL, max = NULL;
+ value_range_kind vr0_kind = vr0->kind (), vr1_kind = vr1->kind ();
+ tree vr0_min = vr0->min (), vr0_max = vr0->max ();
+ tree vr1_min = vr1->min (), vr1_max = vr1->max ();
+ /* This will normalize things such that calculating
+ [0,0] - VR_VARYING is not dropped to varying, but is
+ calculated as [MIN+1, MAX]. */
+ if (vr0->varying_p ())
{
- kind = VR_VARYING;
- return;
+ vr0_kind = VR_RANGE;
+ vr0_min = vrp_val_min (expr_type);
+ vr0_max = vrp_val_max (expr_type);
}
-
- if (TYPE_OVERFLOW_WRAPS (type))
+ if (vr1->varying_p ())
{
- /* If overflow wraps, truncate the values and adjust the
- range kind and bounds appropriately. */
- wide_int tmin = wide_int::from (wmin, prec, sgn);
- wide_int tmax = wide_int::from (wmax, prec, sgn);
- if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
+ vr1_kind = VR_RANGE;
+ vr1_min = vrp_val_min (expr_type);
+ vr1_max = vrp_val_max (expr_type);
+ }
+ const bool minus_p = (code == MINUS_EXPR);
+ tree min_op0 = vr0_min;
+ tree min_op1 = minus_p ? vr1_max : vr1_min;
+ tree max_op0 = vr0_max;
+ tree max_op1 = minus_p ? vr1_min : vr1_max;
+ tree sym_min_op0 = NULL_TREE;
+ tree sym_min_op1 = NULL_TREE;
+ tree sym_max_op0 = NULL_TREE;
+ tree sym_max_op1 = NULL_TREE;
+ bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1;
+
+ neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false;
+
+ /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or
+ single-symbolic ranges, try to compute the precise resulting range,
+ but only if we know that this resulting range will also be constant
+ or single-symbolic. */
+ if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE
+ && (TREE_CODE (min_op0) == INTEGER_CST
+ || (sym_min_op0
+ = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
+ && (TREE_CODE (min_op1) == INTEGER_CST
+ || (sym_min_op1
+ = get_single_symbol (min_op1, &neg_min_op1, &min_op1)))
+ && (!(sym_min_op0 && sym_min_op1)
+ || (sym_min_op0 == sym_min_op1
+ && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1)))
+ && (TREE_CODE (max_op0) == INTEGER_CST
+ || (sym_max_op0
+ = get_single_symbol (max_op0, &neg_max_op0, &max_op0)))
+ && (TREE_CODE (max_op1) == INTEGER_CST
+ || (sym_max_op1
+ = get_single_symbol (max_op1, &neg_max_op1, &max_op1)))
+ && (!(sym_max_op0 && sym_max_op1)
+ || (sym_max_op0 == sym_max_op1
+ && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1))))
+ {
+ wide_int wmin, wmax;
+ wi::overflow_type min_ovf = wi::OVF_NONE;
+ wi::overflow_type max_ovf = wi::OVF_NONE;
+
+ /* Build the bounds. */
+ combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1);
+ combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1);
+
+ /* If we have overflow for the constant part and the resulting
+ range will be symbolic, drop to VR_VARYING. */
+ if (((bool)min_ovf && sym_min_op0 != sym_min_op1)
+ || ((bool)max_ovf && sym_max_op0 != sym_max_op1))
{
- /* If the limits are swapped, we wrapped around and cover
- the entire range. We have a similar check at the end of
- extract_range_from_binary_expr. */
- if (wi::gt_p (tmin, tmax, sgn))
- kind = VR_VARYING;
- else
- {
- kind = VR_RANGE;
- /* No overflow or both overflow or underflow. The
- range kind stays VR_RANGE. */
- min = wide_int_to_tree (type, tmin);
- max = wide_int_to_tree (type, tmax);
- }
+ vr->set_varying (expr_type);
return;
}
- else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
- || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
+
+ adjust_range_for_overflow (type, wmin, wmax, expr_type,
+ min_ovf, max_ovf,
+ TYPE_OVERFLOW_WRAPS (expr_type));
+ if (type == VR_VARYING)
{
- /* Min underflow or max overflow. The range kind
- changes to VR_ANTI_RANGE. */
- bool covers = false;
- wide_int tem = tmin;
- tmin = tmax + 1;
- if (wi::cmp (tmin, tmax, sgn) < 0)
- covers = true;
- tmax = tem - 1;
- if (wi::cmp (tmax, tem, sgn) > 0)
- covers = true;
- /* If the anti-range would cover nothing, drop to varying.
- Likewise if the anti-range bounds are outside of the
- types values. */
- if (covers || wi::cmp (tmin, tmax, sgn) > 0)
- {
- kind = VR_VARYING;
- return;
- }
- kind = VR_ANTI_RANGE;
- min = wide_int_to_tree (type, tmin);
- max = wide_int_to_tree (type, tmax);
+ vr->set_varying (expr_type);
return;
}
- else
+ gcc_assert (type != VR_UNDEFINED);
+ min = wide_int_to_tree (expr_type, wmin);
+ max = wide_int_to_tree (expr_type, wmax);
+
+ /* Build the symbolic bounds if needed. */
+ adjust_symbolic_bound (min, code, expr_type,
+ sym_min_op0, sym_min_op1,
+ neg_min_op0, neg_min_op1);
+ adjust_symbolic_bound (max, code, expr_type,
+ sym_max_op0, sym_max_op1,
+ neg_max_op0, neg_max_op1);
+
+ /* If either MIN or MAX overflowed, then set the resulting range to
+ VARYING. */
+ if (min == NULL_TREE
+ || TREE_OVERFLOW_P (min)
+ || max == NULL_TREE
+ || TREE_OVERFLOW_P (max))
{
- /* Other underflow and/or overflow, drop to VR_VARYING. */
- kind = VR_VARYING;
+ vr->set_varying (expr_type);
return;
}
+
+ int cmp = compare_values (min, max);
+ if (cmp == -2 || cmp == 1)
+ {
+ /* If the new range has its limits swapped around (MIN > MAX),
+ then the operation caused one of them to wrap around, mark
+ the new range VARYING. */
+ vr->set_varying (expr_type);
+ }
+ else
+ vr->set (type, min, max);
+ return;
}
else
{
- /* If overflow does not wrap, saturate to the types min/max
- value. */
- wide_int type_min = wi::min_value (prec, sgn);
- wide_int type_max = wi::max_value (prec, sgn);
- kind = VR_RANGE;
- if (min_ovf == wi::OVF_UNDERFLOW)
- min = wide_int_to_tree (type, type_min);
- else if (min_ovf == wi::OVF_OVERFLOW)
- min = wide_int_to_tree (type, type_max);
- else
- min = wide_int_to_tree (type, wmin);
-
- if (max_ovf == wi::OVF_UNDERFLOW)
- max = wide_int_to_tree (type, type_min);
- else if (max_ovf == wi::OVF_OVERFLOW)
- max = wide_int_to_tree (type, type_max);
- else
- max = wide_int_to_tree (type, wmax);
+ /* For other cases, for example if we have a PLUS_EXPR with two
+ VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort
+ to compute a precise range for such a case.
+ ??? General even mixed range kind operations can be expressed
+ by for example transforming ~[3, 5] + [1, 2] to range-only
+ operations and a union primitive:
+ [-INF, 2] + [1, 2] U [5, +INF] + [1, 2]
+ [-INF+1, 4] U [6, +INF(OVF)]
+ though usually the union is not exactly representable with
+ a single range or anti-range as the above is
+ [-INF+1, +INF(OVF)] intersected with ~[5, 5]
+ but one could use a scheme similar to equivalences for this. */
+ vr->set_varying (expr_type);
}
}
+
/* Extract range information from a binary operation CODE based on
the ranges of each of its operands *VR0 and *VR1 with resulting
type EXPR_TYPE. The resulting range is stored in *VR. */
@@ -1731,34 +1815,7 @@ extract_range_from_binary_expr (value_range_base *vr,
vr->set_varying (expr_type);
}
else if (code == POINTER_PLUS_EXPR)
- {
- /* For pointer types, we are really only interested in asserting
- whether the expression evaluates to non-NULL.
- With -fno-delete-null-pointer-checks we need to be more
- conservative. As some object might reside at address 0,
- then some offset could be added to it and the same offset
- subtracted again and the result would be NULL.
- E.g.
- static int a[12]; where &a[0] is NULL and
- ptr = &a[6];
- ptr -= 6;
- ptr will be NULL here, even when there is POINTER_PLUS_EXPR
- where the first range doesn't include zero and the second one
- doesn't either. As the second operand is sizetype (unsigned),
- consider all ranges where the MSB could be set as possible
- subtractions where the result might be NULL. */
- if ((!range_includes_zero_p (&vr0)
- || !range_includes_zero_p (&vr1))
- && !TYPE_OVERFLOW_WRAPS (expr_type)
- && (flag_delete_null_pointer_checks
- || (range_int_cst_p (&vr1)
- && !tree_int_cst_sign_bit (vr1.max ()))))
- vr->set_nonzero (expr_type);
- else if (vr0.zero_p () && vr1.zero_p ())
- vr->set_zero (expr_type);
- else
- vr->set_varying (expr_type);
- }
+ handle_symbolics_in_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1);
else if (code == BIT_AND_EXPR)
{
/* For pointer types, we are really only interested in asserting
@@ -1780,115 +1837,8 @@ extract_range_from_binary_expr (value_range_base *vr,
range and see what we end up with. */
if (code == PLUS_EXPR || code == MINUS_EXPR)
{
- value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind ();
- tree vr0_min = vr0.min (), vr0_max = vr0.max ();
- tree vr1_min = vr1.min (), vr1_max = vr1.max ();
- /* This will normalize things such that calculating
- [0,0] - VR_VARYING is not dropped to varying, but is
- calculated as [MIN+1, MAX]. */
- if (vr0.varying_p ())
- {
- vr0_kind = VR_RANGE;
- vr0_min = vrp_val_min (expr_type);
- vr0_max = vrp_val_max (expr_type);
- }
- if (vr1.varying_p ())
- {
- vr1_kind = VR_RANGE;
- vr1_min = vrp_val_min (expr_type);
- vr1_max = vrp_val_max (expr_type);
- }
-
- const bool minus_p = (code == MINUS_EXPR);
- tree min_op0 = vr0_min;
- tree min_op1 = minus_p ? vr1_max : vr1_min;
- tree max_op0 = vr0_max;
- tree max_op1 = minus_p ? vr1_min : vr1_max;
- tree sym_min_op0 = NULL_TREE;
- tree sym_min_op1 = NULL_TREE;
- tree sym_max_op0 = NULL_TREE;
- tree sym_max_op1 = NULL_TREE;
- bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1;
-
- neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false;
-
- /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or
- single-symbolic ranges, try to compute the precise resulting range,
- but only if we know that this resulting range will also be constant
- or single-symbolic. */
- if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE
- && (TREE_CODE (min_op0) == INTEGER_CST
- || (sym_min_op0
- = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
- && (TREE_CODE (min_op1) == INTEGER_CST
- || (sym_min_op1
- = get_single_symbol (min_op1, &neg_min_op1, &min_op1)))
- && (!(sym_min_op0 && sym_min_op1)
- || (sym_min_op0 == sym_min_op1
- && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1)))
- && (TREE_CODE (max_op0) == INTEGER_CST
- || (sym_max_op0
- = get_single_symbol (max_op0, &neg_max_op0, &max_op0)))
- && (TREE_CODE (max_op1) == INTEGER_CST
- || (sym_max_op1
- = get_single_symbol (max_op1, &neg_max_op1, &max_op1)))
- && (!(sym_max_op0 && sym_max_op1)
- || (sym_max_op0 == sym_max_op1
- && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1))))
- {
- wide_int wmin, wmax;
- wi::overflow_type min_ovf = wi::OVF_NONE;
- wi::overflow_type max_ovf = wi::OVF_NONE;
-
- /* Build the bounds. */
- combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1);
- combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1);
-
- /* If we have overflow for the constant part and the resulting
- range will be symbolic, drop to VR_VARYING. */
- if (((bool)min_ovf && sym_min_op0 != sym_min_op1)
- || ((bool)max_ovf && sym_max_op0 != sym_max_op1))
- {
- vr->set_varying (expr_type);
- return;
- }
-
- /* Adjust the range for possible overflow. */
- min = NULL_TREE;
- max = NULL_TREE;
- set_value_range_with_overflow (type, min, max, expr_type,
- wmin, wmax, min_ovf, max_ovf);
- if (type == VR_VARYING)
- {
- vr->set_varying (expr_type);
- return;
- }
-
- /* Build the symbolic bounds if needed. */
- adjust_symbolic_bound (min, code, expr_type,
- sym_min_op0, sym_min_op1,
- neg_min_op0, neg_min_op1);
- adjust_symbolic_bound (max, code, expr_type,
- sym_max_op0, sym_max_op1,
- neg_max_op0, neg_max_op1);
- }
- else
- {
- /* For other cases, for example if we have a PLUS_EXPR with two
- VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort
- to compute a precise range for such a case.
- ??? General even mixed range kind operations can be expressed
- by for example transforming ~[3, 5] + [1, 2] to range-only
- operations and a union primitive:
- [-INF, 2] + [1, 2] U [5, +INF] + [1, 2]
- [-INF+1, 4] U [6, +INF(OVF)]
- though usually the union is not exactly representable with
- a single range or anti-range as the above is
- [-INF+1, +INF(OVF)] intersected with ~[5, 5]
- but one could use a scheme similar to equivalences for this. */
- vr->set_varying (expr_type);
- return;
- }
+ extract_range_from_plus_expr (vr, code, expr_type, &vr0, &vr1);
+ return;
}
else if (code == MIN_EXPR
|| code == MAX_EXPR)
@@ -20,22 +20,6 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_TREE_VRP_H
#define GCC_TREE_VRP_H
-/* Types of value ranges. */
-enum value_range_kind
-{
- /* Empty range. */
- VR_UNDEFINED,
- /* Range spans the entire domain. */
- VR_VARYING,
- /* Range is [MIN, MAX]. */
- VR_RANGE,
- /* Range is ~[MIN, MAX]. */
- VR_ANTI_RANGE,
- /* Range is a nice guy. */
- VR_LAST
-};
-
-
/* Range of values that can be associated with an SSA_NAME after VRP
has executed. */
class GTY((for_user)) value_range_base
@@ -863,3 +863,105 @@ wide_int_range_div (wide_int &wmin, wide_int &wmax,
extra_range_p = false;
return true;
}
+
+/* Adjust the range in [WMIN, WMAX] for possible overflow and store the
+ parts of the resulting range in KIND, WMIN, WMAX.
+
+ TYPE is the type of the range.
+
+ MIN_OVF and MAX_OVF indicate what type of overflow, if any,
+ occurred while originally calculating WMIN or WMAX. */
+
+void
+adjust_range_for_overflow (value_range_kind &kind,
+ wide_int &wmin, wide_int &wmax,
+ tree type,
+ wi::overflow_type min_ovf,
+ wi::overflow_type max_ovf,
+ bool overflow_wraps)
+{
+ const signop sgn = TYPE_SIGN (type);
+ const unsigned int prec = TYPE_PRECISION (type);
+
+ /* For one bit precision if max < min, then the swapped
+ range covers all values. */
+ if (prec == 1 && wi::lt_p (wmax, wmin, sgn))
+ {
+ kind = VR_VARYING;
+ return;
+ }
+
+ if (overflow_wraps)
+ {
+ /* If overflow wraps, truncate the values and adjust the
+ range kind and bounds appropriately. */
+ wide_int tmin = wide_int::from (wmin, prec, sgn);
+ wide_int tmax = wide_int::from (wmax, prec, sgn);
+ if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
+ {
+ /* If the limits are swapped, we wrapped around and cover
+ the entire range. We have a similar check at the end of
+ extract_range_from_binary_expr. */
+ if (wi::gt_p (tmin, tmax, sgn))
+ kind = VR_VARYING;
+ else
+ {
+ kind = VR_RANGE;
+ /* No overflow or both overflow or underflow. The
+ range kind stays VR_RANGE. */
+ wmin = tmin;
+ wmax = tmax;
+ }
+ return;
+ }
+ else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
+ || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
+ {
+ /* Min underflow or max overflow. The range kind
+ changes to VR_ANTI_RANGE. */
+ bool covers = false;
+ wide_int tem = tmin;
+ tmin = tmax + 1;
+ if (wi::cmp (tmin, tmax, sgn) < 0)
+ covers = true;
+ tmax = tem - 1;
+ if (wi::cmp (tmax, tem, sgn) > 0)
+ covers = true;
+ /* If the anti-range would cover nothing, drop to varying.
+ Likewise if the anti-range bounds are outside of the
+ types values. */
+ if (covers || wi::cmp (tmin, tmax, sgn) > 0)
+ {
+ kind = VR_VARYING;
+ return;
+ }
+ kind = VR_ANTI_RANGE;
+ wmin = tmin;
+ wmax = tmax;
+ return;
+ }
+ else
+ {
+ /* Other underflow and/or overflow, drop to VR_VARYING. */
+ kind = VR_VARYING;
+ return;
+ }
+ }
+ else
+ {
+ /* If overflow does not wrap, saturate to the types min/max
+ value. */
+ wide_int type_min = wi::min_value (prec, sgn);
+ wide_int type_max = wi::max_value (prec, sgn);
+ kind = VR_RANGE;
+ if (min_ovf == wi::OVF_UNDERFLOW)
+ wmin = type_min;
+ else if (min_ovf == wi::OVF_OVERFLOW)
+ wmin = type_max;
+
+ if (max_ovf == wi::OVF_UNDERFLOW)
+ wmax = type_min;
+ else if (max_ovf == wi::OVF_OVERFLOW)
+ wmax = type_max;
+ }
+}
@@ -185,4 +185,11 @@ wide_int_range_zero_p (const wide_int &wmin, const wide_int &wmax,
return wmin == wmax && wi::eq_p (wmin, wi::zero (prec));
}
+void
+adjust_range_for_overflow (value_range_kind &,
+ wide_int &, wide_int &,
+ tree type,
+ wi::overflow_type, wi::overflow_type,
+ bool overflow_wraps);
+
#endif /* GCC_WIDE_INT_RANGE_H */