wi = wi::shwi (0, prec);
}
-/* Given a range in [WMIN, WMAX], adjust it for possible overflow and
- put the result in VR.
-
- 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. -1 indicates
- underflow. +1 indicates overflow. 0 indicates neither. */
+/* Fold two value range's of a POINTER_PLUS_EXPR into VR. Return TRUE
+ if successful. */
-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)
+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)
++extract_range_from_pointer_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))
- {
- kind = VR_VARYING;
- return;
- }
-
- if (TYPE_OVERFLOW_WRAPS (type))
- {
- /* 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. */
- min = wide_int_to_tree (type, tmin);
- max = wide_int_to_tree (type, 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;
- min = wide_int_to_tree (type, tmin);
- max = wide_int_to_tree (type, tmax);
- return;
- }
+ 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
- {
- /* 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)
- 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);
+ vr->set_varying (expr_type);
+ return true;
}
+ return false;
}
- /* 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
- 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)
- {
- 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 ())
- {
- 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_range_for_overflow (type, wmin, wmax, expr_type,
- min_ovf, max_ovf,
- TYPE_OVERFLOW_WRAPS (expr_type));
- if (type == VR_VARYING)
- {
- vr->set_varying (expr_type);
- return;
- }
- 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))
- {
- 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
- {
- /* 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. */
vr->set_varying (expr_type);
}
else if (code == POINTER_PLUS_EXPR)
- handle_symbolics_in_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1);
- {
- /* 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);
- }
++ extract_range_from_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
range and see what we end up with. */
if (code == PLUS_EXPR || code == MINUS_EXPR)
{
- extract_range_from_plus_expr (vr, code, expr_type, &vr0, &vr1);
- return;
+ 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);
++ adjust_range_for_overflow (type, wmin, wmax, expr_type,
++ min_ovf, max_ovf,
++ TYPE_OVERFLOW_WRAPS (expr_type));
+ if (type == VR_VARYING)
+ {
+ vr->set_varying (expr_type);
+ return;
+ }
++ 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);
+ }
+ 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;
+ }
}
else if (code == MIN_EXPR
|| code == MAX_EXPR)
return;
}
- if (handle_symbolics_in_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1))
+/* Given two ranges (OLD_VR and NEW_VR) that are the result of
+ VR0 .OPCODE. VR1, abort if they are not equivalent. */
+
+void
+assert_compare_value_ranges (const value_range_base *old_vr,
+ const value_range_base *new_vr,
+ tree_code code,
+ const value_range_base *vr0,
+ const value_range_base *vr1)
+{
+ if (old_vr->equal_p (*new_vr))
+ return;
+
+ /* Now account for any known differences between range-ops and
+ extract_range_from_*expr. If we can't account for the difference
+ between the ranges, fail vewwy woughly. */
+
+ /* Ideally, unsigned [1, MAX] should've been canonicalized as
+ ~[0, 0], but this causes issues with ranges_from_anti_range.
+ Special case this for now, and avoid batting the beehive. */
+ if (TYPE_UNSIGNED (old_vr->type ())
+ && integer_onep (old_vr->min ())
+ && vrp_val_is_max (old_vr->max ())
+ && new_vr->nonzero_p ())
+ return;
+
+ /* extract_range_from_binary_expr special cases this scenario, and
+ gives up. Since range-ops can do better, avoid a false
+ positive. */
+ if (code == EXACT_DIV_EXPR && vr0->nonzero_p ())
+ return;
+
+ /* The ordering in which range-ops and
+ extract_range_from_binary_expr split up and handle sub-ranges
+ matters, and this can yield slightly worse results for VRP at
+ times. This is because the union of intermediate ranges,
+ depending on which order they are done in, can yield
+ unrepresentable ranges that ultimately generate a VARYING.
+
+ This is imprecise at best, so avoid comparing pairs of
+ VR_ANTI_RANGES inputs, for which VRP produces VARYING and
+ range-ops does better.
+
+ For example, extract_range_from_binary_expr, with its recursive
+ ranges_from_anti_range approach, will handle ~[5,10] OP [20,30]
+ in this order:
+
+ [0,4][11,MAX] OP [0,19][31,MAX]
+
+ t1 = [0,4] OP [0,19]
+ t2 = [0,4] OP [31,MAX]
+ t3 = union(t1, t2)
+
+ t4 = [11,MAX] OP [0,19]
+ t5 = [11,MAX] OP [31,MAX]
+ t6 = union(t4, t5)
+
+ t = union(t3, t6)
+
+ Whereas, range-ops will do:
+
+ t = union([0,4] OP [0,19])
+ t = union(t, union([0,4] OP [31,MAX]))
+ t = union(t, union([11,MAX] OP [0,19]))
+ t = union(t, union([11,MAX] OP [31,MAX]))
+
+ Ugh. In the amount of time it took to explain this, I could've
+ rewritten VRP to match range-ops, but let's avoid touching too
+ much of existing code.
+
+ Triggered by: gcc.target/i386/sse4_2-crc32b.c. */
+ if (vr0->kind () == VR_ANTI_RANGE && vr1->kind () == VR_ANTI_RANGE
+ && old_vr->varying_p ())
+ return;
+
+ /* MAX/MIN of pointers in VRP dumbs everything down to
+ NULL/NON_NULL/VARYING. When running range-ops with multiple
+ sub-ranges, we may get slightly better ranges. In this case,
+ pretend we're varying and see if we matched VRP. */
+ if ((code == MAX_EXPR || code == MIN_EXPR)
+ && POINTER_TYPE_P (new_vr->type ())
+ && !new_vr->zero_p ()
+ && !new_vr->nonzero_p ()
+ && old_vr->varying_p ())
+ return;
+
+ /* Sigh. extract_range_from_binary_expr may refuse to work on
+ varying ranges for some codes, but range-ops can sometimes derive
+ useful information. This is the same check we have in
+ extract_range_from_binary_expr. */
+ if (code != BIT_AND_EXPR
+ && code != BIT_IOR_EXPR
+ && code != TRUNC_DIV_EXPR
+ && code != FLOOR_DIV_EXPR
+ && code != CEIL_DIV_EXPR
+ && code != EXACT_DIV_EXPR
+ && code != ROUND_DIV_EXPR
+ && code != TRUNC_MOD_EXPR
+ && code != MIN_EXPR
+ && code != MAX_EXPR
+ && code != PLUS_EXPR
+ && code != MINUS_EXPR
+ && code != RSHIFT_EXPR
+ && code != POINTER_PLUS_EXPR
+ && (vr0->varying_p ()
+ || vr1->varying_p ()
+ || vr0->symbolic_p ()
+ || vr1->symbolic_p ()))
+ {
+ /* If VRP was varying, we know we did better. */
+ if (old_vr->varying_p ())
+ return;
+ }
+
+ /* There's an unaccounted difference. This may be a real bug. */
+
+ tree expr_type = old_vr->type ();
+ fprintf (stderr, "------------\n");
+ fprintf (stderr, "Ranges from VRP and range-ops do not agree!\n");
+ fprintf (stderr, "CODE: %s\n", get_tree_code_name (code));
+ fprintf (stderr, "TYPE = ");
+ debug_generic_stmt (expr_type);
+ if (CONVERT_EXPR_CODE_P (code))
+ {
+ fprintf (stderr, "\tFROM TYPE = ");
+ debug_generic_stmt (vr0->type ());
+ }
+ fprintf (stderr, "vr0: ");
+ vr0->dump (stderr);
+ fputc ('\n', stderr);
+ if (TREE_CODE_CLASS (code) != tcc_unary)
+ {
+ fprintf (stderr, "vr1: ");
+ vr1->dump (stderr);
+ fputc ('\n', stderr);
+ }
+ fprintf (stderr, "VRP returned: ");
+ old_vr->dump (stderr);
+ fprintf (stderr, "\nrange-ops returned: ");
+ new_vr->dump (stderr);
+ fputc ('\n', stderr);
+ gcc_unreachable();
+}
+
+/* Normalize a value_range for use in range_ops and return it.
+ Eventually, range-ops should do this for us. */
+
+static value_range_base
+normalize_for_range_ops (const value_range_base &vr)
+{
+ tree type = vr.type ();
+
+ /* This will return ~[0,0] for [&var, &var]. */
+ if (POINTER_TYPE_P (type) && !range_includes_zero_p (&vr))
+ {
+ value_range_base temp;
+ temp.set_nonzero (type);
+ return temp;
+ }
+ if (vr.symbolic_p ())
+ return normalize_for_range_ops (vr.normalize_symbolics ());
+ if (TREE_CODE (vr.min ()) == INTEGER_CST
+ && TREE_CODE (vr.max ()) == INTEGER_CST)
+ return vr;
+ /* Anything not strictly numeric at this point becomes varying. */
+ return value_range_base (vr.type ());
+}
+
+/* Fold a binary expression of two value_range's with range-ops. */
+
+static void
+range_ops_fold_binary_expr (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type,
+ const value_range_base *vr0_,
+ const value_range_base *vr1_)
+{
+ /* Mimic any behavior users of extract_range_from_unary_expr may
+ expect. */
+ range_operator *op = range_op_handler (code);
+ if (!op)
+ {
+ vr->set_varying (expr_type);
+ return;
+ }
+ value_range_base vr0 = *vr0_, vr1 = *vr1_;
+ if (vr0.undefined_p () && vr1.undefined_p ())
+ {
+ vr->set_undefined (expr_type);
+ return;
+ }
+ if (vr0.undefined_p ())
+ vr0.set_varying (expr_type);
+ else if (vr1.undefined_p ())
+ vr1.set_varying (expr_type);
+
+ /* Handle symbolics. Worth moving into range-ops?? */
+ if ((code == PLUS_EXPR || code == MINUS_EXPR)
+ && (vr0.symbolic_p () || vr1.symbolic_p ()))
+ {
+ /* Pass on down until we handle anti-ranges in
+ extract_range_from_plus_expr. */
+ extract_range_from_binary_expr (vr, code, expr_type, &vr0, &vr1);
+ return;
+ }
++ if (extract_range_from_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1))
+ return;
+
+ /* Do the range-ops dance. */
+ value_range_base n0 = normalize_for_range_ops (vr0);
+ value_range_base n1 = normalize_for_range_ops (vr1);
+#if USE_IRANGE
+ irange ir;
+ op->fold_range (ir, n0, n1);
+ *vr = ir;
+#else
+ op->fold_range (*vr, n0, n1);
+#endif
+}
+
+/* Fold a unary expression of a value_range with range-ops. */
+
+static void
+range_ops_fold_unary_expr (value_range_base *vr,
+ enum tree_code code, tree expr_type,
+ const value_range_base *vr0)
+{
+ /* Mimic any behavior users of extract_range_from_unary_expr may
+ expect. */
+ range_operator *op = range_op_handler (code);
+ if (!op)
+ {
+ vr->set_varying (expr_type);
+ return;
+ }
+ if (vr0->undefined_p ())
+ {
+ vr->set_undefined (expr_type);
+ return;
+ }
+
+ /* Handle symbolics. Worth moving into range-ops?? */
+ if (code == NEGATE_EXPR && vr0->symbolic_p ())
+ {
+ /* -X is simply 0 - X. */
+ value_range_base zero;
+ zero.set_zero (vr0->type ());
+ range_ops_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0);
+ return;
+ }
+ if (code == BIT_NOT_EXPR && vr0->symbolic_p ())
+ {
+ /* ~X is simply -1 - X. */
+ value_range_base minusone;
+ minusone.set (build_int_cst (vr0->type (), -1));
+ range_ops_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
+ return;
+ }
+ if (CONVERT_EXPR_CODE_P (code) && (POINTER_TYPE_P (expr_type)
+ || POINTER_TYPE_P (vr0->type ())))
+ {
+ /* This handles symbolic conversions such such as [25, x_4]. */
+ if (!range_includes_zero_p (vr0))
+ vr->set_nonzero (expr_type);
+ else if (vr0->zero_p ())
+ vr->set_zero (expr_type);
+ else
+ vr->set_varying (expr_type);
+ return;
+ }
+
+
+ /* Do the range-ops dance. */
+ value_range_base n0 = normalize_for_range_ops (*vr0);
+ value_range_base n1 (expr_type);
+#if USE_IRANGE
+ irange ir;
+ op->fold_range (ir, n0, n1);
+ *vr = ir;
+#else
+ op->fold_range (*vr, n0, n1);
+#endif
+}
+
+/* Generic folding of a binary expression between two value_ranges.
+ Uses range-ops and extract_range_from_binary_expr, and verifies
+ that the results match. */
+
+void
+range_fold_binary_expr (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type,
+ const value_range_base *vr0,
+ const value_range_base *vr1)
+{
+ if (!value_range_base::supports_type_p (expr_type)
+ || !value_range_base::supports_type_p (vr0->type ())
+ || !value_range_base::supports_type_p (vr1->type ()))
+ {
+ *vr = value_range (expr_type);
+ return;
+ }
+ if (flag_ranges_mode & RANGES_RANGE_OPS)
+ range_ops_fold_binary_expr (vr, code, expr_type, vr0, vr1);
+ if (flag_ranges_mode & RANGES_VRP)
+ {
+ value_range_base old;
+ extract_range_from_binary_expr (&old, code, expr_type, vr0, vr1);
+ if (flag_ranges_mode & RANGES_CHECKING)
+ assert_compare_value_ranges (&old, vr, code, vr0, vr1);
+ else
+ *vr = old;
+ }
+}
+
+/* Generic folding of a unary expression of a value_range. Uses
+ range-ops and extract_range_from_unary_expr, and verifies that the
+ results match. */
+
+void
+range_fold_unary_expr (value_range_base *vr,
+ enum tree_code code,
+ tree expr_type,
+ const value_range_base *vr0)
+{
+ if (!value_range_base::supports_type_p (expr_type)
+ || !value_range_base::supports_type_p (vr0->type ()))
+ {
+ *vr = value_range (expr_type);
+ return;
+ }
+ if (flag_ranges_mode & RANGES_RANGE_OPS)
+ range_ops_fold_unary_expr (vr, code, expr_type, vr0);
+ if (flag_ranges_mode & RANGES_VRP)
+ {
+ value_range_base old;
+ extract_range_from_unary_expr (&old, code, expr_type, vr0, vr0->type ());
+ if (flag_ranges_mode & RANGES_CHECKING)
+ {
+ value_range_base vr1 (expr_type);
+ assert_compare_value_ranges (&old, vr, code, vr0, &vr1);
+ }
+ else
+ *vr = old;
+ }
+}
+
/* 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
'N = ASSERT_EXPR <V, V OP W>'. */
/* Work on a temporary so we can still use vr0 when union returns varying. */
value_range_base tem;
if (vr0type == VR_UNDEFINED)
- tem.set_undefined ();
+ tem.set_undefined (TREE_TYPE (vr0->min ()));
else if (vr0type == VR_VARYING)
- tem.set_varying (TREE_TYPE (vr0->min ()));
+ tem.set_varying (vr0->type ());
else
tem.set (vr0type, vr0min, vr0max);